Audit — Coordenador não conseguia copiar o link do Mural
Data: 2026-05-03 Escopo: Edge Function
mural-escola(batch_init), hookuseMuralEscola, UI "Mural Olímpico" Severidade: Alta — feature visível ao gestor escolar parecia indisponível Status: Resolvido (Wave 7)
1. Sintoma reportado
Coordenador autenticado via OLP, ao acessar Mural Olímpico, não enxergava o link público da escola e não conseguia copiá-lo. A UI exibia o estado "Mural não configurado" mesmo para escolas com escola_mural_config.mural_slug válido e mural_ativo = true.
2. Hipótese inicial (descartada): RLS
Suspeita: a policy de escola_mural_config estaria bloqueando coordenador/diretor. Verificação:
- Policy
escola_mural_config_select_coordenador_diretorexiste e cobre os papéis. principal_role IN ('coordenador','diretor')+escola_id::text = (auth.jwt()->>'escola_id')casa o JWT real do usuário afetado.- Query manual com a mesma chave de claim retorna a linha esperada.
Conclusão: RLS não é a causa. A policy está correta — ver MURAL_OVERVIEW.md §RLS.
3. Causa raiz
Regressão de orquestração no batch_init da Edge Function mural-escola:
// ANTES (bug)
const [pubResult, olimpResult, portalResult] = await Promise.all([
publicacoesQuery,
olimpiadasQueryA,
olimpiadasQueryB, // duplicata
portalConfigQuery, // resultado IGNORADO pelo destructuring
]);
// portalResult recebia a 3ª posição (olimpíadas duplicadas), não o portal.Sintomas observáveis nos logs:
✅ batch_init escola=<uuid>: 12 pub, 4 olimp, portal.slug=null (ok)diagnostico='ok' + slug=null em escola comprovadamente configurada é o anti-sinal que deveria ter sido tratado antes como erro de integração.
4. Correção aplicada
Arquivo: supabase/functions/mural-escola/index.ts
- Removida a query duplicada de olimpíadas no
Promise.all. - Destructuring agora casa 1:1 com as queries (
pubResult,olimpResult,portalResult). escola_mural_configlida via.maybeSingle()para distinguir corretamente "linha ausente" de "erro técnico".portalDiagnosticopassou a ser explícito em 4 estados:
| Estado | Quando |
|---|---|
ok | Linha encontrada e shape válido (mural_slug, mural_ativo) |
not_configured | Sem linha (PGRST116 ou data === null) |
rls_blocked | Erro 42501 |
error | Qualquer outro erro técnico ou shape inesperado |
- Endurecimento de shape: se
datanão tivermural_slugstring oumural_ativoboolean, retornaerrorem vez de mascarar comook. useMuralEscolaconfirmado preservando comportamento fail-close (nunca inventa slug).
5. Lição / regra preventiva
Edge Function —
Promise.allcom destructuring O número de variáveis noconst [...]DEVE ser idêntico ao número de queries no array. Quando o array tiver ≥3 itens, é obrigatório code review específico desse trecho. Verdocs/development/CODING_STANDARDS.md.
Anti-sinal a tratar como bug
diagnostico='ok'com campo de identidade nulo (slug, id, …) em registro confirmadamente existente no banco = problema de integração/orquestração, nunca "comportamento esperado". Verdocs/development/PROBLEM_SOLVING.mdCaso 14.
6. Validação pós-correção
- Coordenador da escola afetada: link copiado com sucesso,
portal.slugpopulado nos logs. batch_initpara escola sem config:diagnostico='not_configured'+ UI exibe estado correto.- Sem regressão em listas de publicações ou olimpíadas.
7. Referências
supabase/functions/mural-escola/index.tssrc/hooks/useMuralEscola.tsdocs/features/MURAL.md— seção "Diagnóstico do portal"docs/mural/MURAL_OVERVIEW.mddocs/development/PROBLEM_SOLVING.md— Caso 14