feat: opt-in scored related posts and category neighbours

- golem15.journal.related_mode (category | scored, default category) and
  golem15.journal.related_count (3 to 6, default 3, clamped) in
  config/config.yaml; classes.ReadRelatedSettings reads them
- the default mode answers GET /posts/{slug} exactly as before
- scored: related posts ranked by 2 points per shared tag plus 1 per
  shared category, ties by newest, in one scoring query
  (classes.ScoredRelatedPosts), published only for visitors; the answer
  adds previous_in_category and next_in_category, the neighbours by
  publish time within the post's first category by name
  (classes.CategoryNeighbour), in the direction of previous_post and
  next_post
- TestRelatedDefaultUnchanged, TestRelatedScored (a draft and a future
  post sharing every tag never shown) and TestRelatedScoredCountClamped
This commit is contained in:
Jakub Zych
2026-11-04 14:14:09 +01:00
parent 0edf6e1b67
commit ee3cb263dc
5 changed files with 461 additions and 2 deletions

View File

@@ -8,3 +8,13 @@
# H1 to H4. Changing it never rewrites stored content; journal:fix-headings
# --apply does.
content_h1_to_h2: true
# Related posts on GET /_journal/api/v1/posts/{slug} (opt-in).
# related_mode "category" (the default) answers as before: up to three
# posts sharing a category with the post, newest first. "scored" ranks
# posts by shared tags (2 points each) and shared categories (1 point
# each), ties by the newest, returns related_count of them (3 to 6,
# clamped) and adds previous_in_category and next_in_category, the post's
# neighbours by publish time within its first category by name.
related_mode: category
related_count: 3