# ThrillWiki Monorepo Deployment Guide This document outlines deployment strategies, build processes, and infrastructure considerations for the ThrillWiki Django + Vue.js monorepo. ## Build Process Overview ```mermaid graph TB A[Source Code] --> B[Backend Build] A --> C[Frontend Build] B --> D[Django Static Collection] C --> E[Vue.js Production Build] D --> F[Backend Container] E --> G[Frontend Assets] F --> H[Production Deployment] G --> H ``` ## Development Environment ### Prerequisites - Python 3.11+ with UV package manager - Node.js 18+ with pnpm - PostgreSQL (production) / SQLite (development) - Redis (for caching and sessions) ### Local Development Setup ```bash # Clone repository git clone cd thrillwiki-monorepo # Install root dependencies pnpm install # Backend setup cd backend uv sync uv run manage.py migrate uv run manage.py collectstatic # Frontend setup cd ../frontend pnpm install # Start development servers cd .. pnpm run dev # Starts both backend and frontend ``` ## Build Strategies ### 1. Containerized Deployment (Recommended) #### Multi-stage Dockerfile for Backend ```dockerfile # backend/Dockerfile FROM python:3.11-slim as builder WORKDIR /app COPY pyproject.toml uv.lock ./ RUN pip install uv RUN uv sync --no-dev FROM python:3.11-slim as runtime WORKDIR /app COPY --from=builder /app/.venv /app/.venv ENV PATH="/app/.venv/bin:$PATH" COPY . . RUN python manage.py collectstatic --noinput EXPOSE 8000 CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"] ``` #### Dockerfile for Frontend ```dockerfile # frontend/Dockerfile FROM node:18-alpine as builder WORKDIR /app COPY package.json pnpm-lock.yaml ./ RUN npm install -g pnpm RUN pnpm install --frozen-lockfile COPY . . RUN pnpm run build FROM nginx:alpine as runtime COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` #### Docker Compose for Development ```yaml # docker-compose.dev.yml version: '3.8' services: db: image: postgres:15 environment: POSTGRES_DB: thrillwiki POSTGRES_USER: thrillwiki POSTGRES_PASSWORD: password volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" redis: image: redis:7-alpine ports: - "6379:6379" backend: build: context: ./backend dockerfile: Dockerfile.dev ports: - "8000:8000" volumes: - ./backend:/app - ./shared/media:/app/media environment: - DEBUG=1 - DATABASE_URL=postgresql://thrillwiki:password@db:5432/thrillwiki - REDIS_URL=redis://redis:6379/0 depends_on: - db - redis frontend: build: context: ./frontend dockerfile: Dockerfile.dev ports: - "3000:3000" volumes: - ./frontend:/app - /app/node_modules environment: - VITE_API_URL=http://localhost:8000 volumes: postgres_data: ``` #### Docker Compose for Production ```yaml # docker-compose.prod.yml version: '3.8' services: db: image: postgres:15 environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data restart: unless-stopped redis: image: redis:7-alpine restart: unless-stopped backend: build: context: ./backend dockerfile: Dockerfile environment: - DEBUG=0 - DATABASE_URL=${DATABASE_URL} - REDIS_URL=${REDIS_URL} - SECRET_KEY=${SECRET_KEY} - ALLOWED_HOSTS=${ALLOWED_HOSTS} volumes: - ./shared/media:/app/media - static_files:/app/staticfiles depends_on: - db - redis restart: unless-stopped frontend: build: context: ./frontend dockerfile: Dockerfile restart: unless-stopped nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/ssl:/etc/nginx/ssl - static_files:/usr/share/nginx/html/static - ./shared/media:/usr/share/nginx/html/media depends_on: - backend - frontend restart: unless-stopped volumes: postgres_data: static_files: ``` ### 2. Static Site Generation (Alternative) For sites with mostly static content, consider pre-rendering: ```bash # Frontend build with pre-rendering cd frontend pnpm run build:prerender # Serve static files with minimal backend ``` ## CI/CD Pipeline ### GitHub Actions Workflow ```yaml # .github/workflows/deploy.yml name: Deploy ThrillWiki on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest services: postgres: image: postgres:15 env: POSTGRES_PASSWORD: postgres options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install UV run: pip install uv - name: Backend Tests run: | cd backend uv sync uv run manage.py test uv run flake8 . uv run black --check . - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '18' - name: Install pnpm run: npm install -g pnpm - name: Frontend Tests run: | cd frontend pnpm install --frozen-lockfile pnpm run test pnpm run lint pnpm run type-check build: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - name: Build and push Docker images run: | docker build -t thrillwiki-backend ./backend docker build -t thrillwiki-frontend ./frontend # Push to registry - name: Deploy to production run: | # Deploy using your preferred method # (AWS ECS, GCP Cloud Run, Azure Container Instances, etc.) ``` ## Platform-Specific Deployments ### 1. Vercel Deployment (Frontend + API) ```json // vercel.json { "version": 2, "builds": [ { "src": "frontend/package.json", "use": "@vercel/static-build", "config": { "distDir": "dist" } }, { "src": "backend/config/wsgi.py", "use": "@vercel/python" } ], "routes": [ { "src": "/api/(.*)", "dest": "backend/config/wsgi.py" }, { "src": "/(.*)", "dest": "frontend/dist/$1" } ] } ``` ### 2. Railway Deployment ```toml # railway.toml [environments.production] [environments.production.services.backend] dockerfile = "backend/Dockerfile" variables = { DEBUG = "0" } [environments.production.services.frontend] dockerfile = "frontend/Dockerfile" [environments.production.services.postgres] image = "postgres:15" variables = { POSTGRES_DB = "thrillwiki" } ``` ### 3. DigitalOcean App Platform ```yaml # .do/app.yaml name: thrillwiki services: - name: backend source_dir: backend github: repo: your-username/thrillwiki-monorepo branch: main run_command: gunicorn config.wsgi:application environment_slug: python instance_count: 1 instance_size_slug: basic-xxs envs: - key: DEBUG value: "0" - name: frontend source_dir: frontend github: repo: your-username/thrillwiki-monorepo branch: main build_command: pnpm run build run_command: pnpm run preview environment_slug: node-js instance_count: 1 instance_size_slug: basic-xxs databases: - name: thrillwiki-db engine: PG version: "15" ``` ## Environment Configuration ### Environment Variables #### Backend (.env) ```bash # Django Settings DEBUG=0 SECRET_KEY=your-secret-key-here ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com # Database DATABASE_URL=postgresql://user:password@host:port/database # Redis REDIS_URL=redis://host:port/0 # File Storage MEDIA_ROOT=/app/media STATIC_ROOT=/app/staticfiles # Email EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend EMAIL_HOST=smtp.yourmailprovider.com EMAIL_PORT=587 EMAIL_USE_TLS=True EMAIL_HOST_USER=your-email@yourdomain.com EMAIL_HOST_PASSWORD=your-email-password # Third-party Services SENTRY_DSN=your-sentry-dsn AWS_ACCESS_KEY_ID=your-aws-key AWS_SECRET_ACCESS_KEY=your-aws-secret ``` #### Frontend (.env.production) ```bash VITE_API_URL=https://api.yourdomain.com VITE_APP_TITLE=ThrillWiki VITE_SENTRY_DSN=your-frontend-sentry-dsn VITE_GOOGLE_ANALYTICS_ID=your-ga-id ``` ## Performance Optimization ### Backend Optimizations ```python # backend/config/settings/production.py # Database optimization DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'CONN_MAX_AGE': 60, 'OPTIONS': { 'MAX_CONNS': 20, } } } # Caching CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.redis.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379/1', 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient', }, 'KEY_PREFIX': 'thrillwiki' } } # Static files with CDN AWS_S3_CUSTOM_DOMAIN = 'cdn.yourdomain.com' STATICFILES_STORAGE = 'storages.backends.s3boto3.StaticS3Boto3Storage' DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.MediaS3Boto3Storage' ``` ### Frontend Optimizations ```typescript // frontend/vite.config.ts export default defineConfig({ build: { rollupOptions: { output: { manualChunks: { vendor: ['vue', 'vue-router', 'pinia'], ui: ['@headlessui/vue', '@heroicons/vue'] } } }, sourcemap: false, minify: 'terser', terserOptions: { compress: { drop_console: true, drop_debugger: true } } } }) ``` ## Monitoring and Logging ### Application Monitoring ```python # backend/config/settings/production.py import sentry_sdk from sentry_sdk.integrations.django import DjangoIntegration sentry_sdk.init( dsn="your-sentry-dsn", integrations=[DjangoIntegration()], traces_sample_rate=0.1, send_default_pii=True ) # Logging configuration LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'INFO', 'class': 'logging.FileHandler', 'filename': '/var/log/django/thrillwiki.log', }, }, 'root': { 'handlers': ['file'], }, } ``` ### Infrastructure Monitoring - Use Prometheus + Grafana for metrics - Implement health check endpoints - Set up log aggregation (ELK stack or similar) - Monitor database performance - Track API response times ## Security Considerations ### Production Security Checklist - [ ] HTTPS enforced with SSL certificates - [ ] Security headers configured (HSTS, CSP, etc.) - [ ] Database credentials secured - [ ] Secret keys rotated regularly - [ ] CORS properly configured - [ ] Rate limiting implemented - [ ] File upload validation - [ ] SQL injection protection - [ ] XSS protection enabled - [ ] CSRF protection active ### Security Headers ```python # backend/config/settings/production.py SECURE_SSL_REDIRECT = True SECURE_HSTS_SECONDS = 31536000 SECURE_HSTS_INCLUDE_SUBDOMAINS = True SECURE_HSTS_PRELOAD = True SECURE_CONTENT_TYPE_NOSNIFF = True SECURE_BROWSER_XSS_FILTER = True X_FRAME_OPTIONS = 'DENY' # CORS for API CORS_ALLOWED_ORIGINS = [ "https://yourdomain.com", "https://www.yourdomain.com", ] ``` ## Backup and Recovery ### Database Backup Strategy ```bash # Automated backup script #!/bin/bash pg_dump $DATABASE_URL | gzip > backup_$(date +%Y%m%d_%H%M%S).sql.gz aws s3 cp backup_*.sql.gz s3://your-backup-bucket/database/ ``` ### Media Files Backup ```bash # Sync media files to S3 aws s3 sync ./shared/media/ s3://your-media-bucket/media/ --delete ``` ## Scaling Strategies ### Horizontal Scaling - Load balancer configuration - Database read replicas - CDN for static assets - Redis clustering - Auto-scaling groups ### Vertical Scaling - Database connection pooling - Application server optimization - Memory usage optimization - CPU-intensive task optimization ## Troubleshooting Guide ### Common Issues 1. **Build failures**: Check dependencies and environment variables 2. **Database connection errors**: Verify connection strings and firewall rules 3. **Static file 404s**: Ensure collectstatic runs and paths are correct 4. **CORS errors**: Check CORS configuration and allowed origins 5. **Memory issues**: Monitor application memory usage and optimize queries ### Debug Commands ```bash # Backend debugging cd backend uv run manage.py check --deploy uv run manage.py shell uv run manage.py dbshell # Frontend debugging cd frontend pnpm run build --debug pnpm run preview ``` This deployment guide provides a comprehensive approach to deploying the ThrillWiki monorepo across various platforms while maintaining security, performance, and scalability.