Each PRD documents real UI/API processes, service methods, states and gaps. Co-authored-by: Cursor <cursoragent@cursor.com>
4.2 KiB
4.2 KiB
PRD — Cardápio Joinville (Menu)
| Campo | Valor |
|---|---|
| Produto | Pizza Digital |
| Versão app auditada | v0.5.0 |
| Ambiente | https://pizza.itecnologys.com · VM125 · loja pizza-digital-piloto |
| Spec de origem | docs/CARDAPIO-JOINVILLE.md + docs/SPEC-CARDAPIO.md |
| Módulo | Cardápio / PDV sheet de pizza |
| Rotas UI | /pdv · Admin menu |
| APIs | GET/POST/PATCH/DELETE /api/menu/* · GET /api/menu/sizes |
| Data | 2026-11-09 |
| Estilo | PRD operacional detalhado (visão de desenvolvedor) |
| Audiência | Dev / QA / Product |
Como ler: cada seção descreve o processo real (o que o sistema faz hoje), com passos de usuário, chamadas de API, regras de negócio e estados. Status: ✅ construído · ⚠️ parcial · ⏳ especificado / não entregue · 🐛 gap observado.
1. Contexto do desenvolvedor
O cardápio Joinville não é só uma lista de sabores: é o catálogo canônico que o PDV usa para montar OrderItem.
Pesquisa regional (CARDAPIO-JOINVILLE.md) virou seed + PizzaSizeBase. Preço catalogado = Grande 40 cm;
tamanho/split resolvem no pedido.
Artefatos de código
- UI:
apps/web/src/PdvPage.tsx(sheet tamanho/sabores) - API:
apps/api/src/menu/menu.controller.ts·menu.service.ts·pizza-sizes.ts - Dados:
MenuCategory,MenuItem,PizzaSizeBase,MenuItemStation,MenuItemRecipeLine - Seed:
apps/api/prisma/seed.ts
Inventário auditado
8 categorias ativas · 92 itens ativos · 6 tamanhos · cat. Broto legado active=false.
2. Processo — carregar cardápio no PDV
- Operador autentica (
POST /api/auth/logincomstoreSlug). - Front chama
GET /api/menu→{ pizzaSizes, categories[] }filtrandoactive=true. - Front monta abas/lista por categoria.
- Item com
halfHalf=trueabre sheet; demais vão direto ao carrinho.
Estados
- Sem token → 401
- Categoria sem itens ativos → não deve renderizar (ou vazia)
- 🐛 Em 2026-11-09 a UI chegou a mostrar “Nenhuma categoria…” com API OK — validar fetch/storeSlug no client
3. Processo — montar pizza (passo a passo)
- Atendente escolhe fulfillment: Entrega / Balcão / Mesa.
- Clica sabor (ex.: Calabresa) → sheet.
- Escolhe
sizeCode(broto|pequena|media|grande|gigante|familia). - Sistema lê
maxFlavors/priceFactor/diameterCm/slicesdePizzaSizeBase. - Seleciona sabores até o limite; se exceder → erro UI.
- Preço unitário =
max(priceCents dos sabores) * priceFactor. - Opcional: borda (
Bordas especiais). - Confirma → linha no pedido:
Pizza Grande 40cm · SaborA / SaborB. POST /api/orderscom items (sizeCode,halfHalf, notes).
Tabela de regras (congelada)
| sizeCode | cm | fatias | max sabores | fator |
|---|---|---|---|---|
| broto | 25 | 4 | 1 | 0,55 |
| pequena | 30 | 6 | 1 | 0,70 |
| media | 35 | 8 | 2 | 0,85 |
| grande | 40 | 12 | 3 | 1,00 |
| gigante | 45 | 16 | 4 | 1,20 |
| familia | 50 | 20 | 4 | 1,35 |
4. Processo — CRUD gestor
- Gestor com capability
menu.manage. POST /api/menu/categories/PATCH/ soft-delete.POST /api/menu/itemscompriceCents,halfHalf, estações,stockMode.GET /api/menu/ficha-metapara BOM/ingredientes.- Item inativo (
active=false) some do PDV, permanece no banco.
5. Sequência (dev)
Login → GET /menu → render cats
→ tap pizza → sheet(size, flavors)
→ calc priceForSize
→ add line → POST /orders
→ KDS tickets por MenuItemStation
6. Aceite / gaps
- ✅ Seed Joinville + tamanhos
- ✅ Cálculo split no PDV
- ⚠️ UI Admin CRUD
- ⏳ PWA público
/c/:slug - 🐛 Validar PDV vazio intermitente
7. Notas de implementação (dev)
halfHalf=trueno MenuItem ⇒ sheet de tamanho no PDV (mesmo para pizza “inteira”).- Broto legado: categoria
active=false; não use SKU Broto separado. - Preço: sempre derive de
priceCents(Grande) ×PizzaSizeBase.priceFactor. - Após
POST /orders, conferirOrderTicketgerados via estações do item. - Se PDV listar vazio: checar JWT
storeId,GET /api/menuno Network eactivedas categories.