Infraestrutura & Ferramentas

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');