## MG-2 — Modelo de dados no Firestore e regras de participação

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

**Como** time, **quero** as 12 tabelas traduzidas para coleções com as regras de
acesso escritas, **para** o resto da migração ter onde se apoiar.

**Prioridade:** Must — modelo errado no Firestore não se corrige com refactor, se
corrige com migração de dados.

**Critérios de aceite:**

- Dado um bolão, quando alguém que não participa tenta ler qualquer documento dele,
  então a leitura é recusada pela **regra**, não por filtro de aplicação.
- Dado que saí do bolão, então perco a leitura, e os meus palpites e pontos
  **permanecem** para o histórico do bolão.
- Dado que sou participante comum, quando tento escrever em documento de outro
  participante, então a escrita é recusada.
- Dado o ranking de um bolão com 60 participantes, quando a tela abre, então é
  **uma** leitura — não uma por participante.
- Dado que o modelo mudou, então existe um mapa escrito de tabela → coleção, com o
  que foi desnormalizado e **por quê**.

**Tasks:**

_Backend_
- [x] `BE-1` Coleções e subcoleções conforme o mapa do spike, com IDs determinísticos
- [x] `BE-2` Security rules de participação: leitura do bolão só para membro ativo (depende de BE-1)
- [x] `BE-3` Security rules de papel: ação de admin só para admin, criador imutável (depende de BE-2)
- [x] `BE-4` Agregado materializado de classificação, para o ranking ser uma leitura (depende de BE-1)
- [x] `BE-5` Índices compostos declarados no `firestore.indexes.json` (depende de BE-1)

_QA_
- [x] `QA-1` Escrever o plano de casos de teste a partir desta story
- [x] `QA-2` Executar com `@firebase/rules-unit-testing`, cobrindo não participante, quem saiu, membro comum e admin

**Riscos/Dependências:**

- Depende de `MG-1`.
- **O ranking é o risco de custo, não de correção.** Somar pontos na leitura
  estoura o free tier; por isso `BE-4` é task e não otimização futura.
- Reaproveitar os IDs dos casos de `PR-3` e `CC-7` no plano: são os mesmos critérios,
  outro mecanismo.

- **07/08 — feita e verificada.** 28 casos de security rule verdes
  (`functions/src/participacao.spec.ts`), plano em `docs/testes/MG-2-plano.md`,
  execução em `docs/testes/MG-2-execucao.md`. O schema vive em
  `functions/src/modelo.ts` — o Firestore não tem schema, então esse arquivo **é**
  o contrato que as rules assumem.
- **Correção de desenho encontrada por teste:** a lista de "meus bolões" não pode
  ser consulta de **grupo** em `membros`. No `list` de consulta de grupo o `{uid}`
  do caminho não é vinculado e a rule não inspeciona o `where` — não há como provar
  que a pessoa pediu só o que é dela (`Null value error`). Virou índice sob o
  próprio usuário (`usuarios/{uid}/boloes/{poolId}`), com o resumo dentro: uma
  leitura, rule sem `get()`, e o spike foi corrigido.
- **`BE-4` entrega estrutura e acesso da classificação**, não o escritor: quem
  preenche é a Function de apuração em `MG-5 BE-3`. A rule já garante o que
  importa — cliente lê, cliente **não** escreve.
- **`BE-5`: nenhum índice composto é necessário ainda**, e isso está declarado em
  vez de suposto. ⚠️ O emulador **não exige** índice, então consulta que precisaria
  de um passa aqui e falha em produção — verificação obrigatória de `MG-8` contra o
  projeto real.
