Skip to content

Feature/2874 multi image bookmarks - #3057

Draft
juntaotan wants to merge 60 commits into
karakeep-app:mainfrom
juntaotan:feature/2874-multi-image-bookmarks
Draft

Feature/2874 multi image bookmarks#3057
juntaotan wants to merge 60 commits into
karakeep-app:mainfrom
juntaotan:feature/2874-multi-image-bookmarks

Conversation

@juntaotan

Copy link
Copy Markdown

Fixes #2874

Draft PR for design and scope alignment on #2874, which proposes ordered multi‑image bookmarks that can manage and display a series of images as a single logical bookmark, and this issue has already been approved. In current implementation, users can group image bookmarks into a single logical bookmark, view the images in a stable order, reorder or remove individual images, and append another image to an existing collection. Images that belong to a collection are hidden from the regular bookmark listing to avoid duplicate entries.

Feedback Requested

Before expanding the remaining test coverage, I would particularly appreciate maintainer feedback on the following decisions:

The first is the data model selection. Due to minimum modification, the current implementation models a collection as a bookmark containing ordered references to exist image bookmarks, allowing it to reuse the current asset, OCR, and tagging workflows. As a potential direction, I propose allowing collections to manage image assets directly through an ordered collection-to-asset relation, with an asset's collection membership derived from that relation. This would require broader restructuring of the existing data model and workflows, so I would appreciate maintainer feedback before pursuing it.

The second is the child bookmark deletion lifecycle. The current implementation deletes only the collection bookmark and its membership records; the child image bookmarks and their associated assets are retained and become visible again as standalone bookmarks. I propose using a collection-specific confirmation dialog that lets the user choose between deleting only the collection or deleting the collection together with all of its child image bookmarks and associated assets. I would appreciate feedback on whether this optional cascading behavior matches the expected data lifecycle and UX.

⁠Current implementation

The database upgrade introduces image collections with minimal impact on the existing schema. Collections are modelled as a new bookmark type, allowing them to reuse existing bookmark metadata and behaviour, while two additive tables store collection-specific timestamps and ordered image membership. The migration does not modify or backfill existing bookmark or asset records, and cascading foreign keys, indexes and Drizzle relations support consistent, efficient access. Collection creation, reordering and item removal are handled transactionally, with validation performed at the application layer. However, to integrate the collection module more naturally into the existing data model, we are also considering having collections manage image assets directly; see the Known limitations section for details.

Collection support extends the existing bookmark APIs for retrieval, updates and deletion, with dedicated endpoints for reordering and removing images. Retrieval returns images in their stored order, including bookmark IDs, asset IDs and filenames, together with deduplicated collection and child-image tags and aggregated tagging status. Bookmark listings exclude images already grouped into collections to avoid duplicate entries. Updates reuse existing bookmark fields and validate that any selected image belongs to the collection before modifying its content. Reordering requires the complete existing set of images, while removing an image preserves its bookmark and asset, prevents removal of the final item and renumbers the remaining positions. Deleting a collection also retains its child images. Further fixes use synchronous transactions for related writes, initialise collection tagging status from its children, align tag aggregation between detail and list responses, and invalidate affected caches after updates to prevent stale results.

The frontend displays collections as gallery cards with up to four image previews, a prominent first image, an image count and an overlay indicating additional images. Opening a collection shows all images in order, with filenames, position indicators and links to individual image previews. Users can create a collection by dragging one image bookmark onto another across grid, list and compact layouts, with valid targets highlighted and confirmation required before creation. Shared drag state and dedicated drag identifiers prevent conflicts with bulk editing and file uploads. Image order follows the stored positions, initially preserving the source–target order for drag merges or file order for multiple-image uploads. Within a collection, users reorder images using up and down controls, which submit the complete revised order to the API. Successful reordering or removal refreshes both the gallery and its card preview, while controls are disabled during pending requests to prevent conflicting actions.

⁠Known limitations

This PR is not ready for final review yet, and the test coverage is still in progress. An initial backend test covers collection creation, reordering, tag deduplication, tagging status aggregation, ordered OCR content retrieval, and image removal, including protection against removing the last image. Remaining test work includes coverage for appending images to existing collections, ownership and invalid-input checks, per-image OCR editing, and asynchronous tagging status updates. End-to-end validation of multi-image uploads, drag-and-drop interactions, and failure handling is also pending. The current implementation models a collection as a bookmark containing ordered references to individual image bookmarks. This allows it to reuse the existing asset, OCR, and tagging workflows.

The following work includes adding test talked before, confirming the data mode and addressing review feedback

⁠How Has This Been Tested?

We ran pnpm exec turbo run --no-daemon typecheck lint format --force, with all 64 tasks completing successfully. We also ran the shared package, tRPC, and worker test suites: 110 shared package tests, 449 tRPC tests, and 27 worker tests passed.

The current tRPC bookmark tests cover collection creation, image reordering and persistence, tag deduplication and tagging status aggregation, retrieval of stored OCR content in collection order, and image removal, including preventing removal of the last image. Our team also manually tested the feature across all web bookmark layouts: masonry, grid, list, and compact.

The repository’s existing CI workflow additionally includes E2E tests, workspace consistency checks, and verification that the generated OpenAPI specification is up to date. Feature-specific test coverage is still being expanded.

Screenshots

image-20260905133234-q0f5tej image-20260905133355-1uayspb image-20260905133436-on1ra07

⁠# Checklist

  • I have carefully read CONTRIBUTING.md
  • I have completed a full self-review of the implementation
  • I have made corresponding changes to the documentation if applicable
  • I have no unrelated changes in the PR diff
  • I have confirmed that no new dependency is required
  • I have written initial tests for the new code
  • I have completed the remaining tests listed above
  • The data model and feature scope have been confirmed by the maintainers

Which degree of AI using

LLMs were utilised to rapidly comprehend the project architecture, data structures, and governance policies. AI tools also assisted with the code review process and debugging tasks. Its insights and suggestions were evaluated and manually integrated to ensure alignment with existing architecture and coding conventions.

juntaotan and others added 30 commits August 8, 2026 13:49
- Add the imageCollections table to store image collection metadata for frontend consumption, such as ownership, title, cover, and timestamps.
- Add the imageCollectionItems table to associate bookmarks with collections and preserve the position of each item within a collection
- Keep the existing bookmarks and bookmarkAssets schemas unchanged by modeling image collections through separate relational tables
- Add a new enum value to AssetType in bookmarks.ts
- Extend the enum definition of the bookmarks.type column to include the new asset type
- Define the relationship between imageCollections table and bookmark table (one collection can has many bookmarks);
- Define the relationship between imageCollectionItems and imageCollection (one item only have one collection)
- Generate the Drizzle migration and snapshot for image collections and ordered collection items
- Store collection item timestamps in the addedAt column and enforce one collection per bookmark
- Rename the image collection item relation for consistency
- Extend shared and admin API schemas to support the collection bookmark type
- Add a scoped imageOcr.reprocess mutation that accepts up to 500 bookmark IDs and supports optional forced reprocessing
- Introduce a shared ImageOcrService entry point for dispatching OCR jobs from collection and bookmark workflows
- Deduplicate bookmark IDs while preserving collection order when submitting preprocessing jobs
- Restrict OCR processing to image asset bookmarks owned by the authenticated user
- Skip images that already contain OCR text unless force mode is explicitly enabled
- Reuse the existing AssetPreprocessingQueue and worker pipeline so extracted text continues to be stored in bookmarkAssets.content
- Add stable idempotency keys, user queue grouping, and default queue priority for OCR jobs
- Return detailed counters for queued, previously processed, and unsupported bookmark items
- Register the image OCR router in the main tRPC application router
- Add tests covering ownership checks, duplicate IDs, unsupported bookmark types, existing OCR content, and forced reprocessing
…-delete-api

feat: support asset bookmark image series
…from-collection

feat(bookmarks): support removing items from image collections
- add an API for removing items from image collections
- prevent removal of the final collection item
- reorder remaining items after deletion
- add a confirmation dialog and deletion feedback
- Expose bookmark types through the BareBookmark model
- Detect collection bookmarks before regular bookmark handling
- Query collection items using the requested collection ID
- Join collection items with bookmark assets
- Retrieve bookmark IDs, asset IDs, positions, and stored OCR content
- Preserve collection image ordering by position
- Regenerate the OpenAPI specification for collection bookmarks
- Leave OCR response-schema mapping for a follow-up change
- Add collection content to the bookmark response schema
- Join image titles and stored OCR text in collection order
- Respect the includeContent option
- Add coverage and regenerate the OpenAPI specification
- Join collection items with existing AI-generated tags
- Deduplicate inherited tags while preserving collection tags
- Derive collection tagging status from image bookmarks
- Add coverage for tag aggregation and status updates
juntaotan and others added 30 commits August 17, 2026 23:34
…on-image-filename

feat: show image collection item filenames
…e-frontend

Feature/2874 bookmark drag merge frontend
…elete-i18n

fix: use i18n for collection delete UI
implement multi-image gallery with editor card support; unrelated out-of-scope changes will be removed later
- Remove HomeBookmarkCollection and the All saved items landing view.
- Remove showAsCollection and restore direct bookmark grid rendering.
- Remove per-page layout settings keyed by pathname.
- Remove bookmarkGridLayoutsByView from user local settings.
- Restore the shared global bookmarkGridLayout behavior.
- Regenerate the OpenAPI specification to include the nullable fileName field for image collection items.

These homepage and layout preference changes are unrelated to the multi-image gallery issue.
- Request bookmark content with `includeContent` enabled for collections.
- add an image selector to the collection bookmark editor
- load extracted content for the selected collection image
- update the selected image content when saving the collection
- validate that the selected image belongs to the collection
- invalidate both collection and selected image caches after updates
- aggregate manually attached tags from collection images
- find cached collections containing the updated image
- propagate collection IDs through image tagging jobs
- preserve collection context across embedding dispatch
- aggregate child tagging statuses after inference completes
- include bookmark IDs with extracted content query results
- update the form only for the currently selected image
- clear null extracted content when switching images
- initialise collection tagging status from child bookmarks
- return the aggregated status when creating a collection
- include and deduplicate child image tags in bookmark listings
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.

Multi-image notes

3 participants