feat(web): ping API ponta-a-ponta via TanStack Query + Zod contract
Fecha loop B+C — Web consome @sar/api-interface em runtime, não só build. - Vite proxy /api → localhost:3000 (zero CORS em dev, mesma URL em prod via Nginx) - api-client.ts: fetch wrapper parseando RFC 9457 problem+json em ApiError - useApiPing: TanStack Query + PingResponseSchema.parse — drift servidor falha alto - FoundationStatus pill na Topbar (verde/vermelho/cinza + Tooltip com requestId) Validado via curl proxy:4200 → 200 ok contratual; /nope → 404 problem+json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -319,6 +319,30 @@
|
||||
4. **Master-login stub + WorkspacePrismaPool** (frente arquitetural pesada — depende de #3).
|
||||
5. **OpenTelemetry SDK** plugar quando entrar em catálogo (stub atual mantém posição).
|
||||
|
||||
### 2026-05-27 — Web→API ponta-a-ponta (loop B+C fechado) CONCLUÍDO ✅
|
||||
- **Escopo da sessão:** Pendência #1 do roadmap — provar que `@sar/api-interface` é honrado pelos dois lados em runtime, não só em build time. Loop B (Web foundation) + C (Zod contracts) fechado.
|
||||
- **Arquivos novos:**
|
||||
- `apps/web/src/lib/api-client.ts` — fetch wrapper que parseia `application/problem+json` (RFC 9457) em `ApiError` estruturado carregando status+type+title+detail+requestId+errors[]. Sem validação Zod aqui — responsabilidade do caller (CODING-RULES §05).
|
||||
- `apps/web/src/lib/queries/ping.ts` — `useApiPing()` TanStack Query chamando `/api/v1/ping` + `PingResponseSchema.parse(...)`. Drift servidor falha alto **antes** de chegar nos componentes. `refetchInterval: 30s` (Visual DNA "sereno").
|
||||
- `apps/web/src/components/layout/FoundationStatus.tsx` — pill discreto na Topbar (verde/vermelho/cinza) com Tooltip detalhando service+version+workspaceId+requestId+uptime. Pulse `processing` no refetch silencioso. Conscientemente temporário — quando produto entrar em normal, vira indicador só em `/health`.
|
||||
- **Modificados:**
|
||||
- `apps/web/vite.config.mts` — `server.proxy['/api']: http://localhost:3000`. Evita CORS em dev e mantém URL relativa no código da Web; em produção, Nginx roteia mesmo origin. `changeOrigin: false` (mesma host).
|
||||
- `apps/web/src/components/layout/Topbar.tsx` — `<FoundationStatus />` antes do sino.
|
||||
- **Validação ponta-a-ponta:**
|
||||
- `nx run web:lint` ✅ · `nx run web:build` ✅ (821ms, 309KB gzip)
|
||||
- `curl :4200/api/v1/ping` via proxy Vite → `200 application/json` com payload contratual completo (`status=ok`, `workspaceId=dev-workspace`, `requestId`, `uptimeSeconds=144`, `now`)
|
||||
- `curl :4200/api/v1/nope` → `404 application/problem+json` com `type/title/detail/instance/requestId` — prova que `ApiError` captura erro estruturado quando servidor falhar
|
||||
- Headers helmet, x-request-id, CORS expose-headers passam pelo proxy intactos
|
||||
- **Decisão arquitetural confirmada:** Web consome lib `@sar/api-interface` sem arrastar nada do Nest. `PingResponseSchema` viaja como Zod puro; `ApiError` na Web não conhece `HttpException` do Nest — só o contrato HTTP+JSON. Alinhamento com regra "lib stays framework-free" da sessão anterior.
|
||||
- **Pegadinhas notadas (não bloquearam):**
|
||||
- `_sidebarOpen` no AppShell ainda tem `eslint-disable` — fica pra Frente D ou primeiro responsivo mobile.
|
||||
- Bundle Web 976KB (309KB gzip) — code-splitting esperado quando rotas de cockpit virarem separadas (TanStack Router suporta nativo). Não age agora.
|
||||
- **Pendente próxima sessão (ordem atualizada):**
|
||||
1. **Frente D — ESLint boundaries** (tags Nx `scope:* · type:* · domain:*`) + Husky + gitleaks. Higiene de PR antes de feature pesada.
|
||||
2. **PRD WDS** via `/bmad-prd create` antes de modelar domínio.
|
||||
3. **Master-login stub + WorkspacePrismaPool** (frente arquitetural — depende do PRD).
|
||||
4. **OpenTelemetry SDK** plugar quando entrar no catálogo.
|
||||
|
||||
---
|
||||
|
||||
## About This Folder
|
||||
|
||||
Reference in New Issue
Block a user