Skip to content

Plan de implementación — Billing-driven dunning

Fase A · Billing emite eventos (2-3 días)

  1. Migración: tabla billing_events_outbox (patrón outbox) con id, type, payload, created_at, published_at.
  2. Trigger SQL en invoices que inserta en outbox cuando:
    • status cambia a overdue.
    • status cambia a paid.
    • status cambia a suspended.
  3. Worker billing lee outbox y publica a Kafka impulse.billing.events, marca published_at.
  4. Topic + schema versionado (schema_version=1 en payload) para evolución futura.

Fase B · CRM consume (1 día)

  1. Agregar consumer group crm-api-billing-events en internal/consumers/billing_events.go.
  2. Registrar en cmd/api/main.go.
  3. Mapear eventos → handlers del DunningService.
  4. Tests de integración con testcontainers Kafka.

Fase C · Template nuevo (1 día + review Meta)

  1. Crear payment_received en Meta Business Manager.
  2. Enviar a review (suele tardar 24-48h).
  3. Mientras, desarrollar el handler HandlePaid con fallback a "mensaje de texto libre" por si no se aprueba el template.

Fase D · Ledger + observabilidad (1 día)

  1. Colección Mongo dunning_ledger.
  2. Endpoint GET /v1/contacts/:id/dunning-history.
  3. Widget en la vista del contacto (tab Cobranza) mostrando las últimas 10 notificaciones.
  4. Dashboard Grafana: mensajes enviados por día, tasa de respuesta (pagos < 24h post-mensaje), cooldowns saltados.

Fase E · Cutover (0.5 día)

  1. Deploy billing con outbox + worker (silencioso, nadie consume).
  2. Deploy CRM con consumer (silencioso, flag DUNNING_EVENT_MODE=shadow) — lee eventos y los loggea pero no envía.
  3. Validar durante 48h que shadow mode match con el polling.
  4. Flip DUNNING_EVENT_MODE=primary, DUNNING_POLLING_FALLBACK=true (keep as safety net).
  5. Dos semanas después, DUNNING_POLLING_FALLBACK=false.

Riesgos

  • Outbox lag: si el worker billing se cuelga, los overdue no se notifican. Mitigación: alerta Prometheus sobre max(now - billing_events_outbox.created_at WHERE published_at IS NULL) > 15min.
  • Orden de eventos: si paid llega antes que overdue (carrera), el handler debe tolerarlo (check estado actual antes de actuar).
  • Duplicados: Kafka at-least-once + idempotency_key → OK.

Definición de done

  • [ ] Zero polling en prod (flag off 14 días).
  • [ ] Métrica dunning_notification_latency_seconds con p95 < 60s (desde invoice.overdue a message.sent).
  • [ ] payment_received aprobado y en uso real.
  • [ ] Dashboard Grafana operativo con las 4 métricas clave.

Impulse Tech · Documentación interna