Conn2Flow
Navegação das docs

SDD

Decision Log (Archive: DEC-041 to DEC-050)

Centralização de Injeção de Recursos de Widgets e Arquitetura do Publicador Índice (req-028 / BATCH-028). Decisões desta rodada: 1. Helper de Injeção Centralizada: Criar a função…

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:

  1. Helper de Injeção Centralizada: Criar a função gestor_pagina_recursos_incluir() na biblioteca comum gestor/bibliotecas/gestor.php. A função lida com css, css_compiled e html_extra_head, aplicando formatação e incluindo nos respectivos arrays globais ($_GESTOR).

  2. 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.

  3. 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.

  4. 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 no fields_schema JSON para items_per_page, show_search_input, show_sorting_select, show_load_more_btn.

  5. 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úblico publisher-index.widget.js para 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:

  1. 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 migrar linguagem_codigo→language, porém todas já usam language em suas migrações de criação (premissa do intake desatualizada). A única tabela que ainda usava linguagem_codigo era a variaveis (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 tabela variaveis, cumprindo o princípio de abertura do req ("todas as tabelas que utilizam linguagem_codigo") e o DEC-008. Inclui migração de criação ajustada, índice composto atualizado e nova migração corretiva idempotente (renameColumn com guards hasColumn), além das referências em configuracao.php/gestor.php/plugins-installer.php/gerador/atualizadores e regeneração do VariaveisData.json.

  2. Metadados de sincronização declarativos (tabela.config): As regras antes hardcoded no atualizador ($tabelasChaveNatural, $tabelasInsertOnly, $preserveMap e a chave natural por tabela) passam a ser declaradas no bloco "tabela" de cada módulo, sob a sub-chave config (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 global gestor/resources/tables_config.json com o mesmo schema.

  3. Contrato consolidado (schema-metadata.json) via Registry Pattern: O gerador atualizacao-dados-recursos.php ganha um motor de varredura genérico que consolida os blocos locais + o global em gestor/db/data/schema-metadata.json (17 tabelas), preservando a geração específica dos *Data.json existente (decisão de baixo risco: adicionar o motor sem reescrever a coleta de recursos). Inclui carregamento/execução sequencial de data-hooks.php (globais e por módulo) pós-geração e substituição dos @ cegos por ensureDir() com log.

  4. Atualizador dinâmico: atualizacoes-banco-de-dados.php lê o contrato (schemaMetadata()), remove os arrays hardcoded, usa chave natural genérica (naturalKeyGenerica, lowercase + alias language/linguagem_codigo) e WHERE genérico null-safe (<=>), loteador threshold-based (maxAllowedPacket() a 70%, fallback 16MB) com inserirEmLote (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.

  5. Unificação e visibilidade de logs / remoção de CLI exec: log_unificado() (em atualizacoes-banco-de-dados.php e atualizacao-plugin-banco-de-dados.php) escreve em disco, no EXTERNAL_LOGGER por 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 retorna db_logs (resumido ou completo conforme full_log); atualizacoes-sistema.php (executarAtualizacaoBanco) passa a rodar estritamente inline (remoção do exec() de banco), capturando e prefixando os logs com [BANCO]. O passthru() remanescente em atualizacoes-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):

  1. usuarios_provedores sem chave estrangeira física: O req-030 §1 pedia FK usuario_id → usuarios.id_usuario ON DELETE CASCADE, mas (a) a PK real é id_usuarios e (b) nenhuma migração do legado usa addForeignKey (relacionamentos são por coluna integer + índice, ex.: usuarios.id_hosts). Decisão: criar usuario_id integer + í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 guard hasTable(); a de 2FA em usuarios com guards hasColumn()/up/down idempotentes. Timestamps 20260706* (> maior existente 20260705100000) para garantir ordem.

  2. JWT HS256 com kid e chaves versionadas no banco: A biblioteca jwt.php assina em HMAC-SHA256 (chaves simétricas, auto-suficiente, sem dependência de RSA/par de chaves) e inclui kid no header para selecionar a chave na validação. O conjunto de chaves fica em variaveis (modulo='sistema', id='jwt_keys', coluna valor em JSON) — a tabela variaveis não tem coluna chave, ao contrário do que o req §3.2 sugeria.

  3. Grace period medido por expired_at: Divergência justificada do req §3.2 (que sugeria created_at). O período de carência é contado a partir de quando a chave foi rotacionada para expired (campo expired_at, fallback created_at). Medir por created_at invalidaria o grace em produção, pois a chave ativa vive AUTH_JWT_ROTATION_DAYS (30) dias antes de expirar, e created_at + 24h já teria passado.

  4. 2FA TOTP próprio (RFC 6238/4226) sem libs externas: 2fa.php implementa Base32, HOTP e TOTP (drift ±1 ciclo) em funções byte-wise puras (sem mb_*), validado contra os vetores oficiais dos RFCs. O envio por e-mail usa a função real comunicacao_email() (o req cita gestor_email_enviar() como placeholder).

  5. 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), pois banco.php implementa apenas mysqli (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:

  1. admin-environment como painel global de auth: As chaves AUTH_METHOD_*, OAUTH_*, AUTH_2FA_* e AUTH_JWT_* são lidas/gravadas no .env pela 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 AJAX rotacionar-jwt → jwt_rotate_keys().

  2. 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 (helper modelo_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 URI otpauth://, mantendo o secret fora de serviços de terceiros. O secret TOTP é persistido com two_factor_enabled=0 até a confirmação do primeiro código (evita estado de sessão frágil). Desativar 2FA exige senha (password_verify) + código atual.

  3. Interceptador 2FA fail-safe no login: Inserido no perfil_usuario_signin após a validação de credenciais; só intercepta quando o usuário tem 2FA habilitado ou AUTH_2FA_REQUIRED é true — caso contrário o login segue idêntico (não trava instalações sem 2FA). Tela signin-2fa unificada serve verificação e configuração obrigatória. A finalização do login foi extraída para perfil_usuario_finalizar_login() (reuso entre login direto, 2FA e social). Todo o estado de fluxo (2FA pendente e OAuth state/provider/action) usa o store de sessão do sistema (gestor_sessao_variavel, persistido in sessoes_variaveis e iniciado automaticamente por gestor_sessao_iniciar), não $_SESSION nativo — por orientação do Engenheiro Chefe.

  4. 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ções social-login, oauth-callback e signin-2fa registradas 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.

  5. Endurecimento via bibliotecas/seguranca.php: Session Hijacking valida User-Agent + bloco de IP (3 octetos) dentro de gestor_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: helpers gestor_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 via log.php ficam 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:

  1. Configuração e Auxílio na UI: Adicionar toggle AUTH_METHOD_EMAIL_ACTIVE nas configurações globais do admin-environment (salvo no .env). Adicionar na interface de configuração links diretos externos com target="_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.

  2. 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.

  3. 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_code e salva as variáveis na sessão do gestor (pending_2fa_user = ID, pending_2fa_mode = 'verify', pending_2fa_type = 'email'), redirecionando-o à rota signin-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:

  1. 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.

  2. 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.

  3. 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 se AUTH_API_2FA_REQUIRED estiver 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 rota oauth-authenticate-2fa/.

  4. Finalização via nova rota oauth-authenticate-2fa/: Essa nova página recebe o código de 6 dígitos. Após validação, recupera pending_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:

  1. Lógica de Identificação Permissiva: Modificar o HtmlEditor para que qualquer tag no DOM seja editável (exceto se declarada na lista ignoredTags do editor). O tipo de edição resolve para 'image' para tags <img>, 'text' para tags que contêm texto puro editável diretamente (conforme isDirectlyTextEditable), e 'code' (outerHTML) como fallback para todas as demais tags estruturais (ex: div, section, table, etc.).

  2. 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).

  3. 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).

  4. 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.

  5. 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-list em html-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.

  6. Histórico Undo/Redo Parametrizado: Gerenciamento de estado visual mantido na pilha undoStack/redoStack da instância do editor no iframe. A profundidade máxima do histórico é controlada por config.undoLimit (padrão 30), 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).

  7. 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.

  8. 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):

  1. 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 "+", AJAX html-editor-widgets-list, atalhos de teclado, alças de redimensionamento e sincronização de largura) ficou num arquivo novo gestor/assets/interface/html-editor-visual-controls.js (incluído via html-editor.php), evitando inflar o já extenso html-editor-interface.js (3236 linhas). O html-editor-interface.js sofreu apenas 2 edições cirúrgicas: remoção do handler antigo .screenPagina (que encolhia o modal inteiro com tiny/longer) e uso de iframe.contentWindow.htmlEditorGetCleanHtml() no save.

  2. *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`).

  3. Largura controlada no frame interno, não no modal: Os botões desktop/tablet/mobile (agora com data-width 100%/768px/375px) e as alças ajustam a largura de um wrapper .iframe-preview-frame centralizado, mantendo o modal sempre fullscreen (a troca de classes tiny/longer do modal foi removida). O dimmer/loader foi mantido como irmão do #iframe-preview para não quebrar iframe.parent().find('.ui.dimmer').

  4. 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 do srcdoc — a ação "Editar" reusa openEditModal no iframe. Os overlays/toolbar/breadcrumb/styler são ocultados enquanto esse modal está aberto (evita conflito de z-index).

  5. 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-wrapper usa prompt() nativo para trocar o grupo_slug (coerente com o confirm() nativo do delete), atualizando data-widget-slug/data-widget-signature e o rótulo.

  6. i18n parcial: Apenas os 3 tooltips do visual-modal (html-editor-add-element-tooltip/-undo-tooltip/-redo-tooltip) foram adicionados em resources/{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). O VariaveisData.json não foi editado — é compilado a partir do variables.json pelo pipeline.

DEC-049 - 2026-06-13 - accepted

Refinamentos no Editor HTML Visual (req-035 / BATCH-035). Decisões de design/layout:

  1. Toolbar à direita: Ancorar o #html-editor-floating-toolbar no lado direito do contêiner selecionado (calculando a coordenada left com 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.

  2. Seletor de Filhos (Children Breadcrumb): Criar o contêiner #html-editor-selection-children posicionado verticalmente abaixo do contêiner de ancestrais e acima do editor de classes Tailwind.

  3. Labels de Identificação: Inserir os labels "Ancestrais:" e "Filhos:" nas barras de navegação do DOM correspondentes.

  4. 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.

  5. 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:

  1. 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.clipboardElement via cloneNode(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 + C e Ctrl + V sincronizados no iframe e repassados pelo pai.

  2. 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.

O Futuro é Híbrido: Humano + IA.

O Conn2Flow é a ferramenta. Se você precisa do Arquiteto para desenhar a estratégia da sua empresa usando essa tecnologia...

Contrate Consultoria Especializada