Filmdesk is a Next.js movie discovery dashboard powered by The Movie Database (TMDB). The application UI now lives under the /filmdesk route family and focuses on a dashboard-style discovery workflow, movie search, movie detail pages, actor detail pages, cached catalog APIs, PostgreSQL-backed sync jobs, semantic discovery, and operational endpoints for cache, sync, database, AI, and provider health.
- Use a Filmdesk dashboard for trend scanning and curated discovery sections.
- Search movies through the Filmdesk search page and catalog API routes.
- View movie detail pages with posters, summaries, genres, ratings, similar titles, and recommendations.
- Explore actor detail pages from movie credits.
- Cache TMDB/catalog requests with Redis, Upstash Redis, or in-memory fallback.
- Sync TMDB catalog data into PostgreSQL with BullMQ background workers.
- Run semantic movie discovery with ChromaDB and a local hashing embedding provider.
- Inspect operational metrics for cache, database, sync jobs, AI discovery, latency, reliability, and estimated provider cost.
- Next.js 15 and React 18
- TypeScript and JavaScript
- Tailwind CSS, CSS Modules, and Material UI
- Prisma 7 and PostgreSQL
- Redis, Upstash Redis, and BullMQ
- ChromaDB for semantic search storage
- TMDB API as the movie data provider
- Docker Compose and Vercel deployment support
The UI is intentionally scoped to Filmdesk routes:
/filmdesk/filmdesk/search/filmdesk/movie/[id]/filmdesk/actor/[id]
Legacy public pages such as /, /search, /movie/[id], /actors/[id], and /category/[slug] are not part of the active app surface.
| Filmdesk Dashboard | Full Page Dashboard |
|---|---|
![]() |
![]() |
| Search Initial | Search Results |
|---|---|
![]() |
![]() |
| Initial State | Full Page | Reveal States |
|---|---|---|
![]() |
![]() |
![]() |
| Search Header State |
|---|
![]() |
- Node.js 20 or newer
- npm
- A TMDB v4 read access token
- PostgreSQL and Redis for the full local stack
- Docker, if you prefer running the full stack through Compose
git clone https://github.com/mussarri/next-movie-app.git
cd next-movie-app
npm install
cp .env.example .envEdit .env and set at least TMDB_API_TOKEN.
For a full local database-backed setup, start PostgreSQL and Redis, then generate the Prisma client and push the schema:
npm run prisma:generate
npm run db:push
npm run devThe app runs at http://localhost:3000/filmdesk.
The project ships with .env.example.
TMDB_API_TOKEN=your_tmdb_v4_read_access_token
DATABASE_URL=postgres://movie_app:movie_app@localhost:5432/movie_app
REDIS_URL=redis://localhost:6379
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
CRON_SECRET=
OPERATIONS_SECRET=
CATALOG_SYNC_CONCURRENCY=2
CATALOG_SYNC_RATE_LIMIT_MAX=35
CATALOG_SYNC_RATE_LIMIT_WINDOW_MS=10000
CHROMA_URL=http://localhost:8000
CHROMA_COLLECTION=movie_semantic_discovery
SEMANTIC_EMBEDDING_PROVIDER=local-hash
SEMANTIC_EMBEDDING_MODEL=hashing-v1
SEMANTIC_VECTOR_SIZE=384
SEMANTIC_INDEX_BATCH_SIZE=100
TMDB_ESTIMATED_COST_PER_CALL_USD=0
PROVIDER_DAILY_BUDGET_USD=10
AI_DAILY_BUDGET_USD=5Notes:
TMDB_API_TOKENis required for TMDB-backed catalog features.DATABASE_URLenables PostgreSQL catalog persistence and operational metrics.REDIS_URLenables BullMQ workers and Redis cache.UPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKENcan be used in hosted environments without a Redis TCP connection.CRON_SECRETprotects cron endpoints when set.OPERATIONS_SECRETprotects mutating or sensitive operations endpoints when set.CHROMA_URLenables Chroma-backed semantic discovery. If ChromaDB is unavailable, AI discovery falls back to PostgreSQL scoring.
npm run dev # Start the Next.js development server
npm run build # Build the production app
npm run start # Start the production server
npm run lint # Run ESLint
npm run prisma:generate # Generate Prisma client
npm run prisma:validate # Validate Prisma schema
npm run db:push # Push Prisma schema to the database
npm run db:studio # Open Prisma Studio
npm run sync:enqueue # Enqueue default catalog sync jobs
npm run worker:catalog # Process catalog sync jobs
npm run worker:semantic # Build semantic search documents and index themRun the app, PostgreSQL, Redis, ChromaDB, and the catalog worker:
docker compose up -d --buildThe app runs at http://localhost:3000/filmdesk.
Useful Docker scripts:
npm run docker:up
npm run docker:ps
npm run docker:logs
npm run docker:downStart the optional semantic worker profile:
npm run docker:aiCatalog sync uses BullMQ and Redis:
npm run sync:enqueue
npm run worker:catalogSemantic indexing reads movies from PostgreSQL and writes discovery documents to ChromaDB:
npm run worker:semanticIn Docker Compose, the worker service starts automatically. The semantic-worker service is available through the ai profile.
Catalog and discovery endpoints:
GET /api/catalog/discoverGET /api/catalog/trendingGET /api/catalog/genresGET /api/catalog/movie-list/[list]GET /api/catalog/movies/[id]GET /api/catalog/movies/[id]/recommendationsGET /api/catalog/movies/[id]/similarGET /api/searchPOST /api/ai/discover
Operations and cron endpoints:
GET /api/ops/cachereturns cache hit, miss, and write metrics.DELETE /api/ops/cacheresets cache metrics. SetOPERATIONS_SECRETto protect this endpoint.GET /api/ops/databasereturns PostgreSQL catalog health and row counts.GET /api/ops/syncreturns BullMQ sync queue metrics.GET /api/ops/aireturns AI discovery index and Chroma health.GET /api/ops/observabilityreturns API latency, provider cost, reliability, and alert metrics.GET /api/cron/warm-cachewarms popular catalog entries. SetCRON_SECRETto requireAuthorization: Bearer <secret>.GET /api/cron/enqueue-syncenqueues default catalog sync jobs. BullMQ requiresREDIS_URL.
When DATABASE_URL is configured, the app records 24-hour operational metrics into PostgreSQL:
- API request count, status code, and p50/p95/p99 latency by route.
- TMDB provider call count, latency, error rate, and estimated cost.
- Cache hit rate from Redis, Upstash Redis, or memory metrics.
- Sync job depth and worker duration from
sync_jobs. - AI discovery latency and zero-result rate.
Use TMDB_ESTIMATED_COST_PER_CALL_USD, PROVIDER_DAILY_BUDGET_USD, and AI_DAILY_BUDGET_USD to tune budget alerts returned by /api/ops/observability.
Vercel is configured through vercel.json.
Set the same environment variables in Vercel Project Settings before deploying. Vercel Cron is configured to call:
/api/cron/warm-cacheevery 15 minutes/api/cron/enqueue-synchourly
This project is private unless a license is added.







