pizza-digital/docs/SPEC-CARDAPIO.md
Admin d669f56398 Import Pizza Digital SPECs and docs from Obsidian vault sync
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-09 19:52:34 +00:00

197 lines
7.2 KiB
Markdown
Raw 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.

# SPEC — Cardápio (Menu)
| Campo | Valor |
|-------|--------|
| **Produto** | Pizza Digital |
| **Capítulo** | SPEC §7.5 RF-MEN · domínio Menu* |
| **Versão** | 0.1.0 |
| **Data** | 2026-10-19 |
| **Owner** | Roger / iTecnologys |
| **Pesquisa regional** | [`CARDAPIO-JOINVILLE.md`](CARDAPIO-JOINVILLE.md) |
| **SPEC irmã (obrigatória)** | [`SPEC-ESTOQUE.md`](SPEC-ESTOQUE.md) — ficha técnica / BOM |
| **Canais** | [`SPEC-CANAIS-DIGITAIS.md`](SPEC-CANAIS-DIGITAIS.md) — PWA `/c/:slug` |
---
## 1. Objetivo
Ser a **fonte única da verdade** do que a loja vende: categorias, itens, preços, tamanhos, modifiers (borda/meia-a-meia) e mapeamento para KDS.
O cardápio **não guarda saldo**. Saldo, compra e baixa ficam no **Estoque**. A ponte é a **ficha técnica (BOM)**: cada item do menu consome 1+ insumos.
```text
Cardápio (o que vende) ──BOM──► Estoque (o que tem)
│ │
▼ ▼
PDV / PWA / iFood alerta / bloqueio / CMV
│
▼
Order → KDS
```
---
## 2. Escopo
### Inclui
- Categorias e itens (CRUD gestor)
- Preços por tamanho (Broto / G / Gigante) ou SKU por tamanho
- Meia-a-meia, bordas, adicionais
- Map item → estações KDS + componentes (tags)
- Disponibilidade: ativo / pausado / esgotado (via Estoque)
- Cardápio Joinville piloto (tradicionais, especiais SC, doces, bebidas)
- Exposição ao PDV, Central, PWA público e (futuro) iFood
### Não inclui (Estoque)
- Quantidade em prateleira, NF de compra, inventário físico → [`SPEC-ESTOQUE.md`](SPEC-ESTOQUE.md)
---
## 3. Modelo de dados (alvo)
```text
MenuCategory
id, storeId, name, sortOrder, active, channelVisibility[]
MenuItem ← já existe (Prisma)
id, storeId, categoryId, name, description
priceCents ← preço base (ou ver Size)
halfHalf, active, sortOrder
stations[] · components[]
MenuItemSize (novo — Track M1)
id, menuItemId, sizeCode ← broto|media|grande|gigante
diameterCm, slices, maxFlavors
priceCents, active
MenuModifier (borda / adicional)
id, storeId, name, priceCents, kind ← borda|extra|bebida_combo
stationCodes[]
Recipe (ficha técnica) ← vive na SPEC-ESTOQUE, FK menuItemId
id, menuItemId, sizeCode?
lines[] → Ingredient + qty + unit
```
### Tamanhos padrão Joinville (congelar no piloto)
Referência de prato de mesa (~25 cm) + diâmetro / fatias comerciais SC:
| sizeCode | Nome UI | cm | Fatias | ≈ pratos | Sabores máx. (split) | Fator preço (base = Grande) |
|----------|---------|----|--------|----------|----------------------|------------------------------|
| `broto` | Broto | 25 | 4 | 1 | **1** | 0,55 |
| `pequena` | Pequena | 30 | 6 | 1,5 | **1** | 0,70 |
| `media` | Média | 35 | 8 | 2 | **2** | 0,85 |
| `grande` | Grande | 40 | 12 | 2,5 | **3** | 1,00 |
| `gigante` | Gigante | 45 | 16 | 3 | **4** | 1,20 |
| `familia` | Família | 50 | 20 | 3,5 | **4** | 1,35 |
**Regras de split:** Broto e Pequena = inteira (1 sabor). Média até 2. Grande até 3. Gigante e Família até 4. Preço = **maior sabor** × fator do tamanho (+ borda).
**Default comercial:** `grande` (40 cm). Catálogo em `GET /api/menu/sizes` e no sheet do PDV.
---
## 4. Categorias piloto (já no seed)
| # | Categoria | Papel |
|---|-----------|--------|
| 1 | Pizzas Tradicionais | Sabores · preço base Grande; tamanho no pedido |
| 2 | Especiais Joinville | Diferencial SC |
| 3 | Pizzas Doces | Pós-salgada |
| 4 | Refrigerantes | Acompanhamento |
| 5 | Sucos | Natural + caixa |
| 6 | Energéticos | Acompanhamento |
| 7 | Vitaminas · frutas c/ leite | Feitas na hora |
| 8 | Bordas e extras | Modifiers |
---
## 5. Requisitos (RF-MEN + extensão)
| ID | Requisito | Fase |
|----|-----------|------|
| RF-MEN-01 | CRUD categorias, itens, preços, adicionais | ✅ parcial |
| RF-MEN-02 | Mapear item → estações KDS | ✅ |
| RF-MEN-03 | SLA por categoria/item | Fase 1 |
| RF-MEN-04 | Cardápio digital público PWA | Track C1 |
| RF-MEN-05 | Meia-a-meia / combos | ✅ split multi-sabor por tamanho |
| RF-MEN-06 | Horário loja aberta/fechada | Track C1 |
| RF-MEN-07 | Áreas entrega + taxa | Track C1 |
| RF-MEN-08 | Tamanhos Broto→Família + preço por fator | ✅ PDV + `/menu/sizes` |
| RF-MEN-09 | Pausar item (manual ou por estoque baixo) | **M1** |
| RF-MEN-10 | Ficha técnica obrigatória p/ item produzido | **M1** → Estoque |
| RF-MEN-11 | Bebida 1:1 → 1 unidade de SKU estoque | **M1** |
| RF-MEN-12 | Vitamina/suco natural → BOM (fruta + leite + gelo) | **M1** |
| RF-MEN-13 | Sync disponibilidade → PWA/PDV ≤ 2 s | Track C1+M1 |
| RF-MEN-14 | Preço meia-a-meia = maior sabor (config) | ✅ regra |
| RF-MEN-15 | Cada pizza com BOM em **gramas** (catálogo Joinville 38) | **M1** ↔ EST-13 |
---
## 6. Ponte Cardápio ↔ Estoque
| Evento cardápio | Efeito estoque |
|-----------------|----------------|
| Criar/editar `MenuItem` produzido | Exigir `Recipe` (ou marcar `stockMode=none`) |
| Pedido `confirmado` / `em_producao` | Reserva ou baixa (política EST) |
| Pedido `cancelado` antes da produção | Estorna reserva |
| Saldo < `minStock` de insumo crítico | Item → `paused` ou badge “esgotado” |
| Compra / ajuste no Estoque | Recalcula disponibilidade do menu |
Detalhe de baixas, **pesos em g por tipo de pizza**, unidades e alertas:
**[`SPEC-ESTOQUE.md`](SPEC-ESTOQUE.md) §4–4.1** · [`FICHAS-TECNICAS-PESO.md`](FICHAS-TECNICAS-PESO.md) · [`data/fichas-pizzas-peso.json`](data/fichas-pizzas-peso.json).
### `stockMode` por item
| Modo | Uso | Exemplo |
|------|-----|---------|
| `bom` | Consome receita | Pizza Calabresa G |
| `sku` | 1 item = 1 unidade SKU | Coca 2L, Red Bull |
| `none` | Sem controle | Observação / taxa |
---
## 7. Regras de negócio
1. Item `active=false` ou `paused` **não aparece** no PDV/PWA (gestor ainda vê no admin).
2. Meia-a-meia: ambos sabores precisam estar disponíveis; baixa BOM proporcional (½ + ½) — ver Estoque.
3. Borda é `MenuModifier` com BOM própria (catupiry/cheddar).
4. Vitamina: sempre `stockMode=bom` (leite + fruta + gelo); se faltar fruta → pausa só aquele sabor.
5. Preços em **centavos BRL**; UI pt-BR (`formatBRL`).
---
## 8. Track M — implementação
| ID | Entrega | Dependência |
|----|---------|-------------|
| **M0** | Seed Joinville (pizzas + bebidas) no ar | ✅ |
| **M1** | `Recipe` + `Ingredient` + baixa no pedido | SPEC-ESTOQUE E1 |
| **M2** | Admin UI ficha técnica + pausa auto | M1 |
| **M3** | `MenuItemSize` multi-preço | M0 |
| **M4** | Cardápio PWA lê só itens disponíveis | C1 + M1 |
---
## 9. Critérios de aceite
1. Gestor lista/edita categorias e itens no admin (ou seed + API).
2. PDV mostra categorias Joinville com preços BRL.
3. Todo item `stockMode=bom|sku` tem ficha ou SKU ligado (M1).
4. Coca 2L sem saldo → some/pausada no PDV em ≤ 2 s (M1).
5. Pizza sem mussarela no estoque → Calabresa e Mussarela pausam (M1).
6. SPEC-ESTOQUE referencia este doc e vice-versa (sem requisitos órfãos).
---
## 10. Fora de escopo (agora)
- Cardápio multi-idioma
- Fotos HD / CMS marketing
- Precificação dinâmica por horário
- Marketplace multi-loja
---
*SPEC satélite. Versão do produto pai: SPEC.md. Cruzamento obrigatório com SPEC-ESTOQUE.*