Sistema de Canary Release — Plano Completo
Status: Implementado (Fases 1-6)
Criado em: 2026-03-06
Última atualização: 2026-03-26
Alteração recente: Especialista removido do bypass de feature flags; Admin removido da UI de flags
1. Visão Geral
Sistema interno de Release Management com estratégia Canary Release para liberar funcionalidades gradualmente para grupos controlados de escolas antes do rollout geral.
Objetivos
- Controle de deploy do frontend: gerenciar qual versão do app vai ao ar
- Changelog interno: registrar versões e mudanças para a equipe
- Feature Flags: ligar/desligar funcionalidades sem novo deploy
- Controle por escola: liberar features gradualmente, escola por escola
- Canary Release: validar com grupo piloto antes de promover para todos
2. Arquitetura
text
┌─────────────────────────────────────────────────┐
│ Admin Panel: "Releases & Versões" │
│ ├── Changelog (histórico de versões) │
│ ├── Feature Flags (toggle de funcionalidades) │
│ └── Canary Groups (grupos de rollout) │
└──────────────┬──────────────────────────────────┘
│
┌──────────▼──────────┐
│ Edge Function │
│ release-manager │
│ (CRUD + consulta) │
└──────────┬──────────┘
│
┌──────────▼──────────────────────────┐
│ Tabelas Supabase │
│ ├── releases (changelog/versões) │
│ ├── feature_flags (flags globais) │
│ ├── canary_groups (grupos) │
│ ├── canary_group_escolas (vínculo) │
│ └── feature_flag_canary (flag↔grupo)│
└─────────────────────────────────────┘
│
┌──────────▼──────────────────────────┐
│ Frontend │
│ ├── useFeatureFlags() hook │
│ ├── FeatureFlagsProvider context │
│ └── <FeatureGate> component │
└─────────────────────────────────────┘3. Banco de Dados
3.1 Tabela releases — Changelog / Versionamento
| Coluna | Tipo | Descrição |
|---|---|---|
id | uuid PK | |
versao | text NOT NULL UNIQUE | Ex: "2.4.0" |
titulo | text NOT NULL | Título da release |
descricao | text | Notas da versão (Markdown) |
tipo | enum('major','minor','patch','hotfix') | Classificação semântica |
status | enum('rascunho','canary','liberada','arquivada') | Ciclo de vida |
publicada_em | timestamptz | Quando foi liberada para todos |
rollback_snapshot | jsonb | Snapshot do estado de flags antes da promoção |
criado_por | uuid FK usuarios | Admin que criou |
criado_em | timestamptz DEFAULT now() | |
atualizado_em | timestamptz DEFAULT now() |
3.2 Tabela feature_flags — Flags de Funcionalidade
| Coluna | Tipo | Descrição |
|---|---|---|
id | uuid PK | |
chave | text UNIQUE NOT NULL | Ex: "mural_v2", "novo_calendario" |
nome | text NOT NULL | Nome legível |
descricao | text | O que a flag controla |
ativa_global | boolean DEFAULT false | Liberada para todos? |
release_id | uuid FK releases NULL | Vinculada a qual release |
criado_em | timestamptz DEFAULT now() | |
atualizado_em | timestamptz DEFAULT now() |
3.3 Tabela canary_groups — Grupos de Rollout
| Coluna | Tipo | Descrição |
|---|---|---|
id | uuid PK | |
nome | text NOT NULL | Ex: "Beta Testers", "Escolas Piloto" |
descricao | text | |
ativo | boolean DEFAULT true | |
criado_em | timestamptz DEFAULT now() | |
atualizado_em | timestamptz DEFAULT now() |
3.4 Tabela canary_group_escolas — Escolas em Cada Grupo
| Coluna | Tipo | Descrição |
|---|---|---|
id | uuid PK | |
canary_group_id | uuid FK canary_groups | |
escola_id | uuid FK escolas | |
adicionada_em | timestamptz DEFAULT now() | |
| UNIQUE(canary_group_id, escola_id) |
3.5 Tabela feature_flag_canary — Flags Liberadas por Grupo
| Coluna | Tipo | Descrição |
|---|---|---|
id | uuid PK | |
feature_flag_id | uuid FK feature_flags | |
canary_group_id | uuid FK canary_groups | |
criado_em | timestamptz DEFAULT now() | |
| UNIQUE(feature_flag_id, canary_group_id) |
3.6 Tabela canary_group_usuarios — Usuários em Cada Grupo
| Coluna | Tipo | Descrição |
|---|---|---|
id | uuid PK | |
canary_group_id | uuid FK canary_groups | |
usuario_id | uuid FK usuarios | |
adicionado_em | timestamptz DEFAULT now() | |
| UNIQUE(canary_group_id, usuario_id) |
Uso: Permite canary por usuário individual (ex: especialista ou admin de teste). Usado pelo
checkCanaryAccess()emfeature-gate.ts.
3.7 RLS
- Todas as tabelas: RLS ativado
- Somente
administradorpode ler/escrever (via RBAC no Edge Function) - Consulta de flags ativas usa security definer function para performance
3.8 Feature Gate — Bypass
| Papel | Bypass de Feature Flags | Bypass de Permissões |
|---|---|---|
administrador | ✅ Total (BYPASS_ROLES em feature-gate.ts) | ✅ Menu completo sem filtro |
especialista | ❌ Sujeito a flags (removido do bypass em Mar/2026) | N/A (sem tabela de permissões) |
escola/coordenador/diretor | ❌ Sujeito a flags | ❌ Sujeito a usuarios_escola_permissoes |
4. Edge Function: release-manager
Actions Autenticadas (papel administrador)
| Action | Descrição |
|---|---|
list_releases | Listar releases com paginação |
create_release | Criar nova release |
update_release | Atualizar release existente |
list_flags | Listar feature flags |
create_flag | Criar nova flag |
update_flag | Atualizar flag |
toggle_flag | Toggle ativa_global |
list_canary_groups | Listar grupos canary |
create_canary_group | Criar grupo |
update_canary_group | Atualizar grupo |
add_escola_to_group | Adicionar escola a grupo |
remove_escola_from_group | Remover escola de grupo |
assign_flag_to_group | Vincular flag a grupo canary |
remove_flag_from_group | Desvincular flag de grupo |
promote_release | Canary → Liberada (ativa_global=true para todas flags) |
rollback_release | Reverter release (restaura snapshot) |
Action Pós-Auth (qualquer papel com escola)
| Action | Descrição |
|---|---|
get_active_flags | Retorna array de chaves ativas para a escola do JWT |
Lógica de get_active_flags
sql
-- Flags ativas para uma escola específica:
-- 1. Flags com ativa_global = true
-- 2. OU flags vinculadas a um grupo canary que contém a escola
SELECT DISTINCT ff.chave
FROM feature_flags ff
WHERE ff.ativa_global = true
UNION
SELECT DISTINCT ff.chave
FROM feature_flags ff
JOIN feature_flag_canary ffc ON ffc.feature_flag_id = ff.id
JOIN canary_group_escolas cge ON cge.canary_group_id = ffc.canary_group_id
WHERE cge.escola_id = $escola_id;5. Frontend
5.1 Hook useFeatureFlags()
typescript
// Carrega flags ativas no boot via get_active_flags
// Cache com React Query (staleTime: 10min)
const { hasFlag, flags, isLoading } = useFeatureFlags();5.2 Context FeatureFlagsProvider
- Wrapa o app inteiro
- Carrega flags no boot (após autenticação)
- Disponibiliza
hasFlag()para toda a árvore
5.3 Componente <FeatureGate>
tsx
// Renderiza children somente se a flag está ativa
<FeatureGate flag="mural_v2">
<MuralV2 />
</FeatureGate>
// Com fallback para versão anterior
<FeatureGate flag="mural_v2" fallback={<MuralV1 />}>
<MuralV2 />
</FeatureGate>5.4 Painel Admin: seção "Releases"
- Aba Versões: Lista de releases com status, criar/editar, visualizar changelog em Markdown
- Aba Feature Flags: Tabela de flags, toggle global, ver quais grupos canary têm acesso
- Aba Grupos Canary: Criar grupos, vincular escolas, vincular flags
- Ação "Promover": Botão que muda release de canary → liberada
- Ação "Reverter": Botão que restaura snapshot e desativa flags
6. Fluxo Canary na Prática
- Admin cria uma Release "v2.5.0" com status
rascunho - Cria feature flags:
novo_mural,calendario_v2 - Vincula flags à release
- Cria grupo canary "Escolas Piloto" com 3 escolas
- Vincula flags ao grupo canary
- Muda status da release para
canary - Escolas do grupo passam a ver as funcionalidades via
<FeatureGate> - Após validação, clica "Promover para Produção"
- Sistema salva snapshot do estado atual
ativa_global = truepara todas as flags da release- Status muda para
liberada
- Todas as escolas passam a ver as funcionalidades
- Se algo der errado: "Reverter" restaura o snapshot
7. Inovações Planejadas
7.1 Rollout Progressivo Automático (Auto-Promote) — V2.0
Regras configuráveis de promoção automática:
- "Se 0 erros reportados em 48h no grupo canary → promover"
- "Se 80% das escolas do grupo acessaram a feature → promover"
- Percentual progressivo: 5% → 25% → 50% → 100%
7.2 Rollback com Um Clique + Snapshot — MVP
- Snapshot JSONB salvo antes de cada promoção
- Botão "Reverter" restaura estado anterior
- Histórico de rollbacks visível no changelog
7.3 Métricas de Saúde por Feature Flag — V1.1
- Engajamento: escolas/usuários que acessaram a feature no grupo canary
- Erros: falhas de Edge Function correlacionadas com flag ativa
- Feedback: botão "Reportar problema" visível apenas em canary
7.4 Comunicação Contextual — V1.1
- Banner canary: "Você está testando uma novidade!"
- Notificação interna explicando o que mudou
- Notícia automática no Mural quando release é promovida
- Tutorial contextual acionado pela flag
7.5 Segmentação Inteligente de Grupos — V1.2
Critérios dinâmicos para grupos:
- "Todas as escolas com plano Premium"
- "Escolas com mais de 6 meses de uso"
- "Escolas com mais de 200 alunos"
- "Escolas em estado X" (rollout regional)
7.6 Feature Flags com Variantes (A/B Testing) — V2.0
- Variantes
AeBem vez de apenas on/off - Cada grupo canary recebe uma variante
- Métricas de engajamento por variante
- Promover a variante vencedora
7.7 Dependências entre Flags — V1.2
- Flag X requer flag Y ativa
- Impedir desativar Y se X ainda está ativa
- Árvore de dependências visual
7.8 Portal de Transparência para Escolas — V2.0
Painel read-only para o gestor da escola:
- "Sua escola está no grupo Beta Testers"
- "Funcionalidades em teste: Novo Calendário"
- Changelog das últimas versões
- Opt-in/opt-out de beta tester
8. Priorização
| Prioridade | Feature | Justificativa |
|---|---|---|
| MVP | Sistema base (flags + grupos + changelog + promote) | Fundação |
| MVP | Rollback com um clique + snapshot | Segurança operacional |
| V1.1 | Comunicação contextual (banner canary + notícia auto) | Já têm mural + notificações |
| V1.1 | Métricas básicas de engajamento | Dados para decisão |
| V1.2 | Segmentação dinâmica de grupos | Escala |
| V1.2 | Dependências entre flags | Robustez |
| V2.0 | Auto-promote com regras | Automação |
| V2.0 | A/B Testing com variantes | Sofisticação |
| V2.0 | Portal de transparência para escolas | Diferencial |
9. Fases de Implementação
Fase 1 — Fundação
- [ ] Criar tabelas no banco (releases, feature_flags, canary_groups, canary_group_escolas, feature_flag_canary)
- [ ] RLS em todas as tabelas
- [ ] Edge Function
release-managercom CRUD completo - [ ] Painel admin "Releases" com 3 abas (Versões, Feature Flags, Grupos Canary)
- [ ] Hook
useReleaseManagercom React Query
Fase 2 — Integração Frontend
- [x] Hook
useFeatureFlags()— wrapper leve sobre AuthContext (sem requests extras) - [x] Componente
<FeatureGate>— renderização condicional com admin bypass - [x] Integração no boot do App — já integrado via AuthContext (
canaryFlags+permissoesdo/me) - [x]
Context— desnecessário, dados já estão noFeatureFlagsProviderAuthContext - [x] Sync em tempo real via
useFeatureFlagSync+ Supabase Realtime broadcast - [ ] Action
promote_releasecom snapshot (V1.1 — requer tabelareleases) - [ ] Action
rollback_release(V1.1 — requer tabelareleases)
Fase 3 — Comunicação & Métricas (V1.1)
- [ ] Banner contextual para escolas em canary
- [ ] Notícia automática no mural ao promover release
- [ ] Métricas básicas de engajamento por flag
- [ ] Botão "Reportar problema" em canary
Fase 4 — Notificações (Pendente)
- [ ] Integrar
create_batchno fluxo de toggle de flag - [ ] Notificação de desativação planejada (INSERT antecipado)
- [ ] Notificação de desativação de emergência (pós-toggle)
- [ ] Mapeamento flag → papéis para destinatários precisos
Status: Documentado, aguardando implementação.
Fase 5 — Escala & Automação (V1.2+)
- [ ] Segmentação dinâmica de grupos
- [ ] Dependências entre flags
- [ ] Auto-promote com regras configuráveis
- [ ] A/B Testing com variantes
- [ ] Portal de transparência para escolas
10. Arquivos a Criar/Modificar
| Ação | Arquivo | Status |
|---|---|---|
| Criar | supabase/functions/release-manager/index.ts | ⏳ Pendente (Fase 1) |
| Criar | src/hooks/useFeatureFlags.ts | ✅ Criado (Fase 2) |
| Criar | src/hooks/useReleaseManager.ts | ⏳ Pendente (Fase 1) |
| Criar | src/components/feature-gate.tsx | ✅ Criado (Fase 2) |
| Criar | src/components/admin-releases.tsx | ⏳ Pendente (Fase 1) |
src/contexts/feature-flags-context.tsx | ❌ Desnecessário — dados integrados ao AuthContext | |
| Modificar | src/App.tsx (FeatureFlagsProvider) | ❌ Desnecessário — idem |
| Modificar | supabase/config.toml (nova function) | ⏳ Pendente (Fase 1) |
| Criar | docs/architecture/CANARY_RELEASE_SYSTEM.md (este arquivo) | ✅ Criado |
11. Uso no Código
tsx
// Proteger uma funcionalidade nova
<FeatureGate flag="novo_mural">
<MuralV2 />
</FeatureGate>
// Com fallback
<FeatureGate flag="novo_mural" fallback={<MuralV1 />}>
<MuralV2 />
</FeatureGate>
// Via hook
const { hasFlag } = useFeatureFlags();
if (hasFlag('calendario_v2')) {
// renderizar versão nova
}