Saltar a contenido

ADR-0009 · Migración legacy → ambiente nuevo: cutover total con freeze + parity fixtures

  • Status: Accepted (revisado 2026-05-13)
  • Date: 2026-04-30 · Revisado: 2026-05-13
  • Deciders: Cristian Fernández (Zerviz Group)
  • Related: ADR-0006 (CI/CD parity gate), docs/discovery/00-phase1-prerequisites.md 5.1, 5.2, 5.3, docs/discovery/08-legacy-delta.md.

Revisión 2026-05-13 — Cuenta única + delta de inventario

  • Cuenta AWS Fase 2: se reutiliza la cuenta existente 450972188274 (no se crea ze-dev aún). Recursos nuevos llevan prefijo zen-{env}-* y tag Project=zengine-v2. Promoción a cuenta dedicada se hace tras la primera versión revisada.
  • Legacy intacto: los recursos ze-* y el código ZengineDEV no se tocan. El "freeze" pasa a significar "no se modifica desde el monorepo nuevo"; el owner sí puede seguir evolucionando el legacy en paralelo.
  • Delta de inventario obligatorio: antes de iniciar build, se ejecuta el re-inventario del legacy (código + AWS) y se publica docs/discovery/08-legacy-delta.md. Cualquier funcionalidad nueva detectada se evalúa como entrada al backlog de Fase 2 (no se copia código).
  • Cutover: se mantiene la estrategia de cutover total con parity gate. La diferencia: el switch DNS no es a otra cuenta, sino a los endpoints nuevos zen-* dentro de la misma cuenta.

Context

Asentado: cutover total con freeze del legacy una vez completado el ambiente nuevo (no strangler fig). Parity tests basados en fixtures sintéticas + flujos IPLACEX (no grabación de tráfico real, ya que no hay tráfico real en dev y no hay prod del que grabar — checklist U-03). Todo puede evolucionar; el ambiente nuevo NO debe replicar 1:1 el legacy.

Decision

Estrategia

  1. Freeze del legacy declarado en el día 1 de Fase 2 (post-aprobación de Fase 1). PR-rule en GitHub bloquea cambios a aws/step-1-read-api/ y src/ en ZengineDEV. Excepción: hotfixes críticos de seguridad, autorizados por owner.
  2. Construcción del ambiente nuevo en la cuenta existente 450972188274 con prefijo zen-{env}-* (ver Revisión 2026-05-13; promoción a cuenta dedicada en fase posterior), siguiendo ADRs 0001..0008. Greenfield total — no se reutiliza código del legacy salvo los 2 patrones identificados (ZE-D360-Sender, ZE-conexion).
  3. Parity gate (workflow parity-gate.yml):
  4. Fixture set IPLACEX-demo: 50 escenarios end-to-end (inbound WhatsApp → flow → Five9 → outbound respuesta → encuesta).
  5. Cada fixture tiene input (payload de webhook) y expected_outputs (eventos publicados, mensajes outbound, estado final en flow-state).
  6. Se ejecuta en qa contra el ambiente nuevo. Falla = bloquea cutover.
  7. Cutover manual en ventana de mantenimiento:
  8. Switch DNS / API GW custom domain del cliente: el legacy sigue en *.zengine.online (sin tocar). El nuevo expone zen.zervizdev.com (frontal cliente) y zen-admin.zervizdev.com (admin interno), con subdominios por env (dev.*, qa.*). El cutover redirige cuando el owner lo decida; mientras tanto ambos coexisten en distintos dominios.
  9. Webhooks Meta/360/Five9 reapuntados al ambiente nuevo.
  10. Confirmación con smoke test sintético (1 conversación end-to-end por canal).
  11. Rollback plan: DNS revierte al endpoint legacy. Ambiente legacy permanece intacto y monitoreado durante 90 días post-cutover; si pasa el período sin incidentes, se decommissiona vía PR de Terraform import + delete.

Lo que NO migramos

  • Código legacy: descartado por completo. Sólo se rescatan 2 patrones (D360-Sender + adjuntos S3) como referencia para packages/connector-sdk.
  • chat-flow.json legacy (4 versiones divergentes — R-15): se reconstruye desde cero con esquema multi-tenant + Zod en packages/flow-schema.
  • DynamoDB chat-widget-auth-sessions (605 items, sin TTL): no se migra. El tier lógico arranca con ze-{env}-five9-sessions vacío.
  • RDS ze-db: no se migra data. Esquema nuevo desde cero; data productiva no existe (es dev). En Fase 2 se documenta el esquema nuevo en docs/data/postgres-schema.md.
  • S3 ze-engine legacy: queda intacto bajo freeze. Bucket nuevo ze-{env}-data/flows/ arranca vacío.
  • CloudFront legacy: distribuciones huérfanas se documentan pero NO se tocan (regla base).

Lo que SÍ migramos

  • Funcionalidad (no código): inbound WhatsApp/360, webchat, Five9 handoff, outbound campañas, encuestas NPS, builder admin de flows.
  • Patrones de integración: documentados en docs/discovery/03-code-aws-crosswalk.md §4.1.bis.
  • Catálogo de proveedores: Meta Cloud API, 360dialog, Five9, OpenAI (variables y modos de uso).
  • Catálogo de plantillas WhatsApp: se reconstruye en tenant-mgmt desde el dashboard del builder.

Parity fixtures (estructura)

tests/parity/fixtures/iplacex-demo/
├── 01-whatsapp-inbound-greeting.json
├── 02-whatsapp-flow-decision-tree.json
├── 03-handoff-to-five9.json
├── 04-outbound-template-broadcast.json
├── 05-encuesta-nps-completion.json
├── ...

Cada fixture tiene: - input: payload normalizado + tenant_id IPLACEX-demo + timestamp determinístico. - expected_outputs.events: eventos esperados a EventBridge (orden, tenant_id, schema). - expected_outputs.outbound: requests esperadas a externos (mockeados en CI). - expected_outputs.state: estado esperado en DDB después.

Consequences

Positive

  • Sin overhead de strangler fig (no shadow traffic, no parity-online).
  • Greenfield permite refactor profundo (multi-tenant, RLS, KMS por tenant, etc.) sin restricciones del legacy.
  • Rollback simple = DNS switch.

Negative

  • Cutover en ventana = downtime breve (esperado < 15 min). Aceptable porque dev no tiene tráfico real.
  • Si fixtures IPLACEX no cubren un caso real futuro, lo descubrimos post-cutover. Mitigación: fixture set crece durante Fase 2-5.

Alternatives considered

  • Strangler fig: rechazado por el owner (5.1). Razón: legacy frozen, no vale la pena coexistencia.
  • Cutover por canal: rechazado, implica mantener ambos ambientes activos en simultáneo.
  • Parity con tráfico real grabado: rechazado (no hay tráfico real).

Tenant-isolation impact

  • Fixtures incluyen iplacex-demo y zerviz-internal. Tests aseguran cero leak entre fixtures.

Blast radius

  • Cutover fallido = rollback DNS. RPO 0 / RTO < 30 min.

Cost note

  • Sin costo extra (fixtures viven en CI).
  • Mantener legacy 90 días post-cutover: ~ USD 50/mes (sin tráfico).

ISO 27001 controls touched

  • A.12.5.1 (instalación de software en sistemas operativos): cutover documentado.
  • A.14.2.9 (testing de aceptación): parity gate.
  • A.17.1.2 (implementación de continuidad): rollback plan.

Sources

  • docs/discovery/00-phase1-prerequisites.md 5.1, 5.2, 5.3.
  • docs/discovery/03-code-aws-crosswalk.md §4.1.bis (patrones rescatables).
  • ADR-0006 (CI/CD parity gate).