Add production deployment migration guide and configuration files

Added comprehensive migration documentation and configuration files for restructuring the application to split frontend/backend:

New Documentation:
- MIGRATION_GUIDE.md: Complete step-by-step migration instructions
- MIGRATION_SUMMARY.md: Quick reference guide for deployment
- MIGRATION_CHECKLIST.md: Printable checklist for migration day
- DEPLOYMENT_RESTRUCTURE.md: Architecture overview and benefits

New Configuration Files:
- run_api_server.py: Production WSGI server wrapper using Waitress
- ai_qc.service: Systemd service configuration for backend
- apache_config.conf: Apache virtual host configuration template

Updated Files:
- requirements.txt: Added waitress>=2.1.2 for production WSGI server
- README.md: Added deployment documentation section

Migration Overview:
- Split current monolithic structure into separate frontend/backend
- Move backend to /opt/ai_qc/ (following server standards)
- Keep frontend in /var/www/html/ai_qc/ (single index.html)
- Use Apache reverse proxy to connect frontend to backend API
- Implement systemd service for reliable backend process management

Benefits:
- Improved security (backend code not in web root)
- Better separation of concerns
- Follows industry best practices
- Matches existing server app patterns (/opt/veo3, /opt/voice2text)
- Easier independent updates of frontend/backend

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nickviljoen 2025-11-06 11:45:31 +02:00
parent 824c7639ec
commit b7b7f57b35
9 changed files with 1734 additions and 1 deletions

444
DEPLOYMENT_RESTRUCTURE.md Normal file
View file

@ -0,0 +1,444 @@
# Deployment Restructure Guide
## Overview
This guide explains how to restructure the Visual AI QC application for production deployment by splitting frontend and backend components.
## Current vs. Proposed Structure
### Current Structure (All in one location)
```
/current/location/
├── api_server.py # Backend
├── web_ui.html # Frontend
├── visual_qc_apps/ # Backend
├── profiles/ # Backend
├── brand_guidelines/ # Backend
├── uploads/ # Backend data
├── output/ # Backend data
└── ... (all other files)
```
### Proposed Structure (Split deployment)
#### **Frontend (Web Root: `/var/www/html/ai_qc/`)**
```
/var/www/html/ai_qc/
└── index.html # Renamed from web_ui.html
```
#### **Backend (Application Directory: `/opt/ai_qc/`)**
```
/opt/ai_qc/
├── api_server.py
├── llm_config.py
├── profile_config.py
├── jwt_validator.py
├── auth_middleware.py
├── visual_qc_apps/
│ ├── utils.py
│ ├── flask_app_template.py
│ └── (all QC check modules)
├── profiles/
│ └── (all JSON profiles)
├── brand_guidelines/
│ ├── guidelines_db.json
│ └── (reference assets)
├── config/
│ ├── production.env
│ └── development.env
├── uploads/
├── uploads-dev/
├── output/
├── output-dev/
├── scripts/
│ ├── run-local.sh
│ ├── deploy-to-prod.sh
│ └── test-system.sh
├── requirements.txt
├── CLAUDE.md
├── DEV_PROD_SETUP.md
└── README.md
```
## Required Code Changes
### 1. Frontend Changes (`web_ui.html`)
The frontend HTML needs to know where the backend API is located. Currently, it likely uses relative URLs like `/api/start_analysis`.
**Update API Base URL:**
```javascript
// Add at the top of the script section
const API_BASE_URL = '/api'; // If using reverse proxy
// OR
const API_BASE_URL = 'http://your-domain.com/api'; // If using different port
// Update all fetch calls to use API_BASE_URL
fetch(`${API_BASE_URL}/start_analysis`, {
method: 'POST',
// ... rest of the fetch call
});
```
### 2. Backend Changes (`api_server.py`)
**Update Static File Serving:**
```python
# Current: Flask serves web_ui.html from same directory
# After split: Backend only serves API endpoints, no HTML
# Remove or comment out any static file serving for web_ui.html:
# @app.route('/')
# def index():
# return send_file('web_ui.html')
```
**Update CORS Settings (if needed):**
```python
# If frontend and backend on different domains/ports
from flask_cors import CORS
app = Flask(__name__)
CORS(app,
origins=['https://your-frontend-domain.com'],
supports_credentials=True)
```
### 3. Path Configuration Updates
**Update file paths in `api_server.py`:**
```python
# Ensure all paths are absolute or relative to /opt/ai_qc/
UPLOAD_FOLDER = '/opt/ai_qc/uploads'
OUTPUT_FOLDER = '/opt/ai_qc/output'
UPLOAD_FOLDER_DEV = '/opt/ai_qc/uploads-dev'
OUTPUT_FOLDER_DEV = '/opt/ai_qc/output-dev'
BRAND_GUIDELINES_FOLDER = '/opt/ai_qc/brand_guidelines'
```
## Web Server Configuration Options
### Option A: Nginx Reverse Proxy (Recommended)
```nginx
# /etc/nginx/sites-available/ai_qc
server {
listen 80;
server_name your-domain.com;
# Frontend - Serve static HTML from web root
location / {
root /var/www/html/ai_qc;
index index.html;
try_files $uri $uri/ /index.html;
}
# Backend - Reverse proxy to Flask application
location /api {
proxy_pass http://127.0.0.1:7183;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Increase timeout for long-running analysis
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
}
# Serve uploaded files and outputs
location /uploads {
alias /opt/ai_qc/uploads;
}
location /output {
alias /opt/ai_qc/output;
}
}
```
### Option B: Apache Reverse Proxy
```apache
# /etc/apache2/sites-available/ai_qc.conf
<VirtualHost *:80>
ServerName your-domain.com
# Frontend - Serve static HTML
DocumentRoot /var/www/html/ai_qc
<Directory /var/www/html/ai_qc>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Backend - Reverse proxy to Flask
ProxyPreserveHost On
ProxyPass /api http://127.0.0.1:7183/api
ProxyPassReverse /api http://127.0.0.1:7183/api
# Static file aliases
Alias /uploads /opt/ai_qc/uploads
Alias /output /opt/ai_qc/output
<Directory /opt/ai_qc/uploads>
Require all granted
</Directory>
<Directory /opt/ai_qc/output>
Require all granted
</Directory>
# Enable required modules
# a2enmod proxy proxy_http
</VirtualHost>
```
## Backend Service Configuration
### Systemd Service (Production Deployment)
Create `/etc/systemd/system/ai_qc.service`:
```ini
[Unit]
Description=Visual AI QC Flask Application
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/ai_qc
Environment="ENVIRONMENT=production"
Environment="PATH=/opt/ai_qc/venv/bin"
ExecStart=/opt/ai_qc/venv/bin/gunicorn \
--bind 127.0.0.1:7183 \
--workers 4 \
--timeout 300 \
--access-logfile /var/log/ai_qc/access.log \
--error-logfile /var/log/ai_qc/error.log \
api_server:app
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
```
**Enable and start the service:**
```bash
sudo systemctl daemon-reload
sudo systemctl enable ai_qc
sudo systemctl start ai_qc
sudo systemctl status ai_qc
```
## Migration Steps
### Step 1: Backup Current Deployment
```bash
# On web server
cd /path/to/current/ai_qc
tar -czf ai_qc_backup_$(date +%Y%m%d).tar.gz .
```
### Step 2: Prepare Backend Location
```bash
# Create backend directory
sudo mkdir -p /opt/ai_qc
sudo chown $USER:$USER /opt/ai_qc # Or appropriate user
# Copy all files except web_ui.html
rsync -av --exclude='web_ui.html' \
--exclude='*.pyc' \
--exclude='__pycache__' \
/path/to/current/ai_qc/ /opt/ai_qc/
# Set up virtual environment
cd /opt/ai_qc
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```
### Step 3: Prepare Frontend Location
```bash
# Create frontend directory
sudo mkdir -p /var/www/html/ai_qc
sudo chown $USER:$USER /var/www/html/ai_qc
# Copy and rename web_ui.html
cp /path/to/current/ai_qc/web_ui.html /var/www/html/ai_qc/index.html
```
### Step 4: Update Configuration Files
```bash
# Update production environment config
nano /opt/ai_qc/config/production.env
# Ensure paths are correct in api_server.py
nano /opt/ai_qc/api_server.py
# Update API URLs in frontend
nano /var/www/html/ai_qc/index.html
```
### Step 5: Configure Web Server
```bash
# For Nginx
sudo nano /etc/nginx/sites-available/ai_qc
sudo ln -s /etc/nginx/sites-available/ai_qc /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
# For Apache
sudo nano /etc/apache2/sites-available/ai_qc.conf
sudo a2ensite ai_qc
sudo a2enmod proxy proxy_http
sudo apache2ctl configtest
sudo systemctl reload apache2
```
### Step 6: Set Up Backend Service
```bash
# Create service file
sudo nano /etc/systemd/system/ai_qc.service
# Create log directory
sudo mkdir -p /var/log/ai_qc
sudo chown www-data:www-data /var/log/ai_qc
# Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable ai_qc
sudo systemctl start ai_qc
sudo systemctl status ai_qc
```
### Step 7: Test the Deployment
```bash
# Check backend is running
curl http://localhost:7183/api/profiles
# Check frontend is accessible
curl http://localhost/
# Check full flow through web server
curl http://your-domain.com/api/profiles
```
### Step 8: Verify Authentication
```bash
# Test MSAL authentication endpoints
curl http://your-domain.com/api/auth/status
# Check JWT validation is working
# (This requires authenticated requests from the browser)
```
## Security Considerations
### File Permissions
```bash
# Backend files
sudo chown -R www-data:www-data /opt/ai_qc
sudo chmod -R 750 /opt/ai_qc
sudo chmod 640 /opt/ai_qc/config/*.env
# Upload and output directories need write access
sudo chmod 770 /opt/ai_qc/uploads /opt/ai_qc/output
```
### Firewall Rules
```bash
# Only allow web server ports externally
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Flask port (7183) should NOT be exposed externally
# It should only be accessible via reverse proxy
```
### Environment Variables
```bash
# Ensure sensitive configs are not world-readable
chmod 600 /opt/ai_qc/config/production.env
# Consider using environment variables instead of .env files
# Add to systemd service file:
# Environment="OPENAI_API_KEY=your-key"
# Environment="GOOGLE_API_KEY=your-key"
```
## Monitoring and Logs
### Log Locations
- **Backend Application**: `/var/log/ai_qc/error.log` and `/var/log/ai_qc/access.log`
- **Web Server (Nginx)**: `/var/log/nginx/access.log` and `/var/log/nginx/error.log`
- **Web Server (Apache)**: `/var/log/apache2/access.log` and `/var/log/apache2/error.log`
- **Systemd Service**: `journalctl -u ai_qc -f`
### Health Check Script
```bash
#!/bin/bash
# /opt/ai_qc/scripts/health_check.sh
# Check if service is running
if ! systemctl is-active --quiet ai_qc; then
echo "ERROR: AI QC service is not running"
exit 1
fi
# Check if backend is responding
if ! curl -sf http://localhost:7183/api/profiles > /dev/null; then
echo "ERROR: Backend API is not responding"
exit 1
fi
echo "OK: AI QC application is healthy"
exit 0
```
## Rollback Plan
If issues occur during migration:
```bash
# Stop new service
sudo systemctl stop ai_qc
# Restore backup to original location
cd /path/to/original/location
tar -xzf ai_qc_backup_YYYYMMDD.tar.gz
# Restart original deployment method
# (python api_server.py or previous service)
# Disable new web server config
sudo a2dissite ai_qc # Apache
sudo rm /etc/nginx/sites-enabled/ai_qc # Nginx
sudo systemctl reload apache2 # or nginx
```
## Benefits of This Structure
1. **Security**: Backend code not accessible from web root
2. **Separation of Concerns**: Frontend and backend can be updated independently
3. **Scalability**: Backend can be moved to separate server if needed
4. **Standard Practice**: Follows industry best practices for web application deployment
5. **Better Performance**: Web server serves static files directly, Flask only handles API requests
## Next Steps
1. Identify current web server (Apache/Nginx)
2. Determine current Flask running method
3. Test restructure in development environment first
4. Plan maintenance window for production migration
5. Prepare rollback plan
6. Execute migration during low-usage period
7. Monitor logs and performance after migration

428
MIGRATION_CHECKLIST.md Normal file
View file

@ -0,0 +1,428 @@
# Migration Day Checklist ✅
Use this checklist during your migration to track progress and ensure nothing is missed.
---
## Pre-Migration (30 minutes before)
- [ ] **Read Complete Documentation**
- [ ] Read `MIGRATION_GUIDE.md` completely
- [ ] Review `MIGRATION_SUMMARY.md` for quick reference
- [ ] Understand rollback procedure
- [ ] **Prepare Environment**
- [ ] SSH access to server confirmed
- [ ] Sudo privileges verified
- [ ] Backup directory prepared (`~/backups/`)
- [ ] Maintenance window scheduled and communicated
- [ ] **Verify Current State**
```bash
# Run these commands to document current state:
sudo systemctl status ai_qc | tee ~/pre-migration-service-status.txt
ps aux | grep run_api_server.py | tee ~/pre-migration-process.txt
ls -la /var/www/html/ai_qc/ | tee ~/pre-migration-files.txt
```
---
## Migration Steps (20-30 minutes)
### Step 1: Backup ✅
- [ ] Create backup of current deployment
```bash
cd /var/www/html/ai_qc
sudo tar -czf ~/ai_qc_backup_$(date +%Y%m%d_%H%M%S).tar.gz .
ls -lh ~/ai_qc_backup_*.tar.gz # Verify backup created
```
- [ ] Backup created successfully
- [ ] Backup size looks reasonable (should be several MB)
- [ ] Backup location noted: `_______________`
### Step 2: Stop Current Service ✅
- [ ] Find service name
```bash
sudo systemctl list-units --type=service | grep ai_qc
```
- [ ] Service name identified: `_______________`
- [ ] Stop the service
```bash
sudo systemctl stop [SERVICE_NAME]
```
- [ ] Verify service stopped
```bash
sudo systemctl status ai_qc
ps aux | grep run_api_server.py # Should return nothing
```
- [ ] Service fully stopped (no processes running)
### Step 3: Create Backend Directory ✅
- [ ] Create `/opt/ai_qc/` directory
```bash
sudo mkdir -p /opt/ai_qc
```
- [ ] Copy files to backend location
```bash
cd /var/www/html/ai_qc
sudo rsync -av \
--exclude='web_ui.html' \
--exclude='*.pyc' \
--exclude='__pycache__' \
--exclude='.git' \
. /opt/ai_qc/
```
- [ ] Verify files copied
```bash
ls -la /opt/ai_qc/ # Should see all Python files
```
- [ ] Set ownership
```bash
sudo chown -R www-data:www-data /opt/ai_qc
```
- [ ] Set permissions
```bash
sudo chmod -R 750 /opt/ai_qc
sudo chmod 770 /opt/ai_qc/uploads /opt/ai_qc/output
sudo chmod 770 /opt/ai_qc/uploads-dev /opt/ai_qc/output-dev
sudo chmod 640 /opt/ai_qc/config/*.env
```
### Step 4: Prepare Frontend ✅
- [ ] Create new frontend directory
```bash
sudo mkdir -p /var/www/html/ai_qc_new
```
- [ ] Copy and rename web_ui.html
```bash
sudo cp /var/www/html/ai_qc/web_ui.html /var/www/html/ai_qc_new/index.html
```
- [ ] Set ownership
```bash
sudo chown -R www-data:www-data /var/www/html/ai_qc_new
```
- [ ] Verify frontend file exists
```bash
ls -la /var/www/html/ai_qc_new/index.html
```
### Step 5: Update Backend Paths ✅
- [ ] Edit production.env
```bash
sudo nano /opt/ai_qc/config/production.env
```
- [ ] Verify paths are absolute (start with `/opt/ai_qc/`)
- [ ] UPLOAD_FOLDER=/opt/ai_qc/uploads
- [ ] OUTPUT_FOLDER=/opt/ai_qc/output
- [ ] UPLOAD_FOLDER_DEV=/opt/ai_qc/uploads-dev
- [ ] OUTPUT_FOLDER_DEV=/opt/ai_qc/output-dev
- [ ] BRAND_GUIDELINES_FOLDER=/opt/ai_qc/brand_guidelines
- [ ] Save and exit
### Step 6: Update Systemd Service ✅
- [ ] Backup existing service file
```bash
sudo cp /etc/systemd/system/ai_qc.service /etc/systemd/system/ai_qc.service.backup
```
- [ ] Edit service file
```bash
sudo nano /etc/systemd/system/ai_qc.service
```
- [ ] Verify key settings:
- [ ] WorkingDirectory=/opt/ai_qc
- [ ] ExecStart=/opt/ai_qc/venv/bin/python /opt/ai_qc/run_api_server.py ...
- [ ] User=www-data
- [ ] Group=www-data
- [ ] Save and exit
- [ ] Reload systemd
```bash
sudo systemctl daemon-reload
```
### Step 7: Install Dependencies ✅
- [ ] Activate virtual environment
```bash
cd /opt/ai_qc
source venv/bin/activate
```
- [ ] Install waitress
```bash
pip install waitress
```
- [ ] Verify requirements
```bash
pip install -r requirements.txt
```
- [ ] Deactivate venv
```bash
deactivate
```
### Step 8: Test Backend Standalone ✅
- [ ] Test backend starts
```bash
cd /opt/ai_qc
sudo -u www-data /opt/ai_qc/venv/bin/python run_api_server.py --host localhost --port 7183 --workers 2
```
- [ ] Backend server started without errors
- [ ] In another terminal, test API
```bash
curl http://localhost:7183/api/profiles
```
- [ ] API response received (should show profiles JSON)
- [ ] Stop test server (Ctrl+C)
### Step 9: Update Apache Configuration ✅
- [ ] Backup current Apache config
```bash
sudo cp /etc/apache2/sites-available/ai_qc.conf /etc/apache2/sites-available/ai_qc.conf.backup
```
- [ ] Edit Apache config
```bash
sudo nano /etc/apache2/sites-available/ai_qc.conf
```
- [ ] Update key sections:
- [ ] DocumentRoot points to /var/www/html/ai_qc_new
- [ ] ProxyPass /api and /ai_qc/api configured
- [ ] Alias /uploads points to /opt/ai_qc/uploads
- [ ] Alias /output points to /opt/ai_qc/output
- [ ] Save and exit
- [ ] Test Apache config
```bash
sudo apache2ctl configtest
```
- [ ] Apache config test result: Syntax OK
### Step 10: Start Services ✅
- [ ] Start backend service
```bash
sudo systemctl start ai_qc
```
- [ ] Check service status
```bash
sudo systemctl status ai_qc
```
- [ ] Service running successfully (active/running)
- [ ] Check logs for errors
```bash
sudo journalctl -u ai_qc -n 50 --no-pager
```
- [ ] No critical errors in logs
- [ ] Verify backend responds
```bash
curl http://localhost:7183/api/profiles
```
- [ ] Backend API responding correctly
### Step 11: Reload Apache ✅
- [ ] Reload Apache
```bash
sudo systemctl reload apache2
```
- [ ] Check Apache status
```bash
sudo systemctl status apache2
```
- [ ] Apache reloaded successfully
- [ ] Check Apache errors
```bash
sudo tail -20 /var/log/apache2/ai_qc_error.log
```
- [ ] No critical Apache errors
---
## Testing (10 minutes)
### Browser Testing ✅
- [ ] Open application URL: `_______________`
- [ ] Frontend loads correctly
- [ ] No console errors (F12 → Console tab)
- [ ] "Sign In with Microsoft" button visible
- [ ] Click sign in and authenticate
- [ ] Authentication successful
- [ ] User name displayed in UI
### Functionality Testing ✅
- [ ] Upload test file successfully
- [ ] Select profile from dropdown
- [ ] Start analysis
- [ ] Progress updates appear in real-time
- [ ] Analysis completes successfully
- [ ] Results display correctly
- [ ] Overall score shown
- [ ] Individual check results visible
- [ ] Download report button works
- [ ] Saved files list updates automatically
- [ ] New file highlighted in saved files list
### Additional Testing ✅
- [ ] Test different profile (e.g., General Check)
- [ ] Test with reference asset selection
- [ ] Test JSON output mode
- [ ] Verify JSON download works
- [ ] Test sign out functionality
- [ ] Test sign in again
---
## Finalization (5 minutes)
### Directory Cleanup ✅
- [ ] Rename old directory
```bash
sudo mv /var/www/html/ai_qc /var/www/html/ai_qc_old
```
- [ ] Rename new directory
```bash
sudo mv /var/www/html/ai_qc_new /var/www/html/ai_qc
```
- [ ] Update Apache config DocumentRoot (if needed)
```bash
sudo nano /etc/apache2/sites-available/ai_qc.conf
# Change: DocumentRoot /var/www/html/ai_qc_new
# To: DocumentRoot /var/www/html/ai_qc
```
- [ ] Reload Apache
```bash
sudo systemctl reload apache2
```
- [ ] Test application still works after rename
### Enable Service on Boot ✅
- [ ] Enable service
```bash
sudo systemctl enable ai_qc
```
- [ ] Verify enabled
```bash
sudo systemctl is-enabled ai_qc
```
- [ ] Result shows "enabled"
### Documentation ✅
- [ ] Document migration completion time: `_______________`
- [ ] Note any issues encountered: `_______________`
- [ ] Record backup location: `_______________`
- [ ] Save this checklist for reference
---
## Post-Migration Monitoring (24 hours)
### Immediate Monitoring (First Hour) ✅
- [ ] Monitor logs every 10 minutes
```bash
sudo journalctl -u ai_qc -f
```
- [ ] Check for errors or warnings
- [ ] Test multiple analyses
- [ ] Verify all features working
### Day 1 Monitoring ✅
- [ ] Check service status multiple times
```bash
sudo systemctl status ai_qc
```
- [ ] Review logs for any anomalies
```bash
sudo journalctl -u ai_qc -n 200 --no-pager
```
- [ ] Check disk space
```bash
df -h /opt/ai_qc
```
- [ ] Verify uploads and outputs working
### After 48 Hours ✅
- [ ] Confirm no issues reported by users
- [ ] Review system logs one final time
- [ ] Remove old directory (optional)
```bash
sudo rm -rf /var/www/html/ai_qc_old
```
- [ ] Keep backup for 30 days before deleting
---
## Rollback Procedure (If Needed) 🚨
### Quick Rollback Steps
If issues occur and you need to rollback immediately:
1. **Stop New Service**
```bash
sudo systemctl stop ai_qc
```
2. **Restore Old Directory**
```bash
sudo mv /var/www/html/ai_qc /var/www/html/ai_qc_failed
sudo mv /var/www/html/ai_qc_old /var/www/html/ai_qc
```
3. **Restore Old Apache Config**
```bash
sudo cp /etc/apache2/sites-available/ai_qc.conf.backup /etc/apache2/sites-available/ai_qc.conf
sudo systemctl reload apache2
```
4. **Restore Old Service File**
```bash
sudo cp /etc/systemd/system/ai_qc.service.backup /etc/systemd/system/ai_qc.service
sudo systemctl daemon-reload
```
5. **Start Old Service**
```bash
sudo systemctl start ai_qc
```
6. **Verify Old Version Works**
```bash
curl http://your-domain.com/
```
---
## Migration Summary
**Migration Date**: `_______________`
**Started**: `_______________`
**Completed**: `_______________`
**Total Duration**: `_______________`
**Services Involved**:
- Backend Service: `_______________`
- Web Server: Apache2
- Working: ✅ / ❌
**Issues Encountered**:
```
Write any issues or notes here:
```
**Final Status**:
- [ ] ✅ Migration Successful - All features working
- [ ] ⚠️ Migration Partial - Some issues to resolve
- [ ] ❌ Migration Failed - Rolled back to original
**Sign-off**: `_______________` (Name and Date)
---
## Notes and Reminders
- Keep backup for at least 30 days before deleting
- Monitor logs for first week after migration
- Update any deployment documentation with new paths
- Inform team of new directory structure
- Update any automation scripts pointing to old paths
---
**End of Migration Checklist** ✨

515
MIGRATION_GUIDE.md Normal file
View file

@ -0,0 +1,515 @@
# Visual AI QC Migration Guide
## Moving from Web Root to /opt/ Structure
This guide provides step-by-step instructions for migrating the Visual AI QC application from `/var/www/html/ai_qc/` to a split frontend/backend structure.
---
## Current vs. New Structure
### Current Structure
```
/var/www/html/ai_qc/
├── api_server.py # Backend
├── run_api_server.py # Backend launcher
├── web_ui.html # Frontend
├── visual_qc_apps/ # Backend
├── profiles/ # Backend
├── brand_guidelines/ # Backend
├── uploads/ # Backend data
├── output/ # Backend data
├── venv/ # Backend dependencies
└── ... (all other files)
```
### New Structure
```
Frontend: /var/www/html/ai_qc/
└── index.html # Renamed from web_ui.html
Backend: /opt/ai_qc/
├── api_server.py
├── run_api_server.py
├── llm_config.py
├── profile_config.py
├── jwt_validator.py
├── auth_middleware.py
├── visual_qc_apps/
├── profiles/
├── brand_guidelines/
├── config/
├── uploads/
├── output/
├── venv/
└── ... (all Python/backend files)
```
---
## Prerequisites
Before starting, ensure you have:
1. SSH access to the server with sudo privileges
2. Backup of current deployment
3. Maintenance window scheduled (estimated 15-30 minutes downtime)
4. Apache restart permissions
---
## Step-by-Step Migration
### Step 0: Preparation (On your server via SSH)
```bash
# Check current service name
sudo systemctl list-units --type=service | grep ai_qc
# Check current Apache configuration
ls -la /etc/apache2/sites-enabled/ | grep ai_qc
# Backup current deployment
cd /var/www/html/ai_qc
sudo tar -czf ~/ai_qc_backup_$(date +%Y%m%d_%H%M%S).tar.gz .
echo "Backup created at: ~/ai_qc_backup_$(date +%Y%m%d_%H%M%S).tar.gz"
```
### Step 1: Stop Current Service
```bash
# Find the service name (likely ai_qc or ai_qc.service)
sudo systemctl list-units --type=service | grep ai_qc
# Stop the service (replace SERVICE_NAME with actual name)
sudo systemctl stop SERVICE_NAME
# Verify it's stopped
ps aux | grep run_api_server.py
# Should return no results (except the grep command itself)
```
### Step 2: Create Backend Directory Structure
```bash
# Create backend directory
sudo mkdir -p /opt/ai_qc
# Copy all files except web_ui.html to backend
cd /var/www/html/ai_qc
sudo rsync -av \
--exclude='web_ui.html' \
--exclude='*.pyc' \
--exclude='__pycache__' \
--exclude='.git' \
. /opt/ai_qc/
# Set ownership
sudo chown -R www-data:www-data /opt/ai_qc
# Set permissions
sudo chmod -R 750 /opt/ai_qc
sudo chmod 770 /opt/ai_qc/uploads /opt/ai_qc/output
sudo chmod 770 /opt/ai_qc/uploads-dev /opt/ai_qc/output-dev
sudo chmod 640 /opt/ai_qc/config/*.env
```
### Step 3: Prepare Frontend Directory
```bash
# Create clean frontend directory
sudo mkdir -p /var/www/html/ai_qc_new
# Copy web_ui.html and rename to index.html
sudo cp /var/www/html/ai_qc/web_ui.html /var/www/html/ai_qc_new/index.html
# Set ownership
sudo chown -R www-data:www-data /var/www/html/ai_qc_new
```
### Step 4: Update Backend Configuration
```bash
# Update production environment config with absolute paths
sudo nano /opt/ai_qc/config/production.env
# Ensure these paths are absolute:
# UPLOAD_FOLDER=/opt/ai_qc/uploads
# OUTPUT_FOLDER=/opt/ai_qc/output
# UPLOAD_FOLDER_DEV=/opt/ai_qc/uploads-dev
# OUTPUT_FOLDER_DEV=/opt/ai_qc/output-dev
# BRAND_GUIDELINES_FOLDER=/opt/ai_qc/brand_guidelines
```
### Step 5: Update Frontend API URLs
```bash
# Edit the frontend to use absolute API paths
sudo nano /var/www/html/ai_qc_new/index.html
# Find all fetch() calls and ensure they use /api/ prefix
# Search for: fetch('
# Replace relative URLs with /api/ prefix if needed
# Example: fetch('/start_analysis') → fetch('/api/start_analysis')
```
**Important**: Check if your current `web_ui.html` already uses `/api/` prefix. If it does, no changes needed!
### Step 6: Update Systemd Service
```bash
# Find current service file
sudo find /etc/systemd/system -name "*ai_qc*"
# Create new service file (or update existing)
sudo nano /etc/systemd/system/ai_qc.service
```
Paste this content:
```ini
[Unit]
Description=Visual AI QC Flask Application
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/ai_qc
Environment="ENVIRONMENT=production"
Environment="PATH=/opt/ai_qc/venv/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart=/opt/ai_qc/venv/bin/python /opt/ai_qc/run_api_server.py --host localhost --port 7183 --workers 2
Restart=always
RestartSec=10
NoNewPrivileges=true
PrivateTmp=true
StandardOutput=journal
StandardError=journal
SyslogIdentifier=ai_qc
[Install]
WantedBy=multi-user.target
```
Save and exit (Ctrl+X, Y, Enter)
```bash
# Reload systemd
sudo systemctl daemon-reload
```
### Step 7: Update Apache Configuration
```bash
# Find current Apache config
ls -la /etc/apache2/sites-available/ | grep ai_qc
# Backup current config
sudo cp /etc/apache2/sites-available/ai_qc.conf /etc/apache2/sites-available/ai_qc.conf.backup
# Edit Apache config
sudo nano /etc/apache2/sites-available/ai_qc.conf
```
Update the configuration to:
```apache
<VirtualHost *:80>
ServerName your-domain.com
# Frontend - serve from web root
DocumentRoot /var/www/html/ai_qc_new
<Directory /var/www/html/ai_qc_new>
Options -Indexes +FollowSymLinks
AllowOverride None
Require all granted
DirectoryIndex index.html
</Directory>
# Backend API - proxy to Flask
ProxyPreserveHost On
ProxyPass /api http://localhost:7183/api
ProxyPassReverse /api http://localhost:7183/api
ProxyTimeout 300
# Serve uploaded files from backend
Alias /uploads /opt/ai_qc/uploads
<Directory /opt/ai_qc/uploads>
Options -Indexes
Require all granted
</Directory>
# Serve output files from backend
Alias /output /opt/ai_qc/output
<Directory /opt/ai_qc/output>
Options -Indexes
Require all granted
</Directory>
# Development folders (optional)
Alias /uploads-dev /opt/ai_qc/uploads-dev
<Directory /opt/ai_qc/uploads-dev>
Options -Indexes
Require all granted
</Directory>
Alias /output-dev /opt/ai_qc/output-dev
<Directory /opt/ai_qc/output-dev>
Options -Indexes
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/ai_qc_error.log
CustomLog ${APACHE_LOG_DIR}/ai_qc_access.log combined
</VirtualHost>
```
Save and exit, then:
```bash
# Test Apache configuration
sudo apache2ctl configtest
# Should return "Syntax OK"
```
### Step 8: Install Dependencies (if needed)
```bash
# Activate virtual environment
cd /opt/ai_qc
source venv/bin/activate
# Install waitress if not already installed (for run_api_server.py)
pip install waitress
# Verify all dependencies
pip install -r requirements.txt
deactivate
```
### Step 9: Test Backend Standalone
```bash
# Test if backend starts correctly
cd /opt/ai_qc
sudo -u www-data /opt/ai_qc/venv/bin/python run_api_server.py --host localhost --port 7183 --workers 2
# In another terminal, test the API
curl http://localhost:7183/api/profiles
# Should return profile data
# Press Ctrl+C to stop the test server
```
### Step 10: Start Services
```bash
# Start the backend service
sudo systemctl start ai_qc
# Check status
sudo systemctl status ai_qc
# Check logs
sudo journalctl -u ai_qc -f
# Verify backend is responding
curl http://localhost:7183/api/profiles
```
### Step 11: Reload Apache
```bash
# Reload Apache to apply new configuration
sudo systemctl reload apache2
# Check Apache status
sudo systemctl status apache2
# Check Apache error log
sudo tail -f /var/log/apache2/ai_qc_error.log
```
### Step 12: Test the Application
```bash
# Test frontend is accessible
curl http://your-domain.com/
# Test API through Apache proxy
curl http://your-domain.com/api/profiles
# Test file serving
curl -I http://your-domain.com/uploads/
curl -I http://your-domain.com/output/
```
**Then test in browser:**
1. Open http://your-domain.com/ in browser
2. Sign in with Microsoft authentication
3. Upload a test file
4. Run analysis
5. Verify results display correctly
6. Check saved files list updates
### Step 13: Finalize Migration
Once everything is working:
```bash
# Rename directories
sudo mv /var/www/html/ai_qc /var/www/html/ai_qc_old
sudo mv /var/www/html/ai_qc_new /var/www/html/ai_qc
# Update Apache config DocumentRoot if needed
sudo nano /etc/apache2/sites-available/ai_qc.conf
# Change: DocumentRoot /var/www/html/ai_qc_new
# To: DocumentRoot /var/www/html/ai_qc
# Reload Apache
sudo systemctl reload apache2
# Test again to ensure everything still works
```
### Step 14: Enable Service on Boot
```bash
# Ensure service starts on boot
sudo systemctl enable ai_qc
# Verify it's enabled
sudo systemctl is-enabled ai_qc
# Should return "enabled"
```
---
## Verification Checklist
After migration, verify:
- [ ] Backend service is running: `sudo systemctl status ai_qc`
- [ ] Backend responds: `curl http://localhost:7183/api/profiles`
- [ ] Apache is running: `sudo systemctl status apache2`
- [ ] Frontend loads: Visit http://your-domain.com/
- [ ] API calls work: Check browser console for errors
- [ ] Authentication works: Sign in with Microsoft
- [ ] File upload works: Upload test file
- [ ] Analysis works: Run QC analysis on test file
- [ ] Results display: Verify results show correctly
- [ ] Saved files work: Check saved files list updates
- [ ] File downloads work: Download generated PDF reports
- [ ] Logs are clean: `sudo journalctl -u ai_qc -n 50 --no-pager`
---
## Rollback Plan
If issues occur:
### Quick Rollback
```bash
# Stop new service
sudo systemctl stop ai_qc
# Restore old Apache config
sudo cp /etc/apache2/sites-available/ai_qc.conf.backup /etc/apache2/sites-available/ai_qc.conf
sudo systemctl reload apache2
# Rename directories back
sudo mv /var/www/html/ai_qc /var/www/html/ai_qc_failed
sudo mv /var/www/html/ai_qc_old /var/www/html/ai_qc
# Restore old service file (if you backed it up)
sudo cp /etc/systemd/system/ai_qc.service.backup /etc/systemd/system/ai_qc.service
sudo systemctl daemon-reload
# Start old service
sudo systemctl start ai_qc
# Verify old version works
curl http://your-domain.com/
```
### Full Restore from Backup
```bash
# Stop all services
sudo systemctl stop ai_qc
sudo systemctl stop apache2
# Remove new directories
sudo rm -rf /opt/ai_qc
sudo rm -rf /var/www/html/ai_qc_new
# Restore from backup
cd /var/www/html/ai_qc
sudo tar -xzf ~/ai_qc_backup_YYYYMMDD_HHMMSS.tar.gz
# Restore old config and restart
sudo systemctl start ai_qc
sudo systemctl start apache2
```
---
## Monitoring After Migration
### Check Logs Regularly
```bash
# Backend logs
sudo journalctl -u ai_qc -f
# Apache logs
sudo tail -f /var/log/apache2/ai_qc_error.log
sudo tail -f /var/log/apache2/ai_qc_access.log
# Check disk space
df -h /opt/ai_qc
```
### Performance Monitoring
```bash
# Check backend process
ps aux | grep run_api_server
# Check memory usage
sudo systemctl status ai_qc
# Check port is listening
sudo ss -tlnp | grep 7183
```
---
## Benefits of New Structure
**Security**: Backend code not accessible from web root
**Separation**: Frontend and backend can be updated independently
**Scalability**: Backend can be moved to separate server if needed
**Standard Practice**: Matches other apps on your server (/opt/veo3, /opt/voice2text)
**Better Permissions**: More granular access control
**Cleaner Structure**: Clear separation of concerns
---
## Need Help?
If you encounter issues:
1. Check logs: `sudo journalctl -u ai_qc -n 100 --no-pager`
2. Check Apache logs: `sudo tail -100 /var/log/apache2/ai_qc_error.log`
3. Test backend directly: `curl http://localhost:7183/api/profiles`
4. Verify permissions: `ls -la /opt/ai_qc`
5. Check service status: `sudo systemctl status ai_qc`
Common issues:
- **Permission denied**: Check file ownership (`sudo chown -R www-data:www-data /opt/ai_qc`)
- **Module not found**: Check virtual environment (`which python` should show venv path)
- **Port already in use**: Check if old service is still running (`ps aux | grep 7183`)
- **API not responding**: Check if service is running (`sudo systemctl status ai_qc`)

202
MIGRATION_SUMMARY.md Normal file
View file

@ -0,0 +1,202 @@
# Visual AI QC Migration - Quick Summary
## What You Need to Know
### Why Split Frontend/Backend?
Your server already follows this pattern with other apps:
- `/opt/veo3/backend/` - Backend in opt
- `/opt/voice2text/` - Backend in opt
- `/opt/justeight/` - Backend in opt
This structure provides:
- ✅ **Better Security** - Backend code not in web root
- ✅ **Cleaner Separation** - Frontend and backend updates independent
- ✅ **Standard Practice** - Industry standard for web applications
- ✅ **Better Permissions** - Granular access control
### Current vs. New Structure
**Current:**
```
/var/www/html/ai_qc/ ← Everything here
├── web_ui.html (frontend)
├── api_server.py (backend)
├── visual_qc_apps/ (backend)
└── ... (all files mixed together)
```
**After Migration:**
```
/var/www/html/ai_qc/ ← Frontend only
└── index.html (renamed from web_ui.html)
/opt/ai_qc/ ← Backend only
├── api_server.py
├── run_api_server.py
├── visual_qc_apps/
├── profiles/
├── brand_guidelines/
├── uploads/
├── output/
└── ... (all Python code and data)
```
### Files Created for Migration
1. **`run_api_server.py`** - Production server wrapper (uses Waitress WSGI)
2. **`ai_qc.service`** - Systemd service configuration
3. **`apache_config.conf`** - Apache virtual host configuration
4. **`MIGRATION_GUIDE.md`** - Complete step-by-step instructions
5. **`requirements.txt`** - Updated with Waitress dependency
### Frontend Changes Required
**NONE!** Your `web_ui.html` already has smart base path detection:
```javascript
function getBasePath() {
const path = window.location.pathname;
if (path.includes('/ai_qc/')) {
return path.substring(0, path.indexOf('/ai_qc/') + 7);
}
return '/';
}
```
This automatically detects if running at root (`/`) or subdirectory (`/ai_qc/`) and adjusts API calls accordingly.
### Backend Changes Required
Minimal! Just update file paths in `api_server.py` to use absolute paths:
```python
UPLOAD_FOLDER = '/opt/ai_qc/uploads'
OUTPUT_FOLDER = '/opt/ai_qc/output'
# etc.
```
### Migration Timeline
- **Preparation**: 10 minutes (backup, read guide)
- **Migration**: 15-20 minutes (follow MIGRATION_GUIDE.md)
- **Testing**: 10 minutes (verify all features work)
- **Total Downtime**: ~20-30 minutes
### Quick Migration Checklist
1. ✅ Read `MIGRATION_GUIDE.md` completely
2. ✅ Schedule maintenance window
3. ✅ Backup current deployment
4. ✅ Stop current service
5. ✅ Copy backend files to `/opt/ai_qc/`
6. ✅ Copy frontend to `/var/www/html/ai_qc/` (rename to index.html)
7. ✅ Update systemd service file
8. ✅ Update Apache configuration
9. ✅ Install waitress dependency
10. ✅ Test backend standalone
11. ✅ Start services
12. ✅ Test in browser
13. ✅ Enable service on boot
### Rollback Plan
If issues occur, rollback is simple:
1. Stop new service
2. Restore old Apache config
3. Rename old directory back
4. Start old service
Full instructions in `MIGRATION_GUIDE.md` → "Rollback Plan" section.
### What to Test After Migration
- [ ] Frontend loads (http://your-domain.com/)
- [ ] Authentication works (Microsoft sign-in)
- [ ] File upload works
- [ ] Analysis runs successfully
- [ ] Results display correctly
- [ ] Saved files list updates
- [ ] PDF downloads work
- [ ] All profiles load
- [ ] Brand guidelines work
### Need Help During Migration?
**Before Migration:**
- Read `MIGRATION_GUIDE.md` completely
- Test commands in Step 0 to understand current setup
- Verify backup is created successfully
**During Migration:**
- Follow steps sequentially - don't skip
- Test each step before moving to next
- Check logs if something fails:
```bash
sudo journalctl -u ai_qc -n 50 --no-pager
sudo tail -100 /var/log/apache2/ai_qc_error.log
```
**After Migration:**
- Monitor logs for first hour
- Test all major features
- Keep backup for 48 hours before deleting
### Common Issues and Solutions
| Issue | Cause | Solution |
|-------|-------|----------|
| Backend won't start | Permission denied | `sudo chown -R www-data:www-data /opt/ai_qc` |
| Module not found | Wrong Python environment | Check service file uses `/opt/ai_qc/venv/bin/python` |
| API not responding | Service not running | `sudo systemctl status ai_qc` |
| Frontend shows 404 | Apache config wrong | Check DocumentRoot path in Apache config |
| Uploads fail | Directory permissions | `sudo chmod 770 /opt/ai_qc/uploads` |
### Key Commands
```bash
# Check service status
sudo systemctl status ai_qc
# View logs (live)
sudo journalctl -u ai_qc -f
# Check Apache logs
sudo tail -f /var/log/apache2/ai_qc_error.log
# Test backend directly
curl http://localhost:7183/api/profiles
# Test through Apache
curl http://your-domain.com/api/profiles
# Restart service
sudo systemctl restart ai_qc
# Reload Apache
sudo systemctl reload apache2
```
### Files to Review Before Migration
1. **Read completely**: `MIGRATION_GUIDE.md`
2. **Understand**: `apache_config.conf` (your Apache setup)
3. **Review**: `ai_qc.service` (systemd service)
4. **Check**: `run_api_server.py` (server wrapper)
### Next Steps
1. **Read `MIGRATION_GUIDE.md`** - Complete step-by-step instructions
2. **Schedule maintenance window** - 30 minutes recommended
3. **Test in development** - If you have a dev server, test there first
4. **Execute migration** - Follow guide exactly
5. **Monitor and verify** - Test all features thoroughly
---
## Questions?
- **Where's the detailed guide?**`MIGRATION_GUIDE.md`
- **What Apache config do I use?**`apache_config.conf`
- **How do I start the service?** → See `ai_qc.service`
- **Need to rollback?**`MIGRATION_GUIDE.md` → "Rollback Plan"

View file

@ -713,13 +713,19 @@ DEBUG_MODE=false
## 📚 Additional Documentation
### Core Documentation
- **[Development/Production Setup](DEV_PROD_SETUP.md)**: Complete guide for development and production environments (**NEW** ⭐)
- **[API Reference](API_README.md)**: Detailed API endpoint documentation
- **[Environment Setup](ENVIRONMENT_SETUP_GUIDE.md)**: Comprehensive setup instructions
- **[Environment Setup](ENVIRONMENT_SETUP_GUIDE.md)**: Comprehensive setup instructions
- **[Testing Guide](TESTING_GUIDE.md)**: Testing procedures and examples
- **[Triage System](TRIAGE_SYSTEM_README.md)**: Automatic content type detection
- **[Profiles Guide](profiles/README.md)**: Profile configuration and customization
### Deployment Documentation
- **[Migration Guide](MIGRATION_GUIDE.md)**: Complete step-by-step migration to split frontend/backend structure (**NEW** 🚀)
- **[Migration Summary](MIGRATION_SUMMARY.md)**: Quick reference for deployment restructure (**NEW** 📋)
- **[Deployment Restructure](DEPLOYMENT_RESTRUCTURE.md)**: Detailed architecture and benefits explanation (**NEW** 🏗️)
## 🤝 Contributing
1. Fork the repository

28
ai_qc.service Normal file
View file

@ -0,0 +1,28 @@
[Unit]
Description=Visual AI QC Flask Application
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/ai_qc
Environment="ENVIRONMENT=production"
Environment="PATH=/opt/ai_qc/venv/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart=/opt/ai_qc/venv/bin/python /opt/ai_qc/run_api_server.py --host localhost --port 7183 --workers 2
# Restart policy
Restart=always
RestartSec=10
# Security settings
NoNewPrivileges=true
PrivateTmp=true
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=ai_qc
[Install]
WantedBy=multi-user.target

70
apache_config.conf Normal file
View file

@ -0,0 +1,70 @@
# Apache Configuration for Visual AI QC
# Save to: /etc/apache2/sites-available/ai_qc.conf
# Enable with: sudo a2ensite ai_qc.conf
<VirtualHost *:80>
ServerName your-domain.com
ServerAlias www.your-domain.com
# Document root for frontend
DocumentRoot /var/www/html/ai_qc
<Directory /var/www/html/ai_qc>
Options -Indexes +FollowSymLinks
AllowOverride None
Require all granted
# Serve index.html as default
DirectoryIndex index.html
</Directory>
# Proxy API requests to Flask backend
# Handle both /api and /ai_qc/api patterns (frontend auto-detects)
ProxyPreserveHost On
# If serving from subdirectory /ai_qc/
ProxyPass /ai_qc/api http://localhost:7183/api
ProxyPassReverse /ai_qc/api http://localhost:7183/api
# If serving from root /
ProxyPass /api http://localhost:7183/api
ProxyPassReverse /api http://localhost:7183/api
# Increase timeout for long-running analysis
ProxyTimeout 300
# Serve uploaded files from backend location
Alias /uploads /opt/ai_qc/uploads
<Directory /opt/ai_qc/uploads>
Options -Indexes
Require all granted
</Directory>
# Serve output files from backend location
Alias /output /opt/ai_qc/output
<Directory /opt/ai_qc/output>
Options -Indexes
Require all granted
</Directory>
# Development folders (optional, comment out in production)
Alias /uploads-dev /opt/ai_qc/uploads-dev
<Directory /opt/ai_qc/uploads-dev>
Options -Indexes
Require all granted
</Directory>
Alias /output-dev /opt/ai_qc/output-dev
<Directory /opt/ai_qc/output-dev>
Options -Indexes
Require all granted
</Directory>
# Logging
ErrorLog ${APACHE_LOG_DIR}/ai_qc_error.log
CustomLog ${APACHE_LOG_DIR}/ai_qc_access.log combined
</VirtualHost>
# Enable required Apache modules with:
# sudo a2enmod proxy proxy_http alias

View file

@ -6,6 +6,7 @@ opencv-python>=4.0.0
python-dotenv>=1.0.0
flask>=2.2.3
hypercorn>=0.14.3
waitress>=2.1.2
requests>=2.28.2
python-multipart>=0.0.5
colorama>=0.4.4

39
run_api_server.py Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""
Production server wrapper for Visual AI QC
Runs the Flask application using Waitress WSGI server
"""
import argparse
import sys
import os
from waitress import serve
# Add current directory to Python path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# Import the Flask app
from api_server import app
def main():
parser = argparse.ArgumentParser(description='Run Visual AI QC API Server')
parser.add_argument('--host', default='localhost', help='Host to bind to')
parser.add_argument('--port', type=int, default=7183, help='Port to bind to')
parser.add_argument('--workers', type=int, default=2, help='Number of worker threads')
args = parser.parse_args()
print(f"Starting Visual AI QC server on {args.host}:{args.port}")
print(f"Worker threads: {args.workers}")
print(f"Working directory: {os.getcwd()}")
# Use Waitress WSGI server (production-ready)
serve(
app,
host=args.host,
port=args.port,
threads=args.workers,
url_scheme='http'
)
if __name__ == '__main__':
main()