docs(website): per-channel notification preferences (engagement Phase 3) #182

Merged
whitlocktech merged 1 commits from docs/engagement-channel-prefs into edge 2026-08-29 12:11:06 +00:00
Member

Companion to website#169. The documentation §6.0b assigns Phase 3 — BACKEND_DESIGN.md's route table and android/PLAN.md §11 — plus the phase's as-built section and one correction the build forced.

ENGAGEMENT.md

  • Phase 3's as-built: the three decisions settled before any code, why the channel registry could not wait for Phase 6, what the sparse PUT buys, the projection stated as an invariant, and the staff-ceiling filter.
  • The phase's own acceptance line was wrong and is struck through. "A fresh user's … push defaults instant" reads naturally beside §3.1's "email opt-IN, push opt-OUT" — but §3.1 borrowed that from team_notification_prefs, where no row genuinely does mean notified. Push stream subscriptions have never worked that way (notification_subscriptions holds a row only on opt-in), so instant would have projected the entire catalog into the legacy GET for every existing user and switched every toggle on in the shipped app. §3.1's own comment is corrected in the same pass rather than left to contradict the phase below it.
  • Status line and the Phase 3 heading marked built.

BACKEND_DESIGN.md

  • The /me/notifications/channels route row: the union catalog, the effective-mode semantics, the sparse PUT and its drop-don't-refuse posture.
  • The notification_channel_prefs table entry — including that absence means the channel's default, not off, and that all three channels agreeing on off today is a fact about the declarations rather than about the table, which code must not assume.
  • A note on notification_subscriptions that it is now the push projection and stays what utils/pushDispatch reads.

android/PLAN.md §11

Nothing above the new section changed — the shipped APK keeps working and the {"streams":[]} gotcha still applies to that endpoint. What the new section tells whoever adopts the superset endpoint:

  • render the toggles from each item's channels, never a hardcoded three — a trigger-only id has no push
  • modes is the effective mode; the client must not re-implement the defaulting
  • the PUT is sparse, so the empty-array gotcha does not apply hereoff is a row like any other
  • one id may be missing that the app expects: a staff-ceilinged trigger is not offered to a non-staff caller

  • AI-assisted: written with Claude Code (Opus)

🤖 Generated with Claude Code

Companion to **website#169**. The documentation §6.0b assigns Phase 3 — `BACKEND_DESIGN.md`'s route table and `android/PLAN.md` §11 — plus the phase's as-built section and one correction the build forced. ## `ENGAGEMENT.md` - **Phase 3's as-built**: the three decisions settled before any code, why the channel registry could not wait for Phase 6, what the sparse PUT buys, the projection stated as an invariant, and the staff-ceiling filter. - **The phase's own acceptance line was wrong and is struck through.** "A fresh user's … push defaults `instant`" reads naturally beside §3.1's "email opt-IN, push opt-OUT" — but §3.1 borrowed that from `team_notification_prefs`, where no row genuinely *does* mean notified. Push **stream** subscriptions have never worked that way (`notification_subscriptions` holds a row only on opt-in), so `instant` would have projected the entire catalog into the legacy GET for every existing user and switched every toggle on in the shipped app. §3.1's own comment is corrected in the same pass rather than left to contradict the phase below it. - Status line and the Phase 3 heading marked built. ## `BACKEND_DESIGN.md` - The `/me/notifications/channels` route row: the union catalog, the effective-mode semantics, the sparse PUT and its drop-don't-refuse posture. - The `notification_channel_prefs` table entry — including that **absence means the *channel's* default, not `off`**, and that all three channels agreeing on `off` today is a fact about the declarations rather than about the table, which code must not assume. - A note on `notification_subscriptions` that it is now the push projection and stays what `utils/pushDispatch` reads. ## `android/PLAN.md` §11 **Nothing above the new section changed** — the shipped APK keeps working and the `{"streams":[]}` gotcha still applies to that endpoint. What the new section tells whoever adopts the superset endpoint: - render the toggles from each item's `channels`, never a hardcoded three — a trigger-only id has no push - `modes` is the **effective** mode; the client must not re-implement the defaulting - the PUT is sparse, so the empty-array gotcha **does not apply here** — `off` is a row like any other - one id may be missing that the app expects: a `staff`-ceilinged trigger is not offered to a non-staff caller --- - [x] AI-assisted: written with Claude Code (Opus) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wtclaude added 1 commit 2026-08-29 12:09:38 +00:00
The documentation §6.0b assigns Phase 3 — `BACKEND_DESIGN.md`'s route table and
`android/PLAN.md` §11 — plus the phase's as-built section and one correction the
build forced.

`ENGAGEMENT.md`:
- Phase 3's as-built: the three decisions settled before any code, why the
  channel registry could not wait for Phase 6, what the sparse PUT buys, the
  projection stated as an invariant, and the staff-ceiling filter.
- **The phase's own acceptance line was wrong and is struck through.** "A fresh
  user's … push defaults `instant`" reads naturally beside §3.1's "email opt-IN,
  push opt-OUT", but §3.1 borrowed that from `team_notification_prefs`, where no
  row genuinely does mean notified. Push STREAM subscriptions have never worked
  that way — `notification_subscriptions` holds a row only on opt-in — so
  `instant` would have projected the entire catalog into the legacy GET for
  every existing user. §3.1's comment is corrected in the same pass.

`BACKEND_DESIGN.md`: the `/me/notifications/channels` row, the
`notification_channel_prefs` table entry (including that absence means the
channel's default rather than `off`, and that all three agreeing on `off` today
is a fact about the declarations and not about the table), and a note on
`notification_subscriptions` that it is now the push projection.

`android/PLAN.md` §11: nothing above it changed — the shipped APK keeps working
and the `{"streams":[]}` gotcha still applies to that endpoint. The new section
documents the superset endpoint for whenever the app adopts it: render toggles
from each item's `channels` rather than a hardcoded three, `modes` is the
effective mode and the client must not re-implement the defaulting, the PUT is
sparse so the empty-array gotcha does NOT apply here, and one id may be missing
that the app expects (a `staff`-ceilinged trigger is not offered to a non-staff
caller).

Companion to website#169.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech merged commit 713e6fa6c8 into edge 2026-08-29 12:11:06 +00:00
whitlocktech deleted branch docs/engagement-channel-prefs 2026-08-29 12:11:07 +00:00
Sign in to join this conversation.
No description provided.