Mini fluxo de checkout para venda de capinhas, com proteção de estoque, idempotência e processamento assíncrono de pedidos enquanto um ERP simulado permanece lento e instável.
This is a challenge by Coodesh
| Camada | Tecnologias |
|---|---|
| Frontend | Next.js 16, React 19, TypeScript, Tailwind CSS 4, TanStack Query |
| Backend | NestJS 11, Prisma 6, TypeScript |
| Banco | PostgreSQL 17 |
| Infra local | Docker Compose |
A stack segue a preferência do desafio (Next.js + NestJS + Prisma). O banco escolhido é PostgreSQL (via Docker) para validar concorrência e transações de forma realista.
Pré-requisitos: Docker e Docker Compose.
docker compose up --build -d| Serviço | URL |
|---|---|
| Frontend | http://localhost:3001 |
| API | http://localhost:3000 |
| Healthcheck API | http://localhost:3000/health |
| PostgreSQL | localhost:5432 (user/db/password: casecellshop) |
Verificar saúde dos containers:
docker compose psParar:
docker compose downdocker compose -f docker-compose.dev.yml up --build- Subir apenas o Postgres:
docker compose up -d postgres- API:
cd apps/api
cp .env.example .env
npm install
npm run prisma:generate
npx prisma db push
npm run prisma:seed
npm run start:dev- Web:
cd apps/web
cp .env.example .env
npm install
npm run devFrontend em http://localhost:3000 (dev) ou conforme porta exibida no terminal.
| Método | Rota | Descrição |
|---|---|---|
GET |
/health |
Healthcheck |
GET |
/products |
Lista produtos e estoque |
GET |
/products/:id |
Detalhe do produto |
POST |
/checkout |
Cria tentativa de compra (header Idempotency-Key opcional; gerado se ausente) |
GET |
/orders/:id |
Status do pedido (requer Idempotency-Key correspondente) |
Códigos de erro padronizados: VALIDATION_ERROR, INSUFFICIENT_STOCK, ERP_TEMPORARY, TECHNICAL_FAILURE, NOT_FOUND.
- Estoque: reserva transacional com
updateManycondicional (available >= quantity) para evitar oversell. - Idempotência:
idempotencyKeyúnica emOrder; o backend gera UUID se o cliente não enviar; o frontend persiste a chave por payload (produto + quantidade) para retry seguro. - ERP:
ErpClientsimula latência e falhas temporárias; worker interno (polling) processa pedidosPENDINGsem Redis na primeira versão. - Observabilidade:
x-request-idem todas as requisições e logs estruturados no worker. - Segurança: rate limit (Throttler), Helmet, CORS restrito a localhost,
GET /orders/:idexige a mesma chave de idempotência do pedido.
Detalhes adicionais em .cursor/DECISIONS.md.
- Sem autenticação real, pagamento ou integração com ERP de produção.
- Schema sincronizado com
prisma db push(sem migrations versionadas no repositório). - Mensageria real (Redis/BullMQ) deixada como evolução futura.
- Testes e2e HTTP completos dependem de Postgres; a suíte principal usa mocks unitários.
- Migrations Prisma versionadas e pipeline CI.
- Fila real (BullMQ) substituindo o worker por polling.
- Testes e2e de API com Postgres em container efêmero.
- Cache de catálogo para reduzir carga no “ERP”.
Descrições dos testes em inglês (padrão do projeto).
cd apps/api
npm test # unit tests (business rules, ERP, checkout)
npm run test:cov # coverage em regras críticasPrincipais cenários cobertos:
should return same order for same idempotency keyshould throw INSUFFICIENT_STOCK when inventory is not enoughshould not oversell under concurrent checkouts(reserva atômica)- ERP temporary failure e retry via worker
cd apps/web
npm run build
npm run lintsequenceDiagram
participant Web as Frontend
participant API as Checkout API
participant DB as PostgreSQL
participant ERP as ERP (simulado)
Web->>API: POST /checkout (Idempotency-Key)
API->>DB: TX reserva estoque + Order PENDING
API-->>Web: orderId + status
loop Worker
API->>ERP: placeOrder (lento/instável)
ERP-->>API: ok / falha temporária
API->>DB: CONFIRMED / PENDING / FAILED
end
Web->>API: GET /orders/:id (poll)
API-->>Web: status final
apps/
api/ # NestJS + Prisma
web/ # Next.js
docker-compose.yml
docker-compose.dev.yml
.cursor/DECISIONS.md
PROMPTS.md