feat: personalized 'For you' feed + open-source repo hygiene#1336
Conversation
- Add CLAUDE.md orienting contributors; flags the repo as public and sets a high bar for code that must pass open-source review. - Remove docs/plans/* internal design/planning notes (not appropriate for a public repo) and drop their references from code comments. - gitignore .claude/ and other local AI assistant config.
Adds opt-in feed personalization built on the topic vocabulary: - Schema (migration 0039, additive): user_topic_pref (follow/mute) and user_topic_affinity (implicit interest, time-decayed). - feedRanking: pure, unit-tested scoring — a transparent weighted blend of recency, quality, and topic affinity, with muted topics filtered out. - topicAffinity: derive per-user affinity from votes/bookmarks/comments through post_topic edges with decay; recomputed for active users by the nightly cron. - profile.getTopicPrefs / setTopicPref: manage follows and mutes. - content.getForYouFeed: re-rank a recent candidate window for the user; cold start (no signal) falls back to recency, so the existing feed is untouched. Also trims verbose comments across the content-pipeline modules.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedPull request was closed or merged during review WalkthroughAdds a full feed personalization pipeline: new ChangesFeed Personalization Pipeline
OG Card Templates Rewrite
Repo Housekeeping
Sequence Diagram(s)sequenceDiagram
participant Client
participant contentRouter
participant feedPersonalization as feedPersonalization.ts
participant feedRanking as feedRanking.ts
participant DB
Client->>contentRouter: getForYouFeed(limit, offset)
contentRouter->>feedPersonalization: loadUserProfile(db, userId)
feedPersonalization->>DB: SELECT user_topic_pref + user_topic_affinity
DB-->>feedPersonalization: prefs + affinity rows
feedPersonalization-->>contentRouter: UserProfile {follows, mutes, affinity}
contentRouter->>DB: SELECT posts + qualityScore (recent window)
DB-->>contentRouter: post candidates[]
alt hasProfileSignal(profile)
contentRouter->>feedPersonalization: loadTopicsByPost(db, postIds)
feedPersonalization->>DB: SELECT post_topic edges
DB-->>feedPersonalization: postId→topicIds
feedPersonalization-->>contentRouter: topicsByPost Map
contentRouter->>feedRanking: rankCandidates(candidates, profile, nowMs)
feedRanking-->>contentRouter: RankedCandidate[] sorted by score
end
contentRouter-->>Client: {items, nextOffset, personalized}
sequenceDiagram
participant CronRoute as daily-review cron
participant topicAffinity as topicAffinity.ts
participant DB
CronRoute->>topicAffinity: findRecentlyActiveUsers(db, since24h, cap)
topicAffinity->>DB: SELECT distinct userIds from votes/bookmarks/comments
DB-->>topicAffinity: userIds[]
topicAffinity-->>CronRoute: activeUsers[]
loop per user
CronRoute->>topicAffinity: recomputeUserAffinity(db, userId, nowMs)
topicAffinity->>DB: fetch votes/bookmarks/comments + post_topic edges
DB-->>topicAffinity: interactions with timestamps
topicAffinity->>topicAffinity: decayedWeight per interaction per topic
topicAffinity->>DB: DELETE existing user_topic_affinity rows
topicAffinity->>DB: INSERT positive-score rows
topicAffinity-->>CronRoute: updatedTopicCount
end
CronRoute-->>CronRoute: summary.affinityUsersUpdated
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What
Opt-in feed personalization ("For you"), plus repo hygiene.
Personalization (Phase 3)
Built on the topic vocabulary, additive and cold-start safe — the existing feed is untouched.
0039, additive):user_topic_pref(follow/mute) anduser_topic_affinity(implicit, time-decayed interest).feedRanking— a pure, unit-tested scoring module: a transparent weighted blend of recency, quality, and topic affinity, with muted topics filtered out. "Why did this rank here?" is always answerable.topicAffinity— derives per-user affinity from votes/bookmarks/comments throughpost_topicedges with time decay; recomputed for recently-active users as a new pass in the nightly cron.profile.getTopicPrefs/setTopicPref— manage follows/mutes against the controlled topic vocabulary.content.getForYouFeed— re-ranks a recent candidate window for the signed-in user. No profile signal → falls back to recency, so a new user sees the normal feed. Ready for the client to adopt as a "For you" tab.Repo hygiene
CLAUDE.mdorienting contributors; flags the repo as public and sets a high bar for code that must pass open-source review.docs/plans/*design/planning notes (not appropriate for a public repo) and drop their references from code comments.gitignorelocal AI-assistant config.Verification (local)
tsc: 0 errors ·eslint: clean ·prettier --check: clean ·next build: succeeds.vitest: 110 tests pass (incl. 16 new ranking/affinity tests). The one failing file is the pre-existingbackfill-url-idDB-integration test that needsDATABASE_URL— unrelated to this change.Notes
0039is additive and applies on the production deploy viadb:migrate.