Deva-1903/TasteGraph

★ 0Forks 0TypeScriptGitHub ↗Compare

README

Taste Graph

Taste Graph is a production-grade MVP for cross-media identity mapping. Users log films, books, music, food, places, and ideas that shaped them, generate a taste fingerprint, and discover people through overlap stories and rare shared tastes.

  • No algorithmic feed
  • Discovery via constellation map + search + overlap matches
  • TypeScript end-to-end
  • Local-first setup with Docker + pnpm

Stack

  • Frontend: Next.js (App Router), Tailwind CSS, shadcn-style UI primitives, React Hook Form, Zod
  • Data viz: D3 (CategoryBarChart), react-force-graph-2d (ConstellationMap)
  • Backend: tRPC + Next.js route handlers
  • DB: PostgreSQL (Docker) + Prisma ORM
  • Auth: NextAuth (Credentials + optional GitHub OAuth)
  • Tooling: pnpm, ESLint, Prettier, Playwright smoke test

Local Setup

  1. Install dependencies:
pnpm install
  1. Start PostgreSQL:
docker compose up -d
  1. Run migrations:
pnpm prisma migrate dev
  1. Seed realistic sample data:
pnpm db:seed
  1. Start app:
pnpm dev

App URL: http://localhost:3000

Seeded Login

  • Username: devaanand (primary demo profile)
  • Password: tastegraph123

All seeded users use the same password for local development.

Environment Variables

Copy .env.example to .env and update values.

Required:

  • DATABASE_URL
  • NEXTAUTH_SECRET
  • NEXTAUTH_URL

Optional integrations (feature-flagged; never required for local run):

  • FEATURE_TMDB, TMDB_API_KEY
  • FEATURE_GOOGLE_BOOKS, GOOGLE_BOOKS_API_KEY
  • FEATURE_SPOTIFY, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET

Scripts

pnpm dev
pnpm build
pnpm start
pnpm lint
pnpm test
pnpm test:e2e
pnpm db:push
pnpm db:migrate
pnpm db:seed

Core Routes

Public:

  • / landing
  • /login, /signup
  • /u/:username profile (shareable)
  • /u/:username/world/:slug
  • /explore
  • /match/:usernameA/:usernameB

Auth required:

  • /me redirect to own profile
  • /me/add
  • /me/settings
  • /me/worlds

tRPC Procedures

  • auth.signUp
  • user.searchPeople
  • user.getByUsername
  • user.updateProfile
  • item.search
  • item.createManual
  • userItem.addExisting
  • userItem.update
  • fingerprint.computeForUser
  • similarity.computeAll (admin/dev only)
  • similarity.getForPair
  • similarity.getTopMatchesForUser
  • world.create
  • world.addItem
  • world.removeItem
  • world.getBySlug

Data Model Highlights

Prisma models:

  • User, Account, Session, VerificationToken
  • Item, Tag, ItemTag
  • UserItem, UserItemTag
  • World, WorldEntry
  • TasteFingerprint
  • SimilarityCache

Indexes include:

  • Item(canonicalSlug), Item(title)
  • Tag(name)
  • User(username)
  • SimilarityCache(userAId,userBId)

Matching Logic

Implemented in [src/lib/services/matching.ts](/Users/devaanand/Desktop/Coding Stuff/TasteGraph/src/lib/services/matching.ts):

  • itemWeight(item) = log((N_users + 1) / (users_who_saved_item + 1))
  • tagWeight(tag) = log((N_users + 1) / (users_who_used_tag + 1))
  • shapedMe boost = x2
  • user fingerprint stores:
    • category weights (shapedMe-first)
    • top tags
    • signature items (top 10 rarity-weighted)
  • similarity:
    • itemSim = cosine(weightedItemVectorA, weightedItemVectorB)
    • tagSim = cosine(weightedTagVectorA, weightedTagVectorB)
    • categorySim = 1 - JS_divergence(categoryDistA, categoryDistB)
    • overall = 0.45*tagSim + 0.45*itemSim + 0.10*categorySim
  • unexpected overlaps sorted by rarity descending

Seed Data

prisma/seed.ts creates:

  • 20 users
  • 300 canonical items (50 per category)
  • 30+ tags including:
    • slow cinema, existentialism, magical realism, shoegaze, ethiopian, ramen, brutalism
  • realistic overlap clusters:
    • arthouse
    • pop culture
    • philosophy
    • travel/food
  • rare cross-cluster overlaps for “unexpected overlap” results
  • worlds/collections per user
  • recomputed fingerprint + similarity caches

Testing

Playwright smoke test:

  • login with seeded user
  • add an item
  • open explore
  • open a match page

Test file:

  • [tests/e2e/smoke.spec.ts](/Users/devaanand/Desktop/Coding Stuff/TasteGraph/tests/e2e/smoke.spec.ts)

Run:

pnpm test:e2e

Repository Tree

.
├── docker-compose.yml
├── prisma
│   ├── migrations
│   ├── schema.prisma
│   └── seed.ts
├── src
│   ├── app
│   │   ├── api
│   │   ├── explore
│   │   ├── login
│   │   ├── match/[usernameA]/[usernameB]
│   │   ├── me/{add,settings,worlds}
│   │   ├── signup
│   │   └── u/[username]/world/[slug]
│   ├── components
│   │   ├── charts
│   │   ├── forms
│   │   ├── map
│   │   ├── shared
│   │   └── ui
│   ├── lib
│   │   ├── services
│   │   └── ...
│   ├── server
│   │   ├── api
│   │   └── auth
│   └── trpc
├── tests/e2e/smoke.spec.ts
├── .env.example
└── README.md

Future Upgrades

  • External API search integrations (TMDB, Google Books, Spotify)
  • Embedding-based matching (optional OpenAI)
  • Real-time updates for worlds and overlap recalculation
  • Invite-only growth loops and referral graph mechanics

Contributors

Deva-1903

Issues