Skip to content

feat: add collections, read lists, and want-to-read#36

Merged
AshDevFr merged 13 commits into
mainfrom
collections-read-lists-want-to-read
Jun 16, 2026
Merged

feat: add collections, read lists, and want-to-read#36
AshDevFr merged 13 commits into
mainfrom
collections-read-lists-want-to-read

Conversation

@AshDevFr

Copy link
Copy Markdown
Owner

Summary

Adds three Komga-style organization features to Codex: Collections (shared, ordered groupings of series), Read Lists (shared, ordered groupings of books across series), and Want to Read (a per-user on-deck queue of series and books). Each is fully managed through the native API with browsing surfaced in the web UI, the read-only Komga compatibility layer, and OPDS catalogs.

Motivation

Codex had no way to group related series (franchises, publisher lines, themes) or to curate cross-series reading orders such as crossover events, and Komga apps connecting to the compatibility layer saw empty collection and read-list stubs. Separately, users had been faking a "read later" queue by opening page 1 of a title so it surfaced in "Keep Reading," abusing read-progress state. These features provide first-class grouping and a proper personal queue.

Changes

  • API — Collections & Read Lists: New CRUD endpoints under /api/v1/collections and /api/v1/readlists, including member add/remove/reorder, per-container thumbnails, and reverse lookups (collections containing a series, read lists containing a book). Member lists are filtered to what the requesting user is allowed to see, and counts reflect only visible members.
  • API — Want to Read: New per-user endpoints under /api/v1/want-to-read to add/remove series and books and list the queue (sortable by when items were added). Series and book responses gain a wantToRead flag reflecting the current user's queue state.
  • Permissions: New collections:read|write|delete and readlists:read|write|delete permissions. Read access is granted to all roles; write/delete go to Maintainer and Admin. Want to Read requires only authentication. These also act as API-key scopes.
  • Web UI: New Collections, Read List, and Want to Read pages with detail views and manual reordering; "Add to collection," "Add to read list," and "Want to read" controls on series and book pages. Management controls are hidden from users without write/delete permission.
  • Komga compatibility (read-only): The collection and read-list endpoints now serve real data instead of empty stubs, including members, thumbnails, and reverse lookups, available on both Komga API versions.
  • OPDS 1.2 / 2.0 (read-only): New navigation and member feeds for collections and read lists, linked from the catalog root.

Notes

  • The Komga compatibility endpoints remain behind the existing komga_api.enabled flag; no new configuration is required for the native API or OPDS.
  • The change adds new tables only, with no changes to existing tables and no data backfill; rolling back drops the new tables and leaves existing data untouched.
  • Collection, read-list, and OPDS write support over the Komga/OPDS layers is intentionally out of scope; full management is native-API only.

AshDevFr added 9 commits June 13, 2026 16:01
Add the database foundation for three Komga-style grouping concepts:

- collections + collection_series: shared, ordered groupings of series
- read_lists + read_list_books: shared, ordered groupings of books
  across series (with a nullable summary)
- want_to_read: per-user on-deck queue where each row flags exactly one
  series or one book, enforced by an inline CHECK constraint and two
  partial-unique indexes per user

Junction tables carry a position column and cascade-delete with their
parents; reverse relations are wired into the series, books, and users
entities. The CHECK is rendered inline at table creation so it holds on
SQLite as well as PostgreSQL.

Covered by schema tests for ordered membership, uniqueness, cascade
deletes, and the want-to-read CHECK, run on SQLite with ignored
PostgreSQL variants.
…tories

Introduce six RBAC permissions — collections:read/write/delete and
readlists:read/write/delete. Read is granted to the Reader role (so all
roles can browse), while write/delete go to Maintainer (inherited by
Admin), matching how maintainers already manage series and books.

Add repositories backing the new tables:
- CollectionRepository: CRUD, idempotent membership add, reorder, and
  visibility-filtered ordered member fetch plus counts and a
  collections-for-series lookup
- ReadListRepository: the same shape for books, with a nullable summary
  and series-based book visibility filtering
- WantToReadRepository: per-user idempotent add/remove for series and
  books, queue listing by added-at, and batch in-queue lookups for DTO
  enrichment

Member fetches return stored position order; the unordered computed sort
is left to the API layer. Covered by unit tests and updated permission
role-count assertions.
Expose the per-user want-to-read queue over /api/v1/want-to-read:
- GET lists the queue, newest-first by default, with a
  sort=added_at:asc|desc toggle
- POST flags a series or a book (exactly one; idempotent), 400 on a
  malformed target and 404 when it doesn't exist
- DELETE removes a series or book from the queue

Every endpoint scopes to the authenticated user; being signed in is
sufficient since a user only manages their own queue.

Surface queue membership on the existing series and book DTOs via a new
wantToRead flag, populated on detail and list endpoints with a single
batched lookup per page so cards can render the toggle state without an
extra request.

Register the new paths and schemas in the OpenAPI doc and regenerate the
committed spec. Covered by integration tests.
Add the frontend for the per-user want-to-read queue:
- A Want to Read page with a Newest/Oldest sort toggle and a responsive
  grid that reuses the standard media card, with per-entry removal and
  empty/loading states
- A bookmark toggle on the series and book detail pages, driven by the
  DTO's wantToRead flag, that adds/removes the item and refreshes state
- A sidebar nav link and route, plus the API client and query hooks

Also surface wantToRead on the full series and book responses (the
flattened DTOs the detail pages fetch), populated with one batched query
per page, and regenerate the OpenAPI spec and TypeScript types.

Covered by a component test for the toggle.
Expose shared, ordered collections of series over /api/v1/collections:
- List, create, get, rename / toggle ordering, and delete collections
- Manage members: add one or many series, remove, and set manual order
- Browse members as full series DTOs, filtered by the requesting user's
  sharing-tag visibility, with the visible count on each collection
- A thumbnail endpoint that redirects to the first visible member's
  cover, and a reverse lookup of the collections containing a series

Reads are available to every role; create/modify require collections
write and delete requires collections delete. Register the paths and
schemas in the OpenAPI doc and regenerate the committed spec and types.
Covered by integration tests including the permission matrix.
Add the frontend for shared collections of series:
- A collections list page with cover thumbnails and a gated "New
  collection" modal
- A collection detail page showing member series, with per-member
  removal and up/down reordering for ordered collections, plus gated
  edit and delete
- An "Add to collection" menu on the series page that toggles
  membership across collections and can create new ones inline
- A sidebar link and routes, the API client, and query hooks

Mirror the new collection and read-list permissions in the frontend
permission map so create/modify/delete controls only render for users
who can manage collections. Covered by a component test.
Expose shared, ordered read lists of books over /api/v1/readlists:
- List, create (with an optional summary), get, rename / edit summary /
  toggle ordering, and delete read lists
- Manage members: add one or many books, remove, and set manual reading
  order
- Browse members as full book DTOs, filtered by the requesting user's
  sharing-tag visibility, with the visible count on each read list
- A thumbnail endpoint that redirects to the first visible member's
  cover, and a reverse lookup of the read lists containing a book

Reads are available to every role; create/modify require read-list write
and delete requires read-list delete. The update request distinguishes
an omitted summary from an explicit null (which clears it). Register the
paths and schemas in the OpenAPI doc and regenerate the committed spec
and types. Covered by integration tests including the permission matrix.
Add the frontend for shared read lists of books:
- A read lists list page with cover thumbnails and a gated "New read
  list" modal that captures a name, summary, and reading-order flag
- A read list detail page showing the summary and member books, with
  per-member removal and up/down reordering for ordered lists, plus
  gated edit and delete
- An "Add to read list" menu on the book page that toggles membership
  across read lists and can create new ones inline
- A sidebar link and routes, the API client, and query hooks

Controls that create, modify, or delete only render for users who can
manage read lists. Covered by a component test.
Replace the empty collection and read-list stubs in the Komga-compatible
API with real data, so third-party Komga apps can browse them:
- List and detail endpoints return collections (with member series IDs)
  and read lists (with summary and member book IDs)
- Member endpoints render the series and books in Komga's own DTO shape,
  reusing the existing series/book builders with batched metadata and
  read progress
- Thumbnail endpoints redirect to the first visible member's cover, and
  reverse lookups expose the collections/read lists containing a given
  series or book

All endpoints are exposed under both the v1 and v2 Komga routers, filter
members by the requesting user's sharing-tag visibility, and keep the
Spring-Data page wrapper Komga clients expect. Covered by integration
tests; the existing Komga suite still passes after dropping the stubs.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploying codex with  Cloudflare Pages  Cloudflare Pages

Latest commit: 85587c4
Status: ✅  Deploy successful!
Preview URL: https://7dccd26b.codex-asm.pages.dev
Branch Preview URL: https://collections-read-lists-want.codex-asm.pages.dev

View logs

AshDevFr added 4 commits June 15, 2026 20:46
Expose collections and read lists through both OPDS catalogs so e-reader
apps can browse them:
- OPDS 1.2 gains navigation feeds listing collections and read lists, a
  collection feed of its member series, and an acquisition feed of a
  read list's books (with download, page-streaming, and cover links)
- OPDS 2.0 gains the equivalent JSON navigation and publication feeds,
  including per-book reading progress
- Both root catalogs now link to the new Collections and Read Lists
  sections

Member series and books are filtered by the requesting user's
sharing-tag visibility. Covered by integration tests for both catalog
versions.
Add a user guide covering the three grouping features — the per-user
Want to Read queue, shared Collections of series, and shared Read Lists
of books — including how they differ, how to use them, the management
permissions, and visibility behavior.

Update the Komga and OPDS pages to reflect that collections and read
lists are now served read-only (with their endpoint and feed listings),
and add a collection/read-list permission table to the permissions
reference.
The collection, read-list, and want-to-read features added new admin
permissions, raising ADMIN_PERMISSIONS from 23 to 29. The source unit
test in codex-models was updated, but two duplicate hardcoded
assertions in the integration tests still expected 23, causing
test_permission_sets and test_user_with_multiple_api_keys to fail.

Bump both stale assertions to 29 to match the current permission set.
Surface collection and read-list membership directly from the library
grid instead of only the series/book detail pages.

- Add nested "Add to collection" / "Add to read list" submenus to the
  media card dropdown, gated by collections:write / readlists:write.
  Series cards manage collections; book cards manage read lists. The
  membership query is deferred until a card's menu opens, so a grid does
  not fan out one request per card.
- Add bulk "Add to collection" / "Add to read list" submenus to the
  selection toolbar's More menu. Picking a target adds every selected
  item, with an inline option to create a new collection/read list that
  immediately receives the selection.
- Group the card dropdowns into divided sections (reading, management,
  membership) with guards so empty groups never leave orphan dividers.
- Label the card menu trigger for accessibility.

Fix a navigation regression: the inline-create modal was a child of the
card, so its portaled clicks bubbled through React's tree to the card's
navigation handler and opened the detail page. The modals now render as
siblings of the card.

Add tests for the new card menu entries and permission gating.
@AshDevFr AshDevFr merged commit e62f7b1 into main Jun 16, 2026
22 checks passed
@AshDevFr AshDevFr deleted the collections-read-lists-want-to-read branch June 16, 2026 23:01
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.

1 participant