CLI
Comandos PHP CLI do MAD.
CLI — php artisan
O MAD framework não tem um runner próprio — é php artisan, o CLI nativo do Laravel,
com um punhado de comandos extras no namespace mad:* (migrations multi-tenant,
observabilidade, manutenção). Tudo que funciona num app Laravel comum funciona aqui.
Uso
php artisan list # todos os comandos disponíveis
php artisan list mad # só os comandos do namespace mad:*
php artisan help migrate # ajuda detalhada de 1 comando
Migrations
Padrão do Laravel — database/migrations/ é a fonte única, e cada migration usa
Schema::connection('nome') quando precisa mirar uma conexão específica
(minierp, permission/iam, communication/comm, ged, ai, ...; veja
config/database.php). Um único php artisan migrate roda tudo:
php artisan migrate # roda as migrations pendentes
php artisan migrate --pretend # mostra o SQL sem executar
php artisan migrate:status # o que já rodou x o que está pendente
php artisan migrate:rollback # desfaz o último batch
php artisan migrate:rollback --step=3 # desfaz os últimos 3 batches
php artisan migrate:fresh # dropa tudo e roda do zero (destrutivo — pede confirmação)
php artisan make:migration CreateOrdersTable
Multi-tenant — mad:tenant:*
Específico do modo multi-tenant (1 DB físico por tenant para o data-plane
business/comm/ged/ai; o control-plane fica compartilhado e migra normal):
# Provisiona o DB de 1 tenant novo + registra em mad_iam_tenant
php artisan mad:tenant:provision acme
php artisan mad:tenant:provision acme --database=/path/acme.sqlite --connection=tenant_acme
# Sincroniza o schema data-plane em TODOS os tenants já registrados (idempotente)
php artisan mad:tenant:migrate
php artisan mad:tenant:migrate --tenant=acme # só 1 tenant
Filas
php artisan queue:work # worker em foreground
php artisan queue:work --queue=critical,default # múltiplas filas por prioridade
php artisan queue:work --once # processa 1 job e sai
php artisan queue:failed # lista jobs falhados
php artisan queue:retry all # re-tenta todos os falhados
php artisan queue:flush # apaga todos os falhados
php artisan queue:restart # sinaliza os workers a reciclar (pós-deploy)
Ver Filas para a lista completa de opções e como subir o worker em produção (systemd/Supervisor).
Agendamento
php artisan schedule:run # executa tarefas devidas agora (o que o cron chama)
php artisan schedule:list # lista tarefas com próxima execução
php artisan schedule:work # loop local, substitui o cron em dev
Ver Scheduler para como definir tarefas.
Banco de dados
php artisan db:show # visão geral da conexão default (tabelas, tamanho)
php artisan db:show --database=ged # outra conexão configurada
php artisan db:table mad_comm_notification # estrutura de 1 tabela
Observabilidade — mad:trace-*
Agendados automaticamente em routes/console.php (a cada minuto) — normalmente você não
chama isso à mão, mas é útil para depurar o pipeline do MadTrace:
php artisan mad:trace-flush # drena o spool NDJSON (modo send=async) pro receptor
php artisan mad:trace-flush --max-attempts=5
php artisan mad:trace-infra # snapshot de infra (CPU/mem/disco/filas) pro receptor
php artisan mad:trace-infra --dry # só imprime o payload, não envia
REST Driver — mad:rest-driver:install
Pareia o app com o Database Manager do MadBuilder (acesso serviço-a-serviço, HMAC, sem abrir porta/VPN). O segredo só aparece nesta saída uma vez:
php artisan mad:rest-driver:install --connection=business
php artisan mad:rest-driver:install --connection=business --read-only --label="leitura BI"
php artisan mad:rest-driver:install --json > pareamento.json # só o JSON, p/ pipe
| Flag | Default | Descrição |
|---|---|---|
--connection= |
a conexão padrão do app | Conexão de banco a expor |
--read-only |
off | Bloqueia INSERT/UPDATE/DELETE nesta chave |
--label= |
— | Rótulo livre para identificar a chave |
--url= |
APP_URL + path |
URL pública do driver |
--json |
off | Imprime só o JSON do pareamento (para pipe) |
MCP — mad:mcp:lint-scope
Valida o bloco scope de mcp.config.json contra o schema real do banco (gate de CI) —
detecta owner_column/unit_column que não existem de verdade, tabelas expostas sem
escopo, e colunas audit-only (created_by, granted_by, ...) usadas por engano como dono:
php artisan mad:mcp:lint-scope
php artisan mad:mcp:lint-scope --manifest=/path/alternativo/mcp.config.json
Saída != 0 (com tabela → problema → fix) se houver violação.
Manutenção — uso local/QA
# Limpa exports antigos (CSV/XLSX/PDF) do scratch (disco mad_tmp, prefixo output/)
# O MadGridExporter grava cada export como output/<uniqid>.<ext> e nunca limpa —
# sem isto o diretório cresce sem limite. Já agendado diário em routes/console.php.
php artisan mad:grid:purge-exports
php artisan mad:grid:purge-exports --hours=48 --dry-run # --hours default: 24
# Move uploads legados de public/uploads (expostos) para uploads/ (privado, fora do docroot)
php artisan mad:uploads:migrate-private --dry-run
php artisan mad:uploads:migrate-private
# Reabre o instalador web pra QA — SÓ roda em APP_ENV=local (apaga DB SQLite + token)
php artisan mad:install-reset
php artisan mad:install-reset --keep-db # preserva o banco, zera só o gate
# Puxa o código gerado mais recente do MadBuilder (app vinculado a um projeto)
php artisan mad:self-update --dry # só mostra o diff
php artisan mad:self-update
A tela Central de Comando (admin) expõe boa parte disso numa UI — migrations, jobs, agendamentos e o sync com o MadBuilder — sem precisar de SSH.
Criando comandos próprios
Comandos da sua aplicação seguem o fluxo padrão do Laravel:
php artisan make:command RelatorioMensalCommand
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class RelatorioMensalCommand extends Command
{
protected $signature = 'relatorio:mensal {--mes=}';
protected $description = 'Gera o relatório mensal de vendas';
public function handle(): int
{
$mes = $this->option('mes') ?: now()->format('Y-m');
$this->info("Gerando relatório de {$mes}...");
// lógica aqui
return self::SUCCESS;
}
}
O comando já aparece em php artisan list (auto-discovery via app/Console/Commands/) e
pode ser agendado normalmente em routes/console.php:
Schedule::command('relatorio:mensal')->monthlyOn(1, '06:00');