Skip to content

Add bookmark soft delete with deletedAt#64

Open
katsumi-axis wants to merge 3 commits intoviperrcrypto:mainfrom
katsumi-axis:codex/bookmark-soft-delete
Open

Add bookmark soft delete with deletedAt#64
katsumi-axis wants to merge 3 commits intoviperrcrypto:mainfrom
katsumi-axis:codex/bookmark-soft-delete

Conversation

@katsumi-axis
Copy link
Copy Markdown

@katsumi-axis katsumi-axis commented Mar 29, 2026

Summary

This PR adds bookmark soft delete support using deletedAt so imported data can be removed from the app without physically deleting related records.

What Changed

  • added Bookmark.deletedAt and a new per-bookmark DELETE /api/bookmarks/[id] route
  • added a delete action to bookmark cards and removed deleted items from the current client view immediately
  • filtered main bookmark read paths to exclude soft-deleted bookmarks from listings, stats, search, categorization, image analysis, mindmap data, exports, and FTS rebuilds
  • added a small helper to compute category counts from active bookmarks only

Why

The app previously only had an all-data destructive delete path. This change adds a safer, more reversible deletion model while keeping the existing structure mostly intact and minimizing changes to current query patterns.

Impact

  • deleting a bookmark now hides it from normal product surfaces instead of removing the row entirely
  • existing category assignments, enrichment data, and media relations stay attached to the bookmark record
  • the existing bulk DELETE /api/bookmarks behavior is unchanged
  • re-import does not currently restore a soft-deleted bookmark with the same tweetId

Validation

  • npx prisma generate
  • npx prisma db push
  • rebuilt FTS after schema sync
  • verified getActiveBookmarkCountMap() executes successfully

Known Issue

npx tsc --noEmit is currently blocked by an existing unrelated nullability error in app/api/import/x-oauth/fetch/route.ts.

@katsumi-axis katsumi-axis changed the title Add bookmark soft delete with deletedAt [codex] Add bookmark soft delete with deletedAt Mar 29, 2026
@katsumi-axis katsumi-axis changed the title [codex] Add bookmark soft delete with deletedAt Add bookmark soft delete with deletedAt Mar 29, 2026
Copy link
Copy Markdown

@xkonjin xkonjin left a comment

Choose a reason for hiding this comment

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

Code Review: Bookmark Soft Delete

Overall: Solid implementation of soft delete pattern. The deletedAt nullable timestamp approach is idiomatic and the comprehensive query updates across all API routes show good attention to detail.

What looks good

  • Consistent use of deletedAt: null filter across all Prisma queries
  • New getActiveBookmarkCountMap() helper properly filters via join table
  • Migration includes index on deletedAt for query performance
  • UI handles deletion with optimistic update and proper loading state
  • DELETE endpoint returns appropriate 404/200 responses

Issues to address

1. Missing foreign key cleanup consideration (medium risk)
The PR adds soft delete to bookmarks but doesn't address related data in BookmarkCategory join table. While the count queries correctly filter via the relation, you may want to consider:

  • Should deleting a bookmark also cascade-soft-delete its category relationships?
  • Or should BookmarkCategory entries remain (they won't show in counts due to the join filter, but they accumulate orphaned rows)

2. UI race condition on category page
The category page fetches data server-side then allows deletion. If a bookmark is deleted, the total count decrements but the pagination might be stale if the user navigates pages. Consider refetching or using the existing SWR pattern.

3. No test coverage
A change touching 20+ files and modifying core data access patterns should have at least:

  • Unit tests for getActiveBookmarkCountMap()
  • Integration tests that verify deleted bookmarks don't appear in search/AI routes
  • Test for the DELETE endpoint (404 case, already deleted case, success case)

Minor

  • The migration filename suggests manual timestamp — fine, but verify it doesn't conflict with existing migrations
  • Consider adding a deletedAt filter to any analytics/aggregation queries that might be in other files not shown in the diff

Security note

Good: The delete endpoint checks if bookmark exists and already deleted before proceeding. No auth middleware shown in diff — assume that's handled upstream or in layout.

Copy link
Copy Markdown

@xkonjin xkonjin left a comment

Choose a reason for hiding this comment

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

Code Review: Bookmark Soft Delete

Overall: Solid implementation of soft delete pattern. The deletedAt nullable timestamp approach is idiomatic and the comprehensive query updates across all API routes show good attention to detail.

What looks good

  • Consistent use of deletedAt: null filter across all Prisma queries
  • New getActiveBookmarkCountMap() helper properly filters via join table
  • Migration includes index on deletedAt for query performance
  • UI handles deletion with optimistic update and proper loading state
  • DELETE endpoint returns appropriate 404/200 responses

Issues to address

1. Missing foreign key cleanup consideration (medium risk)
The PR adds soft delete to bookmarks but doesn't address related data in BookmarkCategory join table. While the count queries correctly filter via the relation, you may want to consider:

  • Should deleting a bookmark also cascade-soft-delete its category relationships?
  • Or should BookmarkCategory entries remain (they won't show in counts due to the join filter, but they accumulate orphaned rows)

2. UI race condition on category page
The category page fetches data server-side then allows deletion. If a bookmark is deleted, the total count decrements but the pagination might be stale if the user navigates pages. Consider refetching or using the existing SWR pattern.

3. No test coverage
A change touching 20+ files and modifying core data access patterns should have at least:

  • Unit tests for getActiveBookmarkCountMap()
  • Integration tests that verify deleted bookmarks don't appear in search/AI routes
  • Test for the DELETE endpoint (404 case, already deleted case, success case)

Minor

  • The migration filename suggests manual timestamp — fine, but verify it doesn't conflict with existing migrations
  • Consider adding a deletedAt filter to any analytics/aggregation queries that might be in other files not shown in the diff

Security note

Good: The delete endpoint checks if bookmark exists and already deleted before proceeding. No auth middleware shown in diff — assume that's handled upstream or in layout.

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.

2 participants