Conn2Flow
Navegação das docs

SDD

Human Request: Persistência de Estilos de Widgets e Criação do Módulo Publicador Índice (req-028)

Esta especificação define o lote de trabalho req-028 (BATCH-028) para o Engenheiro Executor. O escopo é composto por duas demandas integradas: 1. Persistência e Injeção de…

Esta especificação define o lote de trabalho req-028 (BATCH-028) para o Engenheiro Executor. O escopo é composto por duas demandas integradas:

  1. Persistência e Injeção de Recursos de Widgets: Gravar no banco de dados e aplicar na página publicada o CSS compilado (css_compiled) e o cabeçalho extra (html_extra_head) gerados nos editores de templates dos módulos menus, galleries e publisher-highlights.

  2. Criação do Módulo Publicador Índice (publisher-index): Desenvolver um novo módulo de indexação de publicações baseado na estrutura do publicador de destaques, adicionando paginação ("Carregar Mais"), busca AJAX client-side e ordenação em tempo de execução.


1. Banco de Dados e Migrações

1.1 Atualização de Migrações Existentes

Para garantir a consistência de novas instalações limpas do sistema, as migrações originais de criação das tabelas dos três módulos devem ser modificadas para incluir as colunas css_compiled e html_extra_head:

  • 20260701100000_create_publisher_highlights_table.php: Adicionar após o campo css:

    ->addColumn('css_compiled', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true])
    ->addColumn('html_extra_head', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true])
  • 20260701110000_create_menus_table.php: Adicionar após o campo css:

    ->addColumn('css_compiled', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true])
    ->addColumn('html_extra_head', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true])
  • 20260701120000_create_galleries_table.php: Adicionar após o campo css:

    ->addColumn('css_compiled', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true])
    ->addColumn('html_extra_head', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true])

1.2 Migração de Atualização de Ambiente Existente [NEW]

Criar uma nova migração Phinx com timestamp atual para atualizar bancos de dados em execução: gestor/db/migrations/20260611110000_add_css_compiled_and_html_extra_head_to_widgets_tables.php

  • Lógica: Adicionar colunas css_compiled (mediumtext, null: true) e html_extra_head (mediumtext, null: true) após a coluna css nas tabelas publisher_highlights, menus e galleries caso elas não existam (usando $this->table()->hasColumn()).


2. Injeção Centralizada de Recursos (gestor.php)

2.1 Criar Função Helper gestor_pagina_recursos_incluir

Na biblioteca comum gestor.php, criar uma nova função utilitária para centralizar a injeção e desduplicação de recursos:

/**
 * Inclui recursos de página (CSS, CSS compilado e HTML extra head) no pipeline global.
 * Controla duplicidades via hash MD5 para evitar inclusão redundante.
 *
 * @param array $params
 * @param string $params['css']
 * @param string $params['css_compiled']
 * @param string $params['html_extra_head']
 */
function gestor_pagina_recursos_incluir($params = false){
    global $_GESTOR;
    if($params)foreach($params as $var => $val)$$var = $val;
    if(!isset($_GESTOR['recursos-incluidos-hashes'])){
        $_GESTOR['recursos-incluidos-hashes'] = Array();
    }
    // 1) HTML Extra Head
    if(isset($html_extra_head) && existe($html_extra_head)){
        $hash = md5($html_extra_head);
        if(!isset($_GESTOR['recursos-incluidos-hashes'][$hash])){
            $_GESTOR['recursos-incluidos-hashes'][$hash] = true;
            $html_extra_head_formatted = preg_replace("/(^|\n)/m", "\n    ", $html_extra_head);
            $_GESTOR['html-extra-head'][] = $html_extra_head_formatted."\n";
        }
    }
    // 2) CSS Customizado
    if(isset($css) && existe($css)){
        $hash = md5($css);
        if(!isset($_GESTOR['recursos-incluidos-hashes'][$hash])){
            $_GESTOR['recursos-incluidos-hashes'][$hash] = true;
            $css_formatted = preg_replace("/(^|\n)/m", "\n        ", $css);
            $_GESTOR['css'][] = '<style>'."\n";
            $_GESTOR['css'][] = $css_formatted."\n";
            $_GESTOR['css'][] = '</style>'."\n";
        }
    }
    // 3) CSS Compilado
    if(isset($css_compiled) && existe($css_compiled)){
        $hash = md5($css_compiled);
        if(!isset($_GESTOR['recursos-incluidos-hashes'][$hash])){
            $_GESTOR['recursos-incluidos-hashes'][$hash] = true;
            $css_compiled_formatted = preg_replace("/(^|\n)/m", "\n        ", $css_compiled);
            $_GESTOR['css-compiled'][] = '<style>'."\n";
            $_GESTOR['css-compiled'][] = $css_compiled_formatted."\n";
            $_GESTOR['css-compiled'][] = '</style>'."\n";
        }
    }
}

2.2 Refatorar gestor_componente()

Substituir o bloco de injeção direta de estilos da função gestor_componente() em gestor/bibliotecas/gestor.php (linhas 218 a 238) pela chamada à nova helper:

gestor_pagina_recursos_incluir(Array(
    'css' => $css,
    'css_compiled' => $css_compiled,
    'html_extra_head' => $html_extra_head,
));

3. Persistência de Estilos nos Módulos Menus, Galerias e Destaques

3.1 CRUD Administrativo (PHP)

Aplicar o mesmo tratamento de persistência e edição de css_compiled e html_extra_head nos arquivos:

Regras:

  1. Mapeamento e Sanitização (adicionar e clonar / submit do form): No submit de gravação no banco, ler os requests e aplicar o preg_replace de variáveis globais:

    $_REQUEST['css_compiled'] = preg_replace("/".preg_quote($openText)."(.+?)".preg_quote($closeText)."/", strtolower($open."$1".$close), $_REQUEST['css_compiled'] ?? '');
    $_REQUEST['html_extra_head'] = preg_replace("/".preg_quote($openText)."(.+?)".preg_quote($closeText)."/", strtolower($open."$1".$close), $_REQUEST['html_extra_head'] ?? '');

    Mapear nas arrays de campos a serem inseridos:

    foreach(['html','css','css_compiled','html_extra_head'] as $clonable_field){
        if(isset($_REQUEST[$clonable_field]) && $_REQUEST[$clonable_field] !== ''){
            $campos[] = Array($clonable_field, banco_escape_field($_REQUEST[$clonable_field]));
        }
    }
  2. Validação e Backup (editar):

    • Adicionar 'css_compiled' e 'html_extra_head' ao array $camposBanco.

    • No submit do update, sanitizar as variáveis e verificar alterações aplicando backups caso os valores anteriores existam (usando banco_select_campos_antes e interface_backup_campo_incluir).

  3. Placeholders no Editor HTML (editar e clonar):

    • Substituir placeholders do editor no DOM para alimentar o CodeMirror:

      $_GESTOR['pagina'] = modelo_var_troca_tudo($_GESTOR['pagina'],'#pagina-css-compiled#',$css_compiled);
      $_GESTOR['pagina'] = modelo_var_troca_tudo($_GESTOR['pagina'],'#pagina-html-extra-head#',$html_extra_head);
    • Na tela de clonagem, carregar os valores originais do banco e adicioná-los como campos de formulário ocultos no template para que trafeguem no submit:

      $_GESTOR['pagina'] = modelo_var_troca_tudo($_GESTOR['pagina'],'#css-compiled-original#',htmlspecialchars($css_compiled, ENT_QUOTES));
      $_GESTOR['pagina'] = modelo_var_troca_tudo($_GESTOR['pagina'],'#html-extra-head-original#',htmlspecialchars($html_extra_head, ENT_QUOTES));

3.2 Refatorar Renderização de Widgets (.widget.php)

Nos arquivos de widgets públicos, extrair css_compiled e html_extra_head do banco, repassá-los ao renderizador inline e modificar a função de montagem de saída:

Regras:

  1. Selecionar do Banco: Adicionar css_compiled e html_extra_head no select do registro.

  2. Chamar Renderizador Inline: Passar css_compiled e html_extra_head nas propriedades do array de render.

  3. Montar Saída: Modificar as funções xxx_widget_montar_saida para realizar a injeção em $_GESTOR e retornar apenas o HTML limpo:

    function xxx_widget_montar_saida($html, $css, $css_compiled = '', $html_extra_head = ''){
        gestor_pagina_recursos_incluir(Array(
            'css' => $css,
            'css_compiled' => $css_compiled,
            'html_extra_head' => $html_extra_head,
        ));
        return $html;
    }

4. Novo Módulo: Publicador Índice (Publisher Index)

4.1 Estrutura de Arquivos e Manifesto [NEW]

Criar a pasta gestor/modulos/publisher-index/ contendo:

  • publisher-index.json: Configuração do manifesto do módulo. Clonar a estrutura do publisher-highlights.json, alterando todas as strings e identificadores de publisher-highlights para publisher-index. O nome visível do módulo deve ser "Publicador Índice" (pt-br) / "Publisher Index" (en).

  • Recursos de Tradução: Criar a estrutura resources/en/ e resources/pt-br/ com suas subpastas contendo os HTMLs/CSS e arquivos JSON de interface de CRUD de forma análoga a destaques, renomeando todas as variáveis e títulos.

4.2 Migração de Banco de Dados [NEW]

Criar a migração gestor/db/migrations/20260611120000_create_publisher_index_table.php para declarar a tabela do novo módulo:

  • Nome da Tabela: publisher_index

  • Chave Primária: id_publisher_index

  • Colunas: Copiar exatamente a estrutura física da tabela publisher_highlights (com css_compiled e html_extra_head já incorporados), ajustando índices e defaults.

4.3 CRUD Administrativo (publisher-index.php) [NEW]

Desenvolver o script do backend de administração clonado e adaptado do publisher-highlights.php.

  • Diferença no fields_schema: O fields_schema deste módulo suporta novas propriedades de exibição além de rule, count, order_by e selected_items:

    • items_per_page (int, default 10)

    • show_search_input (bool, default true)

    • show_sorting_select (bool, default true)

    • show_load_more_btn (bool, default true)

  • Mapeamento e Serialização: Garantir a leitura, hidratação de variáveis globais client-side no page load, e a persistência correta destas chaves adicionais no banco.

4.4 Interface do Painel Administrativo (publisher-index.js) [NEW]

Desenvolver o JavaScript do painel clonado de publisher-highlights.js:

  • Substituir termos globais por publisher-index ou publisher_index.

  • Inserir os elementos na aba de parâmetros para expor os novos campos (Exibição da barra de busca, ordenação de itens e paginação "Carregar Mais" com campo numérico para itens por página).

  • Incluir no parser e na serialização do schema estas novas variáveis.

4.5 Widget Renderer (publisher-index.widget.php) [NEW]

Criar o renderizador PHP do widget público em gestor/modulos/publisher-index/publisher-index.widget.php.

  • Inclusão do Script Público: A função publisher_index_render($params) deve incluir o script frontend do widget:

    gestor_pagina_javascript_incluir(Array(
        'tipo' => 'widget',
        'modulo_id' => 'publisher-index',
        'versao' => publisher_index_get_version(),
    ));
  • Renderização Inicial (Backend - Page Load):

    • Seleciona o registro da tabela publisher_index pelo slug correspondente.

    • Carrega as configurações (fields_schema JSON).

    • Injeta os recursos no head chamando gestor_pagina_recursos_incluir().

    • Busca as publicações da primeira página (de 0 a items_per_page) filtrando pelo publicador.

    • Injeta no elemento HTML do contêiner atributos data-* para que o script Javascript client-side consiga identificar os parâmetros de execução (ex: data-grupo-slug="[slug]" data-items-per-page="[N]" data-page="1" data-publisher-id="[pub_id]").

    • Caso haja mais itens no banco do que os exibidos na primeira página, renderizar o botão "Carregar Mais" (se ativo no schema).

    • Retornar o HTML gerado.

  • Roteamento AJAX (publisher_index_render_ajax): Lógica acionada quando o widget faz requisição AJAX em produção:

    function publisher_index_render_ajax($params){
        global $_GESTOR;
        $grupo_slug = $_REQUEST['ajaxRegistroId'] ?? '';
        $busca = $params['busca'] ?? '';
        $ordenacao = $params['ordenacao'] ?? 'date_desc';
        $pagina = (int)($params['pagina'] ?? 1);
        if(empty($grupo_slug)) return;
        // 1) Buscar registro no banco de dados e ler fields_schema
        // 2) Calcular offsets de paginação baseados em $pagina e $items_per_page (lido de fields_schema)
        // 3) Realizar consulta SQL na tabela paginas/publisher_pages aplicando WHERE
        //    para o publisher_id E filtrando registros cujo campo "nome" ou
        //    campos customizados combinem com o termo $busca (LIKE %$busca%)
        // 4) Aplicar a ordenação $ordenacao correspondente (date_desc, date_asc, title_asc, title_desc)
        // 5) Renderizar os itens usando o template HTML
        // 6) Verificar se há uma próxima página (tem_mais) rodando count de controle
        // 7) Definir $_GESTOR['ajax-json'] com o resultado:
        $_GESTOR['ajax-json'] = Array(
            'status' => 'Ok',
            'html' => $html_itens_renderizados,
            'tem_mais' => $tem_mais_itens
        );
    }

4.6 Comportamento Público Client-Side (publisher-index.widget.js) [NEW]

Criar o script do widget público em gestor/modulos/publisher-index/publisher-index.widget.js para gerenciar a interface dinâmica na página de produção:

  1. Escopo e Inicialização: Identificar todos os elementos .conn2flow-publisher-index na página. Para cada um, inicializar o estado inicial (Página = 1, Busca = '', Ordenação = inicial).

  2. Eventos:

    • Busca (Pesquisa): Escutar input em .publisher-index-search. Aplicar debounce de 300ms. Atualizar estado local de busca, resetar página para 1 e disparar AJAX.

    • Ordenação: Escutar change em .publisher-index-sort. Atualizar estado local de ordenação, resetar página para 1 e disparar AJAX.

    • Carregar Mais: Escutar clique em .publisher-index-load-more. Incrementar a página local em 1 e disparar AJAX de paginação.

  3. Chamada AJAX: Disparar requisição POST/GET para o endereço atual da página enviando os dados parametrizados no array params e os ponteiros de widgets:

    var requestData = 'ajax=sim' +
        '&ajaxOpcao=publisher-index-load' +
        '&ajaxRegistroId=' + encodeURIComponent(grupoSlug) +
        ((typeof gestor !== 'undefined' && gestor.widgetsToAjax) ? '&ajaxWidgets=' + encodeURIComponent(gestor.widgetsToAjax) : '') +
        '&params%5Bbusca%5D=' + encodeURIComponent(buscaEstado) +
        '&params%5Bpagina%5D=' + encodeURIComponent(paginaEstado) +
        '&params%5Bordenacao%5D=' + encodeURIComponent(ordenacaoEstado);
    $.ajax({
        url: window.location.href,
        type: 'POST',
        data: requestData,
        dataType: 'json',
        success: function(res) {
            if(res.status === 'Ok') {
                if(paginaEstado === 1) {
                    // Substitui os itens existentes
                    $containerItens.html(res.html);
                } else {
                    // Anexa os novos itens no final
                    $containerItens.append(res.html);
                }
                // Exibir/ocultar botão "Carregar Mais"
                if(res.tem_mais) {
                    $btnLoadMore.removeClass('hidden');
                } else {
                    $btnLoadMore.addClass('hidden');
                }
            }
        }
    });

4.7 Modo de IA do Publicador Índice (publisher-index.md) [NEW]

Criar o arquivo markdown do modo de IA do índice:

  • gestor/modulos/publisher-index/resources/pt-br/ai_modes/publisher-index/publisher-index.md

  • gestor/modulos/publisher-index/resources/en/ai_modes/publisher-index/publisher-index.md

  • Regras: Clonar e adaptar as instruções de publisher-highlights.md para suportar a injeção do contêiner de busca, ordenação de itens e o botão de carregamento condicional. Listar as novas variáveis e blocos para a IA (ex: [[items_per_page]], [[show_search_input]], etc.).


5. Regras de Homologação e Execução

  • Manifestos: Adicionar a configuração de IA correspondente em publisher-index.json.

  • Executar Rotina: O executor deve rodar o script de atualização de dados e recursos atualizacao-dados-recursos.php para registrar o novo módulo, componentes e alvos de IA.

  • Restrição: Todas as edições permanecem locais na máquina de testes, sem commits/pushes por parte do executor.

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