The Material Kai Vision Platform uses a multi-service deployment strategy:
graph TB
subgraph "Production Environment"
A[Vercel Frontend<br/>Static + Edge]
B[MIVAA Service<br/>Docker Container]
C[Supabase<br/>Database + Auth]
D[External APIs<br/>OpenAI, HuggingFace]
end
subgraph "Development Environment"
E[Local Frontend<br/>localhost:5173]
F[Local MIVAA<br/>localhost:8000]
G[Supabase Cloud<br/>Shared Instance]
end
A --> B
A --> C
B --> C
B --> D
E --> F
E --> G
F --> G
# Application
NODE_ENV=production
VITE_DEBUG=false
# Supabase
SUPABASE_URL=https://bgbavxtjlbvgplozizxu.supabase.co
SUPABASE_ANON_KEY=your_production_anon_key
# Services
MIVAA_GATEWAY_URL=https://v1api.materialshub.gr
MIVAA_API_KEY=your_production_mivaa_jwt_token
# External APIs
VITE_OPENAI_API_KEY=your_production_openai_key
VITE_HUGGINGFACE_API_KEY=your_production_hf_key
VITE_REPLICATE_API_TOKEN=your_production_replicate_token
# Security
VITE_ALLOWED_ORIGINS=https://your-domain.com
# Application
ENVIRONMENT=production
DEBUG=false
LOG_LEVEL=ERROR
HOST=0.0.0.0
PORT=8000
# Database
SUPABASE_URL=https://bgbavxtjlbvgplozizxu.supabase.co
SUPABASE_ANON_KEY=your_production_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_production_service_key
# Security
JWT_SECRET_KEY=your_secure_production_jwt_secret
CORS_ORIGINS=https://your-domain.com
RATE_LIMIT_REQUESTS=50
RATE_LIMIT_WINDOW=60
# Performance
MAX_WORKERS=4
CACHE_TTL=3600
DATABASE_POOL_SIZE=20
# Monitoring
SENTRY_DSN=your_sentry_dsn
LOG_FILE=/var/log/mivaa/app.log
File: vercel.json
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"framework": "vite",
"headers": [
{
"source": "/assets/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-XSS-Protection",
"value": "1; mode=block"
}
]
}
]
}
Connect Repository:
# Install Vercel CLI
npm install -g vercel
# Login and link project
vercel login
vercel link
Configure Environment Variables:
# Set production environment variables
vercel env add SUPABASE_URL production
vercel env add SUPABASE_ANON_KEY production
vercel env add VITE_MIVAA_SERVICE_URL production
# ... add all required variables
Deploy:
# Deploy to production
vercel --prod
# Or use automatic deployment via Git
git push origin main # Triggers automatic deployment
Vite Configuration (vite.config.ts):
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
ui: ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
supabase: ['@supabase/supabase-js'],
utils: ['clsx', 'tailwind-merge', 'lucide-react'],
},
},
},
sourcemap: true,
chunkSizeWarningLimit: 1000,
},
});
main or production branchesWhen health checks fail, the system automatically:
All MIVAA service endpoints are available at:
https://v1api.materialshub.grhttps://v1api.materialshub.gr/healthhttps://v1api.materialshub.gr/docshttps://v1api.materialshub.gr/redochttps://v1api.materialshub.gr/openapi.jsonhttps://v1api.materialshub.gr/api/v1/pdf/*https://v1api.materialshub.gr/api/v1/ai/*https://v1api.materialshub.gr/api/v1/search/*Dockerfile:
FROM python:3.9-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
g++ \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create non-root user
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
# Expose port
EXPOSE 8000
# Health check
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# Start application
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Docker Compose (docker-compose.yml):
version: '3.8'
services:
mivaa-service:
build: .
ports:
- "8000:8000"
environment:
- ENVIRONMENT=production
- DEBUG=false
- SUPABASE_URL=${SUPABASE_URL}
- SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
volumes:
- ./logs:/var/log/mivaa
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- mivaa-service
restart: unless-stopped
AWS ECS Deployment:
# Build and push to ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin your-account.dkr.ecr.us-east-1.amazonaws.com
docker build -t mivaa-service .
docker tag mivaa-service:latest your-account.dkr.ecr.us-east-1.amazonaws.com/mivaa-service:latest
docker push your-account.dkr.ecr.us-east-1.amazonaws.com/mivaa-service:latest
# Deploy to ECS
aws ecs update-service --cluster mivaa-cluster --service mivaa-service --force-new-deployment
Setup Script (deploy/setup-server.sh):
#!/bin/bash
# Update system
sudo apt update && sudo apt upgrade -y
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
sudo usermod -aG docker $USER
# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# Clone repository
git clone https://github.com/your-org/material-kai-vision-platform.git
cd material-kai-vision-platform/mivaa-pdf-extractor
# Set up environment variables for Docker deployment
# These MUST be available in the shell environment where docker-compose runs
export SUPABASE_URL="https://your-project.supabase.co"
export SUPABASE_ANON_KEY="your-anon-key"
export OPENAI_API_KEY="your-openai-key"
export MATERIAL_KAI_API_URL="https://your-platform-url.com"
export MATERIAL_KAI_API_KEY="your-api-key"
export SENTRY_DSN="your-sentry-dsn"
# Deploy
docker-compose -f docker-compose.prod.yml up -d
# Set up SSL with Let's Encrypt
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
File: .github/workflows/deploy.yml
Features:
main or production branchesUsage:
# Automatic deployment
git push origin main
# Manual deployment
# Go to GitHub Actions → "MIVAA Deployment (Default)" → Run workflow
File: .github/workflows/orchestrated-deployment.yml
Features:
Usage:
# Manual orchestrated deployment
# Go to GitHub Actions → "Orchestrated MIVAA Deployment Pipeline (On-Demand)"
# Configure options:
# - Deployment Mode: intelligent
# - Target Branch: main
# - Deployment Reason: "Feature release with enhanced monitoring"
# Run workflow
Both workflows include comprehensive health monitoring:
# Tested endpoints:
curl https://v1api.materialshub.gr/health
curl https://v1api.materialshub.gr/docs
curl https://v1api.materialshub.gr/redoc
curl https://v1api.materialshub.gr/openapi.json
# System diagnostics collected:
- Server uptime and load averages
- Memory and disk usage
- Service status (systemctl status mivaa-pdf-extractor)
- Recent service logs (last 50 lines)
- Network status (port 8000 availability)
- Process binding verification
- Service restart attempt
- Post-restart verification
All deployment results are displayed on the main GitHub Action page with:
Set these in GitHub repository secrets:
# Server Access
SSH_PRIVATE_KEY=your_ssh_private_key
DEPLOY_HOST=104.248.68.3
# Application Environment
SUPABASE_URL=https://bgbavxtjlbvgplozizxu.supabase.co
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
JWT_SECRET_KEY=your_jwt_secret
OPENAI_API_KEY=your_openai_key
HUGGINGFACE_API_KEY=your_huggingface_key
MATERIAL_KAI_API_URL=https://v1api.materialshub.gr
MATERIAL_KAI_API_KEY=your_api_key
SENTRY_DSN=your_sentry_dsn
Create Project:
Configure Database:
-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "vector";
CREATE EXTENSION IF NOT EXISTS "ltree";
Set Up Authentication:
# Configure JWT settings in Supabase dashboard
# Set up email templates
# Configure OAuth providers (if needed)
Deploy Schema:
# Initialize migrations (when available)
supabase migration new initial_schema
supabase db push
Row Level Security (RLS):
-- Enable RLS on all tables
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
ALTER TABLE api_keys ENABLE ROW LEVEL SECURITY;
-- Create policies
CREATE POLICY "Users can only access their workspace data" ON documents
FOR ALL USING (workspace_id IN (
SELECT workspace_id FROM user_workspaces
WHERE user_id = auth.uid()
));
Nginx Configuration (nginx.conf):
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
location / {
proxy_pass http://mivaa-service:8000;
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;
}
}
# UFW firewall setup
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Health Check Endpoints:
# Frontend health
curl https://your-domain.com/api/health
# MIVAA service health
curl https://your-mivaa-service.com/health
# Database health
curl https://your-mivaa-service.com/api/v1/health
Structured Logging:
# mivaa-pdf-extractor/app/utils/logging.py
import structlog
logger = structlog.get_logger()
# Log with context
logger.info("Document processed",
document_id=doc_id,
processing_time=time_taken,
user_id=user_id)
Sentry Integration:
// Frontend error tracking
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: process.env.VITE_SENTRY_DSN,
environment: process.env.NODE_ENV,
});
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm test
- run: npm run build
deploy-frontend:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: amondnet/vercel-action@v20
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.ORG_ID }}
vercel-project-id: ${{ secrets.PROJECT_ID }}
vercel-args: '--prod'
deploy-backend:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to server
env:
# ⚠️ IMPORTANT: Use GH_TOKEN, not GITHUB_TOKEN as env var name
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
script: |
cd /app/material-kai-vision-platform
git pull origin main
# Authenticate with GitHub Container Registry
echo "$GH_TOKEN" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker-compose -f docker-compose.prod.yml up -d --build
Token Naming: GitHub doesn't allow environment variables starting with GITHUB_ prefix
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Container Registry Authentication: Always authenticate before pulling private images
echo "$GH_TOKEN" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
Missing Docker Environment Variables:
export SUPABASE_URL="https://your-project.supabase.co"
export SUPABASE_ANON_KEY="your-anon-key"
export OPENAI_API_KEY="your-openai-key"
export MATERIAL_KAI_API_URL="https://your-platform-url.com"
export MATERIAL_KAI_API_KEY="your-api-key"
export SENTRY_DSN="your-sentry-dsn"
Environment Variable Mismatch:
CORS Errors:
Database Connection Issues:
SSL Certificate Issues:
# Quick rollback for MIVAA service
docker-compose -f docker-compose.prod.yml down
docker-compose -f docker-compose.prod.yml up -d --scale mivaa-service=0
docker tag mivaa-service:previous mivaa-service:latest
docker-compose -f docker-compose.prod.yml up -d
Database Backups (Supabase):
# Supabase provides automatic daily backups
# Access backups in Supabase Dashboard → Settings → Backups
# Point-in-time recovery (PITR) available for 7 days
# Restore via Supabase Dashboard or API
Application Data Backups:
# Automated backup script (runs daily via cron)
# Location: /usr/local/bin/backup-mivaa.sh
# Manual backup
backup-mivaa.sh
# Backup location: /backups/mivaa_backup_YYYYMMDD_HHMMSS.tar.gz
# Retention: Last 7 backups kept automatically
Database Recovery:
Application Recovery:
# Restore from backup
cd /backups
tar -xzf mivaa_backup_YYYYMMDD_HHMMSS.tar.gz -C /app
# Restart service
systemctl restart mivaa-pdf-extractor
Using Supabase Migrations:
# Create new migration
supabase migration new add_new_table
# Apply migrations
supabase db push
# Rollback migration
supabase db reset
Zero-Downtime Deployments:
Required PostgreSQL Extensions:
-- Enable in Supabase Dashboard → SQL Editor
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "vector";
CREATE EXTENSION IF NOT EXISTS "ltree";
The platform implements automatic job recovery for PDF processing:
Job States:
pending - Waiting to startprocessing - Currently runningcompleted - Successfully finishedfailed - Processing failedcancelled - User cancelledRecovery on Restart:
# Automatic on service startup
# Resumes jobs in 'processing' state
# Retries failed jobs up to max_retries
Graceful Shutdown:
# Service receives SIGTERM
# Completes current operations
# Persists job state
# Exits cleanly
# Timeout: 30 seconds before SIGKILL
MIVAA Service Scaling:
# docker-compose.yml
services:
mivaa-service:
deploy:
replicas: 3 # Scale to 3 instances
Load Balancing:
upstream mivaa_backend {
server mivaa-service:8000;
server mivaa-service:8001;
server mivaa-service:8002;
}
server {
location / {
proxy_pass http://mivaa_backend;
}
}
Supabase Connection Pool:
# Set in MIVAA environment
DATABASE_POOL_SIZE=20
DATABASE_POOL_TIMEOUT=30
Application-Level Caching:
// Production caching configuration
caching: {
enabled: true,
ttl: 3600000, // 1 hour
maxSize: 1000, // 1000 items
strategy: 'lru' // Least Recently Used
}
Key Metrics to Monitor:
Sentry Configuration:
// Frontend monitoring
Sentry.init({
dsn: process.env.VITE_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
integrations: [
new Sentry.Replay({
maskAllText: true,
blockAllMedia: true,
}),
],
});
alertThresholds: {
errorRate: 0.05, // 5% error rate
responseTime: 2000, // 2 seconds
memoryUsage: 0.7, // 70% memory
cpuUsage: 0.8, // 80% CPU
}
# MIVAA Service environment
RATE_LIMIT_REQUESTS=50
RATE_LIMIT_WINDOW=60 # per minute
# nginx.conf
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header Content-Security-Policy "default-src 'self'";
Rotation Schedule:
Rotation Process:
Deploy Function:
# Create new function
supabase functions new my-function
# Deploy to production
supabase functions deploy my-function --project-ref bgbavxtjlbvgplozizxu
Environment Variables:
# Set in Supabase Dashboard → Edge Functions → Secrets
supabase secrets set JWT_SECRET_KEY=your_secret