Visão Geral
Produzir e preservar a prova legal da CIPA — atas assinadas e imutáveis (hash SHA-256 + auditoria) e eleições com voto secreto real e apuração determinística — conforme a NR-5 e a Lei 14.457/2022, sem depender do banco da Livon.
Microserviço em Go, com banco de dados próprio (PostgreSQL), que gere o ciclo de vida completo da CIPA (Comissão Interna de Prevenção de Acidentes — segurança do trabalho) em conformidade com a NR-5 e a Lei 14.457/2022. Roda fora do monólito da Livon (plataforma EHS Django/Nuxt) e integra com ela 100% via API REST: o dado da CIPA (eleições, atas, reuniões, riscos, denúncias) é do microserviço; quem é o usuário, de qual empresa e a lista de colaboradores vêm da Livon pela API. É um backend (API); as telas pertencem à camada Livon/Nuxt.
- Plataforma Livon: EHS/saúde ocupacional brasileira, monólito Django 4.1 + DRF + PostgreSQL (backend) e Nuxt 2/Vue 2 (frontend), auth Keycloak OIDC, multi-tenant (
Tenant/appGHCompany→Unit). A CIPA é greenfield na Livon — não existe módulo CIPA/NR-5 hoje (só duas flagsis_candidate_to_cipa/is_elected_to_cipaemappUser.User). - Origem do domínio: um protótipo Lovable (React/Supabase,
livon-cipa-hub, ~30 tabelas, RLS) foi submetido a engenharia reversa (_reversa_sdd/). O protótipo é fonte derivada e incompleta — as regras autoritativas NR-5 + Lei 14.457 prevalecem sobre ele. - Realidade da integração (sem achismo): "100% via API puro" não é totalmente viável hoje. A auth de sistema da Livon (
ClientIntegrationAuthentication) só cobre poucos endpoints; as leituras que a CIPA precisa exigem usuário logado. Padrão que funciona: pass-through do token Keycloak do usuário. A integração é bidirecional (consumir + legar) e exige construir endpoints no lado da Livon (mapeada e rodando local; merge/UAT oficial é o passo final). - Lei 14.457/2022: área inteira (canal de denúncia anônimo + treinamento anual de assédio) que o protótipo não tinha — adicionada às regras autoritativas.
- Estado atual do código: Fases 0–1 prontas e verificadas (fundação agnóstica de regra, observabilidade, auth/ACL/RBAC).
ListEligibleVoters,GetCompanyHeadcounteGetUnitretornamErrLivonEndpointNotAvailable(endpoints a construir na Livon). - Gate de processo (regra dura): nenhuma execução de código de feature começa antes de o Bruno revisar e aprovar a visão geral consolidada das fases. As Fases 0–1 ficam como estão.
Especificação Funcional
-
✓
AUTH-01
O serviço valida localmente o token Keycloak (Bearer JWT) por JWKS — assinatura,
iss,audeexp; token inválido/expirado retorna 401 -
✓
AUTH-02
O serviço extrai um
Principal(livon_user_id=sub, email, empresa, unidade, roles) do token e o expõe emGET /api/v1/me -
✓
AUTH-03
O token do usuário é repassado (pass-through) às chamadas da API da Livon (
GET /api/v1/livon/meresolve o colaborador via ACL) -
✓
AUTH-04
Em modo dev (
AUTH_ENABLED=false), o serviço injeta umPrincipalsintético (admin) sem validar token
-
✓
RBAC-01
O serviço combina papéis do token (
realm_access.roles) com o RBAC próprio persistido (cipa_role_assignments: admin, it_admin, cipa_member, president, secretary, auditor) -
✓
RBAC-02
Endpoints protegidos exigem papel via middleware
RequireRole; acesso é negado por padrão (defesa no servidor, não cosmética) - ○ RBAC-03 Toda autorização é escopada por empresa/unidade (tenant); um usuário só acessa recursos da própria empresa/unidade
-
○
RBAC-04
Papéis funcionais (presidente, secretário, membro) são derivados do mandato vigente (
cipa_members) e concedem permissões operacionais (criar reunião/ata, triar sugestões) - ○ RBAC-05 Auditor tem acesso somente-leitura às trilhas (atas, eleições, acessos), sem escrita em nenhum recurso
-
✓
INTEG-01
Todo acesso à Livon passa pela camada anticorrupção (
LivonClient); DTOs da Livon nunca vazam ao domínio - ✓ INTEG-02 O cliente HTTP da Livon tem circuit breaker, retry, timeout, cache efêmero (~60s) e singleflight; nenhum dado da Livon é persistido
-
✓
INTEG-03
GetEmployeeconsomeGET /users/user_informationcom pass-through do Bearer do usuário -
○
INTEG-04
ListEligibleVotersretorna colaboradores elegíveis por empresa/unidade com campos eleitorais (endpoint a construir na Livon) -
○
INTEG-05
GetCompanyHeadcountretorna nº de empregados + grau de risco (NR-4) por empresa/unidade, base do dimensionamento (endpoint a construir na Livon) -
○
INTEG-06
GetUnitretorna dados da unidade/estabelecimento (endpoint a construir na Livon) - ○ INTEG-07 Trilha de auth de sistema para leituras sem usuário logado (rotinas/jobs) — bloqueador, a construir na Livon
-
○
INTEG-08
A CIPA grava de volta na Livon o resultado da eleição / mandato (flags
is_candidate_to_cipa/is_elected_to_cipaou recurso de "mandato CIPA") -
○
INTEG-09
Registro do módulo CIPA + entitlement por empresa (
CompanyLinkedModule) e permissões na Livon - ○ INTEG-10 Webhook de admissão/desligamento mantém a elegibilidade/membros atualizados (sem dado defasado)
- ○ INTEG-11 Operações autoritativas (homologar eleição, fechar dimensionamento) falham fechado quando a Livon está indisponível
-
○
INTEG-12
Toda chamada à Livon padroniza o tenant via
X-Company-Id - ○ INTEG-13 Documento "Contrato de Integração Livon" lista todos os endpoints consumidos e gravados (existentes vs a construir), servindo de spec do lado da Livon
- ○ RISK-01 Usuário (admin/cipa_member) pode criar áreas de risco e itens de risco vinculados a empresa/unidade
- ○ RISK-02 Item de risco tem severidade (baixo/médio/alto/crítico) × probabilidade (raro…certo); o nível de risco (1–20) é calculado automaticamente
- ○ RISK-03 Item de risco tem tipo (físico/químico/biológico/ergonômico/acidente)
- ○ RISK-04 Item de risco transiciona por estados (identificado → sob controle → mitigado → eliminado)
- ○ RISK-05 Usuário pode visualizar o mapa de riscos com bandas por nível
- ○ SUGG-01 Colaborador pode enviar sugestão identificada ou anônima (anônima = sem vínculo ao autor)
- ○ SUGG-02 Sugestão tem categoria e segue máquina de estados (nova → em análise → em deliberação → concluída → arquivada) com transições válidas impostas
- ○ SUGG-03 Nova sugestão notifica os membros CIPA ativos sem vazar o autor
-
○
SUGG-04
Membro/admin pode triar a sugestão (categoria, prioridade, resposta) e o revisor (
reviewed_by) é registrado - ○ SUGG-05 Colaborador vê apenas as próprias sugestões na visão pública
- ○ SUGG-06 Sugestão pode ser vinculada a uma deliberação de ata (opcional)
- ○ MEET-01 Usuário (admin/cipa_member) pode agendar reunião (ordinária/extraordinária) com data futura, pauta e participantes
- ○ MEET-02 Reunião segue estados agendada → em andamento → concluída, com ramo cancelada
- ○ MEET-03 O sistema alerta o compliance de periodicidade: ordinária mensal (bimestral para ME/EPP grau 1–2); ata assinada pelos presentes
- ○ MEET-04 O quórum da reunião é configurável (Regimento Interno; default maioria absoluta = membros ativos/2 + 1) e calculado pelos presentes
- ○ MEET-05 O quórum pode ser dispensado com justificativa registrada
- ○ MEET-06 Agendar reunião gera convocação/notificação a cada participante
- ○ MEET-07 Usuário registra presença (presente/ausente/atrasado/justificado); ausência de titular exige justificativa
- ○ MEET-08 Reunião tem plano de ação com responsável, prazo, prioridade e status
- ○ ATA-01 Usuário pode criar uma ata a partir de reunião concluída/em andamento que ainda não tem ata (relação 1:1)
- ○ ATA-02 A ata é pré-preenchida com pauta e participantes presentes/ausentes (com justificativa) da reunião
-
○
ATA-03
A ata recebe numeração automática única
ATA-<UNIDADE>-<ANO>-<SEQ>por unidade+ano (sem corrida) - ○ ATA-04 A ata é máquina de estados rica: rascunho → em revisão → em aprovação → assinado → publicado → arquivado, com → retificado (nova versão); transições são métodos com invariantes
- ○ ATA-05 A ata não pode ser assinada sem número + quórum atingido + ≥1 deliberação
-
○
ATA-06
Ao assinar, o serviço calcula o hash SHA-256 do conteúdo canônico e registra a assinatura (
minute_signatures: signed_at, IP, user_agent); a ata assinada torna-se imutável - ○ ATA-07 A ata pode ser enviada para aprovação e o presidente é notificado
-
○
ATA-08
A ata assinada não pode ser editada — apenas retificada (nova versão com
parent_version_id,version++; a anterior viraretificado; ambas acessíveis) -
○
ATA-09
Toda transição/edição/assinatura/publicação grava
ata_audit_log -
○
ATA-10
A ata tem retenção legal de 5 anos (
retention_until); ao vencer é arquivada, nunca deletada -
○
ATA-11
Toda deliberação segue 5W2H (what/who/when/where/why/how/howMuch) com status; concluir deliberação com
evidence_requiredexige anexo - ○ ATA-12 A ata publicada gera PDF com o hash no rodapé e um resumo
- ○ ELEC-01 Admin pode abrir eleição que segue o ciclo NR-5: convocação (edital) → inscrição → campanha → votação → apuração → posse
- ○ ELEC-02 O edital é publicado ≥45 dias antes do fim do mandato; votação ≥30 dias antes; inscrição de candidatos ≥15 dias; posse até o fim do mandato anterior; o sistema alerta os prazos
-
○
ELEC-03
O dimensionamento usa o Quadro I da NR-5 (nº de empregados × grau de risco 1–4) para titulares + suplentes;
overrideexige justificativa - ○ ELEC-04 Colaborador elegível pode se candidatar (1 candidatura por pessoa por eleição); a elegibilidade valida ≥90 dias de casa, ativo (sem aviso prévio) e não-chefia
- ○ ELEC-05 Candidatura nasce pendente; admin aprova ou rejeita (motivo obrigatório)
- ○ ELEC-06 Eleitor apto vota uma única vez por eleição (voto único garantido por unicidade no log de votantes)
- ○ ELEC-07 O voto é secreto de verdade: o log de votantes (quem votou) é desvinculado da cédula (sem identidade); a cédula não é auditada
- ○ ELEC-08 A apuração é serviço de domínio determinístico: contagem → desempate NR-5 (tempo de casa/idade/sorteio auditável) → atribuição titular/suplente → homologação
-
○
ELEC-09
A homologação cria os
cipa_members(mandato) e grava o resultado de volta na Livon - ○ ELEC-10 Toda operação de eleição/candidatura é auditada; o voto não é auditado (sigilo)
- ○ MEMB-01 Mandato = 1 ano, com 1 reeleição (máx. 2 consecutivos); 2 anos só via convenção coletiva
- ○ MEMB-02 O sistema rastreia a estabilidade do membro: da candidatura até 1 ano após o fim do mandato (titulares e suplentes que exerceram)
- ○ MEMB-03 A posse é bloqueada até o membro concluir o treinamento NR-5 (8/12/16/20h conforme grau de risco), antes da posse (até 30 dias após, se eleição extraordinária)
- ○ MEMB-04 Membro segue estados ativo → inativo/suspenso/substituído; vacância convoca o suplente
- ○ MEMB-05 O sistema alerta a expiração de mandato (faixas 30/60/90 dias)
- ○ MEMB-06 A composição é paritária (representantes do empregador × dos empregados)
- ○ MEMB-07 Empresa ≤19 empregados (ou ≤20 grau 1–2) designa 1 responsável (designado), sem eleição, mas com treinamento e atribuições
- ○ MEMB-08 Em registros com valor jurídico (participante de ata assinada, candidato homologado), grava-se um snapshot de nome/matrícula do momento do evento
- ○ COMM-01 Usuário (admin/cipa_member) pode criar comunicado (nasce rascunho) e publicá-lo (ação separada)
- ○ COMM-02 Usuário confirma ciência por ação afirmativa ("Li e estou ciente"); a leitura é idempotente (1 por usuário+comunicado)
- ○ COMM-03 Comunicado tem visibilidade (aberto/cipa_only) e segmentação de público
- ○ COMM-04 O dashboard mostra a taxa de leitura (derivada dos registros de leitura)
- ○ SIPAT-01 Usuário pode planejar e gerir a SIPAT anual, com mínimo de 5 dias consecutivos
- ○ SIPAT-02 Comunicados podem ser agrupados em campanha (SIPAT / mês temático)
- ○ HARASS-01 O sistema oferece um canal de denúncia anônimo de assédio/violência, com proteção anti-retaliação
- ○ HARASS-02 As regras de conduta sobre assédio são divulgadas e incluídas no regimento da CIPA
- ○ HARASS-03 O sistema gerencia o treinamento anual sobre assédio/violência/diversidade (registro + alerta)
- ○ HARASS-04 A denúncia segue um fluxo de triagem confidencial, com acesso restrito
-
✓
OBS-01
O serviço expõe
GET /healthz(liveness) eGET /readyz(readiness, checa banco; Livon é dependência soft) - ✓ OBS-02 O serviço exporta traces via OTLP; cada request HTTP vira um trace com spans de banco (visível no Grafana/Tempo)
-
✓
OBS-03
Logs em
slogJSON comtrace_id/span_id(stdout; pipeline OTLP→Loki pré-configurado) -
✓
OBS-04
A stack (Prometheus/Loki/Tempo/Grafana) sobe via
docker composecom dashboards/datasources provisionados -
○
OBS-05
O serviço exporta métricas RED + de domínio (atas pendentes, estado do breaker Livon, p95 da apuração) via
MeterProvider - ○ OBS-06 Logs são enviados via OTLP (log bridge) ao Loki
-
○
AI-01
A IA gera rascunho de ata (entra como
rascunho; humano revisa; IA nunca assina/aprova) - ○ AI-02 A IA classifica sugestões
- ○ AI-03 A IA apoia a análise de risco
- ○ AI-04 PII é pseudonimizada antes do prompt; acesso é registrado; opt-out por empresa; saída marcada como "sugestão de IA"; provedor com no-train/zero-retention
Especificação Técnica
Arquitetura Hexagonal
Ports & adapters: o domínio (regras legais) fica no centro e não depende de banco, web ou Livon. Tudo aponta para dentro.
100% via API
Zero acesso ao banco da Livon. Identidade e colaboradores vêm por API REST (bidirecional); o dado da CIPA é do microserviço.
Observabilidade dia 1
Traces, logs e métricas desde a Fase 0 (OpenTelemetry → Grafana/Tempo/Loki/Prometheus). Cada request é rastreável ponta a ponta.
Prova legal
Ata com hash SHA-256, imutável e auditável; voto secreto real. A peça jurídica é blindada por design, não por confiança.
Microserviço Go + banco Postgres próprio
Independência de deploy/evolução; stack escolhida; regras legais explícitas (sem ORM mágico)
Integração 100% via API com a Livon (bidirecional)
Não acoplar ao banco da Livon; respeitar LGPD; consumir + legar
Pass-through do token Keycloak do usuário
Auth de sistema da Livon só cobre poucos endpoints; pass-through resolve identidade+papel+empresa de uma vez, continua "via API"
Observabilidade desde o dia 1
Operação e diagnóstico de fluxos críticos (apuração, ata) desde o início
IA isolada (Anthropic) na camada app, nunca no domínio
IA assistiva, nunca autoritativa (não assina/aprova); LGPD (pseudonimização, no-train)
Quórum configurável (Regimento Interno)
A NR-5 não fixa percentual; resolve o conflito de quórum do protótipo (não hardcodar)
Regras NR-5 / Lei 14.457 acima do protótipo
Protótipo é fonte derivada e incompleta (errou estabilidade, ignorou grau de risco, sem assédio)
Voto secreto real — election_voter_log (quem votou) desvinculado de election_ballots (cédula sem identidade)
Supera o protótipo, que só escondia por RLS
Ata como máquina de estados com hash SHA-256 + auditoria + imutabilidade + retificação versionada
Materializa a prova legal que o protótipo prometia mas não implementava
Auth via Keycloak com validação local (JWKS) + RBAC próprio escopado por empresa
Autenticação na Livon; autorização na CIPA (papéis funcionais via cipa_members)
Dimensionamento via Quadro I (nº empregados × grau de risco NR-4)
Protótipo ignorava o grau de risco; depende de headcount + grau vindos da Livon
Snapshots legais de PII (nome/matrícula no momento do evento)
Blinda registros jurídicos contra anonimização LGPD futura na Livon; não é cópia/sync
Tech stack
Go (net/http Go 1.22 + chi, pgx/v5 + sqlc, goose, go-oidc+jwx, gobreaker+go-retryablehttp, anthropic-sdk-go) — decisão de stack e ausência de ORM mágico (regras legais explícitas)
Banco
PostgreSQL próprio do microserviço, um schema por bounded context; IDs externos opacos da Livon (livon_user_id/livon_company_id/livon_unit_id, sem FK física) — independência do banco da Livon
Integração
100% via API REST com a Livon, bidirecional; sem DB direto, sem cópia persistente — independência e LGPD
Compliance
NR-5 (vigente 2023) + Lei 14.457/2022 + LGPD são regras autoritativas acima do protótipo — risco legal/trabalhista
Dependência
endpoints a construir no lado da Livon + contrato/SLA por escrito antes da Fase 4 — bloqueia a apuração eleitoral (dados de colaboradores/headcount/grau de risco)
Segurança (Livon)
exigir JWT_SECRET separado do SECRET_KEY (P838), JWT com iss/aud/nbf/iat (P839), aplicar quota (P840) antes de produção
Infra/Deploy
Docker + Portainer na VPS Contabo; 3 ambientes (local / dev-VPS / banco estável p/ versionamento); futuro: plugar na Livon (AWS/Keycloak)
Esqueleto hexagonal roda em containers com observabilidade ponta a ponta desde o dia 1 (CONCLUÍDA)
Usuário autentica via Keycloak e o serviço autoriza por papel, falando com a Livon pela camada anticorrupção (CONCLUÍDA)
Entregar valor cedo com módulos de baixo acoplamento à Livon (só livon_user_id), escopados por tenant
Produzir e preservar a prova legal — atas assinadas, imutáveis e auditáveis a partir de reuniões com quórum
Firmar e implementar o contrato bidirecional com a Livon (consumir + legar) que destrava a apuração eleitoral
Conduzir eleições NR-5 com voto secreto real, apuração determinística e gestão completa de mandato (incluindo designado)
Engajamento e conformidade com a Lei 14.457 — comunicados com ciência afirmativa, SIPAT anual e canal anônimo de assédio
IA assistiva isolada na camada app, nunca autoritativa, com salvaguardas LGPD
Visão Unificada
O que é a CIPA?
É a comissão eleita pelos próprios colegas para cuidar da segurança no trabalho. Pense num 'conselho de segurança' interno, obrigatório por lei (NR-5), que se reúne, registra atas e propõe melhorias.
Por que um sistema separado?
Em vez de mexer na casa principal (a plataforma Livon), construímos um puxadinho especializado ao lado, com sua própria fechadura e seu próprio armário (banco). Os dois conversam por uma ponte (API) — mais seguro e fácil de evoluir.
A ata como cofre lacrado
Quando a ata é assinada, o sistema gera um 'lacre digital' (hash SHA-256). A partir daí vira documento de cartório: ninguém edita. Se precisar corrigir, anexa-se uma nova versão e a antiga fica preservada.
Voto secreto de verdade
São duas urnas separadas: uma lista de quem votou (para garantir voto único) e outra com os votos sem nome. Ninguém consegue juntar as duas — o sigilo é real, não só uma tela escondida.
Eleição por tamanho da empresa
O Quadro I da NR-5 é uma tabela que decide quantos membros a CIPA terá, conforme o número de funcionários e o grau de perigo do ramo. O sistema calcula isso automaticamente.
Caixa-preta do avião
Como a caixa-preta registra tudo num voo, a observabilidade grava cada passo do sistema (rastros, logs, métricas). Se algo falhar numa apuração ou ata, dá para reconstituir o que aconteceu.
Canal de denúncia anônimo
A Lei 14.457/2022 exige um canal anônimo contra assédio. É como uma caixa de correio lacrada: a pessoa denuncia sem se identificar e fica protegida de retaliação.
IA como estagiário
A inteligência artificial escreve rascunhos (de ata, de classificação), mas nunca assina nem aprova nada. Um humano sempre revisa e decide — a IA é assistente, jamais autoridade.