- Implement tests for RideLocation and CompanyHeadquarters models to verify functionality and data integrity. - Create a manual trigger test script for trending content calculation endpoint, including authentication and unauthorized access tests. - Develop a manufacturer sync test to ensure ride manufacturers are correctly associated with ride models. - Add tests for ParkLocation model, including coordinate setting and distance calculations between parks. - Implement a RoadTripService test suite covering geocoding, route calculation, park discovery, and error handling. - Create a unified map service test script to validate map functionality, API endpoints, and performance metrics.
18 KiB
🏗️ ThrillWiki Nuxt Frontend - Architecture Decisions
Status: ✅ COMPLETE
Last Updated: 2025-01-27 19:58 UTC
Dependencies: requirements.md
Blocks: All implementation phases
🎯 Architecture Overview
System Architecture
┌─────────────────────────────────────────────────────────────┐
│ ThrillWiki System │
├─────────────────────────────────────────────────────────────┤
│ Frontend (Nuxt 3) │ Backend (Django) │
│ ┌─────────────────────┐ │ ┌─────────────────────┐ │
│ │ Pages & Components │ │ │ REST API (/api/v1/) │ │
│ │ ├─ Parks │ │ │ ├─ Authentication │ │
│ │ ├─ Rides │ │ │ ├─ Parks CRUD │ │
│ │ ├─ Auth │ │ │ ├─ Rides CRUD │ │
│ │ └─ Admin │ │ │ ├─ Photos │ │
│ └─────────────────────┘ │ │ └─ Moderation │ │
│ ┌─────────────────────┐ │ └─────────────────────┘ │
│ │ Composables │ │ ┌─────────────────────┐ │
│ │ ├─ useAuth │◄───┼──┤ JWT Authentication │ │
│ │ ├─ useApi │◄───┼──┤ Token Management │ │
│ │ ├─ useParks │◄───┼──┤ CORS Configuration │ │
│ │ └─ useRides │ │ └─────────────────────┘ │
│ └─────────────────────┘ │ │
│ ┌─────────────────────┐ │ ┌─────────────────────┐ │
│ │ Component Library │ │ │ Database (PostgreSQL)│ │
│ │ ├─ UI Components │ │ │ ├─ Parks │ │
│ │ ├─ Forms │ │ │ ├─ Rides │ │
│ │ ├─ Navigation │ │ │ ├─ Users │ │
│ │ └─ Modals │ │ │ └─ Photos │ │
│ └─────────────────────┘ │ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Technology Stack Decisions
Frontend Framework: Nuxt 3
Decision: Use Nuxt 3 with Vue 3 Composition API
Rationale:
- Server-Side Rendering: Better SEO and initial load performance
- File-based Routing: Intuitive page organization
- Auto-imports: Reduced boilerplate code
- Built-in Optimization: Image optimization, code splitting, etc.
- TypeScript Support: First-class TypeScript integration
- Ecosystem: Rich ecosystem with modules and plugins
Alternatives Considered:
- Next.js: Rejected due to React requirement
- SvelteKit: Rejected due to smaller ecosystem
- Vite + Vue: Rejected due to lack of SSR out-of-the-box
State Management: Pinia
Decision: Use Pinia for global state management
Rationale:
- Vue 3 Native: Built specifically for Vue 3
- TypeScript Support: Excellent TypeScript integration
- DevTools: Great debugging experience
- Modular: Easy to organize stores by feature
- Performance: Optimized for Vue 3 reactivity
Alternatives Considered:
- Vuex: Rejected due to Vue 3 compatibility issues
- Composables Only: Rejected for complex state management needs
Component Library: TBD (User Choice Required)
Status: ⏳ PENDING USER DECISION
Options Analyzed:
Option 1: Nuxt UI (Recommended)
// Installation
npm install @nuxt/ui
// Configuration
export default defineNuxtConfig({
modules: ['@nuxt/ui'],
ui: {
global: true,
icons: ['heroicons']
}
})
Pros:
- Built specifically for Nuxt 3
- Tailwind CSS integration
- Headless UI foundation (accessibility)
- TypeScript support
- Modern design system
- Tree-shakable
Cons:
- Newer library (less mature)
- Smaller component set
- Limited complex components
Option 2: Vuetify
// Installation
npm install vuetify @mdi/font
// Configuration
import { createVuetify } from 'vuetify'
export default defineNuxtPlugin(() => {
const vuetify = createVuetify({
theme: { defaultTheme: 'light' }
})
return { provide: { vuetify } }
})
Pros:
- Mature, battle-tested
- Comprehensive component set
- Material Design system
- Strong community
- Good documentation
Cons:
- Large bundle size
- Material Design constraints
- Vue 3 support still evolving
- Less customizable
Option 3: PrimeVue
// Installation
npm install primevue primeicons
// Configuration
import PrimeVue from 'primevue/config'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(PrimeVue)
})
Pros:
- Enterprise-focused
- Comprehensive components
- Good TypeScript support
- Professional themes
- Accessibility features
Cons:
- Commercial themes cost
- Learning curve
- Less modern design
- Larger bundle size
Authentication: JWT with Refresh Tokens
Decision: Implement JWT authentication with refresh token mechanism
Rationale:
- Stateless: No server-side session storage required
- Scalable: Works well with multiple frontend instances
- Secure: Short-lived access tokens with refresh mechanism
- Standard: Industry standard for API authentication
Implementation Strategy:
// composables/useAuth.ts
export const useAuth = () => {
const accessToken = useCookie('access_token', {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 15 * 60 // 15 minutes
})
const refreshToken = useCookie('refresh_token', {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 // 7 days
})
const refreshAccessToken = async () => {
// Auto-refresh logic
}
return {
login, logout, refreshAccessToken,
isAuthenticated: computed(() => !!accessToken.value)
}
}
API Integration: Custom Composables with $fetch
Decision: Use Nuxt's built-in $fetch with custom composables
Rationale:
- Built-in: No additional HTTP client needed
- SSR Compatible: Works seamlessly with server-side rendering
- Type Safe: Full TypeScript support
- Caching: Built-in request caching
- Error Handling: Consistent error handling patterns
Implementation Pattern:
// composables/useApi.ts
export const useApi = () => {
const { $fetch } = useNuxtApp()
const { accessToken } = useAuth()
const apiCall = async (endpoint: string, options: any = {}) => {
return await $fetch(`/api/v1${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${accessToken.value}`,
...options.headers
}
})
}
return { apiCall }
}
Project Structure Decisions
Directory Structure
frontend/
├── assets/ # Static assets (images, fonts, etc.)
├── components/ # Vue components
│ ├── ui/ # UI library components
│ ├── layout/ # Layout components
│ ├── forms/ # Form components
│ └── features/ # Feature-specific components
│ ├── parks/ # Park-related components
│ ├── rides/ # Ride-related components
│ ├── auth/ # Authentication components
│ └── admin/ # Admin/moderation components
├── composables/ # Vue composables
│ ├── useAuth.ts # Authentication logic
│ ├── useApi.ts # API integration
│ ├── useParks.ts # Parks data management
│ ├── useRides.ts # Rides data management
│ └── useModeration.ts # Moderation logic
├── layouts/ # Nuxt layouts
│ ├── default.vue # Default layout
│ ├── auth.vue # Authentication layout
│ └── admin.vue # Admin layout
├── middleware/ # Route middleware
│ ├── auth.ts # Authentication middleware
│ └── admin.ts # Admin access middleware
├── pages/ # File-based routing
│ ├── index.vue # Homepage
│ ├── parks/ # Parks pages
│ ├── rides/ # Rides pages
│ ├── auth/ # Authentication pages
│ └── admin/ # Admin pages
├── plugins/ # Nuxt plugins
│ ├── api.client.ts # API configuration
│ └── context7.client.ts # Context7 integration
├── stores/ # Pinia stores
│ ├── auth.ts # Authentication store
│ ├── parks.ts # Parks store
│ └── ui.ts # UI state store
├── types/ # TypeScript type definitions
│ ├── api.ts # API response types
│ ├── auth.ts # Authentication types
│ └── components.ts # Component prop types
├── utils/ # Utility functions
│ ├── validation.ts # Form validation
│ ├── formatting.ts # Data formatting
│ └── constants.ts # Application constants
├── nuxt.config.ts # Nuxt configuration
├── package.json # Dependencies
└── tsconfig.json # TypeScript configuration
Development Environment Decisions
Package Manager: npm
Decision: Use npm for package management
Rationale:
- Consistency: Matches existing project setup
- Reliability: Stable and well-supported
- Lock File: package-lock.json for reproducible builds
- CI/CD: Easy integration with deployment pipelines
Development Server Configuration
// nuxt.config.ts
export default defineNuxtConfig({
devtools: { enabled: true },
// Development server configuration
devServer: {
port: 3000,
host: '0.0.0.0'
},
// Proxy API calls to Django backend
nitro: {
devProxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true
}
}
},
// Runtime configuration
runtimeConfig: {
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || 'http://localhost:8000/api/v1'
}
}
})
Environment Variables
# .env
NUXT_PUBLIC_API_BASE=http://localhost:8000/api/v1
NUXT_SECRET_JWT_SECRET=your-jwt-secret
NUXT_PUBLIC_APP_NAME=ThrillWiki
NUXT_PUBLIC_APP_VERSION=1.0.0
Performance Optimization Decisions
Code Splitting Strategy
Decision: Implement route-based and component-based code splitting
Implementation:
// Lazy load heavy components
const PhotoGallery = defineAsyncComponent(() => import('~/components/PhotoGallery.vue'))
// Route-based splitting (automatic with Nuxt)
// pages/admin/ - Admin bundle
// pages/parks/ - Parks bundle
// pages/rides/ - Rides bundle
Image Optimization
Decision: Use Nuxt Image module for automatic optimization
Configuration:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/image'],
image: {
provider: 'ipx',
quality: 80,
format: ['webp', 'avif', 'jpg'],
screens: {
xs: 320,
sm: 640,
md: 768,
lg: 1024,
xl: 1280
}
}
})
Caching Strategy
Decision: Multi-layer caching approach
Layers:
- Browser Cache: Static assets with long cache times
- API Cache: Response caching with TTL
- Component Cache: Expensive component computations
- Route Cache: Static route pre-generation
// API caching example
export const useParks = () => {
const { data: parks } = useLazyFetch('/api/v1/parks/', {
key: 'parks-list',
server: true,
default: () => [],
transform: (data: any) => data.results || data
})
return { parks }
}
Security Decisions
Token Storage
Decision: Use HTTP-only cookies for token storage
Rationale:
- XSS Protection: Tokens not accessible via JavaScript
- CSRF Protection: SameSite cookie attribute
- Automatic Handling: Browser handles cookie management
Input Validation
Decision: Client-side validation with server-side verification
Implementation:
// utils/validation.ts
import { z } from 'zod'
export const parkSchema = z.object({
name: z.string().min(1).max(100),
location: z.string().min(1),
operator: z.string().optional(),
status: z.enum(['OPERATING', 'CLOSED', 'UNDER_CONSTRUCTION'])
})
export type ParkInput = z.infer<typeof parkSchema>
CORS Configuration
Decision: Strict CORS policy for production
Django Configuration:
# backend/config/settings/production.py
CORS_ALLOWED_ORIGINS = [
"https://thrillwiki.com",
"https://www.thrillwiki.com"
]
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_ALL_ORIGINS = False # Never true in production
Testing Strategy Decisions
Testing Framework: Vitest
Decision: Use Vitest for unit and component testing
Rationale:
- Vite Integration: Fast test execution
- Vue Support: Excellent Vue component testing
- TypeScript: Native TypeScript support
- Jest Compatible: Familiar API for developers
E2E Testing: Playwright
Decision: Use Playwright for end-to-end testing
Rationale:
- Cross-browser: Chrome, Firefox, Safari support
- Mobile Testing: Mobile browser simulation
- Reliable: Stable test execution
- Modern: Built for modern web applications
Testing Configuration
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
test: {
environment: 'happy-dom',
coverage: {
reporter: ['text', 'json', 'html'],
threshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
}
}
}
})
Deployment Decisions
Build Strategy
Decision: Hybrid rendering with static generation for public pages
Configuration:
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
prerender: {
routes: [
'/',
'/parks',
'/rides',
'/about',
'/privacy',
'/terms'
]
}
},
// Route rules for different rendering strategies
routeRules: {
'/': { prerender: true },
'/parks': { prerender: true },
'/rides': { prerender: true },
'/admin/**': { ssr: false }, // SPA mode for admin
'/auth/**': { ssr: false } // SPA mode for auth
}
})
Docker Configuration
Decision: Multi-stage Docker build for production
Dockerfile:
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# Production stage
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/.output ./
EXPOSE 3000
CMD ["node", "server/index.mjs"]
Context7 Integration Decisions
Documentation Strategy
Decision: Integrate Context7 for automatic documentation generation
Implementation:
// plugins/context7.client.ts
export default defineNuxtPlugin(() => {
if (process.dev) {
// Initialize Context7 connection
const context7 = new Context7Client({
endpoint: 'http://localhost:8080',
project: 'thrillwiki-frontend'
})
// Auto-document API calls
context7.trackApiCalls()
// Document component usage
context7.trackComponentUsage()
}
})
Knowledge Preservation
Decision: Structured documentation with progress tracking
Features:
- Automatic API endpoint documentation
- Component usage tracking
- Implementation decision logging
- Progress milestone tracking
- LLM handoff preparation
🔧 Implementation Priorities
Phase 1: Foundation (Week 1)
- Project Setup: Initialize Nuxt 3 with TypeScript
- Component Library: Integrate chosen UI library
- Authentication: Implement JWT auth system
- API Integration: Set up Django backend communication
- Basic Layout: Create header, footer, navigation
Phase 2: Core Features (Week 2)
- Parks System: Listing, detail, search functionality
- Rides System: Listing, detail, filtering
- User Profiles: Profile management and settings
- Photo System: Upload, display, basic moderation
Phase 3: Advanced Features (Week 3)
- Submission System: Content submission workflow
- Moderation Interface: Admin tools and queues
- Advanced Search: Filters, autocomplete, suggestions
- Maps Integration: Location visualization
Phase 4: Polish & Deployment (Week 4)
- Performance Optimization: Bundle size, loading times
- Testing: Comprehensive test suite
- Documentation: Complete user and developer docs
- Deployment: Production setup and monitoring
🚨 Critical Dependencies
Immediate Blockers
- Component Library Choice: Must be decided before implementation
- Django JWT Setup: Backend enhancement required
- Development Environment: CORS and proxy configuration
Technical Dependencies
- Node.js 18+: Required for Nuxt 3
- Django Backend: Must be running for development
- PostgreSQL: Database must be accessible
- Context7: Integration approach needs clarification
Next Document: component-library-analysis.md - Detailed analysis of chosen library
Status: Ready for component library decision and implementation start