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
| Rol | Responsabilidad |
|---|---|
| Admin documental | Es dueño del protocolo. Edita y versiona la plantilla de declaración jurada. |
| Encargado de sistemas | Interviene si una plantilla no editable desde la UI necesita cambios. Valida con el Admin documental antes de modificarla. |
| Sistema | Valida 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-juradadesde 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ódigo | Control | Tipo |
|---|---|---|
| C1 | AAL2 obligatorio en cada mutación (assertAdminAal2) | Guarda de código |
| C2 | Solo declaracion-jurada es editable desde la UI (isEditableTemplate) | Guarda de código |
| C3 | Variables limitadas a variables_schema.allowed_keys | Guarda de datos |
| C4 | Alerta si se eliminan cláusulas canónicas (diffCanonicalClauseIds) | Control preventivo |
| C5 | Historial automático en pdf_template_versions con autor y resumen | Trazabilidad |
10. Criterios de decisión
| Situación | Decisión |
|---|---|
| El admin intenta editar un tipo no editable | El sistema rechaza la operación. Escalar al Encargado de sistemas. |
| Se detecta eliminación de cláusula canónica | El admin decide confirmar o revertir. El sistema no bloquea, pero alerta. |
| El preview falla al regenerarse | El admin notifica al Encargado de sistemas. La plantilla ya guardada es válida; el preview es solo vista previa. |
| El admin necesita revertir un cambio | Usa 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_templateses la fuente de verdad para la generación de documentos.
12. Registros generados
| Registro | Dónde | Notas |
|---|---|---|
| Versión previa de plantilla | pdf_template_versions | Con version, change_summary, created_by |
| Plantilla actualizada | pdf_templates | Con nuevo número de versión y updated_by |
| Preview PDF | R2 (privado), URL en pdf_templates.preview_pdf_url | Con hash del contenido para detectar desactualización |
| Evento ISO | iso_system_events | CONFIRMADO: logISOSystemEvent("document_updated" as any, "pdf_templates", id) llamado en app/actions/pdf-templates.ts:271 |
| Registro de auditoría | audit_logs | CONFIRMADO: 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
| Indicador | Meta |
|---|---|
| Cláusulas canónicas eliminadas en algún guardado | 0 |
Actualizaciones sin change_summary | 0 |
Plantillas con preview_pdf_url vigente | 100 % de los tipos con plantilla activa |
Versiones en pdf_template_versions por tipo en el período | Registro de toda modificación |
14. Riesgos y controles
| Riesgo | Nivel | Control |
|---|---|---|
| Eliminación de cláusula legal canónica sin revisión | Alto | C4: alerta de diff de cláusulas |
| Edición sin segundo factor | Alto | C1: guarda AAL2 |
| Variable no autorizada en el texto | Medio | C3: whitelist en editor |
| Cambio sin resumen descriptivo | Bajo | Campo change_summary en el formulario |
| Preview desactualizado respecto de la plantilla activa | Bajo | preview_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 protocolo | Dónde vive |
|---|---|
| Paso 1 — Carga de plantilla | lib/pdf/template-adapter.ts, consulta a pdf_templates |
| Paso 2 — Guarda AAL2 | app/actions/pdf-templates.ts: assertAdminAal2(supabase) |
| Paso 3 — Verificación de tipo editable | lib/pdf-clinical/template-types.ts:57: EDITABLE_TEMPLATE_TYPES = ["declaracion-jurada"] |
| Paso 4 — Whitelist de variables | lib/pdf-clinical/variables-whitelist.ts; variables_schema.allowed_keys en pdf_templates |
| Paso 5 — Diff de cláusulas | lib/pdf-clinical/canonical-clause-diff.ts: diffCanonicalClauseIds |
| Paso 6 — Historial | Tabla pdf_template_versions; interfaz PdfTemplateVersion en app/actions/pdf-templates.ts |
| Paso 7 — Registro | CONFIRMADO: 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 — Preview | lib/pdf-clinical/preview-cache.ts: regeneratePreviewPdf; URL en pdf_templates.preview_pdf_url |
Brechas conocidas:
-
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.
-
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ón | Fecha | Cambio |
|---|---|---|
| 1.0 | 2026-08-28 | Primera redacción con evidencia del harness DOC |
| 1.1 | 2026-08-29 | Cierre 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)