Mapa vivo da plataforma (gerado de /api/system/catalog federado — nunca desenhado à mão)
SPA React + AntD Pro · PWA · PMP Manager (plano de controlo)
API GATEWAY :443 — TLS · JWT RS256 · rate-limit/tenant · x-request-id · /api/v1
svc-workflow :3050
Motor Maker-Checker central · SoD · delegações · escalonamento por prazo · Central de Aprovações
EVENT BUS — PG Outbox + LISTEN/NOTIFY (→ NATS)
Envelope v1 · fat events · inbox idempotente · retenção 90d · replay
PostgreSQL 16 — 1 cluster · schema por serviço · role PG por serviço (JOIN cross-módulo = impossível) · RLS por tenant em todos · pgAudit em payroll/discipline · PgBouncer(tx) · pgBackRest PITR
Regra 1 — Isolamento
Nenhum serviço lê o schema de outro. Integração só por eventos (assíncrono) ou API via gateway (síncrono).
Regra 2 — Catálogo verificável
Cada serviço arranca só se manifesto ≡ implementação (Module Registry). O mapa acima é gerado, não documentado.
Regra 3 — Strangler Fig (re-sequenciado, I49)
F1 = M0 svc-hr (fonte única do colaborador nasce PRIMEIRO) → F2 time → F3 discipline+perf/train → F4 recruit → F5 payroll (shadow-run diff=0). O monólito morre por estrangulamento, não por big-bang.
Módulos da aplicação → serviços que os servem (divisão CORE v2 · I49/I50/I53/P11 · fonte: docs/ARCHITECTURE_MACRO_V2.md)
Como ler: 1 módulo de negócio = 1 bounded context = 1 serviço com schema PostgreSQL próprio (excepção: M3 tem 2 serviços; M6 é a plataforma transversal). Nenhum serviço lê o schema de outro — integração só por eventos ou API via gateway.
Tecto para 2 devs (emenda P11): 9 serviços de domínio + svc-report read-only + gateway. Schemas PG: hr, org, ged, time, pay, perf, train, recruit, discipline, wf, audit, report — todos com RLS por tenant.
Central de Aprovações (svc-workflow — única fila para TODOS os módulos)
7
Aguardam a minha aprovação
2
Em atraso (SLA excedido)
3
Delegadas a mim (férias de M. Costa)
41
Concluídas este mês
| Módulo | Operação | Cadeia Maker-Checker | SLA | Ação |
|---|
Catálogo de Módulos (GET /api/system/catalog — artefacto vivo; usado também pelo PMP Manager p/ licenciamento)
$ npm run verify:catalog # corre em CI e no arranque de cada serviço
✅ Catálogo VERIFICADO: 6 módulo(s), 38 rota(s), 9 workflow(s).
— rota não declarada, dependência em falta, workflow inválido ou tabela sem dono ⇒ exit 1 (o serviço NÃO arranca)
Barramento de Eventos (monitor do outbox — quem alimenta quem)
| Evento | Produtor | Consumidores | Estado |
|---|
Envelope v1 (congelado — dec. B9)
{
"event_id": "0192f3a1-…", // uuid v7
"event_type": "time.timesheet.closed",
"version": 1,
"tenant_id": "…",
"occurred_at": "2026-09-30T23:59:00+01:00",
"actor": { "user_id": "…", "role": "rh_admin" },
"payload": { /* FAT: tudo o que o consumidor precisa */ }
}
Garantias
- Transacional: evento gravado na MESMA tx do dado (outbox)
- At-least-once + inbox UNIQUE(event_id) = efetivamente once
- Retenção 90 dias → replay para serviços novos
- LISTEN/NOTIFY p/ latência + polling crash-safe
- Migração p/ NATS JetStream: só o relay muda
Trilha de Auditoria (svc-audit — append-only, particionada por mês, pgAudit em leituras sensíveis)
Qualidade & Release (SonarQube + gates CI — qualidade por serviço, merge bloqueado se gate falhar)
SonarQube — Quality Gate "GORO Enterprise" por serviço
| Serviço | Gate | Coverage novo | Duplicação | Vulns novas | Dívida | Maior ficheiro |
|---|
Pipeline CI — PR #214 (svc-payroll: rubrica subsídio noturno)
- Gitleaks + Semgrep (regras GORO) · 41s
- tsc strict + dependency-cruiser (fronteiras) · 1m02
- verify:catalog — manifesto ≡ implementação · 12s
- Vitest + Testcontainers PG16 (RLS · SoD · outbox) · 3m18
- Pact: contrato time.timesheet.closed v1 válido · 29s
- SonarQube Quality Gate (payroll: coverage ≥ 90%)…
- Review humana — 2 aprovações (regra payroll/discipline)
Plano 180 dias (I55: 120 dev + 30 rev + 15 testes + 15 polimentos) — progresso por sprint
Caminho crítico: svc-time → svc-payroll. Shadow-runs nos fechos ~d40 e ~d60; 3º fecho (d91-100) = GO/NO-GO do cutover payroll. Decisão de corte de âmbito (recruit MVP) até ao dia 45.
Shadow-run Payroll — fecho 2026-10 (motor PROD vs svc-payroll) · diff automático linha-a-linha
324
funcionários comparados
324
recibos idênticos
0,00 AOA
desvio total (líquidos)
2/3
shadows concluídos · falta fecho #3 (d91-100)
Infra & Deploy (decisão I40: Compose+Traefik agora · K8s-ready · Kubernetes por gatilhos pós-GA — KUBERNETES_ANALYSIS.md)
DEV · gorodev.chk.co.ao
● ONLINE · TLS A+
- Docker Compose v2 + overlay
compose.dev.yml - Dados sintéticos/anonimizados (dec. G38 — nunca PII real)
- Deploy automático no merge a
main(CI verde) - ZAP baseline nightly contra este ambiente
PROD · goro.chk.co.ao (a confirmar)
cutover d101-110
- MESMO compose · overlay
compose.prod.yml(réplicas + limites + secrets) - Deploy manual aprovado (tag assinada Cosign) · rollback < 2 min
- pgBackRest PITR (RPO 15 min) · restore-drill mensal · RTO 4h
Stack da VM Azure (Compose) — componentes de segurança/estabilidade adicionados na revisão pré-código
| Camada | Componentes | Estado |
|---|
Deploy rolling sem paragem — svc-payroll v2.3.1 → v2.3.2
- Imagem
sha-8f3a21cassinada (Cosign) · Trivy 0 críticas - Migração expand (coluna nova, sem DROP) · job isolado OK
- Réplica B → v2.3.2 ·
/readyz✓ · Traefik roteia - Réplica A: drain (SIGTERM · 12 pedidos in-flight)…
- Smoke automático · alerta se 5xx > 1% → rollback automático
Downtime: 0s. Kill-switch Unleash disponível (rollback por toggle, sem deploy).
Kubernetes — decisão I40 e gatilhos de migração
Matriz (ponderada): Compose+Traefik 8.5 · Swarm 8.0 · K3s 7.2 · AKS 6.3 — curva K8s (3-6 sem.) incompatível com o caminho crítico payroll nos 90 dias.
Contrato K8s-ready K1-K9 em vigor desde o dia 1: 12-factor · stateless · /healthz+/readyz · graceful SIGTERM · imagens non-root · logs stdout JSON · DNS por nome · migrações fora do boot · limites de recursos → migração futura = helm install, não refactor.
Gatilho 1
carga exige 2º nó
Gatilho 2
SLA multi-nó contratual
Gatilho 3
SRE contratado
Reavaliação: dia 120 (GA) e a cada tenant enterprise novo. Caminho: K3s (2-3 VMs, soberania) → AKS.