
Pix Automático — Reference Implementation
Implementação de referência production-grade para Pix Automático + Open Finance Brasil
Backend Spring Boot 4.0 + Java 21 · Frontend React 18 + TypeScript + Tailwind · Empacotados como artefato único
Hexagonal · Saga · Outbox · Idempotência forte · OpenTelemetry

TL;DR · Esta é a implementação que você procuraria se sua fintech precisasse integrar com o Pix Automático amanhã e não pudesse errar. Hexagonal, com idempotência forte, outbox transacional, saga orquestrada, observabilidade end-to-end, painel operacional React e testes que cobrem do agregado até o webhook. Roda 100% local com make up && make run.
Sumário
Por que existe
O Pix Automático (lançado em out/2025) e a Fase 4 do Open Finance Brasil tornaram obrigatória a adequação de sistemas de cobrança recorrente, assinaturas, utilities e fintechs a um conjunto de contratos técnicos não triviais definidos pelo Banco Central. Integrações mal-feitas resultam em cobranças duplicadas, perda de conciliação, multas regulatórias e churn.
Este repositório demonstra, em código real e executável, os padrões que uma integração correta, auditável e resiliente exige — sem atalhos.
Capacidades
| Categoria | O que está implementado |
|---|
| Domínio | Agregados Consent, Subscription, Charge com domain events e invariantes do BCB |
| Idempotência | Idempotency-Key (UUIDv4) + Redis + unique constraint em DB — defesa em profundidade |
| Consistência | Outbox Pattern: transação local atômica + publisher Kafka assíncrono |
| Orquestração | Saga orquestrada: autorizar → agendar → iniciar → conciliar com compensação |
| Resiliência | Resilience4j: circuit breaker, retry, rate limiter, bulkhead — por endpoint |
| Segurança | Spring Security + OAuth2 Client Credentials simulando mTLS / FAPI para BCB |
| Observabilidade | OpenTelemetry traces + Prometheus metrics + Loki logs estruturados, correlacionados por traceId |
| Testes | Unitário (domínio puro), integração (Testcontainers), contrato (Pact), arquitetura (ArchUnit) |
| Migrations | Flyway versionado |
| Contratos | OpenAPI 3 autogerado (SpringDoc) |
| Decisões | 5 ADRs documentando cada escolha arquitetural não trivial |
| Painel operacional | SPA React + TypeScript + shadcn/ui — Dashboard, CRUD de Consents, agendamento de Charges, timeline de saga |
Painel operacional (frontend)
SPA em React 18 + TypeScript empacotada dentro do mesmo JAR do backend — make run sobe API + UI no mesmo :8080. Não tem deploy separado, não tem CORS, não tem dois contextos pra debugar.
| Página | O que mostra |
|---|
| Dashboard | KPIs (consents/subscriptions/charges totais, taxa de sucesso), feed das últimas 5 cobranças, indicadores de saúde da plataforma |
| Consents | Tabela paginada, criar consent, autorizar, revogar (com motivo), drill-down no detalhe |
| Subscriptions | Tabela vinculada a consents autorizados, criar subscription |
| Charges | Tabela com auto-refresh a cada 5s (acompanha saga ao vivo), agendar cobrança |
| Charge detail | Timeline visual SCHEDULED → INITIATED → SETTLED/FAILED com erro do BCB se houver |
| Webhooks | Documentação do contrato POST /webhooks/bcb/charge-status + atalhos pra Kafka UI / Grafana |
Stack: Vite (build), React 18 + TypeScript, Tailwind CSS + shadcn/ui (Radix primitives), TanStack Query (cache + refetch), React Router.
Comandos:
make web-dev # Vite dev server em :5173 com proxy pra :8080 (hot reload)
make web-build # builda só o frontend pra src/main/resources/static/
make run # build full + roda app (API + UI bundled em :8080)
make run-fast # roda só backend, pula build do frontend
Arquitetura
Arquitetura hexagonal (Ports & Adapters). O domínio é puro: nem Spring, nem Jakarta, nem JPA. ArchUnit valida as fronteiras no CI.
flowchart LR
subgraph In[" "]
direction TB
WEB["adapter.web<br/>REST controllers"]
WHK["adapter.web<br/>BCB webhooks"]
end
subgraph App["application"]
direction TB
UC["Use cases"]
SAGA["Charge Saga"]
end
subgraph Dom["domain (puro)"]
direction TB
AGG["Aggregates<br/>Consent · Subscription · Charge"]
EVT["Domain Events"]
end
subgraph Out["infrastructure"]
direction TB
DB[("PostgreSQL<br/>JPA / Flyway")]
RDS[("Redis<br/>Idempotency")]
KFK[["Kafka<br/>Outbox publisher"]]
BCB(["BCB API<br/>OAuth2 / FAPI"])
end
WEB --> UC
WHK --> UC
UC --> AGG
UC --> SAGA
SAGA --> AGG
AGG -.eventos.-> EVT
UC --> DB
UC --> RDS
EVT --> KFK
SAGA --> BCB
classDef domain fill:#fff5d6,stroke:#b08800,color:#000
classDef app fill:#dff5e1,stroke:#2e7d32,color:#000
classDef adapter fill:#e3f0ff,stroke:#1565c0,color:#000
classDef infra fill:#fde2e2,stroke:#b71c1c,color:#000
class AGG,EVT domain
class UC,SAGA app
class WEB,WHK adapter
class DB,RDS,KFK,BCB infra
Diagramas C4 detalhados em docs/architecture/.
Stack
| Camada | Tecnologia |
|---|
| Runtime | Java 21 (virtual threads) |
| App framework | Spring Boot 4.0 + Spring Web MVC |
| Persistência | PostgreSQL 16 + Spring Data JPA + Flyway |
| Cache / Idempotência | Redis 7 |
| Mensageria | Apache Kafka 3.8 (KRaft, sem ZooKeeper) |
| Resiliência | Resilience4j 2.4 |
| Tracing | OpenTelemetry → Tempo |
| Métricas | Micrometer → Prometheus → Grafana |
| Logs | Logback JSON estruturado → Loki |
| Segurança | Spring Security + OAuth2 client/resource server |
| API docs | SpringDoc OpenAPI 3 |
| Testes | JUnit 5 · Testcontainers · Pact · ArchUnit · JaCoCo |
| Build | Maven 3.9 (wrapper) + frontend-maven-plugin (npm via Maven) |
| Container | Buildpacks (Spring Boot OCI image) |
| Frontend | Vite + React 18 + TypeScript + Tailwind + shadcn/ui + TanStack Query |
| CI/CD | GitHub Actions · CodeQL · Semgrep · Trivy · Dependabot |
Quickstart
Pré-requisitos: JDK 21, Docker Desktop, ~4 GB de RAM livre. Node 22 só é necessário se for desenvolver o frontend separado (make web-dev); o build pelo Maven baixa o Node automaticamente.
# 1. Clonar
git clone https://github.com/Paulo-Marcos-Lucio/pix-automatico-reference.git
cd pix-automatico-reference
# 2. Sobe Postgres + Redis + Kafka + stack de observabilidade
make up
# 3. Roda a app (perfil local) — builda backend + frontend e empacota tudo
make run
# 4. Abre o painel
open http://localhost:8080 # ou xdg-open / start, conforme OS
Acessos:
Targets úteis do Makefile:
make up # docker-compose up -d
make down # derruba (preserva volumes)
make test # mvn test (unit)
make it # mvn verify (unit + integration via Testcontainers)
make image # build OCI image via Buildpacks
make clean # mvn clean + docker volumes prune
Fluxo Pix Automático
Resumido — detalhe completo em docs/flows/charge-saga.md.
sequenceDiagram
autonumber
actor C as Cliente (devedor)
participant App as Sua plataforma<br/>(este repo)
participant DB as Postgres
participant K as Kafka
participant BC as BCB / OF API
C->>App: autoriza recorrência
App->>BC: POST /consents
BC-->>App: consentId AUTHORIZED
App->>DB: persist Consent + outbox event (tx)
App-->>K: publish ConsentAuthorized (async)
Note over App: agenda Subscription
loop Cada ciclo de cobrança
App->>DB: persist Charge SCHEDULED
App->>BC: POST /charges (idempotência)
BC-->>App: status + endToEndId
App->>DB: update Charge INITIATED
BC-->>App: webhook charge-status
App->>DB: reconcile + update SETTLED
App-->>K: publish ChargeSettled
end
Garantias do fluxo:
- ✅ Cobrança duplicada é matemática-impossível (idempotência em 3 camadas)
- ✅ Falha entre
update DB e publish Kafka é resolvida pelo Outbox (eventual consistency)
- ✅ Webhook reentrante: mesmo
endToEndId chegando 2× não causa double-credit
- ✅ Saga compensa ao falhar entre etapas (rollback de side-effects parciais)
Endpoints
| Método | Path | Descrição | Idempotente |
|---|
POST | /v1/consents | Cria Consent de recorrência | ✅ |
GET | /v1/consents/{id} | Consulta Consent | — |
POST | /v1/consents/{id}/revoke | Revoga Consent | ✅ |
POST | /v1/subscriptions | Cria Subscription vinculada a um Consent | ✅ |
POST | /v1/charges | Agenda/inicia Charge | ✅ |
GET | /v1/charges/{id} | Consulta Charge | — |
POST | /webhooks/bcb/charge-status | Recebe notificação do BCB | ✅ |
Todos os POST exigem header Idempotency-Key: <UUIDv4>. Reuso da mesma key com payload divergente retorna 422 Unprocessable Entity.
Exemplos prontos em requests.http (compatível com IntelliJ HTTP Client e VS Code REST Client).
Estrutura do projeto
pix-automatico-reference/
├── src/main/java/dev/pmlsp/pixauto/
│ ├── domain/ # puro: entidades, agregados, eventos, ports
│ │ ├── model/ # Consent, Subscription, Charge, value objects
│ │ ├── port/in/ # use case interfaces
│ │ ├── port/out/