architecture
# Architecture ## Papel do serviço O Communications Service é o motor operacional de comunicações assíncronas da plataforma. Direção-alvo: o serviço deve evoluir de motor operacional para central de comunicação da plataforma. Isso inclui inbox, preferências, remetentes, templates operacionais, delivery ledger, status, replies e enforcement de supressões. A decisão está registrada em [`ADR-002`](../adr/ADR-002-communications-domain-and-postgres.md) e detalhada em [`communications-domain-roadmap.md`](communications-domain-roadmap.md). Essa direção não muda automaticamente o caminho atual das notificações comuns. Enquanto não houver estratégia equivalente para leitura/realtime, o fluxo PocketBase continua sendo o contrato de compatibilidade. Comunicações da própria Ailian também continuam podendo usar a identidade/domínio da Ailian. Ele faz: - ingestão de notificações via API interna - scan de reminders - enqueue e processamento de jobs - retries com backoff - dispatch de notification deliveries - envio de push - observabilidade técnica ## Providers de email Estado atual: email usa Resend quando `RESEND_API_KEY` está configurada. Direção-alvo: Resend deve ser tratado como adapter inicial, não como fronteira de domínio. O Communications deve depender de um `EmailProviderAdapter` e resolver `ProviderAccount`, `SendingPool` e `SenderIdentity` antes do envio. Isso permite manter Resend para transacional da Ailian e, no futuro, conectar SMTP, SMTP2GO, Amazon SES, múltiplas contas Resend ou outro provider sem mudar o contrato dos produtores. Implementação atual: `ResendProvider` usa `EmailProviderAdapter` para a chamada técnica e `EmailSendingIdentityPort` para resolver remetente. Com `DATABASE_URL`, identidades vêm de `communications.sender_identities`. Sem Postgres, `EMAIL_SENDING_IDENTITIES` é o adapter estático. `RESEND_DEFAULT_FROM` continua como fallback para comunicação da própria Ailian. Domínios de cliente informados em `payload.email.from` precisam existir com `status=verified`, escopo compatível e finalidade permitida. Templates também ficam atrás de `EmailTemplateRegistryPort`. Com Postgres, o catálogo vem de `communications.communication_templates` e versões publicadas. Os templates locais atuais foram seedados com `artifact.renderer=local`, então o provider depende da porta e a renderização local segue como engine transitória. ## O que fica no PocketBase Estado atual: o PocketBase continua como fonte de verdade de domínio: - `notifications` - `notification_recipients` - `notification_deliveries` - `notification_preferences` - `push_devices` - `reminders` - `reminder_deliveries` Direção-alvo: esses dados deixam de ser tratados como domínio canônico do PocketBase principal. O Communications deve passar a persistir seu domínio em Postgres, mantendo PocketBase apenas como adapter/projeção transitória durante a migração. Implementação atual: Postgres é opcional via `DATABASE_URL`. O runtime cria um client somente quando a variável existe e expõe o estado no `/ready`. A migração inicial em `migrations/001_communications_domain_foundation.sql` cobre os subdomínios novos, `migrations/002_seed_local_email_templates.sql` semeia os templates locais atuais, mas a inbox e os deliveries atuais continuam no PocketBase. A primeira entrada de Postgres deve priorizar subdomínios novos ou mal cobertos pelo PocketBase atual, como sender identities, sender domains, template registry, delivery ledger ampliado e bulk runs. A inbox só deve migrar depois de uma decisão explícita sobre realtime e consumo pelo front/BFF. ## O que fica no Redis O Redis segura apenas o estado efêmero operacional: - filas BullMQ - locks de idempotência - jobs recorrentes ## Fronteira de acesso - browser não chama o Communications Service diretamente - o serviço é interno - rotas administrativas exigem `Authorization: Bearer <SERVICE_AUTH_TOKEN>` - `n8n` e outros produtores trusted devem preferir `POST /internal/notifications` ## Ingestão de notificações Contrato recomendado: - produtor chama a API interna - o serviço aplica `notification_preferences` - cria `notifications`, `notification_recipients` e `notification_deliveries` - enfileira imediatamente o que já estiver elegível Isso reduz acoplamento com o schema do PocketBase e centraliza: - defaults - dedupe - idempotência - fan-out - política de preferência por usuário ## Intervalos padrão - `REMINDER_SCAN_EVERY_MS = 30000` - `NOTIFICATION_SCAN_EVERY_MS = 30000` - `JOB_ATTEMPTS = 5` - `JOB_BACKOFF_BASE_MS = 5000`