Apêndice B — Módulos Concretos de Implementação
Propósito e relação com “O Formigueiro”
Seção intitulada “Propósito e relação com “O Formigueiro””O Apêndice Técnico “O Formigueiro” define a arquitetura: orientação a eventos, núcleo (Event Bus + Registry), colônias autônomas, regras duras de isolamento e fases de evolução. Ele responde ao o quê.
Este apêndice responde ao como. Para cada colônia, abre uma ficha técnica: o que faz, onde termina sua responsabilidade, quais eventos consome e produz, quais dados possui, que lógica executa e quais técnicas ou algoritmos são candidatos de implementação. Tecnologias são sempre referências — não decisões fechadas.
A estrutura segue as três fases do Formigueiro, mantendo a mesma espinha dorsal. Módulos mais complexos são quebrados em sub-colônias especializadas. O critério de quebra é simples: quando a lógica interna for distinta o suficiente para ter estado próprio, ciclo de vida independente e fronteira clara com os demais.
O objetivo deste documento é servir de base para a decisão de escopo do MVP antes de qualquer linha de código.
Convenções da ficha técnica
Seção intitulada “Convenções da ficha técnica”Cada colônia usa o seguinte template:
- Contexto e responsabilidade — o que faz e, explicitamente, o que não faz.
- Eventos consumidos — o que a colônia escuta no barramento.
- Eventos produzidos — o que a colônia publica após processar.
- Estado próprio (write model) — as entidades que a colônia possui e ninguém mais escreve.
- Lógica e algoritmos — o processamento interno, com detalhamento dos passos e pseudocódigo onde ajudar.
- Técnicas e referências de implementação — stacks, algoritmos e padrões candidatos.
- Sub-colônias — quando o módulo se quebra em partes especializadas.
- Critério de saída — quando o módulo cumpre seu papel na fase.
Princípios herdados do Formigueiro
Seção intitulada “Princípios herdados do Formigueiro”Valem para todas as colônias sem exceção:
- Colônias não importam código umas das outras.
- Nenhuma colônia escreve no banco de dados de outra.
- Toda comunicação entre colônias ocorre exclusivamente via eventos no barramento. Exceção única: o BFF da D-1a pode chamar outras colônias via HTTP para operações síncronas iniciadas pelo front-end (login, atualização de perfil, cadastro e recusa de conselheiro). O BFF atua como proxy de entrada, nunca como lógica de negócio — ele não toma decisão sobre dados de outras colônias, apenas roteia comandos do usuário, publica eventos no barramento e mantém projeções locais de leitura.
- A única dependência permitida é com o núcleo: Event Bus e Registry.
- IA não decide nem prioriza. Publica com marcação de origem automática quando a confiança excede o limiar parametrizado, desde que o caminho para contestação humana seja imediato e visível. Abaixo do limiar, a publicação aguarda revisão. Acima, a revisão é reativa (contestar), não preventiva (aprovar). Atua como redução de atrito, não como autoridade.
- Todo output de processamento automático é marcado como automático, versionado e mantém acesso ao conteúdo bruto.
- Monolito modular no MVP. Cada colônia nasce sem dependência das demais, pronta para se tornar microsserviço quando o sistema escalar.
Arquitetura do MVP — Monolito Modular
Seção intitulada “Arquitetura do MVP — Monolito Modular”Decisão de arquitetura
Seção intitulada “Decisão de arquitetura”O MVP é um monolito modular. Cada colônia existe como módulo autônomo dentro de um único processo de servidor. A separação é lógica, não física: módulos não se importam entre si, não compartilham banco de escrita, comunicam-se exclusivamente via barramento interno.
A escolha é deliberada e tem dois objetivos simultâneos:
- Fechar o ciclo completo sem a complexidade operacional de microsserviços distribuídos — sem orquestração de containers por serviço, sem service discovery, sem latência de rede entre colônias.
- Servir como base de onboarding. O monolito modular é o mapa do sistema. Um dev novo lê um módulo e entende completamente o que aquela colônia faz, quais eventos consome, quais produz, onde termina sua responsabilidade. Quando o sistema evoluir para microsserviços, cada módulo já está pronto para ser extraído — sem refatoração de fronteira, apenas extração física.
A evolução natural é: módulo NestJS no monolito → microsserviço independente com o mesmo contrato de eventos. O dev que contribuiu no módulo é o candidato natural a manter o microsserviço.
Stack de referência
Seção intitulada “Stack de referência”- Licença: AGPL-3.0. Copyleft forte para serviços de rede — se alguém modificar e operar publicamente, é obrigado a publicar o código fonte das alterações. Alinhado com o princípio de transparência radical do projeto.
- Backend: TypeScript + NestJS. Cada colônia = um módulo NestJS com encapsulamento próprio (controllers, services, repositórios).
- ORM: Prisma. Schema declarativo com tipos TypeScript auto-gerados. Migrations versionadas. O schema-first do Prisma casa com a arquitetura orientada a contratos de evento — o banco é a verdade, o código reflete o schema.
- Banco de dados: PostgreSQL único. Cada colônia opera em schema ou conjunto de tabelas próprios — mesma instância, fronteiras claras no nível de schema. Nenhuma colônia faz query nas tabelas de outra.
- Armazenamento de arquivos: MinIO (S3-compatible) via Docker. API idêntica ao AWS S3: presigned URLs, buckets, object keys baseadas em hash. Trocar de MinIO para AWS S3 (ou DigitalOcean Spaces, Cloudflare R2) é mudar 3 variáveis de ambiente (
endpoint,access key,secret key). Zero acoplamento com provedor. - Event Bus MVP: barramento in-process.
EventEmitter2do NestJS como implementação de referência. Eventos persistidos em tabela append-only (core.event_log) no mesmo PostgreSQL. A troca para Kafka ou NATS JetStream, quando o sistema escalar, não altera as colônias — apenas a camada de publicação e consumo do barramento. - Cache e ranking: Redis para sorted sets do ranking (D-4) e cache geo (D-2 e L-2) na Fase 2. No MVP implementado, ranking e caches geo vivem em memória (Map), reconstruídos do estado próprio no boot. Redis não é usado no código atual.
- IA local (MVP):
- Transcrição de áudio: whisper-tiny via
@huggingface/transformers(ONNX runtime) no mesmo processo Node.js do monolito. Pesos de ~75 MB. Timeout de 60s por transcrição. - Descrição de imagens: Florence-2-base (~1,06 GB fp32) via
@huggingface/transformersno mesmo processo Node.js do monolito. Legenda por tarefa (<MORE_DETAILED_CAPTION>padrão). Timeout de 180s por descrição. Detecção de objetos e OCR disponíveis no modelo, como capacidade futura para a D-1c. - Ambos são abstraídos por serviços dedicados no módulo D-1b. Carregamento preguiçoso com cache em volume (
modelos_d1b). Se indisponíveis, o pipeline segue com funcionalidade reduzida (sem transcrição/descrição, confiança reduzida).
- Transcrição de áudio: whisper-tiny via
- Frontend: React + Vite + TypeScript. shadcn/ui + Tailwind CSS. Leaflet + react-leaflet para mapa (tiles vetoriais self-hosted e satélite Esri, trocáveis). Zustand para estado, React Hook Form para formulários. PWA com service worker para operação offline.
- Autenticação MVP: Device ID anônimo (UUID v4 gerado pelo front-end). Login social Google como upgrade voluntário para perfil persistente. Gov.br e validação de vínculo entram na Fase 2.
MVP = Fase 1 / MLP = Fase 2
Seção intitulada “MVP = Fase 1 / MLP = Fase 2”Os termos se mapeiam diretamente para as fases do Formigueiro:
- MVP (Produto Mínimo Viável) cobre a Fase 1 — ciclo completo local: demanda entra, é categorizada, entra no ranking, vira agenda, recebe conselheiro, tem andamento registrado publicamente. Inclui as colônias de empresa básicas para mapeamento e simulação salarial.
- MLP (Produto Mínimo Adorável) cobre a Fase 2 — escala territorial, robustez institucional, validação de vínculo, votação, anti-fraude, análise de cobertura e incubação social.
A separação não é apenas técnica. O MVP precisa provar que um ciclo mínimo fecha. O MLP prova que o sistema escala.
Núcleo — O Chão do Formigueiro
Seção intitulada “Núcleo — O Chão do Formigueiro”O núcleo não processa demandas, não executa lógica de negócio e não toma decisões. Define as regras do jogo e garante que os eventos fluam de forma confiável entre todas as colônias.
N-0a — Event Bus (Feromônios)
Seção intitulada “N-0a — Event Bus (Feromônios)”Contexto e responsabilidade
O barramento de eventos é o canal único de comunicação do sistema. Toda colônia publica e consome exclusivamente por aqui. Nenhuma colônia se comunica diretamente com outra.
Não executa lógica de negócio. Não filtra conteúdo. Não decide quem pode publicar o quê — isso é responsabilidade do Registry.
Responsabilidades do barramento:
- Receber eventos publicados por qualquer colônia.
- Garantir a ordem de entrega dentro de cada tópico/stream.
- Persistir o histórico de eventos de forma append-only. Nenhum evento é apagado.
- Reexecutar eventos em caso de falha de consumidor: se uma colônia cair e voltar, processa o que ficou pendente.
- Expor o histórico completo para auditoria e replay.
Estado próprio
O barramento possui o log de eventos. É a memória do sistema. Um evento publicado é permanente. Pode ser reprocessado, auditado e comparado com qualquer versão anterior.
Lógica central
evento chega ao barramento→ valida tipo, versão e payload contra o Registry→ atribui sequence number global→ persiste no log (append-only)→ entrega aos consumidores registrados para aquele tipo→ falha de consumo registra na DLQ e o replay do boot reprocessa a partir do cursor da colôniaTécnicas e referências de implementação
- MVP implementado:
EventEmitter2in-process com persistência append-only emcore.event_log(PostgreSQL). Publicação valida tipo e payload contra o Registry, persiste e só então emite. Falhas de consumo vão para a DLQ (core.dead_letter_queue) e o replay do boot reprocessa a partir do cursor de cada colônia. - Escala: Apache Kafka, Redpanda ou NATS JetStream. Kafka é a referência mais documentada para event sourcing com retenção de log e consumer groups. Redpanda oferece API Kafka-compatível com menor overhead operacional.
- Garantia de entrega: at-least-once como padrão. Consumidores devem ser idempotentes.
- Ordenação: garantida por partição/tópico. Cada tipo de entidade (ex:
demanda-id) mapeia para uma partição para manter sequência causal.
Critério de saída
Eventos publicados são persistidos, entregues a todos os consumidores registrados e reexecutados após falha sem perda. O log é auditável por ID de evento e por sequência temporal.
Documento detalhado: N-0a - Event Bus.md
N-0b — Registry (Mapa do Formigueiro)
Seção intitulada “N-0b — Registry (Mapa do Formigueiro)”Contexto e responsabilidade
O registry é o idioma oficial do sistema. Define os tipos de eventos que existem, os schemas de dados que cada tipo carrega e os contratos que cada colônia cumpre para publicar ou consumir.
Não executa lógica. Não valida conteúdo de negócio. Não decide quem pode usar o quê.
Responsabilidades:
- Catalogar todos os tipos de evento com nome, versão e schema.
- Expor contratos como pacotes ou documentação estruturada para cada colônia.
- Versionar schemas: um schema alterado gera nova versão, nunca substitui a anterior.
- Ser a fonte da verdade sobre o idioma do sistema.
Estado próprio
Catálogo de tipos de evento com versões e schemas. Histórico de todas as versões anteriores de cada schema.
Convenção de nomenclatura de eventos
{domínio}.{entidade}.{ação}
Exemplos: demanda.recebida demanda.categorizada demanda.ranqueada conselheiro.sorteado agenda.gerada vínculo.validado voto.submetido hash.checkpoint_publicadoSchema mínimo de um evento
{ "sequence_number": "bigint (BIGSERIAL, monotônico global)", "event_id": "uuid-v4", "tipo": "demanda.recebida", "versao_schema": "1.0.0", "timestamp": "ISO-8601", "origem": "D-1a", "correlacao_id": "uuid-da-sessão-ou-requisição", "payload": { ... }, "criado_em": "ISO-8601"}Técnicas e referências de implementação
- Schema definition: JSON Schema, Avro ou Protobuf. Avro é referência comum com Kafka (Schema Registry do Confluent ou Karapace como alternativa open source).
- MVP implementado: JSON Schema com Ajv (draft 2020-12). O catálogo da Fase 1 vive em
src/nucleo/n-0b-registry/schemas/e é sincronizado no banco no boot de forma idempotente. OEventBusService.publicar()valida tipo, versão e payload contra o catálogo (tiposdeprecatedsão rejeitados). - Distribuição: o registry se materializa como pacote versionado (npm, pip, ou equivalente) que cada colônia importa do núcleo — única dependência permitida.
- Alterar o registry sem versionar é a única operação proibida no núcleo.
Critério de saída
Toda colônia consegue publicar e consumir eventos usando apenas os contratos do registry. Qualquer mudança de schema gera nova versão rastreável. Nenhuma colônia precisa conhecer a estrutura interna de outra.
Documento detalhado: N-0b - Registry.md
N-0c — Observabilidade
Seção intitulada “N-0c — Observabilidade”Contexto e responsabilidade
Camada transversal. Não é uma colônia de negócio, mas um requisito do núcleo desde o primeiro módulo. Sem observabilidade, erros em eventos são invisíveis e rastreamento de falhas é impossível.
Responsabilidades:
- Logs estruturados em JSON: toda entrada e saída do barramento gera log com
mensagem,correlacao_id,event_id,coloniae os dados do registro. - Trace distribuído por
correlacao_id: uma demanda que passou por 6 colônias tem um trace único que mostra cada passo. - Métricas básicas: volume de eventos por tipo, latência de processamento por colônia, taxa de falha e tamanho da DLQ.
- Alertas de anomalia: fila crescendo sem consumo, timeout de processamento, schema inválido.
Técnicas e referências de implementação
- Logs: formato JSON estruturado, emitido pelo
Loggerdo NestJS com serialização manual. - Trace: OpenTelemetry como padrão de instrumentação na Fase 2. Backend: Jaeger ou Zipkin.
- Métricas: Prometheus + Grafana como referência de visualização.
- No MVP implementado: spans de processamento com contexto de trace via
AsyncLocalStorage(oTraceInterceptorpropaga ocorrelacao_idnas requisições HTTP), métricas em memória expostas em formato Prometheus (GET /api/observability/metrics), gauge da DLQ vivo e health/readiness com checagem real de banco e MinIO. O trace porcorrelacao_idé materializado pelo N-0a (GET /api/events/trace/:correlacaoId), que consulta ocore.event_log. OpenTelemetry/Jaeger e Prometheus/Grafana são referência para a Fase 2.
Critério de saída
É possível, dado um demanda_id, recuperar o histórico completo de eventos que ela gerou e em qual colônia cada um foi processado.
Documento detalhado: N-0c - Observabilidade.md
Fase 1 — MVP Funcional Local
Seção intitulada “Fase 1 — MVP Funcional Local”Objetivo: fechar um ciclo mínimo completo. Demanda entra, é categorizada, entra no ranking, vira agenda, recebe conselheiro e tem andamento registrado publicamente. Nenhum passo pode ser pulado.
D-1 — Ingestão de Demanda
Seção intitulada “D-1 — Ingestão de Demanda”Esta colônia é o ponto de entrada do sistema. O que chega aqui é dado bruto: texto livre, foto, áudio, localização aproximada, horário. O que sai daqui é uma demanda normalizada, com campos padronizados, pronta para o restante do pipeline.
A complexidade interna justifica a quebra em três sub-colônias especializadas.
D-1a — Captura
Seção intitulada “D-1a — Captura”Contexto e responsabilidade
Recebe o input do cidadão por qualquer canal disponível: app móvel, formulário web, SMS, ou integração com plataformas existentes (ex: 156). Valida os campos mínimos obrigatórios e publica o evento de entrada.
Não normaliza. Não categoriza. Não valida conteúdo.
Eventos produzidos
demanda.recebida(versão publicada1.2.0) — payload:texto_bruto(vazio na captura só com mídia),tipo_midia(texto/foto/áudio),localizacao_bruta(lat/lng),midia_urlscomo campo adicional,assistenciacomo campo adicional de auditoria do revisor de texto,cidadao_id,canal,timestamp_criacao,termos_versao,consentimentose os camposcategoria_idesubcategoria_idda versão 1.1.0.lugar.recebido— fluxo de lugares do mesmo BFF, com o dado bruto do lugar.- Eventos de identidade e do fluxo do conselheiro publicados pelo BFF:
cidadão.cadastrado,cidadão.perfil_atualizado,cidadão.vinculado,conselheiro.cadastrado,conselheiro.atribuicao_recusadaeconselheiro.atualização_registrada.
Estado próprio
Registro de demandas recebidas com status pendente_normalizacao. Apenas o dado bruto, sem processamento.
Lógica
cidadão submete input→ valida campos mínimos (localização + descrição mínima)→ gera demanda_id único→ persiste dado bruto no estado próprio→ publica demanda.recebida no barramento→ retorna confirmação ao cidadão com demanda_id para acompanhamentoTécnicas e referências de implementação
- Rate limiting por IP, com 5 demandas por minuto no POST de captura. Referência: token bucket ou sliding window counter.
- Validação de localização: bounding box do território coberto. Rejeita coordenadas fora da área de operação.
- Raio de captura: a posição final da demanda/lugar precisa estar a no máximo 10 km do fix do GPS do dispositivo (
fix_lat/fix_lngopcionais no DTO; sem fix, a validação não roda). Impede relato de ponto distante do local de captura. - Canal de entrada como metadado persistido: útil para análise de padrões de acesso e cobertura territorial.
- Idempotência: hash do conteúdo +
cidadao_id, sem componente temporal. Submissão duplicada retorna HTTP 409 com odemanda_idexistente (idempotência permanente, não janela curta). A identidade do cidadão anônimo chega via headerX-Cidadao-Id(UUID v4 obrigatório na captura). - Assistência de texto:
POST /api/assistencia/textostateless no BFF, público, com rate limit de 10/min por IP, timeout de 8 s e degradação graciosa (disponivel: false). O campo adicionalassistencianos eventos de demanda, lugar e empresa registra o uso do revisor sem guardar o texto anterior nem o sugerido.
Critério de saída
Qualquer input válido de cidadão gera um demanda_id rastreável e o evento demanda.recebida no barramento dentro de tempo aceitável.
Documento detalhado: D-1a - Captura.md, D-1a - Front-end.md, D-1a - BFF.md
D-1b — Normalização
Seção intitulada “D-1b — Normalização”Contexto e responsabilidade
Consome demanda.recebida. Transforma o input bruto em um registro estruturado com campos padronizados. É aqui que texto livre vira campos semânticos, áudio vira transcrição e imagem vira descrição textual em campo próprio.
A autoria do texto é separada. A descricao_limpa publicada carrega exclusivamente o texto do cidadão e aceita string vazia; a descrição automática das imagens fica em midias_descritas e alimenta o título quando não há texto do cidadão.
A IA entra aqui como redução de atrito, nunca como decisão. Todo output automático é marcado como origem: 'automatico' e mantém acesso ao conteúdo bruto original.
Não categoriza. Não prioriza. Não valida vínculo.
Eventos consumidos
demanda.recebida
Eventos produzidos
demanda.normalizada(1.4.0; as versões 1.0.0 a 1.3.0 permanecem no catálogo) — payload contém: campos estruturados (título do cidadão ou da primeira legenda, descrição exclusivamente do cidadão, tipo de mídia processada, coordenadas validadas),confianca_normalizacao(0-1),demanda_id,conteudo_suspeitoetermos_suspeitos. A 1.4.0 separa a autoria e aceitadescricao_limpavazia;midias_descritastraz a descrição e a tradução de cada imagem da captura. O conteúdo suspeito alimenta a fila da D-1d e fica fora da vitrine até a decisão de moderação; as descrições alimentam o item de anexo da fila e a projeção pública por evidência.
Estado próprio
Versão normalizada de cada demanda, com referência ao dado bruto original. O bruto nunca é descartado.
Lógica
consome demanda.recebida→ se texto: limpa ruído (encoding, caracteres especiais), extrai título (primeiros N tokens significativos)→ se áudio: transcreve para texto (Whisper local); sem texto do cidadão, a transcrição preenche a descrição→ se imagem/foto: descreve cada imagem em sequência pelo modelo de visão local (Florence-2) e traduz cada legenda do inglês para o português (OPUS-MT), acumulando midias_descritas sem compor a descricao_limpa→ sem texto do cidadão, o título usa a primeira legenda exibível truncada→ valida coordenadas contra a bounding box única do território (a resolução fina fica na D-2)→ aplica a denylist de texto sobre o título e a descrição do cidadão e marca conteudo_suspeito quando há termo→ extrai entidades e calcula o score de confiança sobre o texto de análise (texto do cidadão e legendas exibíveis)→ persiste versão normalizada→ publica demanda.normalizada 1.4.0Detecção de idioma por biblioteca é Fase 2. A validação geo da D-1b rejeita apenas pontos fora da bounding box nacional; a resolução fina do território fica na D-2.
Técnicas e referências de implementação
- Transcrição de áudio: whisper-tiny via
@huggingface/transformers(ONNX runtime), no mesmo processo Node.js, com timeout de 60s. Referência: Whisper (OpenAI, open source). - Descrição de imagem: Florence-2-base via
@huggingface/transformers, com timeout de 180s, uma descrição por imagem da demanda em fluxo sequencial com o modelo já carregado. Se indisponível, o pipeline segue com confiança reduzida. A falha de uma imagem não impede as demais. - Tradução da legenda: OPUS-MT/Marian en→pt (Helsinki-NLP) via
@huggingface/transformers, depois do Florence, imagem por imagem; ela alimenta a legenda exibível demidias_descritase não compõe adescricao_limpa. A legenda original fica emprocessamento_detalhes.descricao_originale emmidias_descritas. Motor desligado, modelo ausente ou texto já em português mantém o original, gravadescricao_idioma: 'en'e penaliza a confiança da descrição. Cache no mesmo volumemodelos_d1b. - Limpeza de texto: remoção de HTML, normalização Unicode, detecção de idioma com langdetect ou fastText.
- Extração de entidades básicas: endereço, CEP, nome de rua. spaCy com modelo pt-BR ou regex estruturado para MVP.
- Score de confiança: função heurística simples no MVP (campos presentes / campos esperados). Modelos de confiança mais sofisticados entram na Fase 2.
- Denylist de texto:
MODERACAO_DENYLIST_TEXTOcom termos separados por vírgula, normalizados sem acento e em minúscula. Lista vazia ou ausente mantém o comportamento sem filtro. O resultado viraconteudo_suspeitoetermos_suspeitose alimenta a fila da D-1d. - Dado bruto preservado: armazenado com referência ao
demanda_id. Sempre acessível. Normalização é uma visão derivada, não substituta.
Critério de saída
Toda demanda recebida tem uma versão normalizada com campos estruturados, score de confiança calculado e referência ao dado bruto preservado.
Documento detalhado: D-1b - Normalização.md
D-1c — Gestão de Anexos
Seção intitulada “D-1c — Gestão de Anexos”Contexto e responsabilidade
Gerencia o ciclo de vida dos arquivos anexados a demandas: fotos, documentos, áudio. Recebe o binário, valida, armazena com segurança e disponibiliza URL de acesso.
Não processa conteúdo semântico dos arquivos — isso é da sub-colônia de normalização. Apenas garante que o arquivo existe, é válido e está acessível.
Eventos consumidos
demanda.recebida(quando contém mídia)demanda.evidencia_adicionada(evidências de confirmação e conclusão coletiva)moderacao.decidida(decisão de anexo; a D-1c aplica no registro e publicaanexo.moderadoou, na decisãoremovido, apaga o objeto e publicaanexo.removido)
Eventos produzidos
anexo.processado(1.4.0; as versões 1.0.0 a 1.3.0 permanecem no catálogo) — payload:demanda_id,anexo_id, URL de acesso, tipo MIME, tamanho, hash SHA-256,object_key_tempda captura,via(captura|confirmacao|conclusao),possui_dado_sensivel,categoria_sensivel,motivo_sensivelemoderacao_status. Oobject_key_temppermite à D-1d casar a descrição automática da imagem com o item da fila e à D-7 casá-la com a evidência no resumo e no relatório.anexo.moderado(1.0.0) — payload:anexo_id,status(ativo|bloqueado) emoderacao_status(aprovado|bloqueado).anexo.removido(1.0.0) — payload:anexo_id,demanda_idehash_sha256. Um evento por anexo afetado.
Estado próprio
Registro de anexos com metadados, URL de armazenamento e hash de integridade.
Lógica
recebe arquivo binário→ valida tipo MIME contra lista permitida→ valida tamanho máximo→ calcula hash SHA-256→ verifica duplicidade por hash (evita armazenamento redundante)→ armazena com nome derivado do hash→ classifica imagem (NSFW, pessoa e heurística de documento/PII)→ bloqueia NSFW e enfileira a moderação quando sinalizado→ registra metadados no estado próprio→ publica anexo.processado
consome moderacao.decidida (tipo anexo)→ aprovado ou bloqueado: aplica no registro e publica anexo.moderado→ removido: apaga o objeto permanente e os temporários de todas as cópias do hash, publica anexo.removido por cópia e marca as linhas com status removidoTécnicas e referências de implementação
- Armazenamento: S3-compatible (MinIO para self-hosted, S3 em cloud). URLs pré-assinadas com expiração para acesso controlado.
- Validação de tipo: por magic bytes, não apenas extensão.
- Limite de tamanho por tipo: imagem até 10MB, áudio até 5MB, application (documentos) até 20MB, texto até 5MB. Máximo de 10 mídias por demanda. Contrato de mídia da Fase 1:
imagemeaudio(vídeo não é aceito). - Privacidade de imagens: remoção de metadados EXIF, heurística de documento/PII via
sharpe classificação local comAdamCodd/vit-base-nsfw-detector(NSFW, limiares 0,85 e 0,50) eXenova/detr-resnet-50(pessoa, sinalização a 0,50). Pessoa sinaliza sem bloquear; NSFW bloqueia e enfileira a moderação. - Deduplicação por hash: mesmo arquivo enviado por duas demandas diferentes ocupa espaço uma única vez.
- Remoção física: a decisão
removidoda moderação apaga o objeto e todas as cópias do hash. O parhash_sha256 + demanda_idremovido funciona como tombstone e bloqueia o re-upload do mesmo arquivo para a mesma demanda. - Disponibilidade pública: arquivos de demandas públicas têm URL acessível sem autenticação. Expiração configurável.
Critério de saída
Todo arquivo anexado tem URL de acesso estável, hash de integridade registrado e é acessível publicamente quando a demanda for pública. Arquivo removido pela moderação não existe mais no bucket e não pode ser reenviado para a mesma demanda.
Documento detalhado: D-1c - Gestão de Anexos.md
D-1d — Moderação
Seção intitulada “D-1d — Moderação”Contexto e responsabilidade
Organiza a revisão humana do conteúdo sinalizado pela classificação automática. Consome anexo.processado (imagem com NSFW, pessoa ou documento sinalizado), demanda.normalizada (texto com termo da denylist) e conselheiro.atualização_publicada (relato com termo da denylist), enfileira os itens e expõe os endpoints de decisão e de histórico para o moderador. Aprovar libera o conteúdo na vitrine. Bloquear mantém o conteúdo oculto e pode ser revertido. Remover apaga a mídia do armazenamento e limpa o texto dos schemas, sem reversão; o tipo relato recusa remoção.
Não classifica conteúdo e não executa a remoção física. A classificação fica na D-1c e na D-1b, e a denylist do relato roda na D-6b pelo helper compartilhado. A aplicação da decisão fica nas colônias donas do estado: a D-1c aplica no anexo e publica anexo.moderado ou anexo.removido; a D-7 libera, oculta ou limpa o texto, o relato e a trilha pública; a N-0d limpa o texto nos schemas de origem.
Eventos consumidos
anexo.processado(1.4.0), quandomoderacao_status='pendente'oupossui_dado_sensivel=truedemanda.normalizada(1.4.0), quandoconteudo_suspeito=trueconselheiro.atualização_publicada(1.2.0), quandoconteudo_suspeito=true, como itemrelato
Eventos produzidos
moderacao.decidida(1.1.0) — payload:item_id,tipo(anexo|texto|relato),referencia_id,decisao(aprovado|bloqueado|removido),moderador_id,demanda_id?,motivo?,remover_texto_demanda?(só anexo) ereaberto?(reversão). A versão 1.0.0 permanece no catálogo para replay.
Estado próprio
Fila d1d.fila_moderacao com itens pendentes e decididos, histórico append-only d1d.decisoes_moderacao com uma linha por decisão ou reversão, descrições automáticas em d1d.descricoes_midia com upsert idempotente por demanda e chave da captura, mais d1d.eventos_processados (idempotência) e d1d.consumer_offset (cursor). A fila e o histórico mudam na mesma transação, com o evento_id reusado na publicação. O item de anexo guarda midia_object_key, a chave temporária que casa a descrição na listagem.
Lógica
consome anexo.processado / demanda.normalizada / conselheiro.atualização_publicada→ persiste as midias_descritas em d1d.descricoes_midia, inclusive no descarte→ sinalizado: enfileira com motivo, trecho e midia_object_key no anexo→ não sinalizado: descarta e avança o cursor→ a listagem casa a descrição por (demanda_id, midia_object_key) e monta descricao_imagem→ moderador decide ou reverte em /admin/moderacao→ grava a fila e o histórico na mesma transação→ publica moderacao.decidida→ D-1c aplica no anexo e publica anexo.moderado (ou anexo.removido, na remoção)→ D-7 libera, oculta ou limpa o conteúdo, incluindo o relato→ N-0d limpa o texto nos schemas de origem, na remoçãoEndpoints
GET /admin/moderacao/fila— listagem paginada com filtros de tipo e status, incluindoremovido(60/min, papel de moderação)GET /admin/moderacao/fila/:item_id/historico— decisões e reversões do item em ordem cronológica, com decisão, motivo, moderador e data; 404 para item inexistente (60/min, papel de moderação)POST /admin/moderacao/fila/:item_id/decidir— decisão com motivo opcional; na remoção o motivo é obrigatório e a flagremover_texto_demandasó vale para anexo;removidoem relato responde 400 (60/min, papel de moderação)POST /admin/moderacao/fila/:item_id/reverter— reverteaprovadooubloqueadopara a decisão oposta; item pendente ou removido responde 409 (60/min, papel de moderação)
Técnicas e referências de implementação
- Fila com idempotência por
evento_ide cursor de replay próprio (N-0a). - Decisão humana e auditável: a IA bloqueia por limiar e a revisão é reativa, no padrão da D-3.
- Bloquear mantém a mídia no bucket e o conteúdo oculto. Remover é a exceção ao append-only, com motivo obrigatório, confirmação de irreversibilidade e hash preservado como impressão digital.
- Histórico append-only com id abreviado do moderador na interface e a trava de concorrência no
updateManycondicional com 409; a fila do web se atualiza em intervalo de 30 segundos com a aba visível. - Descrição da imagem: o card do anexo mostra a tradução em destaque e o original do Florence abaixo, rotulado com o idioma, sob o selo de descrição automática. Sem descrição, o bloco não renderiza, e ele não aparece em item de texto nem de relato. O selo não expõe confiança, porque o valor do Florence é constante.
- Atalho para a demanda: o id no card abre
/acompanhamento/:demanda_idem nova guia, comtarget="_blank"erel="noreferrer", sem tirar o moderador da fila. - LGPD: a eliminação do titular anonimiza o trecho e o moderador da fila e do histórico e apaga as descrições automáticas das demandas do titular em
d1d.descricoes_midia; a remoção por moderação sobrescreve o trecho e os termos do motivo.
Critério de saída
Todo conteúdo sinalizado entra na fila e recebe uma decisão registrada com moderador, data e trilha legível. O conteúdo aprovado volta à vitrine, o bloqueado permanece oculto e o removido sai do armazenamento e dos schemas sem possibilidade de reversão. O relato sinalizado fica oculto até a decisão. O item de anexo mostra a descrição automática da imagem quando ela existe, com a tradução em destaque e o original abaixo.
Documento detalhado: D-1d - Moderação.md
D-2 — Georreferenciamento
Seção intitulada “D-2 — Georreferenciamento”Contexto e responsabilidade
Consome demandas normalizadas e resolve a questão territorial: a qual unidade cívica essa demanda pertence? E a qual nível?
Não categoriza o conteúdo da demanda. Não prioriza. Apenas resolve a geometria territorial.
Eventos consumidos
demanda.normalizada
Eventos produzidos
demanda.georreferenciada— payload:demanda_id,unidade_civica_idde menor nível resolvida,nivel_minimo_resolvido(1-7),cadeia_ucs(lista de unidades cívicas pai, do menor ao maior nível),municipio_idopcional (UUID do nível 4 da cadeia, resolvido pela D-2 pelo nível dos polígonos),metodo_resolucao(gps,enderecoouinferencia; no MVP sempregps),confianca_geo(alta,mediaoubaixa) ecoordenadas_lat/coordenadas_lngopcionais.
Estado próprio
Cache de resoluções geo por coordenada. Base de polígonos das unidades cívicas (GeoJSON por nível).
Lógica
consome demanda.normalizada→ extrai coordenadas (se disponíveis) ou endereço textual→ se coordenadas: point-in-polygon contra base de polígonos de unidades cívicas→ se endereço textual: geocodificação para coordenadas, depois point-in-polygon→ resolve nível mínimo (ex: micro-unidade cívica / quadra)→ resolve cadeia completa de unidades pai até nível nacional→ calcula confiança_geo: sempre `alta` no MVP, porque toda coordenada chega por GPS. Os valores `media` (endereço textual) e `baixa` (inferência) variam na Fase 2, junto com o geocoding→ ponto fora de todos os polígonos: persiste revisão pendente (`d2.revisoes_geo_pendentes`), não publica o evento de saída e não descarta em silêncio→ registra resolução no cache→ publica demanda.georreferenciadaSub-colônias potenciais (se o volume territorial escalar)
A Fase 1 trata como colônia única. Com escala, pode se quebrar em:
- Resolvedor de coordenadas: point-in-polygon puro.
- Geocodificador: texto → coordenadas, com cache agressivo.
- Validador de cobertura: verifica se a unidade cívica tem cobertura suficiente de dados (índice de subrepresentação, descrito na gestão).
Técnicas e referências de implementação
- Base geográfica — seed em três camadas:
- IBGE (automático): malha municipal 2025 (níveis 4 a 7) e malha de bairros do Censo 2022 (nível 2) como carga única. 23.123 polígonos, 17.575 deles bairros, convertidos de shapefile para GeoJSON. A cobertura de bairros é parcial: 895 municípios e 25 UFs, sem Tocantins e sem o Distrito Federal.
- Mapeamento coletivo (contínuo): cidadãos desenham os polígonos dos níveis 1-2 (setores e bairros) no front-end via ferramenta de desenho (
react-leaflet-draw). O polígono é submetido comolugar.recebido(tipo=poligono_uc), validado pela L-1 e inserido emcore.uc_polygons. Este é o mecanismo de bootstrap territorial alinhado com a filosofia do projeto. O fluxo de desenho no front ficou fora do MVP e entra na Fase 2; a captura via API permanece disponível e inerte no MVP. - OpenStreetMap (fallback, planejado): importação de relações
admin_level=10para bairros já mapeados. Cobertura parcial, complementar ao IBGE e ao mapeamento coletivo.
- Validação implícita por uso: quanto mais demandas e lugares são georreferenciados dentro de um polígono desenhado pela comunidade, mais validação o polígono recebe. Polígonos inconsistentes geram evidência acumulada de erro (demandas caindo fora de todos os polígonos ou no polígono errado).
- Point-in-polygon: Turf.js (JavaScript). Ray casting padrão, mesma biblioteca usada na validação de geometria do front-end, garantindo consistência.
- Geocodificação: Nominatim (OpenStreetMap, self-hosted) ou Photon como alternativas open source. Fallback para API externa em casos de falha.
- Cache:
Mapem memória no MVP para coordenadas resolvidas. Redis com TTL longo entra na Fase 2. A geometria dos polígonos não muda frequentemente. - Confiança geo: sempre
altano MVP (GPS do dispositivo). Endereço digitado (media) e inferência por texto (baixa) entram na Fase 2 com o geocoding. A confiança vira metadado da demanda para uso na priorização.
Critério de saída
Toda demanda normalizada tem unidade_civica_id resolvida e cadeia de unidades pai completa. Demandas com confiança geo baixa são marcadas e ficam visíveis no dashboard como “localização incerta”.
Documento detalhado: D-2 - Georreferenciamento.md
D-3 — Categorização
Seção intitulada “D-3 — Categorização”Contexto e responsabilidade
Classifica a demanda dentro da taxonomia de categorias do sistema. A taxonomia é estática na Fase 1 — definida nos parâmetros públicos, não gerada automaticamente. A colônia aplica a taxonomia, não a cria.
O resultado da categorização é o que permite ao ranking aplicar os pesos da tabela de precedência material. Sem categoria, não há ranqueamento.
Não define prioridade. Não altera o conteúdo da demanda. Não valida vínculo.
Eventos consumidos
demanda.normalizada— gatilho de processamento. O título, a descrição do cidadão e as legendas automáticas das imagens (midias_descritas) são a entrada do classificador.demanda.georreferenciada— alimenta projeção local (d3.projecao_geo) que mapeiademanda_idaounidade_civica_id.
Eventos produzidos
demanda.categorizada— payload:demanda_id,categoria_id,nivel_precedencia(1-5),score_horizontal,confianca_categorizacao,metodo(automatico/manual/revisao_pendente),sugestoes_alternativas(lista de{categoria_id, score_confianca}com até 5 candidatas),unidade_civica_id,nivel_minimo_resolvido.
Estado próprio
Categorização de cada demanda com histórico de versões. Se a categoria for corrigida manualmente, a versão anterior é preservada.
Taxonomia estática (Fase 1) — subconjunto MVP
O MVP implementa as seguintes categorias, extraídas da taxonomia completa (ver D-3 - Taxonomia.md). IDs e nomes são os mesmos do documento de referência.
O critério de inclusão é duplo: demanda universalmente reconhecível em qualquer bairro urbano do mundo e ciclo de resolução conduzível por um conselheiro de bairro sem depender de estrutura institucional específica por país.
Nível 1 — Sobrevivência básica 1.1 Abastecimento de água 1.2 Esgotamento sanitário 1.3 Energia elétrica
Nível 3 — Infraestrutura e serviços 3.1 Vias e pavimentação 3.2 Calçadas e acessibilidade física 3.3 Coleta de resíduos e limpeza urbana 3.4 Iluminação pública 3.9 Praças, parques e espaços públicosCategorias como saúde, educação e segurança pública são universais como demanda, mas seus ciclos de resolução variam por estrutura nacional — ficam na taxonomia completa para o classificador sugerir, mas saem da tela principal do MVP. O classificador pode atribuir qualquer categoria da taxonomia completa a partir do texto livre do cidadão, mesmo que o front-end do MVP não a exiba como opção direta.
Scores horizontais, pesos e categorias são definidos e revisados pelos comitês técnicos de parametrização, nunca pela colônia de categorização.
Lógica
consome demanda.normalizada→ aplica classificador sobre o texto de análise (título, descrição do cidadão e legendas automáticas das imagens)→ gera lista de categorias candidatas com score de confiança para cada→ seleciona categoria principal (maior score)→ se confiança >= limiar_automático: → categoriza automaticamente com marcação de origem=automático → publica demanda.categorizada imediatamente → caminho de contestação fica visível na timeline: qualquer cidadão pode sinalizar "categoria errada?"→ se confiança < limiar_automático e >= limiar_mínimo: → categoriza automaticamente com marcação de origem=automático → publica demanda.categorizada → mas também enfileira para revisão humana por amostragem (não bloqueia o pipeline)→ se confiança < limiar_mínimo: → enfileira para revisão manual obrigatória → não publica demanda.categorizada até que um moderador confirme ou corrija→ registra categorização com versão e métodoLógica de revisão manual
demanda.categorizada com metodo = 'revisao_pendente'→ exibe para moderador com sugestões do classificador→ moderador seleciona categoria ou cria nova (se justificada)→ decisão do moderador gera nova versão da categorização→ o par (texto, categoria_correta) alimenta o pipeline de melhoria do classificadorTécnicas e referências de implementação
- MVP: classificador baseado em palavras-chave e regras por nível + categoria. Dicionário de termos mapeados para
categoria_id. Rápido, explicável, zero dependência de modelo externo. - Evolução: TF-IDF + cosine similarity contra exemplos rotulados de cada categoria. Treinável com os dados corrigidos manualmente ao longo do tempo.
- Fase 2+: fine-tuning de modelo de linguagem leve (ex: BERT multilíngue ou BERTimbau para português) sobre o corpus de demandas rotuladas. Mantém explicabilidade via atenção.
- Limiar de confiança automático: parâmetro público. Valor inicial de referência: 0.85. Acima disso, a categorização é publicada imediatamente sem revisão humana, mantendo o caminho de contestação aberto na timeline.
- Limiar mínimo de confiança: parâmetro público. Valor inicial de referência: 0.7. Abaixo disso, a publicação é bloqueada até revisão manual. Entre 0.7 e 0.85, a categorização é publicada automaticamente mas também enfileirada para revisão por amostragem.
- Active learning: demandas com baixa confiança são priorizadas na fila de revisão manual. Demandas contestadas por cidadãos também entram na fila. Cada correção melhora o classificador.
- O modelo de classificação é open source, versionado e auditável. Qualquer pessoa pode replicar a classificação de uma demanda com os mesmos dados de entrada.
Critério de saída
Toda demanda categorizada tem categoria_id, nivel_precedencia e score_horizontal definidos. Demandas com confiança baixa estão sinalizadas e em fila de revisão. A taxa de revisão manual cai ao longo do tempo com o acúmulo de dados rotulados.
Documento detalhado: D-3 - Categorização.md
D-4 — Priorização e Ranking
Seção intitulada “D-4 — Priorização e Ranking”Contexto e responsabilidade
Aplica a fórmula de priorização sobre as demandas categorizadas e georreferenciadas. Produz o ranking ordenado por unidade cívica. É a colônia que transforma dados em fila de trabalho.
Não executa agenda. Não aloca conselheiros. Não define política — aplica parâmetros definidos externamente.
Eventos consumidos
demanda.categorizada— gatilho primário do cálculo.duplicidade.agregada(membros do agregado marcados inativos; ranking recalculado e republicado)parâmetros.atualizados— stub no MVP: loga e avança o cursor. O recálculo dinâmico com novos parâmetros é Fase 2.demanda.removida_por_votação— Fase 2, sem consumidor no MVP.peso_situacional.atualizado— Fase 2, sem consumidor no MVP; reajuste a cada 18 meses.
Eventos produzidos
demanda.ranqueada(1.1.0) — payload:demanda_id,unidade_civica_id,categoria_id,nivel_precedencia,score_final,breakdown(peso_nacional,peso_situacional,score_horizontal),posicao_no_ranking,total_demandas_na_uc,versao_parametrosetimestamp_calculo.ranking.atualizado— publicado quando o ranking de uma unidade cívica muda de forma significativa (novo item, re-ranqueamento por votação, atualização de parâmetros, desativação de membros de agregado).
Estado próprio
Ranking atual por unidade cívica (write model de posições). Histórico de scores por demanda_id com versão dos parâmetros vigentes no cálculo. A tabela é append-only: membros de agregado permanecem com linha inativa (ativo = false), nunca são apagados.
Lógica central — fórmula de priorização
Score_final = Peso_nacional(nivel_precedencia) × Peso_situacional(unidade_cívica, nivel_precedencia) × Score_horizontal(categoria_id)Peso nacional (nível de precedência) Valor estrutural por nível. Define a ordem macro. Nível 1 sempre à frente de nível 2, etc. Exemplo de referência:
Nível 1: 100Nível 2: 80Nível 3: 60Nível 4: 40Nível 5: 20Peso situacional (dinâmico por unidade cívica) Reflete onde a unidade cívica ainda está deficiente. Se saneamento (nível 1) já está resolvido naquela unidade, o peso situacional para nível 1 cai. Reajustado a cada 18 meses com dados reais.
Peso_situacional(UC, nível) = 1 - (cobertura_atingida(UC, nível) / cobertura_meta(UC, nível))Cobertura atingida é calculada com base em agendas concluídas e avaliações de resultado. Cobertura meta é parametrizada pelos comitês técnicos.
Score horizontal (por categoria dentro do nível) Posição relativa de cada tipo de demanda dentro do mesmo nível. Desempate dentro do nível.
Exemplo dentro do nível 1: Água potável: 95 Saneamento: 85 Energia básica: 70 Habitação risco: 60Distribuição por decaimento geométrico
A capacidade de conselheiros é distribuída entre todos os níveis por decaimento geométrico. O nível corrente recebe a maior fatia; os demais recebem fatias progressivamente menores conforme a distância. O fator f (referência: 0,40) define a razão entre fatias adjacentes. A distribuição normaliza para somar 100%.
Peso_bruto(j) = f ^ |j - nível_corrente| (onde f = 0,40)
Depois normaliza: cada nível recebe (peso_bruto / soma_total) da capacidade.Exemplo com f = 0,40 e nível corrente = 1:
| Nível | Distância | Peso bruto | Capacidade |
|---|---|---|---|
| 1 (corrente) | 0 | 1,0000 | 61% |
| 2 | 1 | 0,4000 | 24% |
| 3 | 2 | 0,1600 | 10% |
| 4 | 3 | 0,0640 | 4% |
| 5 | 4 | 0,0256 | 2% |
Soma dos pesos brutos = 1,6496. A normalização é exata em runtime — os percentuais acima são arredondados para exibição.
Nenhum nível fica a zero. Quando um nível vence, o seguinte assume a posição de corrente e a distribuição desliza sem salto. O fator f é parametrizável pelos comitês técnicos.
“Nível vencido” = peso_situacional(UC, nível) abaixo de limiar parametrizado (referência: 0.1).
Lógica de cálculo
para cada demanda_categorizada nova ou atualização de parâmetros: → recupera nivel_precedencia e score_horizontal da demanda → recupera peso_situacional atual da unidade_cívica → calcula score_final → registra breakdown completo (todos os fatores usados) → atualiza posição no ranking da unidade_cívica → publica demanda.ranqueada → se ranking mudou significativamente: publica ranking.atualizadoAuditabilidade do ranking
O breakdown é o mecanismo de explicabilidade. Para qualquer demanda, qualquer pessoa pode ver:
- Qual peso nacional foi aplicado e por quê (nível da demanda).
- Qual peso situacional foi aplicado e por quê (gap da unidade cívica naquele nível).
- Qual score horizontal foi aplicado e por quê (categoria).
- Qual versão dos parâmetros estava vigente no momento do cálculo.
Reproduzir o score manualmente, dado o breakdown, deve ser possível.
Técnicas e referências de implementação
- Estrutura de dados do ranking: no MVP implementado, ranking em memória com posições persistidas no banco (
d4.rankings) e reconstruído no boot. RedisZADDé referência para a Fase 2. - Recalculação em batch vs. incremental: incremental por evento no MVP (recalcula só a demanda afetada). Recalculação global quando parâmetros mudam.
- Versionamento de parâmetros: toda mudança de parâmetro gera uma versão nova. O breakdown persiste a versão dos parâmetros usados no cálculo — nunca apenas o score final.
- Frequência de re-ranqueamento: configurável por nível de demanda (semanal para nível 1, mensal para nível 2, etc.).
Critério de saída
O ranking de qualquer unidade cívica é público, ordenado, com breakdown completo por demanda. Qualquer alteração de parâmetro gera recalculação rastreável com nova versão.
Limites do modelo
O ranking é algoritmo de prioridade. Não é instrumento orçamentário. Não define de onde virá o recurso para executar as demandas ranqueadas. No estágio inicial, o financiamento é privado — doações, vaquinhas e contribuições de entusiastas — sem dependência de orçamento público. O sistema é agnóstico quanto a quem financia e executa: a exigência é execução rastreável e gastos públicos. Demandas impostas por decisão judicial entram como prioridade externa, com registro visível de que não passaram pelo algoritmo padrão. Conselhos setoriais já existentes (saúde, assistência social, educação) podem fornecer parâmetros técnicos para os scores horizontais.
Documento detalhado: D-4 - Priorização e Ranking.md
D-5 — Agenda
Seção intitulada “D-5 — Agenda”Contexto e responsabilidade
Transforma o ranking em backlog de trabalho concreto para as unidades cívicas. Agrupa demandas territorialmente, organiza o backlog e publica o estado atual da fila de trabalho.
Não executa as demandas. Não aloca conselheiros (isso é a D-6). Não re-rankeia: apenas consome o ranking produzido pela D-4.
Eventos consumidos
demanda.ranqueada— gatilho primário: insere ou atualiza demanda no backlogranking.atualizado— dispara rebuild completo do backlogdemanda.georreferenciada— projeção local de coordenadas para agrupamento geográfico (DBSCAN)conselheiro.sorteado(para marcar a demanda comoatribuidoe evitar re-sinalização para a D-6a)conselheiro.demanda_iniciada(para marcar a demanda comoem_progressono backlog)demanda.concluída(para retirar do backlog ativo)demanda.conclusao_confirmada(conclusão coletiva: item fora deem_progressopassa aconcluidocom data e dias até a conclusão; os demais casos são ignorados com log)duplicidade.agregada(membros marcadosagregado; backlog regenerado)demanda.removida_por_votação— stub da Fase 2: registrado sem cursor e fora do replay; apenas loga.parâmetros.atualizados— stub da Fase 2: loga e avança o cursor.
Eventos produzidos
agenda.gerada— publicado quando o backlog de uma unidade cívica é (re)construído.agenda.item_disponível— publicado quando uma nova demanda entra no topo do backlog, sinalizando para a colônia de conselheiros que há trabalho disponível.
Estado próprio
Backlog ordenado por unidade cívica, com projeção local de coordenadas (d5.coordenadas_demanda) e registro dos membros de agregado (d5.demandas_agregadas). Status de cada item: disponivel, atribuido, em_progresso, concluido e agregado; o status removido fica reservado à Fase 2. Itens agregado saem da ordenação e nunca geram agenda.item_disponível. Itens concluídos por qualquer via carregam data_conclusao e dias_ate_conclusao. Os grupos territoriais são efêmeros: vivem no resultado em memória do clustering e apenas o grupo_id gerado é persistido no item.
Conclusão coletiva
Quando demanda.conclusao_confirmada chega com ratificacao_necessaria: false, o handler conclui o item por status:
item inexistente → log.warn, cursor avançaitem em_progresso → ignorado com log (aguarda ratificação na D-6b)item agregado → ignorado com log (terminal)item concluido → idempotente, cursor avançademais status → status concluido + data_conclusao + dias_ate_conclusao + anúncio do próximo disponível da UCEvento com ratificacao_necessaria: true não mexe no backlog: a conclusão aguarda a ratificação na D-6b, que então publica demanda.concluída pelo fluxo normal. Itens agregado e concluido são preservados em qualquer ordem de entrega.
Lógica
consome ranking.atualizado→ recupera lista ordenada de demandas da unidade_cívica→ aplica distribuição por decaimento geométrico→ agrupa demandas por proximidade geográfica (clustering leve para otimizar deslocamento)→ gera backlog ordenado com posição, score e agrupamento→ publica agenda.gerada→ para cada demanda nova no topo: publica agenda.item_disponívelAgrupamento territorial
Demandas próximas geograficamente, do mesmo nível e categoria, podem ser agrupadas para otimizar a atuação do conselheiro. O agrupamento é sugestivo, não mandatório. O conselheiro decide se trata como demanda única ou separada.
critério de agrupamento no MVP: mesma unidade_cívica + mesma categoria + distância ≤ 500 m (raio padrão) com no mínimo 2 demandasTécnicas e referências de implementação
- Agrupamento geográfico: DBSCAN com Haversine como métrica de distância, no
GeoClusteringem memória. Raio padrão de 500 m e mínimo de 2 pontos. - Visualização do backlog: o backlog é público. A projeção de leitura é um endpoint paginado com filtros por nível, categoria, status e território.
- Agendas em backlog: demandas validadas e planejadas pelo ministério/secretaria responsável ficam em status
disponivelaté um conselheiro iniciar.
Critério de saída
O backlog de qualquer unidade cívica é público, acessível por API e atualizado em tempo real. A posição de cada demanda no backlog é justificada pelo score do ranking.
Documento detalhado: D-5 - Agenda.md
D-6 — Conselheiros
Seção intitulada “D-6 — Conselheiros”Esta colônia é responsável por toda a gestão do ciclo de atuação dos conselheiros: sorteio, atribuição de demandas, relatoria e acompanhamento. A complexidade justifica a quebra em duas sub-colônias com estados próprios distintos.
D-6a — Sorteio e Atribuição
Seção intitulada “D-6a — Sorteio e Atribuição”Contexto e responsabilidade
Gerencia o cadastro de conselheiros elegíveis, executa o sorteio quando necessário e atribui demandas disponíveis a conselheiros disponíveis respeitando a regra central: 1 conselheiro = 1 demanda ativa.
Não acompanha a execução. Não registra atualizações de status. Não avalia o conselheiro.
Eventos consumidos
agenda.item_disponível— sinaliza que há demanda esperando conselheiro.conselheiro.cadastrado— novo candidato no sistema (v1.1.0 inclui campocapacitacao_concluida).conselheiro.ciclo_concluído— conselheiro ficou disponível para nova atribuição.conselheiro.atribuicao_recusada— conselheiro recusou a atribuição. Dispara re-sorteio e contagem para anti-acumulação. O motivorisco_pessoal(1.1.0) encerra e re-sorteia sem contagem e sem suspensão;recusa_explicitaconta e suspende na quarta recusa (limite 3, 90 dias).duplicidade.agregada(D-12) — remove da fila de pendentes os membros de agregados.conselheiro.elegibilidade_atualizada— stub da Fase 2: loga e ignora. A mudança nos critérios (histórico de atuação, progressão de nível) entra na Fase 2.
Eventos produzidos
conselheiro.sorteado— payload:conselheiro_id,demanda_id,unidade_civica_id,metodo_sorteio,timestamp,seed_publico(para auditoria do sorteio).sorteio.sem_candidatos— publicado quando há demanda disponível mas nenhum conselheiro elegível na unidade cívica. Aciona notificação.
Estado próprio
Cadastro de conselheiros com status (disponível/ocupado/inativo), nível de atuação, unidade cívica vinculada e histórico de atribuições. Identidade unificada no MVP: o id do registro é o cidadao_id. A colônia mantém um único endpoint de leitura do próprio estado: GET /d6a/conselheiros/me/situacao (ConselheiroGuard, 60/min).
Critérios de elegibilidade (Fase 1)
Fase 1: - manifestou interesse - completou capacitação básica (certificação simples) - sem suspensão vigente - não tem demanda ativa no momento - a UC de atuação cobre ela mesma e as unidades menores dentro delaLógica do sorteio
agenda.item_disponível recebido para unidade_cívica X→ monta a cadeia ascendente de X: [X, pai, avô, ..., raiz]→ filtra conselheiros elegíveis por degrau, do exato à raiz; o primeiro degrau com elegíveis vence→ se nenhum degrau tem elegíveis: publica sorteio.sem_candidatos→ se há elegíveis: → gera seed público (HMAC-SHA256 do último `event_id` do barramento e do timestamp do momento) → ordena lista por seed (Fisher-Yates com seed determinístico) → seleciona primeiro da lista ordenada → atribui demanda ao conselheiro selecionado → atualiza status do conselheiro para "ocupado" → publica conselheiro.sorteado com o total_elegiveis do degrau vencedorAuditabilidade do sorteio
O seed_publico é derivado de dados imprevisíveis no momento da atribuição: HMAC-SHA256 sobre o último event_id do barramento combinado com o timestamp ISO-8601 do momento. Quando o barramento está indisponível, cai para um UUID aleatório com log. Publicado junto com o resultado. Qualquer pessoa pode reproduzir a ordenação da lista e verificar que o conselheiro selecionado era o correto. Nenhuma parte do sistema pode predeterminar quem será sorteado.
Técnicas e referências de implementação
- Geração de seed verificável: HMAC-SHA256 sobre o último
event_iddo barramento e o timestamp do momento. Referência de padrão: commit-reveal scheme simplificado. - Algoritmo de ordenação: Fisher-Yates shuffle com seed determinístico. Implementação em qualquer linguagem produz o mesmo resultado dado o mesmo seed.
- Anti-acumulação: conselheiro não pode recusar a atribuição indefinidamente. Recusa gera registro. Mais de 3 recusas consecutivas suspende o cadastro por período parametrizável; suspensos com prazo vencido são reativados no boot.
- Publicação com retry inline (
publicarComRetry) emconselheiro.sorteadoesorteio.sem_candidatos. - Re-sorteio após recusa usa o snapshot da demanda persistido em
d6a.atribuicoes(score_final,categoria_id,nivel_precedenciaegrupo_id), evitando placeholders na fila de pendentes. - Sorteio serializado por fila global em memória; os pools de UCs sobrepostas compartilham conselheiros e o MVP roda em instância única.
Critério de saída
Todo sorteio é reproduzível por terceiros. A atribuição de uma demanda a um conselheiro tem seed público, lista de elegíveis e método documentados.
Documento detalhado: D-6a - Sorteio e Atribuição.md
D-6b — Relatoria e Acompanhamento
Seção intitulada “D-6b — Relatoria e Acompanhamento”Contexto e responsabilidade
Registra cada atualização feita pelo conselheiro sobre a demanda que acompanha: status, prazos, evidências, contatos realizados, entraves encontrados. Transforma o trabalho do conselheiro em eventos estruturados e públicos.
Não avalia o conselheiro. Não decide sobre a demanda. Não gera a timeline pública — isso é responsabilidade da D-7 transparência.
Eventos consumidos
conselheiro.sorteado(inicia o acompanhamento; guarda de sorteio tardio: demanda já concluída socialmente não cria acompanhamento)conselheiro.atualização_registrada(publicado pela interface do conselheiro)demanda.conclusao_confirmada(com acompanhamento ativo, gravapendencia_conclusaoe registra entrada na relatoria; sem acompanhamento, apenas avança o cursor)
Eventos produzidos
conselheiro.demanda_iniciada— conselheiro fez o primeiro contato formal (telefonou, protocolou, agendou). É este evento que muda a demanda deatribuidoparaem_progressona D-5.conselheiro.atualização_publicada— payload:atualizacao_id,demanda_id,conselheiro_id, tipo, texto estruturado, campos estruturados, origem da estruturação,descricao_sanitizadaenumero_sequencial. A versão 1.2.0 acrescentaconteudo_suspeitoetermos_suspeitosquando a denylist de texto encontra termo; a 1.1.0 marca a transcrição automática e a 1.0.0 cobre o relato digitado limpo.conselheiro.prazo_próximo— alerta publicado N dias antes do prazo estimado. Disparado por CronJob a cada 6 horas.demanda.concluída— publicado quando o conselheiro marca a demanda como resolvida. Consumido pela D-5 para transição do backlog paraconcluido.conselheiro.ciclo_concluído— ciclo de atuação encerrado (demanda concluída, fim de mandato ou desistência). Publicado apósdemanda.concluídaquando a demanda é resolvida; publicado isoladamente nos demais casos. Consumido pela D-6a para liberar o conselheiro. As duas saídas de conclusão são persistidas emsaidas_conclusaoantes da publicação e republicadas pela varredura do boot quando a publicação falha.demanda.resumo_ciclo_atualizado(1.0.0) — resumo público do ciclo, comdemanda_id,resumo,total_atualizacoes,data_inicio,data_fim,versao_metodo,gerado_emefontes. Publicado a cada atualização publicada e no fecho do ciclo, com o texto sanitizado antes de persistir e publicar.
Estado próprio
Histórico de atualizações por demanda. Status atual de cada acompanhamento. Prazos registrados e alertas pendentes. pendencia_conclusao no acompanhamento (null sem pendência; { conclusao_id, total_conclusoes, data } com pendência). Snapshot saidas_conclusao com as duas saídas de conclusão (demanda.concluída e conselheiro.ciclo_concluído) e a flag saidas_conclusao_pendentes, que a varredura do boot republica quando a publicação falha. Tabela d6b.conclusoes_sociais com as conclusões confirmadas que não exigem ratificação, para a guarda de sorteio tardio. A coluna texto_resumo_ciclo guarda o resumo público do ciclo, atualizado a cada publicação e no fecho. O dossiê do caminho chega ao conselheiro pela projeção da D-7; a D-6b não consome caminho.atualizado no MVP. As atualizações do mesmo acompanhamento são serializadas por um lock em memória; o lock distribuído fica para a Fase 2.
Ratificação de conclusão coletiva
Rota POST /d6b/demandas/:demanda_id/ratificar-conclusao com ConselheiroGuard (JWT com sessão Google, 5/min, fora do prefixo api). Validações na ordem: sessão Google (401); acompanhamento ativo da demanda (404); pendência registrada (409); o cidadão é o conselheiro do acompanhamento (403). O sucesso reusa o fluxo de conclusão existente: publica demanda.concluída e conselheiro.ciclo_concluído com motivo_encerramento: 'demanda_concluida', limpa a pendência e registra a conclusão social. A conclusão por atualização normal do conselheiro também limpa a pendência. Sem motivo de encerramento novo.
Tipos de atualização (estruturados)
contato_realizado → com quem, canal, resultadoprotocolo_aberto → número, órgão, datadocumento_anexado → tipo, descrição, referência ao anexoentrave_registrado → descrição do bloqueio, órgão envolvidostatus_atualizado → pendente / em_andamento / aguardando / concluido / bloqueadoprazo_registrado → data estimada de resolução, fonte da estimativaLógica de normalização de atualização
conselheiro registra atualização via interface (front-end → BFF D-1a)→ front-end chama endpoint REST da D-6b para sugestão de IA (POST /d6b/sugerir-estruturacao)→ D-6b retorna sugestão com campos estruturados e score de confiança→ conselheiro revisa, edita e confirma no front-end→ BFF publica conselheiro.atualização_registrada no barramento→ D-6b consome, valida, persiste e verifica o texto na denylist de texto→ publica conselheiro.atualização_publicada (1.2.0 com suspeição, 1.1.0 na transcrição limpa, 1.0.0 no relato digitado limpo)→ se primeira atualização do acompanhamento: publica também conselheiro.demanda_iniciada→ se tipo for status_atualizado com conclusão: publica demanda.concluída + conselheiro.ciclo_concluídoIA na relatoria
A IA sugere como estruturar o texto da atualização (separar fato de interpretação, padronizar linguagem neutra) via endpoint REST dedicado (POST /d6b/sugerir-estruturacao, sob ConselheiroGuard, 10/min), chamado sincronamente pelo front-end do conselheiro. A sugestão é stateless: não persiste dados. O conselheiro sempre revisa e confirma antes da publicação. A sugestão original é preservada no payload do evento conselheiro.atualização_registrada para auditoria: o que a IA sugeriu vs. o que o conselheiro publicou. Se a IA não estiver disponível, opera em modo fallback com heurísticas de extração de campos. Em todos os casos, a sugestão é marcada como automática e o texto final publicado é do conselheiro. A IA nunca publica sem que o conselheiro tenha visto e confirmado a tela de revisão.
Critério de saída
Cada demanda ativa tem histórico de atualizações rastreável com timestamp, tipo estruturado e referência ao conselheiro responsável. O primeiro ato formal do conselheiro (iniciação) gera evento público imediato.
Documento detalhado: D-6b - Relatoria e Acompanhamento.md
D-7 — Transparência
Seção intitulada “D-7 — Transparência”Contexto e responsabilidade
Consolida o histórico de eventos de cada demanda em visões públicas de leitura. É a colônia de output principal para cidadãos, pesquisadores e auditores. Aplica o padrão CQRS: write model está nas colônias de origem, aqui ficam as projeções de leitura.
Não processa dados novos. Não toma decisões. Consome eventos de todas as demais colônias e projeta o estado legível.
Eventos consumidos
- 30 tipos em produção:
demanda.recebida,demanda.normalizada,demanda.categorizada,demanda.georreferenciada,demanda.ranqueada,ranking.atualizado,agenda.gerada,agenda.item_disponível,conselheiro.sorteado,conselheiro.demanda_iniciada,conselheiro.atualização_publicada,conselheiro.prazo_próximo,demanda.concluída,conselheiro.ciclo_concluído,lugar.cadastrado,lugar.georreferenciado,demanda.confirmada,demanda.evidencia_adicionada,duplicidade.candidata_detectada,duplicidade.agregada,anexo.processado,demanda.conclusao_confirmada,anexo.moderado,moderacao.decidida,anexo.removido,lugar.validado,lugar.desativado,demanda.resumo_agregado_atualizado,demanda.resumo_ciclo_atualizadoecaminho.atualizado. - Três stubs da Fase 2, fora do replay:
demanda.removida_por_votação,votação.resultado_publicadoehash.checkpoint_publicado.
Os eventos de demanda_id alimentam a timeline e o snapshot. lugar.cadastrado e lugar.georreferenciado alimentam d7.lugares_geo; residências e poligono_uc são descartados com cursor avançado. Os eventos do agregado projetam confirmações, evidências e representante. As decisões de moderação liberam, ocultam ou limpam o conteúdo, inclusive o relato do conselheiro suspenso pela denylist, que nasce interno e só entra na vitrine após a aprovação. Os dois resumos e o caminho atualizam o snapshot e a tabela de perfis, sem entrada de timeline, para não duplicar na vitrine o texto derivado que já aparece nos resumos.
Eventos produzidos
- Nenhum. Colônia de leitura pura. Serve queries, não produz eventos de negócio.
Estado próprio
Projeções de leitura desnormalizadas (otimizadas para query, não para escrita):
- Timeline por
demanda_id: lista cronológica inversa de todos os eventos (mais recentes primeiro), com descrição legível. - Dashboard por
unidade_civica_id: contagens, médias, distribuição por status e categoria. - Snapshot por
demanda_id(d7.demanda_snapshots): título,coordenada_latecoordenada_lng(dedemanda.recebida.localizacao_bruta, sobrescritas pordemanda.georreferenciada), status, categoria, UC,municipio_id(campomunicipio_iddedemanda.georreferenciada, com fallback pelo quarto elo dacadeia_ucs),total_confirmacoes,agregado_representante_id,agregado_membros_ids,resumo_agregado,resumo_ciclo,resumos_atualizado_em,caminho_dossieedescricoes_midia([{ object_key, descricao }], com a descrição automática de cada imagem, sanitizada e truncada em 2.000 caracteres). Adescricaopública do snapshot é exclusivamente o texto do cidadão; a descrição das imagens aparece por evidência e no bloco marcado como IA. d7.caminhos: perfil por (município, subcategoria) alimentado porcaminho.atualizado, com contagem de casos, prazo mediano, canais, órgãos, gargalos, documentos, dossiê eversao_metodo. Ocaminho_dossiedo snapshot é a cópia denormalizada do perfil para a demanda, e os endpoints servem o caminho pela chave da demanda, com fallback para a categoria.d7.demanda_evidencias: evidências da captura, das confirmações e da conclusão, comvia,object_keyeobject_key_temp; a URL é assinada na leitura, com validade de 5 minutos. Oobject_key_tempcasa a evidência comdescricoes_midiae a leitura devolve adescricaoda imagem; evidência sem par fica sem o campo.d7.lugares_geo: lugares públicos (organização e equipamento público) com coordenadas, tipo, nome, subtipo declarado e confirmado,descricao,horario_funcionamento, UC resolvida,status,status_confianca(defaultprovisorio),metodo_validacao,total_confirmacoeseconfianca_tipificacao. O lugar provisório entra na projeção e aparece no mapa com marcação distinta;disputadooudesativadosai da listagem pública e o resumo devolve 404.- Visão pública de um conselheiro: demandas acompanhadas, status, tempo médio (Fase 2).
- Polígonos de UC são lidos de
core.uc_polygonsno endpoint de listagem (exceção controlada, read-only). - A decisão
removidolimpa a projeção: o snapshot perde título, descrição, última atualização edescricoes_midia, as entradas internas recebem a marca de remoção, a timeline ganha a entrada pública e a evidência removida sai ded7.demanda_evidenciascom a entrada correspondente dedescricoes_midia. Como o log já foi tombstonado pela N-0d, o rebuild não ressuscita conteúdo nem evidência; as descrições de mídia, preservadas em claro pela redação, sobrevivem ao replay. A eliminação e a retenção do titular também zeramdescricoes_midia. - O relato do conselheiro entra na timeline com
dados_relevantes.atualizacao_id. Comconteudo_suspeito=true, a entrada nasce interna e otexto_ultima_atualizacaonão é tocado; a aprovação publica as entradas doatualizacao_ide repõe o texto da última atualização truncado em 200 caracteres; a reversão para bloqueado oculta de novo e zera o texto.
Endpoints públicos
GET /api/d7/timeline/:demanda_id(60/min) — timeline completa da demanda, paginada, em ordem cronológica inversa.GET /api/d7/dashboard/:uc_id(30/min) — dashboard de indicadores agregados da unidade cívica.GET /api/d7/demandas(60/min) — demandas por bounding box; excluiremovida,agregadaeconcluidano filtro padrão, aceitastatusexplícito, inclusiveconcluida, e devolvetotal_confirmacoeseagregado_representante_idpor linha. O mapa mostra só o que está em aberto.GET /api/d7/lugares(60/min) — lugares por bounding box, comstatus_confiancapor linha e filtro dedisputadoedesativado; residências nunca são retornadas (LGPD).GET /api/d7/lugar/:lugar_id/resumo(60/min) — resumo público do lugar. 404 para lugar inexistente, disputado ou desativado.GET /api/d7/uc/poligonos(30/min) — polígonos de UC por nível opcional,uc_ide nome normalizado (sem acento, caixa ou pontuação); cada linha devolveuf?eparent_nome?, eincluir_geometria(padrãotrue) permite respostas sem GeoJSON. O seletor do web mostraSP · São Paulo · Pinheiros.GET /api/d7/demanda/:demanda_id/resumo(60/min) — título e descrição públicos quando projetados, subcategoria resolvida pela taxonomia, contador de confirmações, membros do agregado, evidências com URL de 5 minutos edescricaoopcional por imagem, coordenadas opcionais, as marcasconteudo_removidoeconteudo_removido_eme os camposresumo_agregado,resumo_ciclo,resumos_atualizado_emecaminhoquando projetados.GET /api/d7/demanda/:demanda_id/relatorio(30/min) — relatório da demanda: identificação, descrição pública sanitizada do cidadão (quando projetada), categoria com nome e área da taxonomia, subcategoria com a descrição formal, status com descrição, datas, coordenadas, score e posição corrente no ranking, contador de confirmações, agregado, evidências (comdescricaoopcional por imagem), timeline pública completa, dias em aberto, responsáveis nos três níveis federativos e os mesmosresumo_agregado,resumo_ciclo,resumos_atualizado_emecaminhodo resumo. O acompanhamento e o relatório exportado mostram a mesma visão.GET /api/d7/uc/:uc_id/relatorio(15/min) — demandas da UC agregadas por categoria, com filtros opcionais de categoria, status e janela temporal, demanda mais antiga por categoria e responsáveis. A matéria-prima vem das projeções existentes: snapshots, timeline, evidências e o mapashared/taxonomia/responsaveis-categorias.ts.GET /api/d7/uc/:uc_id/historico(60/min) — histórico público paginado das demandas concluídas da UC e das unidades menores dentro dela, com status fixoconcluida, filtros de categoria, janela pordata_conclusaoe título, e ordenação por data de conclusão decrescente. É a consulta do que já foi resolvido; o mapa fica com o que está em aberto.GET /api/d7/ranking/:uc_id(60/min) — ranking público da UC, ordenado por score final, com busca opcional por trecho do título. Agregadas, removidas e concluídas não aparecem.POST /api/d7/rebuild(1/hora,PapelOperadorGuard) — rebuild síncrono das projeções via replay; responde 409 quando já há uma reconstrução em andamento.
Contratos completos no documento detalhado, seções 1.8 a 1.12.
Lógica de projeção
para cada evento relevante: → mapeia evento para descrição legível em português → adiciona ao log cronológico da demanda → atualiza agregados do dashboard da unidade_cívica → se evento é público: marca como visível sem autenticação → persiste projeção no banco de leituraExemplos de descrição legível na timeline
evento: demanda.recebida→ "Demanda registrada via app em 14/03/2026 às 10:32"
evento: demanda.categorizada (método=automático)→ "Categorizada automaticamente como: Saneamento básico (nível 1) — confiança 82%"
evento: conselheiro.sorteado→ "Conselheiro designado via sorteio em 15/03/2026"
evento: conselheiro.demanda_iniciada→ "Conselheiro fez o primeiro contato com a Prefeitura em 16/03/2026"
evento: conselheiro.atualização_publicada (tipo=entrave)→ "Entrave registrado: aguardando autorização da SABESP — 20/03/2026"Dashboard básico — indicadores da Fase 1
por unidade_cívica: total de demandas ativas distribuição por nível de precedência distribuição por status tempo médio de início (da recepção até a primeira ação do conselheiro) tempo médio de conclusão (das demandas já encerradas) número de conselheiros ativos taxa de demandas com confiança geo baixa (sinaliza necessidade de revisão)Técnicas e referências de implementação
- Banco de leitura: PostgreSQL com índices otimizados para as queries do dashboard. Ou ElasticSearch para queries de texto e geoespaciais.
- Padrão CQRS: os eventos são a fonte da verdade. O banco de leitura é descartável e reconstruível a qualquer momento replaying todos os eventos do barramento. Isso é o que garante que a projeção pública nunca diverge do estado real — pode ser reconstruída do zero se necessário.
- API pública: endpoints REST com paginação. Nenhuma autenticação necessária para dados públicos. Rate limiting para proteção contra scraping massivo.
- Internacionalização das descrições: os textos legíveis são templates parametrizados. Trocar o idioma é trocar os templates, sem alterar a lógica de projeção.
Critério de saída
Qualquer cidadão consegue acessar a timeline completa de qualquer demanda pública pelo demanda_id. O dashboard de qualquer unidade cívica está acessível sem autenticação e atualizado em tempo próximo ao real. O histórico das demandas concluídas de uma unidade cívica está acessível por UC, sem autenticação.
Documento detalhado: D-7 - Transparência.md
C-1 — Cadastro de Cidadãos
Seção intitulada “C-1 — Cadastro de Cidadãos”Fase 1 (embarcada no BFF) → Fase 2 (microsserviço independente)
Contexto e responsabilidade
A C-1 é a fonte da verdade da identidade do cidadão e de suas autodeclarações de perfil. Responde a duas perguntas: quem é o cidadao_id que está operando e o que esse cidadão declara sobre si? Gerencia os providers de autenticação (device anônimo, Google, gov.br na Fase 2) e mantém os metadados de perfil: nome, email, avatar, endereço autodeclarado e unidade cívica de residência autodeclarada.
A C-1 guarda a declaração. A verificação é outra camada. Quando o cidadão declara “moro na Rua X, UC Jardim das Flores”, a C-1 armazena. Na Fase 2, a D-9 (Validação de Vínculo) verifica independentemente essa declaração (documento, validação social ou presença) e publica o resultado. A C-1 e a D-9 são donas de entidades distintas no mesmo fluxo. A D-9 referencia o par cidadao_id + uc_id declarado na C-1 e emite vínculo.validado com status, método e hash da evidência.
Não valida vínculo, não gerencia elegibilidade de conselheiro, não toma decisão sobre quem pode fazer o quê. Apenas estabelece identidade e armazena autodeclarações.
No MVP (Fase 1), a C-1 não existe como módulo separado. Os dados de cidadão residem no estado próprio do BFF da D-1a. É uma tabela encapsulada dentro do módulo. O BFF é o dono natural porque é ele quem gera o cidadao_id e gerencia os providers de autenticação.
Na Fase 2, quando o monolito se parte em microsserviços, a tabela é extraída para a C-1 como serviço independente. O BFF passa a consumi-la por API síncrona (login, atualização de perfil) e por eventos (projeções locais de leitura). Nenhuma outra colônia acessa o banco da C-1.
Eventos produzidos
cidadão.cadastrado— novo registro criado com identidade básica.cidadão.perfil_atualizado— nome, email, avatar, endereço ou UC de residência alterados.cidadão.vinculado— Device ID anônimo vinculado a uma conta Google/gov.br.
Eventos consumidos
vínculo.validado(D-9) — a C mantém projeção local do status de vínculo para exibição no perfil.
Estado próprio
Registro de cidadãos com:
id,nome,email,avatar_url,auth_provider- Mapeamento de providers (
google_sub,govbr_sub) - Endereço autodeclarado e
unidade_civica_idde residência (opcionais, autodeclarados) - Projeção local: status de vínculo por UC (consumido da D-9)
Critério de saída
Toda colônia que precisa de metadados de cidadão ou de status de vínculo os obtém via cidadao_id. A C-1 não armazena dados pessoais além do mínimo necessário. Documentos e evidências de vínculo são domínio exclusivo da D-9.
Documento detalhado: C-1 - Cadastro de Cidadãos.md
D-12 — Detecção de Duplicidade
Seção intitulada “D-12 — Detecção de Duplicidade”Contexto e responsabilidade
Detecta demandas equivalentes e as agrega sob um representante, por confirmação coletiva. Reduz ruído no ranking e no mapa: a mesma necessidade ocupa uma posição, não várias. No MVP, a detecção é heurística determinística. A similaridade semântica por embeddings entra na Fase 2.
Não rejeita, não mescla e não decide sozinha. Sinaliza candidatas e executa a agregação que a confirmação coletiva autorizou.
Eventos consumidos
demanda.recebida(grava o relator privado)demanda.normalizada(descrição do cidadão, legendas automáticas das imagens e coordenadas)demanda.categorizada(categoria; UC da versão 1.1.0)demanda.georreferenciada(UC e coordenadas)demanda.concluída(status terminal)conselheiro.sorteado(statusatribuida)duplicidade.agregada(statusagregada)demanda.conclusao_confirmada(própria saída, no replay e no rebuild: conclui o índice quando a ratificação é desnecessária)cidadão.vinculado(funde relator, confirmações e conclusões do device anônimo nocidadao_idda conta Google)
Eventos produzidos
duplicidade.candidata_detectada— candidatas com similaridade, distância, categoria e UC;origem: 'automatico',versao_modeloe critérios no payload.demanda.confirmada—total_confirmacoesnovo e mecanismo (mapa|captura). Semcidadao_id.demanda.evidencia_adicionada— evidência anexada (imagem|audio, URL pública,via: 'confirmacao' | 'conclusao').duplicidade.agregada— representante e membros,mecanismo: 'confirmacao_coletiva'. Semcidadao_id.demanda.conclusao_confirmada— conclusão coletiva no limiar:demanda_id,unidade_civica_id,conclusao_id,total_conclusoes,data_conclusao,mecanismo: 'confirmacao_coletiva',ratificacao_necessaria. Semcidadao_id, sem evidência, sem coordenada.demanda.resumo_agregado_atualizado(1.0.0) — resumo público do agregado, comdemanda_iddo representante,membros,resumo,total_relatos,periodo,versao_metodo,gerado_emefontes. Publicado no fecho do agregado e a cada membro novo, com o texto sanitizado antes de persistir e publicar.
Estado próprio (schema d12)
d12.demanda_indice: texto normalizado e tokens, categoria, UC, coordenadas, status,relator_cidadao_id(privado),conclusao_confirmada_publicada,data_recebida,ultimo_event_id.d12.candidatas: pares com similaridade, distância, categoria e UC.d12.confirmacoes:cidadao_ide localização de presença (privados), evidência, mecanismo,verificada.d12.conclusoes:cidadao_ide localização de presença (privados), evidência,verificada,evento_id; unique[demanda_id, cidadao_id].d12.agregados: representante, membros, critérios eresumo_agregado(texto público do agregado).d12.consumer_offset.
O índice guarda descricao_limpa apenas com o texto do cidadão; a comparação usa a descrição e as legendas automáticas das imagens (midias_descritas, tradução quando aplicada), com fallback para o título. O resumo agregado segue lendo a descricao_limpa do cidadão.
Lógica de detecção (heurística MVP)
consome demanda.categorizada ou demanda.georreferenciada→ índice completo (UC + categoria + coordenadas + texto)→ compara com demandas da mesma UC e categoria, excluindo status atribuida, concluida e agregada→ Haversine própria ≤ 500 m + Jaccard ≥ 0,6 (unigrams + bigrams, stopwords PT)→ par novo vira linha em d12.candidatas→ publica duplicidade.candidata_detectadaLógica de confirmação e agregação
confirmação via POST /api/d12/demandas/:id/confirmacoes→ identidade: JWT com auth_provider='google' tem precedência; sem JWT, X-Cidadao-Id anônimo (400 sem header, 401 com Bearer inválido)→ demanda existe no índice (404) e tem status não terminal (409)→ não é o relator (400); cidadão ainda não confirmou (409)→ presença: Haversine entre cidadão e demanda ≤ 700 m (400)→ anônimo com total atual ≥ 2 recebe 401 login_necessario; a terceira exige conta Google verificada→ persiste confirmação; publica demanda.confirmada (+ evidencia_adicionada por item)→ com candidatas registradas, total ≥ 3 e ao menos uma confirmação verificada: → representante = mais confirmações (desempate: data_recebida mais antiga) → membros passam a status agregada → publica duplicidade.agregadaLógica de conclusão coletiva
conclusão via POST /api/d12/demandas/:id/conclusoes→ identidade: JWT com auth_provider='google' tem precedência; sem JWT, X-Cidadao-Id anônimo (400 sem header, 401 com Bearer inválido)→ demanda existe no índice (404); status terminal ou agregada rejeita (409)→ não é o relator (400); cidadão ainda não concluiu (409, unique no banco)→ presença: Haversine entre cidadão e demanda ≤ 700 m (400)→ evidência obrigatória de 1 a 3 mídias (400 sem evidência)→ anônimo com total atual ≥ 2 recebe 401 login_necessario; a terceira exige conta Google verificada→ persiste conclusão; publica demanda.evidencia_adicionada (1.3.0, via: 'conclusao') por item→ quando o total cruza 3 (CONCLUSAO_CONFIRMACOES_MINIMAS): → ratificacao_necessaria = (status do índice === atribuida) → publica demanda.conclusao_confirmada se ainda não publicada e houver ao menos uma conclusão verificada → sem ratificação: índice passa a concluida (status monotônico, não regride atribuida) → índice grava conclusao_confirmada_publicada = true (restaurado no rebuild pelo próprio evento)Endpoints REST
POST /api/d12/demandas/:demanda_id/confirmacoes(5/min) — identidade por JWT (precedência) ou headerX-Cidadao-Id(UUID v4; 400 sem header, 401 com Bearer inválido). Anônimo com total atual ≥ 2 recebe 401login_necessario. DTO com localização e evidência opcional (máx. 3).POST /api/d12/demandas/:demanda_id/conclusoes(5/min) — identidade igual à confirmação; anônimo com total atual ≥ 2 recebe 401login_necessario. DTO com localização e evidência obrigatória (1 a 3 mídias com URL validada). 201 devolve{ conclusao_id, total_conclusoes, ratificacao_necessaria }.POST /api/d12/candidatas(30/min) — busca prévia de candidatas por texto, categoria e coordenada; devolve top 5 por similaridade, depois distância.POST /api/d12/rebuild(1/hora, operador) — truncademanda_indice,candidataseagregados, zera offsets e faz replay paginado dos tipos consumidos. Confirmações e conclusões são preservadas (não reconstruíveis de eventos públicos) e seus contadores permanecem.
Desvínculo e LGPD
Nenhum payload de evento carrega cidadao_id. A confirmação e a conclusão são públicas só como total. A evidência anexada por terceiro é pública com o mesmo aviso e consentimento de mídia pública da captura (art. 11, I). A coordenada de presença do confirmador é privada: não entra em payload nem em projeção. A conclusão segue o mesmo padrão. A partir da terceira validação, a identidade exigida é a conta Google verificada; o vínculo do device anônimo à conta (cidadão.vinculado) funde as validações do mesmo titular, com deduplicação, e as linhas migradas passam a contar como verificadas. O identificador e a presença continuam restritos ao schema d12.
Técnicas e referências de implementação
- Normalização de texto: lowercase, remoção de acentos, pontuação e stopwords PT mínima; tokens com unigrams + bigrams deduplicados.
- Similaridade: Jaccard sobre conjuntos de tokens. Haversine própria para distância.
- Parâmetros estáticos em
d12.constants.ts: raio de candidatura 500 m, raio de presença 700 m, similaridade mínima 0,6, limiar de 3 confirmações, limiar de 3 conclusões (CONCLUSAO_CONFIRMACOES_MINIMAS), top 5 candidatas, confirmações e conclusões anônimas até 2 (CONFIRMACOES_ANONIMAS_PERMITIDASeCONCLUSAO_ANONIMAS_PERMITIDAS) e ao menos uma validação verificada no limiar (VERIFICADAS_MINIMAS_PARA_TRIGGER). - Fase 2: embeddings multilíngues leves + busca ANN (FAISS/Annoy). O limiar por categoria passa a se calibrar com duplicidades confirmadas ou descartadas.
Critério de saída
Demandas equivalentes da mesma unidade cívica são sinalizadas como candidatas antes de entrarem no ranking. Com 3 confirmações de cidadãos distintos, sendo ao menos uma verificada, o agregado existe sob um representante: membros com status agregada, fora do mapa, do ranking e do backlog, preservados com timeline e evidências próprias. Com 3 conclusões de cidadãos distintos, sendo ao menos uma verificada, a demanda encerra por via coletiva: sem conselheiro ativo, conclui direto; com conselheiro sorteado, a D-6b registra pendência e a rota de ratificação encerra o ciclo. Validações anônimas valem até o total 2; a terceira exige conta Google verificada.
D-24 — Memória de Caminhos
Seção intitulada “D-24 — Memória de Caminhos”Fase 3 no desenho original, antecipada para a Fase 1 junto do ciclo de demandas. A antecipação está registrada no Apêndice C.
Contexto e responsabilidade
Acumula o caminho real de resolução de cada ciclo concluído e transforma os casos em conhecimento agregado por município e subcategoria. O perfil do par (município, subcategoria) reúne o que funcionou antes: canais, órgãos, documentos, gargalos, prazo mediano e taxa de resolução. O dossiê explica os casos que compõem o perfil, com referências e datas.
O conhecimento volta ao conselheiro, que vê o caminho dos casos anteriores ao abrir um novo acompanhamento, e ao público, que vê o mesmo dossiê no acompanhamento e no relatório. A décima primeira demanda de buraco na via nasce com o caminho das dez anteriores explicado e concatenado.
Não decide, não prioriza e não prescreve. O dossiê é histórico automático e versionado pelo método caminho_v1. A decisão continua humana, e o conselheiro pode registrar caminhos diferentes, que entram no acúmulo.
Eventos consumidos
demanda.georreferenciada— município no campomunicipio_id(nível 4), com fallback pelo quarto elo dacadeia_ucs.demanda.categorizada— subcategoria, com fallback para a categoria.conselheiro.atualização_publicada— campos estruturados do caminho: canal, órgão, protocolo, documentos, gargalos e prazos.duplicidade.agregada— marca de membro de agregado, para o membro não contar como caso.demanda.concluída— fecho sem conselheiro ativo.conselheiro.ciclo_concluído— desfecho, prazos, total de atualizações e resumo final.
Eventos produzidos
caminho.atualizado(1.0.0) — payload:municipio_id,subcategoria_id,categoria_id,total_casos,prazo_mediano_dias,canais,orgaos,gargalos,documentos,dossie,versao_metodoegerado_em. Publicado apenas quando o perfil muda. Consumido pela D-7, que projetad7.caminhose o dossiê no snapshot da demanda. O workspace do conselheiro lê o dossiê pela projeção da D-7.
Estado próprio (schema d24)
d24.demandas: projeção de cada demanda com município, categoria, subcategoria e a marcaagregado_representante_id. A coluna da marca não estava no contrato original e entrou na migration0009_d24.d24.caminhos_casos: caminho de cada caso concluído, comorgao_acionado,canal,protocolo,documentos,gargalos,prazo_dias,desfecho,total_atualizacoeseresumo.desfechousaconcluidaouencerrada_sem_conclusao.d24.caminhos_perfis: perfil agregado por (município, subcategoria), comtotal_casos,canais,orgaos,documentos,gargalos,prazo_mediano_dias,taxa_resolucao, primeiro e último caso,dossieeversao_metodo.d24.eventos_processadosed24.consumer_offset: protocolo de consumo com replay e idempotência porevent_id.
Lógica
consome um dos seis tipos de entrada→ atualiza d24.demandas ou extrai o caminho para d24.caminhos_casos (canal, órgão, protocolo, documentos, gargalos e prazo por tipo de atualização)→ no fecho, grava desfecho, prazo, total de atualizações e resumo→ membro de agregado não gera caso e o fecho dele é ignorado→ recomputa o perfil do par (município, subcategoria), com fallback para a categoria→ publica caminho.atualizado quando o perfil mudaDossiê caminho_v1
Template determinístico com a contagem de casos, o período, os canais e órgãos mais usados, os documentos e gargalos recorrentes e a lista de referências dos casos. O texto exibe até 20 referências e informa quantas ficaram de fora; a lista completa fica no JSONB dossie. O teto é de 4000 caracteres e o mínimo para exibir é um caso. A sanitização de PII roda nos campos de texto antes de compor o dossiê, e o texto final mantém os identificadores das referências intactos.
Endpoint administrativo
POST /api/d24/rebuild(1/hora,PapelOperadorGuard) — reprocessa os eventos consumidos em ordem desequence_numbere reconstrói casos e perfis. O rebuild zera projeções, idempotência e offsets e bloqueia o consumo ao vivo durante a reconstrução.
Técnicas e referências de implementação
- Agregação determinística por par (município, subcategoria) em SQL, sem embeddings nesta leva. A busca semântica segue a mesma evolução da D-12, na fase da infraestrutura de IA dedicada.
- Fallback de subcategoria para a categoria quando o caso não tem subcategoria ou não há perfil do par.
- O dossiê é publicado com
publicarComRetry. Falha persistente vai para a DLQ e a retentativa do boot recomputa e republica, sem perda silenciosa.
Critério de saída
Cada ciclo concluído alimenta o perfil do par (município, subcategoria) e o dossiê fica disponível para o conselheiro e para o público. O caminho acumulado não decide nada e é sempre marcado como histórico automático.
Fase 2 — Expansão e Maturidade
Seção intitulada “Fase 2 — Expansão e Maturidade”Objetivo: escala territorial e robustez institucional. Começa quando ciclos completos foram documentados em múltiplos municípios e os dados da Fase 1 permitem comparação entre unidades cívicas.
D-8 — Manutenção Programada
Seção intitulada “D-8 — Manutenção Programada”Contexto e responsabilidade
Gera demandas de manutenção preventiva a partir de projetos concluídos. Quando uma demanda do tipo “projeto” ou “obra” é concluída com parâmetros de manutenção definidos, esta colônia agenda ciclos conforme o plano registrado pelo responsável técnico. No intervalo programado, publica uma nova demanda que entra no pipeline normal.
Não executa manutenção, não fiscaliza o estado físico do ativo e não decide prioridade. Apenas gera a demanda no momento certo e mantém o vínculo com o projeto original.
Eventos consumidos
demanda.concluída(somente demandas com campoplano_manutencaopreenchido)manutenção.executada(resultado de uma manutenção concluída, para registro no histórico)demanda.recebida(tracking de pipeline: apenas demandas comorigem = 'manutenção_programada')
Eventos produzidos
demanda.recebida— a demanda de manutenção em si, comorigem = 'manutenção_programada',projeto_original_ide o dossiê.demanda.manutenção_gerada— payload:demanda_id(nova),projeto_original_id,categoria,localizacao,tipo_manutencao,intervalo_programado,prazo_toleranciaeciclo_numero.manutenção.ciclo_encerrado— quando o projeto atinge o fim da vida útil programada ou o último ciclo previsto.
Estado próprio
- Projetos monitorados:
projeto_id, categoria,localizacao, parâmetros de manutenção (intervalo, tipo, prazo de tolerância), próximo ciclo agendado. - Histórico de manutenções por projeto: data, demanda gerada, status, conselheiro responsável.
Lógica
demanda.concluída recebido→ verifica se a demanda contém plano_manutencao→ se não contém: ignora→ se contém: registra no estado próprio com próximo ciclo = data_conclusão + intervalo
varredura periódica (CronJob de polling):→ seleciona os projetos com proximo_ciclo <= NOW()→ gera nova demanda com categoria e localizacao herdadas do projeto original→ publica demanda.recebida e demanda.manutenção_gerada→ recalcula próximo ciclo (data_atual + intervalo)→ se próximo ciclo excede a vida útil programada: publica manutenção.ciclo_encerradoTécnicas e referências de implementação
@nestjs/schedule(ScheduleModule + CronJob), com varredura periódica em vez de agendamento dinâmico por projeto.- O plano de manutenção é um campo opcional no evento
demanda.concluída:plano_manutencao: { intervalo_dias, tipo, prazo_tolerancia_dias, vida_util_dias } | null. - A demanda gerada reutiliza o pipeline existente: é uma
demanda.recebidacomo qualquer outra, comorigem = 'manutenção_programada'eprojeto_original_id.
Fase: 2
Critério de saída
O sistema gera automaticamente demandas de manutenção nos intervalos programados. Cada manutenção tem rastro vinculado ao projeto original. Projetos sem manutenção acumulam tempo de inação visível no backlog.
D-9 — Validação de Vínculo
Seção intitulada “D-9 — Validação de Vínculo”Contexto e responsabilidade
Verifica se o cidadão tem vínculo legítimo com a unidade cívica em que atua. Vínculo é moradia, emprego ou outro vínculo documentado. O resultado é um status binário: válido ou inválido. Nada mais é armazenado.
Não armazena dados pessoais além do mínimo. Não decide sobre o conteúdo das demandas. Não bloqueia participação — sinaliza para outras colônias o status do vínculo.
Eventos consumidos
cidadão.solicitou_validação_vínculovalidação.documento_submetidovalidação.social_concluída(resultado de validação por pares)
Eventos produzidos
vínculo.validado— payload:cidadao_id,unidade_civica_id,status(valido/invalido/provisorio),metodo_validacao,data_validadeehash_evidencia(hash do documento, sem o documento em si).validação.social_solicitada— aciona sorteio de validadores pares para confirmação presencial.
Estado próprio
Status de vínculo por cidadao_id + unidade_civica_id. Validade com data de expiração. Hash da evidência (não o documento).
Métodos de validação (em ordem de prioridade)
1. Documental automático → título de eleitor, comprovante de residência, contracheque → IA extrai campos relevantes, valida formato e consistência → cidadão mantém o documento, sistema guarda apenas o hash
2. Validação social por pares → sorteio de N cidadãos com vínculo já validado na mesma UC → validadores confirmam que conhecem o cidadão ou verificam presença → maioria qualificada (2/3) define resultado
3. Presença verificada → cidadão realiza ação geolocada dentro do território da UC → múltiplas presenças em dias distintos consolidam o vínculo → GPS + timestamp do dispositivo como evidênciaLógica
cidadão solicita validação de vínculo em UC X→ seleciona método preferido→ se documental: → IA processa documento, extrai endereço/vínculo → valida consistência dos campos extraídos → calcula hash do documento original → se confiança suficiente: publica vínculo.validado(provisório) → agenda revisão por amostragem (N% dos vínculos provisórios passam por revisão humana)→ se social: → sorteia N validadores elegíveis na UC X → publica validação.social_solicitada → aguarda resultado → se 2/3 confirmam: publica vínculo.validado(válido)→ define data_validade (parametrizável, referência: 24 meses)Privacidade por design
O sistema registra apenas: status, método, data/validade e hash da evidência. Não armazena o documento. Não mantém cópia do comprovante. O hash permite verificar que uma evidência foi processada sem expor seu conteúdo. Dados pessoais além do mínimo estritamente necessário não entram no sistema.
Técnicas e referências de implementação
- OCR para extração de campos de documentos: Tesseract (open source) com modelos pt-BR, ou AWS Textract / Google Document AI como referências cloud.
- Validação de consistência: regex + heurísticas para campos de endereço, CEP, datas.
- Hash de evidência: SHA-256 do arquivo original antes de qualquer processamento. O arquivo é descartado após hash calculado e campos extraídos.
- Revalidação periódica: vínculo expira. Cidadão recebe notificação antes da expiração para renovar.
Critério de saída
Todo cidadão com vínculo válido tem status registrado com data de validade, método e hash de evidência. Nenhum dado pessoal além do mínimo está armazenado. O status é consultável por outras colônias sem acesso aos dados de validação.
D-10 — Votação
Seção intitulada “D-10 — Votação”Contexto e responsabilidade
Implementa os mecanismos de votação do sistema: abertura e fechamento de rodadas, controle de quórum, registro de resultado com dissenso documentado. A votação é mecanismo pontual de legitimação, não o centro do sistema.
Não decide o que vai a voto. Não decide o resultado além do apurado. Não interfere no ranking nem na execução diretamente — publica o resultado e outras colônias reagem.
Tipos de votação suportados
priorização → re-ranking de demandas dentro de um nívelvalidação → confirmação de que uma agenda pode avançarcontestação → sinalização de revisão ou interrupçãoajuste_parâmetro → revisão de pesos e regras do sistemalegislativa → deliberação sobre normas (escopo regional/nacional)Eventos consumidos
votação.aberta(publicado pelo sistema de parametrização ou por iniciativa da UC)voto.submetidovotação.prazo_encerrado
Eventos produzidos
votação.resultado_publicado— payload:votacao_id, tipo, resultado_aprovado (bool), contagem, quórum_atingido, dissenso registrado (contagem dos votos vencidos), versão dos parâmetros vigentes.votação.quórum_não_atingido— encerra rodada sem resultado vinculante.
Estado próprio
Rodadas de votação com status (aberta/encerrada). Votos por cidadao_id e votacao_id (sem expor voto individual — apenas se participou e o resultado agregado). Histórico de resultados.
Lógica de apuração
votação.prazo_encerrado recebido→ conta votos por opção→ verifica quórum mínimo (parametrizável por tipo de votação)→ se quórum não atingido: publica votação.quórum_não_atingido→ se quórum atingido: → calcula resultado (maioria simples, maioria qualificada — por tipo) → registra dissenso (contagem dos votos na(s) opção(ões) vencida(s)) → publica votação.resultado_publicadoPrivacidade do voto
O sistema registra que cidadao_id participou da votação (para controle de quórum e prevenção de duplo voto), mas não expõe qual opção escolheu. O resultado publicado é sempre agregado. O dissenso é registrado como contagem, nunca como lista de quem votou no quê.
Técnicas e referências de implementação
- Prevenção de duplo voto: bloom filter ou conjunto de
cidadao_idque já votaram, porvotacao_id. Não expõe a lista. - Quórum parametrizável: valor mínimo de participantes ou percentual da UC. Diferente por tipo de votação.
- Votação assíncrona: cidadão pode votar a qualquer momento dentro da janela. Sem necessidade de presença simultânea.
- Auditabilidade: o resultado agregado, a contagem por opção e o quórum são públicos. A lista de participantes (sem voto) também é pública para verificação de quórum.
Critério de saída
Toda rodada encerrada tem resultado publicado com contagem, quórum, dissenso e versão dos parâmetros vigentes. Nenhum voto individual é exposto.
D-11 — Anti-fraude e Confiabilidade
Seção intitulada “D-11 — Anti-fraude e Confiabilidade”Contexto e responsabilidade
Monitora padrões anômalos no comportamento de inserção e validação de demandas. Não pune automaticamente. Sinaliza. A decisão de investigar ou atuar é sempre humana.
Não bloqueia demandas por conta própria. Não acessa dados de outras colônias diretamente — consome eventos do barramento.
Eventos consumidos
demanda.recebida(monitora padrões de inserção)validação.social_concluída(monitora padrões de co-validação)cidadão.dispositivo_registrado(detecta múltiplas identidades no mesmo dispositivo)
Eventos produzidos
anomalia.detectada— payload:tipo_anomalia, entidades envolvidas, score de suspeição, evidências (padrões detectados),ação_recomendada(sempre humana).demanda.score_validade_atualizado— score público de confiabilidade de cada demanda.
Estado próprio
Score de validade por demanda. Histórico de padrões por cidadao_id. Grafo de co-validações.
Tipos de anomalia monitorados (Fase 2)
burst_inserção → N demandas do mesmo cidadão em janela curtaco_validação seletiva → contas novas validando apenas contas novasmúltiplas identidades → mesmo dispositivo com múltiplos cidadão_iddemandas_clonadas → texto muito similar enviado em massaLógica de detecção de burst
para cada demanda.recebida de cidadão_id X: → conta demandas de X na janela de tempo T (referência: 1 hora) → se count > limiar_N: incrementa score de suspeição de X → se score > limiar_alerta: publica anomalia.detectada(burst_inserção) → demandas de X entram em status "revisão_pendente" até score normalizarLógica de grafo de co-validações
para cada validação.social_concluída: → registra aresta (validador → validado) no grafo → calcula métricas do grafo por janela de tempo: → densidade de conexões entre contas novas → componentes fortemente conectados com baixa diversidade territorial → ratio validações_recebidas / validações_dadas por conta → se padrão suspeito detectado: publica anomalia.detectada(co_validação seletiva)Score de validade da demanda
score_validade = f( idade_da_conta_do_criador, histórico_de_criação_do_criador, número_de_validações_recebidas, diversidade_dos_validadores, ausência_de_anomalias_associadas)Score é público e aparece na timeline da demanda. Não é eliminatório automaticamente — é sinalização.
Técnicas e referências de implementação
- Grafo de co-validações: Neo4j ou implementação em memória com NetworkX (Python) para MVP. Algoritmos: PageRank para detectar validadores centrais, detecção de comunidades (Louvain ou Label Propagation).
- Séries temporais de inserção: sliding window counter por
cidadao_id. Redis com estruturas de janela deslizante. - Fingerprint de dispositivo: hash de atributos do dispositivo (user-agent, resolução, timezone). Não identifica o usuário, apenas detecta reuso do mesmo dispositivo.
- Transparência radical como dissuasão: todo histórico de inserção e validação é público. A exposição pública do comportamento é o principal mecanismo de dissuasão — mais eficaz que bloqueio automatizado.
Critério de saída
Demandas com padrão suspeito têm score de validade baixo visível na timeline. Anomalias detectadas geram alerta para revisão humana, não bloqueio automático.
D-13 — Classificação de Risco
Seção intitulada “D-13 — Classificação de Risco”Contexto e responsabilidade
Adiciona ao processamento de demandas uma camada de avaliação de urgência, impacto potencial e criticidade territorial. Demandas de risco elevado recebem peso adicional no ranking e podem acionar notificações específicas.
Não define a prioridade final — complementa o ranking com um fator de urgência quando parâmetros públicos indicam criticidade.
Eventos consumidos
demanda.categorizadademanda.georreferenciada
Eventos produzidos
demanda.risco_classificado— payload:demanda_id,score_urgencia,score_impacto,score_criticidade_territorial,nivel_risco(baixo/médio/alto/crítico), fatores que contribuíram.
Estado próprio
Score de risco por demanda com versão dos parâmetros usados no cálculo.
Dimensões de risco
urgência → há risco imediato à saúde ou segurança? (ex: esgoto a céu aberto, estrutura em colapso, ausência de água)
impacto potencial → quantas pessoas são afetadas? (estimado pela densidade populacional da UC + abrangência territorial)
criticidade_territorial → a UC já tem demandas críticas não resolvidas no mesmo nível? (acumular risco não resolvido aumenta criticidade das novas)Lógica
consome demanda.categorizada + demanda.georreferenciada→ recupera parâmetros de risco por categoria→ calcula score_urgência com base em palavras-chave de risco + categoria→ estima população afetada pela área territorial da UC→ verifica histórico de demandas críticas não resolvidas na mesma UC/categoria→ calcula score composto→ classifica em nível de risco→ publica demanda.risco_classificado→ se nível crítico: aciona notificação para conselheiros e gestores da UCTécnicas e referências de implementação
- Detecção de urgência por texto: dicionário de termos de risco por categoria + score de presença. Complementado por classificador de urgência treinável.
- Estimativa de população: dados do IBGE por setor censitário. Cruzamento geoespacial com a área da demanda.
- Criticidade acumulada: série temporal de demandas críticas não resolvidas por UC e categoria. Integra com o histórico da D-7 transparência.
Critério de saída
Toda demanda categorizada tem score de risco calculado. Demandas críticas geram notificação imediata. O nível de risco é visível na timeline pública.
D-14 — Agregação Multinível
Seção intitulada “D-14 — Agregação Multinível”Contexto e responsabilidade
Integra os dados entre os níveis de unidade cívica. Demandas que excedem a capacidade do nível local escalam com contexto completo para o nível superior. Produz visões agregadas sem perder o rastro das demandas individuais.
Não decide quais demandas escalam — aplica critérios parametrizados de capacidade por nível.
Eventos consumidos
demanda.ranqueada(monitora acúmulo por nível de UC)ranking.atualizado(reavaliação do acúmulo quando o ranking de uma UC muda de forma significativa)agenda.item_disponível(monitora fila sem conselheiros disponíveis por período)conselheiro.ciclo_concluído(atualiza capacidade disponível por UC)
Eventos produzidos
demanda.escalada— payload:demanda_id,unidade_civica_origem,unidade_civica_destino,motivo_escalonamento, contexto completo da demanda.agregado.municipal_atualizado— visão consolidada das demandas de todos os bairros de um município.agregado.regional_atualizado— visão consolidada de múltiplos municípios.
Estado próprio
Visões agregadas por nível com histórico temporal. Rastro de escalonamentos por demanda_id.
Critérios de escalonamento
capacidade_técnica → demanda requer expertise ou recursos indisponíveis no nível atualcapacidade_financeira → custo estimado excede orçamento disponível no nível atualabrangência_territorial → impacto ultrapassa os limites da UC atualfila_sem_conselheiro → demanda sem conselheiro disponível por período > limiar parametrizadoLógica
para demanda em unidade_cívica X de nível N: → avalia critérios de escalonamento → se algum critério atingido: → identifica UC de nível N+1 responsável pelo território de X → empacota contexto completo (histórico, validações, status, evidências) → publica demanda.escalada para UC nível N+1 → mantém referência na UC original (visibilidade bidirecional) → atualiza agregados dos níveis superioresTécnicas e referências de implementação
- Hierarquia territorial: estrutura de árvore com UC de cada nível contendo referências às UCs filhas. Consultas de nível N+1 são sempre eficientes.
- Agregados pré-computados: atualizados por evento, não calculados on-demand. Redis ou materialized views no PostgreSQL.
- Bidirecionalidade: a UC original mantém visibilidade da demanda escalada. O cidadão que a registrou pode acompanhar pela timeline mesmo após o escalonamento.
Critério de saída
Demandas escaladas chegam ao nível superior com contexto completo e rastreável. Visões agregadas por município e região estão disponíveis em tempo próximo ao real.
D-15 — Pesquisa e Exportação de Dados
Seção intitulada “D-15 — Pesquisa e Exportação de Dados”Contexto e responsabilidade
Expõe os dados do sistema para uso acadêmico, jornalístico e de auditoria externa. Dados anonimizados, agregados, com schema documentado e versionado.
Não expõe dados pessoais. Não decide o que é público — aplica as regras de privacidade definidas nos parâmetros do sistema.
Eventos consumidos
ranking.atualizado,agenda.gerada,votação.resultado_publicadoe outros eventos de estado do sistema.
Eventos produzidos
dataset.exportado— publicado quando um novo snapshot de dataset é gerado.
Estado próprio
Snapshots versionados de datasets por data e versão de schema.
Datasets disponíveis (referência)
demandas_anonimizadas → categoria, nível, UC, status, timestamps (sem cidadão_id)rankings_históricos → score, posição, versão dos parâmetros — por UC e dataagenda_histórica → itens, status de conclusão, tempo médio por categoriaconselheiros_histórico → ciclos (sem identificação pessoal), tipos de demanda, tempovotações → resultados, quórum, tipo, UCcobertura_territorial → índice de cobertura por UC por períodoLógica
publicação periódica (ex: diária ou semanal): → coleta estado atual das projeções de leitura → aplica regras de anonimização (k-anonimidade mínima por agregado) → gera arquivo em formato aberto (CSV, Parquet, JSON Lines) → calcula hash do arquivo → publica em repositório público com versão e hash → publica dataset.exportadoTécnicas e referências de implementação
- Formatos: CSV para acessibilidade, Parquet para análise em grande escala, JSON Lines para streaming.
- k-anonimidade: grupos com menos de k registros são suprimidos ou generalizados (ex: UC com poucas demandas tem dados agrupados no nível superior).
- Versionamento: nomenclatura por data + hash. Ex:
demandas_2026-03-14_sha256-abc123.parquet. - Repositório público: GitHub Releases ou equivalente para datasets pequenos. IPFS ou sistema de armazenamento distribuído para escala.
Critério de saída
Datasets públicos disponíveis para download em formato aberto, com schema documentado, versionados por data. Nenhum dado pessoal exposto.
D-16 — Integridade Criptográfica
Seção intitulada “D-16 — Integridade Criptográfica”Contexto e responsabilidade
Implementa o encadeamento de hashes sobre os eventos do barramento. Qualquer alteração retroativa no histórico de eventos se torna detectável por verificação independente, sem depender da infraestrutura do sistema.
Não processa conteúdo de negócio. Não interfere no fluxo de eventos. Apenas registra e publica checkpoints verificáveis.
Eventos consumidos
- Todos os eventos do barramento (apenas para fins de hashing — não processa payload de negócio).
Eventos produzidos
hash.checkpoint_publicado— payload:bloco_id, hash do bloco atual, hash do bloco anterior (encadeamento), número de eventos no bloco, timestamp, hash raiz de Merkle dos eventos do bloco.
Estado próprio
Cadeia de checkpoints com hash encadeado. Último hash conhecido para continuação da cadeia.
Lógica
para cada N eventos processados (ou a cada intervalo de tempo): → coleta os N eventos em ordem de sequence number → calcula hash de cada evento (SHA-256 do payload serializado) → constrói Merkle tree com os N hashes → calcula hash do bloco = SHA-256(hash_raiz_merkle + hash_bloco_anterior + timestamp) → persiste bloco no estado próprio → publica hash.checkpoint_publicadoVerificação independente
Qualquer pessoa pode, dado o histórico de eventos do barramento e a cadeia de checkpoints publicados:
- Recalcular o hash de cada evento.
- Reconstruir a Merkle tree de cada bloco.
- Verificar se o hash do bloco confere com o publicado.
- Verificar se o encadeamento é contínuo (hash anterior de cada bloco aponta para o bloco anterior).
Qualquer alteração retroativa quebra a cadeia a partir do ponto modificado.
Publicação de checkpoints
Os checkpoints são publicados em repositório externo ao sistema (ex: GitHub, IPFS, sistema de notarização pública). Isso garante que mesmo que o sistema seja comprometido, os checkpoints históricos sejam imutáveis em repositório independente.
Técnicas e referências de implementação
- Hash: SHA-256. Padrão, amplamente auditável.
- Merkle tree: implementação direta ou biblioteca. Referência: bitcoin-merkle-tree pattern.
- Notarização externa: OpenTimestamps para ancorar checkpoints em blockchain pública (Bitcoin) sem custo por transação.
- Frequência dos blocos: parâmetro configurável. Referência: a cada 1000 eventos ou a cada hora, o que vier primeiro.
Critério de saída
A cadeia de checkpoints é verificável de forma independente. Qualquer alteração retroativa é detectável. Checkpoints publicados em repositório externo ao sistema.
D-17 — Controle de Mandato e Progressão
Seção intitulada “D-17 — Controle de Mandato e Progressão”Contexto e responsabilidade
Registra o histórico de atuação de cada conselheiro, aplica critérios de elegibilidade para progressão entre níveis e bloqueia reentrada indevida.
Não faz o sorteio. A D-6a sorteia; esta colônia diz quem pode ou não participar do sorteio.
Eventos consumidos
conselheiro.ciclo_concluídoconselheiro.avaliação_registradaconselheiro.sorteado(para registrar início de ciclo)capacitação.concluída
Eventos produzidos
conselheiro.elegibilidade_atualizada— publicado sempre que o status de elegibilidade muda.progressão.habilitada— conselheiro completou os requisitos para sortear no nível seguinte.
Estado próprio
Histórico de ciclos por conselheiro_id: nível, unidade cívica, demandas acompanhadas, avaliações, capacitações concluídas. Status de elegibilidade atual por nível.
Critérios de progressão
para nível N+1: → concluiu ao menos 1 ciclo completo no nível N → ciclo concluído = cargo do início ao fim + ao menos 1 demanda acompanhada + sem registro negativo pendente → manifestou interesse no nível N+1 → completou cursos obrigatórios para o nível N+1 → passou em prova de habilitação (quando exigida) → está adimplente com o sistemaLógica
conselheiro.ciclo_concluído recebido→ registra ciclo no histórico→ verifica se todos os critérios de progressão para nível N+1 estão atendidos→ se sim: publica progressão.habilitada→ atualiza elegibilidade para sorteios futuros→ publica conselheiro.elegibilidade_atualizadaBloqueio de reentrada indevida
tentativa de sorteio no nível N sem ciclo N-1 concluído → bloqueada, notificação ao candidatotentativa de sorteio com registro negativo pendente → colocada em fila de revisãoconselheiro com múltiplas recusas de atribuição → elegibilidade suspensa temporariamenteTécnicas e referências de implementação
- Máquina de estados por conselheiro: estados possíveis por nível (não_elegível, elegível, em_ciclo, ciclo_concluído, progressão_habilitada, suspenso). Transições geradas por eventos.
- Histórico imutável: cada ciclo é um registro append-only. Nada é apagado ou alterado retroativamente.
- Auditabilidade pública: o histórico de ciclos é público no nível de “ciclos concluídos por nível” sem expor dados pessoais do conselheiro além do necessário.
Critério de saída
A elegibilidade de qualquer conselheiro para qualquer nível é calculável a partir do histórico de eventos. Nenhuma reentrada indevida é possível sem que o critério de ciclo anterior esteja registrado.
Fase 3 — Consolidação Institucional
Seção intitulada “Fase 3 — Consolidação Institucional”Objetivo: sistema resistente a manipulação e preparado para pressão institucional de longo prazo. Começa após ciclos completos em escala regional e primeiras tentativas reais de captura respondidas.
D-18 — Simulação de Cenário
Seção intitulada “D-18 — Simulação de Cenário”Contexto e responsabilidade
Permite projetar o efeito de alterações nos parâmetros de priorização antes de aplicá-las ao sistema em produção. Opera sobre cópia versionada do estado atual. Não altera nenhum dado de produção.
Eventos consumidos
simulação.solicitada(por comitê técnico ou pesquisador)simulação.parâmetros_alternativos_submetidos
Eventos produzidos
simulação.resultado_publicado— payload:simulacao_id, parâmetros usados, ranking resultante por UC, diferença em relação ao ranking atual, metodologia.
Estado próprio
Snapshots de simulações com parâmetros e resultados. Histórico de simulações realizadas.
Lógica
simulação.solicitada recebida→ cria cópia do estado atual do ranking e parâmetros→ aplica parâmetros alternativos propostos sobre os dados históricos→ recalcula ranking para cada UC com os novos parâmetros→ calcula delta: quais demandas subiriam, quais desceriam, em quantas posições→ gera relatório comparativo→ publica simulação.resultado_publicado (sempre com metodologia e parâmetros usados)Técnicas e referências de implementação
- Análise de sensibilidade: variação de cada parâmetro ±N% e comparação do efeito no ranking. Identifica quais parâmetros têm maior influência no resultado.
- Sandbox de dados: banco de leitura separado para simulações. Jamais conectado ao barramento de produção.
- Visualização comparativa: heatmap de posições antes/depois por UC. Útil para comitês técnicos avaliarem impacto territorial de mudanças de parâmetro.
Critério de saída
Qualquer proposta de mudança de parâmetro acompanha simulação com resultado publicado. O efeito da mudança é quantificado antes de qualquer votação.
D-19 — Governança de Parâmetros
Seção intitulada “D-19 — Governança de Parâmetros”Contexto e responsabilidade
Formaliza o ciclo completo de revisão de parâmetros: proposta documentada, simulação de impacto, votação em camadas por perfil, publicação do resultado com dissenso, versionamento da mudança.
Nenhum parâmetro muda sem que o histórico da decisão seja público e rastreável.
Eventos consumidos
parâmetro.proposta_submetidasimulação.resultado_publicado(requisito para avançar no ciclo)votação.resultado_publicado(cada camada de votação)parâmetro.aprovado(todas as camadas concluídas)
Eventos produzidos
parâmetros.atualizados— payload: novo conjunto de parâmetros, versão, histórico da decisão (proposta, simulações, resultados de votação por camada, dissenso).
Estado próprio
Catálogo de versões de parâmetros com histórico completo de cada mudança.
Fluxo do ciclo de revisão
1. proposta documentada submetida por comitê técnico2. simulação obrigatória de impacto (D-18)3. votação em 4 camadas: → pesquisadores: método → técnicos (secretarias, autarquias): aplicabilidade → cidadãos: peso relativo percebido → conselhos de UC: ajuste local4. resultado de cada camada registrado com dissenso5. parâmetro aprovado entra em vigor com nova versão6. parâmetros.atualizados publicado no barramento→ colônia de ranking recalcula scores com novos parâmetrosCritério de saída
Qualquer versão de parâmetros é rastreável até a proposta que a originou, com simulações e resultados de votação por camada preservados. A fórmula de priorização não muda silenciosamente.
D-20 — Anti-abuso e Resistência a Manipulação Coordenada
Seção intitulada “D-20 — Anti-abuso e Resistência a Manipulação Coordenada”Contexto e responsabilidade
Expande os mecanismos da Fase 2 (D-11) com detecção de padrões mais sofisticados: coordenação entre grupos geograficamente dispersos, uso de identidades válidas em comportamento coordenado, inserção gradual projetada para passar pelos filtros de burst.
Não pune automaticamente. Qualquer padrão detectado gera alerta público. A decisão de investigar é humana.
Eventos consumidos
demanda.recebida,validação.social_concluída,voto.submetido— todos com metadados de contexto.anomalia.detectada(do D-11; esta colônia consome e correlaciona anomalias já detectadas).
Eventos produzidos
manipulação.padrão_detectado— payload: tipo de padrão, entidades envolvidas, evidências (séries temporais, grafos de correlação), nível de confiança.
Estado próprio
Grafos de co-validação e co-inserção expandidos. Séries temporais de comportamento por cidadao_id. Histórico de padrões detectados.
Padrões sofisticados monitorados
coordenação_dispersa → cidadãos em UCs distintas inserindo demandas similares em horários correlacionados (sugere organização central)
identidades_válidas_coordenadas → cidadãos com histórico limpo exibindo comportamento sincronizado em janela curta (voto/validação)
inserção_gradual → volume de inserção abaixo do limiar de burst, mas com crescimento consistente e conteúdo muito similar
captura_de_parâmetro → concentração de participação de um grupo específico nas votações de ajuste de parâmetroLógica de detecção de coordenação dispersa
para cada janela de tempo W: → agrupa demandas com embedding similar (cosine > 0.9) → verifica distribuição geográfica das UCs de origem → calcula correlação temporal das inserções → se alta similaridade + dispersão geográfica + correlação temporal elevada: → publica manipulação.padrão_detectado(coordenação_dispersa)Técnicas e referências de implementação
- Análise de grafos: algoritmos de detecção de comunidades (Louvain, Label Propagation). Detecção de comportamento coordenado: Coordinated Inauthentic Behavior (CIB) detection — técnicas usadas em análise de desinformação em redes sociais.
- Séries temporais: DTW (Dynamic Time Warping) para detectar padrões temporais similares entre grupos distintos.
- Cross-correlação de embeddings + tempo: combina similaridade semântica com correlação temporal para detectar campanhas coordenadas.
- Alerta público: qualquer padrão detectado é publicado com evidências. Não há detecção silenciosa.
Critério de saída
Padrões de manipulação coordenada são detectados e alertados publicamente antes de afetarem o ranking. A decisão de ação é sempre humana e rastreável.
D-21 — Monitoramento Executivo
Seção intitulada “D-21 — Monitoramento Executivo”Contexto e responsabilidade
Produz visões consolidadas do desempenho dos ministérios e secretarias responsáveis pela execução das agendas. Compara prazos prometidos com realizados, rastreia desvios de escopo e custo, agrega indicadores por categoria.
Eventos consumidos
conselheiro.atualização_publicada(contém atualizações de andamento da execução)agenda.item_concluídoministério.plano_submetido(custo estimado, prazo, cronograma)
Eventos produzidos
desempenho.executivo_atualizado— payload:ministerio_id, indicadores de desempenho por categoria, desvios identificados.
Estado próprio
Histórico de desempenho por ministério/secretaria e categoria de demanda.
Indicadores produzidos
prazo_realizado vs. prometido → por agenda, por categoria, por executordesvio_de_custo → custo realizado vs. estimadotaxa_de_conclusão_no_prazo → % agendas encerradas dentro do prazogargalos_recorrentes_por_executor → tipos de entrave mais frequentes por ministériovelocidade_de_resposta → tempo entre protocolo e primeira resposta do executivoTécnicas e referências de implementação
- Painel público: dashboard com filtros por período, ministério, categoria de demanda e UC. Todas as métricas com fonte rastreável no histórico de eventos.
- Alertas de desvio: quando prazo prometido é ultrapassado sem atualização, alerta público é gerado automaticamente.
Critério de saída
O painel de desempenho executivo é público. Qualquer comparação entre prazo prometido e realizado é rastreável até o evento que gerou cada dado.
D-22 — Projeções Independentes
Seção intitulada “D-22 — Projeções Independentes”Contexto e responsabilidade
Módulo isolado que processa o histórico de eventos do sistema para gerar indicadores derivados: tendências de demanda por categoria, velocidade de execução, padrões de gargalo recorrente. Opera como leitura independente. Não interfere em nenhum fluxo de produção.
As projeções são publicadas com metodologia documentada e distinguidas com clareza de dados factuais.
Eventos consumidos
- Replay do histórico completo do barramento (acesso somente leitura ao log de eventos).
Eventos produzidos
projeção.publicada— payload: tipo de projeção, metodologia, período analisado, resultado, intervalo de confiança, hash do dataset usado.
Estado próprio
Histórico de projeções com versão do dataset e metodologia.
Tipos de projeções
tendência_de_demanda_por_categoria → crescimento/decrescimento de volume por categoria/UCvelocidade_de_execução_por_tipo → tempo médio histórico por tipo de agendagargalos_estruturais → padrões de entrave recorrentes por executor/territóriocobertura_territorial_projetada → estimativa de quando uma UC atingirá cobertura mínimaimpacto_de_mudança_de_parâmetro → projeção do efeito de parâmetros alternativos (via simulação)Transparência das projeções
Toda projeção é publicada com:
- Metodologia completa (qual algoritmo, quais dados, qual período).
- Dataset usado (referência ao snapshot versionado do D-15).
- Intervalo de confiança ou margem de erro.
- Distinção explícita: “isso é projeção baseada em dados históricos, não é dado factual”.
Pesquisadores externos podem replicar qualquer projeção a partir dos datasets públicos.
Critério de saída
Projeções publicadas são replicáveis externamente. A distinção entre dado factual e projeção é sempre explícita. Nenhuma projeção interfere no fluxo de produção.
D-23 — Snapshot Público Versionado
Seção intitulada “D-23 — Snapshot Público Versionado”Contexto e responsabilidade
Gera periodicamente um estado completo e auditável do sistema: ranking atual, parâmetros vigentes, agenda ativa, histórico de mandatos, métricas de cobertura territorial. Assinado criptograficamente e publicado em repositório aberto.
Funciona como evidência imutável do estado do sistema em qualquer momento — útil para auditorias externas, pesquisa longitudinal e disputas sobre o histórico.
Eventos consumidos
snapshot.geração_solicitada(publicado em schedule periódico)
Eventos produzidos
snapshot.publicado— payload:snapshot_id, data de geração, hash do arquivo, URL do repositório externo.
Estado próprio
Histórico de snapshots com hash e URL de acesso.
Conteúdo do snapshot
ranking_atual → posição e score de cada demanda ativa por UC (anonimizado)parâmetros_vigentes → versão e valores de todos os parâmetros ativosagenda_ativa → backlog atual com status de cada itemhistórico_de_mandatos → ciclos concluídos por nível (sem identificação pessoal)cobertura_territorial → índice de cobertura por UCmétricas_de_sistema → volume de eventos, taxa de conclusão, tempo médio por categoriaLógica
snapshot.geração_solicitada recebido→ coleta estado atual de todas as projeções de leitura→ aplica anonimização (consistente com o D-15)→ serializa em formato aberto (JSON + Parquet)→ calcula hash do conjunto de arquivos→ assina criptograficamente com chave da vanguarda do software→ publica no repositório externo (GitHub, IPFS ou equivalente)→ registra no estado próprio→ publica snapshot.publicadoCritério de saída
Snapshots gerados periodicamente, assinados e publicados em repositório externo. Verificáveis por hash independentemente da infraestrutura do sistema.
Colônias de Empresas
Seção intitulada “Colônias de Empresas”Módulos paralelos ao fluxo principal das unidades cívicas. Não interferem no ranking de demandas nem no ciclo de conselheiros. Operam sobre os dados das organizações.
Colônia E-1 — Cadastro Institucional
Seção intitulada “Colônia E-1 — Cadastro Institucional”Fase 1 — MVP
Contexto e responsabilidade
Registra e mantém o perfil de cada organização: razão social, porte, setor, localização e associação às unidades cívicas do território de atuação. É o ponto de entrada para todas as colônias de empresa. Sem registro, não há visibilidade no sistema.
No MVP, o cadastro é manual — preenchido diretamente pela empresa ou por um representante. A adesão começa pelas empresas entusiastas: pequenas e médias que querem fazer parte do modelo de transparência. Não há integração automática com bases externas de CNPJ nesta fase.
Eventos consumidos
lugar.georreferenciado— quando o lugar associado à sede ou filial da organização é resolvido pela Colônia L-2, a E-1 consome esse evento para definir a associação territorial. A localização de uma organização é dado das colônias de lugares, não da E-1.
Eventos produzidos
empresa.cadastradaempresa.associação_territorial_definida— vincula a empresa às UCs do território de operação.lugar.recebido— um por endereço de operação, comtipo_lugar = 'organizacao', publicado diretamente no barramento. Ocorrelacao_idde cada endereço volta nolugar.georreferenciadoe permite o lookup reverso.
Estado próprio
Cadastro de organizações com status (cadastrada/socializada/pendente/recusada).
Lógica de associação territorial
empresa cadastrada com endereço(s) de operação→ para cada endereço: publica lugar.recebido(tipo=organizacao) via barramento→ aguarda lugar.georreferenciado correspondente da Colônia L-2→ quando recebido: extrai unidade_civica_id e cadeia de UCs pai→ define UCs primárias (sede) e secundárias (filiais, área de impacto)→ publica empresa.associação_territorial_definidaA E-1 não chama a D-2 de demandas diretamente. O georreferenciamento de organizações passa pela L-2, que além de resolver o território enriquece a tipificação com bases de CNPJ e OSM — dado útil para o cadastro institucional.
Simplificações válidas no MVP
- Cadastro via formulário manual. Sem integração com Receita Federal ou base pública de CNPJ.
- Associação territorial: a empresa informa os endereços de operação e a L-2 resolve o georreferenciamento. Endereços sem coordenadas ou com publicação falha ficam com
status_geo = 'pendente'e são republicados pela varredura de órfãos do boot. - Porte declarado pela empresa: micro, pequena, média, grande. Sem validação cruzada com faturamento nesta fase.
Critério de saída
Toda empresa cadastrada tem associação territorial definida e visível. O cadastro é público no nível de razão social, setor e território — dados financeiros ficam nas colônias específicas.
Documento detalhado: E-1 - Cadastro Institucional.md
Colônia E-2 — Transparência Salarial e Folha
Seção intitulada “Colônia E-2 — Transparência Salarial e Folha”Fase 1 — MVP
Contexto e responsabilidade
Recebe e processa a autodeclaração da folha salarial da empresa. Aplica a razão máxima salarial parametrizada (referência: 10x). Calcula o que mudaria na folha sem aumentar o custo total.
Esta é a colônia central do MVP de empresas. Ela responde a pergunta concreta: dado o que a empresa declara, qual é a razão atual entre o menor e o maior salário, e o que seria necessário redistribuir para chegar ao parâmetro de referência? O resultado é o “achatamento simulado” — quanto o maior salário precisaria ceder e quanto isso representa no bolso de quem está na base.
Não decide sobre a empresa. Não aplica automaticamente mudanças. Produz o diagnóstico.
Eventos consumidos
empresa.cadastrada— mantém projeção local de empresas ativas (e2.empresas_projecao), via UPSERT idempotente.
Eventos produzidos
empresa.folha_submetida— publicado pela face BFF da E-2 quando a empresa submete a folha.event_id=submissao_id.empresa.diagnóstico_salarial_publicado— payload:empresa_id, menor salário, maior salário, razão atual, razão máxima parametrizada, redistribuição necessária sem aumento de custo total, custo total antes e depois.event_id=diagnostico_id.
Face BFF
A E-2 tem BFF acoplado para o formulário de folha e a leitura do diagnóstico:
POST /api/empresas/:id/folha— folha em JSON (cargos + salários, sem nomes). Autenticado por JWT.POST /api/empresas/:id/folha/csv— folha em CSV multipart (cabeçalhocargo,salario[,jornada], delimitador vírgula ou ponto-e-vírgula, formatos brasileiros).- A submissão é idempotente por hash de conteúdo (duplicata retorna 409 permanente), sem janela de tempo.
- Os dois eventos (
folha_submetidaediagnóstico_salarial_publicado) são publicados no mesmo fluxo síncrono do controller, com retry inline.
Estado próprio
Diagnóstico salarial por empresa com versão dos parâmetros usados. Submissões brutas preservadas com idempotencia_hash e payload_diagnostico para auditoria.
Lógica
empresa submete folha via POST (JSON ou CSV)→ valida cargos e salários (sem nomes), idempotência por hash→ publica empresa.folha_submetida→ recupera lista de salários declarados→ calcula razão maior/menor→ se razão > parâmetro_máximo (10x no MVP): → calcula redistribuição interna por compressão logarítmica (ln → comprime → exp, com aritmética decimal): → comprime os gaps entre cargos proporcionalmente → preserva a ordem relativa e mantém o custo total da folha constante→ gera diagnóstico com before/after→ publica empresa.diagnóstico_salarial_publicadoTransparência do diagnóstico
O diagnóstico é público no nível de agregados: “razão atual foi X, parâmetro é Y, redistribuição equivale a Z% do total da folha”. Salários individuais não são expostos publicamente — apenas internamente para o conselho da empresa e auditores autorizados.
Simplificações válidas no MVP
- Folha declarada via duas rotas: JSON estruturado com campos por cargo e salário, ou CSV multipart (parser interno;
papaparse/csv-parsenão constam nos pacotes permitidos). Sem OCR, sem extração automática de holerite. - A lista de salários é enviada sem nomes — apenas cargo e valor. A E-2 não armazena identificação de colaborador.
- Cálculo da redistribuição é determinístico, por compressão logarítmica: os gaps entre cargos são comprimidos proporcionalmente, sem teto rígido, e o custo total da folha permanece constante ao centavo.
- Parâmetro inicial fixo em configuração (razão 10x). Sem sistema de parametrização dinâmica nesta fase.
Critério de saída MVP
Empresa com folha declarada tem diagnóstico publicado com: razão atual calculada, razão parametrizada, valor total da folha antes e depois da redistribuição, e a contagem de colaboradores que cederam e que receberam. Nenhum salário individual exposto.
Documento detalhado: E-2 - Transparência Salarial e Folha.md
Colônia E-3 — Simulação Econômica
Seção intitulada “Colônia E-3 — Simulação Econômica”Fase 1 — MVP
Contexto e responsabilidade
Recebe os dados declarados pela empresa (folha, receita, excedente) e aplica os parâmetros públicos para calcular o excedente disponível para redistribuição e a projeção dos fluxos possíveis.
Nenhum cálculo é sigiloso. Metodologia pública. Qualquer pessoa pode replicar a simulação com os mesmos dados de entrada.
No MVP, a simulação opera sobre dados autodeclarados sem verificação cruzada. O valor está na visibilidade: a empresa que declara abre a caixa-preta e demonstra o que seria possível. Cada simulação publicada é um dado público — comparável com outras empresas do mesmo porte e setor, agregável para análises territoriais.
Eventos consumidos
empresa.cadastrada(mantém projeção local de empresas ativas)empresa.folha_submetida(extraitotal_colaboradorespara o cálculo do valor por trabalhador)empresa.diagnóstico_salarial_publicado(extraicusto_total_depois— folha reequilibrada — para a fórmula do excedente)empresa.balanço_submetido(gatilho principal: recebe receita, custos e referência à folha)parâmetros.atualizados(stub no MVP — recalcula simulações com novos parâmetros na Fase 2)
Face BFF
A face BFF da E-3 recebe a submissão de balanço e persiste em e3.balancos_submissoes antes de publicar empresa.balanço_submetido, com idempotência por hash de conteúdo (duplicata retorna 409 permanente). POST /api/empresas/:id/balanco responde 202 Accepted com { submissao_id, status: 'aceito' }. Submissões com evento_publicado_em nulo são republicadas na varredura do boot. Balanço sem periodo_referencia é descartado com log. A leitura pública das simulações é GET /api/empresas/:id/simulacoes, que espelha o payload do evento sem os campos internos.
Documento detalhado com justificativa completa de cada evento, contratos e algoritmos: E-3 - Simulação Econômica.md
Eventos produzidos
empresa.balanço_submetido— publicado pela face BFF no POST de balanço.event_id=submissao_id.empresa.simulação_econômica_publicada— payload:empresa_id, receita declarada, custo declarado, excedente calculado, divisão parametrizada (valores iniciais de referência: 40% caixa interno, 40% retorno ao sistema, 20% trabalhadores),total_colaboradores,valor_por_trabalhador, período de referência, identificador do diagnóstico e da folha base. Sem rateio por UC: o retorno ao sistema é um fluxo único para o fomento.
Lógica
A E-3 mantém projeções locais atualizadas por evento: → empresa.cadastrada: projeção de empresas ativas (id, razao_social, porte, setor_id, status, representante_id) → empresa.folha_submetida + empresa.diagnóstico_salarial_publicado: projeção unificada de folha (total_colaboradores + custo_total_depois)
empresa.balanço_submetido recebido→ verifica se a folha referenciada já tem diagnóstico: se não: armazena como pendente, processa quando diagnóstico chegar→ obtém custo_total_depois e total_colaboradores da projeção de folha→ calcula excedente = receita - custos operacionais - folha_reequilibrada→ aplica divisão parametrizada: → X% caixa interno (solvência e reinvestimento) → Y% retorno ao sistema (fluxo único para o fomento) → Z% distribuição igualitária entre trabalhadores→ calcula valor por trabalhador na parte de distribuição→ publica empresa.simulação_econômica_publicadaSimplificações válidas no MVP
- Balanço declarado via formulário (face BFF na própria E-3): receita bruta, custos operacionais, folha (já declarada na E-2). O excedente é calculado pela colônia — não exige DRE completo.
- Sem verificação cruzada com Receita Federal ou SPED. A declaração é pública e verificável socialmente. O próprio sistema de transparência radical é o mecanismo de pressão por veracidade.
- Parâmetros de divisão (40/40/20) fixos em configuração no MVP, como ponto de partida a calibrar. Variantes paramétricas ficam na Fase 2 com o sistema de governança de parâmetros.
- Cálculos monetários com precisão de centavos via aritmética decimal (
decimal.js), não ponto flutuante nativo. - O retorno ao sistema é um fluxo único, sem rateio por UC. A associação territorial da empresa não participa do cálculo no MVP. O cruzamento com o território entra na E-4 (Fase 2).
- Projeções locais de estado de outras colônias (
empresa.cadastrada,empresa.folha_submetida,empresa.diagnóstico_salarial_publicado) mantidas via consumo de eventos, sem consulta direta a bancos externos. - Balanços que chegam antes do diagnóstico salarial da folha referenciada são armazenados como pendentes e processados automaticamente quando o diagnóstico é publicado. Pendentes são varridos no boot e por intervalo periódico, sem depender de evento novo. Sem polling ou retry pelo usuário.
Critério de saída MVP
A simulação de qualquer empresa cadastrada é pública e replicável com os dados declarados. O resultado mostra: excedente calculado, valor do caixa interno, valor de retorno ao sistema e valor de distribuição por trabalhador. A metodologia e os parâmetros usados estão visíveis junto ao resultado.
Documento detalhado: E-3 - Simulação Econômica.md
Colônia E-4 — Impacto Territorial
Seção intitulada “Colônia E-4 — Impacto Territorial”Contexto e responsabilidade
Cruza a redistribuição simulada pela colônia econômica com as demandas mapeadas nas unidades cívicas do território de atuação da empresa. Produz uma projeção concreta do que o excedente poderia financiar.
Esta projeção não é compromisso nem garantia. É evidência quantificada do potencial de impacto.
Eventos consumidos
empresa.simulação_econômica_publicadaranking.atualizado(para saber quais são as demandas prioritárias das UCs do território)
Eventos produzidos
empresa.impacto_territorial_publicado— payload:empresa_id, UC(s) de impacto, demandas prioritárias que poderiam ser financiadas, custo estimado de cada, cobertura do excedente disponível.
Lógica
empresa.simulação_econômica_publicada recebida→ recupera UCs associadas à empresa→ recupera top-N demandas prioritárias de cada UC (do ranking)→ recupera custo estimado de cada demanda (quando disponível)→ ordena demandas por prioridade→ simula quanto do excedente que retorna ao fomento cobre cada demanda do território da empresa→ gera projeção: "com X reais de excedente, seria possível financiar as demandas A, B e C da UC Y"→ publica empresa.impacto_territorial_publicadoCritério de saída
Para cada empresa com simulação econômica publicada, existe uma projeção concreta de impacto territorial baseada nas demandas reais da UC. A projeção é pública e rastreável.
Colônia E-5 — Mapeamento de Estrutura Interna
Seção intitulada “Colônia E-5 — Mapeamento de Estrutura Interna”Contexto e responsabilidade
Processa a autodeclaração de funções por cargo: cargo formal, salário, descrição das atividades reais. Gera um mapa de cargos consistente com a estrutura declarada.
Não expõe salários individuais publicamente. O mapa derivado é público no nível de estrutura e cargo. Serve como base para onboarding replicável e para o relatório do conselho interno.
Eventos consumidos
empresa.estrutura_submetida
Eventos produzidos
empresa.mapa_estrutural_publicado— payload:empresa_id, mapa de cargos agregado (sem nomes), sobreposições detectadas, recomendações de redistribuição de função.
Lógica
empresa.estrutura_submetida recebida→ agrupa declarações por cargo formal→ compara descrições de atividades reais vs. atribuições formais do cargo→ detecta sobreposição: mesma atividade declarada por múltiplos cargos distintos→ detecta lacuna: atividade sem cargo formal associado→ gera mapa agregado de cargos com funções reais→ publica empresa.mapa_estrutural_publicadoTécnicas e referências de implementação
- Clustering semântico de descrições de atividades: embeddings + DBSCAN para agrupar atividades similares independente do cargo formal declarado.
- Comparação com CBO (Classificação Brasileira de Ocupações): validação das funções declaradas contra descrições oficiais de cargos.
Colônias de Lugares
Seção intitulada “Colônias de Lugares”Módulos paralelos ao fluxo de demandas e ao fluxo de empresas. Operam sobre a camada de realidade territorial: o que existe fisicamente no território, onde está, de que tipo é e em que quantidade.
A separação de responsabilidades em relação às colônias de empresa é deliberada: a colônia de empresa sabe o que a organização faz, quanto produz e quanto distribui. A colônia de lugar sabe onde ela está e o que existe ao redor. A localização de uma organização é dado das colônias de lugares, consumido pelas colônias de empresa via evento — nunca escrito diretamente por elas.
Fases de implementação:
- L-1 e L-2 — Fase 1: cadastro e georreferenciamento são simples e complementam o ciclo de captura desde o início. Entusiastas já podem popular o mapa de realidade territorial junto com as primeiras demandas.
- L-3 — subconjunto no MVP; Fase 2 completa: o MVP entrega a confirmação automática, a confirmação social por presença, a denúncia, a retirada pelo autor e a reativação por operador. Reincidência temporal, validação presencial sorteada e revalidação periódica ficam para a Fase 2, quando houver volume mínimo de dados.
- L-4 e L-5 — Fase 2: análise de cobertura e incubação social requerem volume mínimo de dados para funcionar com significância.
Colônia L-1 — Cadastro de Lugares
Seção intitulada “Colônia L-1 — Cadastro de Lugares”Contexto e responsabilidade
Ponto de entrada do dado de lugar no sistema. Recebe o evento lugar.recebido publicado pela D-1a (fluxo do cidadão) ou pela E-1 (endereço de organização), valida os campos mínimos obrigatórios, gera o lugar_id definitivo e persiste o dado bruto. Consome também lugar.georreferenciado da L-2 para atualizar o status do registro sem que outra colônia escreva em seu banco.
Não valida conteúdo, não georeferencia, não verifica se o lugar existe de fato. Apenas aceita, registra e publica. O dado bruto nunca é descartado.
Eventos consumidos
lugar.recebido— publicado pela D-1a (cidadão) ou pela E-1 (endereço de organização).lugar.georreferenciado— publicado pela L-2 após resolver UC e tipificação. A L-1 atualiza o próprio status do registro parageorreferenciadoao consumir este evento.
Eventos produzidos
lugar.cadastrado(1.2.0) — payload:lugar_id,tipo_lugar(residencia,organizacao,equipamento_publicooupoligono_uc),subtipo,nome, coordenadas brutas,cidadao_id, timestamp, canal de entrada,horario_funcionamento,descricao(opcional, máximo de 5000 caracteres, publicado quando informado; alimenta o painel de detalhes do lugar no mapa e a projeção da D-7, e entra na allowlist de redação como conteúdo público do lugar) ealerta_proximidade(opcional, quando detectada duplicata por proximidade).
Estado próprio (write model)
Registro de lugares com status pendente_georreferenciamento. Dado bruto preservado com referência ao lugar_id. A L-1 é a única colônia que escreve neste schema. A atualização de status ao consumir lugar.georreferenciado fecha o ciclo sem violação de isolamento.
Lógica
lugar.recebido chega→ valida campos mínimos (tipo_lugar + coordenadas)→ gera lugar_id único (UUID v4)→ deduplica preliminarmente por proximidade (< 10 metros, mesmo tipo): se detectada, inclui alerta_proximidade no payload como metadado, sem bloquear→ persiste dado bruto no estado próprio com status pendente_georreferenciamento→ publica lugar.cadastrado
lugar.georreferenciado chega→ busca registro por lugar_id→ atualiza status para georreferenciadoTécnicas e referências de implementação
- Validação de coordenadas: bounding box do território coberto. Rejeita coordenadas fora da área de operação.
- Idempotência: por
event_idna camada de barramento. Olugar_idé UUID v4 gerado pela L-1 — identidade independente do conteúdo. Submissões duplicadas do barramento (mesmoevent_id) são detectadas e ignoradas. - Deduplicação preliminar: Haversine em raio de 10 metros com pré-filtro por bounding box. Detecta lugares do mesmo tipo muito próximos e inclui o metadado
alerta_proximidadeno payload delugar.cadastrado. Não bloqueia: a L-3 decide sobre a existência de fato do lugar.
Critério de saída
Qualquer input válido de lugar gera um lugar_id rastreável e o evento lugar.cadastrado no barramento. O dado bruto original está preservado e acessível. O status é atualizado exclusivamente pela L-1 ao consumir o evento da L-2.
Documento detalhado: L-1 - Cadastro de Lugares.md
Colônia L-2 — Georreferenciamento e Tipificação
Seção intitulada “Colônia L-2 — Georreferenciamento e Tipificação”Contexto e responsabilidade
Resolve a questão territorial do lugar (a qual UC pertence) e valida a coerência da tipificação (o subtipo declarado é plausível para aquelas coordenadas e contexto). Análoga à D-2 do fluxo de demandas, com a responsabilidade adicional de enriquecer e confirmar o tipo declarado.
É esta colônia que publica lugar.georreferenciado — o evento que a Colônia E-1 (Cadastro Institucional) consome para definir a associação territorial de uma organização às suas UCs. Nenhuma colônia de empresa acessa a D-2 de demandas para isso.
Não valida se o lugar existe. Não aciona validação social. Apenas resolve geometria e tipificação.
Eventos consumidos
lugar.cadastrado
Eventos produzidos
lugar.georreferenciado— payload:lugar_id,unidade_civica_idde menor nível resolvida,nivel_minimo_resolvido,cadeia_ucs(lista de UCs pai, do menor ao maior nível),metodo_resolucao(gps,enderecoouinferencia; no MVP sempregps),confianca_geo,subtipo_declarado?,subtipo_confirmado?,confianca_tipificacao(alta,media,baixaounao_avaliada) eenriquecimento(dados adicionais de bases abertas quando disponíveis).
Estado próprio
Cache de resoluções geo por coordenada de lugar. Referências de enriquecimento por lugar_id.
Lógica
lugar.cadastrado recebido→ point-in-polygon contra base de polígonos das UCs (mesma base da D-2, Turf.js)→ resolve nível mínimo e cadeia completa de UCs pai→ calcula confianca_geo: sempre `alta` no MVP (toda coordenada chega por GPS; `media`/`baixa` variam na Fase 2 com o geocoding)→ tenta enriquecimento de tipificação (MVP: somente OSM Overpass API): → cruzamento com OpenStreetMap por coordenada e raio, com cache em memória → se OSM indisponível: degrada com graça para `nao_avaliada` e segue o fluxo→ se enriquecimento confirma o subtipo declarado: confianca_tipificacao = alta→ se enriquecimento sugere subtipo diferente: registra divergência, mantém declarado como principal→ registra resolução no cache→ publica lugar.georreferenciadoCNPJ (Receita Federal) e CNES/Inep para equipamentos públicos entram na Fase 2. No MVP, organizações são tipificadas somente pelo OSM.
Sub-colônias potenciais (se o volume escalar)
- Resolvedor territorial: point-in-polygon puro, mesmo da D-2.
- Enriquecedor de tipificação: cruzamento com OSM, CNPJ, CNES, Inep.
Técnicas e referências de implementação
- Point-in-polygon: Turf.js em aplicação (mesma stack da D-2). Sem PostGIS no MVP.
- Cache de coordenadas:
Mapem memória no MVP. Redis com TTL longo entra na Fase 2. Coordenadas de lugar mudam muito menos que demandas. - Enriquecimento OSM: Overpass API para consultas por bounding box. Cache agressivo em memória por coordenada.
- Consulta CNPJ: API pública da Receita Federal (dados.gov.br) ou base local espelhada. Busca por coordenada aproximada e razão social quando disponível.
- Bases de equipamentos públicos: CNES (saúde), Censo Escolar/Inep (educação), base de equipamentos IBGE. Todas abertas e atualizáveis periodicamente.
- Confiança composta:
confianca_geo×confianca_tipificacaogeram um score único que a L-3 usa como ponto de partida da validação.
Critério de saída
Todo lugar cadastrado tem unidade_civica_id resolvida, cadeia de UCs pai completa e tipificação com nível de confiança registrado. Lugares com confiança baixa são sinalizados para a L-3 com prioridade de validação.
Documento detalhado: L-2 - Georreferenciamento e Tipificação.md
Colônia L-3 — Validação e Qualidade
Seção intitulada “Colônia L-3 — Validação e Qualidade”Fase 2 no modelo completo; subconjunto social e automático no MVP
Contexto e responsabilidade
Verifica se o lugar existe de fato e se os dados estão corretos. No modelo completo, opera por múltiplos métodos em sequência de custo crescente: cruzamento automático com bases abertas, confirmação temporal por múltiplos cidadãos e validação social presencial sorteada.
O MVP implementa um subconjunto: a confirmação automática pela tipificação da L-2, a confirmação social por presença (3 confirmações de cidadãos distintos em 700 m), a denúncia com motivo em lista fechada (3 denúncias levam o lugar a disputado), a retirada pelo autor e a reativação por operador. A reincidência temporal, a validação presencial sorteada, a revalidação periódica de 24 meses e o evento lugar.validação_social_solicitada ficam para a Fase 2.
Não valida demandas. Não analisa cobertura. Só determina se um lugar é confiável o suficiente para entrar no mapa como confirmado.
Eventos consumidos
lugar.cadastrado— no MVP, cria o registro provisório com autor e coordenadas.lugar.georreferenciado— no MVP, aplica a confirmação automática quando a confiança é alta.lugar.validação_social_concluída(resultado de confirmação por cidadãos sorteados) — Fase 2.lugar.atualização_submetida(cidadão corrige dado de lugar existente) — Fase 2.
Eventos produzidos
lugar.validado— payload:lugar_id,status_confianca(provisorio/confirmado/disputado),metodo_validacao(opcional;automatico,socialouoperador),total_confirmacoes,total_denunciaseversao_dados. Publicado a cada confirmação e denúncia aceitas.lugar.validação_social_solicitada— aciona sorteio de validadores presenciais quando necessário. Fase 2.lugar.desativado— payload:lugar_idemotivo(denuncias/retirado_pelo_autor/operador). No MVP, apenas a retirada pelo autor publica.
Estado próprio
Status de confiança por lugar_id com histórico de validações e métodos usados. No MVP, o schema l3 tem quatro tabelas: status_lugares, confirmacoes, denuncias e consumer_offset. A transição grava publicacao_pendente na mesma atualização e a varredura do boot republica a saída com o event_id determinístico quando a publicação falha. O histórico de atualizações por lugar_id fica para a Fase 2.
Métodos de validação (em ordem de custo crescente)
1. Automático por enriquecimento → se confianca_geo = alta e confianca_tipificacao = alta sem divergência: status = confirmado com metodo_validacao = automatico (implementado no MVP)
2. Confirmação social por presença → 3 confirmações de cidadãos distintos, autor excluído, presença ≤ 700 m → status = confirmado com metodo_validacao = social → 3 denúncias de cidadãos distintos: status = disputado → retirada pelo autor: status = desativado → reativação por operador: status = provisorio (implementado no MVP)
3. Reincidência temporal e validação presencial sorteada → N cidadãos cadastram o mesmo lugar em janela de tempo → sorteio auditável de cidadãos com vínculo validado na UC → confirmação com foto atual + geolocalização no raio do lugar → se 2/3 confirmam: status = confirmado → se maioria nega: status = disputado → revisão manual (Fase 2)Lógica
lugar.cadastrado recebido→ registra o lugar como provisório com autor e coordenadas
lugar.georreferenciado recebido→ avalia o método 1 (enriquecimento automático)→ se confiança alta nas duas dimensões e sem divergência: publica lugar.validado(confirmado)→ senão: mantém provisório
confirmação social recebida→ valida autor, presença de 700 m e repetição→ incrementa o total; ao atingir 3, confirma com método social→ publica lugar.validado
denúncia recebida→ valida autor, presença de 700 m, motivo e repetição→ incrementa o total; ao atingir 3, disputa com método social→ publica lugar.validado
retirada do autor→ desativa e publica lugar.desativado
reativação por operador→ volta a provisório e publica lugar.validado
boot→ republica publicações pendentes de lugar.validado e lugar.desativado com o event_id determinísticoTécnicas e referências de implementação
- Agrupamento por proximidade: DBSCAN com Haversine para detectar cadastros do mesmo lugar por cidadãos distintos. Fase 2.
- Limiar de confiança automática: no MVP,
confianca_geo = altaeconfianca_tipificacao = altasem divergência. O score composto parametrizado fica para a Fase 2. - Sorteio de validadores: mesmo padrão da D-6a — seed público, Fisher-Yates, auditável. Fase 2.
- Foto de validação: hash SHA-256 + metadados EXIF (coordenadas, timestamp). Processada pela D-1c de anexos. Fase 2.
- Revalidação periódica: lugares confirmados passam por reverificação a cada 24 meses ou quando N cidadãos reportam mudança. Fase 2.
- Presença: Haversine em memória, no mesmo helper compartilhado da D-12. Sem PostGIS no MVP.
Critério de saída
Todo lugar tem status de confiança público e rastreável. Lugares provisórios ficam visíveis no mapa com marcação distinta. A taxa de lugares em status provisório por mais de 90 dias é indicador de cobertura insuficiente na UC.
Documento detalhado: L-3 - Validação e Qualidade.md
Colônia L-4 — Análise de Cobertura e Gaps
Seção intitulada “Colônia L-4 — Análise de Cobertura e Gaps”Fase 2
Contexto e responsabilidade
Cruza o mapa de lugares validados com parâmetros técnicos de cobertura mínima por tipo de organização e UC. Produz o mapa de gaps: onde falta o quê, em que quantidade, com que evidência.
Não financia, não aciona criação de organizações. Publica o gap documentado — que a Colônia L-5 consome para iniciar o ciclo de incubação.
Eventos consumidos
lugar.validado(atualiza o índice de cobertura)lugar.desativado(reduz cobertura quando um lugar some)parâmetros.atualizados(recalcula gaps quando parâmetros de cobertura mudam)demanda.ranqueada(cruza demandas recorrentes de um tipo com ausência de lugar correlato)
Eventos produzidos
cobertura.atualizada— payload:uc_id, tipo de organização, quantidade existente, quantidade mínima parametrizada, índice de cobertura (0.0–1.0), timestamp.gap.detectado— payload:gap_id,uc_id, tipo de organização faltante, quantidade faltante, parâmetro de referência usado, demandas correlatas (lista dedemanda_iddo ranking da UC de categoria relacionada),nivel_prioridade_gap, timestamp.gap.resolvido— publicado quando novo lugar validado fecha um gap existente. Payload:gap_id,lugar_idque resolveu, data de resolução.
Estado próprio
Índice de cobertura por tipo de organização e UC, com histórico temporal. Registro de gaps ativos com data de detecção, nível de prioridade e demandas correlatas. Histórico de gaps resolvidos.
Parâmetros de cobertura (referências iniciais, a calibrar)
Os parâmetros partem de estudos existentes (OMS, Ministério da Saúde, Anvisa, FNDE, IBGE) e são revisados pelos comitês técnicos de parametrização. Exemplos de referência:
farmácia → 1 a cada 5.000 habitantes (referência CFF)mercado / supermercado → 1 a cada 2.000 domicíliospadaria / panificadora → 1 a cada 3.000 habitantesUBS → 1 a cada 3.450 habitantes (referência MS / PNAB)creche pública → cobertura de 50% das crianças de 0–3 anos (meta PNE)escola fundamental → raio máximo de 1,5km em área urbana (referência FNDE)Nenhum desses valores está fixo no código. Todos são parâmetros versionados, auditáveis e recalibráveis.
Lógica de gap
lugar.validado recebido (ou parâmetros.atualizados)→ recupera todos os lugares validados da UC por tipo→ recupera parâmetro de cobertura mínima para aquele tipo na UC→ recupera população estimada da UC (IBGE — setor censitário)→ calcula cobertura_atual = contagem_lugares / meta_calculada→ atualiza cobertura.atualizada→ se cobertura_atual < 1.0: → calcula quantidade_faltante = ceil(meta - contagem_existente) → recupera demandas ativas no ranking da UC de categoria correlata (ex: ausência de farmácia + demandas 2.1, 2.2, 2.4 recorrentes) → calcula nível_prioridade_gap: → gap puro (sem demanda correlata): prioridade baixa → gap + demandas correlatas presentes: prioridade média → gap + demandas correlatas de nível 1 ou 2: prioridade alta → publica gap.detectado→ se lugar resolveu gap existente: publica gap.resolvidoTécnicas e referências de implementação
- Estimativa populacional por UC: cruzamento com setores censitários do IBGE. Atualização a cada censo ou com dados da Fase 2 de pesquisas recorrentes.
- Correlação demanda–tipo de lugar: dicionário de mapeamento (categoria_id → subtipo de lugar correlato). Parâmetro público, revisável.
- Dashboard público de cobertura: mapa de calor por UC e tipo de organização. Endpoint paginado com filtros por tipo, UC e nível de prioridade do gap.
- Histórico de gaps: cada gap tem linha do tempo pública: quando foi detectado, quais demandas estavam correlatas, quando foi resolvido e por qual lugar.
Critério de saída
O mapa de gaps de qualquer UC é público, atualizado em tempo próximo ao real, com parâmetros de referência visíveis e demandas correlatas linkadas. Qualquer cidadão ou pesquisador pode verificar por que um gap foi detectado.
Colônia L-5 — Incubação Social
Seção intitulada “Colônia L-5 — Incubação Social”Fase 2
Contexto e responsabilidade
Consome gaps detectados e demandas mapeadas para estruturar o processo de criação de novas organizações socializadas. É a colônia que converte evidência em ação: conecta o gap documentado a grupos com capacidade de operá-lo e ao caixa das unidades cívicas ou estruturas de fomento.
Não financia diretamente. Não cria a organização. Estrutura o processo, registra o ciclo e publica os eventos que ativam as colônias de empresas quando a nova organização nasce.
Consome exclusivamente o que outras colônias produzem. Não tem interface direta com o cidadão — opera sobre dados já processados.
Eventos consumidos
gap.detectado(da L-4 — gatilho principal)gap.resolvido(encerra processos de incubação associados ao gap resolvido)empresa.cadastrada(da E-1 — confirma que a organização incubada foi formalizada)parâmetros.atualizados(ajusta critérios de elegibilidade de propostas)
Eventos produzidos
incubação.processo_aberto— payload:incubacao_id,gap_id, tipo de organização, UC, nível de prioridade, prazo de manifestação de interesse, critérios mínimos de proposta.incubação.proposta_registrada— payload:incubacao_id,proposta_id, grupo proponente, capacidade técnica declarada, modelo de operação proposto.incubação.proposta_aprovada— payload:incubacao_id,proposta_id, fonte de financiamento vinculada, marcos acordados.incubação.concluída— payload:incubacao_id,empresa_idda organização criada, data de início de operação.incubação.cancelada— quando gap é resolvido por outra via ou proposta não atinge critérios mínimos.
Estado próprio
Registro de processos de incubação com status (aberto/em_avaliação/aprovado/concluído/cancelado). Histórico de propostas por incubacao_id. Marcos e prazos acordados.
Lógica
gap.detectado recebido com nível_prioridade >= médio→ abre processo de incubação→ publica incubação.processo_aberto (visível publicamente na UC)→ cidadãos ou grupos manifestam interesse via interface (proposta simples)→ para cada proposta recebida: → registra declaração de capacidade técnica e modelo proposto → publica incubação.proposta_registrada→ comissão de avaliação da UC (sorteada, critérios parametrizados): → avalia viabilidade técnica e aderência ao modelo socializado → se aprovada: vincula fonte de financiamento (caixa da UC ou fomento) → publica incubação.proposta_aprovada→ organização é criada e cadastrada nas colônias de lugares e empresas→ quando empresa.cadastrada recebida: → registra conclusão → publica incubação.concluídaO modelo socializado como requisito de entrada
Toda organização nascida de um processo de incubação entra no modelo socializado desde o início: transparência de folha, razão salarial parametrizada, excedente com destino rastreável para o fomento do sistema. Não é opcional. É critério de aprovação da proposta.
Técnicas e referências de implementação
- Comissão de avaliação: sorteio pelo mesmo mecanismo da D-6a. Mandato limitado ao ciclo de avaliação.
- Critérios de proposta: parametrizados e públicos. Incluem: capacidade técnica mínima declarada, modelo de governança interna, projeção de cobertura do gap, prazo de início de operação.
- Matching de financiamento: colônia consulta o caixa disponível do fomento do sistema via evento. Não acessa diretamente nenhum saldo — publica requisição e aguarda confirmação.
- Transparência do processo: toda proposta, avaliação e decisão é pública. O processo de incubação tem timeline pública análoga à timeline de demandas.
Critério de saída
Todo gap de prioridade média ou alta com processo de incubação aberto tem timeline pública rastreável. Organizações criadas via incubação estão linkadas ao gap que as originou — o ciclo completo (gap detectado → organização operando → gap resolvido) é verificável por qualquer cidadão.
Camada Transversal — Dados Brutos para Informação
Seção intitulada “Camada Transversal — Dados Brutos para Informação”Esta seção não é uma colônia. É a descrição do pipeline que perpassa todas as colônias: como o dado bruto que entra pelo sistema de ingestão se transforma em informação útil, agregável e auditável.
O pipeline de lapidação
Seção intitulada “O pipeline de lapidação”DADO BRUTOtexto livre + localização aproximada + foto + horário ↓NORMALIZAÇÃO (D-1b)campos estruturados + coordenadas validadas ↓CLASSIFICAÇÃO (D-3 + D-13)categoria + nível + score_horizontal + score_risco ↓PONTUAÇÃO (D-4)score_final = peso_nacional × peso_situacional × score_horizontal ↓AGREGAÇÃO (D-5 + D-14)backlog por UC / visão multinível / dashboards comparativos ↓PROJEÇÃO (D-22)tendências / gargalos / velocidade / cobertura ↓EXPORTAÇÃO (D-15 + D-23)datasets públicos / snapshots assinados / repositório abertoCada transformação é um evento. Cada evento é rastreável. O dado bruto original nunca é descartado. A versão normalizada, categorizada e pontuada é derivada — não substituta.
Onde a IA atua em cada etapa
Seção intitulada “Onde a IA atua em cada etapa”| Colônia | Função da IA | Limite explícito |
|---|---|---|
| D-1b Normalização | Transcrição de áudio, descrição de imagem, tradução da legenda para o português, estruturação de texto e denylist de termos | Não publica sem confirmação do cidadão. A denylist apenas sinaliza para a moderação. |
| D-1c Anexos | Classificação de imagem: NSFW, detecção de pessoa e heurística de documento/PII | NSFW bloqueia por limiar. Pessoa apenas sinaliza. A revisão humana é reativa. |
| D-1d Moderação | Não usa IA própria. Organiza a fila da sinalização da D-1b e da D-1c. | A decisão é humana. A IA não aprova nem bloqueia conteúdo. |
| D-3 Categorização | Classificação automática com score de confiança | Acima do limiar automático: publica com marcação e caminho de contestação. Abaixo do limiar mínimo: bloqueia até revisão humana. |
| D-6b Relatoria | Sugestão de estruturação de atualizações | Rotina: conselheiro revisa e confirma. Sensível: revisão obrigatória. IA nunca publica sem o conselheiro ter visto a tela. |
| D-9 Validação de vínculo | Extração de campos de documentos | Resultado provisório, auditado por amostragem |
| D-11 Anti-fraude | Detecção de padrões anômalos | Não bloqueia — apenas sinaliza para revisão humana |
| D-12 Duplicidade | Fase 1: heurística determinística de similaridade textual. Fase 2: embedding + busca semântica | Sinaliza candidatas, não mescla. Agregação por confirmação coletiva |
| D-24 Memória de Caminhos | Agregação determinística do caminho e dossiê por template, sem modelo de linguagem | Histórico automático com referências. Não prescreve e não decide |
| D-13 Risco | Score de urgência por texto e contexto territorial | Não remove da fila automaticamente |
| D-20 Anti-abuso | Detecção de coordenação sofisticada | Alerta público, decisão humana |
| D-22 Projeções | Tendências e padrões históricos | Sempre marcadas como projeção, nunca como dado factual |
| E-2 Folha salarial | Validação de consistência de campos declarados | Não altera dados — apenas sinaliza inconsistência |
| E-5 Estrutura | Clustering semântico de descrições de função | Mapa é sugestão, empresa confirma ou corrige |
A IA nunca decide, nunca prioriza e nunca publica sem revisão humana. É redução de atrito, não autoridade.
Qualidade e evolução dos dados
Seção intitulada “Qualidade e evolução dos dados”O sistema melhora com o tempo porque cada correção humana alimenta os modelos:
- Categorização corrigida manualmente → par (texto, categoria_correta) entra no dataset de treino.
- Vínculo invalidado por revisão → par (documento, resultado_correto) melhora o modelo de OCR.
- Anomalia confirmada por investigação → padrão vira regra de detecção aprimorada.
- Duplicidade confirmada ou descartada → ajusta o limiar de similaridade por categoria.
Cada erro detectado e corrigido é dado estruturado. O sistema não esconde erros — documenta e aprende.
Mapa de Dependências de Eventos entre Colônias
Seção intitulada “Mapa de Dependências de Eventos entre Colônias”Cidadão → [D-1a Captura] → demanda.recebida → [D-1b Normalização] → demanda.normalizada → [D-2 Georreferenciamento] → demanda.georreferenciada → [D-3 Categorização] → demanda.categorizada → [D-1c Anexos] → anexo.processado (consome demanda.recebida, em paralelo à D-1b) → [D-1d Moderação] ← anexo.processado (pendente ou sensível; 1.4.0 com o object_key_temp) ← demanda.normalizada (conteúdo suspeito; 1.4.0 com as midias_descritas) ← conselheiro.atualização_publicada (relato com conteúdo suspeito) → d1d.fila_moderacao + d1d.decisoes_moderacao (decisão e histórico na mesma transação) → d1d.descricoes_midia (descrição automática de cada imagem, casada ao item pelo object_key_temp) → moderacao.decidida → [D-1c Anexos] → anexo.moderado → [D-7 Transparência] → anexo.removido → [D-7 Transparência] → [D-7 Transparência] libera, oculta ou limpa o texto e o relato → [N-0d Direitos do Titular] limpa o texto dos schemas na remoção → [D-12 Duplicidade] → duplicidade.candidata_detectada → [D-13 Risco] → demanda.risco_classificado → [D-4 Priorização] → demanda.ranqueada / ranking.atualizado → [D-5 Agenda] → agenda.gerada / agenda.item_disponível → [D-6a Sorteio] → conselheiro.sorteado ────┐ │ → conselheiro.atribuicao_recusada ──┐ │ │ ┌───────────────────────────────────┘ │ │ ▼ (re-sorteio interno) │ │ [D-6a] processa recusa, │ │ re-sorteia mesma demanda │ │ │ [BFF D-1a] → conselheiro.atualização_registrada ─────┤ │ │ → [D-6b Relatoria] → conselheiro.demanda_iniciada → conselheiro.atualização_publicada → conselheiro.prazo_próximo (CronJob 6h) → conselheiro.ciclo_concluído ──┐ → demanda.concluída ─────┘ │ ┌───────────────────────────────┘ ▼ (libera conselheiro) [D-6a] varre fila de pendentes, novo sorteio [D-5 Agenda] atualiza status (atribuido / em_progresso / concluido) ← [D-7 Transparência] consome todos os eventos acima → timeline pública + dashboard
[D-12 Duplicidade] consome: demanda.recebida, demanda.normalizada, demanda.categorizada, demanda.georreferenciada, demanda.concluída, conselheiro.sorteado, duplicidade.agregada, demanda.conclusao_confirmada (índice, quando a ratificação é desnecessária), cidadão.vinculado (funde relator, confirmações e conclusões do device na conta Google) → duplicidade.candidata_detectada / demanda.confirmada / demanda.evidencia_adicionada → duplicidade.agregada (3 confirmações de cidadãos distintos, presença ≤ 700 m, ao menos uma verificada; anônimo no limiar 2 recebe 401 login_necessario) → [D-4 Priorização] desativa membros, recalcula posições, republica ranking.atualizado → [D-5 Agenda] marca membros como agregado, regenera backlog → [D-6a Sorteio] remove os membros da fila de pendentes
[D-12 Conclusão coletiva] → demanda.evidencia_adicionada (via: 'conclusao') por mídia → demanda.conclusao_confirmada (3 conclusões de cidadãos distintos, presença ≤ 700 m, ao menos uma verificada; anônimo no limiar 2 recebe 401 login_necessario; ratificacao_necessaria = demanda atribuída tem conselheiro sorteado) → [D-5 Agenda] conclui item fora de em_progresso com data_conclusao e dias_ate_conclusao; item em_progresso aguarda ratificação → [D-6b Relatoria] pendência de ratificação com acompanhamento ativo; POST /d6b/demandas/:id/ratificar-conclusao reusa o fluxo de conclusão → [D-7 Transparência] snapshot concluida (ou só timeline quando há ratificação); evidências projetadas com via conclusao
[D-24 Memória de Caminhos] consome: demanda.georreferenciada, demanda.categorizada, conselheiro.atualização_publicada, duplicidade.agregada, demanda.concluída e conselheiro.ciclo_concluído → caminho.atualizado → [D-7 Transparência] projeta d7.caminhos e o dossiê no snapshot da demanda; o workspace do conselheiro lê o dossiê por essa projeção
[D-11 Anti-fraude] consome: demanda.recebida, validação.social_concluída, cidadão.dispositivo_registrado[D-14 Agregação] consome: demanda.ranqueada, ranking.atualizado, agenda.item_disponível, conselheiro.ciclo_concluído[D-17 Mandato] consome: conselheiro.ciclo_concluído, conselheiro.sorteado, conselheiro.avaliação_registrada, capacitação.concluída
Fase 2:[D-9 Vínculo] consome: cidadão.solicitou_validação_vínculo, validação.documento_submetido, validação.social_concluída[D-10 Votação] consome: votação.aberta, voto.submetido, votação.prazo_encerrado[D-15 Pesquisa] consome: eventos de estado agregado[D-16 Integridade] consome: todos os eventos (apenas para hashing)
Fase 3:[D-18 Simulação] opera sobre snapshot de parâmetros e ranking[D-19 Governança de parâmetros] consome: proposta, simulação, votação[D-20 Anti-abuso] consome: padrões do D-11 + eventos de comportamento[D-21 Monitoramento] consome: atualizações de conselheiro + planos de ministério[D-22 Projeções] consome: replay do histórico completo[D-23 Snapshot] consome: estado de todas as projeções de leitura
Colônias de empresa (paralelas — E-1/E-2/E-3 no MVP, E-4/E-5 na Fase 2):[E-1] → empresa.cadastrada + lugar.recebido(tipo=organizacao) → [L-1/L-2] → lugar.cadastrado → lugar.georreferenciado → [E-1] consome lugar.georreferenciado → empresa.associação_territorial_definida[E-2] consome: empresa.cadastrada (projeção local)[E-2] face BFF → empresa.folha_submetida → empresa.diagnóstico_salarial_publicado[E-3] consome: empresa.cadastrada, empresa.folha_submetida, empresa.diagnóstico_salarial_publicado, empresa.balanço_submetido, parâmetros.atualizados[E-3] face BFF → empresa.balanço_submetido → empresa.simulação_econômica_publicada → [E-4] → empresa.impacto_territorial_publicado (Fase 2 — depende de L-4)[E-5] → empresa.mapa_estrutural_publicado (Fase 2)
Colônias de lugares (paralelas):[D-1a] → lugar.recebido → [L-1] → lugar.cadastrado → [L-2] → lugar.georreferenciado → [L-3] → lugar.validado / lugar.desativado → [D-7] projeta status_confianca, metodo_validacao e total_confirmacoes em d7.lugares_geo → [L-3] → lugar.validação_social_solicitada (Fase 2) → [L-4] → cobertura.atualizada / gap.detectado / gap.resolvido (Fase 2) → [L-5] consome: gap.detectado → incubação.processo_aberto → incubação.proposta_registrada → incubação.proposta_aprovada → incubação.concluída → empresa.cadastrada (via E-1)[E-1] publica lugar.recebido(tipo=organizacao) para a L-1 ao cadastrar organização[L-4] consome: demanda.ranqueada (cruza gaps com demandas correlatas)[L-5] consome: empresa.cadastrada (confirma conclusão da incubação)Priorização para o MVP
Seção intitulada “Priorização para o MVP”Das colônias de negócio mais o núcleo, o MVP mínimo que fecha um ciclo completo — demandas, conselheiros, transparência — e inicia o mapeamento de empresas é:
Bloco 1 — Núcleo (pré-requisito absoluto):
| Prioridade | Colônia | Justificativa |
|---|---|---|
| 1 | N-0a (Event Bus) | Sem barramento não existe nada |
| 2 | N-0b (Registry) | Idioma comum, pré-requisito de todas |
| 3 | N-0c (Observabilidade) | Sem logs, erros são invisíveis |
Bloco 2 — Ciclo de demandas (Fase 1):
| Prioridade | Colônia | Justificativa |
|---|---|---|
| 4 | D-1a Captura | Ponto de entrada do cidadão |
| 5 | D-1b Normalização | Dado bruto não serve ao pipeline |
| 6 | D-1c Gestão de Anexos | Armazenamento de mídia do cidadão |
| 7 | D-1d Moderação | Fecha a entrada: sinalização automática e decisão humana |
| 8 | D-2 Georreferenciamento | Sem território, não há UC |
| 9 | D-3 Categorização | Sem categoria, sem ranking |
| 10 | D-12 Detecção de Duplicidade | Agrega demandas equivalentes antes do ranking |
| 11 | D-4 Priorização e Ranking | Sem ranking, sem agenda |
| 12 | D-5 Agenda | Sem backlog, sem conselheiro |
| 13 | D-6a Sorteio e Atribuição | Sem sorteio, sem acompanhamento |
| 14 | D-6b Relatoria e Acompanhamento | Sem relatoria, sem transparência |
| 15 | D-7 Transparência | Sem timeline pública, o ciclo não é verificável |
Bloco 3 — Lugares (Fase 1, paralelo ao ciclo de demandas):
| Prioridade | Colônia | Justificativa |
|---|---|---|
| 16 | L-1 Cadastro de Lugares | Entusiastas populam o mapa de realidade territorial desde o início |
| 17 | L-2 Georreferenciamento e Tipificação | Associação territorial das organizações depende daqui |
| 18 | L-3 Validação e Qualidade (subconjunto) | Confirmação automática, confirmação social por presença, denúncia e retirada fecham o ciclo de vida do lugar |
Bloco 4 — Empresas (Fase 1, paralelo):
| Prioridade | Colônia | Justificativa |
|---|---|---|
| 19 | E-1 Cadastro Institucional | Pré-requisito de todas as colônias de empresa |
| 20 | E-2 Transparência Salarial e Folha | Mapeamento de cargos e diagnóstico do achatamento salarial |
| 21 | E-3 Simulação Econômica | Simulação do excedente e da redistribuição — responde “quanto mudaria” |
Simplificações válidas no MVP:
Ciclo de demandas:
- D-1c Anexos: MinIO com object key derivada do hash SHA-256 (deduplicação por hash), validação de MIME por magic bytes, EXIF removido via sharp. Sem OCR. Classificação local de NSFW e pessoa com transformers.js.
- D-1d Moderação: fila única com filtro de tipo, denylist de texto no lugar de modelo de toxicidade e decisão tripla (aprovado, bloqueado ou removido) com confirmação. O histórico append-only por item guarda decisão, motivo, moderador, data e reversão. A remoção física é reservada ao conteúdo ilegal e recusada no relato; a D-1c apaga a mídia e a N-0d limpa o texto.
- D-2 Georreferenciamento: base de polígonos no schema
core(core.uc_polygons) compartilhada com a L-2 via leitura direta. Exceção controlada ao isolamento — justifica-se como dependência de infraestrutura. Migra para colônia dedicada de geo na Fase 2. Confiança geo semprealtano MVP; ponto fora de todos os polígonos gera revisão pendente. - D-3 Categorização: classificador por palavras-chave e regras. Sem modelo de ML. Fila de revisão persistida para confiança < 0.85.
- D-12 Duplicidade: heurística determinística (mesma UC e categoria, distância de até 500 m, Jaccard de 0,6) e confirmação coletiva. Sinaliza candidatas, não mescla.
- D-4 Priorização: pesos fixos em configuração. Sem recalculação dinâmica por evento de parâmetro. Ranking em memória com posições persistidas e reconstrução no boot.
- D-6a Sorteio: seed auditável = HMAC-SHA256 do último
event_iddo barramento e do timestamp do sorteio. Fisher-Yates determinístico. Sorteio serializado por UC. - D-7 Transparência: timeline em texto plano. Dashboard calculado on-demand a partir dos snapshots; rebuild via replay do barramento.
Lugares:
- L-1: sem deduplicação sofisticada. Alerta simples por proximidade de coordenadas.
- L-2: enriquecimento via OSM apenas. CNPJ e bases de equipamentos públicos (CNES, Inep) entram na Fase 2. Base de polígonos compartilhada com a D-2 via
core.uc_polygons(mesma exceção controlada). - L-3: subconjunto social e automático no MVP. Confirmação automática pela confiança da L-2, 3 confirmações de cidadãos distintos em 700 m, 3 denúncias para disputar, retirada pelo autor e reativação por operador. Sem reincidência temporal, sem validação presencial sorteada e sem revalidação periódica.
Empresas:
- E-1: cadastro manual via formulário. Sem integração automática com base de CNPJ no MVP.
- E-2: folha declarada via duas rotas (JSON ou CSV multipart), face BFF dentro da colônia. Sem OCR ou extração automática. Diagnóstico calculado sobre os dados declarados.
- E-3: cálculo sobre dados autodeclarados. Sem verificação cruzada com fontes externas. A simulação é transparente — metodologia pública, replicável com os dados de entrada.
Adiar para Fase 2 (MLP — sem perder o ciclo):
Colônias do ciclo de demandas:
- D-8 Manutenção Programada
- D-9 Validação de Vínculo
- D-10 Votação formalizada
- D-11 Anti-fraude avançada
- D-13 Classificação de Risco
- D-14 Agregação Multinível
- D-15 Pesquisa e Exportação
- D-16 Integridade Criptográfica
- D-17 Controle de Mandato e Progressão
Colônias de lugares:
- L-3 Validação e Qualidade (métodos restantes) — reincidência temporal, validação presencial sorteada e revalidação periódica requerem volume mínimo de dados
- L-4 Análise de Cobertura e Gaps — depende de L-3
- L-5 Incubação Social — depende de L-4
Colônias de empresa:
- E-4 Impacto Territorial — depende de L-4 (gaps) que é Fase 2
- E-5 Mapeamento de Estrutura Interna — clustering semântico de descrições de função, complexidade que não justifica no MVP
Nunca adiar (mesmo no MVP):
- Observabilidade básica: logs com
demanda_idecorrelacao_id - Dado bruto preservado: normalização nunca descarta o original
- Breakdown do score no ranking: auditabilidade desde o primeiro dia
- Timeline pública de cada demanda: sem isso o ciclo não fecha
- Metodologia de simulação de empresas: pública e replicável desde o primeiro diagnóstico