# 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 ```mermaid 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 ```mermaid 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 ```bash # 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 ```bash # 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 ```yaml packages: - 'frontend' # Backend is managed separately with uv ``` #### Root package.json ```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 ```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 ```mermaid 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 ```python # 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 ```javascript // 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.