diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..4318420 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,151 @@ +# GitHub Actions Deployment Workflows + +Các workflow tự động deploy được tạo cho project Laravel Portal. + +## Workflows Available + +### 1. `deploy.yml` - Deployment thông thường +- **Trigger**: Push vào branches `main`, `master`, `develop` hoặc manual trigger +- **Mục đích**: Deploy cho staging/development environment +- **Actions**: Git pull, npm run production, Laravel optimization + +### 2. `deploy-minified.yml` - Production Deployment với minification +- **Trigger**: Push vào branches `main`, `master` hoặc manual trigger +- **Mục đích**: Deploy cho production environment +- **Actions**: Git pull, npm run minify-all, database migration, backup, cleanup + +## Setup Requirements + +### 1. GitHub Secrets Configuration + +Cần setup các secrets sau trong GitHub repository: + +#### For `deploy.yml`: +``` +HOST - IP address hoặc domain của server +USERNAME - SSH username +SSH_KEY - SSH private key content +PORT - SSH port (optional, default: 22) +PROJECT_PATH - Đường dẫn tới project (optional, default: /var/www/portal) +``` + +#### For `deploy-minified.yml`: +``` +PROD_HOST - Production server IP/domain +PROD_USERNAME - Production SSH username +PROD_SSH_KEY - Production SSH private key +PROD_PORT - Production SSH port (optional, default: 22) +PROD_PROJECT_PATH - Production project path (optional, default: /var/www/portal) +``` + +### 2. Server Requirements + +#### Server cần có sẵn: +- Git +- PHP >= 8.0 +- Composer +- Node.js & NPM +- Web server (nginx/apache) với quyền www-data + +#### Project directory structure: +``` +/var/www/portal/ # Main project +/var/www/portal-backup-* # Backup directories (auto-created) +``` + +### 3. SSH Key Setup + +1. **Generate SSH key pair:** + ```bash + ssh-keygen -t rsa -b 4096 -C "github-actions@yourdomain.com" + ``` + +2. **Add public key to server:** + ```bash + # Copy public key to server + cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys + ``` + +3. **Add private key to GitHub Secrets:** + - Copy nội dung của private key file + - Paste vào GitHub Secrets với tên `SSH_KEY` hoặc `PROD_SSH_KEY` + +## Manual Deployment + +Có thể trigger deployment manually: + +1. Vào GitHub repository +2. Click tab "Actions" +3. Chọn workflow muốn chạy +4. Click "Run workflow" +5. Chọn branch và click "Run workflow" + +## Workflow Features + +### Security Features: +- SSH key authentication +- Separate production secrets +- Backup before deployment + +### Performance Features: +- Asset minification cho production +- Laravel optimization commands +- Cache clearing/rebuilding + +### Maintenance Features: +- Automatic backup rotation (keep last 5) +- Queue restart +- Permission fixing +- Database migration + +## Troubleshooting + +### Common Issues: + +1. **SSH Connection Failed:** + - Kiểm tra HOST, USERNAME, SSH_KEY secrets + - Verify SSH key format (complete private key including headers) + +2. **Permission Denied:** + - Kiểm tra SSH user có quyền access project directory + - Verify www-data ownership + +3. **Build Failed:** + - Kiểm tra Node.js version trên server + - Verify npm dependencies + +4. **Laravel Commands Failed:** + - Kiểm tra PHP version compatibility + - Verify .env file exists và correct + +### Debug Commands: +Để debug, có thể thêm các commands sau vào workflow: + +```yaml +# Add to workflow script section +echo "Current user: $(whoami)" +echo "Current directory: $(pwd)" +echo "PHP version: $(php -v)" +echo "Node version: $(node -v)" +echo "NPM version: $(npm -v)" +``` + +## Environment-specific Customization + +Có thể customize workflows theo environment: + +### Development: +- Sử dụng `npm run dev` thay vì `production` +- Skip database migrations +- Enable debug mode + +### Staging: +- Sử dụng `npm run production` +- Include database migrations +- Moderate optimization + +### Production: +- Sử dụng `npm run minify-all` +- Full optimization +- Backup và cleanup +- Queue restart \ No newline at end of file diff --git a/.github/workflows/deploy-minified.yml b/.github/workflows/deploy-minified.yml new file mode 100644 index 0000000..96971f1 --- /dev/null +++ b/.github/workflows/deploy-minified.yml @@ -0,0 +1,74 @@ +name: Deploy to Production (Minified) + +on: + push: + branches: [ main, master ] + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Deploy to production server + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.PROD_HOST }} + username: ${{ secrets.PROD_USERNAME }} + key: ${{ secrets.PROD_SSH_KEY }} + port: ${{ secrets.PROD_PORT || 22 }} + script: | + # Navigate to project directory + cd ${{ secrets.PROD_PROJECT_PATH || '/var/www/portal' }} + + # Backup current deployment + echo "💾 Creating backup..." + cp -r . ../portal-backup-$(date +%Y%m%d_%H%M%S) || true + + # Pull latest code + echo "🔄 Pulling latest code..." + git pull origin ${{ github.ref_name }} + + # Install/Update Composer dependencies for production + echo "📦 Installing Composer dependencies..." + composer install --no-dev --optimize-autoloader --no-interaction + + # Install/Update NPM dependencies + echo "📦 Installing NPM dependencies..." + npm ci --only=production + + # Build and minify assets + echo "🏗️ Building and minifying assets..." + npm run minify-all + + # Run database migrations (if needed) + echo "🗃️ Running database migrations..." + php artisan migrate --force + + # Laravel optimizations for production + echo "⚡ Optimizing Laravel for production..." + php artisan config:cache + php artisan route:cache + php artisan view:cache + php artisan optimize + + # Clear all caches + echo "🧹 Clearing caches..." + php artisan cache:clear + php artisan view:clear + php artisan config:clear + + # Queue restart (if using queues) + echo "🔄 Restarting queues..." + php artisan queue:restart || true + + # Set proper permissions + echo "🔐 Setting permissions..." + chmod -R 755 storage bootstrap/cache public/uploads + chown -R www-data:www-data storage bootstrap/cache public/uploads + + # Cleanup old backups (keep last 5) + echo "🧹 Cleaning up old backups..." + find ../portal-backup-* -maxdepth 0 -type d | sort | head -n -5 | xargs rm -rf || true + + echo "✅ Production deployment completed successfully!" \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..862234c --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,56 @@ +name: Deploy to Server + +on: + push: + branches: [ production ] + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Deploy to server + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.SSH_KEY }} + port: ${{ secrets.PORT || 22 }} + script: | + # Navigate to project directory + cd ${{ secrets.PROJECT_PATH || '/var/www/portal' }} + + # Pull latest code + echo "🔄 Pulling latest code..." + git pull origin ${{ github.ref_name }} + + # Install/Update Composer dependencies + echo "📦 Installing Composer dependencies..." + composer install --no-dev --optimize-autoloader + + # Install/Update NPM dependencies + echo "📦 Installing NPM dependencies..." + npm ci --only=production + + # Build assets + echo "🏗️ Building assets..." + npm run production + + # Laravel optimizations + echo "⚡ Optimizing Laravel..." + php artisan config:cache + php artisan route:cache + php artisan view:cache + php artisan optimize + + # Clear application cache + echo "🧹 Clearing application cache..." + php artisan cache:clear + + # Set permissions + echo "🔐 Setting permissions..." + chmod -R 755 storage bootstrap/cache + chown -R www-data:www-data storage bootstrap/cache + + echo "✅ Deployment completed successfully!" \ No newline at end of file diff --git a/app/Providers/MailConfigServiceProvider.php b/app/Providers/MailConfigServiceProvider.php index c1eba80..4f017ce 100644 --- a/app/Providers/MailConfigServiceProvider.php +++ b/app/Providers/MailConfigServiceProvider.php @@ -4,45 +4,50 @@ namespace App\Providers; use App\Http\Facade\SignRSA; use App\Models\Setting; -use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Config; -use Illuminate\Support\Facades\Crypt; +use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider; class MailConfigServiceProvider extends ServiceProvider { - /** - * Register services. - * - * @return void - */ public function register() { - - + // } - /** - * Bootstrap services. - * - * @return void - */ public function boot() { + // 🔐 Không làm gì nếu đang chạy trong CLI (migrate, cache:clear, ...) + if (App::runningInConsole()) { + return; + } + + // ⛔ Tránh lỗi nếu database hoặc bảng `setting` chưa tồn tại + if (!Schema::hasTable('setting')) { + return; + } + + // ✅ Truy vấn an toàn $mail = Setting::where('key', 'smtp')->first(); $setting = Setting::where('key', 'setting')->first(); - if ($mail) { - $mail = (object)json_decode($mail->value); - $config = array( - 'driver' => $mail->transport, - 'host' => $mail->host, - 'port' => $mail->port, - 'from' => array('address' => $mail->user, 'name' => json_decode($setting->value)->company), + if ($mail && $setting) { + $mail = json_decode($mail->value); + $company = json_decode($setting->value)->company ?? 'Your Company'; + + $config = [ + 'driver' => $mail->transport ?? 'smtp', + 'host' => $mail->host ?? '', + 'port' => $mail->port ?? 587, + 'from' => [ + 'address' => $mail->user ?? 'no-reply@example.com', + 'name' => $company, + ], 'encryption' => $mail->encryption === 0 ? 'tls' : $mail->encryption, - 'username' => $mail->user, - 'password' => $mail->password ? SignRSA::DecryptFunc($mail->password) : "" - ); + 'username' => $mail->user ?? '', + 'password' => isset($mail->password) ? SignRSA::DecryptFunc($mail->password) : '', + ]; Config::set('mail', $config); }