# Runbook de desenvolvimento e operação ## Desenvolvimento local 1. Copiar `.env.example` para `.env`. 2. Executar `docker compose build`. 3. Gerar a chave com `docker compose run --rm app php artisan key:generate`. 4. Iniciar com `docker compose up -d`. 5. Preparar dados com `docker compose exec app php artisan migrate --seed`. 6. Abrir o portal em `http://localhost:8000` e emails em `http://localhost:8025`. ## Diagnóstico ```bash docker compose ps docker compose logs --tail=100 app docker compose logs --tail=100 queue docker compose exec app php artisan about docker compose exec app php artisan migrate:status docker compose exec postgres pg_isready -U reserva -d reserva docker compose exec redis redis-cli ping ``` ### Página em branco no desenvolvimento Se o HTML responder mas a interface React não aparecer, confirmar que `public/hot` contém `http://localhost:5173` e não `http://0.0.0.0:5173`. Depois validar os módulos: ```bash curl -I -H 'Origin: http://localhost:8000' http://localhost:5173/@vite/client curl -I -H 'Origin: http://localhost:8000' http://localhost:5173/resources/js/app.tsx ``` Ambos devem responder com estado 200 e `Access-Control-Allow-Origin: http://localhost:8000`. Reiniciar o serviço com `docker compose restart node` se o ficheiro `public/hot` estiver desatualizado. Confirmar também que o HTML inicial já contém conteúdo SSR: ```bash curl -s http://localhost:8000/login | grep 'data-server-rendered="true"' ``` Se o endpoint Vite devolver um erro SSR, procurar primeiro componentes globais montados em `withApp` que chamem hooks Inertia como `usePage()`. Os elementos irmãos do argumento `app` não pertencem ao respetivo contexto; devem receber as propriedades através do segundo argumento de `withApp`. ## Atualização de código ```bash docker compose exec app composer install docker compose exec node npm install docker compose exec app php artisan migrate --force docker compose exec app php artisan optimize:clear docker compose restart queue scheduler ``` ## Integração Snipe-IT Definir no ambiente, sem colocar tokens no repositório: ```dotenv SNIPE_IT_URL=https://inventario.exemplo.pt SNIPE_IT_READ_TOKEN= SNIPE_IT_TIMEOUT=10 SNIPE_IT_PAGE_SIZE=100 SNIPE_IT_RETRIES=3 SNIPE_IT_RETRY_DELAY_MS=250 ``` O token deve pertencer a uma conta técnica com acesso apenas de leitura aos ativos. A aplicação acrescenta `/api/v1` automaticamente quando a URL não o contém. Operações: ```bash # Sincronização imediata e resultado no terminal docker compose exec app php artisan snipe:sync-assets # Colocar na fila docker compose exec app php artisan snipe:sync-assets --queue # Confirmar o agendamento horário docker compose exec app php artisan schedule:list ``` Administradores podem testar a ligação, iniciar uma execução e consultar as últimas dez sincronizações em `http://localhost:8000/administracao/snipe-it`. Uma execução falhada mantém o último catálogo válido e não desativa registos ausentes. Consultar `sync_runs`, os logs do worker e o painel antes de repetir. ## Produção Antes de disponibilizar: - definir `APP_ENV=production`, `APP_DEBUG=false` e HTTPS; - substituir todas as palavras-passe do exemplo; - montar segredos fora do repositório; - remover exposição pública das portas PostgreSQL, Vite e Mailpit; - configurar volumes persistentes e backups cifrados; - executar `php artisan optimize` e frontend compilado; - definir health checks, alertas e rotação de logs; - testar recuperação de backup e falha Snipe-IT. ## Backups Salvaguardar diariamente PostgreSQL e uploads. Manter retenção semanal/mensal e uma cópia fora do servidor. Segredos são salvaguardados através de procedimento separado. Executar um teste de restauro periódico e registar o resultado.