Skip to content

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

ColunaTipoDescrição
iduuid PK
versaotext NOT NULL UNIQUEEx: "2.4.0"
titulotext NOT NULLTítulo da release
descricaotextNotas da versão (Markdown)
tipoenum('major','minor','patch','hotfix')Classificação semântica
statusenum('rascunho','canary','liberada','arquivada')Ciclo de vida
publicada_emtimestamptzQuando foi liberada para todos
rollback_snapshotjsonbSnapshot do estado de flags antes da promoção
criado_poruuid FK usuariosAdmin que criou
criado_emtimestamptz DEFAULT now()
atualizado_emtimestamptz DEFAULT now()

3.2 Tabela feature_flags — Flags de Funcionalidade

ColunaTipoDescrição
iduuid PK
chavetext UNIQUE NOT NULLEx: "mural_v2", "novo_calendario"
nometext NOT NULLNome legível
descricaotextO que a flag controla
ativa_globalboolean DEFAULT falseLiberada para todos?
release_iduuid FK releases NULLVinculada a qual release
criado_emtimestamptz DEFAULT now()
atualizado_emtimestamptz DEFAULT now()

3.3 Tabela canary_groups — Grupos de Rollout

ColunaTipoDescrição
iduuid PK
nometext NOT NULLEx: "Beta Testers", "Escolas Piloto"
descricaotext
ativoboolean DEFAULT true
criado_emtimestamptz DEFAULT now()
atualizado_emtimestamptz DEFAULT now()

3.4 Tabela canary_group_escolas — Escolas em Cada Grupo

ColunaTipoDescrição
iduuid PK
canary_group_iduuid FK canary_groups
escola_iduuid FK escolas
adicionada_emtimestamptz DEFAULT now()
UNIQUE(canary_group_id, escola_id)

3.5 Tabela feature_flag_canary — Flags Liberadas por Grupo

ColunaTipoDescrição
iduuid PK
feature_flag_iduuid FK feature_flags
canary_group_iduuid FK canary_groups
criado_emtimestamptz DEFAULT now()
UNIQUE(feature_flag_id, canary_group_id)

3.6 Tabela canary_group_usuarios — Usuários em Cada Grupo

ColunaTipoDescrição
iduuid PK
canary_group_iduuid FK canary_groups
usuario_iduuid FK usuarios
adicionado_emtimestamptz DEFAULT now()
UNIQUE(canary_group_id, usuario_id)

Uso: Permite canary por usuário individual (ex: especialista ou admin de teste). Usado pelo checkCanaryAccess() em feature-gate.ts.

3.7 RLS

  • Todas as tabelas: RLS ativado
  • Somente administrador pode ler/escrever (via RBAC no Edge Function)
  • Consulta de flags ativas usa security definer function para performance

3.8 Feature Gate — Bypass

PapelBypass de Feature FlagsBypass 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)

ActionDescrição
list_releasesListar releases com paginação
create_releaseCriar nova release
update_releaseAtualizar release existente
list_flagsListar feature flags
create_flagCriar nova flag
update_flagAtualizar flag
toggle_flagToggle ativa_global
list_canary_groupsListar grupos canary
create_canary_groupCriar grupo
update_canary_groupAtualizar grupo
add_escola_to_groupAdicionar escola a grupo
remove_escola_from_groupRemover escola de grupo
assign_flag_to_groupVincular flag a grupo canary
remove_flag_from_groupDesvincular flag de grupo
promote_releaseCanary → Liberada (ativa_global=true para todas flags)
rollback_releaseReverter release (restaura snapshot)

Action Pós-Auth (qualquer papel com escola)

ActionDescrição
get_active_flagsRetorna 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

  1. Admin cria uma Release "v2.5.0" com status rascunho
  2. Cria feature flags: novo_mural, calendario_v2
  3. Vincula flags à release
  4. Cria grupo canary "Escolas Piloto" com 3 escolas
  5. Vincula flags ao grupo canary
  6. Muda status da release para canary
  7. Escolas do grupo passam a ver as funcionalidades via <FeatureGate>
  8. Após validação, clica "Promover para Produção"
    • Sistema salva snapshot do estado atual
    • ativa_global = true para todas as flags da release
    • Status muda para liberada
  9. Todas as escolas passam a ver as funcionalidades
  10. 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 A e B em 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

PrioridadeFeatureJustificativa
MVPSistema base (flags + grupos + changelog + promote)Fundação
MVPRollback com um clique + snapshotSegurança operacional
V1.1Comunicação contextual (banner canary + notícia auto)Já têm mural + notificações
V1.1Métricas básicas de engajamentoDados para decisão
V1.2Segmentação dinâmica de gruposEscala
V1.2Dependências entre flagsRobustez
V2.0Auto-promote com regrasAutomação
V2.0A/B Testing com variantesSofisticação
V2.0Portal de transparência para escolasDiferencial

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-manager com CRUD completo
  • [ ] Painel admin "Releases" com 3 abas (Versões, Feature Flags, Grupos Canary)
  • [ ] Hook useReleaseManager com 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 + permissoes do /me)
  • [x] Context FeatureFlagsProvider — desnecessário, dados já estão no AuthContext
  • [x] Sync em tempo real via useFeatureFlagSync + Supabase Realtime broadcast
  • [ ] Action promote_release com snapshot (V1.1 — requer tabela releases)
  • [ ] Action rollback_release (V1.1 — requer tabela releases)

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_batch no 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çãoArquivoStatus
Criarsupabase/functions/release-manager/index.ts⏳ Pendente (Fase 1)
Criarsrc/hooks/useFeatureFlags.ts✅ Criado (Fase 2)
Criarsrc/hooks/useReleaseManager.ts⏳ Pendente (Fase 1)
Criarsrc/components/feature-gate.tsx✅ Criado (Fase 2)
Criarsrc/components/admin-releases.tsx⏳ Pendente (Fase 1)
Criarsrc/contexts/feature-flags-context.tsx❌ Desnecessário — dados integrados ao AuthContext
Modificarsrc/App.tsx (FeatureFlagsProvider)❌ Desnecessário — idem
Modificarsupabase/config.toml (nova function)⏳ Pendente (Fase 1)
Criardocs/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
}