Getting Started
Backend Server
Overview of the current Nuxt server architecture, API routes, and Supabase data model
The app/server/ folder contains the Nuxt server-side logic for Supabase-backed user state, recommendation generation, TMDB-backed movie lookup, and TMDB import handling.
Architecture Overview
The server is organized around the API layer:
app/server/
├── api/
│ ├── recommend.get.ts
│ ├── watched/
│ ├── mylist/
│ ├── movies/
│ └── admin/
└── utils/
API Routes
| Route | Method | Auth | Purpose |
|---|---|---|---|
/api/recommend | GET | Bearer token | Fetch cached recommendations as TMDB IDs |
/api/recommend/quota | GET | Bearer token | Return the authenticated user's remaining daily recommendation quota |
/api/auth/signup | POST | None | Validate signup input, check for an existing email, and create the account server-side |
/api/movies/search | GET | None | Search TMDB movies for the search page |
/api/movies/popular | GET | None | Return a cached popular-movies feed from TMDB |
/api/movies/:id | GET | None | Fetch movie details and cache them in movies |
/api/watched | GET/POST/DELETE | Bearer token | Read/add/remove watched movies |
/api/mylist | GET/POST/DELETE | Bearer token | Read/add/remove My List entries |
/api/admin/tmdb-import | POST | x-admin-token | Trigger the TMDB import manually or from GitHub Actions |
Protected routes require valid
Authorization: Bearer <token> headers before any user-specific data operation.Recommendation Flow (GET /api/recommend)
Key behavior:
- Requires Bearer auth
- Reads watched history from Supabase
- Reads My List from Supabase
- Builds a compact taste profile from watched movies and My List
- Calls the AI client when regeneration is needed
- Validates AI candidates against watched movies, previous recommendations, TMDB resolution, and My List limits
- Stores valid recommendations in Supabase table
recommendationsastmdb_ids - Reuses cached recommendations for 7 days if watch history hash is unchanged
Query flags:
?refresh=trueforces regeneration?getNew=trueforces regeneration and excludes prior cached recommendations from the next result set
Current Supabase Model
The current implementation relies on four Supabase tables:
moviesstores the imported TMDB information and cached movie-detail fieldsuser_watched_moviesstores one row per(user_id, tmdb_id)user_my_liststores one row per user withtmdb_ids integer[]recommendationsstores cached recommendation IDs intmdb_ids
My List writes are atomic through RPC functions:
append_my_list(target_tmdb_id integer)remove_my_list(target_tmdb_id integer)
Signup also depends on a private RPC helper:
auth_email_exists(target_email text)
TMDB Access
TMDB requests are performed internally through server/utils/tmdb/client.ts, which currently allows only:
search/moviemovie/popularmovie/:id
That helper is used by:
GET /api/movies/searchGET /api/movies/:id- recommendation title-to-ID resolution
Important Server Utilities
server/utils/auth/authorize-user.ts- bearer-token validation and current-user resolutionserver/utils/auth/signup.ts- signup validation, duplicate-email check, and server-side Supabase signup flowserver/utils/tmdb/client.ts- TMDB request wrapper with rate limiting and path allow-listingserver/utils/recommendations/ai-client.ts- OpenAI-compatible provider wrapperserver/utils/recommendations/recommendations.ts- taste-profile prompting, TMDB ID enrichment, and backend validation of AI candidatesserver/utils/tmdb/search-movies.ts- Supabase title lookup used to map recommendation titles back to TMDB IDsserver/utils/tmdb/import-runner.ts- import job runner for TMDB exports
Utility Dependency Map
server/utils/shared/owns API error handling, Redis, and Supabase client factories. It must not import domain utilities.server/utils/auth/,server/utils/tmdb/, andserver/utils/recommendations/may import fromshared/.server/utils/recommendations/may import TMDB helpers for movie lookup and title-to-ID resolution.- API routes compose utilities from the domain folders and should not depend on old top-level utility paths.
Environment Variables
Required environment variables for the server:
NUXT_TMDB_API_KEY=your_key_here
NUXT_GOOGLE_API_KEY=your_google_ai_studio_key
NUXT_GOOGLE_MODELS=gemini-flash-lite-latest,gemini-2.5-flash-lite,gemini-2.0-flash-lite
NUXT_OPENROUTER_API_KEY=your_openrouter_api_key
NUXT_OPENROUTER_MODELS=google/gemini-2.5-flash-lite
NUXT_PUBLIC_SUPABASE_URL=your_supabase_url
NUXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
NUXT_SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
NUXT_PUBLIC_HCAPTCHA_SITE_KEY=your_hcaptcha_site_key
NUXT_HCAPTCHA_SECRET=your_hcaptcha_secret
ADMIN_API_TOKEN=your_admin_token
UPSTASH_REDIS_REST_URL=your_upstash_redis_url
UPSTASH_REDIS_REST_TOKEN=your_upstash_redis_token
Next Steps
- See API Overview for endpoint-by-endpoint request and response details
- See Project Structure for full layout