Skip to content

feat(pub): persist like identity per viewer (#72) - #79

Open
sun-970 wants to merge 1 commit into
bytefolk:mainfrom
sun-970:feat/pub-like-viewer-identity
Open

sun-970 wants to merge 1 commit into
bytefolk:mainfrom
sun-970:feat/pub-like-viewer-identity

Conversation

@sun-970

@sun-970 sun-970 commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add PubDocLike table with (viewerId, pubDocId) unique constraint to track likes per viewer server-side
  • Use cookie-based anonymous viewer token (viewer_id httpOnly cookie) for unauthenticated visitors; user:<id> for authenticated users
  • Make like/unlike idempotent per viewer: duplicate increases are no-ops, cancel only succeeds if the viewer holds a like
  • Replace client-side localStorage in ThumbUpButton with server-side state fetched via new GET endpoint
  • Counts stay nonnegative and survive reload across devices

Changes

File Change
prisma/schema.prisma Add PubDocLike model + likes relation on PubDoc
prisma/migrations/... SQL migration for PubDocLike table
src/lib/viewer-id.ts New resolveViewerId() helper (auth session → cookie fallback)
src/app/api/pub/thumb-up/[publishId]/route.ts Add GET, rewrite PATCH for idempotent increase
src/app/api/pub/thumb-up-decrease/[publishId]/route.ts Rewrite PATCH to delete viewer's like and decrement
src/components/thumb-up-button.tsx Replace localStorage with API-based state
CHANGELOG.md Add entry under [Unreleased]

Test plan

  • npx prisma migrate dev applies the migration successfully
  • npm run build passes
  • Like a pub doc → reload → still liked, count unchanged
  • Unlike → reload → still unliked, count decremented
  • Clear cookies → like again → count increments (new viewer)
  • Call PATCH increase twice rapidly → count only increments once (idempotent)
  • All 307 vitest tests pass (2 pre-existing CLI doctor test failures unrelated)

Closes #72

@waterbro-8 waterbro-8 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The like-identity work for #72 is the right direction, but this PR currently ships two other threads and cannot merge as-is.

  1. Drop the #65 overlap. These files are the i18n/timeAgo/version-timestamp change from #65, not like identity:

    • src/lib/dt.ts, src/__tests__/lib/dt.test.ts
    • messages/en.json, messages/zh-cn.json
    • star-list.tsx, trash.tsx, content-home.tsx
    • src/app/api/doc-version/route.ts, version-dialog.tsx

    Same class of problem as #67. Please rebase onto current main and keep only PubDocLike / viewer-id / thumb-up routes / thumb-up-button.tsx / the like CHANGELOG line.

  2. Coordinate with #70. #70 already rewrites unlike + rollback on thumb-up-button / decrease route. After stripping #65, rebase onto (or wait for) #70 so the identity table is additive rather than a conflicting rewrite of the same files.

I cannot push your fork. After a like-only push I can re-review.

@sun-970
sun-970 force-pushed the feat/pub-like-viewer-identity branch from ea81652 to 404c97d Compare September 18, 2026 06:25

@waterbro-8 waterbro-8 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-review: the #65 i18n/timeAgo/version-timestamp files are gone. Remaining change is PubDocLike + viewer cookie + idempotent like/unlike, which is the right #72 design. CI is green.

Still overlaps #70 on thumb-up-button / decrease route — land this as the like-identity successor and drop or rebase #70 rather than merging both. I cannot satisfy CODEOWNERS myself.

Bindy-lbb
Bindy-lbb previously approved these changes Sep 18, 2026

@Bindy-lbb Bindy-lbb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

CODEOWNERS Review: Approved

Summary of Changes

  • Schema & Migration: Adds PubDocLike with (viewerId, pubDocId) compound unique index and proper foreign key cascade on pubDocId.
  • Identity Resolution: Adds resolveViewerId cleanly falling back from authenticated session to HTTP-only cookie-backed UUID.
  • Endpoint Idempotency:
    • GET /api/pub/thumb-up/[publishId]: Fetches current like status and total count.
    • PATCH /api/pub/thumb-up/[publishId]: Atomic increment + record creation in $transaction.
    • PATCH /api/pub/thumb-up-decrease/[publishId]: Idempotent like cancellation clamped at 0.
  • Client Component: Smooth transition in ThumbUpButton from localStorage to server-backed state with optimistic UI and error recovery.
  • Scope: Cleanly decoupled from PR #65 i18n/timestamp changes as requested during earlier review cycles.

All CI checks are green. Approved for merge.

@waterbro-8

Copy link
Copy Markdown

#65 已合入 main。这个 PR 现在与 main 冲突。我推不了 sun-970/doc,请 rebase 到当前 main 后再 push。

@Bindy-lbb Bindy-lbb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. Server-side like identity is well-designed: PubDocLike table with (viewerId, pubDocId) unique constraint, cookie-based anonymous viewer fallback with httpOnly/sameSite/secure flags, authenticated users get user: prefix. Like/unlike idempotency is correct — duplicate like is a no-op returning current state, cancel only decrements if the viewer actually holds a like. The transaction in the like path ensures atomicity between count increment and like record creation. ThumbUpButton properly migrated from localStorage to API-based state. Migration SQL is clean with appropriate index on pubDocId and CASCADE delete.

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.

feat(pub): persist like identity so cancel/duplicate clicks are per viewer

3 participants