397 lines
15 KiB
Markdown
397 lines
15 KiB
Markdown
# SPEC — Paridade Despacho / Delivery (referência CityFoods)
|
||
|
||
| Campo | Valor |
|
||
|-------|--------|
|
||
| **Produto** | Pizza Digital |
|
||
| **Documento** | Paridade operacional com CityFoods (expedição + delivery + admin) |
|
||
| **Versão** | 0.2.1 |
|
||
| **Data** | 2026-10-22 |
|
||
| **Status impl.** | P0–P2 + Gestor · UI mapa-first em [`SPEC-CITYFOODS-VIDEO-PARITY.md`](SPEC-CITYFOODS-VIDEO-PARITY.md) |
|
||
| **Vídeo referência** | [Siciliana yVtc](https://www.youtube.com/watch?v=yVtcgJt0L_Q) · [Forno Jxau](https://www.youtube.com/watch?v=JxauDKXTJr0) · [Despacho KDcD](https://www.youtube.com/watch?v=KDcDTGEw11A) |
|
||
| **Case** | ~R$ 1M/mês · ~70% iFood · hub multi-marca · entrega < 30 min |
|
||
| **Alinha com** | SPEC §15 S4→S8 · SPEC-FASE1 §6 · rusterando (rotas) |
|
||
| **Fora deste doc** | Cardápio público PWA (C1), fidelidade, caixa completo |
|
||
|
||
---
|
||
|
||
## 0. Objetivo
|
||
|
||
Elevar o Pizza Digital do estado atual (**lista de prontos + SAIR**) ao nível das telas CityFoods do vídeo:
|
||
|
||
1. **Despacho** como cockpit (não só fila)
|
||
2. **Conferência / estufa** como etapa formal
|
||
3. **Frota** (casa / rua) + atribuição
|
||
4. **Rotas** e, depois, marketplace / app entregador
|
||
5. **Admin** de zonas, ranking e relatórios operacionais
|
||
|
||
**Princípio de sequência (já na SPEC mãe):**
|
||
KDS estável → despacho rico → frota → ORS → app motoboy → iFood.
|
||
|
||
---
|
||
|
||
## 1. Estado atual (baseline Pizza Digital)
|
||
|
||
| Tela / capacidade | Rota / artefato | Status |
|
||
|-------------------|-----------------|--------|
|
||
| Central de pedidos | `/pedidos` | ✅ |
|
||
| KDS multi-estação | `/kds/:station` | ✅ |
|
||
| Expedição (KDS) | `/kds/expedicao` · → ESTUFA | ✅ |
|
||
| Etiqueta | `/etiqueta/:id` | ✅ |
|
||
| Despacho cockpit | `/despacho` | ✅ P0–P2 |
|
||
| Frota / motoboy | `/despacho` frota + `/api/drivers` | ✅ |
|
||
| Conferência / estufa | `Order.estufaAt` + Expedição | ✅ |
|
||
| **Gestor de Rotas** | `DispatchBatch` · mapa permanente | ✅ (heurística; ORS com `ORS_API_KEY`) |
|
||
| App entregador | `/motoboy` | ✅ parcial (sem PIN próprio / offline) |
|
||
| Zonas / taxas | `/admin/zonas` | ✅ CRUD (PDV ainda não aplica taxa auto) |
|
||
| Ranking / funil / relatório | `/ops` | ✅ |
|
||
| iFood no fluxo | — | ❌ P3 / C2 |
|
||
|
||
---
|
||
|
||
## 2. Narrativa das telas necessárias (SPEC por tela)
|
||
|
||
Cada subsecção = **uma tela** (ou superfície). Inclui: papel, o que o CityFoods mostra no vídeo, requisitos RF, dados, eventos, aceite.
|
||
|
||
---
|
||
|
||
### Tela A — Cockpit de Despacho (`/despacho`)
|
||
|
||
**Papel:** operador de despacho / gestor de turno.
|
||
**No vídeo:** “coração operacional” — lista de pedidos + frota + tempos + cores + reordenação.
|
||
|
||
#### A.1 O que deve mostrar
|
||
|
||
| Coluna / bloco | Descrição |
|
||
|----------------|-----------|
|
||
| Frota (topo ou lateral) | Motoboys em **casa** / **rua**, nº de entregas ativas |
|
||
| Pedido | Código, canal (PDV / App / iFood / WhatsApp), fulfillment |
|
||
| Tempos | Hora do pedido · tempo na loja · tempo desde `pronto` / estufa |
|
||
| Estágio visual | Cor: novo · em produção · forno · estufa · em rota |
|
||
| Destino | Bairro + endereço curto |
|
||
| Itens resumidos | Qtd × sabor (sem ficha completa) |
|
||
| Ações | Selecionar · atribuir motoboy · SAIR / batch |
|
||
|
||
#### A.2 Requisitos
|
||
|
||
| ID | Requisito | Sprint |
|
||
|----|-----------|--------|
|
||
| RF-DSP-01 | Listar pedidos em `pronto` e `na_estufa` em tempo real (Socket.io) | S4 / S6 |
|
||
| RF-DSP-02 | Exibir canal, código, tempos (pedido / loja / estufa) | S4 |
|
||
| RF-DSP-03 | Faixa de cor por estágio de produção espelhado do KDS | S4 |
|
||
| RF-DSP-04 | Seleção múltipla de pedidos para batch de saída | S6 |
|
||
| RF-DSP-05 | Atribuir entregador antes ou no SAIR | S6 |
|
||
| RF-DSP-06 | SAIR → status `em_rota` + `dispatchedAt` + entregadorId | S6 |
|
||
| RF-DSP-07 | Reordenar fila de prioridade; persistir; refletir no KDS | S6 |
|
||
|
||
#### A.3 Aceite
|
||
|
||
- Despachante vê, sem sair da tela, **quem está livre**, **o que está na estufa** e **há quanto tempo**.
|
||
- Um clique em SAIR com motoboy atribuído remove o pedido da fila de prontos.
|
||
|
||
---
|
||
|
||
### Tela B — Conferência / Estufa
|
||
|
||
**Papel:** conferente (login próprio).
|
||
**No vídeo:** identifica sabor → imprime etiqueta → pedido vai para estufa no despacho.
|
||
|
||
#### B.1 Fluxo
|
||
|
||
```
|
||
KDS BUMP (forno) → fila Conferência
|
||
→ conferente confirma sabores / qtds
|
||
→ imprime etiqueta (código + sabores)
|
||
→ status na_estufa
|
||
→ aparece no Cockpit Despacho como “estufa”
|
||
```
|
||
|
||
#### B.2 Requisitos
|
||
|
||
| ID | Requisito | Sprint |
|
||
|----|-----------|--------|
|
||
| RF-CNF-01 | Tela `/conferencia` ou modo dedicado em `/kds/expedicao` | S4 |
|
||
| RF-CNF-02 | Login com papel/área `conferente` ou `despacho` | S4 |
|
||
| RF-CNF-03 | Checklist de itens/sabores antes de confirmar | S4 |
|
||
| RF-CNF-04 | Confirmar → print etiqueta + `na_estufa` + evento `order.ready` enriquecido | S4 |
|
||
| RF-CNF-05 | Pedidos na estufa ordenáveis por tempo parado (alerta visual) | S4 |
|
||
|
||
#### B.3 Modelo de estado (ampliação)
|
||
|
||
```
|
||
em_producao → pronto_cozinha → na_estufa → em_rota → entregue
|
||
```
|
||
|
||
> Compatibilidade: enquanto `na_estufa` não existir no enum, usar `pronto` + flag `holdingStation=estufa` **ou** migrar enum (preferível).
|
||
|
||
#### B.4 Aceite
|
||
|
||
- Sem etiqueta confirmada, pedido **não** entra na fila “estufa” do despacho.
|
||
- Tempo parado na estufa é visível e alarmante após N minutos (config loja).
|
||
|
||
---
|
||
|
||
### Tela C — Frota / Motoboys
|
||
|
||
**Papel:** despacho + gestor.
|
||
**No vídeo:** quem está na casa, quem está na rua, quantas entregas cada um carrega.
|
||
|
||
#### C.1 Requisitos
|
||
|
||
| ID | Requisito | Sprint |
|
||
|----|-----------|--------|
|
||
| RF-FRT-01 | Cadastro de entregador (nome, telefone, ativo, loja) | S6 |
|
||
| RF-FRT-02 | Status operacional: `casa` \| `rua` \| `offline` | S6 |
|
||
| RF-FRT-03 | Contagem de entregas abertas (`em_rota`) por entregador | S6 |
|
||
| RF-FRT-04 | Painel no cockpit: lista viva atualizada por socket | S6 |
|
||
| RF-FRT-05 | Histórico simples: entregas do turno / canceladas | S6–S8 |
|
||
|
||
#### C.2 Aceite
|
||
|
||
- Ao despachar, só aparecem entregadores `casa` (ou regra configurável).
|
||
- Quando o app marcar entrega, status volta a `casa` se fila zerada.
|
||
|
||
---
|
||
|
||
### Tela D — Gestor de Rotas (mapa + batch)
|
||
|
||
**Papel:** despacho.
|
||
**No vídeo / City Pro:** montar rota → despachar → acompanhar no mapa (não só preview).
|
||
|
||
#### D.0 Fluxo canónico (implementado)
|
||
|
||
```
|
||
Estufa (seleção ± bairro)
|
||
→ Preview mapa (opcional)
|
||
→ Montar rota → DispatchBatch status=montada
|
||
→ Atribuir motoboy
|
||
→ Despachar rota ✈ → status=na_rua · orders em_rota · 1ª parada a_caminho
|
||
→ Motoboy: a caminho / entregue por parada (+ ping GPS)
|
||
→ Última entrega → status=fechada · motoboy casa
|
||
```
|
||
|
||
Mapa **full-bleed** (bloco dominante) em `/despacho` — ver RF-VID-01…08 em SPEC-CITYFOODS-VIDEO-PARITY: todas as rotas/motoboys, filtro por entregador, pin some ao entregar, CTA **Ir para entrega**.
|
||
|
||
#### D.1 Requisitos
|
||
|
||
| ID | Requisito | Sprint | Status |
|
||
|----|-----------|--------|--------|
|
||
| RF-ROT-01 | Agrupar seleção por bairro (manual + sugestão) | S6 | ✅ |
|
||
| RF-ROT-02 | Sugerir ordem de visita (heurística bairro/CEP) | S6 | ✅ |
|
||
| RF-ROT-03 | Otimizar tour com ORS (OpenRouteService) | S7 | ✅ opcional (`ORS_API_KEY`; senão heurística) |
|
||
| RF-ROT-04 | Mapa no despacho com pontos + polyline da rota | S7 | ✅ |
|
||
| RF-ROT-04b | Entidade rota persistida `montada` \| `na_rua` \| `fechada` | S7 | ✅ `DispatchBatch` + `DispatchStop` |
|
||
| RF-ROT-04c | Despachar rota (não só SAIR solto) | S7 | ✅ `POST /api/routes/:id/dispatch` |
|
||
| RF-ROT-04d | Tracking motoboy no mapa (ping) | S7–S8 | ✅ `POST /api/routes/:id/ping` + `driver.ping` |
|
||
| RF-ROT-05 | Comparar custo: frota própria vs marketplace | S7–C2 | ❌ (após iFood) |
|
||
|
||
#### D.2 Aceite
|
||
|
||
- Batch de 2+ pedidos gera rota com código (`Rdd-nn`), ordem e motoboy.
|
||
- Mapa continua visível enquanto a rota está `montada` / `na_rua`.
|
||
- ORS só quando `ORS_API_KEY` + pedidos com geo/bairro resolvível (Joinville centroides MVP).
|
||
|
||
**API:** `/api/routes/*` · **UI:** `/despacho` · **Ref.:** rusterando (modelo, sem fork AGPL).
|
||
|
||
---
|
||
|
||
### Tela E — App / PWA Entregador
|
||
|
||
**Papel:** motoboy.
|
||
**No vídeo / Play Store CityFoods:** mapa, detalhes, iniciar e concluir entrega.
|
||
|
||
#### E.1 Requisitos
|
||
|
||
| ID | Requisito | Sprint | Status |
|
||
|----|-----------|--------|--------|
|
||
| RF-MOT-01 | Login entregador (role/área) | S8 | ⚠️ parcial (escolhe motoboy na UI; sem PIN) |
|
||
| RF-MOT-02 | Lista / rota ativa do motoboy | S8 | ✅ `/motoboy` + `GET /api/routes/driver/:id` |
|
||
| RF-MOT-03 | Mapa da rota + deep-link GPS | S8 | ✅ |
|
||
| RF-MOT-04 | Marcar “a caminho” / “entregue” | S8 | ✅ por parada da rota |
|
||
| RF-MOT-05 | Ping de posição (opt-in geolocation) | S8 | ✅ |
|
||
| RF-MOT-06 | Offline tolerante (fila local → sync) | S8+ | ❌ |
|
||
|
||
#### E.2 Aceite
|
||
|
||
- `entregue` via parada da rota; cockpit atualiza progresso e frota.
|
||
- Última parada fecha a rota e devolve motoboy a `casa` se sem fila.
|
||
|
||
---
|
||
|
||
### Tela F — Ranking de produção (ao vivo)
|
||
|
||
**Papel:** gestor / pizzaiolo.
|
||
**No vídeo:** Cláudio 95, Gil 86… pizzas/noite + tempo médio; remanejo por atraso.
|
||
|
||
#### F.1 Requisitos
|
||
|
||
| ID | Requisito | Sprint |
|
||
|----|-----------|--------|
|
||
| RF-RNK-01 | Bumps KDS creditados ao usuário logado na estação | S4–S5 |
|
||
| RF-RNK-02 | Ranking do turno: pizzas, tempo médio, atrasos | S5 |
|
||
| RF-RNK-03 | Tela TV/gestor só leitura (opcional) | S5 |
|
||
| RF-RNK-04 | Alerta “operador em zona de atraso” (N pedidos late) | S5 |
|
||
|
||
#### F.2 Aceite
|
||
|
||
- Dois logins na mesma estação não misturam contagem.
|
||
- Ranking zera/rotaciona por turno (config).
|
||
|
||
---
|
||
|
||
### Tela G — Funil operacional (métricas)
|
||
|
||
**Papel:** gestor.
|
||
**No vídeo:** tempos produção / forno / estufa / rua; identificar gargalo.
|
||
|
||
#### G.1 Requisitos
|
||
|
||
| ID | Requisito | Sprint |
|
||
|----|-----------|--------|
|
||
| RF-FUN-01 | Timestamps: created, claimed, bumped por estação, estufa, dispatched, delivered | S4 |
|
||
| RF-FUN-02 | Dashboard: p50/p90 por etapa do funil (dia/turno) | S5 |
|
||
| RF-FUN-03 | Contagem de cancelamentos do período | S5 |
|
||
| RF-FUN-04 | Distinto do Pooling comercial (faturado/ticket) — ou abas no mesmo painel gestor | S5 |
|
||
|
||
#### G.2 Aceite
|
||
|
||
- Gestor responde em < 10 s: “o gargalo agora é forno ou estufa ou rua?”.
|
||
|
||
---
|
||
|
||
### Tela H — Admin: zonas de entrega
|
||
|
||
**Papel:** gestor (Setup).
|
||
**No CityFoods (site):** áreas/bairros + taxas diferenciadas.
|
||
|
||
#### H.1 Requisitos
|
||
|
||
| ID | Requisito | Sprint |
|
||
|----|-----------|--------|
|
||
| RF-ZON-01 | CRUD zona: nome, polígono ou lista de bairros, taxa cents, tempo estimado | S6–S9 |
|
||
| RF-ZON-02 | PDV/cardápio aplica taxa pelo bairro/CEP | S9 / C1 |
|
||
| RF-ZON-03 | Despacho usa zona para agrupamento | S6 |
|
||
| RF-ZON-04 | Fora de zona → bloqueio ou taxa especial | S9 |
|
||
|
||
---
|
||
|
||
### Tela I — Admin: relatórios de entrega / equipe
|
||
|
||
**Papel:** gestor.
|
||
**No CityFoods City Pro / Cozinha Digital:** relatórios entregas + entregadores + operação cozinha.
|
||
|
||
#### I.1 Requisitos
|
||
|
||
| ID | Requisito | Sprint |
|
||
|----|-----------|--------|
|
||
| RF-REL-01 | Relatório entregas: qtd, tempo médio, cancelados, por canal | S8 |
|
||
| RF-REL-02 | Relatório entregadores: entregas, tempo rua, ranking | S8 |
|
||
| RF-REL-03 | Relatório cozinha: pizza/hora, atrasos por estação | S5 |
|
||
| RF-REL-04 | Export CSV (padrão estoque) | S5–S8 |
|
||
|
||
---
|
||
|
||
### Tela J — Integração marketplace (iFood) no despacho
|
||
|
||
**Papel:** sistema + despacho.
|
||
**No vídeo:** cotação API iFood vs própria; ~70% do fluxo.
|
||
|
||
#### J.1 Requisitos
|
||
|
||
| ID | Requisito | Track |
|
||
|----|-----------|-------|
|
||
| RF-IFO-01 | Webhook iFood → Order normalizado (idempotente) | C2 |
|
||
| RF-IFO-02 | Pedido aparece na Central + KDS + Despacho com canal iFood | C2 |
|
||
| RF-IFO-03 | Cotação frete marketplace vs frota (UI no batch) | C2 + S7 |
|
||
| RF-IFO-04 | Sync status pronto/despachado quando política da loja exigir | C2 |
|
||
|
||
> Só após Central + despacho interno estáveis (gate SPEC mãe).
|
||
|
||
---
|
||
|
||
## 3. Mapa tela → sprint (resumo executivo)
|
||
|
||
| Tela | Nome | Sprint / track | Prioridade | Status |
|
||
|------|------|----------------|------------|--------|
|
||
| **A** | Cockpit Despacho | S4 → S6 | P0 | ✅ |
|
||
| **B** | Conferência / Estufa | S4 | P0 | ✅ |
|
||
| **C** | Frota | S6 | P1 | ✅ |
|
||
| **D** | Gestor de Rotas / mapa | S6 → S7 | P1–P2 | ✅ (ORS opcional) |
|
||
| **E** | App entregador | S8 | P2 | ✅ parcial |
|
||
| **F** | Ranking produção | S5 | P1 | ✅ `/ops` |
|
||
| **G** | Funil operacional | S4–S5 | P1 | ✅ `/ops` |
|
||
| **H** | Zonas / taxas | S6–S9 | P2 | ✅ CRUD · ❌ taxa no PDV |
|
||
| **I** | Relatórios | S5–S8 | P2 | ✅ básico |
|
||
| **J** | iFood no fluxo | C2 | P3 | ❌ |
|
||
|
||
---
|
||
|
||
## 4. Dados (implementados)
|
||
|
||
```
|
||
Driver { id, storeId, name, phone, active, opsStatus, lastLat?, lastLng?, lastPingAt? }
|
||
Order + estufaAt, driverId, lat?, lng?, batchId?, dispatchedAt, deliveredAt, priority
|
||
DeliveryZone { storeId, name, neighborhoods[], feeCents, etaMinutes, active }
|
||
DispatchBatch {
|
||
id, storeId, code, driverId?, status: montada|na_rua|fechada,
|
||
method, distanceKm?, depotLat, depotLng, polyline?,
|
||
plannedAt, dispatchedAt?, closedAt?
|
||
}
|
||
DispatchStop {
|
||
id, batchId, orderId, seq, lat, lng,
|
||
status: pendente|a_caminho|entregue, arrivedAt?, deliveredAt?
|
||
}
|
||
```
|
||
|
||
Ranking usa `PrepTask` (claimedBy + completedAt). Funil usa timestamps do `Order`.
|
||
|
||
---
|
||
|
||
## 5. Eventos Socket
|
||
|
||
| Evento | Quando | Quem escuta |
|
||
|--------|--------|-------------|
|
||
| `order.ready` | Estufa / pronto | Despacho |
|
||
| `order.priority` | Reordenação | KDS + Despacho |
|
||
| `order.dispatched` | Despacho de rota / SAIR | Despacho + Frota |
|
||
| `order.delivered` | Entregue | Despacho + Relatórios |
|
||
| `driver.updated` | casa/rua | Cockpit frota |
|
||
| `driver.ping` | GPS motoboy | Mapa despacho |
|
||
| `route.updated` | Montar / parada / fecho | Despacho + Motoboy |
|
||
| `route.dispatched` | Despachar rota | Despacho + Motoboy |
|
||
| `route.closed` | Rota fechada | Despacho + Frota |
|
||
|
||
---
|
||
|
||
## 6. Critério de “mesmo nível” (definição de pronto)
|
||
|
||
Paridade operacional com o vídeo **atingida** quando:
|
||
|
||
1. ✅ Cockpit A em `/despacho`
|
||
2. ✅ Conferência B + estufa alimentam o cockpit
|
||
3. ✅ Frota C no SAIR / despacho de rota
|
||
4. ✅ Gestor de Rotas D: montar → despachar → mapa permanente
|
||
5. ✅ Funil G + ranking F em `/ops`
|
||
6. ✅ App motoboy E consome a **mesma rota**
|
||
|
||
**Ainda pode faltar** para paridade comercial City Pro: ORS com chave em produção, PIN/offline motoboy, taxa zona no PDV, iFood cotação, multi-loja — P2+/P3.
|
||
|
||
---
|
||
|
||
## 7. Fora de escopo (neste SPEC)
|
||
|
||
- Programa de fidelidade CityFoods
|
||
- Pop-ups / destaques cardápio
|
||
- Caixa completo / fechamento de turno financeiro
|
||
- Multi-tenant white-label
|
||
- Fork ou cópia de UI proprietária CityFoods (só modelo operacional)
|
||
|
||
---
|
||
|
||
## 8. Próximo passo
|
||
|
||
1. **P3 / C2 — iFood** no fluxo (webhook → Central/KDS/Despacho)
|
||
2. Polimento: `ORS_API_KEY` em prod · taxa zona no PDV · PIN motoboy · CSV relatórios
|
||
|
||
---
|
||
|
||
*Documento derivado do cruzamento vídeo yVtcgJt0L_Q × pizza.itecnologys.com × SPEC §15. v0.2.0 — Gestor de Rotas documentado pós-implementação.*
|