mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 09:11:08 -05:00
- Add complete backend/ directory with full Django application - Add frontend/ directory with Vite + TypeScript setup ready for Next.js - Add comprehensive shared/ directory with: - Complete documentation and memory-bank archives - Media files and avatars (letters, park/ride images) - Deployment scripts and automation tools - Shared types and utilities - Add architecture/ directory with migration guides - Configure pnpm workspace for monorepo development - Update .gitignore to exclude .django_tailwind_cli/ build artifacts - Preserve all historical documentation in shared/docs/memory-bank/ - Set up proper structure for full-stack development with shared resources
13 KiB
13 KiB
ThrillWiki Monorepo Deployment Guide
This document outlines deployment strategies, build processes, and infrastructure considerations for the ThrillWiki Django + Vue.js monorepo.
Build Process Overview
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
# Clone repository
git clone <repository-url>
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
# 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
# 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
# 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
# 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:
# Frontend build with pre-rendering
cd frontend
pnpm run build:prerender
# Serve static files with minimal backend
CI/CD Pipeline
GitHub Actions Workflow
# .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)
// 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
# 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
# .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)
# 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)
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
# 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
// 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
# 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
# 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
# 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
# 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
- Build failures: Check dependencies and environment variables
- Database connection errors: Verify connection strings and firewall rules
- Static file 404s: Ensure collectstatic runs and paths are correct
- CORS errors: Check CORS configuration and allowed origins
- Memory issues: Monitor application memory usage and optimize queries
Debug Commands
# 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.