diff --git a/README.md b/README.md index 9e189fa..757acd6 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ API serverless para solicitação de exclusão de cliente com geração de QR Co - [ADR-001 — Unificar exclusão Pix (CDK + Lambda)](docs/adr/ADR-001-unificar-exclusao-pix.md) — **Accepted** (CAB 2026-09-20). Este repo é o canônico; `aws-api-gateway-cdk` será arquivado após migrar o stack. Access pattern Dynamo: pointer `LATEST`. Auth (PR3): Cognito JWT. +**Feature map (agents):** [docs/feature-map.md](docs/feature-map.md) — rotas, auth Cognito JWT, env vars, pré-reqs `make check`. + --- ## DynamoDB — ponteiro LATEST diff --git a/docs/feature-map.md b/docs/feature-map.md new file mode 100644 index 0000000..d9740a0 --- /dev/null +++ b/docs/feature-map.md @@ -0,0 +1,63 @@ +# Feature map — exclusão Pix API (agent-friendly) + +Factual map for agents. Do not invent routes/auth. Sources: `lambda/app.py`, `lambda/domain_dynamo.py`, `cdk/app.py`, README, SECURITY.md, ADR-001. + +## Auth (base) + +- **Cognito JWT** (ADR-001 / PR3): send `Authorization: Bearer ` (IdToken, not AccessToken). +- Protected at API Gateway (JWT authorizer) before Lambda. +- **Public:** `GET /health` only. + +Pointers: [ADR-001](adr/ADR-001-unificar-exclusao-pix.md), [SECURITY.md](../SECURITY.md), [ARCHITECTURE.md](../ARCHITECTURE.md). + +## Routes → handlers + +| Method + path | Auth | Handler | Behavior | +|---------------|------|---------|----------| +| `POST /solicitar-exclusao-cliente` | Cognito JWT | `solicitar_exclusao` | Body: `cliente_id` (required), `motivo` (optional). Reads Dynamo `LATEST`; if status is `PENDING_PAYMENT` or `PAID`, returns 200 with existing `request_id`. Else creates history row + `LATEST` pointer (`PENDING_PAYMENT`), stub Pix QR, returns 201. | +| `GET /status-exclusao/{cliente_id}` | Cognito JWT | `get_status` | Reads `LATEST` only; 200 with status/`active_request_id`, or 404. | +| `POST /confirmar-pagamento` | Cognito JWT | `confirmar_pagamento` | Body: `cliente_id` + `request_id`. Updates history UUID then `LATEST` to `PAID` (condition on `active_request_id`). | +| `GET /health` | Public | `health_check` | Describes Dynamo table; 200 healthy / 503 unhealthy. | + +HTTP lives in `lambda/app.py`. Dynamo LATEST helpers in `lambda/domain_dynamo.py` (boundary discipline). + +### Dynamo access pattern (obrigatório) + +- PK `cliente_id`, SK `request_id` +- History: `SK = `; pointer: `SK = LATEST` (`active_request_id`, `status`, …) +- Dedup/status read **only** `LATEST`; payment confirm updates uuid **and** `LATEST` + +## Env vars + +| Var | Where | Default / notes | +|-----|--------|-----------------| +| `TABLE_NAME` | Lambda env (CDK) | Table name from stack | +| `PIX_FEE` | Lambda env (CDK) | `"50.00"` (Decimal in domain) | + +No secrets in repo. Cognito IDs / `ApiUrl` only via CloudFormation outputs after deploy (CAB). + +## Pre-reqs — tests / check + +```bash +pip install -r requirements.txt +pip install -r requirements-dev.txt # ruff + mypy +pip install -r cdk/requirements.txt # for synth +PYTHONPATH=. pytest tests/test_exclusao.py -v +make check # lint + typecheck + test + cdk synth (no deploy) +``` + +CI jobs on PR/`push` to `main`: **lint** (ruff + mypy), **test** (pytest/moto), **synth** (`npx aws-cdk@2 synth`). + +## Hard constraints (encoded) + +- Datetimes: `datetime.now(timezone.utc)` — ruff **DTZ** bans `utcnow` +- CORS: CDK localhost only — no `AllowOrigins: "*"` in `cdk/` + +## Doc index + +| Doc | Role | +|-----|------| +| [ADR-001](adr/ADR-001-unificar-exclusao-pix.md) | Canonical decision (monorepo, LATEST, Cognito) | +| [ARCHITECTURE.md](../ARCHITECTURE.md) | Bounded context + components | +| [SECURITY.md](../SECURITY.md) | Auth/CORS/throttle honesty | +| [README.md](../README.md) | Deploy, Cognito lab curls, make check |