## MG-5 — Apuração e classificação materializada em Cloud Functions

**PRD:** `docs/prd/migracao-firebase.md`

**Como** participante, **quero** que o ponto seja calculado pelo servidor e o
ranking apareça na hora, **para** ninguém precisar acreditar em ninguém.

**Prioridade:** Must — é o coração do produto e a regra que o cliente nunca pode
calcular.

**Critérios de aceite:**

- Dado que um jogo recebe placar final, então os palpites daquele jogo são apurados
  pela tabela **do bolão** (não por constantes), e a classificação é atualizada.
- Dado um bolão 20/10/5, então o placar exato vale 20 — no ranking **e** no extrato.
- Dado que palpitei `1x1` num jogo que terminou `4x4`, então valem **3** pontos: todo
  empate tem saldo zero e não existe faixa de saldo para empate.
- Dado que dois participantes empatam em pontos, então a ordem sai pela ordem de
  desempate **configurada no bolão**, e o critério aplicado fica visível para os
  dois lados.
- Dado que um placar é corrigido depois da apuração, então a pontuação é
  recalculada, a classificação acompanha e quem foi afetado é avisado — com **um**
  aviso consolidado quando vários jogos mudam de uma vez.
- Dado um bolão com 60 participantes, quando a apuração roda, então ela não estoura
  o limite de operações por transação.
- Dado que a apuração roda duas vezes para o mesmo jogo, então o ponto não dobra.

**Tasks:**

_Backend_
- [ ] `BE-1` Portar `scoring.service` para Function pura, sem dependência de Prisma (depende de MG-2 BE-1)
- [ ] `BE-2` Gatilho de escrita do jogo dispara a apuração (depende de BE-1)
- [ ] `BE-3` Classificação materializada atualizada na apuração, com desempate configurável (depende de BE-1, MG-2 BE-4)
- [ ] `BE-4` Extrato: composição em memória de palpite + jogo, sem `join` (depende de BE-1)
- [ ] `BE-5` Correção manual de placar pelo admin, com trilha de auditoria (depende de BE-2)
- [ ] `BE-6` Aviso consolidado por participante quando vários jogos são corrigidos juntos (depende de BE-5)
- [ ] `BE-7` Escrita em lote para bolão grande, respeitando o limite de 500 operações (depende de BE-3)
- [ ] `BE-8` Idempotência: apurar duas vezes não dobra ponto nem duplica registro (depende de BE-2)

_QA_
- [ ] `QA-1` Escrever o plano de casos de teste a partir desta story
- [ ] `QA-2` Executar reaproveitando `PR-1`, `PR-2`, `PR-5`, `PR-6`, `PR-7` e `PR-10`, mais o caso de bolão grande

**Riscos/Dependências:**

- Depende de `MG-2`. **Exige Blaze para publicar**, não para testar em emulador.
- **Limite de 500 operações por transação** é o risco técnico real: bolão de 60
  pessoas × jogos da rodada passa disso. Daí `BE-7`.
- A regra do empate (`1x1` num `4x4` = 3 pontos) foi **confirmada pelo dono em
  07/08**. Mudança aqui altera pontos já registrados.
