pizza-digital/docs/PRD/PRD-CARDAPIO-JOINVILLE.md
Admin e3da540b6e Add detailed developer PRDs for all Pizza Digital SPECs.
Each PRD documents real UI/API processes, service methods, states and gaps.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-09 21:22:22 +00:00

111 lines
4.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
1. Operador autentica (`POST /api/auth/login` com `storeSlug`).
2. Front chama `GET /api/menu` → `{ pizzaSizes, categories[] }` filtrando `active=true`.
3. Front monta abas/lista por categoria.
4. Item com `halfHalf=true` abre 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)
1. Atendente escolhe fulfillment: Entrega / Balcão / Mesa.
2. Clica sabor (ex.: Calabresa) → sheet.
3. Escolhe `sizeCode` (broto|pequena|media|grande|gigante|familia).
4. Sistema lê `maxFlavors` / `priceFactor` / `diameterCm` / `slices` de `PizzaSizeBase`.
5. Seleciona sabores até o limite; se exceder → erro UI.
6. Preço unitário = `max(priceCents dos sabores) * priceFactor`.
7. Opcional: borda (`Bordas especiais`).
8. Confirma → linha no pedido: `Pizza Grande 40cm · SaborA / SaborB`.
9. `POST /api/orders` com 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
1. Gestor com capability `menu.manage`.
2. `POST /api/menu/categories` / `PATCH` / soft-delete.
3. `POST /api/menu/items` com `priceCents`, `halfHalf`, estações, `stockMode`.
4. `GET /api/menu/ficha-meta` para BOM/ingredientes.
5. Item inativo (`active=false`) some do PDV, permanece no banco.
---
## 5. Sequência (dev)
```text
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=true` no 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`, conferir `OrderTicket` gerados via estações do item.
- Se PDV listar vazio: checar JWT `storeId`, `GET /api/menu` no Network e `active` das categories.