Reader: mark groups / articles as read, and hide read items #18

Closed
opened 2026-09-11 22:28:35 +00:00 by agent-pi · 3 comments
Collaborator

Problem

The reader has no way to mark a whole group (aggregate) as read, and articles that have been read stay in the view forever. Once I have read an article — or everything in a group — I don't want it cluttering the reader, but I also want the choice of seeing already-read content when I do.

Goal

  • Allow marking groups / articles as read (individual article marking may already partially exist — scope to be confirmed during work)
  • Allow read articles / groups to be hidden, with a configurable toggle rather than forced hiding
## Problem The reader has no way to mark a whole group (aggregate) as read, and articles that have been read stay in the view forever. Once I have read an article — or everything in a group — I don't want it cluttering the reader, but I also want the choice of seeing already-read content when I do. ## Goal - Allow marking groups / articles as read (individual article marking may already partially exist — scope to be confirmed during work) - Allow read articles / groups to be hidden, with a configurable toggle rather than forced hiding
Author
Collaborator

Findings

  • Per-article read/unread tracking already exists (DB + route — noted during the #5 shortcut survey). What is missing: group-level marking and any notion of hiding read content.
  • Design questions for implementation:
    • Is a group's read state stored or computed (all member articles read)? Marking a group read = mark all current member articles?
    • Hide-read toggle: per-session (query param / UI state) vs persisted setting (the #8 settings store would be the natural home once it exists)?

Plan of attack

  1. Verify the existing per-article read surface; extend the DB layer for group read state.
  2. Routes: mark-group-as-read; hide/show-read toggle endpoint.
  3. Reader UI: read visual state, group mark-read control, hide-read toggle (server-rendered).
  4. Tests for the DB and routing logic.

Unblocks #5: the r (toggle read) and h (next unread) shortcuts assume this exists.

## Findings - Per-article read/unread tracking already exists (DB + route — noted during the #5 shortcut survey). What is missing: **group-level** marking and any notion of hiding read content. - Design questions for implementation: - Is a group's read state stored or computed (all member articles read)? Marking a group read = mark all current member articles? - Hide-read toggle: per-session (query param / UI state) vs persisted setting (the #8 settings store would be the natural home once it exists)? ## Plan of attack 1. Verify the existing per-article read surface; extend the DB layer for group read state. 2. Routes: mark-group-as-read; hide/show-read toggle endpoint. 3. Reader UI: read visual state, group mark-read control, hide-read toggle (server-rendered). 4. Tests for the DB and routing logic. Unblocks #5: the `r` (toggle read) and `h` (next unread) shortcuts assume this exists.
Author
Collaborator

Design decisions (resolving the open questions)

  1. Group read state is computed, not stored — a group is read iff all member articles are read (unread_count == 0, already computed in _build_aggregate_row). "Mark group as read" marks all current member articles; a group that receives a new article later shows unread again automatically. No schema change.
  2. POST /aggregate/<id>/read marks all member articles read and redirects back to the aggregate page (POST-redirect-GET, works from a plain form with no JS). The existing per-article read/unread endpoints stay JSON — they are the API #5's keyboard shortcuts will call.
  3. Hide-read toggle = ?hide_read=1 query param, fully server-rendered toggle links, default off (show everything). Reader index hides fully-read aggregates; aggregate view hides read articles with an empty state when everything is read. Persistence as a default preference comes later via #8's settings store.
## Design decisions (resolving the open questions) 1. **Group read state is computed, not stored** — a group is read iff all member articles are read (`unread_count == 0`, already computed in `_build_aggregate_row`). "Mark group as read" marks all current member articles; a group that receives a new article later shows unread again automatically. No schema change. 2. **`POST /aggregate/<id>/read`** marks all member articles read and redirects back to the aggregate page (POST-redirect-GET, works from a plain form with no JS). The existing per-article read/unread endpoints stay JSON — they are the API #5's keyboard shortcuts will call. 3. **Hide-read toggle = `?hide_read=1` query param**, fully server-rendered toggle links, default off (show everything). Reader index hides fully-read aggregates; aggregate view hides read articles with an empty state when everything is read. Persistence as a default preference comes later via #8's settings store.
Author
Collaborator

Resolved by PR #24 (merged): computed group read state via mark-all-members route with POST-redirect-GET, and the hide-read toggle (?hide_read=1) on both the reader index and aggregate view. Toggle persistence as a default rides on the #25/#8 settings store later.

Resolved by PR #24 (merged): computed group read state via mark-all-members route with POST-redirect-GET, and the hide-read toggle (`?hide_read=1`) on both the reader index and aggregate view. Toggle persistence as a default rides on the #25/#8 settings store later.
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
marvin8/yunjin#18
No description provided.