# Arquitetura dos Sistemas Satélites do Monorepo Monetarie

Data: 2026-07-10. Escopo: `npc/`, `sta/`, `clst/`, `backoffice/`, `docs-portal/`, `mobile/`, `packages/`, `etl/`, `migration/`, `benchmark/`, `audit/`, `nginx/`. Levantamento por leitura de código com evidência `arquivo:linha`, mais verificação viva (somente leitura) dos serviços ECS nos clusters `monetarie-greenfield-homolog` e `monetarie-greenfield-prod` (conta 990933657879, sa-east-1) em 2026-07-10.

Convenções do documento: valores monetários dos satélites Elixir são sempre inteiros em centavos (`bigint`); PKs são `binary_id` (UUID) salvo indicação; hosts internos em homolog levam sufixo `-h` e em produção ficam sem sufixo (`infra/aws/greenfield/variables.tf:7-10`, `envs/prod.tfvars:23`).

## Sumário

1. [NPC (Nova Plataforma de Cobrança, boletos Núclea)](#1-npc)
2. [STA (Sistema de Transferência de Arquivos BACEN)](#2-sta)
3. [CLST (Clearing and Settlement)](#3-clst)
4. [Backoffice](#4-backoffice)
5. [Docs-portal](#5-docs-portal)
6. [Mobile (Flutter)](#6-mobile)
7. [Packages (mobile-ui)](#7-packages)
8. [ETL](#8-etl)
9. [Migration](#9-migration)
10. [Benchmark](#10-benchmark)
11. [Audit](#11-audit)
12. [Nginx](#12-nginx)
13. [Infra ECS: homolog vs produção](#13-infra-ecs)
14. [Tabela resumo final](#14-tabela-resumo)

---

## 1. NPC

### 1.1 Propósito

NPC é o conector da Monetarie com a Nova Plataforma de Cobrança, o ecossistema Núclea de boletos (PCR, CMP, SILOC). Evidências: `npc/docs/plans/2026-02-02-npc-boleto-integration-guide.md:53-55` define o termo; `npc/README.md:17,40` descreve "Boleto payment integration platform connecting Monetarie NPC APIs to Brazil's Nuclea financial infrastructure (PCR/CMP/SILOC)".

Funções (`npc/README.md:42-48`, `npc/CLAUDE.md:17`):

- Ciclo de vida do boleto: criação, registro no PCR, rastreio, cancelamento, expiração.
- Liquidação: download e parsing de arquivos ACMP615 da Núclea, conciliação de pagamentos, posição líquida por ciclo (manhã e tarde).
- Integração bidirecional: REST inbound (Monetarie Central, auth X-API-Key), webhooks outbound com HMAC-SHA256 e barramento NATS com o Core.
- Monitoramento em tempo real via Phoenix Channels e configuração criptografada (Cloak).

Glossário Núclea em `npc/CLAUDE.md:166-179`: PCR (Plataforma Centralizada de Recebíveis), CMP (Módulo de Compensação), SILOC (liquidação diferida). Há resquícios da marca antiga "FluxiQ" em `npc/backend/cloudbuild.yaml` e `npc/simulator-frontend/vite.config.ts`.

### 1.2 Tech stack e estrutura

- `npc/backend/`: Elixir ~1.17 / Phoenix ~1.8.3 com Bandit (`npc/backend/mix.exs:8,48-61`), Ecto SQL 3.13 + Postgrex, Oban ~2.19, Guardian + bcrypt (JWT), cloak_ecto (AES-GCM-256), gnat ~1.8 (NATS), Req, e OTP `:ftp`/`:inets` para o cliente FTP do ACMP615 (`npc/backend/mix.exs:29,48-69`). Dockerfile fixa Elixir 1.17.3 / OTP 27 (`npc/backend/Dockerfile:4`).
- `npc/frontend/`: Vue 3.5 + Vite 7 + Pinia + vue-router + vue-i18n + Tailwind 4 + chart.js + cliente `phoenix` para WebSocket (`npc/frontend/package.json`).
- `npc/simulator-frontend/`: segundo app Vue 3 (`monetarie-npc-simulator`), painel do simulador Núclea (`npc/simulator-frontend/package.json`).
- `npc/docs-site/`: VitePress multi-idioma (pt default, en, zh-CN), título "Monetarie NPC API" (`npc/docs-site/.vitepress/config.ts`).
- Contextos principais de `npc/backend/lib/monetarie_npc/`: `boletos/` (contexto de 577 linhas com ciclo de vida completo), `settlements/` (conciliação + `acmp615_parser.ex`), `integrations/` (`pcr_client.ex` OAuth 2.0 + mTLS, `nuclea_ftp.ex` + pool FTPS fail-closed contra cadeia ICP-Brasil, `npc/backend/config/config.exs:89-120`), `nats/`, `mq/` (LDL/GEN simulados sobre NATS), `outbox/`, `webhooks/`, `monitor/`, `simulator/` (PCR, FTP, cenários, chaos), `rbac/`, `workers/`.

### 1.3 Banco de dados

Database dedicado `mon_npc` (`npc/backend/config/dev.exs:9`; `npc/docker-compose.yml` `POSTGRES_DB: mon_npc`; ECS injeta DB `mon_npc`, `infra/aws/greenfield/ecs.tf:216-234`). Prod real via `DATABASE_URL` com SSL (`npc/backend/config/runtime.exs:73-102`). Sem schema Postgres próprio: isolamento por database, tudo em `public`. Repo único `MonetarieNpc.Repo` (`npc/backend/config/config.exs:11`). 17 migrations em `npc/backend/priv/repo/migrations/`.

#### Dicionário de dados (mon_npc)

Tabela `boletos` (migration `20260202173135`, schema `npc/backend/lib/monetarie_npc/boletos/boleto.ex`):

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID do boleto |
| nosso_numero | varchar(20) NOT NULL, único | referência interna do boleto |
| barcode | varchar(44) | código de barras 44 dígitos (mod 11) |
| linha_digitavel | varchar(47) | linha digitável 47 dígitos |
| amount_cents | bigint NOT NULL | valor em centavos |
| due_date | date NOT NULL | vencimento |
| payer_document | bytea (encriptado) | CPF/CNPJ do pagador, AES-256-GCM determinístico (LGPD, migration `20260503150000`) |
| payer_document_hash | bytea | blind index HMAC-SHA256 para busca por igualdade |
| payer_name / payer_name_encrypted | varchar(100) / bytea | nome do pagador (plaintext legado + versão cifrada, migration `20260508213316`) |
| payer_address / payer_address_encrypted | varchar(200) / bytea | endereço do pagador |
| beneficiary_ispb | varchar(8) | ISPB do beneficiário |
| beneficiary_name / beneficiary_name_encrypted | varchar(100) / bytea | nome do beneficiário |
| beneficiary_document / beneficiary_document_hash | bytea / bytea | CPF/CNPJ do beneficiário cifrado + blind index |
| status | varchar(20) default draft | draft, registered, paid, cancelled, expired (`boleto.ex:39`) |
| pcr_protocol | varchar(50) | protocolo devolvido pelo PCR no registro |
| registered_at / paid_at / cancelled_at | timestamp | marcos do ciclo de vida |
| metadata | jsonb default {} | dados livres |
| inserted_at / updated_at | timestamp(0) | timestamps |

Tabela `settlement_cycles` (migration `20260202173137`), ciclo diário de liquidação:

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID |
| cycle_date | date NOT NULL | data do ciclo |
| cycle_number | smallint NOT NULL | 1 = manhã, 2 = tarde; único por (date, number) |
| status | varchar(20) default pending | estado do processamento |
| acmp615_filename | varchar(255) | arquivo ACMP615 baixado |
| acmp615_received_at | timestamp | chegada do arquivo |
| records_total / records_processed / records_matched / records_unmatched | integer default 0 | contadores de conciliação |
| total_credits_cents / total_debits_cents / net_position_cents | bigint default 0 | posição líquida do ciclo |
| started_at / completed_at | timestamp | janela de processamento |

Tabela `settlements` (migration `20260202173138`), pagamento individual do ACMP615:

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID |
| boleto_id | FK boletos | boleto conciliado |
| cycle_id | FK settlement_cycles | ciclo de origem |
| paying_ispb | varchar(8) | ISPB do banco pagador |
| paid_amount_cents | bigint | valor pago |
| payment_date | date | data do pagamento |
| payment_channel | varchar(20) | canal de pagamento |
| authentication_code | varchar(50) | autenticação do pagamento |
| reconciliation_status | varchar(20) | matched, not_found etc. (`settlements.ex:138-155`) |
| reconciliation_diff_cents | bigint | diferença esperado vs pago |
| reconciled_at | timestamp | quando conciliado |
| raw_record | text | linha bruta do arquivo |

Tabela `audit_logs` (migration `20260202173139`), trilha imutável, retenção 5 anos, nunca limpa (`npc/backend/config/config.exs:67-68`): id UUID, entity_type varchar(50), entity_id binary_id, action varchar(50) NOT NULL, changes jsonb, previous_state jsonb, actor_type varchar(20), actor_id varchar(100), ip_address inet, user_agent text, inserted_at (sem updated_at).

Tabela `users` (migration `20260202174430`): id UUID, email único NOT NULL, password_hash (bcrypt) NOT NULL, name, role default user, active boolean default true.

Tabela `configurations` (migration `20260202180001`): id UUID; key única NOT NULL; value text (não secretos); encrypted_value bytea (secretos via Cloak); category NOT NULL (pcr, ftp, central, mq, schedule; `npc/CLAUDE.md:199-209`); value_type default string; description; updated_by_id FK users.

Tabela `webhook_deliveries` (migration `20260202180002`): id UUID, delivery_id uuid NOT NULL, event_type NOT NULL, payload jsonb NOT NULL, status default pending (pending, delivered, failed), attempts int, last_attempt_at, response_status int, response_body text, error_message text.

Tabela `api_requests` (migration `20260202180003`), log de requisições inbound: id UUID, request_id NOT NULL, method, path, source default central (central, frontend, internal), status_code, duration_ms, request_body e response_body jsonb, error_message.

Tabela `event_logs` (migration `20260202180004`), retenção 90 dias (`config.exs:70`): id UUID, direction NOT NULL (inbound, outbound, internal), event_type NOT NULL, status NOT NULL (success, error, pending), source (central, pcr, ftp, scheduler), target (central, pcr, database), request_id (índice na migration `20260202180005`), payload, response e metadata jsonb, duration_ms, error_message.

RBAC (migration `20260309100000`): `modules` (code único, name, icon, display_order, is_active, metadata), `features` (FK module_id, code único, feature_type, route_path, requires_permission), `groups` (code, is_system, is_active), `group_features` (flags can_view/create/edit/delete/approve/configure/export por grupo e feature), `user_groups` (user x group, is_primary). Seed em `npc/backend/priv/repo/seeds/rbac_seed.exs`.

`oban_jobs` (migration `20260202172632`, Oban v12): fila persistente de jobs (webhooks, outbox NATS, cron de liquidação 08:35 e 16:35 em `npc/backend/lib/monetarie_npc/jobs/fetch_settlement_files_job.ex`).

### 1.4 Portas

- Backend: dev 4020 (`npc/backend/config/dev.exs:29`), container EXPOSE 4020 (`npc/backend/Dockerfile:40`), runtime lê `PORT` (`npc/backend/config/runtime.exs:24-27`); no ECS roda com `PORT=4020` (`infra/aws/greenfield/ecs.tf:216-234`).
- Frontend admin: Vite dev 5177 (`npc/frontend/vite.config.ts`), container nginx 8080 (`npc/frontend/nginx.conf`).
- Simulator-frontend: Vite dev 5180 (`npc/simulator-frontend/vite.config.ts`).
- Atenção: README diz 4000/5173, o código real usa 4020/5177.

### 1.5 Integrações

- NATS (gnat, supervisor no boot, `npc/backend/lib/monetarie_npc/application.ex:32`): publica `monetarie.npc.boleto.{created,registered,paid,cancelled,modified,expired}`, `monetarie.npc.cycle.{started,completed}` e `monetarie.npc.protocol.processed` (`npc/backend/lib/monetarie_npc/nats/publisher.ex:97-133`); consome `monetarie.core.npc.*` e `npc.health.check` (`npc/backend/lib/monetarie_npc/nats/consumer.ex:7-10`), com DLQ (`consumer.ex:82-99`). Outbox transacional via Oban (ADR-008; `publisher.ex:86-94`) com guard de runtime e check Credo custom (`npc/backend/lib/monetarie_npc/credo_checks/outbox_atomicity.ex`).
- Núclea: PCR por HTTPS com OAuth 2.0 + mTLS (`npc/backend/lib/monetarie_npc/integrations/pcr_client.ex`; default homolog `https://api-hom.pcr.nuclea.com.br/v1`, `config.exs:80-87`); FTP/FTPS para ACMP615 (`integrations/nuclea_ftp.ex`).
- Monetarie Central: REST inbound `/api/v1/central/*` com X-API-Key (`npc/backend/lib/monetarie_npc_web/router.ex:86-101`) e webhooks outbound HMAC-SHA256 (`webhooks/webhook_client.ex`).
- "MQ" não é IBM MQ: é simulação sobre NATS em `monetarie.npc.mq.*` para LDL0006/0020/0021/0022 e GEN0015 (`npc/backend/lib/monetarie_npc/mq/mq_client.ex:3-25`). IBM MQ real com a Núclea segue pendente (gate G3, `npc/CLAUDE.md:11`).
- Simulador Núclea embutido no backend (`npc/backend/lib/monetarie_npc/simulator/`), com gate que dá `raise` no boot se habilitado em produção (`npc/backend/config/runtime.exs:56-71`).
- Não integra PIX/SPB diretamente; é dedicado a boletos.

```mermaid
graph LR
  Core["Core (Monetarie)"] -- "NATS monetarie.core.npc.*" --> NPC["npc-api :4020"]
  NPC -- "NATS monetarie.npc.boleto.* / cycle.*" --> Core
  Central["Monetarie Central"] -- "REST X-API-Key /api/v1/central/*" --> NPC
  NPC -- "webhooks HMAC-SHA256" --> Central
  NPC -- "HTTPS OAuth+mTLS (PCR)" --> Nuclea["Núclea PCR/CMP/SILOC"]
  Nuclea -- "FTPS ACMP615" --> NPC
  NPC --- DB1[("mon_npc")]
  UI1["npc-admin-ui :8080 (Vue 3)"] -- "REST/WS" --> NPC
  CLST1["clst-api"] -. "consome monetarie.npc.*" .- NPC
```

### 1.6 Estado

Funcional, não placeholder: 89 arquivos `.ex`, contextos de negócio completos, criptografia LGPD at-rest, circuit breaker, dedup, retry, RBAC. 20 arquivos de teste ExUnit + Mox e carga k6 (`npc/backend/k6/npc-load-test.js`). Marcado "Production Ready" com checklist completo (`npc/CLAUDE.md:388-421`). ECS vivo em 2026-07-10: homolog `npc-api:7` e `npc-admin-ui:6` com desired=1/running=1; produção com task-defs `monetarie-npc-api-prod:1` e `monetarie-npc-admin-ui-prod:1` registradas, mas serviços com desired=0 (provisionados e desligados). Deploy legado GCP/GKE (`npc/backend/cloudbuild.yaml`) está descontinuado; o alvo atual é ECS.

---

## 2. STA

### 2.1 Propósito

Conector bidirecional com o STA (Sistema de Transferência de Arquivos) do BACEN, via web service REST com HTTP Basic Auth (Manual STA Web Services v1.5, PDF na raiz `sta/Manual_STA_Web_Services.pdf`). Evidências: `sta/CLAUDE.md:16-18` e `sta/README.md:15`.

Operações implementadas em `sta/backend/lib/sta_connector/sta/client.ex` (GenServer de 2.098 linhas):

- Download: listagem de disponíveis (`client.ex:125`, GET `/arquivos/disponiveis`), download simples e streamed com resume por range/ETag (`client.ex:244,304,594`).
- Upload em duas fases: solicitação de protocolo (`client.ex:199`, POST `/arquivos`) e envio do conteúdo (`client.ex:530`, PUT `/arquivos/{protocolo}/conteudo`), com upload em partes e reconciliação de posição (`client.ex:681,758`).
- Confirmação de recebimento e mudança de situação (`client.ex:343,474`), consultas de protocolo e avançada (`client.ex:380,406`), troca e expiração de senha Sisbacen (`client.ex:436,458`).

Sistemas BACEN suportados: CCS, CIR, CMP, STR, SPI, CAM, LDL, DICT, JUD (`sta/backend/lib/sta_connector/sta/systems.ex:11`), com parsers XML reais por família em `sta/backend/lib/sta_connector/parsers/` (ccs com CCS0001 a CCS0012, astr, acir, acmp, alfl, aptx, agen).

### 2.2 Tech stack e estrutura

- `sta/backend/`: Elixir ~1.17 / Phoenix ~1.8.3 / Bandit, app `:sta_connector` v1.0.0 (`sta/backend/mix.exs:8-11,48-61`); Ecto SQL 3.13, Finch, SweetXml, gnat ~1.8, Oban ~2.18, bcrypt (`mix.exs:48-83`). Dockerfile Elixir 1.17.3 / OTP 27 (`sta/backend/Dockerfile:7`). Cerca de 200 arquivos `.ex`.
- `sta/frontend/`: Vue 3.5 + Vite 7 (`sta/frontend/package.json:14,33`), views Dashboard, Files, Logs, Metrics, Config, Login, Notifications; Pinia, i18n (pt, en, zh-CN), Tailwind.
- `sta/admin-portal/`: portal alternativo em React (estrutura `src/{api,components,context,hooks,pages}`; `sta/admin-portal/package.json:2`). O `sta/CLAUDE.md:30` o descreve como Vue, mas a estrutura é React.
- `sta/docs/`: VitePress multi-idioma. `sta/configs/` e `sta/scripts/` auxiliares.
- Contextos principais de `sta/backend/lib/sta_connector/`: `sta/` (cliente BCB, circuit breaker, rate limiter, password manager), `inbound/` (poller, router, worker), `outbound/` (uploader, worker com state machine), `parsers/`, `files/`, `nats/`, `outbox/`, `config/` (hot-reload), `admin/` (inclui simulador STA), `auth/` + `rbac/`, `metrics/`, `notifications/`, `workers/`, `webhooks/`.

### 2.3 Banco de dados

Database dedicado `mon_sta` (`sta/backend/config/dev.exs:9`; `sta/docker-compose.yml:13`; ECS injeta DB `mon_sta`, `infra/aws/greenfield/ecs.tf:236-261`). Prod via `DATABASE_URL` com SSL `verify_peer` (`sta/backend/config/runtime.exs:42-63`). 8 migrations em `sta/backend/priv/repo/migrations/`.

#### Dicionário de dados (mon_sta)

Tabela `processed_protocols` (migration `20260131000001`, schema `sta/backend/lib/sta_connector/files/processed_protocol.ex:76-97`), rastreio de transferências BCB:

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID |
| protocol_number | string NOT NULL, único | protocolo BCB |
| system_id | string NOT NULL | sistema BACEN (CCS, SPI etc.) |
| file_name | string NOT NULL | nome do arquivo |
| file_size | bigint | tamanho |
| content_hash | string | SHA-256 |
| status | string default pending | pending, downloading, processing, completed, failed, cancelled |
| direction | string NOT NULL | inbound ou outbound |
| route_id | string | rota de processamento configurada |
| parsed_data | jsonb | conteúdo parseado |
| error_message / error_code | text / string | erro |
| retry_count | integer default 0 | tentativas |
| processed_at / downloaded_at / confirmed_at | utc_datetime | marcos do ciclo |
| metadata | jsonb | metadados |
| inserted_at / updated_at | timestamps | |

Tabela `outbound_files` (migration `20260131000002`, schema `files/outbound_file.ex:94-129`), fila de upload para o BCB:

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID |
| request_id | string NOT NULL, único | idempotência |
| system_id | string NOT NULL | sistema BACEN |
| file_name | string NOT NULL | nome |
| file_path | string | caminho local |
| file_size / content_hash | bigint / string | tamanho e hash |
| mime_type | string default application/octet-stream | tipo |
| status | string default pending | pending, uploading, uploaded, confirming, completed, failed, cancelled, expired |
| protocol_number | string | protocolo após upload |
| upload_attempts / max_attempts | integer (0 / 3) | retry |
| last_error / last_error_code | text / string | erro |
| last_attempt_at / uploaded_at / confirmed_at / expires_at | utc_datetime | ciclo |
| callback_url / callback_headers | string / jsonb | webhook de conclusão |
| priority | integer default 0 | -100 a 100 |
| metadata | jsonb | |
| etag | string | resume de download (RFC 7232, migration `20260426150000`) |
| last_modified | utc_datetime | precondition |
| bytes_uploaded | bigint default 0 NOT NULL | bytes já aceitos pelo BCB (upload em partes) |

Tabela `retry_queue` (migration `20260131000003`, schema `files/retry_entry.ex`), retries com backoff exponencial: id UUID; protocol_id FK processed_protocols (delete_all); outbound_id FK outbound_files (delete_all); retry_count / max_retries (0 / 3); base_delay_ms / max_delay_ms / backoff_multiplier (1000 / 300000 / 2.0); next_retry_at / last_attempt_at; last_error / last_error_code; error_history (array de map); status default pending (pending, processing, completed, exhausted, cancelled); operation_type NOT NULL (download, upload, confirm, parse, route, callback); context jsonb. Constraints `must_have_reference` e `valid_retry_count`.

Tabela `config_overrides` (migration `20260131000004`, schema `admin/config_override.ex`), configuração com hot-reload: id UUID; key única NOT NULL (ex. `sta.timeout_ms`); value jsonb NOT NULL; value_type default json; description; enabled boolean default true; category (sta, poller, rate_limit, routes, system); requires_restart boolean; validation_schema jsonb; applied_at / applied_by; previous_value / change_reason; expires_at.

Tabela `users` (migration `20260309100000:14-26`, schema `auth/user.ex:27-40`): id uuid, email único, name, password_hash bcrypt, role default operator (super_admin, operator, auditor), status (active, inactive, locked), last_login_at, metadata.

RBAC (mesma migration): `modules`, `features`, `groups`, `group_features` (7 flags de permissão, único por grupo e feature), `user_groups` (is_primary), mesmo desenho do NPC.

`oban_jobs` (migration `20260427153455`, Oban v13): outbox NATS (fila `nats_publish`, `sta/backend/config/config.exs:92`) e cron `PasswordExpiryWorker` diário 06:00 BRT (`config.exs:100`).

Migration `20260309200000` padroniza timestamps para `timestamp(0)`.

### 2.4 Portas

- Backend: dev 4030 (`sta/backend/config/dev.exs:19`), prod/container 4000 (`sta/backend/Dockerfile:86,93`, runtime `PORT` default 4000, `runtime.exs:80`); no ECS roda com `PORT=4000` (`infra/aws/greenfield/ecs.tf:236-261`).
- Frontend: Vite dev 5178 com proxy `/api` e `/socket` para `localhost:4030` (`sta/frontend/vite.config.ts:13-20`), container nginx 8080 (`sta/frontend/nginx.conf:5`).

### 2.5 Integrações

- BACEN STA: hosts `https://sta-h.bcb.gov.br/staws` (homolog) e `https://sta.bcb.gov.br/staws` (produção) (`sta/backend/config/config.exs:58-59`), TLS fail-closed com cadeia ICP-Brasil (boot falha se `priv/certs/icp_brasil_ca_chain.pem` faltar, `sta/backend/lib/sta_connector/application.ex:178-222`), HTTP Basic (`client.ex:1211-1222`), rate limit do manual (120 consultas/min, 10 simultâneas, `client.ex:60-61`) e circuit breaker.
- NATS JetStream (prefixo `monetarie.sta.*`): publica `monetarie.sta.file.{received,processed,sent,error,uploaded,failed}` e `monetarie.sta.protocol.processed` (`sta/backend/lib/sta_connector/nats/publisher.ex:91-121`); consome `monetarie.sta.regulatory.*`, `monetarie.sta.file.*`, `monetarie.sta.sisbajud.*` e `sta.health.check` (`sta/backend/lib/sta_connector/nats/consumer.ex:20-25`). Outbox transacional via Oban (ADR-008, `publisher.ex:48-64`).
- Consumidor principal é o Core: `core/backend/lib/monetarie/infra/nats/stream_setup.ex:82` (stream com `monetarie.sta.>`); o Core publica upload regulatório (`core/backend/lib/monetarie/use_cases/regulatory/sta_delivery.ex:19`), CADOC (`use_cases/cadoc/sta_dispatcher.ex:15`), câmbio Sisbacen (`use_cases/cambio/sisbacen_adapter.ex:28`) e SISBAJUD (`use_cases/judicial/nats_handler.ex:43`), e consome os eventos de volta (`infra/nats/consumers/sta_consumer.ex:28-29`). Há também rota HTTP Core para STA em dev (`core/backend/config/dev.exs:150`, `http://sta-backend:4000`).
- SSO com o Core: plug valida JWT com issuer `monetarie-sso` e `target_system: "sta"` (`sta/backend/lib/sta_connector_web/plugs/sso_auth.ex:6-12`).
- Não há integração de código com `pix/`; em `spb/` só citação documental de imagens legadas (`spb/CLAUDE.md:222`).

```mermaid
graph LR
  Core2["Core (Monetarie)"] -- "NATS monetarie.sta.regulatory/sisbajud/file.upload" --> STA["sta-api :4000"]
  STA -- "NATS monetarie.sta.file.* / protocol.processed" --> Core2
  STA -- "HTTPS Basic + ICP-Brasil (staws)" --> BCB["BACEN STA (sta.bcb.gov.br)"]
  STA --- DB2[("mon_sta")]
  UI2["sta-admin-ui :8080 (Vue 3)"] -- "REST/WS" --> STA
  CLST2["clst-api"] -. "consome monetarie.sta.*" .- STA
```

### 2.6 Estado

Funcional e maduro: pipelines inbound/outbound completos, 50 endpoints REST (`sta/API-REFERENCE.md:176`), parsers extensos, resiliência (circuit breaker, rate limiter, retry queue, resume de transferências), 87 arquivos de teste (unit, integration, e2e, parsers, outbox) e carga k6. ECS vivo em 2026-07-10: homolog `sta-api:8` e `sta-admin-ui:6` com 1/1; produção com task-defs `:1` registradas e desired=0. Artefatos GKE/ProxMox no repositório são legados (`sta/CLAUDE.md:1-12`).

---

## 3. CLST

### 3.1 Propósito

CLST é o serviço de Clearing and Settlement (câmara de compensação e liquidação) da Monetarie: netting multilateral, janelas de liquidação, reconciliação cross-system e monitoramento de liquidez. Evidências: `clst/README.md:1-3`; `clst/lib/monetarie_clst/application.ex:2` ("Clearing and Settlement Chamber"); migration base em `clst/priv/repo/migrations/20260205120000_create_clst_tables.exs:2`.

É um satélite a jusante das cabines de pagamento e a montante do Core: consome eventos de PIX/SPI, NPC e STA via NATS (`clst/lib/monetarie_clst/nats/consumer.ex:58-72`) e liquida chamando a API de wallets do Core (`clst/lib/monetarie_clst/settlement/coordinator.ex:404-421`). Dois motores de netting com invariante soma-zero (`clst/lib/monetarie_clst/clearing/engine.ex:1-30`, `clst/lib/monetarie_clst/settlement/netting_engine.ex:1-44`), NDC Enforcer (Net Debit Cap via ETS, `clst/lib/monetarie_clst/risk/ndc_enforcer.ex`) e 4 estratégias de reconciliação (intradia, batch, position, obligation) despachadas por grupo SFN (`clst/lib/monetarie_clst/settlement/reconciliation_dispatcher.ex:33-38`).

### 3.2 Tech stack e estrutura

App Elixir único `:monetarie_clst` v0.1.0, Elixir ~1.17 (`clst/mix.exs:6-8`), Phoenix ~1.8.3 API-only com Bandit (`clst/mix.exs:35-38`, `clst/config/config.exs:19`), Ecto SQL 3.12 + Postgrex, Guardian (JWT compartilhado com o Core, `clst/CLAUDE.md:66-67`), Oban ~2.18, gnat ~1.8, Req (`clst/mix.exs:32-63`). Cerca de 10.700 linhas em 54 arquivos `.ex`. Sem frontend próprio (nenhum diretório de assets; CORS aberto para UIs externas, `clst/lib/monetarie_clst_web/endpoint.ex:33-49`); 21 endpoints REST (`clst/API-REFERENCE.md:90-99`).

Contextos de `clst/lib/monetarie_clst/`: `clearing/` (engine + handlers de ingestão `pix_handler.ex`, `npc_handler.ex`, `sta_handler.ex`), `settlement/` (coordinator GenServer com ciclo de 30s, netting_engine, reconciler, dispatcher, strategies), `liquidity/` (monitor + alerts), `risk/`, `nats/`, `outbox/` (ADR-008 com guard e check Credo), `workers/` (Oban cron: StaleSettlementWorker e LiquiditySnapshotWorker a cada 5 min, ReconciliationWorker horário, `clst/config/config.exs:55-72`), `schemas/`.

### 3.3 Banco de dados

Database dedicado `mon_clst` (`clst/config/config.exs:10`; `clst/docker-compose.yml:12`; ECS injeta DB `mon_clst`, `infra/aws/greenfield/ecs.tf:263-278`). Prod via `DATABASE_URL` (`clst/config/runtime.exs:4-13`). 6 migrations em `clst/priv/repo/migrations/`.

#### Dicionário de dados (mon_clst)

Tabela `clearing_batches` (migration `20260205120000:19-37`, schema `clst/lib/monetarie_clst/schemas/clearing_batch.ex`), lotes para netting:

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID |
| system | string NOT NULL | subsistema de origem: npc, pix, sta |
| batch_number | string NOT NULL | id do lote, único com system |
| status | string default pending | pending, processing, completed, settled, failed, cancelled |
| window_start / window_end | utc_datetime NOT NULL | janela de clearing |
| total_entries | integer default 0 | quantidade de entradas |
| net_amount | bigint default 0 | valor líquido após netting |
| metadata | map default {} | posições, total bruto, eficiência do netting (`engine.ex:339-345`) |
| inserted_at / updated_at | utc_datetime | |

Tabela `settlement_windows` (migration `20260205120000:42-60`, schema `schemas/settlement_window.ex`), períodos de liquidação:

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID |
| system | string NOT NULL | npc, pix, sta |
| window_type | string NOT NULL | realtime, batched, daily |
| starts_at / ends_at | utc_datetime NOT NULL | duração |
| status | string default open | open, closing, closed, settling, settled, failed, cancelled |
| settlement_amount | bigint default 0 | valor liquidado |
| participant_count | integer default 0 | participantes |
| metadata | map default {} | batch_id, posições |
| reconciled | boolean default false | flag do worker de reconciliação (migration `20260617120000`) |
| idempotency_key | string, único | dedup de pedidos de settle (migration `20260515100000`) |
| inserted_at / updated_at | utc_datetime | |

Tabela `settlement_entries` (migration `20260205120000:65-89`, schema `schemas/settlement_entry.ex`), débito/crédito individual:

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID |
| batch_id | FK clearing_batches (nilify) | lote |
| window_id | FK settlement_windows (nilify) | janela |
| participant_id | string NOT NULL | ISPB ou id do participante |
| system | string NOT NULL | npc, pix, sta |
| direction | string NOT NULL | debit ou credit |
| amount | bigint NOT NULL | valor em centavos, maior que zero |
| currency | string default BRL | moeda |
| reference_id | string NOT NULL | id da transação original (E2E PIX, boleto NPC) |
| reference_type | string NOT NULL | pix_transfer, pix_return, boleto etc. |
| status | string default pending | pending, cleared, settled, failed, cancelled |
| metadata | map default {} | num_ctrl, msg_id |
| inserted_at / updated_at | utc_datetime | único por (reference_id, reference_type, system), migration `20260515100000` |

Tabela `reconciliation_records` (migration `20260205120000:94-117`, schema `schemas/reconciliation_record.ex`), reconciliação contra o ledger do Core:

| Coluna | Tipo | Propósito |
|---|---|---|
| id | binary_id PK | UUID |
| system | string NOT NULL | npc, pix, sta |
| source_id / source_type | string (id NOT NULL) | transação no subsistema |
| target_id / target_type | string | entrada correspondente no Core |
| expected_amount | bigint NOT NULL | valor esperado |
| actual_amount | bigint NOT NULL | valor encontrado no Core |
| discrepancy | bigint default 0 | actual menos expected |
| status | string default pending | pending, matched, discrepancy, auto_resolved, manually_resolved |
| resolved | boolean default false | flag (migration `20260617120000`) |
| resolved_at / resolution_notes | utc_datetime / text | resolução |
| metadata | map default {} | |
| inserted_at / updated_at | utc_datetime | |

Tabela `liquidity_snapshots` (migration `20260205120000:122-140`, schema `schemas/liquidity_snapshot.ex`): id UUID; participant_id string NOT NULL; system (npc, pix, sta, all); available_balance bigint default 0 (não negativo); reserved_balance bigint default 0 (reservado para settlements pendentes); net_position bigint default 0 (pode ser negativa); snapshot_at utc_datetime NOT NULL; metadata.

Tabela `reconciliation_results` (migration `20260214300000:12-27`, schema `clst/lib/monetarie_clst/settlement/reconciliation_result.ex`), resultado por execução do motor v2: id UUID; clearing string NOT NULL (grupo SFN: STR, CMP, SEL etc.); strategy NOT NULL (intradia, batch, position, obligation); date NOT NULL; status Ecto.Enum default pending (matched, mismatched, pending, error); matched_count / mismatched_count / pending_count integer default 0; total_amount_matched / total_amount_mismatched bigint default 0; details map (mismatches, SLA, faixa de datas); started_at / completed_at utc_datetime_usec NOT NULL.

Tabela `liquidity_alerts` (migration `20260217100000:18-33`, schema `schemas/liquidity_alert.ex`): id UUID; participant_id NOT NULL; system (npc, pix, sta); level NOT NULL (warning, critical); available_balance bigint NOT NULL; reserved_balance / net_position bigint default 0; threshold bigint NOT NULL (limiar rompido); acknowledged boolean default false; acknowledged_at / acknowledged_by; metadata.

Tabela `netting_results` (migration `20260217100000:49-64`, schema `schemas/netting_result.ex`): id UUID; batch_id FK clearing_batches (nilify); window_id FK settlement_windows (nilify); system NOT NULL; participant_count / entry_count integer default 0; gross_debit_total / gross_credit_total bigint default 0; net_positions map (participant_id para valor líquido); netting_ratio float (eficiência); status default completed (completed, partial, failed); computed_at utc_datetime NOT NULL; metadata.

`oban_jobs` e `oban_peers` (migration `20260516100000`, Oban v12).

### 3.4 Portas

HTTP 4004 em dev e prod (`clst/config/dev.exs:10`, `clst/config/runtime.exs:27`, `clst/Dockerfile:72-73`, healthcheck em `:4004/health`), 4014 em test (`clst/config/test.exs:11`). ECS injeta `PORT=4004` (`infra/aws/greenfield/ecs.tf:263-278`).

### 3.5 Integrações

- NATS (consumidor pesado): consome `monetarie.npc.boleto.*`, `monetarie.npc.cycle.*`, `monetarie.npc.protocol.processed`, `monetarie.sta.file.*`, `monetarie.sta.protocol.processed`, `monetarie.spi.transaction.*`, `monetarie.spi.return.*`, `monetarie.spi.balance.*` e `monetarie.settlement.*` (`clst/lib/monetarie_clst/nats/consumer.ex:58-72`); publica `monetarie.clst.*` (settlement, clearing, reconciliation, liquidity; `clst/lib/monetarie_clst/nats/publisher.ex:8-28`); DLQ `planner.dlq.clst.failed` (`nats/dead_letter_queue.ex:5,24`). Outbox transacional (`publisher.ex:90-138`).
- HTTP com o Core via Req: `POST /api/v1/wallets/:id/withdraw` e `/deposit` na liquidação (`settlement/coordinator.ex:404,421`), `GET /api/v1/wallets/:id/balance` na reconciliação (`settlement/reconciler.ex:322,331`), readiness contra `#{core}/health` (`clst/lib/monetarie_clst_web/controllers/health_controller.ex:77`). Config `CORE_API_URL` / `CORE_API_TOKEN` (`clst/config/runtime.exs:49-52`); no ECS a task recebe `CORE_API_URL` (`infra/aws/greenfield/ecs.tf:263-278`).
- Fontes externas de reconciliação (SELIC/CETIP/B3, extrato BCB, compulsório RCO/ECR) são stubs explícitos (`settlement/strategies/position_strategy.ex:303-307`, `intradia_strategy.ex:224-246`, `obligation_strategy.ex:307-353`).

```mermaid
graph LR
  PIXc["cabine PIX (monetarie.spi.*)"] -- NATS --> CLST["clst-api :4004"]
  NPCc["npc-api (monetarie.npc.*)"] -- NATS --> CLST
  STAc["sta-api (monetarie.sta.*)"] -- NATS --> CLST
  CLST -- "NATS monetarie.clst.*" --> Core3["Core (Monetarie)"]
  CLST -- "HTTP wallets deposit/withdraw/balance" --> Core3
  CLST --- DB3[("mon_clst")]
```

### 3.6 Estado

Predominantemente funcional: motores de netting, coordinator, reconciler, liquidez e resiliência implementados de fato; as únicas partes stubbed são as bordas de extratos externos BCB/SELIC. Testes existem mas são majoritariamente rasos (~599 linhas em 6 arquivos; os substantivos são outbox, DLQ e money_path; sem testes de controllers, coordinator ou integração NATS/Core). ECS vivo em 2026-07-10: homolog `clst-api:7` com 1/1; produção `monetarie-clst-api-prod:1` registrada com desired=0. Lacuna observada: o `NDCEnforcer` é GenServer mas não está na árvore de supervisão (`clst/lib/monetarie_clst/application.ex:27-58`).

---

## 4. Backoffice

Dashboard administrativo geral (não específico de um satélite) para os sistemas financeiros: PIX, SPB, SPI, STA, Núclea, SISBAJUD (`backoffice/README.md:6-19`, `backoffice/CLAUDE.md`). Tech: Vue 3 (Composition API) + TypeScript 5.9 + Vuetify 3.11 + Pinia 3 + vue-router 4 + vue-i18n 11 + Vite 7, pnpm (`backoffice/package.json:14-35`); usa o cliente `phoenix` para channels.

Funcionalidades: 25 rotas em `backoffice/src/router/index.ts:6-148` e 17 features em `backoffice/src/features/` (accounts, alerts, audit, auth, command-center, cosif, dashboard, modules, regulatory, serena, settings, transactions, webhooks etc.).

Integração: fala com o Core API por `fetch` same-origin com prefixo `/api` (`backoffice/src/shared/services/api.ts:1`; `backoffice/src/stores/auth.ts:43,68`); em produção o nginx do container faz proxy de `/api` para `core-api-h.monetarie.internal:80` (`backoffice/nginx.conf:72-82`). Sem banco próprio. Portas: dev 5176 (`backoffice/vite.config.ts:17`), container 8080 com health `/health` (`backoffice/nginx.conf:12,65-69`, `backoffice/Dockerfile:37`).

Estado: completo, não placeholder. ECS vivo em 2026-07-10: homolog `backoffice:7` 1/1 e produção `monetarie-backoffice-prod:2` 1/1 (uma das duas UIs satélites já ligadas em prod). Acesso interno via `backoffice{-h}.monetarie.internal` (ALB interno, prioridade 180, `infra/aws/greenfield/alb-internal.tf:112-118`).

```mermaid
graph LR
  Operador["Operador (VPN interna)"] --> BO["backoffice :8080 (Vue 3 + nginx)"]
  BO -- "proxy /api" --> CoreAPI["core-api :4000"]
```

## 5. Docs-portal

Portal estático de documentação servido por nginx 1.27-alpine (`docs-portal/Dockerfile:1`, EXPOSE 8080). O `docs-portal/public/` tem só a landing page (`index.html` + `styles.css`); o conteúdo real é agregado no build: o Dockerfile copia `docs/`, `core/docs` + `core/docs-site`, `pix/docs`, `spb/docs`, `npc/docs-site`, `sta/docs` e `backoffice/docs` para `/usr/share/nginx/html/raw/...` (`docs-portal/Dockerfile:8-15`), com autoindex em `/raw/` (`docs-portal/nginx.conf:23-28`) e health em `/health` (`nginx.conf:18-21`).

Sem banco, sem backend. ECS vivo em 2026-07-10: homolog `docs-portal:6` 1/1 e produção `monetarie-docs-portal-prod:1` 1/1. Host `docs{-h}.monetarie.internal` (prioridade 190, `infra/aws/greenfield/alb-internal.tf:119-125`). Follow-up de segurança conhecido: takedown da exposição interna do docs-h segue pendente (memória do projeto).

```mermaid
graph LR
  Dev["Time (VPN interna)"] --> DP["docs-portal :8080 (nginx estático)"]
  Monorepo["docs de core/pix/spb/npc/sta/backoffice (build time)"] --> DP
```

## 6. Mobile

App Flutter `monetarie_mobile`, "Monetarie cooperative mobile banking application", v1.0.0+1, Dart ^3.10.1 / Flutter ^3.38.3 (`mobile/pubspec.yaml:1-4`). Dependências chave: dio (HTTP), go_router, flutter_secure_storage + sqflite_sqlcipher (armazenamento local cifrado), mobile_scanner (QR PIX), money2, otp + pointycastle, sentry_flutter, e o pacote local `monetarie_mobile_ui` (`mobile/pubspec.yaml:45-46`).

Whitelabel por flavors: `mobile/build_flavor.sh:12-35` injeta cada linha de `flavors/<flavor>.env` como `--dart-define`; flavors presentes: `monetarie.env` (CNPJ 46026562000105, `BASE_URL=https://coreapi-monetarie.vulci.com.br`) e `tenant_example.env` (template). Config lida em `mobile/lib/core/config/whitelabel_config.dart:42-44` e `mobile/lib/core/config/enviroment_key.dart:2-4`.

Integração: fala com o Core API (`$baseUrl/api`, `/api/auth`, `/api/v2/auth`, `/api/v2`; `mobile/lib/core/resources/api_endpoints.dart:15-18`, `mobile/lib/data/services/api/auth_api.dart:29`), mais ViaCEP externo (`mobile/lib/ui/pages/my_data/my_data_page.dart:500`). Estado: app maduro em camadas `lib/{core,data,domain,ui}` com onboarding PF/PJ, PIX, extrato, limites; tem `integration_test/`, `test/`, `maestro/`. Não é serviço ECS. Pendência conhecida do monorepo: ícone/splash nativos do rebrand (CLAUDE.md raiz).

```mermaid
graph LR
  App["mobile (Flutter, flavors whitelabel)"] -- "HTTPS /api, /api/v2" --> CoreAPI2["Core API (coreapi-monetarie.vulci.com.br)"]
  App --- UIkit["packages/mobile-ui (design system)"]
  App -- HTTPS --> ViaCEP["ViaCEP (externo)"]
```

## 7. Packages

`packages/README.md:1-5`: pacotes compartilhados. Único subpacote: `packages/mobile-ui/`, o design system Flutter `monetarie_mobile_ui` v0.0.1 ("Monetarie mobile design system - components, theme, and assets", `packages/mobile-ui/pubspec.yaml`): tema e tipografia (fonte Nunito, `lib/theme/coin_text_style.dart`, `app_theme.dart`), widgets e integrações web (flutter_inappwebview, flutter_svg, url_launcher). Consumido pelo `mobile/` via dependência de path. Sem banco, sem serviço, sem porta. Diagrama: ver o do item 6 (o pacote se pluga apenas no app mobile).

## 8. ETL

Ferramental operacional de migração e estudo de dados, não é serviço:

- `etl/docker-compose.yml:1-27`: Postgres 18 isolado local-only (`127.0.0.1:5544`, db `monbank_acc`) para restaurar o dump contábil do sistema concorrente monbank para estudo.
- `etl/legacy_hml_import/`: loader idempotente do histórico legado AutBank (PIX/SPB em SQL Server) para as tabelas vivas `mon_pix`/`mon_spb`; pipeline deltas, stage, project, verify com reconciliação ao centavo (`etl/legacy_hml_import/README.md:1-40`, orquestrado por `run.sh`).
- `etl/legacy_pix_spb/load_legacy_pix_spb.py`: variante Python (~104 KB) do mesmo import, já executada.
- `etl/study/`: estudo empírico do schema concorrente (`2026-06-25-monbank-acc-deep-study.md` + `monbank_acc_schema.sql`).

```mermaid
graph LR
  BAK["backups SQL Server AutBank"] --> ETL["etl (stage/project/verify)"]
  ETL --> PIXDB[("mon_pix")]
  ETL --> SPBDB[("mon_spb")]
  DUMP["dump monbank (concorrente)"] --> STUDY["etl/study (Postgres local :5544)"]
```

## 9. Migration

Stub: contém apenas `migration/README.md:1-5` ("Seeds/migrations de referência. ETL de backup FORA de escopo, Monetarie é greenfield"), nota de porte do blueprint com a identidade da instituição. Nenhum artefato executável. Não se pluga em runtime a nada; existe como reserva de lugar documental.

## 10. Benchmark

Suite de benchmark standalone (projeto Mix isolado, modelo AVIV `coreproviders/benchmark`) para medir o money path PIX-in do Core (`benchmark/README.md:1-16`, `benchmark/mix.exs:1-8`, app `:bench`, deps mínimas gnat + jason + telemetry, deliberadamente sem path dep no Core). Mede o pipeline `monetarie.spi.transaction.created` até ledger via spans de telemetry (coletor ETS em `benchmark/lib/bench/collector.ex`, percentis em `lib/bench/stats.ex`), com guarda anti-produção que bloqueia CIDR 10.50.*, hosts NATS internos e RDS (`benchmark/lib/bench/guard.ex`). Resultados versionados em `benchmark/bench-results/` (baseline loopback ~43k TPS, `benchmark/README.md:112-117`). Não é serviço ECS.

```mermaid
graph LR
  BENCH["benchmark (:bench, Mix standalone)"] -- "publica monetarie.spi.transaction.created" --> NATS["NATS JetStream"]
  NATS --> CoreP["Core PixConsumer/PixHandler"]
  CoreP -- "telemetry spans" --> BENCH
```

## 11. Audit

Acervo estático de evidências de auditoria do PIX Admin em homolog (2026-06-25): 9 screenshots numerados na raiz, PDFs (`Monetarie-PIX-Admin-Auditoria-2026-06-25.pdf`, `Catalogo_Defeitos_Cabine_PIX_Monetarie_2026-06-25.pdf`, `Relatorio_Validacao_PIX_Admin_Monetarie_2026-06-25.pdf`), `RELATORIO.html`, o markdown `audit/2026-06-25-auditoria-memoria-e-estado-consolidado.md` e os subdiretórios `i18n-evidence/` (7 PNGs) e `pix-admin-full-capture/` (manifest, report, screenshots). Sem código, sem runtime; serve à regra de validação por evidência (regra 11 do CLAUDE.md raiz).

## 12. Nginx

Configs de reverse-proxy para desenvolvimento local (`nginx/README.md:1-4`): `nginx/local/` traz 3 vhosts de admin UIs apontando para backends locais (`pix-admin.conf`, `spb-admin.conf`, `sta-admin.conf`). Sem relação com o nginx dos containers de UI (cada frontend tem seu próprio `nginx.conf`). Não é serviço ECS.

```mermaid
graph LR
  DevLocal["dev local"] --> NG["nginx/local (vhosts)"]
  NG --> PIXADM["pix-admin local"]
  NG --> SPBADM["spb-admin local"]
  NG --> STAADM["sta-admin local"]
```

---

## 13. Infra ECS

Um único root Terraform (`infra/aws/greenfield/`) serve homolog (10.45) e produção (10.50), selecionado por var-file (`infra/aws/greenfield/envs/prod.tfvars:12` define `app_vpc_cidr = "10.50.0.0/16"`). Os serviços são um mapa único: task-defs em `infra/aws/greenfield/ecs.tf:27-352` e target groups/hosts no ALB interno em `infra/aws/greenfield/alb-internal.tf:1-131`. Em prod o tfvars mantém `create_ecs_services = false` (`envs/prod.tfvars:77`): os serviços de aplicação de produção foram criados na Fase 6 fora do apply padrão (promoção por digest), o que confere com o estado vivo abaixo.

Definições dos satélites (evidência):

| Serviço ECS | Porta | Health | Hosts internos | ECR | Evidência |
|---|---|---|---|---|---|
| npc-api | 4020 | /health | `npcapi{-h}` / `npc-api{-h}` | monetarie/npc-api | `ecs.tf:216-234`; `alb-internal.tf:33-42` |
| npc-admin-ui | 8080 | /health | `npcadmin{-h}` | monetarie/npc-admin-ui | `ecs.tf:320-327`; `alb-internal.tf:98-104` |
| sta-api | 4000 | /health | `staapi{-h}` / `sta-api{-h}` | monetarie/sta-api | `ecs.tf:236-261`; `alb-internal.tf:43-52` |
| sta-admin-ui | 8080 | /health | `staadmin{-h}` | monetarie/sta-admin-ui | `ecs.tf:328-335`; `alb-internal.tf:105-111` |
| clst-api | 4004 | /health | `clstapi{-h}` / `clst-api{-h}` | monetarie/clst-api | `ecs.tf:263-278`; `alb-internal.tf:53-62` |
| backoffice | 8080 | /health | `backoffice{-h}` | monetarie/backoffice | `ecs.tf:336-343`; `alb-internal.tf:112-118` |
| docs-portal | 8080 | /health | `docs{-h}` | monetarie/docs-portal | `ecs.tf:344-351`; `alb-internal.tf:119-125` |

Estado vivo verificado em 2026-07-10 (`aws ecs describe-services`, somente leitura):

- Homolog (`monetarie-greenfield-homolog`): todos os 7 com desired=1, running=1: `npc-api:7`, `npc-admin-ui:6`, `sta-api:8`, `sta-admin-ui:6`, `clst-api:7`, `backoffice:7`, `docs-portal:6`.
- Produção (`monetarie-greenfield-prod`): os 7 serviços existem (ACTIVE), mas `npc-api`, `npc-admin-ui`, `sta-api`, `sta-admin-ui` e `clst-api` estão com desired=0, running=0 (task-defs `*-prod:1` registradas, aguardando decisão de ativação); `backoffice` (prod:2) e `docs-portal` (prod:1) rodam com desired=1, running=1.

## 14. Tabela resumo

| Sistema | Serviço ECS | Tech | DB próprio | Portas | Estado |
|---|---|---|---|---|---|
| NPC | npc-api + npc-admin-ui | Elixir/Phoenix 1.8 (Bandit, Oban, Cloak, gnat) + Vue 3/Vite 7 | `mon_npc` (Postgres, 10 tabelas de negócio + RBAC + Oban) | API 4020; UI 8080 (dev 5177; simulador 5180) | Funcional; HML 1/1; PROD provisionado com desired=0 |
| STA | sta-api + sta-admin-ui | Elixir/Phoenix 1.8 (Finch, SweetXml, Oban, gnat) + Vue 3/Vite 7 (admin-portal React alternativo) | `mon_sta` (Postgres, 4 tabelas de negócio + users/RBAC + Oban) | API 4000 (dev 4030); UI 8080 (dev 5178) | Funcional e maduro; HML 1/1; PROD provisionado com desired=0 |
| CLST | clst-api | Elixir/Phoenix 1.8 API-only (Oban, gnat, Req) | `mon_clst` (Postgres, 8 tabelas + Oban) | 4004 (test 4014) | Funcional (bordas BCB/SELIC stubbed, testes rasos); HML 1/1; PROD provisionado com desired=0 |
| Backoffice | backoffice | Vue 3 + Vuetify 3 + Pinia + Vite 7 (nginx) | nenhum (consome Core API) | 8080 (dev 5176) | Completo; HML 1/1; PROD 1/1 |
| Docs-portal | docs-portal | nginx estático (agrega docs no build) | nenhum | 8080 | Ativo; HML 1/1; PROD 1/1 |
| Mobile | nenhum (app) | Flutter/Dart (dio, go_router, sqlcipher) | local cifrado no dispositivo | n/a | App maduro; consome Core API; ícone/splash do rebrand pendentes |
| Packages (mobile-ui) | nenhum (lib) | Flutter package (design system) | nenhum | n/a | Ativo como dependência do mobile |
| ETL | nenhum (ferramenta) | SQL + bash + Python (+ Postgres locais) | efêmeros locais (ex. :5544) | n/a | Operacional sob demanda (imports legados já executados) |
| Migration | nenhum | n/a | nenhum | n/a | Stub (só README) |
| Benchmark | nenhum (ferramenta) | Elixir Mix standalone (gnat, telemetry) | nenhum | n/a | Ativo como ferramenta; baseline loopback ~43k TPS |
| Audit | nenhum | evidências estáticas (PNG, PDF, HTML, MD) | nenhum | n/a | Acervo de auditoria 2026-06-25 |
| Nginx | nenhum | configs nginx | nenhum | n/a | Proxy de dev local (3 vhosts) |
