Rahul.
All projects
01 / CinePulseProduction

Movie discovery & watchlist platform

React 19Express 5PostgreSQLPrisma 7JWT AuthZod

A full-stack platform where users discover films, manage personal watchlists across four states, rate with stars, and analyse their viewing habits — a React SPA over a Node.js REST API with PostgreSQL persistence.

01

Problem statement

Personal film tracking tends to scatter across notes, spreadsheets, and streaming apps: what you want to watch, what you're watching, and what you've finished all live in different places — and nobody keeps the stats. CinePulse collapses that into one system with an explicit watchlist state model and an analytics view that makes the data useful.

02

My role

Sole engineer — designed the data model, built the REST API and authentication, implemented the React frontend, and owns deployment and schema migrations end to end.

03

System architecture

React 19 SPAUI · state management · API integrationHTTPS / REST API (JSON, cookie credentials)Node.js + Express 5Authentication · business logic · Zod validationType-safe Prisma clientPrisma ORMSchema · migrations · type-safe queriesSQLPostgreSQLRelational data · full-text search · aggregation

Illustrative architecture of the deployed system.

04

Technology decisions

PostgreSQL + Prisma over a document database
Users, films, list entries, and ratings are related data with real integrity requirements — one user rates one film once. A normalised relational schema with migrations keeps that consistent, and Prisma gives typed queries plus a versioned schema history.
JWT in httpOnly cookies, not localStorage
Tokens in localStorage are readable by any injected script. Storing the JWT in an httpOnly cookie with SameSite restrictions keeps XSS from exfiltrating credentials while the API stays stateless.
Zod at the API boundary
Every write endpoint validates its payload with Zod, so malformed input dies at the edge and the client/server contract stays explicit — the same shapes drive form validation in the UI.
React SPA over a plain REST API
The frontend is a fast Vite-served SPA; the API is a conventional REST surface. The separation keeps the backend portable and lets the client ship UI iterations without touching server code.
05

Challenges & solutions

Four-state watchlist semantics
Planned → watching → completed, plus dropped, is a small state machine rather than a boolean. Transitions are guarded server-side so invalid jumps (e.g. dropped → completed directly) can't corrupt analytics.
Search that matches how people look for films
Full-text search over titles combined with structured filters (genre, rating, watch state) in a single query path — ranked text results, filtered by the same facets, without loading the catalogue client-side.
Analytics from raw watch history
Completion rates, state distributions, and rating trends are SQL aggregates over the normalised tables, served as one dashboard payload so the client renders a single request instead of N.
Cross-origin cookie authentication
Cookies don't travel cross-origin by default — the fetch client sends credentials explicitly, and the API responds with the right SameSite/CORS headers so the SPA stays authenticated across requests.
06

What I'd improve next

  • Cache catalogue responses and invalidate on demand
  • Unit and E2E test coverage for the watchlist state machine
  • Infinite scroll and prefetching for search results
  • Rate limiting and abuse protection on write endpoints
  • Offline-friendly PWA shell for the watchlist
07

Links

Source code will be linked here once the repository is public.