ai_qc/DEPLOYMENT_RESTRUCTURE.md
nickviljoen b7b7f57b35 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>
2025-11-06 11:45:31 +02:00

11 KiB

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:

// 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:

# 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):

# 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:

# 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

# /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

# /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:

[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:

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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

#!/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:

# 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