Files
SIG-CM2.0/database
dmolinari 1c79dfa0a4 feat(db): V010 audit infrastructure + temporal tables
Applied to SIGCM2 (dev) and SIGCM2_Test.

V010__audit_infrastructure.sql (idempotent, ~280 LoC):
- Filegroups AUDIT_HOT + AUDIT_COLD with physical files (per-DB logical names
  via DB_NAME() prefix to avoid collision in dev/test).
- pf/ps_AuditEvent_Monthly + pf/ps_SecurityEvent_Monthly (RANGE RIGHT,
  DATETIME2(3), 14 boundaries 2026-01..2027-02 → 15 partitions). Job extends
  forward monthly in B11.
- dbo.AuditEvent (partitioned, clustered PK on OccurredAt+Id) + 4 indexes
  (Actor/Target/Action/Correlation) with PAGE compression.
- dbo.SecurityEvent (partitioned) + 3 indexes (Actor/Action_Result/Ip_Failure).
- CHECK constraints: Action LIKE '%.%', ISJSON(Metadata), Result IN (success|failure).
- SYSTEM_VERSIONING ON in Usuario/Rol/Permiso/RolPermiso with 10 YEARS retention +
  PAGE compression in history tables.
- No hard FK on ActorUserId → Usuario.Id (soft FK — audit must survive user deletion).

V010_ROLLBACK.sql: emergency reversal (WARNING: destroys all audit history).

database/README.md: migration order + V010 prod-apply notes.

tests/SIGCM2.TestSupport/SqlTestFixture.cs:
- EnsureV010SchemaAsync() validates audit infra is applied (fails fast with
  clear message if not — migration itself requires ALTER DATABASE privileges
  and is applied manually via sqlcmd).
- Respawn TablesToIgnore extended with *_History (engine rejects direct DELETE
  on system-versioned history tables).

tests/SIGCM2.Api.Tests/Audit/V010MigrationTests.cs — 5 smoke tests:
- AuditEvent insert+roundtrip with CorrelationId.
- CK_AuditEvent_Action rejects Action without '.'.
- CK_AuditEvent_Metadata rejects non-JSON.
- CK_SecurityEvent_Result rejects invalid Result.
- Usuario SYSTEM_VERSIONING: temporal query FOR SYSTEM_TIME AS OF returns
  pre-update state + Usuario_History populated.

Suite: 130/130 passing (previous 124 + spike B0 + 5 new B1). No regressions.

Refs: sdd/udt-010-auditoria-trazabilidad/{spec#REQ-AUD-1,2, #REQ-SEC-1,
design#D-4, tasks}
2026-04-16 13:10:04 -03:00
..

database/ — SIG-CM 2.0

Todo el DDL del sistema vive acá: migraciones versionadas, stored procedures, functions, seeds.

Estructura

database/
├── migrations/        # Migraciones versionadas V0XX__<descripcion>.sql (SQL puro, idempotentes)
├── procedures/        # Stored procedures — creados/alterados por UDTs específicas
├── functions/         # User-defined functions
├── seeds/             # Data de referencia no-versionada
└── schemas/           # Extracciones de schema (referencia)

Migraciones aplicadas (orden obligatorio)

Versión Archivo UDT Descripción
V001 V001__create_usuario.sql UDT-001 Tabla Usuario + IX_Usuario_Username_Activo
V002 V002__create_refresh_token.sql UDT-002 Tabla RefreshToken
V003 V003__create_rol.sql UDT-004 Tabla Rol + 8 roles canónicos
V004 V004__alter_usuario_rol_fk.sql UDT-004 FK Usuario.Rol → Rol.Codigo
V005 V005__create_permiso.sql UDT-005 Tabla Permiso + 18 permisos canónicos
V006 V006__create_rol_permiso.sql UDT-005 Tabla RolPermiso + seed 36 rows
V007 V007__add_admin_permissions_udt006.sql UDT-006 3 permisos administrativos RBAC
V008 V008__add_mustchangepassword_and_indexes.sql UDT-008 Usuario.MustChangePassword + IX_Usuario_Activo_Rol
V009 V009__activate_permisos_overrides.sql UDT-009 Migración shape PermisosJson {grant, deny}
V010 V010__audit_infrastructure.sql UDT-010 Infra de auditoría + Temporal Tables. Ver nota abajo.

Convenciones

  • SQL puro ejecutado manualmente (no hay runner automático; decisión arquitectónica).
  • Idempotentes: cada migración usa IF NOT EXISTS / MERGE / IF NOT EXISTS (SELECT 1 FROM sys....). Re-ejecutarlas es seguro.
  • Boilerplate inicial: SET QUOTED_IDENTIFIER ON; SET ANSI_NULLS ON; SET NOCOUNT ON; GO.
  • Naming: PK_*, UQ_*, FK_*, DF_*, CK_*, IX_*.
  • Se aplican a AMBAS bases: SIGCM2 (dev) y SIGCM2_Test (integration tests). El orden debe ser idéntico.

Cómo aplicar migraciones

En dev (manual)

# Con sqlcmd:
sqlcmd -S TECNICA3 -d SIGCM2      -U desarrollo -P desarrollo2026 -i database/migrations/V010__audit_infrastructure.sql
sqlcmd -S TECNICA3 -d SIGCM2_Test -U desarrollo -P desarrollo2026 -i database/migrations/V010__audit_infrastructure.sql

O desde SSMS: abrir el archivo, conectar a cada base, F5.

En integration tests

tests/SIGCM2.TestSupport/SqlTestFixture.cs aplica automáticamente el schema necesario en SIGCM2_Test al inicializar el fixture (EnsureV008SchemaAsync, EnsureV009SchemaAsync, EnsureV010SchemaAsync…). NO hace falta correr el script manualmente.

En producción (roadmap futuro)

  1. Backup completo de la base.
  2. Revisar notas específicas de la migración (ver abajo).
  3. Ventana de mantenimiento si la migración lo requiere.
  4. sqlcmd + script + verify que los PRINT salieron esperados.
  5. Smoke test post-migración.

⚠️ Notas especiales por migración

V010 — Infraestructura de Auditoría

Riesgos específicos:

  • Activa SYSTEM_VERSIONING en Usuario, Rol, Permiso, RolPermiso. Tablas con datos. ALTER TABLE ADD PERIOD FOR SYSTEM_TIME toma Sch-M lock (schema modification). En dev con pocos usuarios el lock es milisegundos; en prod con conexiones activas puede generar espera.
  • Crea filegroups AUDIT_HOT y AUDIT_COLD con archivos físicos <DB>_AUDIT_HOT.ndf y <DB>_AUDIT_COLD.ndf en el default data path del server.
  • Crea 2 partition functions + schemes mensuales (boundaries 2026-01..2027-02). El job AuditPartitionManagerJob (B11) extiende la ventana mes a mes.

Para aplicar en prod:

  1. Backup completo previo (no negociable).
  2. Ventana de mantenimiento ≥ 10 min (los ALTER de SYSTEM_VERSIONING son rápidos pero pueden caer en timeouts si hay transacciones largas).
  3. Ejecutar el script + verificar todos los PRINT "created/applied".
  4. Smoke test post: SELECT TOP 1 * FROM dbo.AuditEvent (vacío OK); SELECT temporal_type FROM sys.tables WHERE name = 'Usuario' (debe devolver 2 = system-versioned).
  5. Si algo falla → V010_ROLLBACK.sql (pierde toda la historia) o restore de backup.

Catálogo de entidades auditables (source of truth): Obsidian/02-ARQUITECTURA-y-TECH-STACK/2.5 📋 Auditoría.md. Cada UDT nueva que introduzca entidades de negocio debe agregar esas tablas al catálogo y activar SYSTEM_VERSIONING en su migración.

Recursos

  • Design autoritativo: Obsidian/02-ARQUITECTURA-y-TECH-STACK/2.5 📋 Auditoría.md
  • Decisión persistida (engram): sig-cm2/audit-architecture
  • SDD artifacts UDT-010 (engram): sdd/udt-010-auditoria-trazabilidad/{explore,proposal,spec,design,tasks,apply-progress}