diff --git a/.gitea/workflows/pipeline.yml b/.gitea/workflows/pipeline.yml index 8ffc9bf1..9e85b10c 100644 --- a/.gitea/workflows/pipeline.yml +++ b/.gitea/workflows/pipeline.yml @@ -84,7 +84,7 @@ jobs: echo "Starting new container..." docker run -d \ --restart unless-stopped \ - --health-cmd="curl -f http://localhost:8000 || exit 1" \ + --health-cmd="curl -f http://127.0.0.1:8000 || exit 1" \ --health-interval=30s \ --health-timeout=10s \ --health-retries=3 \ @@ -98,7 +98,7 @@ jobs: # Check if container is running sleep 5 - if docker ps | grep -q kulakpos_web_staging; then + if docker ps | grep kulakpos_web_staging; then echo "✅ Staging deployment successful!" docker logs --tail 20 kulakpos_web_staging else @@ -183,7 +183,13 @@ jobs: docker ps --filter name=kulakpos_web_prod # Create backup of current deployment info - docker inspect kulakpos_web_prod > /tmp/kulakpos_backup_$(date +%Y%m%d_%H%M%S).json || true + mkdir -p /opt/kulakpos/backups + docker inspect kulakpos_web_prod > /opt/kulakpos/backups/kulakpos_backup_$(date +%Y%m%d_%H%M%S).json || true + + # Backup .env file + if [ -f "/opt/kulakpos/.env" ]; then + cp /opt/kulakpos/.env /opt/kulakpos/backups/.env_backup_$(date +%Y%m%d_%H%M%S) + fi # Pull the specified image echo "Pulling image: kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:$IMAGE_TAG" @@ -194,11 +200,11 @@ jobs: docker stop kulakpos_web_prod || true docker rm kulakpos_web_prod || true - # Run new container - echo "Starting new container..." + # Run new container (using PHP's built-in server on port 8000 like staging) + echo "Starting new production container on port 8000..." docker run -d \ --restart unless-stopped \ - --health-cmd="pgrep php-fpm" \ + --health-cmd="curl -f http://127.0.0.1:8000 || exit 1" \ --health-interval=30s \ --health-timeout=10s \ --health-start-period=40s \ @@ -206,15 +212,23 @@ jobs: --name kulakpos_web_prod \ --network="host" \ -v /opt/kulakpos/.env:/var/www/html/.env \ - -p 9000:9000 \ - -e MODE=prod \ + -e MODE=production \ -e APP_ENV=production \ + -e APP_DEBUG=false \ + -e AUTO_MIGRATE=false \ kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:$IMAGE_TAG - # Check if container is running + # Wait for container to be ready + echo "Waiting for container to be ready..." sleep 10 - if docker ps | grep -q kulakpos_web_prod; then + + # Check if container is running + if docker ps | grep kulakpos_web_prod; then echo "✅ Production deployment successful!" + echo "" + echo "Container status:" + docker ps --filter name=kulakpos_web_prod --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" + echo "" echo "Container logs (last 20 lines):" docker logs --tail 20 kulakpos_web_prod else @@ -222,50 +236,31 @@ jobs: docker logs kulakpos_web_prod || echo "No logs available" # Attempt rollback to previous version if available + echo "" echo "Attempting rollback to previous version..." - PREVIOUS_IMAGE=$(docker inspect kulakpos_web_prod --format='{{.Config.Image}}' 2>/dev/null || echo "") - if [ -n "$PREVIOUS_IMAGE" ] && [ "$PREVIOUS_IMAGE" != "kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:$IMAGE_TAG" ]; then - docker run -d \ - --restart unless-stopped \ - --name kulakpos_web_prod \ - --network="host" \ - -v /opt/kulakpos/.env:/var/www/html/.env \ - -p 8000:8000 \ - -e MODE=prod \ - -e APP_ENV=production \ - $PREVIOUS_IMAGE - echo "Rollback attempted" + PREVIOUS_BACKUP=$(ls -t /opt/kulakpos/backups/kulakpos_backup_*.json 2>/dev/null | head -1) + if [ -f "$PREVIOUS_BACKUP" ]; then + PREVIOUS_IMAGE=$(jq -r '.[0].Config.Image' $PREVIOUS_BACKUP 2>/dev/null || echo "") + if [ -n "$PREVIOUS_IMAGE" ] && [ "$PREVIOUS_IMAGE" != "kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:$IMAGE_TAG" ]; then + echo "Rolling back to: $PREVIOUS_IMAGE" + docker run -d \ + --restart unless-stopped \ + --health-cmd="curl -f http://127.0.0.1:8000 || exit 1" \ + --health-interval=30s \ + --health-timeout=10s \ + --health-start-period=40s \ + --health-retries=3 \ + --name kulakpos_web_prod \ + --network="host" \ + -v /opt/kulakpos/.env:/var/www/html/.env \ + -e MODE=production \ + -e APP_ENV=production \ + -e APP_DEBUG=false \ + -e AUTO_MIGRATE=false \ + $PREVIOUS_IMAGE + echo "Rollback completed" + fi fi exit 1 fi EOF - - # - name: Verify Production Deployment - # run: | - # ssh kulakpos_prod "curl -f http://localhost:8000/health || curl -f http://localhost:8000 || echo 'Service is running but health check endpoint not configured'" - # echo "✅ Production deployment verified!" - - - name: Verify Production Deployment - run: | - ssh kulakpos_prod "docker ps --filter 'name=kulakpos_web_prod' --format '{{.Status}}' | grep -q healthy" - echo "✅ Production deployment verified!" - - - name: Send Deployment Notification - if: always() - run: | - STATUS="${{ job.status }}" - if [ "$STATUS" = "success" ]; then - echo "✅ Production deployment completed successfully!" - else - echo "❌ Production deployment failed!" - exit 1 - fi - - cleanup: - runs-on: ubuntu-latest - needs: [deploy-staging, deploy-production] - if: always() - steps: - - name: Cleanup old Docker images on runners - run: | - docker system prune -f --filter "until=24h" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 16a44469..d1b989de 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ yarn-error.log /storage/framework/views/* /public/modules/* .qodo -.camel-jbang \ No newline at end of file +.camel-jbang +dump/ \ No newline at end of file diff --git a/composer.json b/composer.json index 3ce74d57..cc01eb3a 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,8 @@ "mockery/mockery": "^1.4.4", "nunomaduro/collision": "^7.0", "phpunit/phpunit": "^10.1", - "spatie/laravel-ignition": "^2.0" + "spatie/laravel-ignition": "^2.0", + "knuckleswtf/scribe": "5.9.0" }, "autoload": { "psr-4": { diff --git a/entrypoint.sh b/entrypoint.sh index 07355dd7..bed55c28 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -9,9 +9,14 @@ echo "========================================" echo "Current user: $(whoami)" echo "Current directory: $(pwd)" -# Force debug mode for troubleshooting -export APP_DEBUG=true -export LOG_LEVEL=debug +# Set debug based on environment +if [ "$APP_ENV" = "production" ]; then + export APP_DEBUG=false + export LOG_LEVEL=error +else + export APP_DEBUG=true + export LOG_LEVEL=debug +fi # Create ALL required Laravel directories echo "Creating storage directories..." @@ -62,7 +67,6 @@ fi echo "Checking .env for APP_KEY..." if ! grep -E "APP_KEY=.{10,}" .env; then echo "APP_KEY is empty or missing. Generating..." - echo "Generating application key..." # If the file doesn't have APP_KEY= at all, add it so artisan can replace it if ! grep -q "APP_KEY=" .env; then echo "Appending APP_KEY= placeholder..." @@ -77,10 +81,62 @@ grep "APP_KEY" .env # Ensure vendor directory matches composer.lock exactly, syncing missing packages echo "Verifying and synchronizing Composer dependencies..." -# Run composer install to physically ensure all files (like laravel/prompts) are present in the volume -composer install --no-interaction --optimize-autoloader -# FIX: Ensure all generated/downloaded files are fully readable and executable by PHP-FPM +# Check if scribe is in composer.json but not installed +if grep -q "knuckleswtf/scribe" composer.json; then + if ! composer show --locked knuckleswtf/scribe --no-ansi 2>/dev/null | grep -q "name"; then + echo "📦 knuckleswtf/scribe found in composer.json but not in lock file. Installing..." + composer require --dev knuckleswtf/scribe --no-interaction --no-progress --update-with-dependencies + else + echo "✅ knuckleswtf/scribe is already in lock file" + composer install --no-interaction --optimize-autoloader + fi +else + # Normal install + composer install --no-interaction --optimize-autoloader +fi + +# If install fails, try update +if [ $? -ne 0 ]; then + echo "⚠️ Composer install failed, attempting update..." + composer update --no-interaction --optimize-autoloader --with-all-dependencies +fi + +# Install and publish Scribe assets +echo "Setting up Scribe/OpenAPI documentation..." + +# Publish Scribe config (if not already published) +if [ ! -f config/scribe.php ]; then + echo "Publishing Scribe configuration..." + php artisan vendor:publish --tag=scribe-config --force +fi + +# Generate OpenAPI/Swagger documentation +if [ "$APP_ENV" != "production" ] || [ "$AUTO_GENERATE_API_DOCS" = "true" ]; then + echo "Generating API documentation..." + + # Generate Scribe documentation + php artisan scribe:generate --no-interaction || echo "⚠️ Scribe generation failed, check your API routes" + + # For OpenAPI/Swagger UI specifically + if [ -f public/docs/openapi.yaml ] || [ -f public/docs/collection.json ]; then + echo "✅ Documentation generated successfully" + echo "📚 Swagger UI available at: /docs (if configured)" + echo "📄 OpenAPI spec available at: /docs/openapi.yaml" + else + echo "⚠️ Documentation files not found after generation" + fi +fi + +# Create symbolic link for Scribe assets if needed +if [ -d vendor/knuckleswtf/scribe/dist ]; then + echo "Creating Scribe assets symlink..." + mkdir -p public/vendor/scribe + cp -r vendor/knuckleswtf/scribe/dist/* public/vendor/scribe/ 2>/dev/null || \ + ln -sf ../vendor/knuckleswtf/scribe/dist public/vendor/scribe 2>/dev/null || true +fi + +# FIX: Ensure all generated/downloaded files are fully readable and executable echo "Setting correct ownership for web server..." chown -R www-data:www-data vendor chmod -R 755 vendor @@ -91,13 +147,21 @@ ls -la /var/www/html/vendor/laravel/prompts/src/helpers.php php -r 'if (file_exists("/var/www/html/vendor/laravel/prompts/src/helpers.php")) { echo "✅ file_exists true\n"; }' php -r 'require "/var/www/html/vendor/laravel/prompts/src/helpers.php"; echo "✅ PHP successfully REQUIRED helpers.php\n";' -# Clear all caches to ensure fresh state -echo "Clearing caches..." -php artisan config:clear || true -php artisan view:clear || true -php artisan route:clear || true -php artisan cache:clear || true -php artisan optimize:clear || true +# Run production optimizations for production environment +if [ "$APP_ENV" = "production" ] || [ "$MODE" = "production" ]; then + echo "Running production optimizations..." + php artisan config:cache + php artisan view:cache + php artisan event:cache +else + # Clear all caches to ensure fresh state for non-production + echo "Clearing caches..." + php artisan config:clear || true + php artisan view:clear || true + php artisan route:clear || true + php artisan cache:clear || true + php artisan optimize:clear || true +fi # Verify Vite manifest exists if [ -f public/build/manifest.json ]; then @@ -108,20 +172,29 @@ else ls -la public/build/ 2>/dev/null || echo "public/build directory does not exist" fi -# Optional: Run migrations if needed -php artisan migrate --force +# Optional: Run migrations if needed (with safety for production) +if [ "$AUTO_MIGRATE" = "true" ] || [ "$APP_ENV" != "production" ]; then + echo "Running migrations..." + php artisan migrate --force +fi echo "========================================" echo "Setup complete. Starting application..." echo "========================================" -# Start the application with proper error handling -if [ "$MODE" = "staging" ]; then - echo "Starting DIRECT PHP server on port 8000 (Bypassing artisan serve)..." +# Start the application based on environment +if [ "$APP_ENV" = "production" ] || [ "$MODE" = "production" ]; then + echo "Starting PHP built-in server on port 8000 (Production mode)..." + echo "Document root: /var/www/html/public" + echo "Workers: Single-threaded PHP server (use Nginx for production scaling)" + # Use direct php -S for production (optimized) + exec php -d opcache.enable=1 -d opcache.memory_consumption=128 -d opcache.max_accelerated_files=10000 -S 0.0.0.0:8000 -t public +elif [ "$MODE" = "staging" ]; then + echo "Starting PHP built-in server on port 8000 (Staging mode)..." # Use direct php -S to eliminate any artisan wrapper issues - exec php -d opcache.enable=0 -S 0.0.0.0:8000 -t public server.php 2>&1 | tee -a /var/log/php-server.log + exec php -d opcache.enable=0 -S 0.0.0.0:8000 -t public else - echo "Starting PHP-FPM on port 9000..." + echo "Starting PHP-FPM on port 9000 (Development mode)..." # Ensure PHP-FPM is properly configured exec php-fpm -F fi \ No newline at end of file