As decisões correntes mais recentes permanecem em
sdd/decisions/DECISION-LOG.md. Este arquivo guarda o histórico movido para manter o log corrente enxuto (≤10 itens).
DEC-041 - 2026-06-11 - accepted
Centralização de Injeção de Recursos de Widgets e Arquitetura do Publicador Índice (req-028 / BATCH-028). Decisões desta rodada:
-
Helper de Injeção Centralizada: Criar a função
gestor_pagina_recursos_incluir()na biblioteca comumgestor/bibliotecas/gestor.php. A função lida comcss,css_compiledehtml_extra_head, aplicando formatação e incluindo nos respectivos arrays globais ($_GESTOR). -
Prevenção de Duplicidades via MD5: A helper calculará o hash MD5 dos conteúdos incluídos para evitar a injeção repetida das mesmas regras de estilo ou tags de cabeçalho na página se múltiplos blocos do mesmo widget forem inseridos.
-
Páginas sem CSS/Head inline: Refatorar
gestor_componente()e os widgets públicos (menus.widget.php,galleries.widget.php,publisher-highlights.widget.php) para chamar a helper em vez de concatenar o CSS/Head inline no HTML do widget. -
Módulo
publisher-index: Criar o novo módulo "Publicador Índice" baseado no publicador de destaques, implementando a tabela de banco correspondente e controles adicionais nofields_schemaJSON paraitems_per_page,show_search_input,show_sorting_select,show_load_more_btn. -
Roteamento AJAX e Comportamento Interativo: No widget renderer, tratar requisições AJAX públicas direcionando para
publisher_index_render_ajax, que consulta, filtra (busca textual via LIKE) e ordena as publicações de acordo com o estado do frontend. Criar o script públicopublisher-index.widget.jspara escutar inputs, atualizar o estado e anexar dinamicamente novos itens (carregamento sob demanda) sem recarga completa de página.
DEC-042 - 2026-06-12 - accepted
Reestruturação e Otimização de Dados, Sincronização e Visibilidade de Logs (req-029 / BATCH-029). Decisões desta rodada:
-
Divergência aprovada do req §1 (escopo da migração de idioma): O req-029 §1 listava 7 tabelas (
menus,galleries,publisher_highlights,publisher_index,prompts_ia,alvos_ia,modos_ia) para migrarlinguagem_codigo→language, porém todas já usamlanguageem suas migrações de criação (premissa do intake desatualizada). A única tabela que ainda usavalinguagem_codigoera avariaveis(não listada no req). Sob aprovação explícita do Engenheiro Chefe Humano, o escopo real do Slice de migração foi redirecionado para a tabelavariaveis, cumprindo o princípio de abertura do req ("todas as tabelas que utilizamlinguagem_codigo") e o DEC-008. Inclui migração de criação ajustada, índice composto atualizado e nova migração corretiva idempotente (renameColumncom guardshasColumn), além das referências emconfiguracao.php/gestor.php/plugins-installer.php/gerador/atualizadores e regeneração doVariaveisData.json. -
Metadados de sincronização declarativos (
tabela.config): As regras antes hardcoded no atualizador ($tabelasChaveNatural,$tabelasInsertOnly,$preserveMape a chave natural por tabela) passam a ser declaradas no bloco"tabela"de cada módulo, sob a sub-chaveconfig(strategy,natural_key_columns,preserve_on_user_modified,insert_only) — nome de chave definido pelo Engenheiro Chefe Humano — mais um bloco"deletar". Tabelas sem módulo dono (variaveis,usuarios_perfis_modulos,usuarios_perfis_modulos_operacoes,alvos_ia) ficam no arquivo globalgestor/resources/tables_config.jsoncom o mesmo schema. -
Contrato consolidado (
schema-metadata.json) via Registry Pattern: O geradoratualizacao-dados-recursos.phpganha um motor de varredura genérico que consolida os blocos locais + o global emgestor/db/data/schema-metadata.json(17 tabelas), preservando a geração específica dos*Data.jsonexistente (decisão de baixo risco: adicionar o motor sem reescrever a coleta de recursos). Inclui carregamento/execução sequencial dedata-hooks.php(globais e por módulo) pós-geração e substituição dos@cegos porensureDir()com log. -
Atualizador dinâmico:
atualizacoes-banco-de-dados.phplê o contrato (schemaMetadata()), remove os arrays hardcoded, usa chave natural genérica (naturalKeyGenerica, lowercase + aliaslanguage/linguagem_codigo) e WHERE genérico null-safe (<=>), loteador threshold-based (maxAllowedPacket()a 70%, fallback 16MB) cominserirEmLote(multi-row agrupado por assinatura de colunas + fallback individual para duplicatas), deleção imperativa (executarDelecoes) e transações PDO (beginTransaction/commit/rollBack) envolvendo sincronização + deleção. -
Unificação e visibilidade de logs / remoção de CLI exec:
log_unificado()(ematualizacoes-banco-de-dados.phpeatualizacao-plugin-banco-de-dados.php) escreve em disco, noEXTERNAL_LOGGERpor referência e no stdout CLI (parte implementada por outro agente que tocou o 029 sem querer e foi incorporada, sem reverter).api.php(api_executar_atualizacao_banco) captura os logs e retornadb_logs(resumido ou completo conformefull_log);atualizacoes-sistema.php(executarAtualizacaoBanco) passa a rodar estritamente inline (remoção doexec()de banco), capturando e prefixando os logs com[BANCO]. Opassthru()remanescente ematualizacoes-sistema.phpé o auto-bootstrap do próprio script de deploy (não roda atualização de banco) e foi preservado.
DEC-043 - 2026-06-13 - accepted
Diretrizes de Autenticação, 2FA e JWT (req-030 / BATCH-030, Slices 1–2). Decisões de design da fundação (banco + bibliotecas puras):
-
usuarios_provedoressem chave estrangeira física: O req-030 §1 pedia FKusuario_id → usuarios.id_usuario ON DELETE CASCADE, mas (a) a PK real éid_usuariose (b) nenhuma migração do legado usaaddForeignKey(relacionamentos são por coluna integer + índice, ex.:usuarios.id_hosts). Decisão: criarusuario_idinteger + índice, índice único composto(provider_name, provider_uid), e tratar o cascateamento ON DELETE em código no fluxo de exclusão de usuário. Migração com guardhasTable(); a de 2FA emusuarioscom guardshasColumn()/up/down idempotentes. Timestamps20260706*(> maior existente20260705100000) para garantir ordem. -
JWT HS256 com
kide chaves versionadas no banco: A bibliotecajwt.phpassina em HMAC-SHA256 (chaves simétricas, auto-suficiente, sem dependência de RSA/par de chaves) e incluikidno header para selecionar a chave na validação. O conjunto de chaves fica emvariaveis(modulo='sistema',id='jwt_keys', colunavalorem JSON) — a tabelavariaveisnão tem colunachave, ao contrário do que o req §3.2 sugeria. -
Grace period medido por
expired_at: Divergência justificada do req §3.2 (que sugeriacreated_at). O período de carência é contado a partir de quando a chave foi rotacionada paraexpired(campoexpired_at, fallbackcreated_at). Medir porcreated_atinvalidaria o grace em produção, pois a chave ativa viveAUTH_JWT_ROTATION_DAYS(30) dias antes de expirar, ecreated_at + 24hjá teria passado. -
2FA TOTP próprio (RFC 6238/4226) sem libs externas:
2fa.phpimplementa Base32, HOTP e TOTP (drift ±1 ciclo) em funções byte-wise puras (semmb_*), validado contra os vetores oficiais dos RFCs. O envio por e-mail usa a função realcomunicacao_email()(o req citagestor_email_enviar()como placeholder). -
Cobertura de testes da fundação: Funções puras com testes PHPUnit permanentes (
tests/Unit/PHP/TwoFactorTest.php,JwtTest.php); o ciclo JWT dependente de banco foi validado por teste standalone com stubs em memória (registrado na evidência), poisbanco.phpimplementa apenasmysqli(não PDO/SQLite), deixando a integração end-to-end para o operador (MySQL real).
DEC-044 - 2026-06-13 - accepted
Integração de Autenticação, 2FA, Login Social e Endurecimento (req-030 / BATCH-030, Slices 3–6). Decisões de integração:
-
admin-environment como painel global de auth: As chaves
AUTH_METHOD_*,OAUTH_*,AUTH_2FA_*eAUTH_JWT_*são lidas/gravadas no.envpela infraestrutura existente (admin_environment_env_read/write); credenciais OAuth aparecem condicionalmente e as URIs de callback são exibidas em readonly. O botão "Rotacionar Chaves JWT" usa a AJAXrotacionar-jwt→jwt_rotate_keys(). -
Rota de Segurança embutida no CRUD de perfil: A seção 2FA + contas sociais é renderizada no bloco
<!-- seguranca-campos -->da página de perfil quando?configurar-seguranca=sim(helpermodelo_tag_in), com HTML gerado em PHP e i18n via variáveis do módulo. O QR Code é renderizado client-side (qrcodejs CDN) a partir da URIotpauth://, mantendo o secret fora de serviços de terceiros. O secret TOTP é persistido comtwo_factor_enabled=0até a confirmação do primeiro código (evita estado de sessão frágil). Desativar 2FA exige senha (password_verify) + código atual. -
Interceptador 2FA fail-safe no login: Inserido no
perfil_usuario_signinapós a validação de credenciais; só intercepta quando o usuário tem 2FA habilitado ouAUTH_2FA_REQUIREDé true — caso contrário o login segue idêntico (não trava instalações sem 2FA). Telasignin-2faunificada serve verificação e configuração obrigatória. A finalização do login foi extraída paraperfil_usuario_finalizar_login()(reuso entre login direto, 2FA e social). Todo o estado de fluxo (2FA pendente e OAuthstate/provider/action) usa o store de sessão do sistema (gestor_sessao_variavel, persistido insessoes_variaveise iniciado automaticamente porgestor_sessao_iniciar), não$_SESSIONnativo — por orientação do Engenheiro Chefe. -
Callback OAuth via rota do módulo: Divergência justificada do req §2 —
oauth_redirect_uri()aponta para{url}/oauth-callback/?provider=X(rota do módulo perfil-usuario) em vez de/_api/auth/callback/X, evitando alterar o roteador de API genérico. Novas páginas/opçõessocial-login,oauth-callbackesignin-2faregistradas no manifest. Login social casa por vínculo (usuarios_provedores) ou, na ausência, por e-mail de usuário ativo (cria o vínculo); aplica o mesmo interceptador 2FA. -
Endurecimento via
bibliotecas/seguranca.php: Session Hijacking valida User-Agent + bloco de IP (3 octetos) dentro degestor_permissao_token()de forma fail-safe (não bloqueia sessões sem marcadores registrados; registra no login efetivo, não na renovação de token — para não anular a checagem). CSRF: helpersgestor_csrf_token()/gestor_csrf_validar()prontos; o rollout estrito em 100% dos controllers é incremental (validação runtime), pois a aplicação global cega quebraria os AJAX legados que ainda não enviam o token. Logs de eventos de segurança vialog.phpficam para um slice corretivo.
DEC-045 - 2026-06-13 - accepted
Login sem Senha por E-mail e Auxílio de Configuração OAuth (req-032 / BATCH-032). Decisões de design:
-
Configuração e Auxílio na UI: Adicionar toggle
AUTH_METHOD_EMAIL_ACTIVEnas configurações globais doadmin-environment(salvo no.env). Adicionar na interface de configuração links diretos externos comtarget="_blank"para os consoles do Google e Meta acompanhados de textos de instrução ("How-To") passo a passo de como gerar e vincular os tokens client ID / secret usando as URIs de callback exibidas. -
Login Sem Senha via E-mail (Passwordless): Em
acessar-sistema.html, se habilitado o login por e-mail, ocultar o campo de senha caso o login convencional com senha esteja inativo. Se ambos estiverem ativos, apresentar abas ou botões alternadores (toggles) Fomantic UI para escolher o método de autenticação. Ao selecionar o método por e-mail, o formulário oculta o campo de senha. -
Reuso da Infraestrutura 2FA: Ao submeter o e-mail no login sem senha, o backend valida a existência e status do usuário. Em caso de sucesso, gera o código de uso único, dispara o e-mail pelo helper
two_factor_email_send_codee salva as variáveis na sessão do gestor (pending_2fa_user = ID,pending_2fa_mode = 'verify',pending_2fa_type = 'email'), redirecionando-o à rotasignin-2fa/. Desta forma, a tela de verificação existente resolve a autenticação final e gera o token de autorização sem necessidade de novas páginas.
DEC-046 - 2026-06-13 - accepted
Segurança no Acesso e Geração de Chaves de API (req-033 / BATCH-033). Decisões de design:
-
Nova aba API no admin-environment: Criar aba "API" no módulo para expor controles e persistir no
.env:AUTH_API_ALLOWED_PROFILES(lista separada por vírgula de perfis autorizados), e toggles de login (senha/e-mail) e 2FA (obrigatório, métodos app/e-mail) para a rota de API. -
Interface Adaptativa de Login da API: Em
oauth-authenticate, reaproveitar a interface reativa de login (Senha vs Código por E-mail) dependendo do estado das variáveis de controle ativas no.env. -
Interceptador 2FA na API e Holding de Tokens: Em
perfil_usuario_oauth_authenticate(), se o usuário logado pertencer a um perfil permitido e se autenticar com sucesso, e seAUTH_API_2FA_REQUIREDestiver ativo (ou se o usuário possuir 2FA ativo em sua conta), o backend gera as chaves de resposta OAuth e as armazena temporariamente na sessão (pending_oauth_tokens), redirecionando-o para a nova rotaoauth-authenticate-2fa/. -
Finalização via nova rota
oauth-authenticate-2fa/: Essa nova página recebe o código de 6 dígitos. Após validação, recuperapending_oauth_tokens, remove as variáveis temporárias da sessão, e conclui emitindo os tokens originais da API (imprimindo JSON ou redirecionando via OAuth).
DEC-047 - 2026-06-13 - accepted
Aprimoramento do Editor HTML Visual (req-034 / BATCH-034). Decisões de design:
-
Lógica de Identificação Permissiva: Modificar o
HtmlEditorpara que qualquer tag no DOM seja editável (exceto se declarada na listaignoredTagsdo editor). O tipo de edição resolve para'image'para tags<img>,'text'para tags que contêm texto puro editável diretamente (conformeisDirectlyTextEditable), e'code'(outerHTML) como fallback para todas as demais tags estruturais (ex:div,section,table, etc.). -
Dual-Overlay com Barra Flutuante: Substituir o comportamento de clique de edição imediata por um fluxo de seleção persistente. O editor visual passa a gerenciar um overlay de hover transitório (
#html-editor-hover-overlay) e um overlay de seleção persistente (#html-editor-selection-overlay). Este último sustenta acoplada logo acima a barra de ferramentas flutuante (#html-editor-floating-toolbar). -
Barra de Ferramentas de Seleção: A barra flutuante possui botões para:
-
Duplicar: clona o elemento via
cloneNode(true)e insere-o como irmão adjacente inferior do elemento ativo. -
Deletar: remove o elemento do DOM após confirmação do usuário usando o
confirm()nativo do JavaScript. -
Editar: abre o Fomantic UI modal no pai para edição de propriedades ou código.
-
Arrastar/Mover: aciona o modo de arraste de elementos (DnD).
-
-
Lightweight Drag and Drop (DnD): O arraste do elemento selecionado exibe uma linha tracejada horizontal de placeholder (
.conn2flow-dnd-placeholder). O reposicionamento do placeholder é calculado comparando as coordenadas do cursor com os elementos sob o mouse. O drop altera a ordem física do nó no DOM e re-sincroniza o CodeMirror no editor principal. -
Inclusão de Novos Elementos e Widgets (Carregar e Soltar): Adicionar um botão de inclusão "+" no cabeçalho do visual-modal. O clique abre um popup categorizado (Elementos HTML x Widgets do Sistema). A lista de Widgets e seus slugs é carregada dinamicamente via AJAX no endpoint
html-editor-widgets-listemhtml-editor.php. Selecionar um elemento ou widget com slug entra em modo de inserção, exibindo o placeholder de drop no iframe e inserindo o novo elemento/bloco de widget (incluindo imagens via ImagePicker) na posição clicada. -
Histórico Undo/Redo Parametrizado: Gerenciamento de estado visual mantido na pilha
undoStack/redoStackda instância do editor no iframe. A profundidade máxima do histórico é controlada porconfig.undoLimit(padrão30), parametrizada para fácil ajuste. O gatilho de restauração é feito por setas no modal (pai) e atalhos globais de teclado (Ctrl + Z/Ctrl + Y). -
Breadcrumb DOM e Quick Tailwind Styler: Trilha breadcrumb em linha na base do overlay de seleção permite navegabilidade vertical rápida na hierarquia do DOM. Ao lado, o quick styler lê classes Tailwind vigentes no elemento em tags visuais descartáveis e possui um campo de input com sugestões para injeção rápida de novas classes Tailwind no nó selecionado.
-
Handles de Resize e Wrappers Virtuais: Contêiner do iframe preview equipado com alças de arraste laterais livres que mostram a largura pixelada em tempo real. Comentários de widgets (highlights, menus, galleries, index) convertidos em divs de wrapper atômicas com borda tracejada amarela para bloquear cliques acidentais no seu conteúdo interno na edição visual, restauradas para comentários no salvamento.
DEC-048 - 2026-06-13 - accepted
Decisões de execução do BATCH-034 (complementam o design da DEC-047, sem alterar requisito):
-
Modularização em
html-editor-visual-controls.js: A pedido do Engenheiro Chefe Humano, toda a lógica nova da JANELA PAI (painel do botão "+", AJAXhtml-editor-widgets-list, atalhos de teclado, alças de redimensionamento e sincronização de largura) ficou num arquivo novogestor/assets/interface/html-editor-visual-controls.js(incluído viahtml-editor.php), evitando inflar o já extensohtml-editor-interface.js(3236 linhas). Ohtml-editor-interface.jssofreu apenas 2 edições cirúrgicas: remoção do handler antigo.screenPagina(que encolhia o modal inteiro comtiny/longer) e uso deiframe.contentWindow.htmlEditorGetCleanHtml()no save. -
*Protocolo
postMessage`c2f-he:**: Comunicação pai↔iframe namespaced (c2f-he:undo/redo/insert-element/insert-widget/cancel-insert/history), preservando intactos os nomes legados do ImagePicker (html-editor-imagepick-open/selected`). -
Largura controlada no frame interno, não no modal: Os botões desktop/tablet/mobile (agora com
data-width100%/768px/375px) e as alças ajustam a largura de um wrapper.iframe-preview-framecentralizado, mantendo o modal semprefullscreen(a troca de classestiny/longerdo modal foi removida). O dimmer/loader foi mantido como irmão do#iframe-previewpara não quebrariframe.parent().find('.ui.dimmer'). -
Modal de edição vive no iframe: Diferente da redação da DEC-047 (item 3.3, "modal no pai"), o modal de edição (
#html-editor-modal, modos text/image/code) é o que o helper clona para dentro dosrcdoc— a ação "Editar" reusaopenEditModalno iframe. Os overlays/toolbar/breadcrumb/styler são ocultados enquanto esse modal está aberto (evita conflito de z-index). -
Edição de widget por
prompt(): Como a modal CRUD completa de cada widget está fora do escopo do editor visual, o botão "Editar" de um.conn2flow-widget-wrapperusaprompt()nativo para trocar ogrupo_slug(coerente com oconfirm()nativo do delete), atualizandodata-widget-slug/data-widget-signaturee o rótulo. -
i18n parcial: Apenas os 3 tooltips do visual-modal (
html-editor-add-element-tooltip/-undo-tooltip/-redo-tooltip) foram adicionados emresources/{pt-br,en}/variables.json. Os rótulos do painel de inclusão e os títulos da toolbar interna do iframe são strings pt-br embutidas no JS (paridade en pode ser endereçada em slice corretivo). OVariaveisData.jsonnão foi editado — é compilado a partir dovariables.jsonpelo pipeline.
DEC-049 - 2026-06-13 - accepted
Refinamentos no Editor HTML Visual (req-035 / BATCH-035). Decisões de design/layout:
-
Toolbar à direita: Ancorar o
#html-editor-floating-toolbarno lado direito do contêiner selecionado (calculando a coordenadaleftcom base na borda direita do elemento ativo menos a largura do próprio toolbar) para evitar sobreposição lateral com o breadcrumb e com o editor de classes Tailwind CSS que ficam do lado esquerdo. -
Seletor de Filhos (Children Breadcrumb): Criar o contêiner
#html-editor-selection-childrenposicionado verticalmente abaixo do contêiner de ancestrais e acima do editor de classes Tailwind. -
Labels de Identificação: Inserir os labels "Ancestrais:" e "Filhos:" nas barras de navegação do DOM correspondentes.
-
Visual e Interação:
-
Usar um fundo mais claro para o contêiner de filhos em relação ao de ancestrais, criando diferenciação visual.
-
Utilizar a barra
|como separador na lista de filhos (atualização do Engenheiro Chefe Humano em 2026-06-13; o intake original previa/). -
Implementar listeners de hover e clique para destacar/selecionar os filhos diretos editáveis.
-
-
Destaque de Hover nos Breadcrumbs: Hover sobre um link/item nos breadcrumbs (ancestrais ou filhos) deve desenhar uma caixa tracejada roxa (mesma cor/tom do selection overlay) sobre o elemento físico correspondente para melhorar a visualização e orientação do operador no DOM.
Notas de execução (BATCH-035): implementado integralmente no editor do iframe (gestor/assets/interface/html-editor.js); o orquestrador da janela pai não precisou de lógica nova (só o sistemaSel do save ganhou os 2 novos ids). O hover roxo usa um overlay dedicado #html-editor-breadcrumb-hover-overlay (z-index 999991, acima da seleção), e onHoverMove() ganhou uma guarda para não desenhar o hover azul quando o cursor está sobre o próprio chrome do editor (toolbar/breadcrumbs/styler), evitando conflito visual entre o azul direto e o roxo dos breadcrumbs. O empilhamento abaixo do elemento é cumulativo por offsetHeight (ancestrais → filhos → styler). Widgets (.conn2flow-widget-wrapper) seguem atômicos: o seletor de filhos é suprimido para eles.
DEC-050 - 2026-06-13 - accepted
Novas Operações Estruturais no Editor HTML Visual (req-036 / BATCH-036). Decisões de design:
-
Copiar e Colar (Copy/Paste):
-
Adicionar os botões "Copiar" (
.he-tb-copy) e "Colar" (.he-tb-paste) na toolbar flutuante. -
Guardar o nó clonado em
this.clipboardElementviacloneNode(true). -
Colar insere a cópia como irmão adjacente inferior do elemento atualmente selecionado (alvo), tanto por botão quanto por atalho
Ctrl + V. -
Adicionar atalhos globais de teclado
Ctrl + CeCtrl + Vsincronizados no iframe e repassados pelo pai.
-
-
Embrulhar Elemento (Wrap Element):
-
Adicionar o botão "Embrulhar" (
.he-tb-wrap) na toolbar flutuante. -
O clique exibe um menu popup com tags estruturais básicas (
div,section,a,p,article,aside). -
Ao selecionar a tag, o editor cria o novo elemento pai, substitui o selecionado atual por ele, coloca o selecionado dentro dele como filho, e mantém o foco da seleção visual no elemento original (filho), forçando o recálculo dos breadcrumbs e styler.
-
Notas de execução (BATCH-036): o botão Colar nasce oculto e só aparece quando clipboardElement tem um clone (updatePasteButton()); como esse botão muda a largura da toolbar, copySelected() chama updateSelectionUI() para reancorá-la à direita. Para não quebrar a cópia nativa de texto, o Ctrl+C só captura o elemento quando não há seleção de texto ativa (getSelection().isCollapsed) e o foco não está em input/textarea — tanto no iframe quanto na janela pai (html-editor-visual-controls.js, que repassa c2f-he:copy/c2f-he:paste). O ícone do botão Duplicar mudou de copy para clone para diferenciá-lo do novo Copiar. O popup #html-editor-wrap-menu foi registrado em isEditorOwned/extractUserHtml/sistemaSel e fecha ao clicar fora, ao trocar de seleção, em hideChrome e no Esc.