Project 14 of ~34

🍿 Streaming Stack β€” Architecture

Personalized cross-platform streaming recommendation service. SvelteKit dashboard + Deno backend + Supabase + Ollama (Mac Mini) for recommendation engine.

SvelteKit Deno Supabase Content API

πŸ—οΈ Architecture Overview

Streaming Stack has three core systems: (1) a content metadata database with cross-platform availability, (2) a recommendation engine matching mood/context to titles, and (3) a watchlist + expiration alert system. The Mac Mini handles nightly data refreshes and the recommendation AI pipeline.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ USER INTERFACE β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Web App β”‚ β”‚ Telegram β”‚ β”‚ Email β”‚ β”‚ β”‚ β”‚ (SvelteKit) β”‚ β”‚ Bot β”‚ β”‚ (Resend) β”‚ β”‚ β”‚ β”‚ Dashboard β”‚ β”‚ Chat UI β”‚ β”‚ Digests β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β–Ό β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ APPLICATION LAYER (Deno) β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Rec Engine β”‚ β”‚ Watchlist β”‚ β”‚ Expiration β”‚ β”‚ β”‚ β”‚ Service β”‚ β”‚ Service β”‚ β”‚ Alert Service β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Content β”‚ β”‚ User Prefs β”‚ β”‚ Analytics β”‚ β”‚ β”‚ β”‚ Sync β”‚ β”‚ Service β”‚ β”‚ Service β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DATA SOURCES β”‚ β”‚ DATA STORES β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ JustWatch API β”‚ │◄────│ β”‚ Supabase (Postgres)β”‚ β”‚ β”‚ β”‚ (availability β”‚ β”‚ β”‚ β”‚ Titles, watchlists, β”‚ β”‚ β”‚ β”‚ + metadata) β”‚ β”‚ β”‚ β”‚ users, alerts β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ TMDB API β”‚ β”‚ β”‚ β”‚ Upstash Redis β”‚ β”‚ β”‚ β”‚ (metadata) β”‚ β”‚ β”‚ β”‚ Session cache, β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ recommendation β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ pre-compute cache β”‚ β”‚ β”‚ β”‚ JustWatch β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ Expired API β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ AI RUNTIME β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Ollama (Mac Mini)β”‚ β”‚ β”‚ β”‚ Mistral 7B β”‚ β”‚ β”‚ β”‚ "Why you'll β”‚ β”‚ β”‚ β”‚ love this" β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚

πŸ› οΈ Tech Stack

Frontend

ComponentTechnologyWhy
Web AppSvelteKitDashboard, recommendation interface, watchlist management. SSR for SEO of recommendation pages.
MobileTelegram Mini AppRich chat-based UI inside Telegram β€” primary mobile interface for many users.
Telegram BotDeno Telegram Bot APIText-based interaction for quick recommendations. "I'm in the mood for X, 90 minutes, solo."

Backend

ComponentTechnologyWhy
RuntimeDeno 2Runs recommendation pipeline and nightly sync on Mac Mini.
DatabaseSupabase (PostgreSQL)Content metadata, user watchlists, alert preferences, viewing analytics.
CacheUpstash RedisRecommendation results cached per user (recompute daily). Session data.
EmailResendWeekly "leaving soon" digest, expiration alerts, monthly viewing report.
SchedulingUpstash QStashNightly content sync (2am), weekly "leaving soon" digest (Sunday 10am), expiration checks every 6 hours.

Content Data

SourceWhat It ProvidesCost
JustWatch APICross-platform availability, pricing, launch datesUsage-based (~$50/mo for 10K queries)
TMDb (The Movie Database)Genre, cast, crew, ratings, keywords, synopsesFree (API key required)
Trakt.tv APIUser watchlists, ratings, viewing history (if user connects)Free
OTT Data (justwatch.com scraper)Content expiration dates (scraped nightly)Build in-house

AI Stack

πŸ€– AI Philosophy: Local for Explanations, Cloud for Scale
  • "Why you'll love this": Ollama Mistral 7B on Mac Mini generates personalized "why" explanations for each recommendation. Free, fast, good enough.
  • Recommendation matching: Hybrid approach: rule-based filtering (genre + mood + duration + platform) first, then Ollama re-ranks with "why" explanations. Avoids cold-start problem of pure ML.
  • Weekly email curation: Human-vetted精选 for top titles (reduces algorithmic churn feel). AI drafts descriptions; human reviews.

πŸ—„οΈ Data Model

titles
iduuidPrimary key
tmdb_idintegerTheMovieDB reference ID
imdb_idvarchar(20)IMDb reference ID
titlevarchar(500)
typeenum('movie','series')
yearinteger
runtime_minutesinteger
genresvarchar[]e.g., {drama, thriller}
moodsvarchar[]e.g., {thoughtful, tense, fun}
moodsvarchar[]e.g., {thoughtful, tense, fun}
critics_scoreintegerRotten Tomatoes
audience_scoreintegerIMDb / user rating
short_synopsisvarchar(500)One-line description
long_synopsistextFull description
key_keywordstext[]For search/matching
platform_availability
title_iduuid (FK)Ref titles
platformenum('netflix','hbo_max','disney_plus','hulu','amazon_prime','apple_tv_plus','peacock','paramount_plus','crunchyroll','max','other')
availability_typeenum('subscription','rent','buy','free')
price_centsinteger (for rent/buy)
expires_attimestamp (nullable)NULL = no expiration known
last_checked_attimestamp
users
iduuid
emailvarchar(255)
telegram_chat_idvarchar(50)For alerts
subscribed_platformsenum[]Which services they have
profile_prefs_jsonjsonb{mood_preferences, avoid_genres, group_watch_style}
tierenum('free','pro','household')
last_recommendation_attimestamp
watchlists
iduuid
user_iduuid (FK)
title_iduuid (FK)
added_attimestamp
watchedboolean
watched_attimestamp
platform_to_watchenumPreferred platform at time of adding
notestextPersonal note
recommendation_log
iduuid
user_iduuid (FK)
moodvarchar(50)
time_available_mininteger
group_sizeinteger
results_jsonjsonbTop 5 recommendations with scores
clicked_title_iduuid (FK, nullable)Which one they clicked
created_attimestamp

πŸ”Œ API Design

Recommendations

POST /api/recommend
Get recommendations. Body: {mood, time_min, group_size, subscribed_platforms[], exclude_titles[]?, watch_history[]?}. Returns top 5 ranked titles with "why" explanations. Rate limited: 10/min for free, unlimited for Pro.
GET /api/recommend/leaving-soon
Get top 20 titles on user's platforms expiring in next 7 days.

Watchlist

GET /api/watchlist
Get user's watchlist with platform availability and expiration warnings.
POST /api/watchlist
Add title to watchlist. Body: {title_id, platform_preference?}.
DELETE /api/watchlist/:titleId
Remove from watchlist.
PATCH /api/watchlist/:titleId/watched
Mark as watched.

Search

GET /api/search?q=&platform=&genre=&page=
Search titles with filters. Returns: title, year, platform(s), runtime, mood tags.

User Profile

GET /api/me/platforms
Get/set subscribed platforms (for filtering recommendations).
PATCH /api/me/preferences
Update mood preferences, avoid genres, notification settings.
GET /api/me/report
Get monthly viewing analytics report (Pro).

Webhooks (Internal)

POST /webhooks/justwatch
Receives JustWatch availability/expiration updates. Updates platform_availability table.

πŸ€– Recommendation AI Pipeline

Step 1: Filter by Constraints
User's mood + time + group size + subscribed platforms β†’ hard filter on titles table. Remove: titles not on their platforms, too long/short, wrong genre mood. Returns candidate set of ~20-50 titles.
Step 2: Rank by Relevance
Score remaining candidates by: watchlist affinity (similar to what user already added), viewing history patterns, critics score, recency, "leaving soon" bonus (if applicable). Ranks top 10.
Step 3: "Why You'll Love This" (Ollama)
For each of top 5 recommendations, Ollama Mistral 7B generates a personalized one-line "why" based on user's watch history and stated mood. Example: "Since you loved Breaking Bad's tension and Darryl's character arc, you'll appreciate this thriller's moral complexity." Cached in Redis for 24hrs.
Step 4: Binge Schedule (Pro)
For series recommendations, Ollama calculates: total runtime, episodes per day to finish in user's target timeframe, flags filler episodes to skip (from community data via Trakt).
Nightly: Content Sync (QStash)
2am nightly: sync with JustWatch API for availability changes. Update expiration dates. Flag newly expired content. This keeps watchlist availability signals fresh.
Weekly: "Leaving Soon" Digest (Resend)
Sunday 10am: for each user, find watchlist titles expiring in next 7 days. Send email/Telegram alert. Include "3 things we think you'd love that are leaving too."

πŸš€ Deployment

ComponentWhereNotes
DashboardCloudflare Pages (free)Auto-deploy, global CDN
Backend APIDeno Deploy or Mac MiniDeno Deploy for production; Mac Mini for nightly jobs
DatabaseSupabase (free tier: 500MB)Sufficient for <50K titles + 10K users.
RedisUpstash (free tier: 10K commands/day)Caching recommendations, sessions
Nightly SyncMac Mini + QStash cronRuns on home server 24/7
AI (local)Mac Mini OllamaMistral 7B β€” "why you'll love this" generation
EmailResend (free: 3K/month)Weekly digest, alerts
Content DataJustWatch API + TMDb~$50/mo for JustWatch

← Requirements  |  All Projects  |  Presentation β†’