Skip to content

fix(bookmark): include bookmarked articles in the saved list - #219

Open
aquie00t wants to merge 1 commit into
mainfrom
fix/article-bookmarks-missing-from-saved
Open

fix(bookmark): include bookmarked articles in the saved list#219
aquie00t wants to merge 1 commit into
mainfrom
fix/article-bookmarks-missing-from-saved

Conversation

@aquie00t

Copy link
Copy Markdown
Collaborator

Problem

Saving an article did nothing visible. POST /articles/:id/bookmark returned 200 and the row landed in article_bookmarksGET /articles/:slug even reported isBookmarked: true — but the article never appeared in the saved list.

Reproduced against a running instance:

POST /api/v1/articles/:id/bookmark   → 200
GET  /api/v1/articles/:slug          → isBookmarked: true
GET  /api/v1/posts/bookmarks         → {"posts": [], "comments": []}

The response had no articles key at all.

Cause

GetBookmarksUseCase only ever asked two sources:

const [postResult, commentResult] = await Promise.all([
    this.postRepository.findAll({ savedByUserId: input.userId, ... }),
    this.commentBookmarkRepository.findBookmarkedByUserId(...),
]);

Articles live in their own table rather than under Post, so the post query cannot see them. No other endpoint filled the gap either: GET /articles has no bookmarked filter and /articles/me returns articles you wrote, filtered by status. Article bookmarks were write-only — reachable by no read path.

Fix

The plumbing already existed and simply was not called:

  • GetArticlesParams.savedByUserId — already declared on the port
  • prisma-article.repository.ts:178where.bookmarks = { some: { userId: savedByUserId } } — already implemented

So this wires up what was there rather than adding a new query.

  • GetBookmarksUseCase takes articleRepository and fetches bookmarked articles alongside posts and comments, in the same Promise.all
  • the response carries data.articles and meta.articleTotal
  • articles are serialized with ArticleSummarySchema, not the full item — a body can be 100 KB of markdown and a saved list renders cards

No DI registration change was needed: awilix runs in CLASSIC mode and resolves by constructor parameter name, which already matches the articleRepository registry key.

Verification

data keys : posts, comments, articles
meta      : {"postTotal":0,"commentTotal":0,"articleTotal":1,...}

Add/remove round-trip against a live instance:

initial          : 1 [Bir Parametre Adını De]
after 2nd save   : 2 [Hata Yönetimini Tek Bi | Bir Parametre Adını De]
after removing 1 : 1 [Hata Yönetimini Tek Bi]
after removing 2 : 0 []

pnpm test:unit — 764/764 passing (5 existing tests adapted to the new dependency, 1 added covering the savedByUserId hand-off). pnpm lint and pnpm format:check clean.

Notes for reviewers

  • The response shape grew. data.articles and meta.articleTotal are additive, so existing clients keep working, but the saved-list screen needs to render the new field before this is visible to users.
  • Pagination stays independent per source. page=2 is passed to each of the three queries separately, matching the existing posts/comments behaviour. A single merged, chronologically sorted feed would be a separate design decision, not a bug fix.

🤖 Generated with Claude Code

https://claude.ai/code/session_019YbEuSAiGYLZmwvhcrov4g

Article bookmarks were write-only. POST /articles/:id/bookmark persisted a
row to article_bookmarks and the article detail endpoint reported
isBookmarked correctly, but GET /posts/bookmarks never queried that table,
so a saved article was unreachable from every read path.

Articles live in their own table rather than under Post, so the existing
post query could not see them. GetArticlesParams.savedByUserId and its
Prisma filter (where.bookmarks) already existed; nothing called them.

- GetBookmarksUseCase takes articleRepository and fetches bookmarked
  articles alongside posts and comments
- the response carries data.articles and meta.articleTotal; articles are
  summaries because a body can be 100 KB of markdown
- unit tests cover the new dependency and the savedByUserId hand-off

No DI change was needed: awilix runs in CLASSIC mode and resolves by
constructor parameter name, which already matches the registry key.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YbEuSAiGYLZmwvhcrov4g
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