Feature Spec: Article Favorites
As a registered user, I can favorite and unfavorite articles so I can curate a reading list, and any client can see accurate favorite state and counts. This spec covers the REST endpoints, the GraphQL mutations, and the favorite read-model behavior.
Behavior / Acceptance Criteria
Favorite an article (REST POST /articles/{slug}/favorite)
- AC1: An authenticated user favoriting an existing article receives
200 and the returned article.favorited is true.
- AC2: The returned
article.favoritesCount reflects the article's favorite count including this user.
- AC3: Favoriting an article that does not exist returns
404.
- AC4: An unauthenticated request returns
401 and does not change favorite state.
- AC5: Favoriting an article the user has already favorited is idempotent — still
200, favorited=true, and the count is not double-incremented.
Unfavorite an article (REST DELETE /articles/{slug}/favorite)
- AC6: An authenticated user unfavoriting a previously favorited article receives
200 and article.favorited is false.
- AC7:
article.favoritesCount decreases accordingly after unfavoriting.
- AC8: Unfavoriting an article that does not exist returns
404.
- AC9: An unauthenticated request returns
401.
- AC10: Unfavoriting an article the user had not favorited is a no-op —
200, favorited=false, count unchanged.
GraphQL parity
- AC11: The
favoriteArticle(slug) mutation sets favorited=true and returns the updated favoritesCount, matching the REST result for the same user/article.
- AC12: The
unfavoriteArticle(slug) mutation sets favorited=false, matching the REST result.
Read-model / persistence
- AC13: The favorite read model reports the correct
favorited flag per (article, viewer) pair — true only for the viewing user's own favorites.
- AC14: The favorites count for an article equals the number of distinct users who have favorited it.
Notes
- Follow the repo's existing test conventions per tier.
favorited is always relative to the authenticated/viewing user; an anonymous viewer sees favorited=false.
Feature Spec: Article Favorites
As a registered user, I can favorite and unfavorite articles so I can curate a reading list, and any client can see accurate favorite state and counts. This spec covers the REST endpoints, the GraphQL mutations, and the favorite read-model behavior.
Behavior / Acceptance Criteria
Favorite an article (REST
POST /articles/{slug}/favorite)200and the returnedarticle.favoritedistrue.article.favoritesCountreflects the article's favorite count including this user.404.401and does not change favorite state.200,favorited=true, and the count is not double-incremented.Unfavorite an article (REST
DELETE /articles/{slug}/favorite)200andarticle.favoritedisfalse.article.favoritesCountdecreases accordingly after unfavoriting.404.401.200,favorited=false, count unchanged.GraphQL parity
favoriteArticle(slug)mutation setsfavorited=trueand returns the updatedfavoritesCount, matching the REST result for the same user/article.unfavoriteArticle(slug)mutation setsfavorited=false, matching the REST result.Read-model / persistence
favoritedflag per (article, viewer) pair —trueonly for the viewing user's own favorites.Notes
favoritedis always relative to the authenticated/viewing user; an anonymous viewer seesfavorited=false.