Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions docs/adr/ADR-002-auth-cognito-jwt-httpapi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# ADR-002 — Auth padrão: Cognito JWT authorizer no HttpApi

- **Status:** Accepted (CAB 2026-10-18)
- **Data:** 2026-10-18
- **Escopo:** todos os repos serverless do Rodrigo (padrão da squad)
- **Decisor:** Chefe via CAB (aprovação) / Arquiteto (proposta)

## Contexto

A decisão de auth existe hoje só dentro da ADR-001 (PR3, CAB 2026-09-20) e só para a exclusão Pix. Na main do canônico (`cdk/app.py`, PR #6): Cognito User Pool + `HttpJwtAuthorizer` com issuer do pool e audience = app client; `POST /solicitar-exclusao-cliente`, `GET /status-exclusao/{cliente_id}` e `POST /confirmar-pagamento` com authorizer; `GET /health` público; sem WAF/ACM; CORS restrito a localhost (ou context `corsOrigins`). Em `aws-crud-api-lambda-dynamodb` (`template.yaml`) **não há auth** ("add auth later"). Sem um padrão escrito, cada repo novo reabre a discussão.

## Decisão

1. Toda API HttpApi usa **JWT authorizer nativo apontando para um Cognito User Pool**.
2. **Todas as rotas protegidas, exceto `GET /health`** (probe/smoke). Rota pública nova = exceção de exposição pública → sobe ao Rodrigo via Chefe.
3. **Um User Pool simples por ambiente/lab**, por stack: login por e-mail, app client sem secret (`USER_PASSWORD` + `USER_SRP`), `RemovalPolicy.DESTROY` só em lab.
4. **Sem WAF por enquanto.** Proteção de lab = JWT + throttle do stage (100 rps / burst 200 no canônico) + CORS sem `*`.
5. SECURITY.md só descreve o que o IaC tem.

## Consequências / trade-offs

- (+) Validação de token no API Gateway, sem código de auth na Lambda; custo de Cognito baixo em lab.
- (+) Um padrão só: issuer + audience, fácil de revisar em PR.
- (−) Autorização fina (escopos/claims por rota) fica para a app ou para ADR futura.
- (−) `self_sign_up_enabled=True` no canônico: qualquer um com o client id cria usuário. Aceito em lab; **produção exige revisão** (desligar sign-up ou ADR nova).
- (−) Sem WAF: sem rate limit por IP nem regras gerenciadas. Revisitar antes de qualquer exposição pública real.
- Dívida: `aws-crud-api-lambda-dynamodb` está fora do padrão (sem auth). Adequar em PR próprio quando o Chefe pedir.

## Princípios do pstack aplicados

- **Encode Lessons in Structure:** a regra "toda rota tem authorizer, exceto /health" deve virar teste de synth (no estilo de `tests/test_cdk_cors_ban.py`), não só esta prosa. Mudou: follow-up pro Dev listado em Pendente.
- **Boundary Discipline:** auth validada na borda (API Gateway), a Lambda confia no evento. Mudou: nenhum código de JWT na app.
- **Subtract Before You Add:** WAF, domínio custom e Lambda authorizer ficaram fora. Mudou: escopo do padrão = o que já está na main.

## Alternativas descartadas

- **Lambda authorizer próprio:** mais código, latência e custo, sem ganho em lab.
- **IAM auth (SigV4):** bom para máquina-a-máquina, ruim para cliente web/mobile.
- **API key / usage plans:** não existe no HttpApi e não é autenticação.
- **WAF já agora:** custo fixo mensal por Web ACL sem tráfego real que justifique.

**Pendente:** teste de synth "authorizer em toda rota exceto /health" (Dev, quando o Chefe pedir).
43 changes: 43 additions & 0 deletions docs/adr/ADR-003-httpapi-lambda-cdk-python.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# ADR-003 — Padrão serverless: API Gateway HttpApi + Lambda, IaC em CDK Python

- **Status:** Accepted (CAB 2026-10-18)
- **Data:** 2026-10-18
- **Escopo:** todos os repos serverless do Rodrigo (padrão da squad)
- **Decisor:** Chefe via CAB (aprovação) / Arquiteto (proposta)

## Contexto

As duas APIs AWS já usam **HttpApi (v2)**, não REST API: o canônico `aws-lambda-api-gateway-python` (`aws_apigatewayv2.HttpApi` em `cdk/app.py`) e `aws-crud-api-lambda-dynamodb` (`AWS::Serverless::HttpApi` em `template.yaml`, comentário "cheaper & simpler than REST API"). O IaC diverge: o canônico é **CDK Python** (ADR-001 PR2, PR #5; CI `make check` + `cdk synth` sem deploy, PR #9); o CRUD é **SAM** (`sam validate --lint`, PR #2). A ADR-001 já fixou "Terraform: não" para a exclusão Pix. Falta o padrão geral.

## Decisão

1. API pública/síncrona = **API Gateway HttpApi + Lambda (Python 3.12)** com integração proxy.
2. IaC padrão de app serverless = **CDK Python**, um stack por bounded context, no mesmo repo do código (`cdk/` + `lambda/` + `tests/`).
3. CI obrigatório sem credenciais AWS: `make check` = lint + typecheck + testes + `cdk synth`. Deploy só com CAB.
4. Throttle no stage e CORS sem `*` (já testado por `test_cdk_cors_ban.py`).
5. SAM e Terraform não entram em repo novo de app serverless. O CRUD em SAM fica como está (demo/referência) até o Chefe pedir migração.

## Consequências / trade-offs

- (+) **Custo:** HttpApi é bem mais barato por milhão de requests que REST API (ordem de ~70% menos, pela tabela pública da AWS; conferir a região antes de citar valor).
- (+) **Latência e simplicidade:** menos overhead, JWT authorizer nativo (ADR-002), CORS nativo.
- (+) CDK Python: mesma linguagem da Lambda, grants tipados (`grant_read_write_data`), `cdk synth` testável no CI.
- (−) **Perde features do REST API:** usage plans e API keys, **WAF associado direto ao stage**, request validation por modelo, caching, transformação de request/response (VTL), endpoint privado/edge. Validação de payload fica na Lambda (Powertools / tipos).
- (−) Precisa WAF ou usage plan? Reabrir com ADR nova (REST API ou CloudFront + WAF na frente).
- (−) CDK exige Node no CI (`npx aws-cdk@2`) e bootstrap da conta no primeiro deploy (Infra).
- Dívida: dois sabores de IaC convivendo (CDK no canônico, SAM no CRUD).

## Princípios do pstack aplicados

- **Laziness Protocol / Subtract Before You Add:** um IaC e um tipo de API só; não manter SAM, CDK e Terraform lado a lado em repo novo. Mudou: SAM e Terraform saem do padrão.
- **Prove It Works:** `cdk synth` no CI prova o IaC sem deploy. Mudou: o `synth` entra no `make check` como gate obrigatório.
- **Encode Lessons in Structure:** CORS sem `*` já é teste; o padrão de IaC deve virar check de CI, não só ADR. Mudou: follow-up de check em Pendente.

## Alternativas descartadas

- **REST API (v1):** mais features, mas custo e latência maiores sem uso real de usage plans/WAF/VTL hoje.
- **SAM:** ótimo para demo, mas mistura YAML e Python e não tem grants tipados. Fica só no CRUD legado.
- **Terraform:** bom para plataforma, mas para app serverless separa IaC do código e repete o problema da ADR-001 (IaC órfã).
- **Lambda Function URL:** sem authorizer JWT, throttle por rota nem CORS gerenciado no mesmo nível.

**Pendente:** decidir se o CRUD migra para CDK (Chefe) e criar o check de "IaC padrão" no template de repo (Dev/Infra).
53 changes: 53 additions & 0 deletions docs/adr/ADR-004-bend-jev-gate-nao-runtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# ADR-004 — Bend (e JEV) são gate de verificação no CI, não runtime em produção

- **Status:** Accepted (CAB 2026-10-18)
- **Data:** 2026-10-18
- **Escopo:** todos os repos que usam Bend ou JEV
- **Decisor:** Chefe via CAB (aprovação) / Arquiteto (proposta)

## Contexto

`patote85/crud-api-bend` reimplementa em Bend 2 o contrato HTTP de `aws-crud-api-lambda-dynamodb` e diz no README que "**não** é um port de Lambda, DynamoDB ou API Gateway". O que o repo tem de fato:

- **Leis e provas:** `LAWS.bend` + `PROOF.bend` (18 leis: create/get/delete/options, dois items, JSON, persist, envelope da lista, PUT parcial). `AGENTS.md`: "Do not weaken or delete a law to make a proof pass. The human owns LAWS.bend."
- **CI:** `.github/workflows/proof.yml` instala Bend e roda `test.sh` (`bend PROOF.bend` + demo em processo) em push/PR. "Sem TCP no CI."
- **Runtime de brinquedo:** processo único TCP `:8080`, HTTP mínimo, canal tamanho 1, store em `store.json` gravado a cada pedido, sem TLS, sem auth, `price` inteiro, `id` contador.

JEV não aparece em `crud-api-bend`; entra aqui pela mesma lógica de gate.

Ou seja: o valor do repo está nas leis verificadas, não no servidor.

## Decisão

1. **Bend é gate de CI:** leis do contrato em `LAWS.bend`, provas em `PROOF.bend`, rodadas em todo PR. Prova falhou, PR não passa o CAB.
2. **Bend não roda em produção.** A runtime de produção continua sendo HttpApi + Lambda Python + DynamoDB (ADR-003). O servidor Bend é só demo local.
3. **JEV entra no mesmo papel:** juiz tipado no CI/review, nunca no caminho de request. Chave só via secret-request (`JEV_API_KEY`).
4. **Leis são do humano:** enfraquecer ou apagar lei para passar prova é proibido e vale como ressalva no CAB.

## Por quê (o que não dá pra ver no código)

- O servidor Bend não tem o que produção exige: TLS, auth (ADR-002), concorrência real (canal tamanho 1), persistência durável e multi-instância (`store.json` local), observabilidade, nem caminho de deploy gerenciado na AWS.
- A força do Bend é provar propriedades do contrato (tipos dependentes, `match` exaustivo) **antes do merge**. Isso é verificação, e cabe no CI sem custo de cloud.
- Usar como runtime criaria um segundo stack para operar, sem SLA nem suporte da AWS, e trocaria "provar o contrato" por "manter um servidor HTTP feito à mão".

## Consequências / trade-offs

- (+) Gate formal barato (GitHub Actions, sem AWS) e contrato com prova, não só teste de exemplo.
- (−) Duas implementações do mesmo contrato (Python e Bend) podem divergir; a lei só prova o modelo Bend, não a Lambda.
- (−) Toolchain instalada via `curl | sh` no CI, sem versão fixada (risco de supply chain e de quebra). Fixar versão/checksum é follow-up.
- (−) Bend 2 é novo: curva de aprendizado e ecossistema pequeno.

## Princípios do pstack aplicados

- **Encode Lessons in Structure:** a regra de negócio vira lei verificável em `LAWS.bend`, não prosa. Mudou: o contrato do CRUD está em lei + prova no CI.
- **Prove It Works:** `test.sh` roda prova + demo a cada PR. Mudou: "pronto" = prova verde, não autodeclaração.
- **Type System Discipline:** tipos dependentes tornam estados ilegais irrepresentáveis no modelo. Mudou: `id`/`price` como `Nat`.
- **Subtract Before You Add:** nada de runtime Bend na AWS. Mudou: zero infra nova.

## Alternativas descartadas

- **Bend como runtime (container/ECS ou custom runtime Lambda):** ver "Por quê"; custo de operar sem ganho.
- **Só pytest, sem Bend:** perde a prova formal; continua valendo para a Lambda, mas não substitui as leis.
- **JEV no caminho de request:** latência, custo por chamada e dependência externa em produção.

**Pendente:** fixar a versão do Bend no `proof.yml`; ligar as leis ao contrato da Lambda (ex.: mesmo conjunto de casos em `test_http_contract.py`). Dev, quando o Chefe pedir.
21 changes: 21 additions & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Índice de ADRs (atualizado 2026-10-18)

ADRs ficam em `docs/adr/` do repo canônico `patote85/aws-lambda-api-gateway-python`. Só ganha ADR o que vira padrão pra mais de um sistema ou um porquê que não aparece no código.

## ADRs

| ADR | Título | Status | Escopo |
|-----|--------|--------|--------|
| [ADR-001](./ADR-001-unificar-exclusao-pix.md) | Unificar exclusão Pix (CDK + Lambda) | Accepted (CAB 2026-09-20) | Exclusão Pix |
| [ADR-002](./ADR-002-auth-cognito-jwt-httpapi.md) | Auth padrão: Cognito JWT authorizer no HttpApi | Accepted (CAB 2026-10-18) | Todos os repos |
| [ADR-003](./ADR-003-httpapi-lambda-cdk-python.md) | HttpApi + Lambda, IaC em CDK Python | Accepted (CAB 2026-10-18) | Todos os repos |
| [ADR-004](./ADR-004-bend-jev-gate-nao-runtime.md) | Bend (e JEV) como gate no CI, não runtime | Accepted (CAB 2026-10-18) | Repos com Bend/JEV |

## Decisões registradas sem ADR (já estão no código ou são fato consumado)

| Decisão | Onde está | Link |
|---------|-----------|------|
| `aws-crud-api-lambda-dynamodb`: modelo de dados (tabela `Items`, PK `id`, on-demand) e CI (pytest + moto, `sam validate --lint`, `make check` = lint + mypy + testes + sam validate) | `template.yaml`, `Makefile`, `tests/` | [PR #1 pytest+moto](https://github.com/patote85/aws-crud-api-lambda-dynamodb/pull/1), [PR #2 sam validate](https://github.com/patote85/aws-crud-api-lambda-dynamodb/pull/2), [PR #3 make check](https://github.com/patote85/aws-crud-api-lambda-dynamodb/pull/3) |
| `aws-api-gateway-cdk` arquivado; stack migrado pro canônico (ADR-001) | banner "Arquivado" no README do repo antigo | [aws-api-gateway-cdk PR #1](https://github.com/patote85/aws-api-gateway-cdk/pull/1) (banner), [canônico PR #5](https://github.com/patote85/aws-lambda-api-gateway-python/pull/5) (migração do CDK) |

Nota: o CI "`make check` + `cdk synth` (sem deploy)" é o [PR #9 do canônico](https://github.com/patote85/aws-lambda-api-gateway-python/pull/9), não do CRUD. O CRUD usa SAM, não CDK (ver ADR-003).
Loading