Skip to content

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

SintomaCausa provável
app, horizon, reverb em loop de restartPasta bootstrap/cache/ ausente (gitignored, não vem no clone)
chmod: /var/www/html/bootstrap/cache*: No such file or directoryMesma — 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.jsonFrontend não foi buildado
Erro do Vite Could not load /resources/js/routesWayfinder 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 localhostAcessando 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/cache

storage/ 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 ps

Esperado: 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.sql

Se não tem dump (ambiente local from-scratch):

bash
docker compose exec -T app php artisan migrate:fresh --seed --force

Cria 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-form

7. Build frontend

bash
docker compose exec -T node npm run build

Para 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"
done

Os 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)

CaminhoComo 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.test

Verifique:

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"
done

Porta 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 80

Acesse os tenants usando essa porta: http://alfa.igreja.test:<porta>. Se for 80, omita.