Padronização para manutenção

Padrão de um módulo BarberBot

Esta página mostra o esqueleto ideal de um módulo para manter o BarberBot consistente. O objetivo é ajudar o próximo desenvolvedor a saber quais arquivos criar, qual responsabilidade cada um tem e como organizar o fluxo.

Estrutura de módulo PHP puro Fluxo previsível Consistência de manutenção
Objetivo

Como o próximo dev deve entender um módulo

No BarberBot, um módulo normalmente é composto por uma tela principal e uma subpasta com arquivos operacionais. A tela principal monta a interface e os arquivos internos executam as ações.

O que a tela principal faz

  • Mostra filtros, botões e modais.
  • Carrega a listagem inicial.
  • Dispara chamadas AJAX para os arquivos internos.
  • Atualiza a interface após salvar, buscar ou excluir.

O que os arquivos internos fazem

  • listar.php consulta e monta HTML.
  • salvar.php insere ou atualiza dados.
  • buscar.php carrega um registro específico.
  • excluir.php remove um registro.
Ponto central: o padrão não existe para “engessar” o projeto. Ele existe para o próximo dev abrir qualquer pasta e reconhecer o módulo sem reaprender tudo do zero.
Estrutura mínima

Pastas e arquivos esperados

Quando for criar ou reorganizar um módulo, este é o formato mais previsível para o BarberBot:

/public_html/sistema/painel/paginas/nome_modulo.php
/public_html/sistema/painel/paginas/nome_modulo/listar.php
/public_html/sistema/painel/paginas/nome_modulo/salvar.php
/public_html/sistema/painel/paginas/nome_modulo/buscar.php
/public_html/sistema/painel/paginas/nome_modulo/excluir.php

Arquivo principal

nome_modulo.php fica diretamente em /paginas e representa a tela.

Subpasta operacional

A subpasta /nome_modulo concentra as operações que a tela chama por AJAX.

Responsabilidades

O que cada arquivo deve fazer

nome_modulo.php

Arquivo de interface. Deve concentrar HTML da tela, filtros, modais, botões e chamadas AJAX.

listar.php

Arquivo de listagem. Deve consultar o banco, aplicar filtros, montar a tabela e devolver HTML.

salvar.php

Arquivo de persistência. Deve validar entradas e executar INSERT ou UPDATE.

buscar.php

Arquivo de carregamento individual. Deve retornar dados de um registro para preencher formulário ou modal.

excluir.php

Arquivo de remoção. Deve validar o ID, excluir com segurança e retornar status simples para a tela.

Boa prática: mesmo que o BarberBot misture algumas responsabilidades em módulos antigos, o ideal para novos módulos é manter o máximo de previsibilidade possível.
Esqueleto ideal

Base de código para novos módulos

nome_modulo.php

Este arquivo deve ser a porta de entrada do módulo. Ele monta a tela, exibe o formulário e dispara as ações.

<?php
require_once("../../conexao.php");
$pag = 'nome_modulo';
?>

<div class="titulo-pagina">
  <h2><?php echo ucfirst(str_replace('_', ' ', $pag)); ?></h2>
  <button type="button" class="btn btn-primary" onclick="abrirModalCadastro()">Novo cadastro</button>
</div>

<div class="filtros-pagina">
  <input type="text" id="busca" class="form-control" placeholder="Buscar...">
  <button type="button" class="btn btn-secondary" onclick="listar()">Filtrar</button>
</div>

<div id="listar"></div>

<div class="modal fade" id="modalForm" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      <form id="form">
        <div class="modal-header">
          <h5 class="modal-title" id="tituloModal">Cadastrar registro</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
        </div>

        <div class="modal-body">
          <input type="hidden" name="id" id="id">
          <div class="row">
            <div class="col-md-12">
              <label>Nome</label>
              <input type="text" class="form-control" name="nome" id="nome" required>
            </div>
          </div>
          <small id="mensagem"></small>
        </div>

        <div class="modal-footer">
          <button type="submit" class="btn btn-primary">Salvar</button>
        </div>
      </form>
    </div>
  </div>
</div>

<script>
function listar() {
  var busca = $('#busca').val();

  $.ajax({
    url: 'paginas/' + 'nome_modulo' + '/listar.php',
    method: 'POST',
    data: { busca: busca },
    dataType: 'html',
    success: function(resposta) {
      $('#listar').html(resposta);
    }
  });
}

function abrirModalCadastro() {
  limparCampos();
  $('#tituloModal').text('Cadastrar registro');
  $('#modalForm').modal('show');
}

function limparCampos() {
  $('#id').val('');
  $('#nome').val('');
  $('#mensagem').text('');
}

$('#form').on('submit', function(e) {
  e.preventDefault();

  $.ajax({
    url: 'paginas/' + 'nome_modulo' + '/salvar.php',
    method: 'POST',
    data: new FormData(this),
    processData: false,
    contentType: false,
    success: function(resposta) {
      if (resposta.trim() === 'Salvo com Sucesso') {
        $('#modalForm').modal('hide');
        listar();
      } else {
        $('#mensagem').text(resposta);
      }
    }
  });
});

$(document).ready(function() {
  listar();
});
</script>

listar.php

Responsável por consultar, tratar lista vazia e retornar o HTML da tabela já pronto para a tela.

<?php
require_once("../../../conexao.php");
@session_start();

$busca = trim($_POST['busca'] ?? '');

$sql = "SELECT * FROM nome_tabela WHERE nome LIKE :busca ORDER BY id DESC";
$query = $pdo->prepare($sql);
$query->bindValue(':busca', '%' . $busca . '%');
$query->execute();
$res = $query->fetchAll(PDO::FETCH_ASSOC);
$total_reg = count($res);

if ($total_reg == 0) {
  echo '<div class="alert alert-light border">Nenhum registro encontrado.</div>';
  exit();
}
?>

<table class="table table-hover">
  <thead>
    <tr>
      <th>Nome</th>
      <th class="esc">Data</th>
      <th width="120">Ações</th>
    </tr>
  </thead>
  <tbody>
    <?php foreach ($res as $item): ?>
      <tr>
        <td><?php echo htmlspecialchars($item['nome']); ?></td>
        <td class="esc"><?php echo date('d/m/Y', strtotime($item['data_cad'])); ?></td>
        <td>
          <button type="button" class="btn btn-sm btn-outline-primary"
                  onclick="editar('<?php echo $item['id']; ?>')">Editar</button>
          <button type="button" class="btn btn-sm btn-outline-danger"
                  onclick="excluir('<?php echo $item['id']; ?>')">Excluir</button>
        </td>
      </tr>
    <?php endforeach; ?>
  </tbody>
</table>

salvar.php

Deve centralizar validação mínima e persistência. O retorno deve ser simples para o AJAX interpretar.

<?php
require_once("../../../conexao.php");
@session_start();

$id   = (int)($_POST['id'] ?? 0);
$nome = trim($_POST['nome'] ?? '');

if ($nome === '') {
  echo 'Preencha o campo nome';
  exit();
}

if ($id > 0) {
  $query = $pdo->prepare("UPDATE nome_tabela SET nome = :nome WHERE id = :id");
  $query->bindValue(':id', $id, PDO::PARAM_INT);
} else {
  $query = $pdo->prepare("INSERT INTO nome_tabela SET nome = :nome, data_cad = curDate()");
}

$query->bindValue(':nome', $nome);
$query->execute();

echo 'Salvo com Sucesso';

buscar.php

Indicado para edição em modal. O ideal é responder em JSON para preencher campos no JavaScript.

<?php
require_once("../../../conexao.php");
@session_start();

$id = (int)($_POST['id'] ?? 0);

if ($id <= 0) {
  echo json_encode(['sucesso' => false, 'mensagem' => 'ID inválido']);
  exit();
}

$query = $pdo->prepare("SELECT * FROM nome_tabela WHERE id = :id LIMIT 1");
$query->bindValue(':id', $id, PDO::PARAM_INT);
$query->execute();
$res = $query->fetch(PDO::FETCH_ASSOC);

if (!$res) {
  echo json_encode(['sucesso' => false, 'mensagem' => 'Registro não encontrado']);
  exit();
}

echo json_encode([
  'sucesso' => true,
  'dados' => [
    'id'   => $res['id'],
    'nome' => $res['nome']
  ]
]);

excluir.php

Deve ser objetivo: validar o ID, excluir o registro e retornar uma mensagem curta de sucesso ou erro.

<?php
require_once("../../../conexao.php");
@session_start();

$id = (int)($_POST['id'] ?? 0);

if ($id <= 0) {
  echo 'ID inválido';
  exit();
}

$query = $pdo->prepare("DELETE FROM nome_tabela WHERE id = :id");
$query->bindValue(':id', $id, PDO::PARAM_INT);
$query->execute();

echo 'Excluído com Sucesso';
Fluxo esperado

Como os arquivos se encadeiam

O módulo ideal do BarberBot segue um fluxo simples e previsível. Isso facilita depuração, manutenção e onboarding de novos devs.

nome_modulo.php
    ↓
listar.php
    ↓
conexao.php
    ↓
SELECT na tabela
    ↓
HTML volta para a tela

nome_modulo.php
    ↓
salvar.php
    ↓
conexao.php
    ↓
INSERT / UPDATE
    ↓
mensagem de retorno
    ↓
listar.php é chamado novamente

Depois de salvar

O padrão mais simples é: salvar, fechar modal, chamar listar() novamente.

Quando usar JSON

Para buscar um registro e preencher formulário, JSON costuma ser melhor do que HTML.

Checklist de consistência

Antes de entregar um módulo novo

Estrutura

  • A tela principal está em /paginas.
  • A subpasta do módulo contém os arquivos operacionais.
  • Os nomes seguem um padrão previsível.
  • O módulo já abre listando os dados.

Segurança mínima

  • As queries usam prepare e bindValue.
  • IDs chegam tratados como inteiro.
  • Campos obrigatórios têm validação antes do banco.
  • Saídas HTML usam htmlspecialchars quando necessário.

Testes

  • Listagem vazia funciona.
  • Cadastro novo funciona.
  • Edição carrega os dados corretos.
  • Exclusão remove e recarrega a listagem.

Manutenção

  • O próximo dev consegue localizar rápido cada responsabilidade.
  • O AJAX retorna mensagens previsíveis.
  • Não há regra crítica escondida no JavaScript sem correspondente no backend.
  • O módulo segue o mesmo padrão dos demais.
Resumo final: o melhor padrão de módulo no BarberBot é aquele em que o próximo dev consegue reconhecer, em poucos minutos, qual arquivo monta a tela, qual lista, qual salva, qual busca e qual exclui.