Appearance
Recuperação de Ambiente (Disaster Recovery)
Procedimento para reconstruir o ambiente local após corrupção de disco (ex.: reset forçado do WSL2), perda do .env ou re-clone do repositório sem os artefatos ignorados pelo Git.
Sintomas
| Sintoma | Causa provável |
|---|---|
app, horizon, reverb em loop de restart | Pasta bootstrap/cache/ ausente (gitignored, não vem no clone) |
chmod: /var/www/html/bootstrap/cache*: No such file or directory | Mesma — entrypoint.sh falha antes do php-fpm subir |
HTTP 502 em localhost:<porta-web> | Container app morto, nginx não tem upstream |
HTTP 500 + Vite manifest not found at: public/build/manifest.json | Frontend não foi buildado |
Erro do Vite Could not load /resources/js/routes | Wayfinder não foi gerado |
Seeder falha com Access denied for user 'laravel'@'%' to database 'tenantalfa' | Usuário laravel sem CREATE DATABASE (necessário para multi-tenant) |
Tenant could not be identified on domain localhost | Acessando via localhost em vez de igreja.test/subdomínio |
Checklist de Recuperação
1. Restaurar .env
Comparar chaves entre backup e .env.example:
bash
comm -23 <(grep -oP '^[A-Z_]+(?==)' html/.env.example | sort -u) \
<(grep -oP '^[A-Z_]+(?==)' html/.env | sort -u)Chaves obrigatórias que costumam faltar em backups antigos:
env
BACKUP_DISK=local
META_REVIEWER_EMAIL=Secrets que ficam vazios e podem ser preenchidos sob demanda: ASAAS_*, GOOGLE_CLIENT_*, FACEBOOK_CLIENT_*, OPENAI_API_KEY, ANTHROPIC_API_KEY, META_WHATSAPP_APP_SECRET, NGROK_AUTHTOKEN, NGROK_DOMAIN.
2. Recriar diretórios gitignored
bash
mkdir -p html/bootstrap/cache
chmod 775 html/bootstrap/cachestorage/ e subpastas (app/, framework/{cache,sessions,testing,views}, logs/) vêm versionadas via .gitignore interno; só recrie se também sumiram.
3. Subir containers
bash
docker compose up -d
docker compose psEsperado: mariadb healthy, app/horizon/reverb Up (não Restarting). ngrok em restart é normal quando NGROK_AUTHTOKEN está vazio — ignorar a menos que precise do webhook do WhatsApp.
4. Privilégios MariaDB para multi-tenant
stancl/tenancy cria um banco por tenant (tenantalfa, tenantbeta, ...) — o usuário laravel precisa de CREATE DATABASE. Senha de root no compose é o valor de DB_USERNAME (literal laravel):
bash
docker compose exec -T mariadb mariadb -uroot -plaravel -e "
GRANT ALL PRIVILEGES ON *.* TO 'laravel'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
"WARNING
Sem isso o TenantSeeder aborta com Access denied for user 'laravel'@'%' to database 'tenantalfa'.
5. Restaurar schema/dados
Se tem dump SQL de backup, importe antes de qualquer migrate:
bash
docker compose exec -T mariadb mariadb -ularavel -plaravel laravel < dump.sqlSe não tem dump (ambiente local from-scratch):
bash
docker compose exec -T app php artisan migrate:fresh --seed --forceCria schema central + 3 tenants de dev (alfa, beta, charlie).
6. Gerar rotas Wayfinder
resources/js/routes/ e resources/js/actions/ são gitignored e devem ser geradas antes do build do Vite:
bash
docker compose exec -T app php artisan wayfinder:generate --with-form7. Build frontend
bash
docker compose exec -T node npm run buildPara dev com HMR, use npm run dev no lugar do build.
8. Verificação
Descubra a porta exposta pelo web no seu docker-compose.yml (cada dev pode usar uma diferente):
bash
PORT=$(docker compose port web 80 | cut -d: -f2)
echo "Porta do nginx: $PORT"
for host in www.igreja.test alfa.igreja.test igreja.test; do
curl -s -o /dev/null -w "$host = %{http_code}\n" -H "Host: $host" "http://localhost:$PORT"
doneOs três devem retornar 200. localhost puro retorna 500 (multi-tenant não identifica o domínio) — não é regressão.
Artefatos não versionados (resumo)
| Caminho | Como recriar |
|---|---|
html/bootstrap/cache/ | mkdir (passo 2) |
html/storage/app/, html/storage/framework/*/, html/storage/logs/ | já vêm com .gitignore interno; mkdir se sumiram |
html/vendor/ | docker compose exec -T app composer install |
html/node_modules/ | docker compose exec -T node npm install |
html/public/build/ | passo 7 (npm run build) |
html/resources/js/routes/, html/resources/js/actions/ | passo 6 (wayfinder:generate) |
igreja/data/ (MariaDB) | recriado pelo container no boot; restaure dump se tiver |
igreja/redis_data/, igreja/typesense_data/ | recriados pelos containers; perda só impacta cache/índice |
Hosts
Lembre-se de manter no /etc/hosts todos os subdomínios. Se faltar algum, o browser nem chega no nginx e o tenant aparenta estar "fora" — mesmo com containers OK:
127.0.0.1 igreja.test www.igreja.test alfa.igreja.test beta.igreja.test charlie.igreja.testVerifique:
bash
for h in igreja.test www.igreja.test alfa.igreja.test beta.igreja.test charlie.igreja.test; do
getent hosts "$h" >/dev/null && echo "OK $h" || echo "FAIL $h"
donePorta do nginx
A porta exposta pelo serviço web no docker-compose.yml é por-dev (cada um pode ajustar para evitar conflito local). Para descobrir:
bash
docker compose port web 80Acesse os tenants usando essa porta: http://alfa.igreja.test:<porta>. Se for 80, omita.