Skip to main content

Overview

VIGIA’s Document Management system provides comprehensive tools for creating, versioning, signing, and exporting regulatory documents with full audit trail and compliance features.

Digital Signatures

Secure electronic signatures with OTP verification

Template Engine

DOCX templates with variable replacement and PDF generation

Version Control

Track document versions with change history

PDF Preview

Auto-generate PDF previews from DOCX files

Document Model

Core Structure

# Model: backend/app/models/documento.py:17-84
class Documento:
    # Identification
    - codigo: Document code/identifier (e.g., "POE-001")
    - titulo: Document title
    - categoria: Category (SOP, Report, Form, etc.)
    
    # Ownership (flexible)
    - owner_type: "IPS", "ICSR", "TRAINING", etc.
    - owner_id: ID of the owning entity
    
    # Classification
    - area: Department/area (QA, Medical, Regulatory)
    
    # Versioning
    - version: Current version (e.g., "1.0", "2.3")
    - vigente: Active status (True/False)
    - current_version_id: Link to active DocumentoVersion
    
    # File attributes
    - nombre_original: Original filename
    - tipo_mime: MIME type (application/pdf, etc.)
    - tamano_bytes: File size
    - ruta_archivo: File path
    
    # Metadata
    - tags: Comma-separated tags for search
    - meta: JSONB field for custom metadata
    
    # Optional ICSR link
    - icsr_id: Link to specific ICSR case

Document Versions

class DocumentoVersion:
    - documento_id: Parent document
    - version: Version string ("1.0", "1.1", "2.0")
    - file_path: Path to version file
    - file_name: Filename
    - file_mime: MIME type
    - file_size: File size in bytes
    - created_at: Version creation timestamp
Each document can have multiple versions, but only one is “current” at any time. This enables full version history tracking.

Template System

Creating Templates

Templates are DOCX files with variable placeholders: Template location: app/templates/docs/{CODIGO}.docx Variable syntax:
{{variable_name}}
Example template:
INFORME DE CAUSALIDAD

Código de caso: {{codigo_caso}}
Paciente: {{paciente_iniciales}}
Producto sospechoso: {{producto_sospechoso}}
Evento adverso: {{evento_adverso}}
Fecha de inicio: {{fecha_inicio}}

EVALUACIÓN DE CAUSALIDAD
Algoritmo: Karch-Lasagna
Puntuación: {{kl_score}}
Clasificación: {{kl_clasificacion}}

CONCLUSIONES
{{conclusiones}}

Fecha de emisión: {{emision}}
Fecha de vigencia: {{vigencia}}

Generating from Templates

POST /api/v1/documentos/generate
Content-Type: application/json

{
  "codigo": "INFORME_CAUSALIDAD",
  "version": "1.0",
  "data": {
    "codigo_caso": "ICSR-2024-001",
    "paciente_iniciales": "ABC",
    "producto_sospechoso": "Paracetamol 500mg",
    "evento_adverso": "Hepatotoxicidad",
    "fecha_inicio": "2024-01-15",
    "kl_score": "7",
    "kl_clasificacion": "Probable",
    "conclusiones": "La relación de causalidad es probable según...",
    "emision": "2024-03-01"
  },
  "owner_type": "ICSR",
  "owner_id": 123
}
Features:
  • Auto-calculate dates: If emision provided but not vigencia, automatically calculates vigencia = emision + 3 years
  • DOCX output: Generates Microsoft Word document
  • PDF conversion: Optional PDF generation via LibreOffice
  • Version tracking: Creates DocumentoVersion record
Response:
{
  "documento_id": 456,
  "version_id": 789,
  "file_path": "/media/docs/INFORME_CAUSALIDAD/v1.0/INFORME_CAUSALIDAD_v1.0.docx",
  "file_size": 45678,
  "preview_url": "/api/v1/documentos/456/preview"
}

PDF Preview

Automatic PDF preview generation from DOCX files:
GET /api/v1/documentos/{doc_id}/preview?disposition=inline
Conversion methods:
  1. LibreOffice (preferred, cross-platform):
    soffice --headless --convert-to pdf --outdir /output /path/to/file.docx
    
  2. docx2pdf (Windows + Microsoft Word):
    from docx2pdf import convert
    convert("input.docx", "output.pdf")
    
Caching:
  • PDF previews are cached in media/previews/pdf/
  • Regenerated only if DOCX is newer than cached PDF
  • Significant performance improvement for repeated views
Source: backend/app/routers/documentos.py:106-135
System requirement: LibreOffice must be installed on the server for PDF conversion. Check availability:
which soffice

Digital Signatures

Secure electronic signature workflow with OTP verification:

Signature Flow

1

Request Signature

Initiate signature request for a document
POST /api/v1/firmas/request
{
  "documento_id": 123,
  "signer_email": "[email protected]",
  "reason": "Aprobación de reporte IPS Q1-2024"
}
2

Send OTP

System sends One-Time Password to signer’s email/phone
  • 6-digit numeric code
  • Valid for 10 minutes
  • Single use only
3

Verify and Sign

Signer enters OTP to complete signature
POST /api/v1/firmas/sign
{
  "request_id": "uuid-1234",
  "otp": "123456",
  "signature_data": "base64_encoded_signature_image"
}
4

Audit Trail

System records:
  • Timestamp (with timezone)
  • Signer identity
  • IP address
  • Document hash (SHA-256)
  • Signature reason

Signature Metadata

Each signature includes:
{
  "id": "firma-uuid-5678",
  "documento_id": 123,
  "signer": {
    "user_id": 45,
    "email": "[email protected]",
    "name": "Dr. Juan Pérez"
  },
  "timestamp": "2024-03-01T15:30:45-05:00",
  "ip_address": "192.168.1.100",
  "reason": "Aprobación de reporte IPS Q1-2024",
  "document_hash": "sha256:a1b2c3d4...",
  "otp_verified": true,
  "signature_image": "data:image/png;base64,..."
}
Source: backend/app/routers/firmas.py, backend/app/models/firma.py

Document Categories

Common document types in pharmacovigilance:
CategoriaDescriptionTemplates
SOPStandard Operating ProceduresPOE-FV-001, SOP-QA-002
REPORTRegulatory reportsINFORME_CAUSALIDAD, REPORTE_IPS
FORMForms and questionnairesFORMULARIO_RAM, CONSENTIMIENTO
ACTAMeeting minutesACTA_COMITE_FV
TRAININGTraining materialsCAPACITACION_RAM, EVALUACION
CERTIFICATECertificatesCERTIFICADO_CAPACITACION

File Upload

Upload existing documents:
POST /api/v1/documentos/upload
Content-Type: multipart/form-data

file: [binary file]
codigo: "SOP-FV-001"
titulo: "Procedimiento de Reporte de RAM"
categoria: "SOP"
area: "Farmacovigilancia"
version: "2.0"
tags: "sop,farmacovigilancia,ram"
Supported formats:
  • PDF (.pdf)
  • Microsoft Word (.docx)
  • Microsoft Excel (.xlsx)
  • Images (.png, .jpg, .jpeg)
  • Plain text (.txt)
Storage:
  • Base directory: media/docs/
  • Path structure: {codigo}/v{version}/{filename}
  • Example: media/docs/SOP-FV-001/v2.0/procedimiento_ram_v2.0.pdf

Version Management

Create New Version

POST /api/v1/documentos/{doc_id}/version
Content-Type: multipart/form-data

file: [new version file]
version: "2.1"
change_notes: "Updated section 3.4 - causality assessment procedure"
System automatically:
  1. Creates new DocumentoVersion record
  2. Updates current_version_id in parent Documento
  3. Marks old version as non-current (but keeps it)
  4. Logs version change in audit trail

List Versions

GET /api/v1/documentos/{doc_id}/versions
Response:
{
  "versions": [
    {
      "id": 789,
      "version": "2.1",
      "is_current": true,
      "created_at": "2024-03-01T10:00:00Z",
      "file_size": 45678,
      "download_url": "/api/v1/documentos/versions/789/download"
    },
    {
      "id": 788,
      "version": "2.0",
      "is_current": false,
      "created_at": "2023-12-01T10:00:00Z",
      "file_size": 44123
    }
  ]
}

Search and Filter

GET /api/v1/documentos?
  q=farmacovigilancia&
  categoria=SOP&
  area=QA&
  vigente=true&
  tags=ram,reporte&
  owner_type=ICSR&
  page=1&
  page_size=20
Filter parameters:
  • q: Full-text search (codigo, titulo, tags)
  • categoria: Document category
  • area: Department/area
  • vigente: Active documents only (true/false)
  • tags: Comma-separated tags (AND logic)
  • owner_type: Filter by owner type
  • owner_id: Filter by specific owner

API Endpoints Summary

Document CRUD

# List/search documents
GET /api/v1/documentos

# Get single document
GET /api/v1/documentos/{doc_id}

# Upload new document
POST /api/v1/documentos/upload

# Generate from template
POST /api/v1/documentos/generate

# Update metadata
PUT /api/v1/documentos/{doc_id}

# Delete document
DELETE /api/v1/documentos/{doc_id}

Versions

# List versions
GET /api/v1/documentos/{doc_id}/versions

# Create new version
POST /api/v1/documentos/{doc_id}/version

# Download specific version
GET /api/v1/documentos/versions/{version_id}/download

Preview

# PDF preview (inline or download)
GET /api/v1/documentos/{doc_id}/preview?disposition=inline

Signatures

# Request signature
POST /api/v1/firmas/request

# Verify OTP and sign
POST /api/v1/firmas/sign

# Get signature details
GET /api/v1/firmas/{firma_id}

# List document signatures
GET /api/v1/documentos/{doc_id}/firmas

Integration Examples

Attach Document to ICSR

POST /api/v1/documentos/upload
Content-Type: multipart/form-data

file: [lab_results.pdf]
codigo: "LAB-ICSR-2024-001"
titulo: "Resultados de laboratorio - Caso #2024-001"
categoria: "ANEXO"
icsr_id: 123
owner_type: "ICSR"
owner_id: 123

Generate IPS Report Document

POST /api/v1/documentos/generate
{
  "codigo": "REPORTE_IPS",
  "version": "1.0",
  "data": {
    "producto_nombre": "Paracetamol 500mg",
    "periodo_inicio": "2024-01-01",
    "periodo_fin": "2024-06-30",
    "casos_total": 15,
    "casos_graves": 2,
    "literaturas_detected": 45
  },
  "owner_type": "IPS",
  "owner_id": 456
}

Code References

FeatureImplementation
Document Modelbackend/app/models/documento.py:17-113
Routerbackend/app/routers/documentos.py:1-300
Template Renderingbackend/app/routers/documentos.py:300-350
PDF Previewbackend/app/routers/documentos.py:106-135
Signaturesbackend/app/routers/firmas.py
Version Controlbackend/app/models/documento.py:89-113

Best Practices

Template Design

  • Use clear, descriptive variable names
  • Include all required regulatory elements
  • Test templates with sample data
  • Version control template files

Document Lifecycle

  • Create new version for substantial changes
  • Retire old versions (don’t delete)
  • Require signatures for critical documents
  • Backup document storage regularly

Build docs developers (and LLMs) love