# Inventory Barcode System Deployment Script (PowerShell) # This script handles production deployment with Docker on Windows param( [Parameter(Position=0)] [ValidateSet("deploy", "rollback", "status", "logs", "stop", "restart")] [string]$Action = "deploy" ) # Configuration $APP_NAME = "inventory-barcode-system" $DOCKER_IMAGE = "$APP_NAME:latest" $CONTAINER_NAME = "$APP_NAME-container" $BACKUP_DIR = "./data/backups" $LOG_FILE = "./logs/deployment.log" # Ensure log directory exists if (!(Test-Path -Path "./logs")) { New-Item -ItemType Directory -Path "./logs" -Force | Out-Null } # Logging functions function Write-Log { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Write-Host "[$timestamp] $Message" -ForegroundColor Green "[$timestamp] $Message" | Out-File -FilePath $LOG_FILE -Append } function Write-Error-Log { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Write-Host "[ERROR] $Message" -ForegroundColor Red "[ERROR] $Message" | Out-File -FilePath $LOG_FILE -Append exit 1 } function Write-Warning-Log { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Write-Host "[WARNING] $Message" -ForegroundColor Yellow "[WARNING] $Message" | Out-File -FilePath $LOG_FILE -Append } # Check prerequisites function Test-Prerequisites { Write-Log "Checking prerequisites..." # Check if Docker is installed try { docker --version | Out-Null } catch { Write-Error-Log "Docker is not installed. Please install Docker Desktop first." } # Check if Docker Compose is available try { docker-compose --version | Out-Null } catch { Write-Error-Log "Docker Compose is not available. Please ensure Docker Desktop is properly installed." } # Check if .env file exists if (!(Test-Path -Path ".env")) { Write-Warning-Log ".env file not found. Creating from .env.example..." if (Test-Path -Path ".env.example") { Copy-Item ".env.example" ".env" Write-Log "Please edit .env file with your configuration before continuing." exit 0 } else { Write-Error-Log ".env.example file not found. Cannot create .env file." } } Write-Log "Prerequisites check completed successfully." } # Create necessary directories function New-Directories { Write-Log "Creating necessary directories..." $directories = @("data/exports", "data/backups", "data/temp", "logs") foreach ($dir in $directories) { if (!(Test-Path -Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } } Write-Log "Directories created successfully." } # Backup existing database function Backup-Database { if (Test-Path -Path "./inventory.db") { Write-Log "Backing up existing database..." $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $backupFile = "$BACKUP_DIR/pre-deployment-backup-$timestamp.db" if (!(Test-Path -Path $BACKUP_DIR)) { New-Item -ItemType Directory -Path $BACKUP_DIR -Force | Out-Null } Copy-Item "./inventory.db" $backupFile Write-Log "Database backed up to: $backupFile" } else { Write-Log "No existing database found. Skipping backup." } } # Build Docker image function Build-Image { Write-Log "Building Docker image..." $result = docker build -t $DOCKER_IMAGE . if ($LASTEXITCODE -eq 0) { Write-Log "Docker image built successfully." } else { Write-Error-Log "Failed to build Docker image." } } # Stop existing container function Stop-Existing { Write-Log "Stopping existing container..." $existingContainer = docker ps -q -f name=$CONTAINER_NAME if ($existingContainer) { docker stop $CONTAINER_NAME | Out-Null docker rm $CONTAINER_NAME | Out-Null Write-Log "Existing container stopped and removed." } else { Write-Log "No existing container found." } } # Deploy with Docker Compose function Start-Deployment { Write-Log "Deploying application with Docker Compose..." # Stop existing services docker-compose down | Out-Null # Start services docker-compose up -d if ($LASTEXITCODE -eq 0) { Write-Log "Application deployed successfully." } else { Write-Error-Log "Failed to deploy application." } } # Health check function Test-Health { Write-Log "Performing health check..." # Wait for application to start Start-Sleep -Seconds 10 # Check if container is running $runningContainer = docker ps -q -f name=$APP_NAME if (!$runningContainer) { Write-Error-Log "Container is not running." } # Check application health endpoint $maxAttempts = 30 $attempt = 1 while ($attempt -le $maxAttempts) { try { $response = Invoke-WebRequest -Uri "http://localhost:3000/health" -UseBasicParsing -TimeoutSec 5 if ($response.StatusCode -eq 200) { Write-Log "Health check passed. Application is running." return } } catch { # Continue to retry } Write-Log "Health check attempt $attempt/$maxAttempts failed. Retrying in 5 seconds..." Start-Sleep -Seconds 5 $attempt++ } Write-Error-Log "Health check failed after $maxAttempts attempts." } # Show deployment status function Show-Status { Write-Log "Deployment Status:" Write-Host "" Write-Host "Container Status:" docker ps -f name=$APP_NAME Write-Host "" Write-Host "Application Logs (last 20 lines):" docker-compose logs --tail=20 Write-Host "" Write-Host "Access the application at: http://localhost:3000" Write-Host "Health check endpoint: http://localhost:3000/health" } # Rollback function function Start-Rollback { Write-Warning-Log "Rolling back deployment..." # Stop current deployment docker-compose down | Out-Null # Restore database backup if exists $latestBackup = Get-ChildItem -Path "$BACKUP_DIR/pre-deployment-backup-*.db" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1 if ($latestBackup) { Write-Log "Restoring database from: $($latestBackup.FullName)" Copy-Item $latestBackup.FullName "./inventory.db" } Write-Warning-Log "Rollback completed. Please check your previous deployment." } # Main deployment function function Start-MainDeployment { Write-Log "Starting deployment of $APP_NAME..." try { Test-Prerequisites New-Directories Backup-Database Build-Image Stop-Existing Start-Deployment Test-Health Show-Status Write-Log "Deployment completed successfully!" } catch { Write-Error-Log "Deployment failed: $($_.Exception.Message)" Start-Rollback } } # Handle command line arguments switch ($Action) { "deploy" { Start-MainDeployment } "rollback" { Start-Rollback } "status" { Show-Status } "logs" { docker-compose logs -f } "stop" { Write-Log "Stopping application..." docker-compose down Write-Log "Application stopped." } "restart" { Write-Log "Restarting application..." docker-compose restart Write-Log "Application restarted." } default { Write-Host "Usage: .\deploy.ps1 {deploy|rollback|status|logs|stop|restart}" Write-Host "" Write-Host "Commands:" Write-Host " deploy - Deploy the application (default)" Write-Host " rollback - Rollback to previous version" Write-Host " status - Show deployment status" Write-Host " logs - Show application logs" Write-Host " stop - Stop the application" Write-Host " restart - Restart the application" } }