|
1 | | -# Payment API |
| 1 | +# payment-api |
2 | 2 |
|
3 | | -API de pagamentos Pix em Java + Spring Boot com Clean Architecture, Kafka (KRaft), Postgres, Prometheus, Grafana e Jaeger. |
| 3 | +Fundação de um core de pagamentos Pix em Java — infraestrutura, observabilidade e pipeline CI/CD prontos; domínio em construção. |
4 | 4 |
|
5 | | -**Documentação de arquitetura:** |
6 | | -- [docs/architecture.md](docs/architecture.md) — domínio, fluxos, API, pacotes, idempotência |
7 | | -- [docs/devops-flow.md](docs/devops-flow.md) — pipeline CI/CD + observabilidade (Mermaid) |
| 5 | +[](https://github.com/lmoraesdev/java-payment-hexagonal/actions/workflows/ci.yml) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +## Status |
| 10 | + |
| 11 | +A plataforma está completa: serviços sobem, métricas chegam no Grafana, traces no Jaeger, testes de integração passam com Testcontainers. O que ainda não existe é o domínio de negócio — entidades, casos de uso, portas e adapters de persistência/mensageria. Esses são os próximos passos (ver [Roadmap](#roadmap)). |
8 | 12 |
|
9 | 13 | ## Stack |
10 | 14 |
|
11 | | -| Camada | Tecnologia | |
12 | | -|---|---| |
13 | | -| Runtime | Java 21 LTS | |
14 | | -| Framework | Spring Boot 3.5.3 | |
15 | | -| Messaging | Kafka 3.9 (KRaft — sem Zookeeper) | |
16 | | -| Persistence | PostgreSQL 18 | |
17 | | -| Métricas | Actuator + Micrometer + Prometheus + Grafana | |
18 | | -| Tracing | Micrometer Tracing + OpenTelemetry → Jaeger | |
19 | | -| Cache | Redis 7 (pré-instalado, profile `cache`) | |
20 | | -| Testes | JUnit 5 + Testcontainers | |
21 | | -| Qualidade | Spotless (GJF AOSP) + Checkstyle | |
22 | | - |
23 | | -## Quickstart |
| 15 | +| Tecnologia | Versão | Para quê | |
| 16 | +|---|---|---| |
| 17 | +| Java | 21 LTS | Runtime | |
| 18 | +| Spring Boot | 3.5.3 | Framework web, DI, auto-configuração | |
| 19 | +| PostgreSQL | 18 | Persistência principal | |
| 20 | +| Kafka (KRaft) | 3.9 | Event streaming — sem Zookeeper | |
| 21 | +| Redis | 7 | Cache / idempotência (pré-instalado, profile `cache`) | |
| 22 | +| Prometheus + Grafana | latest | Métricas + dashboard Payment Overview pré-provisionado | |
| 23 | +| Jaeger + OpenTelemetry | latest | Distributed tracing via OTLP HTTP | |
| 24 | +| Testcontainers | 1.21 | Testes de integração com banco real | |
| 25 | +| Spotless (GJF AOSP) | 2.43 | Formatação automática de código | |
| 26 | +| Checkstyle | 3.5 | Verificação de estilo | |
| 27 | + |
| 28 | +## Arquitetura |
| 29 | + |
| 30 | +O projeto segue Arquitetura Hexagonal (Ports & Adapters): o domínio não conhece Spring, JPA nem Kafka. Frameworks e infraestrutura ficam nas bordas; a lógica de negócio fica isolada e testável sem container. |
| 31 | + |
| 32 | +Decisões de projeto: |
| 33 | +- **Observabilidade desde o início** — Prometheus, Grafana e Jaeger estão na infra antes do primeiro use case existir. Métricas e traces não são afterthought. |
| 34 | +- **Logging estruturado 5W1H** — cada log emite JSON com `where`, `why`, `when`, `who`, `what`, `how` + `traceId`/`spanId` injetados automaticamente pelo Micrometer MDC. Facilita correlação em produção. |
| 35 | +- **Event-driven preparado** — Kafka configurado com KRaft (sem Zookeeper), consumer/producer prontos no `application.yml`. Nenhum evento publicado ainda. |
| 36 | + |
| 37 | +``` |
| 38 | +com.lmoraesdev.payment |
| 39 | +├── adapter |
| 40 | +│ ├── in.web ← PingController, GlobalExceptionHandler |
| 41 | +│ └── out |
| 42 | +│ ├── messaging ← (roadmap — Kafka producers) |
| 43 | +│ └── persistence ← (roadmap — JPA repositories) |
| 44 | +├── application |
| 45 | +│ ├── port.in ← (roadmap — interfaces de entrada) |
| 46 | +│ ├── port.out ← (roadmap — interfaces de saída) |
| 47 | +│ └── usecase ← (roadmap — casos de uso) |
| 48 | +├── config |
| 49 | +│ └── logging ← Log5w1h, Logger5w1hBuilder |
| 50 | +└── domain |
| 51 | + ├── event ← (roadmap — domain events) |
| 52 | + ├── exception ← DomainException (base abstrata com código de erro) |
| 53 | + └── model ← (roadmap — entidades e value objects) |
| 54 | +``` |
| 55 | + |
| 56 | +Especificação do domínio planejado (Charge Pix, máquina de estados, Money, idempotência): [`docs/architecture.md`](docs/architecture.md). |
| 57 | + |
| 58 | +## Como rodar |
| 59 | + |
| 60 | +**Pré-requisitos:** Docker Desktop com WSL2 integration habilitada; contexto Docker configurado para `default` (`docker context use default`). |
24 | 61 |
|
25 | 62 | ```bash |
26 | 63 | # 1. Variáveis de ambiente |
27 | 64 | cp .env.example .env |
28 | 65 |
|
29 | | -# 2. Subir toda a infra + app |
| 66 | +# 2. Subir infra + app (sem Redis) |
30 | 67 | make up |
| 68 | +# equivalente: docker compose up -d --build |
31 | 69 |
|
32 | | -# 3. Status |
| 70 | +# 3. Subir com Redis (profile cache) |
| 71 | +docker compose --profile cache up -d --build |
| 72 | + |
| 73 | +# 4. Verificar status |
33 | 74 | docker compose ps |
34 | 75 | ``` |
35 | 76 |
|
36 | | -| URL | Descrição | |
37 | | -|---|---| |
38 | | -| `GET /ping` | Smoke test | |
39 | | -| `GET /actuator/health` | Health probe | |
40 | | -| `GET /actuator/prometheus` | Métricas Prometheus | |
41 | | -| http://localhost:8090 | Kafka UI | |
42 | | -| http://localhost:9090 | Prometheus | |
43 | | -| http://localhost:3000 | Grafana — Payment Overview | |
44 | | -| http://localhost:16686 | Jaeger — traces | |
| 77 | +## Endpoints e observabilidade |
45 | 78 |
|
46 | | -## Subir Redis (opcional) |
| 79 | +| URL | O que se vê | |
| 80 | +|---|---| |
| 81 | +| `http://localhost:8080/ping` | `{"status":"pong"}` — smoke test | |
| 82 | +| `http://localhost:8080/actuator/health` | Status do app, banco e dependências | |
| 83 | +| `http://localhost:8080/actuator/prometheus` | Métricas no formato Prometheus | |
| 84 | +| `http://localhost:8090` | Kafka UI — tópicos, consumer groups, mensagens | |
| 85 | +| `http://localhost:9090` | Prometheus — séries temporais, targets ativos | |
| 86 | +| `http://localhost:3000` | Grafana — dashboard "Payment Overview" (admin/admin) | |
| 87 | +| `http://localhost:16686` | Jaeger — traces distribuídos por operação | |
47 | 88 |
|
48 | | -Redis está pré-instalado mas **não sobe por padrão**: |
| 89 | +## Testes |
49 | 90 |
|
50 | 91 | ```bash |
51 | | -docker compose --profile cache up -d |
52 | | -``` |
| 92 | +# Unitários — sem Docker, rápido |
| 93 | +make test |
| 94 | +# equivalente: ./mvnw test |
53 | 95 |
|
54 | | -## Makefile |
55 | | - |
56 | | -``` |
57 | | -make up # docker compose up -d --build |
58 | | -make down # docker compose down (mantém volumes) |
59 | | -make clean # docker compose down -v (apaga volumes) |
60 | | -make logs # docker compose logs -f app |
61 | | -make test # ./mvnw test (sem Docker) |
62 | | -make verify # ./mvnw verify (com Testcontainers — requer Docker) |
63 | | -make format # ./mvnw spotless:apply |
64 | | -make db # psql no container postgres |
| 96 | +# Integração — sobe PostgreSQL 18 via Testcontainers |
| 97 | +make verify |
| 98 | +# equivalente: ./mvnw verify |
65 | 99 | ``` |
66 | 100 |
|
67 | | -## Qualidade de código |
| 101 | +Convenção de nomes: |
| 102 | +- `*Test.java` — testes unitários, executados pelo Surefire |
| 103 | +- `*IT.java` — testes de integração, executados pelo Failsafe |
68 | 104 |
|
69 | | -```bash |
70 | | -# Formatar |
71 | | -./mvnw spotless:apply # ou: make format |
| 105 | +O teste `PaymentApiApplicationIT` valida que o contexto Spring sobe corretamente contra um banco PostgreSQL real, sem mocks. |
72 | 106 |
|
73 | | -# Verificar formatação (GJF AOSP, 4-space) |
74 | | -./mvnw spotless:check |
| 107 | +## CI/CD |
75 | 108 |
|
76 | | -# Verificar estilo (Checkstyle) |
77 | | -./mvnw checkstyle:check |
| 109 | +| Trigger | Job | O que roda | |
| 110 | +|---|---|---| |
| 111 | +| Push para `develop` ou `main` | Lint + Unit Tests | `spotless:check` → `checkstyle:check` → `mvnw test` | |
| 112 | +| Push para `main` ou PR → `main` | Full Verify + Docker Build | `mvnw verify` (unit + integração) → `docker build` | |
78 | 113 |
|
79 | | -# CI roda os dois antes dos testes: |
80 | | -./mvnw spotless:check && ./mvnw checkstyle:check && ./mvnw test |
81 | | -``` |
| 114 | +O job de integração roda apenas no caminho para `main`, mantendo o ciclo de feedback rápido no `develop`. |
82 | 115 |
|
83 | | -## Pacotes (Clean Architecture) |
84 | | - |
85 | | -``` |
86 | | -com.lmoraesdev.payment |
87 | | -├── adapter |
88 | | -│ ├── in.web ← controllers, exception handler |
89 | | -│ └── out |
90 | | -│ ├── messaging ← Kafka producers (futuro) |
91 | | -│ └── persistence ← JPA repositories (futuro) |
92 | | -├── application |
93 | | -│ ├── port.in ← interfaces de entrada (futuro) |
94 | | -│ ├── port.out ← interfaces de saída (futuro) |
95 | | -│ └── usecase ← casos de uso (futuro) |
96 | | -├── config |
97 | | -│ └── logging ← Logger5w1h estruturado |
98 | | -└── domain |
99 | | - ├── event ← domain events (futuro) |
100 | | - ├── exception ← DomainException base |
101 | | - └── model ← entidades / value objects (futuro) |
102 | | -``` |
| 116 | +## Padrões |
103 | 117 |
|
104 | | -## Testes |
| 118 | +**Formatação e estilo:** |
105 | 119 |
|
106 | 120 | ```bash |
107 | | -# Unitários (sem Docker) |
108 | | -./mvnw test |
109 | | - |
110 | | -# Integração — sobe Postgres 18 via Testcontainers |
111 | | -./mvnw verify |
| 121 | +./mvnw spotless:apply # formata (Google Java Format, AOSP 4-space) |
| 122 | +./mvnw spotless:check # verifica (roda no CI) |
| 123 | +./mvnw checkstyle:check # estilo (roda no CI) |
112 | 124 | ``` |
113 | 125 |
|
114 | | -## Git hooks |
| 126 | +**Git hooks** (ativar uma vez por clone): |
115 | 127 |
|
116 | 128 | ```bash |
117 | 129 | git config core.hooksPath .githooks |
118 | 130 | ``` |
119 | 131 |
|
120 | | -| Hook | O que faz | |
| 132 | +| Hook | Ação | |
121 | 133 | |---|---| |
122 | | -| `pre-push` | Executa `./mvnw verify` antes de cada push | |
123 | 134 | | `commit-msg` | Valida formato Conventional Commits | |
| 135 | +| `pre-push` | Executa `./mvnw verify` antes de subir | |
124 | 136 |
|
125 | | -Formato de commit: `tipo(escopo): descrição` |
126 | | -Tipos: `feat fix docs style refactor test chore build ci perf revert` |
| 137 | +Formato de commit: `tipo(escopo): descrição` — tipos aceitos: `feat fix docs style refactor test chore build ci perf revert`. |
127 | 138 |
|
128 | | -## CI |
| 139 | +**Makefile:** |
129 | 140 |
|
130 | | -| Branch / PR | Jobs | |
131 | | -|---|---| |
132 | | -| `develop` push | Lint (Spotless + Checkstyle) + unit tests | |
133 | | -| `main` push / PR → main | Lint + unit tests + full-verify + docker build | |
| 141 | +``` |
| 142 | +make up # docker compose up -d --build |
| 143 | +make down # docker compose down (mantém volumes) |
| 144 | +make clean # docker compose down -v (remove volumes) |
| 145 | +make logs # docker compose logs -f app |
| 146 | +make test # ./mvnw test |
| 147 | +make verify # ./mvnw verify |
| 148 | +make format # ./mvnw spotless:apply |
| 149 | +make db # psql no container postgres |
| 150 | +``` |
| 151 | + |
| 152 | +## Roadmap |
| 153 | + |
| 154 | +O que está especificado em [`docs/architecture.md`](docs/architecture.md) e ainda não implementado: |
| 155 | + |
| 156 | +- [ ] Entidade `Charge` com value object `Money` e `ChargeStatus` |
| 157 | +- [ ] Máquina de estados (`PENDING → ACTIVE → PAID / EXPIRED / CANCELLED`) |
| 158 | +- [ ] Caso de uso `CreateCharge` com idempotência por header |
| 159 | +- [ ] Adapter de persistência JPA (`ChargeRepository`) |
| 160 | +- [ ] Publicação de eventos de domínio no Kafka (`ChargeCreated`, `ChargePaid`, etc.) |
| 161 | +- [ ] Consumer para eventos externos (webhook/notificação) |
| 162 | +- [ ] Uso do Redis para cache de idempotência e locks |
| 163 | +- [ ] Endpoints REST de cobrança (`POST /charges`, `GET /charges/{id}`) |
| 164 | + |
| 165 | +--- |
| 166 | + |
| 167 | +[Leandro Moraes](https://github.com/lmoraesdev) |
0 commit comments