[[:templates_ai|{{wiki:user:undo_24.png}}]] ====== Hostinger: Deploy Automático ====== ===== ⚠️ INSTRUÇÕES IMPORTANTES ANTES DE COMEÇAR ===== **Para evitar erros durante a implementação, siga EXATAMENTE estas etapas:** ✅ **1. Ler o template COMPLETO da página** * Leia toda a documentação antes de começar * Entenda o fluxo completo de implementação * Identifique dependências entre os passos ✅ **2. Identificar TODOS os arquivos mencionados** * Liste todos os arquivos que serão criados/modificados * Verifique se já existem no projeto * Anote o caminho exato de cada arquivo ✅ **3. Verificar a estrutura EXATA de cada arquivo** * Confirme namespaces e imports corretos * Verifique se dependências estão instaladas * Valide sintaxe PHP antes de implementar ✅ **4. Implementar linha por linha conforme template** * Copie o código EXATAMENTE como mostrado * Não modifique namespaces ou imports * Execute comandos na ordem especificada **🚨 ATENÇÃO:** * **NÃO pule etapas** - cada passo tem dependências * **NÃO modifique** o código fornecido sem entender as consequências * **SEMPRE teste** após cada implementação * **MANTENHA backup** antes de grandes alterações ===== 📋 Visão Geral ===== Sistema completo de deploy automático para Hostinger usando webhooks do GitHub. Este sistema permite deploy automático quando há push para a branch `hostinger-deploy-auto`, incluindo backup automático, rollback e limpeza de arquivos antigos. ===== 🚀 Comando de Implementação ===== implementar deploy automático hostinger ===== ⚙️ Pré-requisitos ===== - **Laravel 12** instalado - **PHP 8.2+** configurado - **Composer** para dependências - **MySQL/PostgreSQL** para banco de dados - **Redis** para cache (recomendado) - **Acesso SSH** à Hostinger - **Repositório GitHub** configurado - **Sistema de Logging** implementado (Activity Log) ===== 🔧 Implementação Passo a Passo ===== ==== Passo 1: Criar Rotas do Webhook ==== **✅ VERIFICAR PRIMEIRO** - Verificar se as rotas já existem. # Verificar se as rotas já existem grep -n "hostinger/webhook" routes/api.php grep -n "DeployWebhookController" routes/api.php **Se não existir, adicionar as rotas no `routes/api.php`:** // Adicionar no final do arquivo routes/api.php, antes do fechamento // Rotas para Deploy Automático na Hostinger Route::prefix('hostinger')->group(function () { Route::prefix('webhook')->group(function () { Route::post('/deploy', [DeployWebhookController::class, 'deploy']); // POST /api/hostinger/webhook/deploy Route::get('/health', [DeployWebhookController::class, 'health']); // GET /api/hostinger/webhook/health Route::get('/test', [DeployWebhookController::class, 'testDeploy']); // GET /api/hostinger/webhook/test Route::get('/status', [DeployWebhookController::class, 'getStatus']); // GET /api/hostinger/webhook/status }); }); **Verificar se as rotas foram adicionadas corretamente:** # Verificar se as rotas foram adicionadas grep -A 10 "hostinger" routes/api.php # Testar se as rotas estão funcionando php artisan route:list | grep hostinger ==== Passo 2: Criar DeployWebhookController ==== **✅ VERIFICAR PRIMEIRO** - Verificar se o controller já existe. # Verificar se o controller já existe ls -la app/Http/Controllers/Api/DeployWebhookController.php **Se não existir, criar o controller:** # Criar o arquivo do controller touch app/Http/Controllers/Api/DeployWebhookController.php **Conteúdo do arquivo `app/Http/Controllers/Api/DeployWebhookController.php`:** loggingService->logApiRequest($request, [ 'webhook_type' => 'github_deploy_hostinger', 'operation' => 'deploy_webhook' ]); // Get the payload $payload = $request->all(); // Verify if it's a push to the hostinger-deploy-auto branch if (!isset($payload['ref']) || $payload['ref'] !== 'refs/heads/hostinger-deploy-auto') { $this->loggingService->logBusinessOperation('deploy_webhook_ignored', [ 'reason' => 'not_hostinger_hom_branch', 'ref' => $payload['ref'] ?? 'not set' ], 'info'); return response()->json([ 'status' => 'ignored', 'message' => 'Ignored - not hostinger-deploy-auto branch', 'ref' => $payload['ref'] ?? 'not set' ]); } // Verify repository if (!isset($payload['repository']['full_name']) || $payload['repository']['full_name'] !== 'spsise/project-name') { $this->loggingService->logSecurityEvent('deploy_webhook_wrong_repository', [ 'repository' => $payload['repository']['full_name'] ?? 'not set', 'expected' => 'spsise/project-name' ], 'warning'); return response()->json([ 'status' => 'error', 'message' => 'Wrong repository' ], 400); } $this->loggingService->logBusinessOperation('deploy_webhook_started', [ 'branch' => 'hostinger-deploy-auto', 'commit' => $payload['head_commit']['id'] ?? 'unknown', 'message' => $payload['head_commit']['message'] ?? 'no message', 'repository' => $payload['repository']['full_name'] ], 'info'); // Execute deployment script $deployResult = $this->executeDeployScript($payload); if (!$deployResult['success']) { $this->sendDeployNotification('error', $payload, $deployResult['error']); return response()->json([ 'status' => 'error', 'message' => 'Deploy process failed', 'error' => $deployResult['error'] ], 500); } $duration = (microtime(true) - $startTime) * 1000; $this->loggingService->logBusinessOperation('deploy_process_completed', [ 'output' => $deployResult['output'], 'processing_time_ms' => round($duration, 2) ], 'success'); // Log performance metric $this->loggingService->logPerformance('hostinger_deploy_webhook', $duration, [ 'branch' => 'hostinger-deploy-auto', 'commit' => $payload['head_commit']['id'] ?? 'unknown' ]); // Send notification for successful deploy $this->sendDeployNotification('success', $payload, $deployResult['output']); return response()->json([ 'status' => 'success', 'message' => 'Deployment completed successfully', 'processing_time_ms' => round($duration, 2) ]); } catch (\Exception $e) { $duration = (microtime(true) - $startTime) * 1000; $this->loggingService->logException($e, [ 'operation' => 'hostinger_deploy_webhook', 'processing_time_ms' => round($duration, 2) ]); // Send notification for exception $this->sendDeployNotification('error', $payload ?? [], $e->getMessage()); return response()->json([ 'status' => 'error', 'message' => 'Exception during deployment: ' . $e->getMessage() ], 500); } } /** * Execute deployment script * * @param array $payload * @return array */ private function executeDeployScript(array $payload): array { try { $deployScript = base_path('../deploy.sh'); if (!file_exists($deployScript)) { return [ 'success' => false, 'error' => 'Deploy script not found at: ' . $deployScript ]; } // Check if script is executable if (!is_executable($deployScript)) { chmod($deployScript, 0755); } // Create process to run deploy script $process = new Process(['bash', $deployScript]); $process->setWorkingDirectory(dirname($deployScript)); $process->setTimeout(300); // 5 minutes timeout $process->setIdleTimeout(60); // 1 minute idle timeout // Start the process and capture output $process->start(function ($type, $buffer) { if ($type === Process::ERR) { $this->loggingService->logBusinessOperation('deploy_process_error', [ 'output' => trim($buffer) ], 'error'); } else { $this->loggingService->logBusinessOperation('deploy_process_output', [ 'output' => trim($buffer) ], 'info'); } }); // Wait for process to complete $process->wait(); if (!$process->isSuccessful()) { return [ 'success' => false, 'error' => $process->getErrorOutput(), 'output' => $process->getOutput() ]; } return [ 'success' => true, 'output' => $process->getOutput() ]; } catch (\Exception $e) { return [ 'success' => false, 'error' => $e->getMessage() ]; } } /** * Send deploy notification via unified service * * @param string $status * @param array $payload * @param string $output * @return void */ private function sendDeployNotification(string $status, array $payload, string $output = ''): void { try { $deployData = [ 'status' => $status, 'branch' => $payload['ref'] ?? 'unknown', 'commit' => $payload['head_commit']['id'] ?? 'unknown', 'message' => $payload['head_commit']['message'] ?? 'no message', 'timestamp' => now()->format('d/m/Y H:i:s'), 'output' => $output ]; // Send notification using unified service $notificationService = app(UnifiedNotificationService::class); $result = $notificationService->sendDeployNotification($deployData); if ($result['success']) { $this->loggingService->logBusinessOperation('deploy_notification_sent', [ 'status' => $status, 'sent_to_channels' => $result['sent_to_channels'], 'total_channels' => $result['total_channels'] ], 'success'); } else { $this->loggingService->logBusinessOperation('deploy_notification_failed', [ 'status' => $status, 'results' => $result['results'] ], 'error'); } } catch (\Exception $e) { $this->loggingService->logException($e, [ 'operation' => 'send_deploy_notification', 'status' => $status ]); } } /** * Health check for webhook endpoint * * @return JsonResponse */ public function health(): JsonResponse { $deployScript = base_path('../deploy.sh'); $this->loggingService->logBusinessOperation('webhook_health_check', [ 'deploy_script_exists' => file_exists($deployScript), 'deploy_script_executable' => file_exists($deployScript) ? is_executable($deployScript) : false ], 'info'); return response()->json([ 'status' => 'healthy', 'message' => 'Webhook endpoint is working', 'timestamp' => now()->toISOString(), 'deploy_script_exists' => file_exists($deployScript), 'deploy_script_executable' => file_exists($deployScript) ? is_executable($deployScript) : false, 'deploy_script_path' => $deployScript ]); } /** * Test deploy functionality * * @return JsonResponse */ public function testDeploy(): JsonResponse { $this->loggingService->logBusinessOperation('test_deploy_triggered', [ 'type' => 'manual_test' ], 'info'); $testPayload = [ 'ref' => 'refs/heads/hostinger-deploy-auto', 'repository' => ['full_name' => 'spsise/project-name'], 'head_commit' => [ 'id' => 'test-commit-id', 'message' => 'Test deploy from webhook' ] ]; $this->sendDeployNotification('test', $testPayload, 'Test notification sent'); return response()->json([ 'status' => 'success', 'message' => 'Test deploy notification sent', 'payload' => $testPayload ]); } /** * Get deployment status * * @return JsonResponse */ public function getStatus(): JsonResponse { $deployScript = base_path('../deploy.sh'); $deployLog = base_path('../deploy.log'); $status = [ 'deploy_script_exists' => file_exists($deployScript), 'deploy_script_executable' => file_exists($deployScript) ? is_executable($deployScript) : false, 'deploy_log_exists' => file_exists($deployLog), 'last_deploy' => null, 'system_info' => [ 'php_version' => PHP_VERSION, 'laravel_version' => app()->version(), 'memory_limit' => ini_get('memory_limit'), 'max_execution_time' => ini_get('max_execution_time') ] ]; // Get last deploy info from log if (file_exists($deployLog)) { $logContent = File::get($deployLog); $lines = explode("\n", $logContent); $lastLine = end(array_filter($lines)); $status['last_deploy'] = $lastLine; } return response()->json($status); } } **Verificar se o controller foi criado corretamente:** # Verificar se o arquivo existe ls -la app/Http/Controllers/Api/DeployWebhookController.php # Verificar se está sendo usado nas rotas grep -n "DeployWebhookController" routes/api.php # Testar se o controller está funcionando php artisan route:list | grep DeployWebhookController ==== Passo 3: Criar Script de Deploy ==== **✅ VERIFICAR PRIMEIRO** - Verificar se o script já existe. # Verificar se o script já existe ls -la ../deploy.sh **Se não existir, criar o script:** # Criar o arquivo do script touch ../deploy.sh **Conteúdo do arquivo `../deploy.sh`:** #!/bin/bash set -e echo "🚀 Iniciando deploy automático para Hostinger..." # Configurações PROJECT_ROOT="/home/$(whoami)/project-name" API_DIR="/home/$(whoami)/domains/virtualt.com.br/public_html/api-hom" FRONTEND_DIR="/home/$(whoami)/domains/virtualt.com.br/public_html/app-hom" BACKUP_DIR="/home/$(whoami)/project-name/backups" # Criar diretório de backup se não existir mkdir -p "$BACKUP_DIR" # Criar e configurar arquivo de log if [ ! -f "$PROJECT_ROOT/deploy.log" ]; then touch "$PROJECT_ROOT/deploy.log" echo "✅ Arquivo de log criado: $PROJECT_ROOT/deploy.log" fi chmod 644 "$PROJECT_ROOT/deploy.log" cd "$PROJECT_ROOT" # ATUALIZAR REPOSITÓRIO LOCAL COM AS MUDANÇAS DO GITHUB echo "📥 Atualizando repositório local..." git fetch origin git reset --hard origin/hostinger-deploy-auto echo "✅ Repositório atualizado com sucesso" # Log do deploy echo "$(date): Deploy iniciado - repositório atualizado" >> "$PROJECT_ROOT/deploy.log" # FUNÇÃO PARA LIMPAR BACKUPS ANTIGOS cleanup_old_backups() { echo "🧹 Limpando backups antigos..." if [ -d "$BACKUP_DIR" ]; then # Limpar backups de API (manter apenas os 2 mais recentes) api_backups=$(ls -t "$BACKUP_DIR"/api_backup_* 2>/dev/null || true) if [ -n "$api_backups" ]; then total_api=$(echo "$api_backups" | wc -l) if [ "$total_api" -gt 2 ]; then echo "🗑️ Removendo $(($total_api - 2)) backups antigos de API..." echo "$api_backups" | tail -n +3 | xargs rm -rf 2>/dev/null || true fi fi # Limpar backups de frontend (manter apenas os 2 mais recentes) frontend_backups=$(ls -t "$BACKUP_DIR"/frontend_backup_* 2>/dev/null || true) if [ -n "$frontend_backups" ]; then total_frontend=$(echo "$frontend_backups" | wc -l) if [ "$total_frontend" -gt 2 ]; then echo "🗑️ Removendo $(($total_frontend - 2)) backups antigos de frontend..." echo "$frontend_backups" | tail -n +3 | xargs rm -rf 2>/dev/null || true fi fi echo "✅ Limpeza de backups antigos concluída" fi } # EXECUTAR LIMPEZA DE BACKUPS ANTIGOS cleanup_old_backups # Função para fazer backup de arquivos importantes backup_important_files() { local target_dir="$1" local backup_name="$2" local backup_path="$BACKUP_DIR/${backup_name}_$(date +%Y%m%d_%H%M%S)" echo "💾 Fazendo backup de arquivos importantes..." mkdir -p "$backup_path" # Backup de arquivos importantes do Laravel if [ -d "$target_dir/vendor" ]; then echo "📦 Backup do vendor..." cp -r "$target_dir/vendor" "$backup_path/" fi if [ -f "$target_dir/.env" ]; then echo "⚙️ Backup do .env..." cp "$target_dir/.env" "$backup_path/" fi if [ -d "$target_dir/storage/app" ]; then echo "📁 Backup do storage/app..." cp -r "$target_dir/storage/app" "$backup_path/" fi if [ -d "$target_dir/storage/logs" ]; then echo "📝 Backup dos logs..." cp -r "$target_dir/storage/logs" "$backup_path/" fi echo "✅ Backup salvo em: $backup_path" } # Deploy Backend (Laravel) - API Subdomain if [ -d "backend" ]; then echo "🔧 Configurando Laravel API..." # Backup dos arquivos importantes se o diretório já existe if [ -d "$API_DIR" ]; then backup_important_files "$API_DIR" "api_backup" fi # Criar diretório temporário para o novo deploy TEMP_API_DIR="$API_DIR.temp" rm -rf "$TEMP_API_DIR" mkdir -p "$TEMP_API_DIR" # Copiar arquivos do backend para diretório temporário echo "📋 Copiando arquivos do backend..." cp -r backend/* "$TEMP_API_DIR/" # Copiar arquivos ocultos importantes echo "📋 Copiando arquivos ocultos importantes..." cp backend/.env.example "$TEMP_API_DIR/" 2>/dev/null || true cp backend/.gitignore "$TEMP_API_DIR/" 2>/dev/null || true cp backend/phpunit.xml "$TEMP_API_DIR/" 2>/dev/null || true cp backend/vite.config.js "$TEMP_API_DIR/" 2>/dev/null || true cp backend/package.json "$TEMP_API_DIR/" 2>/dev/null || true # Copiar vendor do diretório original (se existir) if [ -d "$API_DIR/vendor" ]; then echo "📦 Copiando vendor do diretório original..." cp -r "$API_DIR/vendor" "$TEMP_API_DIR/" fi # Restaurar outros arquivos importantes do backup (se existir) if [ -d "$API_DIR" ]; then latest_backup=$(ls -t "$BACKUP_DIR"/api_backup_* 2>/dev/null | head -1) if [ -n "$latest_backup" ]; then echo "🔄 Restaurando outros arquivos importantes do backup..." if [ -f "$latest_backup/.env" ]; then cp "$latest_backup/.env" "$TEMP_API_DIR/" fi if [ -d "$latest_backup/storage/app" ]; then rm -rf "$TEMP_API_DIR/storage/app" cp -r "$latest_backup/storage/app" "$TEMP_API_DIR/" fi if [ -d "$latest_backup/storage/logs" ]; then rm -rf "$TEMP_API_DIR/storage/logs" cp -r "$latest_backup/storage/logs" "$TEMP_API_DIR/" fi fi fi # Verificar se vendor foi copiado com sucesso echo "📦 Verificando dependências..." if [ -d "$TEMP_API_DIR/vendor" ]; then echo "✅ Vendor copiado com sucesso para nova versão" else echo "⚠️ Vendor não encontrado" echo "❌ Deploy interrompido - vendor é obrigatório para continuar" exit 1 fi # Mudar para o diretório temporário para executar comandos Laravel cd "$TEMP_API_DIR" # Verificar se o vendor está funcionando echo "🔍 Testando se o vendor está funcionando..." if php artisan --version > /dev/null 2>&1; then echo "✅ Vendor funcionando corretamente" else echo "❌ Vendor não está funcionando - verifique as dependências" exit 1 fi # Verificar se .env foi restaurado do backup, senão criar um novo if [ ! -f ".env" ]; then echo "⚙️ Criando arquivo .env..." cp .env.example .env php artisan key:generate else echo "✅ Usando .env existente do backup" fi # Otimizar para produção echo "⚡ Otimizando para produção..." mkdir -p storage/framework/views chmod -R 755 storage php artisan config:cache php artisan route:cache php artisan view:cache # Criar link simbólico para storage echo "🔗 Criando link simbólico para storage..." mkdir -p public mkdir -p storage/app/public if [ ! -L "public/storage" ]; then if php artisan storage:link > /dev/null 2>&1; then echo "✅ Link simbólico criado via Laravel" else echo "⚠️ Tentando criar link simbólico manualmente..." ln -sf "../storage/app/public" public/storage 2>/dev/null || echo "⚠️ Erro ao criar link simbólico" fi else echo "✅ Link simbólico para storage já existe" fi # Executar migrações echo "🗄️ Executando migrações..." php artisan migrate --force # Limpar arquivos de desenvolvimento echo "🧹 Limpando arquivos de desenvolvimento..." rm -rf tests/ 2>/dev/null || true rm -rf .phpunit.cache/ 2>/dev/null || true rm -rf storage/framework/cache/* 2>/dev/null || true rm -rf storage/framework/sessions/* 2>/dev/null || true rm -rf storage/framework/views/* 2>/dev/null || true # Garantir permissões corretas mkdir -p storage/logs chmod -R 755 storage/logs chmod -R 755 bootstrap/cache chmod 644 .env # Configurar .htaccess para API cat > .htaccess << 'HTACCESS' RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ public/index.php [L] HTACCESS # Fazer swap dos diretórios (deploy atômico) echo "🔄 Fazendo swap dos diretórios..." if [ -d "$API_DIR" ]; then mv "$API_DIR" "$API_DIR.old" fi mv "$TEMP_API_DIR" "$API_DIR" # Remover diretório antigo após alguns segundos if [ -d "$API_DIR.old" ]; then echo "🗑️ Removendo versão anterior em 5 segundos..." (sleep 5 && rm -rf "$API_DIR.old") & fi echo "✅ Backend Laravel configurado em api-hom.virtualt.com.br" fi cd "$PROJECT_ROOT" # Deploy Frontend (React) - App Subdomain if [ -d "frontend" ]; then echo "⚛️ Configurando React App..." # Criar diretório temporário para o novo deploy TEMP_FRONTEND_DIR="$FRONTEND_DIR.temp" rm -rf "$TEMP_FRONTEND_DIR" mkdir -p "$TEMP_FRONTEND_DIR" # Criar diretório temporário para build TEMP_BUILD_DIR="/tmp/frontend-build-$(date +%Y%m%d-%H%M%S)" mkdir -p "$TEMP_BUILD_DIR" # Copiar arquivos do frontend para diretório temporário de build echo "📋 Copiando arquivos do frontend para build temporário..." cp -r frontend/* "$TEMP_BUILD_DIR/" cd "$TEMP_BUILD_DIR" # Verificar se existe build local do frontend if [ -d "dist" ]; then echo "📋 Usando build local existente..." cp -r dist/* "$TEMP_FRONTEND_DIR/" else echo "⚠️ Build local não encontrado. Execute npm run build no frontend antes do deploy." echo "❌ Deploy do frontend interrompido - build necessário" cd "$PROJECT_ROOT" rm -rf "$TEMP_BUILD_DIR" exit 1 fi # Limpar diretório temporário de build echo "🧹 Limpando diretório temporário de build..." cd "$PROJECT_ROOT" rm -rf "$TEMP_BUILD_DIR" # Configurar .htaccess para frontend cat > "$TEMP_FRONTEND_DIR/.htaccess" << 'HTACCESS' RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.html [QSA,L] HTACCESS # Configurar permissões chmod -R 755 "$TEMP_FRONTEND_DIR" # Fazer swap dos diretórios (deploy atômico) echo "🔄 Fazendo swap dos diretórios..." if [ -d "$FRONTEND_DIR" ]; then mv "$FRONTEND_DIR" "$FRONTEND_DIR.old" fi mv "$TEMP_FRONTEND_DIR" "$FRONTEND_DIR" # Remover diretório antigo após alguns segundos if [ -d "$FRONTEND_DIR.old" ]; then echo "🗑️ Removendo versão anterior em 5 segundos..." (sleep 5 && rm -rf "$FRONTEND_DIR.old") & fi echo "✅ Frontend React configurado em app-hom.virtualt.com.br" fi echo "🎉 Deploy automático concluído com sucesso!" echo "🌐 Frontend: https://app-hom.virtualt.com.br" echo "🔗 API: https://api-hom.virtualt.com.br" # Log do deploy echo "$(date): Deploy automático realizado com sucesso" >> "$PROJECT_ROOT/deploy.log" echo "✅ Deploy concluído com zero downtime!" **Tornar o script executável:** # Tornar o script executável chmod +x ../deploy.sh # Verificar se está executável ls -la ../deploy.sh ===== 🧪 Testes ===== === Teste das Rotas === # Testar se as rotas estão funcionando php artisan route:list | grep hostinger # Testar endpoint de health curl -X GET "http://localhost:8000/api/hostinger/webhook/health" # Testar endpoint de status curl -X GET "http://localhost:8000/api/hostinger/webhook/status" # Testar endpoint de teste curl -X GET "http://localhost:8000/api/hostinger/webhook/test" === Teste do Controller === # Testar se o controller está funcionando php artisan tinker # >>> $controller = new \App\Http\Controllers\Api\DeployWebhookController(app(\App\Contracts\LoggingServiceInterface::class)); # >>> $controller->health(); === Teste do Script de Deploy === # Testar se o script de deploy está funcionando cd .. ./deploy.sh # Verificar se o log foi criado cat deploy.log ===== ✅ Validação do Módulo ===== === Checklist de Implementação === - [ ] Rotas do webhook criadas em `routes/api.php` ✅ - [ ] Controller `DeployWebhookController` criado ✅ - [ ] Script `deploy.sh` criado e executável ✅ - [ ] Sistema de logging integrado ✅ - [ ] Sistema de notificações integrado ✅ - [ ] Deploy atômico implementado ✅ - [ ] Sistema de backup implementado ✅ - [ ] Limpeza automática de backups ✅ === Comandos de Validação === # Verificar rotas php artisan route:list | grep hostinger # Verificar controller ls -la app/Http/Controllers/Api/DeployWebhookController.php # Verificar script ls -la ../deploy.sh # Testar endpoints curl -X GET "http://localhost:8000/api/hostinger/webhook/health" curl -X GET "http://localhost:8000/api/hostinger/webhook/status" curl -X GET "http://localhost:8000/api/hostinger/webhook/test" # Verificar logs tail -f ../deploy.log ===== 📋 Próximos Passos ===== 1. **Configurar Webhook no GitHub:** - URL: `https://api-hom.virtualt.com.br/api/hostinger/webhook/deploy` - Branch: `hostinger-deploy-auto` - Event: `push` 2. **Configurar Variáveis de Ambiente:** - Configurar `.env` na Hostinger - Configurar banco de dados - Configurar URLs dos subdomínios 3. **Testar Deploy Completo:** - Fazer push para branch `hostinger-deploy-auto` - Verificar se o deploy foi executado - Verificar se os subdomínios estão funcionando 4. **Monitorar Logs:** - Verificar logs de deploy - Verificar logs da aplicação - Verificar notificações enviadas ===== 🔧 Troubleshooting ===== === Problemas Comuns === **1. Script não executável:** chmod +x ../deploy.sh **2. Permissões incorretas:** chmod -R 755 storage/ chmod -R 755 bootstrap/cache/ **3. Vendor não encontrado:** **4. Deploy falha:** === Comandos de Debug ===