Watchly is a React 19 + TypeScript app for exploring movies, TV series, people, and collections using TMDB data, with supplemental ratings pulled from OMDb.
The app centers on filter-heavy discovery flows, infinite lists, detailed title and person pages, and fast client-side navigation powered by TanStack Router and React Query.
- Movie discovery with a dedicated sidebar for release date, rating, vote count, runtime, sort order, genres, release types, keywords, studios, original language, watch providers, and adult-content filtering.
- Series discovery with a dedicated sidebar for first air date, rating, vote count, sort order, genres, status, TV show types, keywords, studios, networks, original language, watch providers, and adult-content filtering.
- Global search across movies, TV series, and people, with merged results sorted by popularity.
- Popular people browser with infinite scrolling.
- Movie detail pages with cast, crew, recommendations, similar titles, release dates, keywords, studios, runtime, and collection links when present.
- Series detail pages with cast, crew, recommendations, similar titles, content ratings, external IDs, and season/episode exploration.
- Person pages with biography, deduplicated cast appearances, and crew credits.
- Collection pages with collection metadata and sorted movie entries.
- Light, dark, and system theme support persisted in local storage.
- Responsive navigation with desktop tabs and a mobile accordion menu.
- React 19
- TypeScript in strict mode
- Vite 8 for dev and bundling
tsgofor type-checking during builds- TanStack React Router with generated route tree
- TanStack React Query for data loading and caching
@better-fetch/fetchwith Valibot schemas for API validation- Tailwind CSS v4 with Base UI-based primitives in
src/components/ui lucide-reacticons
- Routes live in
src/routesand generatesrc/routeTree.gen.ts. - The root route redirects
/to/movies. - Search and discovery data access is centralized in
src/query-options.ts. - TanStack server functions live in
src/lib/api.functions.ts, and the server-only TMDB and OMDb clients live insrc/lib/api.server.ts. - API response validation lives in
src/schemas.ts. - Default discovery state and lookup maps live in
src/lib/constants.ts. - Shared presentational primitives live in
src/components/ui.
- Discovery and people pages use
infiniteQueryOptions(). - Detail pages use
queryOptions(). - Several infinite queries fetch three pages at a time and deduplicate results by ID before rendering.
- Router and query defaults treat fetched data as fresh with
staleTime: Number.POSITIVE_INFINITY. - Card links use intent-based preloading with
preloadDelay={500}.
- Node.js
24or newer
bun installCreate an ignored .env.local with the variables defined in .env.schema:
TMDB_API_KEY=your-tmdb-api-key
OMDB_API_KEY=your-omdb-api-keyVarlock validates these values and injects them into the Cloudflare development runtime. Then run:
bun run devThe app runs at http://localhost:5173 by default.
bun run devstarts the Vite development server.bun run buildrunstsc --buildand then creates the production Vite bundle.bun run build:analyzebuilds with bundle analysis enabled outside Vercel.bun run previewserves the production build locally.bun run env:auditchecks environment-variable usage against.env.schema.bun run env:scanscans tracked files for leaked sensitive values.bun run lintrunsoxlint.bun run lint:fixrunsoxlint --fix.bun run formatrunsoxfmt.bun run knipchecks for unused files and exports.
- Keep route files under
src/routes; the TanStack router plugin regenerates the route tree. - Update
src/query-options.tswhen adding new fetching flows. - Validate any new or changed external API payloads in
src/schemas.ts. - Use helpers from
src/lib/utils.tsand shared constants fromsrc/lib/constants.ts. - Theme preference is stored under the
watchly-ui-themelocal storage key. - The root layout mounts TanStack Query and Router devtools panels.
- TMDB is the primary data source for movies, TV, people, providers, and collections.
- OMDb is used for supplemental IMDb and Rotten Tomatoes ratings when an IMDb ID is available.
- Varlock manages and validates the API credentials declared in
.env.schema. Values remain in the ignored.env.local, are accessed through typedENVvalues by TanStack Start server functions, and are never included in client-side requests. - Cloudflare deployments use
varlock-wrangler, which uploads sensitive values as Cloudflare secrets. - The app has no authentication, no user accounts, and no user-generated content.
No license file is currently defined in this repository.