trails/openspec/changes/notifications/specs/social-follows/spec.md
Ullrich Schäfer 95ac79b093 Propose: notifications
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>
2026-04-26 00:12:35 +02:00

24 lines
1.2 KiB
Markdown

## ADDED Requirements
### Requirement: Follow lifecycle emits notifications
The follow lifecycle SHALL produce notifications for the recipient of the social event (see `notifications` spec):
- Auto-accepted public follow → `follow_received` to the followed user.
- Approved Pending request → `follow_request_approved` to the follower (now accepted).
- Reject and unfollow do NOT produce notifications.
#### Scenario: Public auto-accept notifies the target
- **WHEN** a user follows another user whose `profile_visibility = 'public'` (auto-accept path)
- **THEN** a `follow_received` notification is created for the followed user
#### Scenario: Approval notifies the requester
- **WHEN** a private user approves a Pending follow request
- **THEN** a `follow_request_approved` notification is created for the follower
#### Scenario: Reject does not notify
- **WHEN** a private user rejects a Pending follow request
- **THEN** no notification is created (silent rejection — the follower can re-request later if they want)
#### Scenario: Unfollow does not notify
- **WHEN** a follower unfollows or cancels a Pending request
- **THEN** no notification is created on the followed side