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

RouteMethodAuthPurpose
/api/recommendGETBearer tokenFetch cached recommendations as TMDB IDs
/api/recommend/quotaGETBearer tokenReturn the authenticated user's remaining daily recommendation quota
/api/auth/signupPOSTNoneValidate signup input, check for an existing email, and create the account server-side
/api/movies/searchGETNoneSearch TMDB movies for the search page
/api/movies/popularGETNoneReturn a cached popular-movies feed from TMDB
/api/movies/:idGETNoneFetch movie details and cache them in movies
/api/watchedGET/POST/DELETEBearer tokenRead/add/remove watched movies
/api/mylistGET/POST/DELETEBearer tokenRead/add/remove My List entries
/api/admin/tmdb-importPOSTx-admin-tokenTrigger 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 recommendations as tmdb_ids
  • Reuses cached recommendations for 7 days if watch history hash is unchanged

Query flags:

  • ?refresh=true forces regeneration
  • ?getNew=true forces regeneration and excludes prior cached recommendations from the next result set

Current Supabase Model

The current implementation relies on four Supabase tables:

  • movies stores the imported TMDB information and cached movie-detail fields
  • user_watched_movies stores one row per (user_id, tmdb_id)
  • user_my_list stores one row per user with tmdb_ids integer[]
  • recommendations stores cached recommendation IDs in tmdb_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/movie
  • movie/popular
  • movie/:id

That helper is used by:

  • GET /api/movies/search
  • GET /api/movies/:id
  • recommendation title-to-ID resolution

Important Server Utilities

  • server/utils/auth/authorize-user.ts - bearer-token validation and current-user resolution
  • server/utils/auth/signup.ts - signup validation, duplicate-email check, and server-side Supabase signup flow
  • server/utils/tmdb/client.ts - TMDB request wrapper with rate limiting and path allow-listing
  • server/utils/recommendations/ai-client.ts - OpenAI-compatible provider wrapper
  • server/utils/recommendations/recommendations.ts - taste-profile prompting, TMDB ID enrichment, and backend validation of AI candidates
  • server/utils/tmdb/search-movies.ts - Supabase title lookup used to map recommendation titles back to TMDB IDs
  • server/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/, and server/utils/recommendations/ may import from shared/.
  • 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

Copyright © 2026