Skip to content

[#209] View counts for storyline and plot pages#217

Merged
realproject7 merged 2 commits intomainfrom
task/209-view-counts
Mar 16, 2026
Merged

[#209] View counts for storyline and plot pages#217
realproject7 merged 2 commits intomainfrom
task/209-view-counts

Conversation

@realproject7
Copy link
Copy Markdown
Owner

Summary

  • Migration: page_views table with session dedup index, view_count denormalized column on storylines, increment_view_count Postgres RPC function
  • API: POST /api/views records views with 1-per-session-per-hour dedup; GET /api/views?storylineId=N returns count
  • ViewCount component: SVG eye icon + compact number formatting (1.2k, 12k, 1.2M)
  • ViewTracker component: fire-and-forget POST on page mount using sessionStorage-based session ID, non-blocking
  • Display locations: home page story cards, story detail page header, writer dashboard (4-column grid with Views)

Acceptance Criteria

  • page_views table created with indexes
  • view_count column on storylines table
  • POST /api/views with session deduplication (1 per session per page per hour)
  • View count displayed on home page cards
  • View count displayed on story page header
  • View count displayed on writer dashboard
  • Eye icon SVG matching design system (stroke-based, not emoji)
  • Compact number formatting (1.2k, 12k, 1.2M)
  • No performance impact on page load (async tracking, non-blocking)

Test plan

  • Run migration on Supabase
  • Visit a story page → verify POST /api/views fires in Network tab
  • Refresh within 1 hour → verify dedup (response: deduplicated: true)
  • Check story card on home page shows eye icon + count
  • Check story detail header shows eye icon + count
  • Check writer dashboard shows Views column with count
  • Verify view_count increments on storylines table after new view

Fixes #209

🤖 Generated with Claude Code

- Migration: page_views table with session dedup, view_count column on
  storylines, atomic increment_view_count RPC function
- API: POST /api/views (insert + dedup per session/hour), GET /api/views
  (returns denormalized count)
- ViewCount component: SVG eye icon + compact number formatting (1.2k, 1M)
- ViewTracker component: fire-and-forget POST on page mount with
  sessionStorage-based session ID
- Display: home page story cards, story detail header, writer dashboard
- No performance impact on page load (tracking is async/non-blocking)

Fixes #209

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES

Summary

The storyline-level view count pieces are in place, but the PR does not actually implement plot-level tracking yet. That leaves the main requirement from issue #209 incomplete.

Findings

  • [high] Plot-level views are never recorded
    • File: src/app/story/[storylineId]/page.tsx:127
    • File: src/components/ViewCount.tsx:89
    • Suggestion: mount ViewTracker with a non-null plotIndex at the actual plot-level page/view surface, or otherwise wire the client so individual plot views generate POST /api/views requests with plotIndex populated. Right now the only mounted tracker is <ViewTracker storylineId={id} />, so every inserted row has plot_index = NULL and the plot-level path is dead code.

Decision

Requesting changes because issue #209 explicitly requires tracking page views for both storylines and individual plots in Supabase, and this implementation only records storyline views.

Each PlotEntry now mounts a ViewTracker with plotIndex, so
individual plot views are recorded in page_views (not just
storyline-level). Addresses T2a review feedback on PR #217.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE

Summary

The follow-up change wires ViewTracker into each rendered plot entry, so the plot-level tracking path is now actually exercised. The PR now matches issue #209 for storyline and individual-plot view recording, and the updated head passes CI.

Findings

  • None.

Decision

Approving because the previously missing per-plot tracking path is now connected and the required display surfaces and API pieces are in place.

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T2b: APPROVE

Clean implementation of view tracking with solid architecture:

  • Migration: Proper table design with dedup index, RLS, and atomic increment RPC
  • API: Good session-based dedup (1hr window), correct NULL handling for plot_index, service-role writes
  • ViewCount: React Query with server-provided initialData avoids layout flash, 2-min staleTime is reasonable
  • ViewTracker: SSR-safe sessionStorage + crypto.randomUUID(), fire-and-forget with query invalidation on new views
  • Plot-level tracking: Each PlotEntry mounts its own ViewTracker with plotIndex — correctly addressed after T2a's feedback

Minor note (non-blocking): formatViewCountDashboard in the dashboard doesn't handle the 10M+ tier that formatViewCount in ViewCount.tsx does — cosmetic inconsistency only.

@realproject7 realproject7 merged commit 91bedc6 into main Mar 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] View counts for storyline and plot pages

2 participants