DEC-061 - 2026-06-22 - accepted
Refatoração dinâmica do módulo Forms com html-editor (req-049 / BATCH-049). Decisões desta rodada:
-
Forms passa a seguir o padrão dos widgets visuais: a tabela
formsrecebehtml,css,css_compiledehtml_extra_head; o CRUD administrativo usahtml_editor_componentecom alvoforms; e o template selecionado é preservado com a opção-modificadoquando há código customizado no banco. -
fields_schemapermanece como contrato estruturado único: metadados gerais, e-mail, redirects, limites, reCAPTCHA efields[]são serializados pelo JS emfields_schema, preservando retrocompatibilidade com a coluna JSON existente e evitando criar tabelas auxiliares neste slice. -
Renderização pública baseada em loop de campos:
forms.widget.phpprocessa o bloco<!-- item < --> ... <!-- item > -->, resolve[[item#label]],[[item#name]],[[item#placeholder]],[[item#type]],[[item#required]],[[item#options]]e aplica blocos condicionaistype-input,type-textareaetype-select. Recursos de CSS/head usamgestor_pagina_recursos_incluir(), mantendo o HTML retornado limpo. -
Parâmetro público preferencial
form_id: o wrapper de widget usaforms->render({"form_id":"slug"}), mas o renderer aceita tambémgrupo_slug/idcomo fallback para compatibilidade com mecanismos genéricos.
DEC-062 - 2026-06-22 - accepted
Correções do visual editor, colisão de abas e novos templates para Forms (req-050 / BATCH-050). Decisões desta rodada:
-
Parâmetro de escape HTML na renderização do editor: Introduzir o parâmetro opcional
html_specialcharsnohtml_editor_componente(). Quando habilitado, o backend escapará os placeholders#pagina-html#e#pagina-html-extra-head#viahtmlspecialchars()para evitar o encerramento precoce de tags<textarea>no HTML original. O CodeMirror decodificará as entidades automaticamente no DOM ao ler a propriedade.valuedo<textarea>. -
Isolamento de abas aninhadas via context no JS: Corrigir o bug que faz os menus de abas desaparecerem ao clicar na sub-aba "Widget". Isolar o escopo do menu externo
menuFormsusandocontext: 'parent'e o escopo do menu internomenuFormsTemplateusandocontext: '[data-tab="forms-template"]', impedindo que a ativação da aba "Widget" oculte a aba pai "Template". -
Criação de novos templates baseados em Tailwind CSS: Desenvolver 4 novos modelos de formulário (Newsletter, Registro de Usuário, Pesquisa de Satisfação e Suporte Técnico) duplicados em português e inglês (totalizando 8 novos registros), todos utilizando Tailwind CSS e a mesma estrutura dinâmica de repetição do widget (
<!-- item < -->). -
Execução local do compilador de recursos: Após registrar os templates físicos no manifest, executar
atualizacao-dados-recursos.phppara recalcular checksums e dados derivados, mantendo o padrão do projeto de não editar checksums manualmente.
DEC-063 - 2026-06-22 - accepted
Escape HTML global no editor e separador de valor/rótulo nos selects do Forms (req-051 / BATCH-051). Decisões desta rodada:
-
Comportamento global de escape HTML no editor: Tornar o escape de tags HTML e HTML Extra Head o padrão no
html_editor_componente()se$htmlou$html_extra_headforem informados no array$params, removendo a necessidade do parâmetro explícitohtml_specialchars. -
Limpeza do parâmetro no módulo Forms: Remover a linha
'html_specialchars' => trueda chamada emforms.php, já que a passagem dehtml/html_extra_headno$paramspassará a ativar o escape por padrão. -
Mapeamento de Valor e Rótulo nos Selects: Atualizar
forms_widget_options_html()no backend para interpretar a sintaxe de divisão de valor e rótulo em strings de opção (usando os caracteres separadores|e:). Se contiver o separador, a parte esquerda viravaluee a direita viralabel. Caso contrário, mantém-se o mesmo comportamento de usar o valor total para ambos. -
Radio e checkbox compartilham o contrato de opções: Reaproveitar
optionse os blocos condicionais do template para renderizarradioecheckbox, evitando criar uma segunda estrutura de schema. No HTML público,checkboxusaname[]para permitir múltiplos valores. -
CRUD mostra opções só para tipos com lista: A textarea de opções no administrativo fica visível apenas para
select,radioecheckbox; ao trocar para tipo simples, o valor é limpo para evitar que opções antigas fiquem persistidas no schema.
DEC-064 - 2026-06-23 - accepted
Sincronização Declarativa de Recursos, Deleção e Atualização Forçada — Módulos e Globais (req-056 / BATCH-056). Decisões desta rodada:
-
configcomo objeto OU array de objetos:normalizarConfigTabela()passa a retornar uma LISTA de configurações normalizadas; um objeto único é convertido internamente em array de 1 elemento. Cada elemento pode nomear sua tabela viatabela_nome(default =tabela.nomedo bloco), permitindo que um único blocotabela.configdeclare N tabelas. As listasdeletar/forcar_atualizacaopodem vir dentro de cada elemento de config ou no nível do bloco (este último herdado apenas quando a tabela coincide com o nome do bloco — retrocompat com BATCH-029). -
Coleta unificada (
coletarConfigsTabelas): novo motor compartilhado porgerarSchemaMetadata()(contrato) e porcoletarRecursos()(varredura dinâmica), mantendo a ordem determinística núcleo→global→módulos e o contexto de varredura (scope/modulo/base_dir/inline). O contratoschema-metadata.jsonganha o mapa de topoforcar_atualizacao(espelhandodeletar), consolidado/agregado por tabela; os campos de varredura/diretivas de recurso NÃO vão ao contrato (são build-time). -
Varredura declarativa de recursos (
sync_resources): tabelas comsync_resources:truegeram<PascalCase>Data.jsonautomaticamente. Metadados vêm de arquivo externo (metadata_file) ou inline (resources -> idioma -> tabela).field_typesconverte campos:json(json_encode) efile:<ext>(injeta<id>.<ext>sem BOM). Cada registro recebelanguage/status='A'/versao/user_modified=0+checksumMD5 (sobre arquivosfile:*ou payload) para reuso de versão entre deploys. Tabelas reservadas (as 9 fixas do pipeline) são puladas para não colidir com a geração existente. -
Atualização forçada no atualizador (
forcar_atualizacao): emsincronizarTabela(), registros que casam porpkounatural_keyignoram a proteção deprojecte a preservação deuser_modified(aplicam payload completo), resetamuser_modified=0quando era 1, e preservam o valor deproject(não alteram/limpam). Aplicado nos três caminhos de update (PK, chave natural e fallback de linguagem ausente). -
tables_config.jsonglobal apenas documentado: o arquivo global manteve as 4 tabelas existentes (configobjeto, retrocompat) e teve o_commentestendido para descreverconfigobjeto/array,tabela_nomee os novos parâmetros — sem fabricar tabela nova (não havia requisito de produto para isso). -
Cobertura de teste: novo
tests/Unit/PHP/ForcarAtualizacaoTest.php(PDO SQLite + contrato temporário) blinda os 4 cenários (forçado por chave natural, forçado por PK, preservação normal, proteção de projeto). Correção colateral: interpolação${var}obsoleta (PHP 8.4) ematualizacoes-banco-de-dados.phptrocada por{$var}(exposta pela inclusão do arquivo no PHPUnit).
DEC-065 - 2026-06-24 - accepted
Correção de Tipagem e Validação de Perfil Anônimo em Menus Condicionais (req-057 / BATCH-057). Decisões desta rodada:
-
Normalização de Usuários Anônimos em Array: Normalizar
$perfil_usuarioparafalsequando este for fornecido como um array cuja chaveidé'_anonimo'ou cuja chaveid_usuariosresolva para0. Isso garante o alinhamento com a lógica que esperafalsepara usuários não autenticados e resolve falhas de asserção em testes de visibilidade pública. -
Prevenção de Warnings de Conversão: Evitar a conversão implícita de array para string (
(string)$perfil_usuario) na resolução do$user_profile_idquando$perfil_usuariofor um array. O identificador correto deve ser extraído de$params['_profile_slug'](caso exista) ou da chaveid_usuarios_perfisdo próprio array de perfil, eliminando os warnings do PHPUnit e permitindo o correto casamento de condições de perfis com múltiplos IDs permitidos.
DEC-066 - 2026-06-25 - accepted
Sistema de Recuperação e Engenharia Reversa de Recursos (Pull System) (req-058 / BATCH-058). Decisões desta rodada:
-
Reuso da exportação reversa existente, não recriação: a função
reverseExport($pdo, $tabelas, $dataDir)(e os helpersdb()/schemaMetadata()/tabelaFromDataFile()) já existiam ematualizacoes-banco-de-dados.php(modo--reverse). O endpoint_api/project/recovere o controlador servidor apenas as orquestram, incluindo o atualizador comdefine('SDD_NO_AUTORUN', true)para reaproveitar as funções sem disparar o deploy. O endpoint gera o dump bruto num diretório temporário, compacta os*Data.jsonviaZipArchivee faz stream comContent-Type: application/zip, limpando o disco em seguida. -
Layout físico PLANO no descompilador (simetria com o compilador): os arquivos
file:<ext>são gravados em<base_dir>/<lang>/<resources_dir|tabela>/<id>.<ext>(sem subpasta por id) e os metadados externos semresources_dirficam em<lang>/<metadata_file>. A prosa do intake §2.1 sugeria<id>/<id>.<ext>, mas isso quebraria o round-trip — o compilador (processarRegistroDinamico/lerMetadadosDinamicos) lê o layout plano. Seguiu-se o código (mesmo precedente do BATCH-056). Orecover-project.shrecompila os recursos após a descompilação justamente para garantir consistência total dos*Data.json. -
Saneamento simétrico ao compilador: o descompilador é o reverso exato das injeções do build — decodifica campos
json(string→array), extraifile:<ext>para arquivo (BOM removido) e remove as colunas geradas:versao,checksum,user_modified,project, a PK auto-increment (id_numericodo contrato) e a coluna de idioma (language/linguagem_codigo, derivada da pasta); removestatusquando'A'(default injetado) emodule/moduloquando igual ao módulo dono e presente na chave natural. Metadados externos (metadata_file) ou inline (resources->idioma->tabela) são reescritos preservando o restante do JSON raiz. -
Descompilador autônomo e
--project-path: o descompilador faz sua própria varredura detables_config.json+modulos/*/<mod>.json(em vez de incluir o compilador), mantendo-o testável isoladamente e blindado porSDD_NO_AUTORUN. Tanto o descompilador quanto orecover-project.shaceitam--project-path, alinhando-se aoupdate-resource-data.sh/deploy (operação por projeto) — uma extensão sobre o exemplo literal do intake §3.1, que não passava o caminho do projeto. Metadados de recurso são gravados comJSON_UNESCAPED_SLASHESpara legibilidade no Git. -
Cobertura de teste: novo
tests/Unit/PHP/RecuperacaoDadosRecursosTest.php(6 testes, 44 assertions) blinda extração de arquivos físicos, decodificação de JSON, saneamento de colunas, escrita externa/inline de metadados e a resolução de caminhos (global com/semresources_dire módulo), todos com fixtures em diretório temporário, sem banco.
DEC-067 - 2026-06-25 - accepted
Atualização de Versões dos Componentes do GitHub Actions (req-064 / BATCH-064). Decisões desta rodada:
-
Atualização de Versões de Actions: Atualizar as ações nos workflows para as últimas versões estáveis disponíveis que oferecem suporte nativo ao runtime Node.js 24:
actions/checkout@v4→actions/checkout@v7,actions/setup-node@v4→actions/setup-node@v6esoftprops/action-gh-release@v2→softprops/action-gh-release@v3. -
Mitigação de Depreciação: Isso remove completamente os avisos de deprecamento do Node.js 20 sem alterar o fluxo funcional ou as tarefas executadas nos scripts dos pipelines.
DEC-068 - 2026-06-29 - accepted
Registro Dinâmico de Widgets do Sistema e Carregamento sob Demanda no Editor HTML (req-066 / BATCH-066). Decisões desta rodada:
-
Tabela global
widgetspopulada pela esteira de recursos: nova tabelawidgets(id/name/icon/tabela/coluna_where/language/status/versao/project, índice único[id, language]) descreve cada categoria/tipo de widget do sistema, substituindo o mapa estático de tabelas tanto no backend quanto no frontend. A colunaprojectnasce junto (espelha20260707100000_add_project_to_widget_tables.php) para não quebrar o UPSERT de deploy de projeto. -
Geração via caminho CLÁSSICO do compilador, não pelo dinâmico
sync_resources: o recurso"widgets"é declarado emresources->idioma->widgetsnos manifestos dos módulos e coletado pela varredura fixa decoletarRecursos()(pilha$widgets, índice$idxWidgetsporlang|id, órfãos emdb/orphans/WidgetsData.json), gerandodb/data/WidgetsData.json. A tabela é declarada emtables_config.jsonapenas para entrar no contratoschema-metadata.json(strategynatural_keypor[language, id]) consumido pelo atualizador — semsync_resources(evita dupla geração; também adicionada à lista$reservadasdo caminho dinâmico por segurança). O Data.json usa a chavename(nãonome) para casar com a coluna real da tabela;versao = 1fixo (registro estrutural sem arquivos físicos). -
Carregamento sob demanda (lazy loading) por categoria no frontend: o painel de inclusão (
html-editor-visual-controls.js) deixa de terWIDGETS_MODULOShardcoded. Ao abrir, busca as categorias ativas via nova rotahtml-editor-widget-typese renderiza os grupos colapsados; ao expandir um grupo, busca os registros daquela categoria viahtml-editor-widgets-list(parâmetromodule), com cache local por módulo (widgetsCache[module]) para evitar chamadas redundantes. -
Resolução dinâmica e segura da tabela alvo no backend:
html_editor_ajax_widgets_list()passa a recebermodule, resolvetabela/coluna_wherena tabelawidgetse consulta dinamicamente a tabela alvo. Os identificadorestabela/coluna_wheresão validados por regex^[a-zA-Z0-9_]+$antes da interpolação (anti-SQL Injection); a coluna de rótulo padrão éname, com fallback paraidquando ausente/vazia.
DEC-069 - 2026-06-29 - accepted
Correção de Exceção de CodeMirror Indefinido no Módulo de Formulários (req-067 / BATCH-067). Decisões desta rodada:
-
Guard de existência antes de manipular instâncias CodeMirror: como a dependência da biblioteca
html-editornoforms.jsonfazhtml-editor-interface.jscarregar em todas as telas do módulo (inclusivelistar/visualizar, que não renderizam o editor), o registro do listenerCodeMirrorHtml.on("change", ...)— que executa no$(document).ready— quebrava a página comTypeError: Cannot read properties of undefined (reading 'on'). A correção envolve esse registro e o handler de backup ($('#gestor-listener').on(backupCallbackName, ...), casoshtml/css/css_compiled) com a verificaçãotypeof X !== 'undefined' && X, padrão já usado paraCodeMirrorHtmlExtraHead. Escopo deliberadamente cirúrgico (apenas os pontos que rodam/disparam sem o editor montado), sem refatorar os demais usos protegidos pelo fluxo do editor ativo.
DEC-070 - 2026-06-29 - accepted
Correção de Causa-Raiz das Abas Travadas e Widget Vazio no Módulo de Formulários (req-067 expandido / BATCH-067, rodada 2). Após os findings expandidos do Engenheiro Chefe (erros em forms/editar/ e forms/adicionar/, onde o editor DEVERIA existir), decisões desta rodada:
-
Editor HTML fora do aninhamento de abas (causa-raiz): no
forms, o#html-editor#estava aninhado em abas inativas no load (forms-template→forms-preview/forms-editor), enquanto módulos funcionais comopublisher-highlightso renderizam direto na página. O CodeMirror (CodeMirror.fromTextAreano ready) e a inicialização das abas internas do editor não se estabilizavam dentro do contexto de abas externas ocultas, deixandoCodeMirrorHtml/CodeMirrorCssindefinidos e travando a troca de abas Fomantic (exceções não capturadas empreviewHtml/totalDeSessoes). Decisão (orientação do Engenheiro Chefe Humano): remover a sub-aba "Editor HTML" domenuFormsTemplatee mover o#html-editor#para uma seção raiz<h4 class="ui dividing header">Conteúdo do Formulário</h4>logo abaixo das abas, sempre visível, nos 6 HTMLs (editar/adicionar/clonar × pt-br/en; "Form Content" no en). -
Blindagem defensiva ampliada: além dos guards da rodada 1, proteger
previewHtml(),getUpdatedHtmlWithValues(),totalDeSessoes()emenuDeSessoes()com early-return quando as instâncias CodeMirror não existem — defesa em profundidade que não altera o fluxo com o editor montado. -
Fallback de template no widget público (
forms.widget.php):forms_render()retornava''quando o campohtmldo registro estava vazio. Esse vazio era consequência do mesmo bug — sem o CodeMirror instanciado, o HTML do template não era carregado/sincronizado no submit, gravandohtmlvazio no banco. Decisão: quandohtmlestiver vazio, carregarhtml/css/css_compiled/html_extra_headdo template referenciado emfields_schema.template_id(tabelatemplates,target='forms'), resolvendo registros legados e dando robustez. Difere de D-023 (que veda fallback para o mockup de arquivo físico): aqui o fallback é para o template do próprio banco.