mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 05:51:08 -05:00
- Implemented park card component with image, status badge, favorite button, and quick stats overlay. - Developed ride card component featuring thrill level badge, status badge, favorite button, and detailed stats. - Created advanced search page with filters for parks and rides, including location, type, status, and thrill level. - Added dynamic quick search functionality with results display. - Enhanced user experience with JavaScript for filter toggling, range slider updates, and view switching. - Included custom CSS for improved styling of checkboxes and search results layout.
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.