{"id":47075222,"url":"https://github.com/ponderrr/smart-advisor","last_synced_at":"2026-05-24T06:00:59.980Z","repository":{"id":299656246,"uuid":"999905316","full_name":"ponderrr/smart-advisor","owner":"ponderrr","description":"AI-powered movie \u0026 book recommendations tailored to who you actually are — built with Claude, Supabase, and React.","archived":false,"fork":false,"pushed_at":"2026-05-20T17:17:30.000Z","size":6253,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-20T22:03:10.983Z","etag":null,"topics":["ai-recommendations","anthropic","book-recommendation-system","claude-ai","deno","edge-functions","movie-recommendation-app","react","row-level-security","supabase","tailwindcss","tmdb","typescript","vercel","vite"],"latest_commit_sha":null,"homepage":"https://smartadvisor.live","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ponderrr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-11T01:23:12.000Z","updated_at":"2026-05-16T21:13:59.000Z","dependencies_parsed_at":"2025-06-17T17:00:01.348Z","dependency_job_id":null,"html_url":"https://github.com/ponderrr/smart-advisor","commit_stats":null,"previous_names":["ponderrr/smartadvisor-v3","ponderrr/smart-advisor"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/ponderrr/smart-advisor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ponderrr%2Fsmart-advisor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ponderrr%2Fsmart-advisor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ponderrr%2Fsmart-advisor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ponderrr%2Fsmart-advisor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ponderrr","download_url":"https://codeload.github.com/ponderrr/smart-advisor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ponderrr%2Fsmart-advisor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33423284,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"online","status_checked_at":"2026-05-24T02:00:06.296Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-recommendations","anthropic","book-recommendation-system","claude-ai","deno","edge-functions","movie-recommendation-app","react","row-level-security","supabase","tailwindcss","tmdb","typescript","vercel","vite"],"created_at":"2026-03-12T06:37:40.597Z","updated_at":"2026-05-24T06:00:59.972Z","avatar_url":"https://github.com/ponderrr.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"public/svgs/smartadvisor/SmartAdvisor-DM.svg\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"public/svgs/smartadvisor/SmartAdvisor-LM.svg\"\u003e\n  \u003cimg src=\"public/svgs/smartadvisor/SmartAdvisor-LM.svg\" width=\"320\" alt=\"Smart Advisor\" /\u003e\n\u003c/picture\u003e\n\nAI-powered movie \u0026 book recommendations tailored to who you actually are.\n\n![License](https://img.shields.io/badge/license-MIT-blue.svg)\n![Next.js](https://img.shields.io/badge/next.js-16-000000?logo=next.js\u0026logoColor=white)\n![TypeScript](https://img.shields.io/badge/typescript-strict-3178C6?logo=typescript\u0026logoColor=white)\n![Supabase](https://img.shields.io/badge/supabase-postgres%20%2B%20edge%20functions-3ECF8E?logo=supabase\u0026logoColor=white)\n![Claude](https://img.shields.io/badge/claude-sonnet%204-D97757?logo=anthropic\u0026logoColor=white)\n![Vercel](https://img.shields.io/badge/vercel-deployed-000000?logo=vercel\u0026logoColor=white)\n![Tests](https://img.shields.io/badge/tests-vitest-6E9F18?logo=vitest\u0026logoColor=white)\n\n[Live Demo](https://smartadvisor.live) · [Setup Guide](docs/SETUP.md) · [Auth Docs](docs/AUTHENTICATION.md) · [Report Bug](https://github.com/ponderrr/smart-advisor/issues)\n\n\u003cimg src=\"public/images/smart-advisor-screenshot.png\" width=\"820\" alt=\"Smart Advisor screenshot\" /\u003e\n\n\u003c/div\u003e\n\n## What It Is\n\nSmart 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).\n\n## How It Works\n\n1. **Sign up** — email + password or Google OAuth, with optional two-factor authentication (TOTP)\n2. **Choose content** — movies, books, or both\n3. **Pick quiz length** — 3 to 15 questions\n4. **Take the quiz** — Claude generates personality-driven questions tailored to your age (scenario-based, preference comparisons, emotional responses)\n5. **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\n6. **Save and revisit** — every recommendation is persisted to your account with favorites and history\n7. **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\n\nNew users can also **try a demo quiz** without signing up — a 5-question survey that generates real-time recommendations from TMDB and Open Library.\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                   Browser (Next.js App Router)                 │\n│  Auth → Quiz → Questions → Answers → Results → History       │\n└──────────────────┬──────────────────────┬───────────────────┘\n                   │ PKCE / JWT           │ JWT\n                   ▼                      ▼\n         ┌─────────────────┐   ┌──────────────────────┐\n         │  Supabase Auth  │   │  Supabase Edge Fns   │\n         │  (PKCE + MFA)   │   │                      │\n         └────────┬────────┘   │  anthropic-questions  │\n                  │            │  anthropic-recs        │\n                  ▼            │  tmdb-proxy            │\n         ┌─────────────────┐   └──────┬──────────┬────┘\n         │Supabase Postgres│          │          │\n         │                 │          ▼          ▼\n         │  profiles       │   ┌────────────┐ ┌────────────┐\n         │  recommendations│   │ Anthropic  │ │ TMDB /     │\n         │  sessions       │   │ Claude API │ │ Open       │\n         │  mfa_factors    │   └────────────┘ │ Library    │\n         │  backup_codes   │                  └────────────┘\n         │  (RLS enforced) │\n         └─────────────────┘\n```\n\n## Feature Highlights\n\n| Feature | Detail |\n|---------|--------|\n| **Age-gated AI personas** | Under-18 gets warm, encouraging picks. 18+ gets unfiltered recommendations including mature themes. |\n| **Single sharp recommendation** | One movie. One book. Deeply explained. Not a ranked list. |\n| **Real cover art** | TMDB and Open Library APIs fetch actual posters and covers. |\n| **Two-factor authentication** | TOTP-based MFA with backup codes and backup email recovery. |\n| **Device \u0026 session management** | View active sessions across devices, revoke individually or globally. |\n| **Avatar uploads** | Drag-and-drop avatar with client-side crop, stored in Supabase Storage with RLS-scoped access. |\n| **Demo quiz** | Try the recommendation flow without an account — rate-limited per IP via `demo_quota`. |\n| **Full auth with PKCE** | Supabase Auth with email confirmation, Google OAuth, and PKCE flow. |\n| **MFA-gated sensitive changes** | Profile, email, password, and account changes require MFA verification. |\n| **Zero exposed secrets** | All API keys live in Supabase Edge Function secrets, never the frontend. |\n| **Row Level Security** | Every DB query is scoped to the authenticated user at the Postgres level. |\n| **Recommendation history** | All picks saved to account with favorites and filters. |\n| **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. |\n| **Hardened frontend** | CSP + strict security headers, Zod-validated inputs, typed env parsing, global error boundary. |\n| **Tested + CI-gated** | Vitest unit tests run in CI alongside `tsc --noEmit` and ESLint on every push. |\n\n## Tech Stack\n\n| Layer | Technology | Why |\n|-------|-----------|-----|\n| Frontend | Next.js 16 + React 18 + TypeScript (strict) | App Router, SSR-ready auth, file-based routing |\n| Styling | Tailwind CSS + Radix UI + shadcn/ui | Utility-first CSS, accessible primitives, dark mode via `next-themes` |\n| Animation | Motion (Framer) | Scroll-linked hero + bento grid transitions |\n| State | Zustand + TanStack Query | Lightweight quiz store; cached server state for recs/history |\n| Forms \u0026 validation | React Hook Form + Zod | Typed schemas shared between form and edge-function payloads |\n| Auth | Supabase Auth (PKCE + MFA) | Email/password, Google OAuth, TOTP two-factor |\n| Database | Supabase Postgres | RLS enforced at DB level, not app level |\n| Storage | Supabase Storage | Avatar uploads scoped by RLS |\n| Edge Functions | Supabase Deno runtime | Server-side secrets, low latency, JWT verification |\n| AI | Anthropic Claude Sonnet 4 | Nuanced reasoning for taste-based recommendations |\n| Movie data | TMDB API | Industry-standard movie metadata and poster images |\n| Book data | Open Library API | Cover art and metadata for millions of titles (no API key) |\n| Testing | Vitest + Testing Library + jsdom | Unit and component tests, run in CI |\n| Analytics | Vercel Analytics + Speed Insights | Real-user web vitals and traffic, no third-party cookies |\n| Hosting | Vercel | Zero-config Next.js deploys with automatic routing |\n\n## Project Structure\n\n```\nsmart-advisor/\n├── src/app/                         # Next.js App Router pages\n│   ├── layout.tsx                   # Root layout with metadata\n│   ├── providers.tsx                # Client providers (Auth, Toaster)\n│   ├── globals.css                  # Global styles (Tailwind + custom)\n│   ├── page.tsx                     # Landing page (/)\n│   ├── error.tsx                    # App-level error boundary\n│   ├── loading.tsx                  # App-level loading skeleton\n│   ├── not-found.tsx                # 404 page\n│   ├── auth/\n│   │   ├── page.tsx                 # Sign up / sign in / MFA challenge (/auth)\n│   │   ├── reset-password/page.tsx  # Password reset flow\n│   │   └── callback/route.ts       # OAuth + email verification handler\n│   ├── demo/\n│   │   ├── page.tsx                 # Unauthenticated demo quiz (/demo)\n│   │   └── results/page.tsx         # Demo recommendation results\n│   ├── settings/page.tsx            # Account settings (profile, security, content, integrations)\n│   ├── account/\n│   │   ├── security/page.tsx        # Security settings\n│   │   └── mfa-setup/page.tsx       # MFA enrollment page\n│   ├── content-selection/page.tsx   # Movie, book, or both\n│   ├── question-count/page.tsx      # 3–15 questions\n│   ├── questionnaire/page.tsx       # Dynamic AI-generated quiz\n│   ├── results/page.tsx             # AI recommendation display + favorites\n│   ├── dashboard/page.tsx           # User dashboard\n│   ├── history/page.tsx             # Saved picks and favorites\n│   ├── library/page.tsx             # Watched/read log with status, rating, reaction\n│   └── api/\n│       ├── open-library/route.ts    # Open Library search proxy\n│       ├── hero-media/route.ts      # Hero section media fetcher\n│       ├── demo-media/route.ts      # Demo quiz media API (Open Library + TMDB)\n│       ├── demo-books/route.ts      # Demo quiz books API (Open Library)\n│       └── account/                 # Account disable/delete endpoints\n│\n├── src/features/\n│   ├── auth/\n│   │   ├── components/              # AuthForm, MfaSetup, MfaManagement, SessionsManagement\n│   │   ├── hooks/use-auth.tsx       # Auth context with MFA, backup codes, backup email\n│   │   ├── services/\n│   │   │   ├── auth-service.ts      # Auth, MFA, backup codes, backup email logic\n│   │   │   └── session-management.ts # Device session tracking with deduplication\n│   │   ├── types/user.ts            # User type definition\n│   │   └── utils/                   # Validation, device parsing\n│   ├── quiz/\n│   │   ├── store/quiz-store.ts      # Zustand store for quiz flow state\n│   │   ├── types/                   # Question, Answer interfaces\n│   │   └── utils/                   # Fallback questions\n│   ├── recommendations/\n│   │   └── services/\n│   │       ├── ai-service.ts        # Calls anthropic-questions + anthropic-recommendations\n│   │       ├── enhanced-recommendations-service.ts  # Retry logic, TMDB/Open Library enrichment\n│   │       ├── tmdb-service.ts      # TMDB proxy client\n│   │       ├── open-library-service.ts  # Open Library client (replaces Google Books)\n│   │       └── database-service.ts  # Recommendation CRUD + favorites\n│   ├── library/\n│   │   ├── components/log-to-library-button.tsx  # Modal log button used on results + history\n│   │   ├── services/library-service.ts           # CRUD for user_library + recentRated taste signal\n│   │   └── types/library.ts                      # LibraryItem, status/rating enums, tone tokens\n│   └── home/\n│       ├── components/hero-section.tsx  # Animated hero with dynamic book/movie covers\n│       └── data/homepage.ts         # Homepage content data\n│\n├── src/components/\n│   ├── ui/                          # Base design system (shadcn — buttons, cards, inputs)\n│   ├── enhanced/                    # Shimmer loaders, animated spinners, progress bars\n│   ├── ErrorBoundary.tsx            # Global error boundary with recovery\n│   └── theme-toggle.tsx             # Dark/light mode toggle\n│\n├── src/integrations/supabase/       # Supabase client + generated DB types\n├── src/utils/                       # Env validation, localStorage helpers\n│\n├── supabase/\n│   ├── functions/\n│   │   ├── anthropic-questions/         # Claude generates personality quiz (JWT required)\n│   │   ├── anthropic-recommendations/   # Claude generates recommendations (JWT required)\n│   │   └── tmdb-proxy/                  # Movie metadata + poster URLs (public)\n│   └── migrations/\n│       ├── 20250101000000_canonical_schema.sql        # Core tables, RLS, indexes\n│       ├── 20250307100000_add_mfa_and_sessions.sql    # MFA factors + session tracking\n│       ├── 20250307200000_add_backup_codes.sql        # Backup codes for MFA recovery\n│       ├── 20250307300000_add_backup_email.sql        # Backup email for recovery\n│       ├── 20250310000000_add_banners_table.sql       # Admin/system banners\n│       ├── 20250311000000_expand_banner_types.sql     # Banner type + priority columns\n│       ├── 20260410000000_add_demo_quota.sql          # Per-IP rate limiting for demo quiz\n│       ├── 20260411000000_add_avatars.sql             # Avatar storage bucket + RLS policies\n│       ├── 20260428000000_add_user_library.sql        # user_library table + RLS for watched/read log\n│       └── 20260429000000_fix_user_library_unique_index.sql  # Plain unique index for ON CONFLICT upserts\n│\n├── public/\n│   ├── images/                      # Photos, screenshots\n│   └── svgs/smartadvisor/           # Brand wordmark + icon SVGs (light/dark)\n├── docs/                            # SETUP.md, AUTHENTICATION.md\n├── .github/workflows/               # CI: typecheck, lint, tests\n└── .env.example                     # All required variables documented\n```\n\n## Quick Start\n\n```bash\ngit clone https://github.com/ponderrr/smart-advisor\ncd smart-advisor\nnpm install\ncp .env.example .env.local\n# Fill in NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY\nnpm run dev           # http://localhost:3000\n```\n\nOther scripts:\n\n```bash\nnpm run build         # production build\nnpm run typecheck     # tsc --noEmit (strict)\nnpm run lint          # eslint\nnpm test              # vitest run\nnpm run test:watch    # vitest watch mode\n```\n\nFor the full guide — including Supabase project setup, database migrations, edge function deployment, and production secrets — see **[docs/SETUP.md](docs/SETUP.md)**.\n\n## Environment Variables\n\n| Variable | Where to set | Required | Description |\n|----------|-------------|----------|-------------|\n| `NEXT_PUBLIC_SUPABASE_URL` | Vercel + `.env.local` | Yes | Your Supabase project URL |\n| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Vercel + `.env.local` | Yes | Supabase anon/public key |\n| `ANTHROPIC_API_KEY` | Supabase secrets | Yes | Powers all AI question and recommendation generation |\n| `TMDB_API_KEY` | Supabase secrets | No | Movie posters and metadata. Falls back to placeholder if absent |\n\n\u003e **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.\n\n## Security Model\n\nAll 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.\n\n## Testing \u0026 CI\n\nVitest 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`.\n\n## Deployment\n\nVercel 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.\n\n## Roadmap\n\n- [ ] Social sharing — let users share a recommendation card with friends\n- [ ] More content types — podcasts, TV shows, video games\n- [ ] Recommendation comparison — side-by-side view of past picks\n- [ ] Rate limiting on edge functions (currently only the demo quiz is quota-gated)\n- [ ] Backup email verification via transactional email service\n- [ ] E2E coverage with Playwright for the critical auth + quiz paths\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fponderrr%2Fsmart-advisor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fponderrr%2Fsmart-advisor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fponderrr%2Fsmart-advisor/lists"}