SGG - Sistema de Gestão de Gabinete
Schema: v4 + Blocos 2-14 + Hotfix 10.1/10.2/10.1.1 + 11.1/11.2 + Geo 1.0/1.1
+ Storage Refactor + Geo Territorial/Completo + CEP + Bloco 12
+ Hotfix 12.1 + Bloco 13 + Bloco 14 + Hotfix UX 14.1 + 14.2
+ Importação de Cidadãos + Hotfix 14.2.1 (Demanda Rápida: câmera Android + preview)
+ Hotfix Título de Mídia (protocolo prefixado + migration 019)
+ Hotfix 14.2.2 (Câmera Android/Samsung A07: inputs estáticos especializados)
+ Bloco Registro de Evolução da Demanda (Situação inicial/final + migration 020)
+ Hotfix Complementação Evolução (resultado/status, observação visível, metadados de mídia, permissão equipe_rua, flash de erro, limite de mídias)
+ Bloco 15 — Central de Comunicação e Marketing (migration 021)
+ Bloco 16 — Consolidação da Plataforma / Auditoria Geral v1.0
+ Hotfix 16.1 — Cadastro Rápido de Cidadão na Demanda Rápida (modal AJAX)
+ Hotfix 16.1.1 — Correção definitiva do modal Novo Cidadão (cascata CSS × atributo hidden)
+ Hotfix 16.1.2 — Complementação do Cadastro Rápido de Cidadão
+ Hotfix 16.1.3 — Atualização do Modelo de Importação de Cidadãos
+ Hotfix 16.1.5 — Filtros avançados na listagem de cidadãos
+ Hotfix 16.1.6 — Busca inteligente e localização avançada de cidadão na
Demanda Rápida
+ Hotfix 16.1.7 — Quantidade de cidadãos por página
+ Hotfix 16.1.7.1 — Aplicação automática da quantidade por página
(este release)
Bloco 14 — Inteligência do Gabinete:
- Nova área /intelligence (protegida por reports.view) que transforma dados
existentes em decisão, sem criar cadastros.
- Indicadores executivos: demandas abertas/resolvidas/atrasadas/vencendo,
visitas, tarefas abertas/vencidas, cidadãos, por mês e por categoria.
- Ranking de bairros (reusa Territory::byNeighborhood) e de secretarias/órgãos
(novo: total, abertas, resolvidas, atrasadas, tempo médio de resolução).
- Produtividade por assessor (demandas atribuídas/resolvidas/atrasadas, visitas,
tarefas) e filtro individual por assessor.
- Heatmap de demandas (reusa leaflet.heat + Territory::heatPoints; coordenada da
demanda, depois do bairro, depois centro de Uberlândia).
- Metas mensais simples (demandas resolvidas, visitas, tarefas) com realizado e
percentual — nova tabela goals (migration 018).
- Botão "🚗 Abrir no Waze" na tela da demanda (coordenada da demanda ou do
bairro; some quando não há coordenada). Botão "Ver no mapa" preservado.
- Item de menu "Inteligência do Gabinete" na seção Gestão.
- Nenhuma tela existente removida; SLA, demanda tradicional, demanda rápida e
mapa intactos. Total de tabelas: 53 (52 + goals).
Hotfix UX 14.1 — Bottom Navigation profissional (mobile):
- Barra inferior redesenhada: Painel · Demandas · [Nova Demanda] · Cidadãos · Mais.
- Botão central flutuante (FAB) circular 64px, elevado, sombra, cor do sistema,
ícone de raio + texto "Nova Demanda", abrindo /demands/quick (rota existente).
- Item "Demanda Rápida" removido da barra (substituído pelo FAB central).
- Menu "Mais": bottom sheet que abre de baixo para cima com Perfil, Agenda,
Documentos, Aniversários, Mapa, Relatórios, Configurações e Sair — cada item
respeita as permissões existentes. Sair via POST+CSRF.
- safe-area-inset-bottom (sem sobreposição com notch), área de toque >=44px,
suporte a tema claro/escuro. Apenas front-end: sem mudança de banco, rotas,
permissões ou regras de negócio.
Hotfix UX 14.2 — Refino final mobile/PWA (iPhone/Safari):
- Safe-area da barra inferior com max(10px, env(safe-area-inset-bottom)) e
espaço final do conteúdo calc(96px + safe-area) — botões finais não ficam
mais escondidos atrás da barra nem colidem com os controles do Safari.
- Botão central "Nova Demanda" refinado (alinhamento, toque >=64px, sem corte).
- Bottom sheet "Mais": altura máxima 80vh com scroll interno, header com título
e botão X, fecha por toque fora/ESC/X, respeita a safe-area. Itens novos:
Cargos e Permissões e Auditoria (quando permitido). Sair segue POST+CSRF.
- Meta tags PWA Apple (apple-mobile-web-app-capable/status-bar-style/
mobile-web-app-capable); viewport-fit=cover preservado sem duplicar.
- Apenas layout/CSS/JS. Sem mudança de banco, rotas, permissões ou regras.
Data: 2026-06-24
Módulo Importação de Cidadãos por Planilha (CSV):
- Nova área /citizens/import (permissão citizens.create) com botão na listagem.
- Download de modelo CSV (UTF-8, separador ';', com linha de exemplo).
- Upload .csv (máx 5MB, máx 5000 linhas, MIME básico, cabeçalhos obrigatórios).
- Validação por linha: nome obrigatório, e-mail, data (DD/MM ou DD/MM/AAAA),
bairro existente, telefone normalizado; dedup interno e contra o banco.
- Prévia em sessão (sem tabela nova) com resumo e status por linha (OK/ERRO/
DUPLICADO) e motivo. Confirmar importa só os válidos; cancela limpa.
- Origem "Importação" garantida com slug='importacao' (busca por slug, insere
slug/name/is_active/sort_order). SEM fallback: se não garantir a origem, NÃO
importa e mostra erro claro.
- Reaproveita Citizen::create e ConsentLog; consent_channel=importacao; auditoria.
- CSV nativo (fgetcsv), sem Composer/XLSX/Node. instagram->notes, whatsapp->phone.
Bloco — Registro de Evolução da Demanda (este release):
- "Mídias vinculadas" da tela da demanda passa a "Situação inicial"; mídias
antigas sem classificação são tratadas como 'initial' (backfill migration 020).
- Nova seção "Situação final" com Tirar foto / Gravar vídeo / Escolher da
galeria, preview, remoção individual e observação da situação final. Reusa
EXATAMENTE a arquitetura estática de câmera validada no Samsung A07 (inputs
especializados + input final único name="media[]" via DataTransfer; sem
input único com capture dinâmico). Mídias salvas com estágio 'final'.
- Título das mídias da situação final: "PROTOCOLO — Situação final — TÍTULO"
(reusa buildDemandMediaTitle; idempotente, não duplica protocolo).
- Observação geral da situação final: registrada no histórico auditável da
demanda (Demand::addComment + Audit::log). Descrição individual reusa
media_files.description. Nenhum campo semanticamente duplicado.
- Upload de "Anexos" movido visualmente para dentro de "Documentos" (tabela e
arquivos de attachments preservados). Documentos oferece "Gerar documento
desta demanda" e "Adicionar documento/arquivo". Seção isolada "Anexos" some.
- Nova coluna media_files.demand_stage VARCHAR(20) DEFAULT 'initial' + índice
idx_media_demand_stage (migration 020, idempotente). RBAC, storage externo,
Demanda Rápida, câmera Android/iPhone, mapa, Waze, agenda, tarefas e
comentários preservados e inalterados.
PHP: 8.0+ Banco: MySQL 8.0+ / MariaDB 10.4+
Hotfix 16.1.7.1 — Aplicacao automatica da quantidade por pagina (este release):
- Ajuste minimo: UM UNICO arquivo alterado (Views/citizens/index.php). SEM
migration, SEM banco, SEM controller, SEM model, SEM rota, SEM permissao e
SEM biblioteca externa.
- AUDITORIA: o listener de "change" do seletor JA EXISTIA desde o 16.1.7 e o
auto-submit ja funcionava. O botao "Aplicar" era apenas fallback sem
JavaScript e vinha sendo OCULTADO por JS (go.hidden = true) — no celular ele
extrapolava a largura da tela antes de ser escondido.
- 4 REMOCOES DE CODIGO: (1) o elemento
foi REMOVIDO do HTML, nao ocultado por CSS; (2) a regra CSS orfa
.cz-perpage__go; (3) a variavel "go"; (4) a linha go.hidden = true.
- O listener de "change" NAO foi tocado nem duplicado: continua sendo o UNICO,
garantindo 1 alteracao = 1 submissao. Sem setTimeout, sem workaround.
- LARGURA NO MOBILE (media query <=600px): o bloco do seletor caiu de ~318px
para ~234px. Num iPhone SE (320px, ~288px uteis) ele ESTOURAVA e agora cabe
com folga; tambem cabe em 360px (Samsung A07), 390px e 412px. Preservados
min-height:44px, max-width:110px e order:3 — o select segue facil de tocar e
"Importar Planilha"/"Novo cidadao" seguem acessiveis. Nenhuma largura fixa em
px, nenhum position:fixed/z-index/overflow-x novo: navegacao inferior e
safe-area intactas.
- SEM JAVASCRIPT: conforme decidido para este hotfix, o fallback com botao NAO
foi recriado; sem JS o seletor permanece visivel, porem sem auto-submit.
- TESTES: php -l OK, node --check OK, 95 casos / 95 PASS — ausencia do botao no
DOM, no CSS e no HTML servido; 1 alteracao = exatamente 1 submissao (e o
evento "input" nao submete); as seis transicoes 250->25, 25->50, 50->100,
100->250, 250->500 e 500->25 submetendo com o per_page correto; "page"
ausente do formulario (retorno a pagina 1 a partir de um cenario real de 187
paginas); preservacao de busca, bairro, lideranca, consentimento e WhatsApp
isolados e combinados; as cinco quantidades ainda renderizando 25/50/100/250/
500 linhas; contador e intervalo preservados; larguras de 320 a 412px.
- NAO-REGRESSAO: diff -rq recursivo acusa 1 arquivo alterado (+ VERSION/
CHANGELOG), 0 novos e 0 removidos — 264 arquivos antes e 264 depois.
Citizen.php, CitizenController.php, routes.php, app.css, demands/quick.php,
citizens/form.php, citizens/import.php, config.php, .htaccess, database.sql,
sw.js e manifest.json byte a byte. Whitelist, padrao 250, filtros, busca,
paginacao, contador, chips e toggle de filtros preservados. Demanda Rapida,
autocomplete, modal Procurar, "+ Novo", camera, importacao, Central de
Comunicacao e PWA intactos.
Hotfix 16.1.7 — Quantidade de cidadaos por pagina:
- SEM migration, SEM alteracao de banco, SEM rota nova, SEM permissao nova,
SEM indice novo e SEM biblioteca externa. Apenas 3 arquivos alterados:
Models/Citizen.php, Controllers/CitizenController.php e
Views/citizens/index.php.
- LIMITE ANTERIOR: 20 registros por pagina. O controller chamava
Citizen::paginate($filters, $page) SEM o 3o argumento, herdando o default do
model. Com 1.600+ cidadaos reais isso dava ~81 paginas.
- PARAMETRO GET: per_page (nao havia convencao previa no sistema).
Whitelist explicita Citizen::PER_PAGE_OPTIONS = [25, 50, 100, 250, 500] e
padrao Citizen::PER_PAGE_DEFAULT = 250.
- VALIDACAO NO SERVIDOR: normalizePerPage() so aceita inteiro ou string de
digitos puros e confronta com in_array estrito. Qualquer outro valor — 0, -1,
1, 20, 999, 999999, abc, 1e3, 25.5, 0x19, 250abc, "25 OR 1=1",
"25' OR '1'='1", "25;DROP TABLE citizens", array, bool — cai em 250. O