Branch Leaderboard
Visão Geral
Ranking de unidades por KPI configurável. Útil para chains que querem visibilidade comparativa entre filiais e gerar competição saudável (ou identificar quem precisa suporte).
Visível só quando o tenant tem 2+ branches ativas.
Localização
| Camada | Arquivo |
|---|---|
| Service | backend/src/branches/branch-leaderboard.service.ts |
| Controller | backend/src/orders/orders.controller.ts (endpoint stats/branch-leaderboard) |
| View | frontend-react/src/views/admin/BranchLeaderboardView.tsx |
| Variant cozinha | frontend-react/src/views/admin/KitchenBranchLeaderboardView.tsx |
Rotas
| Rota | Conteúdo |
|---|---|
/admin/branch-leaderboard | Ranking geral |
/admin/kitchen/branch-leaderboard | Variante focada em SLA da cozinha |
KPIs Disponíveis
| KPI | Cálculo | Sentido |
|---|---|---|
revenue | Σ revenue | Maior = melhor |
avgTicket | revenue ÷ covers | Maior = melhor |
cmvPercent | COGS ÷ revenue × 100 | Menor = melhor |
tableTurnover | covers ÷ tables ÷ horas | Maior = melhor |
kdsSlaCompliance | % pedidos delivered dentro de slaMinutes | Maior = melhor |
cancellationRate | cancelled ÷ total | Menor = melhor |
Default ordering por revenue descendente. Toggle no header altera KPI ordenado.
Endpoint
GET /t/:slug/orders/stats/branch-leaderboard?from=&to=&kpi=revenue
Resposta:
{
"period": { "from": "2026-04-01", "to": "2026-04-30" },
"kpi": "revenue",
"branches": [
{
"branchId": "...",
"name": "Centro",
"revenue": 285400,
"covers": 4720,
"avgTicket": 60.46,
"cmvPercent": 31.2,
"tableTurnover": 2.8,
"rank": 1,
"deltaVsLastPeriod": 0.085
}
]
}deltaVsLastPeriod permite o frontend mostrar setas de tendência (▲ verde ou ▼ vermelho).
Aggregation
BranchLeaderboardService.getRanking(tenantId, period, kpi):
- Lê
KpiSnapshotpor branch agrupando o período - Computa o KPI selecionado
- Ordena conforme sentido (maior ou menor primeiro)
- Calcula
deltaVsLastPeriodlendo o período anterior de mesma duração - Atribui
rankem sequência
Performance: aproximadamente 50ms para 10 branches × 30 dias. Para chains de 100+ unidades, considere cache Redis (TTL 1 hora) — não implementado por ora.
Anonimização (Franchise mode)
Quando o tenant é franqueador (Tenant.isFranchisor: true), o leaderboard mostrado para uma franquia individual é anonimizado:
- Sua própria unidade aparece com nome
- Outras unidades viram "Unidade #2", "Unidade #3", etc.
- Posição relativa preservada
Master franchisor vê tudo com nome.
Lógica em BranchLeaderboardService.applyAnonymization(viewerTenantId, ranking).
Variant: Kitchen Leaderboard
KitchenBranchLeaderboardView foca em métricas operacionais:
- SLA compliance (% dentro do tempo configurado)
- Tempo médio de preparo por categoria
- Throughput pico (pedidos/hora no horário mais movimentado)
Útil para gerentes de cozinha competirem em eficiência sem entrar em revenue (que pode depender de fatores fora do controle deles, como localização).
Permissões
Permission.ReportsViewAllpara ver leaderboard geralPermission.OrdersViewAllpara ver kitchen leaderboard- Branch managers veem apenas o ranking — não números absolutos das outras unidades (a menos que sejam admin)