Skip to main content
Traducción. Autoritativo: fs-core-0005-audit-log.md.

Contexto

ADR-017 eligió CQRS-lite sobre event sourcing, y el registro de auditoría es lo que hace honesto ese canje: sin un registro completo de cambios, descartar event sourcing significaría renunciar a poder responder “por qué esta fila está así”. Tiene un segundo trabajo. La Ley 21.719 fiscaliza evidencia operativa, y el registro es la evidencia: quién accedió a un documento de identidad, cuándo cambió un consentimiento, qué operador suplantó a qué tenant. Por eso se registran también las lecturas de acceso, no solo las escrituras. Se entrega temprano porque no depende de nada y todo depende de él. Un command handler escrito antes de que exista el registro se escribirá sin él.

Alcance (normativo)

  • core.audit_log, append-only, particionada RANGE mensual.
  • Actor tipado: user | member | api_key | system, con id.
  • Diff completo old→new de la entidad modificada.
  • Propagación de correlation_id desde el request que lo causó.
  • El helper que llama todo command handler, dentro de la transacción del comando.
  • Endpoints de lectura para el rastro del propio tenant y para Softcrum Ops.
  • Retención por plan, con el mínimo legal aplicando de forma independiente.

Fuera de alcance (normativo)

  • Logging de aplicación y trazas — eso es packages/observability, otra preocupación con otra retención y otro destino.
  • Alertas sobre patrones de auditoría — una feature de seguridad posterior.
  • Inmutabilidad por criptografía. Append-only más grants restringidos es la postura de F1; una cadena de hashes es un endurecimiento posible más adelante.

Comportamiento (normativo)

  1. Todo comando escribe exactamente una fila de auditoría dentro de su propia transacción. Si el comando revierte, la fila revierte con él — una entrada de auditoría de algo que no ocurrió es peor que ninguna.
  2. El actor está siempre tipado y siempre presente. system es un actor válido; desconocido no.
  3. El diff es oldnew sobre los campos cambiados, completo (DEC-C2). Los valores sensibles se registran enmascarados: el registro prueba que el cambio ocurrió sin volverse una segunda copia del documento.
  4. correlation_id es obligatorio y se hereda del request de origen, para que una fila de auditoría se una con los eventos, jobs y envíos que causó.
  5. La tabla es append-only. Sin camino de update, sin camino de delete, y el rol de aplicación no tiene grant para ninguno.
  6. Las lecturas que exponen datos sensibles escriben su propia fila — leer un documento completo es un acto auditable (DEC-A4).
  7. Particionada mensualmente sobre occurred_at; toda consulta lleva el predicado de partición.
  8. La retención sigue el tier del plan, y el mínimo legal aplica de forma independiente y gana cuando es mayor.
  9. Un tenant puede leer su propio rastro, incluida la suplantación de operador ejercida sobre él. Ocultarlo anularía el propósito de registrarlo.

Datos (normativo)

API (normativo)

El rango de tiempo es obligatorio, no con valor por defecto: es la clave de partición, y una consulta de auditoría sin acotar es un scan completo de la tabla más grande del schema.

Eventos (normativo)

Ninguno. El registro es consumidor de todo y productor de nada.

Criterios de aceptación (normativo)

  1. Un comando que revierte no deja fila de auditoría.
  2. Todo command handler del código escribe una fila — impuesto por una regla de lint, no por revisión.
  3. El diff de un update contiene exactamente los campos cambiados, con valores viejo y nuevo.
  4. Un documento de identidad que aparezca en un diff está enmascarado.
  5. Leer un documento completo produce una fila que nombra al actor y al contacto.
  6. Una consulta de auditoría sin rango de tiempo se rechaza con un error tipado.
  7. Los intentos de update y delete fallan a nivel de grant de base de datos, no solo en la aplicación.
  8. Negativo: no existe fila de auditoría con actor ausente o sin tipar.

Ejecución

Un solo slice, comando síncrono. Schema y particiones en TS-001; el helper en packages/core para que todo módulo escriba la misma forma.

Preguntas abiertas

Changelog

Registro de entrega

Aún no implementado.