Pente fino do Participa
Brasil Participativo · Decidim 0.32.1 · levantamento de 2 de outubro de 2026

Pente fino do Participa e o caminho para o Decidim 0.33

Revisão do projeto inteiro para a transferência de tecnologia: aplicação host, decidim-govbr, módulos externos, multi-tenancy, CI e o chart Helm. Feita por leitura de código e das fontes upstream; nada foi executado em produção.

alto médio baixo severidade confirmado lido no código ou nas release notes inferido deduzido, falta checar

Resumo

O Decidim 0.33 ainda não foi lançado. O trabalho útil agora é preparar o terreno: destravar as gems, colocar os testes na CI e fechar as lacunas de operação.

12gems travam a versão abaixo de 0.33 (11 de 14 externas, mais decidim-govbr)
0testes rodando na CI; existem 22 specs no host e 19 no decidim-govbr
772migrations, cada uma executada em sequência em cada tenant
~20prepend do host sobre classes do Decidim, fora os dos módulos
0CronJobs nos charts: nada agenda as tarefas recorrentes do Decidim
  • Upgrade: não há 0.33 para instalar. O próximo passo real é o 0.32.2, ainda sem tag, com correções de segurança.
  • Dependências: quase todas as gems seguem uma branch móvel, e três delas pertencem a terceiros (duas da Octree, uma em conta pessoal).
  • Qualidade: os overrides têm testes, mas a CI só roda scans de segurança, todos com allow_failure: true.
  • Operação: backup do Postgres está como TODO no chart, a aplicação conecta como superusuário e não há health check.
  • Conhecimento: o README só cobre setup; as decisões de arquitetura não estão registradas neste repositório.

Tamanho da customização

Cerca de 51 mil linhas de código próprio sobre o Decidim; com traduções e testes, 81 mil.

OndeCódigoTraduçõesTestes
App host (app/, config/, lib/)6,7 mil3,2 mil1,9 mil
decidim-govbr4,4 mil0,5 mil1,3 mil
14 gems externas, nas revisões do Gemfile.lock39,7 mil3,3 mil19,7 mil
Total50,8 mil7,0 mil22,9 mil

Código é Ruby, views ERB, JS/SCSS e migrations próprias. Por tipo, no total: cerca de 29 mil linhas de Ruby, 8 mil de views e 12 mil de JS/SCSS.

Gem externaCódigoTestes
decidim-extra_blocks11,6 mil5,3 mil
decidim-community_templates5,6 mil5,0 mil
decidim-participatory_texts4,4 mil0,9 mil
decidim-questionnaires3,4 mil1,9 mil
decidim-government_spaces3,1 mil1,4 mil
decidim-toggle (Octree)2,9 mil2,0 mil
decidim-ephemeral_participation (Octree)2,3 mil0,2 mil
decidim-apartment2,0 mil0,4 mil
decidim-categories1,7 mil0,7 mil
decidim-bp_meetings0,9 mil0,9 mil
decidim-bp_comments0,8 mil0,7 mil
decidim-extra_home_blocks0,7 mil0
decidim-bp_proposals0,2 mil0,2 mil
omniauth-govbr0,1 mil0,02 mil
  • Das 39,7 mil linhas externas, 5,3 mil são de terceiros (as duas gems da Octree e o omniauth-govbr); 34,4 mil são dos repositórios do LAPPIS.
  • São linhas físicas, com linhas em branco e comentários.
  • Ficaram de fora as 770 migrations copiadas do Decidim, o db/schema.rb, node_modules e o chart Helm.
  • O config/ do host inclui configuração padrão de Rails e do Decidim, então o número do host está um pouco acima do que é customização de fato.

Status do 0.33

Tudo que esta página diz sobre o 0.33 descreve a branch develop do Decidim (0.33.0.dev) em 2 de outubro de 2026 e ainda pode mudar. As release notes de develop são rascunho e listam só quatro itens reais; o diff de código é bem maior.

FatoEvidência
Última versão publicada é a 0.32.1, de 30 de julho de 2026GitHub releases e RubyGems
Não existe tag, RC nem branch release/0.33-stableAPI de tags do GitHub; a URL da branch devolve 404
CHANGELOG.md de develop está vazio"Unreleased: Nothing."
release/0.32-stable tem cerca de 65 commits depois da 0.32.1Um 0.32.2 parece próximo inferido
Política de suporte: só os dois últimos minors recebem correção de segurançaSECURITY.md; hoje são 0.32.x e 0.31.x
Data do 0.33.0 e fim do suporte ao 0.32Não publicados. Pela regra, o 0.32 sai de suporte quando o 0.34.0 for lançado inferido

Para referência, o 0.32 teve RC em 24 de abril e versão final em 2 de julho de 2026. A regra upstream é subir um minor por vez, então 0.32 para 0.33 é um salto só.

O que muda no 0.33

Requisitos

Item0.32develop (0.33)Nosso estado
Ruby3.4.x3.4.x3.4.7, sem mudança
Rails8.1.x8.1.x8.1.3.1, sem mudança
Node≥ 22.14.0≥ 24.18.022.14.0, precisa subir
npm≥ 9.6.7≥ 11.16.0precisa subir
shakapacker9.710.3^9.7.0, precisa subir
webpack5.105 (dependência)5.109 (peer dependency)passa a ser nossa responsabilidade declarar

Ações manuais confirmado

  • Procedimento: bundle update decidim, bin/rails decidim:upgrade, db:migrate, data:migrate.
  • config/sidekiq.yml é sobrescrito pelo decidim:upgrade. Filas próprias devem ir para um segundo arquivo (config/sidekiq.local.yml). Temos 15 filas no arquivo atual e outra lista no ConfigMap do Helm.
  • Nova fila active_storage: precisa estar no sidekiq.yml e ser consumida por algum processo.
  • A função JS initFoundation foi removida; nenhum código pode depender de foundation-sites.
  • Perfis ocultos por padrão: participantes sem conta confirmada, sem aceite dos termos ou gerenciados deixam de aparecer no site e na API. Afeta qualquer view, cell ou consulta nossa que liste usuários.
  • Verificações com bloqueio após 5 falhas e throttling por IP. O upstream pede revisão de handlers de autorização customizados; temos o GovbrAuthorizationHandler. Isso também chega no 0.32.2.

Remoções e movimentações inferido do diff

  • Dependências npm retiradas de @decidim/core: foundation-sites, d3, emojibase, svg4everybody.
  • Datepicker movido de src/decidim/datepicker/ para um controller Stimulus em src/decidim/controllers/date_picker/.
  • Cells de wizard removidas (wizard_step_form_cell e variações).
  • Surveys: coluna clean_after_publish e o job de limpeza removidos.
  • Atualizações maiores no frontend: React 18 para 19, @rails/ujs 6 para 7, ESLint 8 para 9.
  • Cerca de 28 controllers do admin alterados, provavelmente por escopo de organização nas buscas.
  • "Steps" renomeado para "Phases" nas strings; overrides de i18n precisam de revisão.

Migrations que pesam inferido do diff

  • Coluna reference nova em posts, textos colaborativos, eleições, páginas e surveys, com preenchimento linha a linha.
  • Regeneração da referência de todo projeto de orçamento, sem volta.
  • Data migrations que reescrevem títulos de debates, reuniões, eleições e propostas, sem volta e lentas em tabelas grandes.
  • Com um schema por organização, tudo isso roda uma vez por tenant, em sequência.

Segurança relevante para multi-tenant inferido dos commits

  • Impede uso de um JWT contra outra organização (PR #16673).
  • Corrige acesso entre tenants na verificação por documento (PR #16666).
  • Sanitização de páginas estáticas e blocos HTML (PR #16451).

Parte desses commits pode já estar no 0.32.x; o backport de cada um não foi conferido.

Onde quebra no nosso código

Colisões diretas com arquivos do host

Arquivo nossoO que aconteceu upstreamRisco
app/packs/src/decidim/datepicker/generate_datepicker.jsArquivo movido: nosso override deixa de ser carregado, sem erroalto
app/packs/src/decidim/datepicker/generate_timepicker.jsIdem; perdemos a correção de data local e os rótulos traduzidosalto
app/cells/decidim/comments/comment_form/show.erbTemplate mudou; nossa cópia integral fica defasadaalto
app/cells/decidim/comments/edit_comment_modal_form/show.erbTemplate mudoualto
app/views/layouts/decidim/admin/_header.html.erbLayout mudou; nossa cópia só acrescenta 5 linhas de PostHogmédio

Essa lista só cobre arquivos no mesmo caminho do upstream. Os casos abaixo ficam em áreas alteradas e precisam de diff quando houver RC.

Overrides em áreas alteradas

  • Comentários: UpdateCommentOverride#call e CommentsControllerOverride#update substituem o método inteiro, sem super, e dependem de métodos privados do upstream. O decidim-bp_comments ainda faz prepend em 7 classes do mesmo módulo.
  • Propostas: ProposalGCellOverride sobrescreve resource_image_path; a cell mudou upstream.
  • Painel system: organizations_controller mudou; decidim-apartment substitui index e edit, e decidim-toggle aplica Deface no mesmo painel.
  • Layouts: _head.html.erb e header/_main_links_dropdown.html.erb mudaram; decidim-govbr aplica Deface em _head e em header/_main.
  • Deface em geral: os 10 overrides do decidim-govbr dependem de seletores CSS dos templates (#accordion-duration, div#main-bar, .item_show__header). Se o seletor some, o override não aplica e não avisa.
  • Exportação de surveys: ExportJobStreamingSurveyAnswers sobrescreve Decidim::ExportJob#perform com assinatura fixa e lê colunas de decidim_forms_responses.
  • Menu do admin: MenuReorder usa instance_variable_get(:@items) em objetos internos do Decidim.

Módulos e dependências

Todas as gems git usam branch: no Gemfile; nenhuma usa tag. O que garante a reprodução do build é só a revisão gravada no Gemfile.lock.

GemOrigemBranchRestrição DecidimBloqueia 0.33Invasividade
decidim-govbrno repositório—= 0.32.1simalta: 10 Deface, 12 views copiadas
decidim-questionnairesLAPPISmain~> 0.32.1simalta: 11 Deface, ~15 prepend
decidim-categoriesLAPPISmain= 0.32.1simalta: 5 Deface, ~20 prepend
decidim-extra_blocksLAPPISmain< 0.33simalta: maior gem, 6 Deface
decidim-ephemeral_participationOctreemain~> 0.29nãoalta: ~15 módulos, sem specs
decidim-bp_commentsLAPPISmain~> 0.32.1simmédia
decidim-bp_meetingsLAPPISmain~> 0.32.1simmédia
decidim-government_spacesLAPPISmain= 0.32.1simmédia; mexe nos mesmos forms que o govbr
decidim-extra_home_blocksLAPPISmain~> 0.32.1simmédia, sem specs
decidim-toggleOctreemain< 0.33simleve a média
decidim-bp_proposalsLAPPISmain~> 0.32.1simleve
decidim-community_templatesLAPPIScore/bump-32< 0.33.0simleve, mas o host aplica patches nela
decidim-participatory_textsLAPPISmain< 0.33.0simleve
decidim-apartmentLAPPIS infrav0.1.0-rc≥ 0.29.0nãoestrutural; docs só citam 0.29 e 0.30
omniauth-govbrconta pessoal no GitHubmainnenhumanãoestratégia OmniAuth simples

Recomendações

  • Trocar branch: por tag: em todas as gems e criar uma tag por versão do Decidim suportada.
  • Espelhar ou fazer fork das três gems de terceiros (decidim-toggle, decidim-ephemeral_participation, omniauth-govbr) num grupo que a equipe controla. O login gov.br hoje depende de um repositório pessoal.
  • Manter uma matriz de compatibilidade por módulo e subir as gems na ordem das dependências: toggle e ephemeral_participation antes de extra_blocks.
  • Resolver a sobreposição entre decidim-govbr e decidim-government_spaces, que alteram o mesmo form e os mesmos comandos de processo participativo.
  • Colocar decidim-govbr na ordem certa sem depender do nome de um initializer do decidim-bp_comments.

Pente fino de arquitetura

Como o projeto altera o Decidim

MecanismoOndeAvaliaçãoRisco
Cópia integral de view, cell ou JS~15 arquivos no host, 12 no decidim-govbrDiverge em silêncio a cada upgrade. Reduzir ao mínimo e anotar a versão de origem em cada cópiaalto
prepend em to_prepareconfig/initializers/decidim_*_overrides.rbPadrão correto. Rever os que não chamam super ou usam métodos privadosmédio
Redefinição de classe no caminho do upstreamapp/cells/decidim/budgets/budget_information_modal_cell.rbSubstitui a classe inteira; converter em prependmédio
Defacemódulos; precompilado no build, desligado em produçãoFalha silenciosa quando o seletor muda. Falta teste que confirme que cada override aplicoumédio
Patch sobre patchhost aplica prepend nos módulos de override do bp_comments e reimplementa métodos do community_templatesLevar a mudança para a gem de origemmédio

Multi-tenancy: um schema Postgres por organização

flowchart LR
  R[Requisicao HTTP] --> E[Elevator do decidim-apartment]
  E -->|host cadastrado| T[Schema UUID do tenant]
  E -->|host desconhecido ou /system| P[Schema public]
  T --> O[CurrentOrganization do Decidim]
  T --> J[Job enfileirado com o tenant nos argumentos]
  J --> S[Middleware do Sidekiq troca o schema]
  T --> A[ActiveStorage com prefixo do tenant]
  
PontoO que o código fazRisco
MigrationsRodam em sequência em todos os tenants. O host tem apartment:schema_drift e apartment:repair_plan, sinal de que migrações parciais já ocorreram inferidoalto
Init do ApartmentO Dockerfile deixa APARTMENT_DISABLE_INIT=true na imagem final; nenhum chart desfaz. O setup de modelos excluídos pode não rodar em runtime inferidoalto
JobsO tenant vai como argumento extra do job e só o middleware do Sidekiq o remove. Jobs enfileirados por rake ou cron rodam em public ou sem tenantmédio
CacheNamespace por tenant só quando REDIS_CACHE_URL existe. Sem ela, não há separação, e toda organização tem id 1 inferidomédio
HostsO elevator só resolve o host principal; secondary_hosts não são consultados. Host desconhecido cai em publicmédio
StorageSem aws-sdk-s3 carregado, o serviço S3 vira disco local sem avisarmédio
Suporte da gemA documentação do decidim-apartment só lista Decidim 0.29 e 0.30médio
Código mortoapartment:sync_schema_migrations tem corpo vazio; DetectOrganizationMiddleware nunca é incluídobaixo

Essa é a decisão que mais encarece cada upgrade. Ela precisa de um ADR próprio e de um ensaio de migração numa cópia dos tenants antes de qualquer salto de versão.

Frontend

  • tailwind.config.js na raiz é um arquivo gerado, com caminhos fixos para decidim-core-0.32.1, e diverge do template config/tailwind.config.js.erb (fonte e cores diferentes).
  • decidim-govbr/package.json ainda aponta para @decidim/* ^0.30.1.
  • config/webpack/custom.js referencia o service worker por um caminho interno do core.

Configuração e resíduos

  • config.load_defaults 6.1 numa aplicação Rails 8.1.
  • Quase toda a configuração do Decidim vem de credentials, com poucas alternativas por ENV. config/secrets.yml continua no repositório, mas o Rails 8 não o lê.
  • .disabled-for-0.32/ tem README desatualizado: diz que community_templates não tem versão para 0.32, mas a gem está ativa e com patches.
  • 17 migrations de sortitions sem a gem no bundle; eager_load_paths aponta para lib/decidim, que não existe.
  • config/brakeman.ignore e pipeline_fixes.md ainda falam em Rails 7.0.10 e Decidim 0.30.1.
  • Quatro módulos do decidim-govbr são carregados e não parecem incluídos em lugar nenhum.
  • A rota update_participatory_process_dates é declarada duas vezes em engine.rb.

Infra e Helm

Imagem e CI

  • A imagem roda como root, mantém o toolchain de build e não define CMD nem RAILS_ENV. Usa npm install em vez de npm ci.
  • Não existe .dockerignore: um build local leva .env, .git e node_modules para dentro da imagem.
  • Os assets não são compilados no build; um job do Helm roda shakapacker:compile a cada deploy, num volume compartilhado.
  • A CI tem só gitleaks, hadolint, brakeman e SCA, todos com allow_failure: true. Nenhum job roda RSpec, RuboCop, ESLint ou Stylelint.
  • build_bump_image só dispara na branch release/0.32.1-v1.0.0. Não há job de deploy.

Chart decidim-helm 0.3.12

Repositório lappis-unb/decidimbr/infra/charts/decidim-helm, main em c996356. A cópia local está igual ao remoto.

AchadoDetalheRiscoBranch que já trata
Sem backup do PostgresBackup e ScheduledBackup comentados como TODO; cluster CNPG com 1 instânciaaltofeat/postgres-s3-backup
Aplicação como superusuárioCredenciais vêm do secret postgresSuperuseraltofeat/db-managed-roles-bootstrap
Sem CronJobsMétricas, lembretes, open data e limpeza de dados não são agendadosaltonenhuma
Sem volume para uploadsSó existe o PVC de assets. Com STORAGE_PROVIDER ausente, uploads vão para disco efêmero inferidoaltonenhuma
Filas divergentesO ConfigMap omite metrics e spam_analysis, que existem no sidekiq.yml do appmédionenhuma
Defaults de outro appImagem upstream 0.31.4, RAILS_ENV=development, DECIDIM_FORCE_SSL=falsemédiofix/chart-defaults-0.32.1
Probes sem valorWeb só com TCP; Sidekiq com test -d /proc/1, que sempre passamédionenhuma
Redis sem autenticaçãoauth.enabled: false nos dois subchartsmédionenhuma
Senha de admin em ConfigMapO job de secrets lê a senha do admin de sistema de um ConfigMap em texto puromédionenhuma
Job de upgrade sem hook do Argo CDdb-upgrade-job só tem anotações de hook do Helmmédionenhuma
IngressGateway API com HTTPRoute; Ingress padrão opcionalbaixofeat/standard-ingress-support

Há também feat/external-postgres-secret. Cinco branches abertas tratam problemas desta lista e ainda não entraram em main. O chart antigo em deploy/decidim-instance-chart (appVersion 0.29.3) segue no repositório do app e deve ser removido ou marcado como legado.

Para o 0.33, o chart precisa de três mudanças: imagem com Node 24, a fila active_storage no ConfigMap do Sidekiq e o passo data:migrate conferido no job de upgrade, que já o executa.

Observabilidade

  • Não há endpoint de health check na aplicação.
  • Logs só vão para STDOUT com RAILS_LOG_TO_STDOUT, que os charts não definem.
  • Não há rastreamento de erros, métricas da aplicação nem logs estruturados. Só Redis e Postgres expõem métricas.
  • O Pyroscope marca tudo como process=web, inclusive dentro do Sidekiq.

Segurança e dados pessoais

AchadoOndeRisco
Credenciais antigas continuam no histórico do git; a CI passou a usar --no-git e não varre mais o histórico. A rotação é dada como obrigatória e não foi possível confirmar se ocorreupipeline_fixes.md, .gitleaksignore (20 exceções)alto
CPF e document_number fora do filtro de parâmetros de logconfig/initializers/filter_parameter_logging.rbalto
/sidekiq aceita qualquer usuário admin; a fila é compartilhada entre tenants inferidoconfig/routes.rbalto
CSP com unsafe-inline e unsafe-eval em script-srcconfig/initializers/content_security_policy01.rbmédio
SMTP sem verificação de certificado TLSconfig/environments/production.rbmédio
PostHog com host padrão no SaaS dos EUA; variáveis fora do .env.sampleconfig/initializers/posthog.rbmédio
Senha de exemplo fixa nos comandos de criação de adminREADME.mdmédio
Endpoint interno de storage citado em comentário.env.samplebaixo
Ferramentas de scan em :latest e instaladas por curl | sh.gitlab-ci.ymlbaixo

A varredura por padrões de chave e token nos arquivos rastreados dos dois repositórios não encontrou credenciais reais no estado atual.

Transferência de tecnologia

Assumir a responsabilidade pede mais que acesso ao código. Estes são os itens que hoje dependem de memória de pessoas ou de repositórios fora do nosso controle.

TemaSituaçãoO que precisa existir
Decisões de arquiteturaComentários citam openspec/ e docs/, ausentes neste checkoutADRs no repositório: multi-tenancy por schema, estratégia de override, Deface precompilado, storage
Testes41 arquivos de spec fora da CI; o app de teste do decidim-govbr precisa ser geradoJob de RSpec obrigatório para host e govbr; scans sem allow_failure depois de zerar os achados
Posse das gems14 repositórios, 3 de terceiros, 12 em branch móvelLista de donos, permissões no GitLab, tags, forks dos terceiros
Configuração de produçãoOs values reais não estão em nenhum dos dois repositóriosValues versionados (sem segredos) e inventário de secrets do cluster
UpgradeHistórico só nos commits; quatro saltos desde 0.29Runbook: ordem das gems, ensaio com cópia dos tenants, auditoria de drift, volta atrás
OperaçãoSem cron, sem backup, sem health checkRunbook de incidentes, restauração testada, criação e remoção de tenant
CredenciaisRotação pós-vazamento não confirmada; master.key fora do repositórioRegistro de rotação e guarda formal das chaves e do cliente gov.br
Documentação de entradaREADME só com setup localMapa dos módulos, do fluxo de tenant e de como alterar o Decidim neste projeto

Roteiro sugerido

Fase 1 · agora

Fechar o risco operacional

  • RSpec na CI para host e decidim-govbr.
  • Backup do Postgres e usuário de aplicação sem superusuário (branches já abertas no chart).
  • CronJobs das tarefas recorrentes, tenant a tenant.
  • Filas do Sidekiq iguais entre app e chart.
  • Confirmar rotação de credenciais; filtrar CPF nos logs; restringir /sidekiq.
  • Aplicar o 0.32.2 quando sair a tag.
Fase 2 · preparação

Destravar e reduzir a superfície

  • Tags e forks das gems; relaxar as restrições na ordem das dependências.
  • Node 24 e shakapacker 10 numa branch de ensaio.
  • Trocar cópias integrais por prepend ou levar a mudança para a gem.
  • Portar os dois overrides de datepicker para o controller Stimulus.
  • Teste que verifica cada Deface aplicado.
  • ADRs e runbook de upgrade; ensaio de migração em cópia dos tenants.
Fase 3 · quando houver RC do 0.33

Executar o upgrade

  • Reler as release notes: o rascunho atual está incompleto.
  • Comparar as gems 0.32.1 instaladas com a tag do RC, arquivo por arquivo, para cada override.
  • Mover filas próprias para sidekiq.local.yml e incluir active_storage.
  • Rever o GovbrAuthorizationHandler e as listagens de usuários.
  • Migrar tenant a tenant, medindo o tempo das data migrations.

A verificar

Pontos deduzidos da leitura que ainda pedem confirmação num ambiente em execução ou com quem opera a plataforma.

  • O efeito de APARTMENT_DISABLE_INIT=true num pod de produção.
  • Se jobs das filas metrics e spam_analysis estão se acumulando no Redis.
  • Os values reais de produção: STORAGE_PROVIDER, REDIS_CACHE_URL, RAILS_ENV, RAILS_LOG_TO_STDOUT.
  • Se as tarefas recorrentes rodam por algum mecanismo fora dos charts.
  • Se a rotação das credenciais que estiveram no histórico foi feita.
  • Se os quatro módulos soltos do decidim-govbr são mesmo código morto.
  • Quantos tenants existem e o tamanho das tabelas de propostas, para estimar a janela de migração.
  • O backport de cada correção de segurança citada para o 0.32.x.
Fontes: código do repositório participa na branch 7-otimiza-exportacao-contribuicoes, gems instaladas na versão 0.32.1, chart decidim-helm em c996356, e a branch develop do Decidim, SECURITY.md, docs de atualização e RubyGems consultados em 2 de outubro de 2026.