main <- release #2

Merged
caio merged 29 commits from release into main 2026-10-08 21:24:00 -03:00
Owner
No description provided.
caio added 29 commits 2026-10-08 21:16:49 -03:00
Causa raiz do exemplo da issue (grupo_acesso_detalhe.php): <select> sem
max-width definido é dimensionado pelo navegador conforme o texto da
opção mais longa (ex: "chave — descrição longa da permissão"), estourando
o card/página inteira. Mesmo padrão encontrado em mais 17 páginas do
painel e do ikarus37 — todas corrigidas com select { max-width: 100%; }
(ou 220px fixo em retirada_marcar.php, onde o select de motivo fica
dentro de célula de tabela sem largura própria).

Também dois casos de <table> sem .scroll-x (grupos.php, backup.php) —
adicionado o wrapper, mesmo padrão já usado no resto do sistema.

Testado visualmente no Docker local: página exata da issue (dark theme,
desktop e mobile) e o select de motivo em retirada_marcar.php, ambos
confirmados contidos no container em vez de estourar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- mysqli_report(MYSQLI_REPORT_OFF) em conectarBanco() (config.php,
  config.example.php, config.docker.php): no PHP 8.1+ o modo de exceção
  padrão do mysqli fazia um erro de chave duplicada derrubar a página
  com uma mysqli_sql_exception não tratada, sem nunca chegar no tratamento
  de erro que já existia no código.
- core/dominio_core.php: valida duplicidade de nome/chave/ordem antes de
  gravar (nova config 'unicos' por entidade — grupos_acesso.nome,
  cargos.(sistema+chave), motivos_falta.(nome, ordem),
  dispensa_tipos.(nome, ordem)), com mensagem amigável em vez do erro cru
  do banco; fallback genérico para qualquer restrição não coberta.
- core/acesso_negado.php (novo): tela padrão de acesso negado, substitui
  os die() crus e sem estilo em todo ponto de checagem de permissão do
  Painel e do Ikarus37.
- web/painel/dominio.php, web/ikarus37/dominio.php: deixa claro que
  "excluir" em entidades com coluna ativo é uma desativação (soft
  delete), não remoção definitiva — botão vira "Desativar", confirmação
  explica o comportamento, e registros inativos (quando "Mostrar
  inativos" está ligado) ganham indicação visual (opacidade + badge).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Corrige UX/erros do Controle do Domínio de Negócio (issue #28)
listarMotivos() — usada tanto pela chamada do painel quanto pelo app do
aluno (api/motivos.php) pra escolher o motivo de uma falta — passa a
excluir motivos com classificacao='presente'. Não faz sentido justificar
uma falta com um motivo que significa "estava presente"; o cadastro do
motivo em si (Controle do Domínio de Negócio) continua intacto, só a
lista oferecida na hora de marcar falta muda.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Remove opção "Presente" da lista de motivos de falta (issue #29)
- core/dispensas_core.php: data de início da dispensa agora precisa estar
  dentro de uma janela de -7/+30 dias em torno de hoje (DISPENSA_TOLERANCIA_*)
  — barra tanto período já totalmente expirado há meses (ex: um ano digitado
  errado) quanto período marcado pra um futuro distante sem vínculo com nada
  agendado. Ainda permite lançar com atraso de alguns dias e cadastrar
  procedimento agendado com até 1 mês de antecedência.
- Nova checagem de duplicidade: mesma combinação aluno + data_inicio +
  data_termino + motivo já cadastrada é bloqueada com mensagem amigável,
  tanto em criarDispensa quanto em atualizarDispensa.
- web/painel/dispensas.php, web/painel/retirada_marcar.php: input de data de
  início ganha min/max no HTML refletindo a mesma janela, pra feedback
  imediato no navegador.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Valida janela de datas e bloqueia dispensa médica duplicada (issue #30)
Nova entidade turmas (não é catálogo fixo — nome/apelido é o
identificador, porque pode haver mais de uma turma do mesmo curso/série
ao mesmo tempo, ex: duas CFS na mesma série como na época do Covid):

- database/migration_013_turmas.sql, database/init_db.sql: cria a tabela
  turmas (nome, curso, série, ingresso, formatura prevista, esquadrão
  atual) e alunos.turma_id (FK opcional); semeia as 5 turmas atuais
  (Fera Azul, Invictus, Ikarus, Warhank, Valhalla); nova permissão
  gerenciar_turmas (mesmos cargos de gerenciar_dominio — CMD_CA/
  SUBCMD_CA — por ser decisão de nível CA, não de esquadrão).
- core/turmas_core.php (novo): CRUD com validação de nome duplicado e
  série compatível com o curso, e formarTurma() — desativa a turma E
  todos os alunos ainda ativos vinculados a ela numa única ação (soft
  delete, nada é apagado).
- core/alunos_core.php: turma_id passa a ser aceito em criarAluno,
  atualizarAluno (API) e atualizarAlunoParcial (painel), e listarAlunos
  ganha o filtro turma_id.
- web/painel/turmas.php (novo): cadastrar turma vazia, editar, e "Formar
  turma" com confirmação mostrando quantos alunos serão desativados
  junto. Alunos entram na turma depois, pelo Efetivo (select novo em
  efetivo_editar.php) ou pela importação em lote existente.

Testado no Docker local: nome duplicado e série inválida rejeitados,
aluno de teste vinculado a turma e formarTurma desativando os dois numa
tacada, ordenação da lista por urgência de formatura (corrigido um bug
encontrado no teste: turma sem data de formatura definida ordenava antes
das que já têm data próxima). Dados de teste apagados depois.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adiciona cadastro e "formatura" de turmas (issue #32)
Atribuir turma aluno por aluno em efetivo_editar.php não escala pra uma
turma de 150+ alunos — issue #32 pedia especificamente "alguma forma
simples". Agora dá pra filtrar o Efetivo (esquadrão/esquadrilha/
especialidade/turma), marcar vários alunos (ou "selecionar todos") e
atribuir (ou remover) a turma de todos de uma vez.

- core/alunos_core.php: nova atribuirTurmaEmLote() — UPDATE em lote por
  lista de ids, reforçando o escopo de esquadrão de quem está logado
  (um POST manipulado não consegue mexer em aluno fora do esquadrão de
  um CMD_ESQUADRAO/ENC_ESQUADRAO); listarAlunos() ganha o filtro
  turma_id e passa a trazer turma_nome (LEFT JOIN turmas).
- web/painel/efetivo.php: filtro de turma, coluna "Turma" na listagem,
  checkboxes + "selecionar todos" + select de turma + botão "Atribuir
  turma", tudo atrás de podeEditarEfetivo() (mesma permissão que já
  gate­ava a edição individual).

Testado no Docker local contra a base real (1001 alunos): atribuição em
lote, bloqueio por escopo de esquadrão incorreto, remoção em lote, e a
coluna Turma refletindo o join corretamente. Dados de teste apagados
depois.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adiciona atribuição de turma em lote na tela de Efetivo
Cadastrar uma turma inteira aluno por aluno não é "simples" como a
issue #32 pediu, e não existia nenhuma tela no Painel pra criar aluno
(só o importador CSV cru do Ikarus37, que é ferramenta técnica). Agora,
a partir de Turmas, cada turma ativa ganha um link "Cadastrar alunos"
pra uma tela dedicada:

- core/alunos_core.php: cadastrarAlunosEmLote() — recebe texto colado
  (uma linha por aluno, campos separados por TAB ou ";", formato
  planilha) e cria cada aluno já com curso/série/turma_id da turma em
  comum, retornando quantos entraram e o motivo de cada linha que
  falhou (linha incompleta, duplicidade etc.) sem interromper as
  demais. listarPostosGraduacao() novo, auxiliar.
- web/painel/turma_cadastrar_alunos.php (novo): formato documentado na
  própria tela com exemplo, campo de esquadrão da leva (trava no
  esquadrão de quem tem escopo restrito), textarea de colagem, e
  relatório de sucesso/erro por linha depois de enviar.

Testado no Docker local: leva com aluno duplicado e linha incompleta
(rejeitados individualmente, resto cadastrado normalmente) via chamada
direta e via a tela de verdade no navegador — 2 alunos de teste
cadastrados, vinculados à turma e ao esquadrão corretos, depois
apagados.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cadastro em lote de alunos novos de uma turma
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adiciona ícone no botão Formar turma
- .i (ícone inline em botões/links) sobe de 13px pra 16px em todo
  web/painel/*.php e web/ikarus37/*.php — pedido explícito do usuário
  depois de ver o 3sgt.svg pequeno demais no botão "Formar turma".
- Todo botão que ainda não tinha ícone ganhou um condizente com a ação
  (Criar/Cadastrar → plus, Salvar → device-floppy, Excluir/Remover/
  Revogar → trash, Adicionar membro → user-plus, Conceder permissão →
  shield-check, Entrar → login, redefinir senha → key, Baixar PDF →
  printer, Gerar → refresh, Enviar chamada → send, Atribuir turma →
  school), cobrindo turmas.php, turma_cadastrar_alunos.php, efetivo.php,
  efetivo_editar.php, dispensas.php, dominio.php (painel + ikarus37),
  grupo_acesso_detalhe.php (painel + ikarus37), grupos.php, index.php,
  dashboard.php, permissoes_cargo.php (painel + ikarus37),
  retirada_marcar.php, retirada_nova.php, usuarios.php.
- livro_do_dia.php ganhou a classe .i que faltava por completo nesse
  arquivo (o ícone do link "painel" já usava a classe, mas ela nunca
  tinha sido definida ali — ficava invisível).
- 8 ícones novos copiados de icons-source/outline pra web/images/icons/:
  device-floppy, key, login, printer, refresh, send, shield-check,
  user-plus.

Testado visualmente no Docker local (turmas.php) — ícones nitidamente
maiores e consistentes entre os botões.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Aumenta ícones e adiciona ícone em todos os botões do Painel/Ikarus37
Nova PWA instalável em web/app/ usando a API já pronta desde a issue #26
(login por QR Code, listar efetivo do esquadrão, abrir/marcar/enviar
retirada) — fecha o ciclo de digitalizar a retirada de faltas direto do
celular do aluno de serviço, sem depender do Painel.

A landing page (web/index.html) ganha uma seção de acesso com links para
Painel, Ikarus37 e Área Funcional, e corta o conteúdo que ficou redundante
ou desatualizado (funcionamento passo a passo e roteiro futuro).
Sem isso, POST para /api/sessao.php a partir da Área Funcional retornava
501 no ambiente Docker (a chave não existia em nenhum lugar acessível ao
container) — reaproveita a chave legada já seedada em init_db.sql, então
funciona direto com docker-compose up, sem passo manual local.

Testado ponta a ponta contra o Docker: login por QR, abrir retirada,
marcar falta e enviar chamada (protocolo gerado) — dados de teste
removidos após a verificação.
O app usava '/api/' fixo e o manifest/service worker caminhos absolutos
(/app/). Em produção o site fica em /cidit/projetos/11/, então o login da
PWA ia bater em sigsaeear.com/api/ e falhar.

- env.php calcula a base da API a partir de onde está publicado
  (window.ARGOS_API_BASE) e o app.js usa ela
- manifest com start_url/scope/id relativos
- service worker reconhece /api/ em qualquer subdiretório (cache v2)
- motivo de falta salvo volta selecionado (id do motivo vinha como string)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Produção não aceita conexão de fora no banco, então o deploy sobe um
endpoint temporário (_deploy/, protegido por token gerado a cada deploy)
que faz backup e aplica as migrations de dentro da aplicação, e é apagado
no fim.

- deploy/migracoes.php: controle em schema_migrations; na 1ª vez detecta
  a baseline pelo que cada migration legada criou
- deploy/backup.php: dump completo em _backups/, protegido mesmo se o
  servidor ignorar .htaccess
- scripts/deploy/deploy-producao.sh: confere o destino, liga manutenção
  (.htaccess + páginas de entrada), backup, apaga a versão anterior
  preservando config.php, sobe a nova, migra, smoke test e reabre
- scripts/release/gerar-pacote.sh: git archive + core/versao.php gerado
  com tag/commit/data (database/, testes e ferramentas ficam de fora)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests/integracao_test.php exercita pelo HTTP o fluxo da Área Funcional:
login por QR, isolamento entre esquadrões, abrir/marcar/enviar retirada,
regra da dispensa médica, manifest, service worker e env.php — além das
páginas de login sem erro de PHP. tests/smoke_producao.php é a versão
somente leitura, segura pra rodar contra produção.

scripts/ci/ instala dependências, faz lint (sintaxe, segredos versionados)
e roda migrations + testes contra um MySQL 8 descartável.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ci.yml: lint + testes nos runners ubuntu-latest e debian em todo push/PR
- release.yml: tag vX.Y.Z na main → testes → deploy por FTP → Release no
  Forgejo com notas e zip; disparo manual re-publica uma tag (rollback)
- smoke-producao.yml: substitui o workflow do GitHub, agora somente
  leitura e conferindo também a chave da PWA

Documentação do fluxo de branches, secrets, rollback e migrations em
docs/CI-CD.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Atualiza a logo do CIDIT
All checks were successful
CI / Lint (debian) (push) Successful in 21s
CI / Lint (ubuntu-latest) (push) Successful in 19s
CI / Testes (debian) (push) Successful in 52s
CI / Testes (ubuntu-latest) (push) Successful in 26s
CI / Lint (debian) (pull_request) Successful in 21s
CI / Lint (ubuntu-latest) (pull_request) Successful in 20s
CI / Testes (debian) (pull_request) Successful in 25s
CI / Testes (ubuntu-latest) (pull_request) Successful in 23s
82742cfde5
Nova logo definida na última reunião.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge pull request 'develop' (#1) from develop into release
All checks were successful
CI / Lint (debian) (push) Successful in 20s
CI / Lint (ubuntu-latest) (push) Successful in 21s
CI / Lint (debian) (pull_request) Successful in 20s
CI / Lint (ubuntu-latest) (pull_request) Successful in 20s
CI / Testes (debian) (push) Successful in 27s
CI / Testes (ubuntu-latest) (push) Successful in 25s
CI / Testes (debian) (pull_request) Successful in 25s
CI / Testes (ubuntu-latest) (pull_request) Successful in 25s
552a8d5934
Reviewed-on: #1
caio changed title from WIP: main <- release to main <- release 2026-10-08 21:23:55 -03:00
caio merged commit 4c5412181e into main 2026-10-08 21:24:00 -03:00
Sign in to join this conversation.
No description provided.