# Plano de testes — `MG-7` App falando com o Firebase

**Story:** `docs/stories/MG-7-app-no-firebase.md`

O critério desta story é estranho de testar porque é uma **ausência**: se o
participante notar a troca, algo quebrou. Não há tela nova para verificar, e o
teste que "passa" pode estar passando contra a stack antiga.

Por isso o plano tem três frentes, e a primeira é a que ninguém tinha escrito:

1. **Escrita no Firestore** (01 a 70) — as callables de participação, regras,
   ciclo de vida e correção de placar. `MG-2`
   modelou os dados e escreveu as rules que **protegem** as coleções; ninguém
   tinha escrito quem **escreve** nelas. Sem isso o app não tem como criar bolão,
   convidar ou entrar, e `FE-1`/`FE-2` não teriam com o que falar.
2. **Camada de dados do app** (71 a 78) — os mesmos repositórios, agora sobre
   Firestore, com o cache e o rascunho offline preservados.
3. **Em device** (79 a 84) — convite → palpite → ranking, offline e com o relógio
   do aparelho alterado. É a única frente que prova a ausência: as telas não
   mudaram.

A coluna **Origem** aponta o caso equivalente no plano do NestJS. Ela é o que
transforma cada linha em comparação: mesma regra, backend diferente, resultado
tem de ser o mesmo. Divergência ali é **defeito de migração**, não comportamento
novo. "novo" é regra que não existia porque o problema não existia no Postgres.

## Frente 1 — participação no Firestore

| ID | Título | Tipo | Origem |
| -- | ------ | ---- | ------ |
| MG-7-01 | Criar bolão põe o criador dentro como admin | caminho feliz | `CC-1-02` |
| MG-7-02 | O bolão criado aparece na tela inicial | caminho feliz | `CC-10-01` |
| MG-7-03 | Rodadas sem jogo não viram bolão vazio | regra de negócio | `CC-1-01` |
| MG-7-04 | Fonte fora do ar não cria bolão pela metade | resiliência | `CC-1-03` |
| MG-7-05 | Rodada final antes da inicial é recusada | validação | `CC-1-13` |
| MG-7-06 | Bolão só de rodadas passadas nasce avisando | regra de negócio | `CC-1-08` |
| MG-7-07 | Criar não sobrescreve placar de jogo já existente | integridade | `CC-1-11` |
| MG-7-08 | Quem entra pelo convite vira participante | caminho feliz | `CC-5-01` |
| MG-7-09 | Abrir o mesmo link duas vezes não duplica | idempotência | `CC-5-08` |
| MG-7-10 | Gerar outro convite mata o link anterior | segurança | `CC-4-06` |
| MG-7-11 | Convite invalidado para de funcionar | segurança | `CC-4-07` |
| MG-7-12 | Convite expirado diz que expirou | mensagem | `CC-5-04` |
| MG-7-13 | Só admin gera convite | autorização | `CC-4-05` |
| MG-7-14 | Bolão já começado não gera convite | regra de negócio | `CC-4-08` |
| MG-7-15 | Convite gerado antes do apito não vale depois | regra de negócio | `CC-5-06` |
| MG-7-16 | Quem saiu não volta pelo convite | regra de negócio | `CC-5-09` |
| MG-7-17 | Bolão encerrado não aceita entrada | regra de negócio | `CC-5-07` |
| MG-7-18 | Sair tira da tela inicial e mantém o histórico | regra de negócio | `CV-4-02` |
| MG-7-19 | A contagem de participantes acompanha entrada e saída | integridade | `CC-10-07` |
| MG-7-20 | Quem criou não sai, não é removido, não é rebaixado | regra de negócio | `CV-4-07` |
| MG-7-21 | O bolão nunca fica sem admin | regra de negócio | `CC-8-05` |
| MG-7-22 | Promover reflete no índice de quem foi promovido | integridade | `CC-8-01` |
| MG-7-23 | Admin remove; o removido não some do bolão | regra de negócio | `CC-9-01` |
| MG-7-24 | Admin usa "sair" para sair, não "remover" | validação | `CC-9-09` |
| MG-7-25 | Renomear chega na tela inicial de todos | integridade | novo |
| MG-7-26 | Encerrar aparece rotulado na tela inicial | integridade | `CC-10-05` |

## Frente 1b — regras, ciclo de vida e correção

| ID | Título | Tipo | Origem |
| -- | ------ | ---- | ------ |
| MG-7-41 | Admin altera as regras antes do primeiro palpite | caminho feliz | `CC-2-08` |
| MG-7-42 | Participante comum não altera as regras | autorização | `CC-2-10` |
| MG-7-43 | O primeiro palpite trava as regras | regra de negócio | `CC-3-02` |
| MG-7-44 | Jogo pendente bloqueia o encerramento | regra de negócio | `CV-1-02` |
| MG-7-45 | Tudo apurado encerra e devolve o campeão | caminho feliz | `CV-1-01` |
| MG-7-46 | Encerrar duas vezes é idempotente | borda | `CV-1-04` |
| MG-7-47 | Ninguém pontuou: encerra sem campeão | borda | `CV-1-09` |
| MG-7-48 | Encerramento antecipado fica marcado como tal | regra de negócio | `CV-3-02` |
| MG-7-49 | Arquivar exige encerrar antes, e volta atrás | regra de negócio | `CV-6-02` |
| MG-7-50 | Recriar herda regras e galera, e zera a pontuação | caminho feliz | `CV-7-01` |
| MG-7-51 | Quem foi reconvidado é avisado | regra de negócio | `CV-7-05` |
| MG-7-52 | Recriar exige a temporada atual encerrada | regra de negócio | `CV-7-07` |
| MG-7-53 | Temporada nova sem jogo na fonte não é criada | borda | novo |
| MG-7-54 | O bolão novo aparece para quem foi herdado | integridade | `CV-7-02` |
| MG-7-55 | Admin corrige, com trilha e origem registradas | caminho feliz | `PR-10-01` |
| MG-7-56 | A correção reapura pelo gatilho da fonte oficial | regra de negócio | `PR-6-01` |
| MG-7-57 | Placar igual ao que já estava não mexe em nada | borda | `PR-10-04` |
| MG-7-58 | Participante comum não corrige placar | autorização | `PR-10-02` |
| MG-7-59 | Jogo que não começou não recebe placar | validação | `PR-10-03` |
| MG-7-60 | W.O.: jogo passado sem placar é corrigível | borda | `PR-10-03b` |
| MG-7-61 | Jogo fora das rodadas do bolão não é corrigível | autorização | novo |
| MG-7-62 | Quem mudou de ponto é avisado, e o aviso diz que foi o admin | caminho feliz | `PR-7-01` |
| MG-7-63 | Dois jogos corrigidos seguidos viram um aviso só | regra de negócio | `PR-7-05` |
| MG-7-64 | Quem não mudou nada não recebe aviso | regra de negócio | `PR-7-02` |
| MG-7-65 | O texto diz a mudança líquida de posição | mensagem | `PR-7-04` |
| MG-7-66 | O extrato explica cada ponto e a soma bate | caminho feliz | `PR-2-01` |
| MG-7-67 | Jogo terminado sem palpite vale zero, e diz isso | regra de negócio | `PR-2-05` |
| MG-7-68 | Jogo com prazo aberto não aparece como zero | borda | `PR-2-04` |
| MG-7-69 | Quem não participa não lê extrato nem ranking | autorização | `PR-2-08` |
| MG-7-70 | Ranking da rodada diz que é parcial | regra de negócio | `PR-4-04` |

## Frente 2 — camada de dados do app

| ID | Título | Tipo |
| -- | ------ | ---- |
| MG-7-71 | Os repositórios trocam de fonte sem a apresentação saber | arquitetura |
| MG-7-72 | Apontar para o emulador é configuração, não código comentado | configuração |
| MG-7-73 | Lista de bolões e ranking guardados abrem sem rede, com a idade visível | offline |
| MG-7-74 | Rascunho de palpite sobrevive ao app fechado | offline |
| MG-7-75 | Fila de envio sobe quando a rede volta, sem duplicar | offline |
| MG-7-76 | A contagem de prazo segue o horário do servidor | regra de negócio |
| MG-7-77 | Ranking de 60 participantes é uma leitura | custo |
| MG-7-78 | Recusa da callable vira mensagem específica, não "erro" | mensagem |

## Frente 3 — em device

| ID | Título | Tipo |
| -- | ------ | ---- |
| MG-7-79 | Convite → palpite → ranking, ponta a ponta | caminho feliz |
| MG-7-80 | Palpite feito sem rede sobe ao voltar a conexão | offline |
| MG-7-81 | Relógio do aparelho adiantado não abre prazo fechado | segurança |
| MG-7-82 | Cold start com sessão válida entra direto | caminho feliz |
| MG-7-83 | Deep link de convite com o app fechado leva ao bolão | caminho feliz |
| MG-7-84 | Nenhuma tela mudou de comportamento | regressão |

## Fora deste plano

- **Paridade completa dos 234 casos** é `MG-8`, não aqui. Este plano cobre o que
  a troca de camada põe em risco.
- **Push e lembrete** (`MG-6 BE-3`/`BE-4`) dependem de app registrado no projeto
  real e entram junto com a verificação em device.
