feat(user): add updates feed for followed players#83
Conversation
Replace the homepage "Activity feed coming soon" placeholder with a feed of recent revisions authored by followed users on public decks. Attribution is by editor (DeckRevision.userId), so a followed user's collaborator edits on other people's public decks surface too. Scoped to visibility=PUBLIC, kind=DECK, matching the discovery convention. Key changes: - getFollowingUpdates cached under userFollowingTag so follow/unfollow refreshes instantly; deck edits ride minutes-level staleness - summarizeDeltas helper for the +N/-M/K-changes row summary - (user_id, updated_at DESC) index on deck_revision for the feed query - UpdatesFeed server component with zero-follow and no-updates empty states plus a CLS-safe skeleton
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
💤 Files with no reviewable changes (2)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds a cached feed of recent public deck revisions from followed users, revision delta summaries and per-editor grouping, supporting database indexing, tests, and home-page rendering with empty and loading states. ChangesUpdates feed
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Viewer
participant HomeView
participant UpdatesFeed
participant getFollowingUpdates
participant Prisma
Viewer->>HomeView: open home page
HomeView->>UpdatesFeed: render with viewer ID
UpdatesFeed->>getFollowingUpdates: load followed-user updates
getFollowingUpdates->>Prisma: query follows and public revisions
Prisma-->>getFollowingUpdates: revisions and editor profiles
getFollowingUpdates-->>UpdatesFeed: feed items
UpdatesFeed-->>Viewer: render update rows or empty state
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
app/(ui)/deck/[id]/history/page.tsxParsing error: The keyword 'import' is reserved app/_components/home/updates-feed.tsxParsing error: The keyword 'import' is reserved lib/deck/mutation/__tests__/revision.test.tsParsing error: The keyword 'import' is reserved
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
lib/user/feed.ts (1)
49-63: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winPagination filtering can reduce visible items below FEED_PAGE_SIZE.
The query fetches 10 revisions, then filters out those with missing editors or empty/malformed changes (lines 84-86). If several are filtered, the user sees fewer than 10 items even when more valid revisions exist. This is a reasonable v1 trade-off, but if the filter rate is high (e.g., deleted users, malformed payloads), consider over-fetching (e.g.,
take: FEED_PAGE_SIZE * 3) and slicing toFEED_PAGE_SIZEafter filtering, or pushing thechangesnon-empty check into the database query.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/user/feed.ts` around lines 49 - 63, Over-fetch revisions in the feed query to compensate for entries removed by later validation: update the `take` value in the `prisma.deckRevision.findMany` call to a larger multiple such as `FEED_PAGE_SIZE * 3`, then filter invalid revisions and slice the resulting list to `FEED_PAGE_SIZE` before returning it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@prisma/migrations/20260710212937_deck_revision_user_updated_at_idx/migration.sql`:
- Around line 1-2: Change the index statement in migration
deck_revision_user_updated_at_idx to CREATE INDEX CONCURRENTLY while preserving
the existing index name, table, columns, and sort order. Ensure this migration
is executed outside a transaction, configuring the Prisma migration workflow as
needed.
---
Nitpick comments:
In `@lib/user/feed.ts`:
- Around line 49-63: Over-fetch revisions in the feed query to compensate for
entries removed by later validation: update the `take` value in the
`prisma.deckRevision.findMany` call to a larger multiple such as `FEED_PAGE_SIZE
* 3`, then filter invalid revisions and slice the resulting list to
`FEED_PAGE_SIZE` before returning it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 76726b3b-2c7e-4608-8f28-9084a573e2cf
📒 Files selected for processing (8)
app/_components/home/home-view.tsxapp/_components/home/updates-feed.tsxlib/deck/__tests__/revision.test.tslib/deck/revision.tslib/user/__tests__/feed.test.tslib/user/feed.tsprisma/migrations/20260710212937_deck_revision_user_updated_at_idx/migration.sqlprisma/schema.prisma
Scope the 5-minute revision merge window per editor so collaborator edits are attributed to their own author instead of being merged into another editor's revision — the feed attributes by DeckRevision.userId, so cross-editor merges mis-attributed or hid collaborator activity. Also: - Match the feed skeleton to the real list (10 rows from FEED_PAGE_SIZE, 64px rows, same bordered divide-y container) to avoid CLS while streaming. - Rewrite the deck_revision index migration to the repo's CONCURRENTLY convention (IF NOT EXISTS inline, manual CONCURRENTLY rollout notes for production). - Drop unused editor.name/image from FeedItem and its query. - Update history page copy to reflect the per-editor merge window.
Description
Replaces the homepage "Activity feed coming soon" placeholder with an updates feed: recent changes that players you follow have made to public decks.
Fixes: #28
Attribution is by editor, not deck owner. The feed filters
DeckRevision.userId IN (followed ids)so a followed user's collaborator edits (#27) on other people's public decks surface too — matching the issue text ("changes they've made"). Always constrained tovisibility=PUBLIC, kind=DECK, so private edits and public wishlists stay out, per the discovery convention.Caching:
getFollowingUpdatesis cached underuserFollowingTag(viewerId)withcacheLife("minutes"). Follow/unfollow already bumps that tag, so the one invalidation that must feel instant is free; deck edits ride the minutes-level staleness rather than fanning tag invalidation out to every follower on the hotapplyDeckMutationpath.No FK added to
DeckRevision— editors are resolved with a second batcheduser.findMany, mirroring the existing two-step pattern inlib/user/queries.ts. Revisions with a missing editor or malformedchangespayload are skipped, never rendered broken.graph TD HV[home-view.tsx] -->|Suspense| UF[UpdatesFeed] UF --> GFU[getFollowingUpdates<br/>lib/user/feed.ts] GFU -->|1. follows| F[(follow)] GFU -->|2. revisions by editor,<br/>PUBLIC + DECK only| DR[(deck_revision<br/>new index: user_id, updated_at DESC)] GFU -->|3. batched editor lookup| U[(user)] UF --> SD[summarizeDeltas<br/>lib/deck/revision.ts] FA[follow/unfollow action] -->|updateTag userFollowingTag| GFUWhat changed
lib/user/feed.ts(new) —getFollowingUpdates(viewerId): cached feed query, page of 10, editor-attributedlib/deck/revision.ts—summarizeDeltashelper for the+N −M · K changesrow summaryapp/_components/home/updates-feed.tsx(new) — server component with zero-follow and no-recent-updates empty states + skeletonapp/_components/home/home-view.tsx— placeholder replaced with<Suspense>-wrapped feedprisma/schema.prisma+ migration —(user_id, updated_at DESC)index ondeck_revisionserving the feed'sIN … ORDER BY … LIMITshapeChecklist
pnpm test) and lint is cleanrevalidate/dynamic/unstable_cache— used'use cache'+cacheLife/cacheTag<Link>imported fromapp/_components/link.tsx, notnext/linkScreenshots / notes
Verified E2E in the browser with a fresh account:
/u/[username]and deck →/deck/[id], withTimeAgoand colored+N/−M · K changessummarykind=DECKdecks surfaceUnit coverage:
lib/user/__tests__/feed.test.ts(early return, query shape, editor dedupe, missing-editor skip, malformed-payload skip, cache tag) andsummarizeDeltascases inlib/deck/__tests__/revision.test.ts. Coverage gate (100 lines / 99 branches) passes.Summary by CodeRabbit