bugfix: bookmark chapter links use chapter number, not UUID

The reader route is keyed on chapter number (URL `/manga/{id}/chapter/{n}`,
loaded via `Number(params.n)`), but the bookmarks list was building
hrefs from `chapter_id` (a UUID). Following any chapter bookmark
produced a NaN load on the reader page.

Fix at the API layer so every consumer of /me/bookmarks gets the
information without a follow-up round-trip per bookmark.

- domain::BookmarkSummary: new type, `Bookmark` plus
  `chapter_number: Option<i32>`. Populated by a LEFT JOIN on chapters
  so manga-level bookmarks come back with `chapter_number = null` and
  chapter-level ones get the value. `Bookmark` itself stays minimal
  for POST / DELETE responses.
- repo::bookmark::list_for_user returns Vec<BookmarkSummary>.
- api::bookmarks::list_me returns PagedResponse<BookmarkSummary>.
- Frontend `Bookmark` type carries an optional `chapter_number`.
- /bookmarks page builds `/manga/{manga_id}/chapter/{chapter_number}`
  for chapter bookmarks, falling back to the manga overview if the
  chapter has been deleted out from under the bookmark (chapter_id is
  ON DELETE SET NULL, so this is a real edge case).

New test asserts both branches of the JOIN: a chapter-level bookmark
comes back with the right chapter_number and page, a manga-level one
has a null chapter_number.

Lockstep version bump to 0.9.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-05-16 23:20:45 +02:00
parent ea60bd97de
commit 563524d51e
10 changed files with 131 additions and 16 deletions

View File

@@ -20,11 +20,16 @@
<ul class="bookmark-list" data-testid="bookmark-list">
{#each bookmarks as b (b.id)}
<li>
{#if b.chapter_id}
<a href="/manga/{b.manga_id}/chapter/{b.chapter_id}">
Chapter bookmark
{#if b.chapter_id && b.chapter_number != null}
<a href="/manga/{b.manga_id}/chapter/{b.chapter_number}">
Chapter {b.chapter_number}
{#if b.page}— page {b.page}{/if}
</a>
{:else if b.chapter_id}
<!-- Chapter bookmark whose chapter was deleted; fall
back to the manga overview rather than emit a
broken link to a number we don't have. -->
<a href="/manga/{b.manga_id}">Chapter bookmark (chapter removed)</a>
{:else}
<a href="/manga/{b.manga_id}">Manga bookmark</a>
{/if}