Saltar al contenido
DispensAI

DOC-003

Plantillas PDF y variables editables

Controlar cómo se crean, editan, versionan y previsualizan las plantillas PDF de la organización, de modo que ningún cambio introduzca variables no autorizadas, borre cláusulas legales canónicas o se haga sin trazabilidad.

DOC-003 — Plantillas PDF y variables editables

1. Objetivo

Controlar cómo se crean, editan, versionan y previsualizan las plantillas PDF de la organización. El objetivo es que ningún cambio en el texto legal, las variables disponibles o el branding de una plantilla se haga sin trazabilidad, sin revisión de cláusulas canónicas y sin registro de quién lo hizo y cuándo.

2. Alcance

Cubre la gestión de plantillas PDF en el sistema: edición autorizada, validación de variables, versionado automático y generación de preview.

No cubre:

  • la generación de un documento a partir de la plantilla → [[DOC-001]], [[DOC-002]];
  • la custodia del documento generado → [[DOC-005]];
  • el sellado criptográfico del documento generado → [[DOC-006]];
  • la verificación pública → [[DOC-007]].

3. Definiciones

Plantilla PDF: fila en pdf_templates que define el contenido, las cláusulas legales, el branding y las variables permitidas para un tipo de documento clínico.

Tipo editable: únicamente declaracion-jurada admite edición desde la UI de admin (EDITABLE_TEMPLATE_TYPES). El resto de los tipos (ficha-ingreso, acta-entrevista, detalle-tratamiento, comprobante-dispensacion) son read-only desde la UI y solo pueden modificarse por intervención de desarrollo.

Variables permitidas: las definidas en variables_schema.allowed_keys de la fila pdf_templates. La whitelist existe en lib/pdf-clinical/variables-whitelist.ts. Ninguna variable fuera de la whitelist puede insertarse en el texto renderizado.

Cláusula canónica: fragmento de texto legal identificado por ID en lib/pdf-clinical/legal-clauses.canonical.ts. El sistema detecta si una edición elimina una cláusula canónica mediante diffCanonicalClauseIds.

Versión de plantilla: fila en pdf_template_versions que preserva el contenido previo cada vez que se guarda un cambio. El número de versión se incrementa en cada guardado.

4. Roles y responsables

RolResponsabilidad
Admin documentalEs dueño del protocolo. Edita y versiona la plantilla de declaración jurada.
Encargado de sistemasInterviene si una plantilla no editable desde la UI necesita cambios. Valida con el Admin documental antes de modificarla.
SistemaValida variables, detecta cambios en cláusulas canónicas, guarda historial, genera el preview y emite el registro.

5. Disparador de inicio

Un admin necesita actualizar el texto, las cláusulas, las variables o el branding de la declaración jurada, o verificar el estado actual de la plantilla.

6. Requisitos previos

  • Sesión admin con autenticación de segundo factor completada (AAL2). Sin AAL2, todas las mutaciones sobre plantillas son rechazadas.
  • Acceso a /admin/plantillas-pdf/ dentro del tenant.

7. Entradas

  • Tipo de plantilla a editar (solo declaracion-jurada desde la UI).
  • Nuevo contenido propuesto (texto, cláusulas, overrides de branding).
  • Descripción del cambio (change_summary).

8. Procedimiento paso a paso

Paso 1 — El admin accede a la gestión de plantillas. Navega a /admin/plantillas-pdf/. El sistema carga la plantilla actual desde pdf_templates para el tipo seleccionado.

Paso 2 — El sistema verifica la identidad con segundo factor. Toda mutación llama a assertAdminAal2(supabase) antes de continuar. Si el nivel de autenticación no es AAL2, la acción retorna error sin procesar el cambio.

Paso 3 — El sistema verifica que el tipo es editable. isEditableTemplate(type) comprueba que el tipo sea declaracion-jurada. Si no lo es, la acción rechaza la edición. Los demás tipos son read-only desde la UI.

Paso 4 — El admin propone el nuevo contenido. Modifica el texto de las cláusulas mediante el editor. Las variables disponibles están limitadas a variables_schema.allowed_keys; el editor no permite insertar otras.

Paso 5 — El sistema detecta cambios en cláusulas canónicas. diffCanonicalClauseIds(contenidoPrevio, contenidoNuevo) calcula cuáles cláusulas canónicas se eliminaron. Si se eliminó alguna, el sistema alerta al admin antes de guardar.

Paso 6 — El sistema guarda el historial y la nueva versión. Antes de actualizar pdf_templates, guarda la fila previa en pdf_template_versions con el change_summary y el created_by. Luego actualiza pdf_templates con el nuevo contenido e incrementa el número de versión.

Paso 7 — El sistema emite el registro de la operación. Se emite evento ISO y se registra en audit_logs la modificación, indicando el admin, el tipo de plantilla, la versión anterior y la nueva.

Paso 8 — El sistema genera el preview PDF. regeneratePreviewPdf() produce un PDF de muestra con datos ficticios y lo almacena en R2, actualizando preview_pdf_url, preview_generated_at y preview_content_hash en la fila de pdf_templates.

9. Puntos de control

CódigoControlTipo
C1AAL2 obligatorio en cada mutación (assertAdminAal2)Guarda de código
C2Solo declaracion-jurada es editable desde la UI (isEditableTemplate)Guarda de código
C3Variables limitadas a variables_schema.allowed_keysGuarda de datos
C4Alerta si se eliminan cláusulas canónicas (diffCanonicalClauseIds)Control preventivo
C5Historial automático en pdf_template_versions con autor y resumenTrazabilidad

10. Criterios de decisión

SituaciónDecisión
El admin intenta editar un tipo no editableEl sistema rechaza la operación. Escalar al Encargado de sistemas.
Se detecta eliminación de cláusula canónicaEl admin decide confirmar o revertir. El sistema no bloquea, pero alerta.
El preview falla al regenerarseEl admin notifica al Encargado de sistemas. La plantilla ya guardada es válida; el preview es solo vista previa.
El admin necesita revertir un cambioUsa la fila en pdf_template_versions para restaurar el contenido anterior. El Encargado de sistemas interviene para copiar el contenido previo y guardar una nueva versión.

11. Excepciones y escalamiento

  • Modificación de tipos no editables. Solo el Encargado de sistemas puede hacerlo, con autorización del Admin documental, mediante intervención directa en el código. Cualquier cambio debe registrarse en el historial de versiones antes de desplegarse.
  • Cláusula canónica eliminada sin revisión. Se trata como incidente de calidad. Se restaura la versión previa y se revisan los documentos generados con la versión problemática.
  • Preview inconsistente con la plantilla activa. El preview es informativo; la plantilla activa en pdf_templates es la fuente de verdad para la generación de documentos.

12. Registros generados

RegistroDóndeNotas
Versión previa de plantillapdf_template_versionsCon version, change_summary, created_by
Plantilla actualizadapdf_templatesCon nuevo número de versión y updated_by
Preview PDFR2 (privado), URL en pdf_templates.preview_pdf_urlCon hash del contenido para detectar desactualización
Evento ISOiso_system_eventsCONFIRMADO: logISOSystemEvent("document_updated" as any, "pdf_templates", id) llamado en app/actions/pdf-templates.ts:271
Registro de auditoríaaudit_logsCONFIRMADO: logAudit llamado en líneas 283, 295 y 336 de app/actions/pdf-templates.ts; la línea 295 corresponde al logAudit disparado cuando diffCanonicalClauseIds detecta remoción de cláusula canónica

13. Indicadores

IndicadorMeta
Cláusulas canónicas eliminadas en algún guardado0
Actualizaciones sin change_summary0
Plantillas con preview_pdf_url vigente100 % de los tipos con plantilla activa
Versiones en pdf_template_versions por tipo en el períodoRegistro de toda modificación

14. Riesgos y controles

RiesgoNivelControl
Eliminación de cláusula legal canónica sin revisiónAltoC4: alerta de diff de cláusulas
Edición sin segundo factorAltoC1: guarda AAL2
Variable no autorizada en el textoMedioC3: whitelist en editor
Cambio sin resumen descriptivoBajoCampo change_summary en el formulario
Preview desactualizado respecto de la plantilla activaBajopreview_content_hash permite detectar la discrepancia

15. Normativa y referencias

  • Ley 19.799, sobre documentos electrónicos y firma electrónica. El texto legal de la declaración debe reflejar los términos de consentimiento exigidos.
  • Ley 20.584, sobre derechos y deberes de los pacientes. Las cláusulas de consentimiento informado deben mantenerse íntegras.
  • Ley 21.719, sobre protección de datos personales. Los textos de consentimiento para tratamiento de datos sensibles deben estar vigentes y alineados con las finalidades declaradas.
  • ISO/IEC 27001:2022, A.5.33: integridad de la información de auditoría.
  • [[DOC-001]], [[DOC-002]] (documentos generados desde las plantillas).
  • [[DOC-005]] (custodia del preview), [[DOC-006]] (sellado de los documentos generados).

16. Anexos y formularios vinculados

  • Editor de cláusulas en /admin/plantillas-pdf/.
  • Lista de cláusulas canónicas en lib/pdf-clinical/legal-clauses.canonical.ts.

17. Implementación en el sistema

El protocolo está implementado para el tipo declaracion-jurada. Los demás tipos son read-only desde la UI.

Elemento del protocoloDónde vive
Paso 1 — Carga de plantillalib/pdf/template-adapter.ts, consulta a pdf_templates
Paso 2 — Guarda AAL2app/actions/pdf-templates.ts: assertAdminAal2(supabase)
Paso 3 — Verificación de tipo editablelib/pdf-clinical/template-types.ts:57: EDITABLE_TEMPLATE_TYPES = ["declaracion-jurada"]
Paso 4 — Whitelist de variableslib/pdf-clinical/variables-whitelist.ts; variables_schema.allowed_keys en pdf_templates
Paso 5 — Diff de cláusulaslib/pdf-clinical/canonical-clause-diff.ts: diffCanonicalClauseIds
Paso 6 — HistorialTabla pdf_template_versions; interfaz PdfTemplateVersion en app/actions/pdf-templates.ts
Paso 7 — RegistroCONFIRMADO: logISOSystemEvent("document_updated" as any, ...) en línea 271; logAudit en líneas 283, 295 y 336 de app/actions/pdf-templates.ts
Paso 8 — Previewlib/pdf-clinical/preview-cache.ts: regeneratePreviewPdf; URL en pdf_templates.preview_pdf_url

Brechas conocidas:

  1. Los tipos no editables desde la UI no tienen mecanismo de revisión en el sistema. Ficha de ingreso, acta de entrevista, detalle de tratamiento y comprobante de dispensación solo se modifican por intervención de desarrollo. Cualquier error en esas plantillas se propaga a todos los documentos generados. El control es solo-humano: revisión previa al deploy.

  2. La regeneración masiva de previews (regenerateAllPreviews) no tiene trigger automático ante cambios en el branding del tenant. Si el logo o los colores cambian, los previews quedan desactualizados hasta que un admin los regenere manualmente.

18. Historial de versiones

VersiónFechaCambio
1.02026-08-28Primera redacción con evidencia del harness DOC
1.12026-08-29Cierre de INFERIDO: confirmado que logISOSystemEvent se llama en línea 271 con evento document_updated (cast as any — no está en el enum ISOEventType); logAudit en líneas 283, 295 y 336; diffCanonicalClauseIds disparada en línea 293 y su remoción registrada vía logAudit en línea 295. Brecha 2 eliminada — era falsa. Frontmatter eventos_iso corregido: el nombre real del evento es document_updated, no pdf_template_updated. Observación nueva: el evento se emite con cast as any porque el tipo document_updated no está en el enum tipado de ISOEventType.

Documentos asociados

  • Plantillas en tabla pdf_templates
  • Historial en tabla pdf_template_versions
  • Lista de cláusulas legales canónicas (lib/pdf-clinical/legal-clauses.canonical.ts)
  • Preview PDF en R2

Registros y evidencia

  • Fila en pdf_template_versions con change_summary y created_by
  • Evento ISO de actualización de plantilla
  • Registro de auditoría de la acción

Indicadores

  • Número de versiones de plantilla creadas por período
  • % de actualizaciones de plantilla con change_summary registrado
  • % de plantillas con preview_pdf_url vigente
  • Cláusulas canónicas eliminadas en algún guardado (debe ser 0)

Normativa y referencias

  • Ley 19.799 sobre documentos electrónicos y firma electrónica
  • Ley 20.584 sobre derechos y deberes de los pacientes
  • Ley 21.719 sobre protección de datos personales
  • ISO/IEC 27001:2022, control A.5.33 (integridad de información de auditoría)

Dónde deja rastro en el sistema

Rutas
  • /admin/plantillas-pdf
Tablas
  • pdf_templates
  • pdf_template_versions
Eventos
  • document_updated (CONFIRMADO: logISOSystemEvent llamado en app/actions/pdf-templates.ts:271, tabla pdf_templates; cast as any porque el tipo no está en el enum ISOEventType)