Closes the social loop opened by social-feed: a Pending follower has no way to know their request was approved, and a follower has no signal at all that someone they follow just posted. Adds a notifications surface for three v1 event types — follow_request_approved, follow_received, activity_published — plus a /notifications page, navbar unread count, and mark-as-read controls. Capabilities: - New: notifications (table, page, badge, generation hooks) - Modified: social-follows (approve + auto-accept emit) - Modified: activity-feed (public create fans out) - Modified: journal-landing (nav entry alongside follow-requests) Design picks: - Fan-out-on-write for activity_published (1:N) so /notifications is a flat single-table query and "mark read" composes trivially. 1:1 events insert directly. Cost ceiling documented at 10k followers × 50 activities/day = 500k/day, still trivial; revisit only if hot. - Single notifications table with loose subject_id (no per-type FK); renderer dereferences by type. Mastodon-style. - Two distinct nav entries (Follow requests + Notifications). Pending is "act on this", notifications is "this happened" — different semantics, kept separate. - Loader-driven unread count (no real-time channel). Real-time is deferred. - 90-day retention for read rows; unread kept indefinitely. Out of scope: per-type mute preferences, email/push, real-time, notifications about routes/replies/mentions, federated notifications. Each tracked as follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
861 B
861 B
ADDED Requirements
Requirement: Notifications entry in the navbar
The navbar SHALL render a "Notifications" entry for signed-in users, linking to /notifications. It SHALL render an unread count badge when the user has at least one unread notification, and no badge when the count is zero. This entry SHALL be distinct from the existing "Follow requests" entry — they cover different categories (informational vs. actionable).
Scenario: Signed-in user sees the entry
- WHEN a signed-in user loads any page
- THEN the navbar includes a "Notifications" link to
/notifications, and a count badge if the user has unread rows
Scenario: Anonymous user does not see the entry
- WHEN an unauthenticated visitor loads any page
- THEN the navbar does not include the Notifications entry (the route requires authentication anyway)