[Feature] Notifications: a bell with an unread badge, a notification history, and delivery settings per person #655

Closed
opened 2026-09-15 18:08:21 +00:00 by claude-bot · 2 comments
Collaborator

Context

Discussions (#654) need this: a new group question notifies everyone. Several v4.6.0 issues need it as well:

  • #121: a flag has to reach the GM
  • #122: the prompt after a session
  • #123: a handout given to one player

What exists today:

  • Email over SMTP, configured in Admin. It sends recap emails, controlled by a per-user users.recap_email_opt_in and a per-campaign recap_email_enabled, plus iCalendar invites (#189).
  • Posts to the campaign's Discord channel through the bot.
  • Needs you (GET /api/users/me/attention, #368).

There is no in-app history of what you were notified about, and no general preferences model.

Decisions (owner, 2026-09-15)

  • A bell in the corner of the top bar, with a red badge when anything is unread. Opening it lists everything you have been notified of, newest first.
  • Delivery is each person's choice. In their own settings, people decide whether to also get alerts by email or through any other channel that can send them.
  • This absorbs #12 (notification preference granularity). #11 (the weekly digest) stays in v5.4.0 as a delivery option built on this.
  • It ships in v4.6.0 with #654. The redesign (#366) leaves room for the bell in the top bar now, rather than adding it later.

Design

  • The bell is not Needs you. Needs you is what is waiting on you, and it empties as you act. The bell is a history of what happened. One event can be in both: "a new question for you" is a notification, and while it is unanswered it is also in Needs you.

  • A notification stores:

    • the recipient and campaign
    • the event type
    • a reference to its subject (a thread, post, session or article)
    • when it was created and when it was read

    Its text is built when it is opened, from the subject and with the reader's permissions. If the reader can no longer see the subject, the entry says it is no longer available rather than showing what it once said.

  • Recipients are worked out on the server with the shared audience model (#593). Nobody is notified about something they cannot see.

  • Delivery channels are small adapters, so adding one later is easy:

    • in-app, always
    • email, through the existing SMTP path
    • Discord DMs, through the bot (the backend never calls Discord itself)
    • browser push, later, for the installed PWA

    External alerts carry a short line and a link, never the content, so a GM's secret is never copied into someone's inbox.

  • Settings stay simple, following #12's rule: campaign settings enable a capability, and personal settings opt in or out. Rather than a toggle for every event:

    • a few categories (Sessions, Discussions, Wiki, GM tasks)
    • a channel choice for each
    • a mute for each campaign
  • Existing behaviour carries over. Today's recap-email opt-in becomes a setting in the new model, and nobody's current email changes on the day this ships.

  • Delivery happens in the background (Celery). It must be safe to retry, so one notification is sent at most once per channel.

Out of scope

  • The weekly digest (#11).
  • The content of Discord embeds (v5.4.0).
  • Browser push, for now.

Acceptance criteria

  • The bell and unread count are in the top bar on phone and desktop. Opening it lists notifications, and one or all can be marked read.
  • A test shows that no notification reaches someone outside its subject's audience.
  • Email follows each person's settings, and existing recap-email opt-ins behave exactly as before.
  • A subject the recipient can no longer see shows as unavailable in their history, without its old text.
  • #654's rules hold: a new group thread notifies every member, and replies notify only followers.
## Context Discussions (#654) need this: a new group question notifies everyone. Several v4.6.0 issues need it as well: - #121: a flag has to reach the GM - #122: the prompt after a session - #123: a handout given to one player What exists today: - **Email over SMTP**, configured in Admin. It sends recap emails, controlled by a per-user `users.recap_email_opt_in` and a per-campaign `recap_email_enabled`, plus iCalendar invites (#189). - **Posts to the campaign's Discord channel** through the bot. - **Needs you** (`GET /api/users/me/attention`, #368). There is no in-app history of what you were notified about, and no general preferences model. ## Decisions (owner, 2026-09-15) - **A bell in the corner of the top bar,** with a red badge when anything is unread. Opening it lists everything you have been notified of, newest first. - **Delivery is each person's choice.** In their own settings, people decide whether to also get alerts by email or through any other channel that can send them. - **This absorbs #12** (notification preference granularity). **#11** (the weekly digest) stays in v5.4.0 as a delivery option built on this. - **It ships in v4.6.0 with #654.** The redesign (#366) leaves room for the bell in the top bar now, rather than adding it later. ## Design - **The bell is not Needs you.** Needs you is what is waiting on you, and it empties as you act. The bell is a history of what happened. One event can be in both: "a new question for you" is a notification, and while it is unanswered it is also in Needs you. - **A notification stores:** - the recipient and campaign - the event type - a reference to its subject (a thread, post, session or article) - when it was created and when it was read **Its text is built when it is opened,** from the subject and with the reader's permissions. If the reader can no longer see the subject, the entry says it is no longer available rather than showing what it once said. - **Recipients are worked out on the server** with the shared audience model (#593). Nobody is notified about something they cannot see. - **Delivery channels are small adapters,** so adding one later is easy: - in-app, always - email, through the existing SMTP path - Discord DMs, through the bot (the backend never calls Discord itself) - browser push, later, for the installed PWA External alerts carry a short line and a link, never the content, so a GM's secret is never copied into someone's inbox. - **Settings stay simple,** following #12's rule: campaign settings enable a capability, and personal settings opt in or out. Rather than a toggle for every event: - a few categories (Sessions, Discussions, Wiki, GM tasks) - a channel choice for each - a mute for each campaign - **Existing behaviour carries over.** Today's recap-email opt-in becomes a setting in the new model, and nobody's current email changes on the day this ships. - **Delivery happens in the background** (Celery). It must be safe to retry, so one notification is sent at most once per channel. ## Out of scope - The weekly digest (#11). - The content of Discord embeds (v5.4.0). - Browser push, for now. ## Acceptance criteria - The bell and unread count are in the top bar on phone and desktop. Opening it lists notifications, and one or all can be marked read. - A test shows that no notification reaches someone outside its subject's audience. - Email follows each person's settings, and existing recap-email opt-ins behave exactly as before. - A subject the recipient can no longer see shows as unavailable in their history, without its old text. - #654's rules hold: a new group thread notifies every member, and replies notify only followers.
Author
Collaborator

The core of this shipped early, as lane 1 of the redesign's server change (#744, merged 2026-09-22), because the new shell's bell needed a store: notifications with a reference to the subject rather than text, recipients worked out on the server, the text rendered at read time with the reader's current permissions ("No longer available" when they may no longer see it), in-app always, email through the existing SMTP path carrying a line and a link and never the content, at most once per channel, the settings grid (Sessions, Discussions, Wiki, GM tasks against email and a not-yet-delivered Discord DM channel) and a mute per campaign. Today's recap_email_opt_in was carried over as the (sessions, email) setting and the recap email is unchanged.

Still to come here: the Discussions kinds (with #654), Discord DM delivery through the bot, and the settings page itself (lane 1's You PR, HOME-6). The bell is in the app bar on every signed-in page since #742.

The core of this shipped early, as lane 1 of the redesign's server change (#744, merged 2026-09-22), because the new shell's bell needed a store: `notifications` with a reference to the subject rather than text, recipients worked out on the server, the text rendered at read time with the reader's current permissions ("No longer available" when they may no longer see it), in-app always, email through the existing SMTP path carrying a line and a link and never the content, at most once per channel, the settings grid (Sessions, Discussions, Wiki, GM tasks against email and a not-yet-delivered Discord DM channel) and a mute per campaign. Today's `recap_email_opt_in` was carried over as the `(sessions, email)` setting and the recap email is unchanged. Still to come here: the Discussions kinds (with #654), Discord DM delivery through the bot, and the settings page itself (lane 1's You PR, HOME-6). The bell is in the app bar on every signed-in page since #742.
Author
Collaborator

Closing, with the one gap moved to #1000. Checked against main on 1 Oct. (The 22 Sep comment's "still to come" list is out of date: all three items exist now.)

Built, across lane 1 (#744), lane 7 and lane 10 (#736):

  • The bell on every signed-in page, with an unread count, mark one or all read.
  • A stored notification names its subject and its words are made when read; something the reader can no longer see says "No longer available".
  • Recipients are worked out on the server; nobody outside the audience is told.
  • Three channels: in the app, email (a line and a link, never content), and Discord DMs through the bot.
  • Per-person settings: kinds against channels, and a mute per campaign. The old recap opt-in carried over.
  • Each channel sends at most once per notification, safely on retry.

Not built: the bell lists the 20 newest and nothing reaches older ones, though the API pages. That is #1000. Browser push and the weekly digest (#11) were out of scope.

Closing, with the one gap moved to #1000. Checked against main on 1 Oct. (The 22 Sep comment's "still to come" list is out of date: all three items exist now.) **Built**, across lane 1 (#744), lane 7 and lane 10 (#736): - The bell on every signed-in page, with an unread count, mark one or all read. - A stored notification names its subject and its words are made when read; something the reader can no longer see says "No longer available". - Recipients are worked out on the server; nobody outside the audience is told. - Three channels: in the app, email (a line and a link, never content), and Discord DMs through the bot. - Per-person settings: kinds against channels, and a mute per campaign. The old recap opt-in carried over. - Each channel sends at most once per notification, safely on retry. **Not built:** the bell lists the 20 newest and nothing reaches older ones, though the API pages. That is #1000. Browser push and the weekly digest (#11) were out of scope.
Sign in to join this conversation.
No project
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.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#655
No description provided.