Modulo Protocolo
Primeiro modulo de negocio entregue. Serve como prova de uso real do GovON: um cidadao protocola uma solicitacao, a secretaria movimenta o protocolo, anexa documentos, conclui ou arquiva. Cada acao gera auditoria, respeita tenant, mascara CPF/email em respostas e enfileira notificacao.
Endpoints
| Metodo | Path | Permissao | Resumo |
|---|---|---|---|
| POST | /protocolo | protocolo.criar | Cria protocolo com numero AAAA/NNNNNN sequencial por municipio. |
| GET | /protocolo | protocolo.ler | Lista paginada do municipio ativo. CPF mascarado em response. |
| GET | /protocolo/:id | protocolo.ler | Detalhe + movimentacoes + anexos. CPF/email mascarados. |
| POST | /protocolo/:id/movimentacoes | protocolo.movimentar | Registra movimentacao em transaction, opcionalmente atualiza status, enfileira notificacao. |
Todas as rotas exigem JWT valido (default-deny via PermissionGuard). Sem token, qualquer chamada devolve 401 AUTH_REQUIRED.
Modelo de dados
Protocolo
| Campo | Tipo | Observacao |
|---|---|---|
| id | uuid | PK |
| municipioId | uuid | tenant scope, FK Municipio |
| numero | string | AAAA/NNNNNN sequencial por municipio/ano (unico por municipio) |
| assunto | string | titulo curto |
| descricao | text | corpo livre |
| requerenteNome | string | — |
| requerenteCpf | string | LGPD: mascarado em todas as respostas (maskCpf) |
| requerenteEmail | string? | LGPD: mascarado em listagens (maskEmail) |
| status | enum | ABERTO | EM_ANDAMENTO | CONCLUIDO | ARQUIVADO |
| abertoPor | uuid | FK Usuario que criou |
| createdAt | timestamp | — |
Movimentacao
| Campo | Tipo | Observacao |
|---|---|---|
| id | uuid | PK |
| protocoloId | uuid | FK Protocolo |
| acao | enum | DESPACHO | RESPOSTA | TRANSFERENCIA | CONCLUSAO | OUTRA |
| descricao | text | corpo da movimentacao |
| statusNovo | enum? | se preenchido, atualiza protocolo.status na mesma transaction |
| atorId | uuid | FK Usuario que registrou |
| createdAt | timestamp | — |
Anexo
| Campo | Tipo | Observacao |
|---|---|---|
| id | uuid | PK |
| protocoloId | uuid | FK Protocolo |
| nomeOriginal | string | LGPD: retencao 3650 dias |
| mimeType | string | validado pelo UploadHandler |
| tamanho | int | bytes |
| hashSha256 | string | integridade |
| storageKey | string | LocalFileStorage hoje (parcial) |
| createdAt | timestamp | — |
Politica LGPD declarada
De modules/protocolo/module.json:
Protocolo.requerenteCpf: identificacao do requerente, retencao 1825 dias (5 anos). Mascarado viamaskCpfem listagens; valor completo so para usuarios comcore.usuario.gerenciar+protocolo.ler.Protocolo.requerenteEmail: contato, retencao 1825 dias. Mascarado viamaskEmailem listagens publicas.Anexo.nomeOriginal: rastreabilidade, retencao 3650 dias (10 anos).
Auditoria
Toda mutacao em Protocolo, Movimentacao e Anexo gera registro em AuditLog via AuditInterceptor global. Campos sensiveis no payload de auditoria sao serializados ja mascarados. Nenhuma movimentacao cross-tenant e possivel: o service usa scopedWhere e scopedData, e o middleware exige TenantContext ativo.
Fluxo de notificacao (Jobs)
POST /protocolo/:id/movimentacoes
|
v
ProtocoloService.movimentar()
|
+-- prisma.$transaction([
| movimentacao.create(...), -- sempre
| protocolo.update(status) -- se statusNovo presente
| ])
|
+-- (fail-soft) enqueue protocolo.notificar
{
protocoloId, numero,
requerenteEmail, acao,
descricaoCurta, statusNovo
}
apps/api/src/worker.ts (BullMQ)
- retry 5x, baseDelay 2000ms
- logs estruturados por attempt
- hoje so loga; stub de email/SES previsto no roadmapEm demo, o worker dedicado ainda nao esta deployed como servico (limite plano free). Isso faz o enqueue ficar pendente no Redis ate o worker subir — sem erro 5xx para o usuario, mas notificacao nao chega. Declarado em Status da demo.
Permissoes registradas
protocolo.criarprotocolo.lerprotocolo.movimentarprotocolo.anexarprotocolo.concluirprotocolo.arquivar
UI no Admin
- https://app.govon.com.br/protocolos — lista com filtro de status + CPF mascarado
- https://app.govon.com.br/protocolos/novo — criacao
https://app.govon.com.br/protocolos/[id]— detalhe com nova movimentacao + historico + anexos
Como testar via API
# 1) login
curl -X POST https://api.govon.com.br/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@govon.demo","password":"..."}'
# -> { data: { token: "eyJ..." } }
# 2) criar
curl -X POST https://api.govon.com.br/protocolo \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"assunto":"IPTU 2026",
"descricao":"Solicito segunda via",
"requerenteNome":"Joao da Silva",
"requerenteCpf":"111.444.777-35"
}'
# -> { data: { numero: "2026/000001", requerenteCpf: "111.***.***-35", ... } }
# 3) movimentar
curl -X POST https://api.govon.com.br/protocolo/<id>/movimentacoes \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"acao":"DESPACHO","descricao":"Enviado para SEFIN","statusNovo":"EM_ANDAMENTO"}'Testes
- 13 unit tests do
ProtocoloService(mock Prisma) — cobrem criacao/listagem/detalhe/movimentacao + mascara + cross-tenant + validacoes - 1 suite E2E em
tests/e2e/protocolo.spec.ts— happy path + 401 + cross-tenant rejeitado
Limitacoes conhecidas
- Worker
protocolo.notificarnao consumindo em demo (item declarado em /status-da-demo). - Upload usa
LocalFileStorageem disco do container (perde em restart). Driver S3 implementado em@govon/upload, plug-in no modulo previsto no roadmap. - Nao ha export PDF/CSV de protocolos ainda. Quando entrar, vai exigir trilha em
AuditLog(regra 24).
Referencias
modules/protocolo/module.jsonmodules/protocolo/audit.jsonmodules/protocolo/openapi.yamlapps/api/src/modules/protocolo/apps/api/prisma/migrations/20260513200000_add_protocolo/- Padrao geral de modulos