Saltar a contenido

Connectors / Strategies

El Strategy Pattern es obligatorio para todos los conectores sociales y de contact center. Decisión inicial en ADR-0007; extensiones V1.1 en ADR-0014.

SDK base

packages/connector-sdk/ expone:

export interface OutboundStrategy<Cfg, Msg> {
  readonly name: string;
  readonly channel: Channel;
  configure(cfg: Cfg): Promise<void>;
  send(msg: Msg, ctx: SendContext): Promise<SendResult>;
  healthcheck?(): Promise<HealthStatus>;
}

export interface InboundStrategy {
  readonly name: string;
  verify(event: unknown): Promise<{ tenantId: string; raw: unknown }>;
  normalize(raw: unknown): CanonicalMessage;
}

Plus utilidades comunes: retry con jitter, circuit breaker, dedup, idempotency keys, logger Powertools wrapper.

Strategies activas en V1.1 (8)

Nombre Servicio host Tipo Notas
whatsapp-meta-cloud connectors-social Inbound + Outbound OAuth via Meta Cloud API
whatsapp-360dialog connectors-social Inbound + Outbound API key 360dialog
webchat-http inbound-router Inbound sync (ADR-0013)
five9-digital connectors-cc Inbound + Outbound basic auth + IP allowlist
ses-email outbound-dispatcher Outbound AWS SES, templates Handlebars
sns-sms outbound-dispatcher Outbound AWS SNS SMS
amazon-connect-chat connectors-cc Inbound + Outbound Amazon Connect Participant API
360dialog-templates outbound-dispatcher Outbound wrapper template management

Cómo agregar una strategy nueva

1. TDD primero

packages/connector-sdk/tests/contract/<strategy>.contract.test.ts
services/<host>/tests/unit/strategies/<strategy>.test.ts

Cubre:

  • happy path send/receive.
  • error mapping (4xx/5xx → DomainError vs IntegrationError).
  • idempotency (mismo clientMessageId no duplica).
  • multi-tenant (no cross-talk entre tenants).
  • secrets fetch falla → fail-fast, no loggea contenido del secret.

2. Implementación

services/<host>/src/strategies/<strategy>/
  index.ts            # exporta la strategy
  client.ts           # DI del cliente AWS/HTTP (testeable)
  mapper.ts           # raw ↔ CanonicalMessage
  schemas.ts          # Zod del payload del proveedor
  • DI del cliente: el constructor recibe el client, no lo construye. Permite mockear en tests.
  • Errores: extender BaseError de @zengine/errors. Nunca throw "string".
  • Idempotency: usar clientMessageId propagado desde el flow-engine. Tabla DDB compartida zen-dev-dedup con TTL 24h.

3. Registro

En el handler del servicio host:

import { whatsappMetaCloud } from './strategies/whatsapp-meta-cloud';

const registry = new StrategyRegistry();
registry.register(whatsappMetaCloud);

El registry resuelve por nombre desde la config del tenant (zen-dev-tenantsSTRATEGY#<name>).

4. Secret + IAM en Terraform

infra/envs/dev/connectors_v11.tf (o el módulo correspondiente):

resource "aws_secretsmanager_secret" "<strategy>" {
  name       = "/zen/dev/<strategy>/<tenant-or-shared>"
  kms_key_id = aws_kms_key.platform.arn
  tags       = local.tags
}

resource "aws_iam_role_policy" "<service>_secret_read" {
  role = module.<service>.role_name
  policy = data.aws_iam_policy_document.secret_read.json
}

5. ADR

Si la strategy introduce un patrón nuevo (nuevo canal, nueva dependencia externa, cambio de contrato), agregar ADR en docs/adr/. Si es extensión de patrón existente, basta una entrada en ADR-0014.

Circuit breaker y retry

El connector-orchestrator envuelve cada strategy en circuit breaker (estado en SSM Parameter Store por strategy+tenant) y retry con backoff exponencial (3 intentos, jitter ±20%). Failures persistentes → DLQ + evento Outbound.Failed.

Healthchecks

Cada strategy implementa healthcheck() opcional. Un Lambda connector-orchestrator programado (EB schedule) lo invoca cada 5min y publica Channel.HealthChanged cuando varía.