Saltar a contenido

ADR-0003 · Persistencia: Postgres histórico + DynamoDB hot-path + S3 split

  • Status: Accepted
  • Date: 2026-04-30
  • Deciders: Cristian Fernández (Zerviz Group)
  • Related: ADR-0002 (tenancy), ADR-0004 (eventing), docs/discovery/00-phase1-prerequisites.md 3.1/3.3 + Anexo A-03/A-04.

Context

Decisión asentada en checklist: cada microservicio elige su store. RDS Postgres es exclusivamente para histórico, audit y reportería; DynamoDB para hot-path. Costo mínimo en dev; HA + Multi-AZ sólo en qa y prod. Aislamiento por tier (ADR-0002): tier lógico comparte RDS+DDB; tier físico tiene los suyos.

Decision

Postgres (ze-{env}-postgres)

  • Engine: RDS for PostgreSQL 16 LTS (no 18.x; 16 tiene soporte largo y es estable). Migrar major version es decisión separada (ADR futuro).
  • Dev: db.t4g.micro, single-AZ, sin réplica, BackupRetentionPeriod = 1 día, DeletionProtection = false. ~USD 13/mes.
  • QA: db.t4g.small, Multi-AZ, BackupRetentionPeriod = 14 días, DeletionProtection = true. ~USD 60/mes.
  • Prod: db.t4g.medium Multi-AZ con read replica + PITR 35 días, DeletionProtection = true, IAM auth ON, slow query log + audit log a CloudWatch. ~USD 250/mes baseline.
  • Bases de datos lógicas:
  • ze_app — datos de aplicación tier lógico (todas las tablas con tenant_id + RLS).
  • ze_control_plane — registros transversales (catálogo de tenants, conectores instalados, audit transversal, billing). Sin tenant_id (datos de plataforma).
  • Esquema multi-tenant tier lógico: RLS sobre tabla compartida + columna tenant_id uuid NOT NULL. Middleware packages/tenant-context ejecuta SET LOCAL app.tenant_id = '<id>' en cada conexión. Roles: un rol app por servicio (ze_inbound_router, ze_reporting_api, ...) con BYPASSRLS = false mandatorio.
  • Tier físico: cada cuenta enterprise tiene su ze-postgres propio sin RLS (innecesario).
  • Storage: GP3, autoscaling habilitado en qa/prod.

DynamoDB

  • Patrón naming: ze-{env}-<entity> (e.g. ze-dev-flow-state, ze-prod-dedup).
  • Modo: PAY_PER_REQUEST por defecto. Pasar a Provisioned + autoscaling si llegamos a > 100 RPS sostenidos.
  • TTL obligatorio en tablas con datos efímeros: dedup (24 h), flow-state (configurable por flow, default 7 días), five9-sessions (1 h, ver checklist 6.1).
  • Tier lógico: PK = TENANT#<id> + SK por entidad. IAM con dynamodb:LeadingKeys = TENANT#${aws:PrincipalTag/tenant_id}.
  • Tier físico: PK directa por entidad (sin prefijo TENANT) en la cuenta del tenant.
  • Streams: activos en tablas que requieren outbox pattern (ver ADR-0004 §Outbox).
  • Encryption: KMS CMK por tenant (alias/ze-{env}-tenant-<id>) para datos confidenciales; AWS-managed para neutros.

S3

  • Topología split por env (asentado checklist 8.1):
  • ze-{env}-spa — bundles de SPA (apps/builder-spa, apps/widget-spa).
  • ze-{env}-data — datos de negocio (encuestas, audit, exports). Prefijo tenants/<id>/....
  • ze-{env}-flows — catálogo de flows (sucesor de s3://ze-engine/flujos/). Single source of truth (mitigación R-15).
  • Versionado: ON en todos los buckets de datos. Object Lock modo compliance en flows/ y tenants/<id>/audit/.
  • Encryption: SSE-KMS con CMK por tenant para tenants/<id>/...; SSE-S3 (AES256) para SPA bundles.
  • Lifecycle: retención configurable por tenant (asentado checklist 8.3) vía tag RetentionDays aplicado a prefijo tenants/<id>/. Default 730 días (2 años); enterprise puede subirlo a 2.555 días (7 años).
  • CloudFront OAC obligatorio sobre ze-{env}-spa. Sin distribuciones huérfanas.

Asignación store ↔ servicio

Servicio Store(s) Justificación
tenant-mgmt RDS ze_control_plane.tenants + DDB ze-tenants-cache Datos transversales relacionales; cache de lookup hot
auth-bff (sin estado propio) Cognito es la fuente
inbound-router DDB ze-dedup (TTL 24 h) Idempotencia hot-path
flow-engine DDB ze-flow-state (TTL configurable) + Streams → outbox Hot-path por conversación
connector-orchestrator SSM Parameter Store (CB state) + DDB ze-circuit-breaker Estado breaker compartido
connectors-social (sin estado, secrets en SM) Stateless
connectors-cc DDB ze-five9-sessions (TTL 1 h) Cache de auth
outbound-dispatcher RDS ze_app.campaigns + DDB ze-outbound-runs (TTL 30 d) Catálogo + locks
reporting-api RDS ze_app (read-only) Queries analíticas
encuesta-service DDB ze-encuesta-state (TTL 30 d) FSM efímera

Consequences

Positive

  • Costo dev mínimo (~USD 15/mes en persistencia).
  • Postgres concentrado en lo que escala mal en NoSQL (audit, joins, reportería).
  • DDB concentrado en lo que escala bien (sesiones, hot-path).
  • S3 split termina con la mezcla ze-engine legacy.

Negative

  • 2 stores ⇒ los devs deben elegir bien. Mitigado con services/_template que sugiere DDB-first.
  • RLS olvidado = leak ⇒ middleware + tests obligatorios.

Alternatives considered

  • Aurora Serverless v2 desde dev: descartado por costo mínimo (cuesta más que t4g.micro hasta scale > 0.5 ACU sostenido). Re-evaluar en qa.
  • DynamoDB para todo: descartado, reportería compleja se vuelve dolorosa.
  • Aurora Postgres en prod: mantener como opción evaluable cuando volumen lo justifique.

Tenant-isolation impact

  • Tier lógico: RLS Postgres + IAM LeadingKeys DDB + KMS CMK por tenant en S3/DDB confidencial.
  • Tier físico: aislamiento por cuenta AWS.

Blast radius

  • RDS dev caída ⇒ greenfield no productivo, sin impacto. RDS prod caída ⇒ Multi-AZ failover automático en < 60 s.
  • DDB caída regional ⇒ degradación severa (no hay multi-region V1; aceptable).

Cost note

  • Dev (lógico): ~USD 13 RDS + ~USD 5 DDB + ~USD 1 S3 = ~USD 19/mes.
  • Prod (lógico tier): ~USD 250 RDS + ~USD 50–500 DDB según tráfico + ~USD 10–50 S3.
  • Prod tier físico (por tenant enterprise): + ~USD 60 RDS + ~USD 30 DDB baseline.

ISO 27001 controls touched

  • A.8.2.3 (manejo de activos según clasificación): tag DataClassification.
  • A.10.1.1 (criptografía): KMS CMK por tenant.
  • A.12.3.1 (respaldo): PITR + Object Lock.
  • A.13.1.3 (segregación): RLS + IAM LeadingKeys + cuenta-por-tenant.

Sources

  • docs/discovery/00-phase1-prerequisites.md 3.1, 3.2, 3.3, 8.1, 8.2, 8.3 + Anexo A-03/A-04.
  • docs/discovery/02-aws-inventory.md §4 (baseline RDS legacy).
  • AWS Postgres 16 LTS docs.