Product architecture case study

SceneIt

I turned several volatile external services into one coherent discovery experience, with explicit boundaries for secrets, caching, personalization, and AI-generated answers.

Role Product architecture and full-stack implementation
Stack Next.js, React, TypeScript, Supabase, TMDB, TanStack Query
Core constraint Useful public discovery without exposing provider credentials
Maturity Working product prototype with a defined hardening path
SceneIt movie recommendation app interface

Engineering brief

SceneIt explores a practical architecture question: how should a product combine public catalog data, authenticated preferences, natural-language discovery, and generative explanations without coupling the UI directly to every provider?

OwnershipArchitecture, interface, integrations, and testing
SurfacesPublic discovery, protected personalization, AI assistant
Quality focusTyped boundaries, cache policy, loading and failure states

System boundary

The browser talks to a stable application API rather than TMDB or Gemini directly. Next.js route handlers keep credentials server-side, allow-list upstream query parameters, normalize errors, and apply a 30-minute revalidation policy. Supabase is isolated behind SSR-aware clients and session middleware.

  1. 01React experienceBrowse, search, filters, favorites, assistant
  2. 02Next.js boundaryValidation, planning, normalization, secret custody
  3. 03TMDB and GeminiCatalog metadata and grounded synthesis
  4. 04SupabaseSessions, interests, and interaction history

Critical decisions

Decision 01 / Integration

Build an anti-corruption layer around TMDB

All catalog calls pass through typed server utilities and application-owned routes. Discover requests forward only known filters, and upstream failures become consistent API responses.

Why it matters: credentials stay private, provider details do not leak across UI components, and the integration can evolve in one place.

Decision 02 / Recommendation quality

Use a deterministic plan before generative output

Natural language is parsed into explicit genres, years, rating, runtime, provider, region, and mood constraints. Results are fetched, enriched, filtered again, and returned with the applied plan visible to the user.

Tradeoff: narrower language coverage than an unconstrained agent, but predictable recommendations that can be debugged and tested.

Decision 03 / AI safety

Ground explanations in retrieved metadata and degrade gracefully

Recap requests first resolve the title and build context from TMDB. Gemini receives that source text with an instruction not to invent missing detail. If the model or key is unavailable, the route returns the source summary.

Why it matters: the useful path survives a model outage, and generated answers have an explicit evidence boundary.

Decision 04 / Product access

Keep discovery public and personalization authenticated

Core browsing and detail routes work without an account. Middleware refreshes sessions and protects profile, favorites, and onboarding surfaces, preserving a low-friction evaluation path.

Why it matters: authentication supports the product instead of becoming a gate in front of its primary value.

Performance reasoning

01

Layered caching

Next.js revalidates TMDB responses every 30 minutes, while TanStack Query deduplicates client requests and manages loading, error, and stale states.

02

Adaptive query cost

Broad discovery reads one result page. Narrow prompts search deeper, then enforce constraints locally. The extra calls are spent only where precision needs them.

03

Concurrent enrichment

Runtime and provider lookups run concurrently where possible, and optional enrichment failures degrade individual results rather than failing the complete response.

Production lens

ConcernCurrent evidenceNext production step
SecretsTMDB and Gemini calls are server-sideSound boundary
ResilienceCache policy, normalized failures, partial enrichment, AI fallbackAdd timeouts and retry budgets
AuthorizationSession middleware protects account pages; interests write verifies identityDerive identity on every interaction API
Data integritySupabase persists preferences and interactionsEnforce RLS, unique constraints, atomic upserts
QualityFocused UI tests cover loading, failure, pagination, and favorite behaviorAdd route contracts and planner tests
OperationsDeployable Next.js applicationAdd telemetry, rate limits, SLOs, and runbooks

I intentionally present SceneIt as a product prototype, not a production system. The senior-level work is visible in the boundaries already chosen and in identifying the controls required before serving real users at scale.

What this demonstrates

  • Containing third-party volatility behind typed, application-owned interfaces.
  • Choosing deterministic, inspectable planning for recommendation correctness and using generation only where it adds value.
  • Reasoning about cache freshness, fan-out cost, graceful degradation, and public versus authenticated product surfaces.
  • Auditing a working prototype honestly and turning gaps into a prioritized production-hardening plan.
Next.js App RouterTypeScriptAPI designSupabase SSR TanStack QueryTMDBGrounded AICache strategy Testing LibraryProduction assessment
Back to Projects Next Case Study: LadyShelf