An open API service indexing awesome lists of open source software.

https://github.com/ponderrr/smart-advisor

AI-powered movie & book recommendations tailored to who you actually are — built with Claude, Supabase, and React.
https://github.com/ponderrr/smart-advisor

ai-recommendations anthropic book-recommendation-system claude-ai deno edge-functions movie-recommendation-app react row-level-security supabase tailwindcss tmdb typescript vercel vite

Last synced: 30 days ago
JSON representation

AI-powered movie & book recommendations tailored to who you actually are — built with Claude, Supabase, and React.

Awesome Lists containing this project

README

          



Smart Advisor

AI-powered movie & book recommendations tailored to who you actually are.

![License](https://img.shields.io/badge/license-MIT-blue.svg)
![Next.js](https://img.shields.io/badge/next.js-16-000000?logo=next.js&logoColor=white)
![TypeScript](https://img.shields.io/badge/typescript-strict-3178C6?logo=typescript&logoColor=white)
![Supabase](https://img.shields.io/badge/supabase-postgres%20%2B%20edge%20functions-3ECF8E?logo=supabase&logoColor=white)
![Claude](https://img.shields.io/badge/claude-sonnet%204-D97757?logo=anthropic&logoColor=white)
![Vercel](https://img.shields.io/badge/vercel-deployed-000000?logo=vercel&logoColor=white)
![Tests](https://img.shields.io/badge/tests-vitest-6E9F18?logo=vitest&logoColor=white)

[Live Demo](https://smartadvisor.live) · [Setup Guide](docs/SETUP.md) · [Auth Docs](docs/AUTHENTICATION.md) · [Report Bug](https://github.com/ponderrr/smart-advisor/issues)

Smart Advisor screenshot

## What It Is

Smart Advisor is a full-stack recommendation engine that builds a taste profile through a personality quiz — then uses Claude to generate one deeply-explained movie and one book pick that actually fit you. It is not a ranked list or a collaborative filter; every recommendation comes with a written explanation of why it matches your specific answers. The system uses different AI personas for users under 18 (warm, encouraging, PG-safe) and adults (direct, opinionated, willing to recommend dark and complex content).

## How It Works

1. **Sign up** — email + password or Google OAuth, with optional two-factor authentication (TOTP)
2. **Choose content** — movies, books, or both
3. **Pick quiz length** — 3 to 15 questions
4. **Take the quiz** — Claude generates personality-driven questions tailored to your age (scenario-based, preference comparisons, emotional responses)
5. **Get your pick** — Claude reads your full answer profile and returns one movie and/or one book with a personalized explanation, enriched with real posters and metadata from TMDB and Open Library
6. **Save and revisit** — every recommendation is persisted to your account with favorites and history
7. **Log what you watch/read** — drop a finished pick into your library with a thumbs rating and a one-line reaction; future quizzes use it as a taste signal so the AI learns what actually landed

New users can also **try a demo quiz** without signing up — a 5-question survey that generates real-time recommendations from TMDB and Open Library.

```
┌─────────────────────────────────────────────────────────────┐
│ Browser (Next.js App Router) │
│ Auth → Quiz → Questions → Answers → Results → History │
└──────────────────┬──────────────────────┬───────────────────┘
│ PKCE / JWT │ JWT
▼ ▼
┌─────────────────┐ ┌──────────────────────┐
│ Supabase Auth │ │ Supabase Edge Fns │
│ (PKCE + MFA) │ │ │
└────────┬────────┘ │ anthropic-questions │
│ │ anthropic-recs │
▼ │ tmdb-proxy │
┌─────────────────┐ └──────┬──────────┬────┘
│Supabase Postgres│ │ │
│ │ ▼ ▼
│ profiles │ ┌────────────┐ ┌────────────┐
│ recommendations│ │ Anthropic │ │ TMDB / │
│ sessions │ │ Claude API │ │ Open │
│ mfa_factors │ └────────────┘ │ Library │
│ backup_codes │ └────────────┘
│ (RLS enforced) │
└─────────────────┘
```

## Feature Highlights

| Feature | Detail |
|---------|--------|
| **Age-gated AI personas** | Under-18 gets warm, encouraging picks. 18+ gets unfiltered recommendations including mature themes. |
| **Single sharp recommendation** | One movie. One book. Deeply explained. Not a ranked list. |
| **Real cover art** | TMDB and Open Library APIs fetch actual posters and covers. |
| **Two-factor authentication** | TOTP-based MFA with backup codes and backup email recovery. |
| **Device & session management** | View active sessions across devices, revoke individually or globally. |
| **Avatar uploads** | Drag-and-drop avatar with client-side crop, stored in Supabase Storage with RLS-scoped access. |
| **Demo quiz** | Try the recommendation flow without an account — rate-limited per IP via `demo_quota`. |
| **Full auth with PKCE** | Supabase Auth with email confirmation, Google OAuth, and PKCE flow. |
| **MFA-gated sensitive changes** | Profile, email, password, and account changes require MFA verification. |
| **Zero exposed secrets** | All API keys live in Supabase Edge Function secrets, never the frontend. |
| **Row Level Security** | Every DB query is scoped to the authenticated user at the Postgres level. |
| **Recommendation history** | All picks saved to account with favorites and filters. |
| **Personal library** | Log titles as Finished / In progress / Wishlist with a thumbs rating and one-line reaction. Reactions feed back into the recommendation prompt as a taste signal. |
| **Hardened frontend** | CSP + strict security headers, Zod-validated inputs, typed env parsing, global error boundary. |
| **Tested + CI-gated** | Vitest unit tests run in CI alongside `tsc --noEmit` and ESLint on every push. |

## Tech Stack

| Layer | Technology | Why |
|-------|-----------|-----|
| Frontend | Next.js 16 + React 18 + TypeScript (strict) | App Router, SSR-ready auth, file-based routing |
| Styling | Tailwind CSS + Radix UI + shadcn/ui | Utility-first CSS, accessible primitives, dark mode via `next-themes` |
| Animation | Motion (Framer) | Scroll-linked hero + bento grid transitions |
| State | Zustand + TanStack Query | Lightweight quiz store; cached server state for recs/history |
| Forms & validation | React Hook Form + Zod | Typed schemas shared between form and edge-function payloads |
| Auth | Supabase Auth (PKCE + MFA) | Email/password, Google OAuth, TOTP two-factor |
| Database | Supabase Postgres | RLS enforced at DB level, not app level |
| Storage | Supabase Storage | Avatar uploads scoped by RLS |
| Edge Functions | Supabase Deno runtime | Server-side secrets, low latency, JWT verification |
| AI | Anthropic Claude Sonnet 4 | Nuanced reasoning for taste-based recommendations |
| Movie data | TMDB API | Industry-standard movie metadata and poster images |
| Book data | Open Library API | Cover art and metadata for millions of titles (no API key) |
| Testing | Vitest + Testing Library + jsdom | Unit and component tests, run in CI |
| Analytics | Vercel Analytics + Speed Insights | Real-user web vitals and traffic, no third-party cookies |
| Hosting | Vercel | Zero-config Next.js deploys with automatic routing |

## Project Structure

```
smart-advisor/
├── src/app/ # Next.js App Router pages
│ ├── layout.tsx # Root layout with metadata
│ ├── providers.tsx # Client providers (Auth, Toaster)
│ ├── globals.css # Global styles (Tailwind + custom)
│ ├── page.tsx # Landing page (/)
│ ├── error.tsx # App-level error boundary
│ ├── loading.tsx # App-level loading skeleton
│ ├── not-found.tsx # 404 page
│ ├── auth/
│ │ ├── page.tsx # Sign up / sign in / MFA challenge (/auth)
│ │ ├── reset-password/page.tsx # Password reset flow
│ │ └── callback/route.ts # OAuth + email verification handler
│ ├── demo/
│ │ ├── page.tsx # Unauthenticated demo quiz (/demo)
│ │ └── results/page.tsx # Demo recommendation results
│ ├── settings/page.tsx # Account settings (profile, security, content, integrations)
│ ├── account/
│ │ ├── security/page.tsx # Security settings
│ │ └── mfa-setup/page.tsx # MFA enrollment page
│ ├── content-selection/page.tsx # Movie, book, or both
│ ├── question-count/page.tsx # 3–15 questions
│ ├── questionnaire/page.tsx # Dynamic AI-generated quiz
│ ├── results/page.tsx # AI recommendation display + favorites
│ ├── dashboard/page.tsx # User dashboard
│ ├── history/page.tsx # Saved picks and favorites
│ ├── library/page.tsx # Watched/read log with status, rating, reaction
│ └── api/
│ ├── open-library/route.ts # Open Library search proxy
│ ├── hero-media/route.ts # Hero section media fetcher
│ ├── demo-media/route.ts # Demo quiz media API (Open Library + TMDB)
│ ├── demo-books/route.ts # Demo quiz books API (Open Library)
│ └── account/ # Account disable/delete endpoints

├── src/features/
│ ├── auth/
│ │ ├── components/ # AuthForm, MfaSetup, MfaManagement, SessionsManagement
│ │ ├── hooks/use-auth.tsx # Auth context with MFA, backup codes, backup email
│ │ ├── services/
│ │ │ ├── auth-service.ts # Auth, MFA, backup codes, backup email logic
│ │ │ └── session-management.ts # Device session tracking with deduplication
│ │ ├── types/user.ts # User type definition
│ │ └── utils/ # Validation, device parsing
│ ├── quiz/
│ │ ├── store/quiz-store.ts # Zustand store for quiz flow state
│ │ ├── types/ # Question, Answer interfaces
│ │ └── utils/ # Fallback questions
│ ├── recommendations/
│ │ └── services/
│ │ ├── ai-service.ts # Calls anthropic-questions + anthropic-recommendations
│ │ ├── enhanced-recommendations-service.ts # Retry logic, TMDB/Open Library enrichment
│ │ ├── tmdb-service.ts # TMDB proxy client
│ │ ├── open-library-service.ts # Open Library client (replaces Google Books)
│ │ └── database-service.ts # Recommendation CRUD + favorites
│ ├── library/
│ │ ├── components/log-to-library-button.tsx # Modal log button used on results + history
│ │ ├── services/library-service.ts # CRUD for user_library + recentRated taste signal
│ │ └── types/library.ts # LibraryItem, status/rating enums, tone tokens
│ └── home/
│ ├── components/hero-section.tsx # Animated hero with dynamic book/movie covers
│ └── data/homepage.ts # Homepage content data

├── src/components/
│ ├── ui/ # Base design system (shadcn — buttons, cards, inputs)
│ ├── enhanced/ # Shimmer loaders, animated spinners, progress bars
│ ├── ErrorBoundary.tsx # Global error boundary with recovery
│ └── theme-toggle.tsx # Dark/light mode toggle

├── src/integrations/supabase/ # Supabase client + generated DB types
├── src/utils/ # Env validation, localStorage helpers

├── supabase/
│ ├── functions/
│ │ ├── anthropic-questions/ # Claude generates personality quiz (JWT required)
│ │ ├── anthropic-recommendations/ # Claude generates recommendations (JWT required)
│ │ └── tmdb-proxy/ # Movie metadata + poster URLs (public)
│ └── migrations/
│ ├── 20250101000000_canonical_schema.sql # Core tables, RLS, indexes
│ ├── 20250307100000_add_mfa_and_sessions.sql # MFA factors + session tracking
│ ├── 20250307200000_add_backup_codes.sql # Backup codes for MFA recovery
│ ├── 20250307300000_add_backup_email.sql # Backup email for recovery
│ ├── 20250310000000_add_banners_table.sql # Admin/system banners
│ ├── 20250311000000_expand_banner_types.sql # Banner type + priority columns
│ ├── 20260410000000_add_demo_quota.sql # Per-IP rate limiting for demo quiz
│ ├── 20260411000000_add_avatars.sql # Avatar storage bucket + RLS policies
│ ├── 20260428000000_add_user_library.sql # user_library table + RLS for watched/read log
│ └── 20260429000000_fix_user_library_unique_index.sql # Plain unique index for ON CONFLICT upserts

├── public/
│ ├── images/ # Photos, screenshots
│ └── svgs/smartadvisor/ # Brand wordmark + icon SVGs (light/dark)
├── docs/ # SETUP.md, AUTHENTICATION.md
├── .github/workflows/ # CI: typecheck, lint, tests
└── .env.example # All required variables documented
```

## Quick Start

```bash
git clone https://github.com/ponderrr/smart-advisor
cd smart-advisor
npm install
cp .env.example .env.local
# Fill in NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY
npm run dev # http://localhost:3000
```

Other scripts:

```bash
npm run build # production build
npm run typecheck # tsc --noEmit (strict)
npm run lint # eslint
npm test # vitest run
npm run test:watch # vitest watch mode
```

For the full guide — including Supabase project setup, database migrations, edge function deployment, and production secrets — see **[docs/SETUP.md](docs/SETUP.md)**.

## Environment Variables

| Variable | Where to set | Required | Description |
|----------|-------------|----------|-------------|
| `NEXT_PUBLIC_SUPABASE_URL` | Vercel + `.env.local` | Yes | Your Supabase project URL |
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Vercel + `.env.local` | Yes | Supabase anon/public key |
| `ANTHROPIC_API_KEY` | Supabase secrets | Yes | Powers all AI question and recommendation generation |
| `TMDB_API_KEY` | Supabase secrets | No | Movie posters and metadata. Falls back to placeholder if absent |

> **Note:** `ANTHROPIC_API_KEY` and `TMDB_API_KEY` are Supabase Edge Function secrets. Set them in **Supabase Dashboard → Edge Functions → Manage Secrets**. They are never exposed to the browser. Open Library requires no API key.

## Security Model

All API keys (Anthropic, TMDB) are server-side only — they live in Supabase Edge Function secrets and are never bundled into the frontend. Row Level Security is enforced at the Postgres level: every `SELECT`, `INSERT`, `UPDATE`, and `DELETE` on `profiles`, `recommendations`, `sessions`, `mfa_factors`, `backup_codes`, and `avatars` is scoped to `auth.uid()`, so even a compromised client cannot access another user's data. Authentication uses the PKCE flow with cookie-based sessions managed by `@supabase/ssr` and Next.js middleware. Two-factor authentication uses TOTP (RFC 6238) with SHA-256 hashed backup codes as a recovery mechanism. Sensitive account changes (profile, email, password, disable/delete) require MFA verification — either a TOTP code or completing MFA enrollment. The frontend ships a strict Content Security Policy and the usual hardening headers (`X-Frame-Options`, `Referrer-Policy`, `Permissions-Policy`, HSTS), all user input is validated through Zod schemas, and environment variables are parsed through a typed loader that fails fast at boot. The `NEXT_PUBLIC_SUPABASE_ANON_KEY` exposed in the frontend is intentionally public; it can only access data that RLS policies explicitly allow for the authenticated user.

## Testing & CI

Vitest runs colocated unit tests (`src/**/*.test.ts{,x}`) against a jsdom environment with Testing Library. GitHub Actions runs `typecheck`, `lint`, and `test` on every push and pull request — a red check blocks merge. See `.github/workflows/ci.yml`.

## Deployment

Vercel handles the frontend — it auto-detects Next.js and handles routing automatically via the App Router. Only two env vars go in Vercel: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY`. Everything else (database, auth, edge functions, secrets) lives in Supabase. See **[docs/SETUP.md](docs/SETUP.md)** for step-by-step instructions.

## Roadmap

- [ ] Social sharing — let users share a recommendation card with friends
- [ ] More content types — podcasts, TV shows, video games
- [ ] Recommendation comparison — side-by-side view of past picks
- [ ] Rate limiting on edge functions (currently only the demo quiz is quota-gated)
- [ ] Backup email verification via transactional email service
- [ ] E2E coverage with Playwright for the critical auth + quiz paths

## License

[MIT](LICENSE)