Files
thrillwiki_django_no_react/cline_docs/architecture/monorepo-structure-plan.md
pacnpal b1c369c1bb Add park and ride card components with advanced search functionality
- 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.
2025-09-24 23:10:48 -04:00

17 KiB

ThrillWiki Django + Vue.js Monorepo Architecture Plan

Executive Summary

This document outlines the optimal monorepo directory structure for migrating the ThrillWiki Django project to a Django + Vue.js architecture. The design separates backend and frontend concerns while maintaining existing Django app organization and supporting modern development workflows.

Current Project Analysis

Django Apps Structure

  • accounts: User management and authentication
  • parks: Theme park data and operations
  • rides: Ride information and management
  • moderation: Content moderation system
  • location: Geographic data handling
  • media: File and image management
  • email_service: Email functionality
  • core: Core utilities and services

Key Infrastructure

  • Package Management: UV-based Python setup
  • Configuration: config/django/ for settings, config/settings/ for modular settings
  • Development: scripts/dev_server.sh with comprehensive setup
  • Static Assets: Tailwind CSS integration, static/ and staticfiles/
  • Media Handling: Organized media/ directory with park/ride subdirectories

Proposed Monorepo Structure

thrillwiki-monorepo/
├── README.md
├── pyproject.toml                    # Python dependencies (backend only)
├── package.json                      # Node.js dependencies (monorepo coordination)
├── pnpm-workspace.yaml              # pnpm workspace configuration
├── .env.example
├── .gitignore
├── 
├── backend/                          # Django Backend
│   ├── manage.py
│   ├── pyproject.toml               # Backend-specific dependencies
│   ├── config/
│   │   ├── django/
│   │   │   ├── base.py
│   │   │   ├── local.py
│   │   │   ├── production.py
│   │   │   └── test.py
│   │   └── settings/
│   │       ├── database.py
│   │       ├── email.py
│   │       └── security.py
│   ├── thrillwiki/
│   │   ├── __init__.py
│   │   ├── urls.py
│   │   ├── wsgi.py
│   │   ├── asgi.py
│   │   └── views.py
│   ├── apps/                        # Django apps
│   │   ├── accounts/
│   │   ├── parks/
│   │   ├── rides/
│   │   ├── moderation/
│   │   ├── location/
│   │   ├── media/
│   │   ├── email_service/
│   │   └── core/
│   ├── templates/                   # Django templates (API responses, admin)
│   ├── static/                      # Backend static files
│   │   └── admin/                   # Django admin assets
│   ├── media/                       # User uploads
│   │   ├── avatars/
│   │   ├── park/
│   │   └── submissions/
│   └── tests/                       # Backend tests
│
├── frontend/                        # Vue.js Frontend
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── vite.config.js
│   ├── tailwind.config.js
│   ├── index.html
│   ├── src/
│   │   ├── main.js
│   │   ├── App.vue
│   │   ├── router/
│   │   │   └── index.js
│   │   ├── stores/                  # Pinia/Vuex stores
│   │   │   ├── auth.js
│   │   │   ├── parks.js
│   │   │   └── rides.js
│   │   ├── components/
│   │   │   ├── common/              # Shared components
│   │   │   ├── parks/               # Park-specific components
│   │   │   ├── rides/               # Ride-specific components
│   │   │   └── moderation/          # Moderation components
│   │   ├── views/                   # Page components
│   │   │   ├── Home.vue
│   │   │   ├── parks/
│   │   │   ├── rides/
│   │   │   └── auth/
│   │   ├── composables/             # Vue 3 composables
│   │   │   ├── useAuth.js
│   │   │   ├── useApi.js
│   │   │   └── useTheme.js
│   │   ├── services/                # API service layer
│   │   │   ├── api.js
│   │   │   ├── auth.js
│   │   │   ├── parks.js
│   │   │   └── rides.js
│   │   ├── assets/
│   │   │   ├── images/
│   │   │   └── styles/
│   │   │       ├── globals.css
│   │   │       └── components/
│   │   └── utils/
│   ├── public/
│   │   ├── favicon.ico
│   │   └── images/
│   ├── dist/                        # Build output
│   └── tests/                       # Frontend tests
│       ├── unit/
│       └── e2e/
│
├── shared/                          # Shared Resources
│   ├── docs/                        # Documentation
│   │   ├── api/                     # API documentation
│   │   ├── deployment/              # Deployment guides
│   │   └── development/             # Development setup
│   ├── scripts/                     # Build and deployment scripts
│   │   ├── dev/
│   │   │   ├── start-backend.sh
│   │   │   ├── start-frontend.sh
│   │   │   └── start-full-stack.sh
│   │   ├── build/
│   │   │   ├── build-frontend.sh
│   │   │   └── build-production.sh
│   │   ├── deploy/
│   │   └── utils/
│   ├── config/                      # Shared configuration
│   │   ├── docker/
│   │   │   ├── Dockerfile.backend
│   │   │   ├── Dockerfile.frontend
│   │   │   └── docker-compose.yml
│   │   ├── nginx/
│   │   └── ci/                      # CI/CD configuration
│   │       └── github-actions/
│   └── types/                       # Shared TypeScript types
│       ├── api.ts
│       ├── parks.ts
│       └── rides.ts
│
├── logs/                            # Application logs
├── backups/                         # Database backups
├── uploads/                         # Temporary upload directory
└── dist/                            # Production build output
    ├── backend/                     # Django static files
    └── frontend/                    # Vue.js build

Directory Organization Rationale

1. Clear Separation of Concerns

  • backend/: Contains all Django-related code, maintaining existing app structure
  • frontend/: Vue.js application with modern structure (Vite + Vue 3)
  • shared/: Common resources, documentation, and configuration

2. Backend Structure (backend/)

  • Preserves existing Django app organization under apps/
  • Maintains UV-based Python dependency management
  • Keeps configuration structure with config/django/ and config/settings/
  • Separates templates for API responses vs. frontend UI

3. Frontend Structure (frontend/)

  • Modern Vue 3 + Vite setup with TypeScript support
  • Organized by feature areas (parks, rides, auth)
  • Composables for Vue 3 Composition API patterns
  • Service layer for API communication with Django backend
  • Tailwind CSS integration with shared design system

4. Shared Resources (shared/)

  • Centralized documentation and deployment scripts
  • Docker configuration for containerized deployment
  • TypeScript type definitions shared between frontend and API
  • CI/CD pipeline configuration

Static File Strategy

Development

graph LR
    A[Vue Dev Server :3000] --> B[Vite HMR]
    C[Django Dev Server :8000] --> D[Django Static Files]
    E[Tailwind CSS] --> F[Both Frontend & Backend]

Production

graph LR
    A[Vue Build] --> B[dist/frontend/]
    C[Django Collectstatic] --> D[dist/backend/]
    E[Nginx] --> F[Serves Both]
    F --> G[Frontend Assets]
    F --> H[API Endpoints]
    F --> I[Media Files]

Implementation Details

  1. Development Mode:

    • Frontend: Vite dev server on port 3000 with HMR
    • Backend: Django dev server on port 8000
    • Proxy API calls from frontend to backend
  2. Production Mode:

    • Frontend built to dist/frontend/
    • Django static files collected to dist/backend/
    • Nginx serves static files and proxies API calls

Media File Management

Current Structure Preservation

media/
├── avatars/                         # User profile images
├── park/                           # Park-specific media
│   ├── {park-slug}/
│   │   └── {ride-slug}/
└── submissions/                    # User-submitted content
    └── photos/

Strategy

  • Development: Django serves media files directly
  • Production: CDN or object storage (S3/CloudFlare) integration
  • Frontend Access: Media URLs provided via API responses
  • Upload Handling: Django handles all file uploads, Vue.js provides UI

Development Workflow Integration

Package Management

  • Root: Node.js dependencies for frontend and tooling (using pnpm)
  • Backend: UV for Python dependencies (existing approach)
  • Frontend: pnpm for Vue.js dependencies

Development Scripts

# Root level scripts
pnpm run dev              # Start both backend and frontend
pnpm run dev:backend      # Start only Django
pnpm run dev:frontend     # Start only Vue.js
pnpm run build           # Build for production
pnpm run test            # Run all tests

# Backend specific (using UV)
cd backend && uv run manage.py runserver
cd backend && uv run manage.py test

# Frontend specific
cd frontend && pnpm run dev
cd frontend && pnpm run build
cd frontend && pnpm run test

Environment Configuration

# Root .env (shared settings)
DATABASE_URL=
REDIS_URL=
SECRET_KEY=

# Backend .env (Django specific)
DJANGO_SETTINGS_MODULE=config.django.local
DEBUG=True

# Frontend .env (Vue specific)
VITE_API_BASE_URL=http://localhost:8000/api
VITE_APP_TITLE=ThrillWiki

Package Manager Configuration

Root pnpm-workspace.yaml

packages:
  - 'frontend'
  # Backend is managed separately with uv

Root package.json

{
  "name": "thrillwiki-monorepo",
  "private": true,
  "packageManager": "pnpm@9.0.0",
  "scripts": {
    "dev": "concurrently \"pnpm run dev:backend\" \"pnpm run dev:frontend\"",
    "dev:backend": "cd backend && uv run manage.py runserver",
    "dev:frontend": "cd frontend && pnpm run dev",
    "build": "pnpm run build:frontend && cd backend && uv run manage.py collectstatic --noinput",
    "build:frontend": "cd frontend && pnpm run build",
    "test": "pnpm run test:backend && pnpm run test:frontend",
    "test:backend": "cd backend && uv run manage.py test",
    "test:frontend": "cd frontend && pnpm run test",
    "lint": "cd frontend && pnpm run lint && cd ../backend && uv run flake8 .",
    "format": "cd frontend && pnpm run format && cd ../backend && uv run black ."
  },
  "devDependencies": {
    "concurrently": "^8.2.0"
  }
}

Frontend package.json

{
  "name": "thrillwiki-frontend",
  "private": true,
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "test": "vitest",
    "test:e2e": "playwright test",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
    "format": "prettier --write src/",
    "type-check": "vue-tsc --noEmit"
  },
  "dependencies": {
    "vue": "^3.4.0",
    "vue-router": "^4.3.0",
    "pinia": "^2.1.0",
    "axios": "^1.6.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.0",
    "vite": "^5.0.0",
    "vue-tsc": "^2.0.0",
    "typescript": "^5.3.0",
    "tailwindcss": "^3.4.0",
    "autoprefixer": "^10.4.0",
    "postcss": "^8.4.0",
    "eslint": "^8.57.0",
    "prettier": "^3.2.0",
    "vitest": "^1.3.0",
    "@playwright/test": "^1.42.0"
  }
}

File Migration Mapping

High-Level Moves

Current → New Location
├── manage.py → backend/manage.py
├── pyproject.toml → backend/pyproject.toml (+ root package.json)
├── config/ → backend/config/
├── thrillwiki/ → backend/thrillwiki/
├── accounts/ → backend/apps/accounts/
├── parks/ → backend/apps/parks/
├── rides/ → backend/apps/rides/
├── moderation/ → backend/apps/moderation/
├── location/ → backend/apps/location/
├── media/ → backend/apps/media/
├── email_service/ → backend/apps/email_service/
├── core/ → backend/apps/core/
├── templates/ → backend/templates/ (API) + frontend/src/views/ (UI)
├── static/ → backend/static/ (admin) + frontend/src/assets/
├── media/ → media/ (shared, accessible to both)
├── scripts/ → shared/scripts/
├── docs/ → shared/docs/
├── tests/ → backend/tests/ + frontend/tests/
└── staticfiles/ → dist/backend/ (generated)

Detailed Backend App Moves

Each Django app moves to backend/apps/{app_name}/ with structure preserved:

  • Models, views, serializers stay the same
  • Templates for API responses remain in app directories
  • Static files move to frontend if UI-related
  • Tests remain with respective apps

Build and Deployment Strategy

Development Build Process

  1. Backend: No build step, runs directly with Django dev server
  2. Frontend: Vite development server with HMR
  3. Shared: Scripts orchestrate starting both services

Production Build Process

graph TD
    A[CI/CD Trigger] --> B[Install Dependencies]
    B --> C[Build Frontend]
    B --> D[Collect Django Static]
    C --> E[Generate Frontend Bundle]
    D --> F[Collect Backend Assets]
    E --> G[Create Docker Images]
    F --> G
    G --> H[Deploy to Production]

Container Strategy

  • Multi-stage Docker builds: Separate backend and frontend images
  • Nginx: Reverse proxy and static file serving
  • Volume mounts: For media files and logs
  • Environment-based configuration: Development vs. production

API Integration Strategy

Backend API Structure

# Enhanced DRF setup for SPA
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ],
}

# CORS for development
CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",  # Vue dev server
]

Frontend API Service

// API service with auth integration
class ApiService {
  constructor() {
    this.client = axios.create({
      baseURL: import.meta.env.VITE_API_BASE_URL,
      withCredentials: true,
    });
  }
  
  // Park operations
  getParks(params = {}) {
    return this.client.get('/parks/', { params });
  }
  
  // Ride operations
  getRides(parkId, params = {}) {
    return this.client.get(`/parks/${parkId}/rides/`, { params });
  }
}

Configuration Management

Shared Environment Variables

  • Database connections
  • Redis/Cache settings
  • Secret keys and API keys
  • Feature flags

Application-Specific Settings

  • Django: backend/config/django/
  • Vue.js: frontend/.env files
  • Docker: shared/config/docker/

Development vs. Production

  • Development: Multiple local servers, hot reloading
  • Production: Containerized deployment, CDN integration

Benefits of This Structure

  1. Clear Separation: Backend and frontend concerns are clearly separated
  2. Scalability: Each part can be developed, tested, and deployed independently
  3. Modern Workflow: Supports latest Vue 3, Vite, and Django patterns
  4. Backward Compatibility: Preserves existing Django app structure
  5. Developer Experience: Hot reloading, TypeScript support, modern tooling
  6. Deployment Flexibility: Can deploy as SPA + API or traditional Django

Implementation Phases

Phase 1: Structure Setup

  1. Create new directory structure
  2. Move Django code to backend/
  3. Initialize Vue.js frontend
  4. Set up basic API integration

Phase 2: Frontend Development

  1. Create Vue.js components for existing Django templates
  2. Implement routing and state management
  3. Integrate with Django API endpoints
  4. Add authentication flow

Phase 3: Build & Deploy

  1. Set up build processes
  2. Configure CI/CD pipelines
  3. Implement production deployment
  4. Performance optimization

Considerations and Trade-offs

Advantages

  • Modern development experience
  • Better code organization
  • Independent scaling
  • Rich frontend interactions
  • API-first architecture

Challenges

  • Increased complexity
  • Build process coordination
  • Authentication across services
  • SEO considerations (if needed)
  • Development environment setup

Next Steps

  1. Validate Architecture: Review with development team
  2. Prototype Setup: Create basic structure with sample components
  3. Migration Planning: Detailed plan for moving existing code
  4. Tool Selection: Finalize Vue.js ecosystem choices (Pinia vs. Vuex, etc.)
  5. Implementation: Begin phase-by-phase migration

This architecture provides a solid foundation for migrating ThrillWiki to a modern Django + Vue.js monorepo while preserving existing functionality and enabling future growth.