Brasil Participativo
bp
Brasil Participativo
Rascunho
Product Requirements Document

Publicação de gems bp-*
no RubyGems

Uma distribuição identificável, versionada e pública do Decidim para o governo brasileiro — instalável com uma linha no Gemfile, sem confundir com o upstream.

Status
Rascunho para revisão
Data
2026-08-26
Autor
Time Brasil Participativo
Versão alvo
0.33.0.bp1

01Problem Statement

Hoje, o repositório decidim é um fork do Decidim com customizações para o governo brasileiro — entre elas a gem decidim-govbr (Padrão Digital de Governo), modificações em decidim-forms e decidim-surveys, e uma coleção de módulos de terceiros vendored em vendor/modules/ com patches de compatibilidade local.

Aplicações downstream (instâncias do Decidim para órgãos do governo) precisam consumir essas customizações. O modelo atual — clonar o repositório inteiro ou referenciar via path: / git: no Gemfile — escala mal, não permite versionamento semântico adequado no ecossistema Ruby, e gera confusão com as gems oficiais do upstream Decidim publicadas no RubyGems. Não há um pacote público, versionado e identificável como "nossa distribuição" que times downstream possam instalar com uma única linha no Gemfile.

02Solution

Publicar as gems customizadas no RubyGems sob o namespace bp-* (Brasil Participativo), com versionamento próprio sincronizado ao major.minor do upstream Decidim e sufixo bp1, bp2, … para as customizações locais. Uma meta-gem bp-decidim agrega todas as outras, permitindo que aplicações downstream instalem tudo com gem "bp-decidim".

O namespace de código Ruby (Decidim::Surveys, Decidim::Forms, etc.) não muda — apenas o nome da gem no RubyGems ganha o prefixo bp-. A estrutura física de diretórios no monorepo também permanece a mesma, para manter compatibilidade de rebase com o upstream.

03User Stories

01
Como mantenedorda distribuição Brasil Participativo, quero publicar as gems customizadas no RubyGems com namespace bp-*, para que elas sejam identificáveis como nossa distribuição e não se confundam com o upstream.
02
Como desenvolvedorde uma instância Decidim para um órgão de governo, quero instalar nossa distribuição com gem "bp-decidim" no Gemfile, para não precisar clonar o monorepo inteiro nem gerenciar paths locais.
03
Como desenvolvedor downstream, quero versionamento previsível (0.33.0.bp1) sincronizado ao upstream, para saber contra qual versão do Decidim nossas gems são compatíveis.
04
Como desenvolvedor downstream, quero poder instalar apenas subconjuntos da distribuição (ex: só bp-decidim-surveys), para evitar dependências que não uso.
05
Como mantenedor, quero que o bundle install em aplicações downstream continue recebendo atualizações do upstream quando o Decidim lançar versões finais, para facilitar o rebase de nossas customizações.
06
Como mantenedor, quero um processo de release que publique todas as gems bp-* na ordem correta de dependências, para evitar publishes que quebrem o resolve do Bundler.
07
Como desenvolvedor downstream, quero que as gems bp-* mantenham os mesmos namespaces Ruby do upstream, para que código, engines e integrações existentes continuem funcionando sem changes.
08
Como mantenedor, quero que os módulos de terceiros vendored também sejam publicados como bp-*, para que aplicações downstream não precisem referenciar path: "vendor/modules/...".
09
Como mantenedor, quero a meta-gem bp-decidim liste tanto as gems renomeadas quanto as upstream não-renomeadas, para que downstream tenha um único ponto de instalação.
10
Como desenvolvedor downstream, quero documentação clara no README explicando que este é um fork para o GovBR e como consumir as gems bp-*, para entender o propósito antes de adotar.
11
Como mantenedor, quero que o processo de publicação seja reproduzível (Rakefile + remote do fork), para que qualquer pessoa do time com credenciais possa fazer uma release.
12
Como mantenedor, quero ter um script/automação (futuro) que publique todas as gems bp-* com uma única confirmação de OTP, para reduzir o custo operacional de releases frequentes.
13
Como mantenedor, quero que cada gem vendored renomeada documente no README qual commit/branch do upstream foi patcheado, para que seja possível rastrear a proveniência e fazer merge de updates futuros.
14
Como desenvolvedor downstream, quero que a gem bp-decidim-govbr forneça os Web Components do GovBR-DS, para adequar a interface ao Padrão Digital de Governo.
15
Como mantenedor, quero publicar apenas depois que as simplificações do decidim-surveys forem aplicadas, para não publicar código que já decidimos remover.
16
Como mantenedor, quero que o metadata de cada gem aponte para o repositório fork (não para github.com/decidim/decidim), para que issues e contribuições cheguem ao lugar certo.

04Implementation Decisions

Escopo de renomeação

20 gems renomeadas e publicadas sob o namespace bp-*, distribuídas entre o monorepo do Decidim fork, módulos vendored e o repositório lappis-unb/decidimbr/components-brasil-participativo.

Padrão A — prefixo bp-decidim-

Gems do monorepo, vendored e componentes GovBR — recebem o prefixo bp-decidim- como sinal de distribuição.

Gem atualNovo nomeOrigemVersão
decidim-formsbp-decidim-formsMonorepo (modificada)0.33.0.bp1
decidim-surveysbp-decidim-surveysMonorepo (modificada)0.33.0.bp1
decidim-govbrbp-decidim-govbrMonorepo (gem nova)0.33.0.bp1
decidimbp-decidimMeta-gem0.33.0.bp1
decidim-analyticsbp-decidim-analyticsVendor0.30.0.bp1
decidim-decidim_awesomebp-decidim-decidim_awesomeVendor0.11.2.bp1
decidim-ephemeral_participationbp-decidim-ephemeral_participationVendor0.0.9.bp1
decidim-extra_blocksbp-decidim-extra_blocksVendor0.1.0.bp1
decidim-homepage_interactive_mapbp-decidim-homepage_interactive_mapVendor2.0.0.bp1
decidim-togglebp-decidim-toggleVendor0.1.3.bp1
caracalbp-caracalVendor1.7.2.bp1
decidim-government_spacesbp-decidim-government_spaceslappis-unb/components-br0.33.0.bp1
decidim-participatory_textsbp-decidim-participatory_textslappis-unb/components-br0.33.0.bp1
decidim-questionnairesbp-decidim-questionnaireslappis-unb/components-br0.33.0.bp1
decidim-categoriesbp-decidim-categorieslappis-unb/components-br0.33.0.bp1
decidim-extra_home_blocksbp-decidim-extra_home_blockslappis-unb/components-br0.33.0.bp1
decidim-apartmentbp-decidim-apartmentlappis-unb/infra0.1.0.bp1

Padrão B — decidim-bp-X

Gems que já tinham bp_ no nome (do repo lappis-unb/decidimbr/components-brasil-participativo). Apenas trocamos underscore por hífen — o bp já identifica como nossa.

Gem atualNovo nomeOrigemVersão
decidim-bp_proposalsdecidim-bp-proposalslappis-unb/components-br0.33.0.bp1
decidim-bp_meetingsdecidim-bp-meetingslappis-unb/components-br0.33.0.bp1
decidim-bp_commentsdecidim-bp-commentslappis-unb/components-br0.33.0.bp1

Gems NÃO renomeadas

Todas as demais do monorepo (decidim-core, decidim-admin, decidim-proposals, decidim-meetings, decidim-budgets, decidim-assemblies, …) continuam com nome upstream. Gems de terceiros que não são do escopo Brasil Participativo: decidim-community_templates (decidim-ice), deface (fork pontual), omniauth-govbr (mantida por pessoa física).

Versões suportadas

Apenas Decidim 0.33 (atual). Aplicações downstream em 0.30 continuam usando path: / git: como hoje. Não haverá branches de release paralelas para versões antigas do upstream.

Estratégia de versionamento

  • Sincronizar major.minor com o upstream Decidim.
  • Usar sufixo pré-release bp1, bp2, … para customizações locais (ex: 0.33.0.bp1).
  • Quando o upstream lançar 0.33.0 final, o Bundler oferecerá upgrade automaticamente (porque 0.33.0.bp1 < 0.33.0 na ordenação do Gem::Version).
  • Após rebasar nossas mudanças no upstream final, publicar como 0.33.1.bp1 ou 0.34.0.bp1 conforme a natureza.
  • Versões base das gems vendored preservam sua origem.

O que muda no empacotamento (e o que NÃO muda)

Muda: s.name no gemspec, s.authors (adicionar contribuidores locais), s.homepage e s.metadata (apontar para o repositório fork), add_dependency que referenciam gems do escopo.

NÃO muda:

  • Diretórios físicos no monorepo (decidim-surveys/ continua com esse nome).
  • Paths de require (require "decidim/surveys" continua igual).
  • Namespaces Ruby (Decidim::Surveys, Decidim::Forms, etc.).
  • Tasks de engine, rotas, migrations, células, controllers.

Essa decisão é crítica para manter compatibilidade com o ecossistema Decidim e evitar refatoração massiva em aplicações downstream.

Meta-gem bp-decidim

Renomeada de decidim para bp-decidim. Lista como dependências:

  • Gems do monorepo renomeadas (bp-decidim-forms, bp-decidim-surveys, bp-decidim-govbr).
  • Gems do monorepo não-renomeadas (mantidas com nome upstream: decidim-core, decidim-admin, decidim-proposals, …).
  • Gems vendored renomeadas (bp-decidim-analytics, bp-decidim-decidim_awesome, bp-decidim-ephemeral_participation, bp-decidim-extra_blocks, bp-decidim-homepage_interactive_map, bp-decidim-toggle, bp-caracal).
  • Gems do repo lappis-unb/decidimbr renomeadas (bp-decidim-government_spaces, bp-decidim-participatory_texts, bp-decidim-questionnaires, bp-decidim-categories, bp-decidim-extra_home_blocks, bp-decidim-apartment).
  • Gems com padrão decidim-bp-X (decidim-bp-proposals, decidim-bp-meetings, decidim-bp-comments).

Downstream instala só bp-decidim e recebe o conjunto completo.

Ordem de publicação (DAG de dependências)

Publicar na ordem topológica, das folhas para a raiz:

  1. Folhas (sem dependências internas bp-*): bp-decidim-analytics, bp-decidim-toggle, bp-decidim-extra_blocks, bp-decidim-ephemeral_participation, bp-decidim-homepage_interactive_map, bp-decidim-decidim_awesome, bp-caracal.
  2. Meio (dependem apenas de upstream não-renomeado): bp-decidim-forms (depende de decidim-core upstream), bp-decidim-govbr (depende de decidim-core upstream).
  3. Dependência interna: bp-decidim-surveys (depende de bp-decidim-forms já publicada + decidim-core upstream).
  4. Raiz (meta-gem): bp-decidim.

Processo de release

  • rake release do bundler/gem_tasks continua sendo o mecanismo base (build → tag → push → gem push).
  • lib/decidim/release_manager.rb passa a aceitar o remote do fork brasileiro (não mais exige decidim/decidim).
  • Rakefile com release_all ajustado para iterar sobre o conjunto bp-* na ordem da DAG.
  • Credenciais: ~/.gem/credentials com :rubygems_api_key, obtido via gem signin.
  • MFA: obrigatório no RubyGems desde 2022; o gem push pede OTP interativamente.
  • Adicionar s.metadata["allowed_push_host"] = "https://rubygems.org" em cada gemspec como segurança contra push acidental para registry privado.

Pré-requisitos da publicação

  • Conta RubyGems com MFA ativo (decidir entre conta pessoal ou ownership group).
  • Todos os 11 nomes bp-* disponíveis no RubyGems (verificar via API; ter alternativos prontos: br-decidim-*, govbr-decidim-*).
  • Simplificações do decidim-surveys aplicadas (fases 1–3 de plano-simplificacao-surveys.md) — pré-requisito hard, não publicar antes.
  • Specs de decidim-forms e decidim-surveys passando em baseline.

05Organização de Repositórios

Com 20 gems distribuídas hoje em 3 repositórios diferentes (monorepo Decidim fork, lappis-unb/decidimbr/components-brasil-participativo, lappis-unb/decidimbr/infra/participa-gem), vale avaliar se faz sentido consolidar ou manter a estrutura atual antes de investir no processo de publicação.

Monorepo (todas as gems bp-* em um único repositório)

Vantagens
  • Commits atômicos cross-gem — uma mudança que afeta 3 gems é um único commit, uma revisão, um merge. Não existe o problema de sincronizar PRs em múltiplos repos.
  • Refatoração global é barata — renomear uma interface compartilhada entre 5 gems gera um PR, não cinco.
  • CI compartilhado — uma única pipeline, um único conjunto de configs (Rubocop, RSpec helpers, linters).
  • Dependências internas via path: durante desenvolvimento — sem publicar versão intermediária para testar integração.
  • Versionamento sincronizado — todas as gems podem ser versionadas juntas (o BP_VERSION único já sugere esse modelo).
  • Descoberta facilitada — qualquer pessoa encontra qualquer gem em um só lugar. Onboarding mais rápido.
  • Issues e PRs unificados — um só backlog para discutir prioridades entre gems.
Desvantagens
  • Repo grande — clone e checkout mais lentos; histórico do git cresce mais rápido.
  • Permissões grossas — quem tem write no repo tem write em todas as gems. Sem isolamento por time.
  • CI lento sem filtros — uma mudança em qualquer gem pode disparar testes de todas (precisa filtros inteligentes por path).
  • Acoplamento implícito — fácil criar dependências circulares entre gems porque "estão todas ali".
  • Release acoplada — quando uma gem muda, as outras podem ser lançadas junto mesmo sem mudanças.
  • Ponto único de falha — problema no repo trava todas as gems.
  • Code ownership difusa — difícil ter "dono" específico de uma gem quando tudo está misturado.

Polyrepo (uma gem por repositório)

Vantagens
  • Repos pequenos e rápidos — clone, CI, histórico todos enxutos.
  • Permissões granulares — time A é dono da gem A, time B é dono da gem B.
  • CI isolado — só roda testes da gem que mudou.
  • Independência de release — cada gem lança no seu ritmo; gem estável não é arrastada por mudança em outra.
  • Autonomia tecnológica — cada gem pode adotar versões diferentes de Ruby, ferramentas, padrões.
  • Blame contido — um bug em uma gem não contamina outras.
  • Documentação focada — cada repo tem README, issues e wiki dedicados ao seu escopo.
Desvantagens
  • Cross-repo changes são caras — uma mudança que afeta 3 gems exige 3 PRs, 3 revisões, 3 merges, 3 releases coordenadas.
  • Dependências internas via git: / versão publicada — loop de feedback mais lento durante desenvolvimento.
  • Duplicação de boilerplate — cada repo precisa seu próprio CI, Rubocop, RSpec setup, templates de PR/issue.
  • Versionamento desencontrado — saber quais combinações de 20 gems são compatíveis entre si vira um problema.
  • Descoberta fragmentada — "onde está a gem X?" precisa de um índice ou catálogo.
  • Refatoração global é cara — mudar uma interface compartilhada = N PRs, N revisões, N merges.
  • Dependency hell distribuído — atualizar uma dependência compartilhada = rodar CI em 20 repos.
  • Context switching — manter 20 abas de repo, 20 backlogs de issue, 20 pipelines de CI.

Recomendação para o contexto Brasil Participativo

Pende para monorepo

Considerando time enxuto de governo, 20 gems com alta interdependência e versionamento sincronizado ao upstream Decidim, a avaliação pende para monorepo.

Por quê: (1) cross-repo changes são frequentes no nosso caso — modificações em decidim-forms frequentemente exigem ajustes em decidim-surveys, decidim-questionnaires e outras; (2) quando o upstream lança 0.33.0, queremos rebasar todas as nossas 20 gems de uma vez; (3) não temos pessoas suficientes para justificar o overhead de manter 20 repos separados; (4) ferramentas já existem — Bundler com path:, CI com filtros por path (os ci_*.yml do próprio Decidim upstream já fazem isso), tooling de release (o Rakefile atual já itera sobre múltiplas gems).

Custos a mitigar no monorepo:

  • CI inteligente: filtrar jobs por paths modificados (já é feito no upstream).
  • Code ownership: usar CODEOWNERS no GitHub para atribuir gems específicas a pessoas específicas.
  • Release seletiva: só publicar gems que mudaram desde a última release (detectar via git diff).
  • Readmes por diretório: cada subdiretório mantém seu próprio README específico, mesmo estando no mesmo repo.

Ações concretas sugeridas:

  1. Consolidar as gems do repo lappis-unb/decidimbr/components-brasil-participativo no monorepo principal (mover os 8 módulos para subdiretórios).
  2. Consolidar decidim-apartment do repo infra/participa-gem também (ou mantê-lo separado se for considerado "infra" e não "componente").
  3. Manter os subdiretórios atuais (decidim-forms/, decidim-surveys/, etc.) como unidades de release independentes, cada uma com seu gemspec, README, specs.
  4. Criar um CODEOWNERS que atribua cada subdiretório a responsáveis específicos.
  5. Adicionar no monorepo um índice (GEMS.md ou similar) listando todas as gems, suas responsabilidades e status.

Quando polyrepo faria sentido: se no futuro as gems amadurecerem e passarem a ter times mantenedores distintos (ex: um time cuidando só de analytics, outro só de formulários), ou se alguma gem precisar ser aberta para contribuição externa sem expor o monorepo inteiro, vale reavaliar a migração de gems específicas para repos próprios. Mas isso é uma decisão futura.

06Testing Decisions

O que torna um teste bom aqui

  • Testar comportamento externo: "a gem publicada instala e resolve corretamente" — não detalhes de como o gemspec foi editado.
  • Preferir testes de integração em aplicação downstream dummy em vez de testes unitários em cada gemspec.
  • Reaproveitar a spec/decidim_dummy_app já existente no monorepo como harness de validação.

O que será testado

  1. Resolve do Bundler: criar Gemfile de teste com gem "bp-decidim", "~> 0.33.0.bp1" e validar que bundle install resolve sem conflito.
  2. Smoke test da aplicação: bundle exec rails server em dummy app com bp-decidim carregado deve subir sem erro.
  3. Metadata das gems: gem specification bp-decidim-surveys -r deve retornar autores, homepage e dependências corretas.
  4. Namespace preservado: require "decidim/surveys" deve continuar funcionando; Decidim::Surveys deve continuar sendo o módulo esperado.
  5. decidim-govbr carrega Web Components: renderizar uma view com <br-header> e validar que o componente é registrado.
  6. Simplificações aplicadas: validar que decidim-surveys não tem mais as features removidas (publicação de respostas por pergunta, múltiplos surveys por componente, allow_unregistered).
  7. Ordenação de versão: Gem::Version.new("0.33.0.bp1") < Gem::Version.new("0.33.0") retorna true.

Prior art

  • spec/i18n_spec.rb (já usado pelo check_locale_completeness no Rakefile).
  • spec/decidim_dummy_app (app de teste já gerada por rake test_app).
  • Workflows ci_*.yml em .github/workflows/ servem de modelo para como as gems são testadas individualmente hoje.

07Out of Scope

Renomear as demais gems do monorepo (decidim-core, decidim-admin, etc.) — ficam com nome upstream. Se no futuro alguma delas receber customização substancial, reavalia-se caso a caso.
Renomear namespaces Ruby (Decidim::Surveys, etc.) — intencionalmente preservados para compatibilidade.
Renomear diretórios físicos no monorepo — preservados para facilitar rebase com upstream.
CI/CD automatizado de publicação — a primeira publicação é manual. Automação (GitHub Action release-bp-gems.yml em tag v*) entra em trabalho futuro, após validar o processo manual.
Script de publicação com OTP único — mesmo caso: automação futura (scripts/publish_bp.rb).
Port de decidim-enhanced_textwork — incompatível com 0.33, será tratado em iniciativa separada.
Criação de conta/ownership group no RubyGems — é pré-requisito humano, não técnico; fica fora do escopo de código.
Changelog automatizado — entra junto com a automação futura (release-please ou similar).
Publicação de pacotes npm — o monorepo também tem packages/. Este PRD cobre só gems Ruby; publicação npm fica como trabalho futuro se necessário.

08Riscos e Mitigações

RiscoMitigação
Nome bp-* já ocupado no RubyGemsVerificar via API antes. Alternativos: br-decidim-*, govbr-decidim-*.
Dependência circular entre bp-*DAG mapeada; publicar em ordem topológica.
decidim-core upstream incompatível com nossas modificaçõesTravar versão (~> 0.33.0) no gemspec até validarmos.
Upstream lançar 0.33.0 final enquanto estamos em 0.33.0.bp1Comportamento desejado: Bundler oferece upgrade. Rebasar e lançar 0.33.1.bp1.
MFA do RubyGems expirar no meio do publishgem signin antes de começar; chave de recovery em local seguro.
Vendor modules perderem sincronia com upstream próprioDocumentar no README de cada vendored o commit/branch base e o que foi patcheado.

09Sequência de Execução Recomendada

Verificar/criar conta RubyGems com MFA.
Confirmar disponibilidade dos 11 nomes bp-*.
Aplicar fases 1–3 de plano-simplificacao-surveys.md.
Rodar rspec em decidim-forms e decidim-surveys (baseline).
Renomear gemspecs das 11 gems.
Atualizar dependências internas.
Criar BP_VERSION e ajustar gemspecs.
Ajustar lib/decidim/release_manager.rb e Rakefile.
Atualizar Gemfile / Gemfile.lock do monorepo.
Commit em branch release/bp-gems.
Publicar gems na ordem da DAG.
Testar instalação em aplicação downstream dummy.
Atualizar READMEs.

10Decisão-chave de Design

Decisão central

A decisão mais importante deste PRD é não renomear o namespace Ruby nem os diretórios. Isso permite que aplicações downstream não precisem reescrever require ou referências a módulos, que o monorepo continue podendo ser rebasado contra o upstream Decidim sem conflitos massivos, e que o prefixo bp- cumpra seu papel (identificação no registry) sem causar fricção no código.

O custo dessa decisão é uma assimetria entre o nome da gem (bp-decidim-surveys) e o módulo (Decidim::Surveys), mas esse custo é bem conhecido no ecossistema Ruby (ex: gem rinku exporta Rinku, gem redcarpet exporta Redcarpet — nomes não precisam bater).

Brasil Participativo · PRD 001
Documento de trabalho · não distribuir fora do time