Notification generation and in-app notification center #94
Labels
No Label
area:auth
area:docs
area:export
area:ops
area:storage
area:supply-chain
auth
backend
blocked
collab
deployment
docs
effort:L
effort:M
effort:S
frontend
plugins
qa
vs-nfd
vs-nfd:blocker
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stwaidele/dorfteich#94
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Watchers are notified about page changes and new comments; the center makes it visible in-app.
Scope
Notification generation: on version snapshot creation (#41 — meaningful change unit, not per keystroke) and on new comments, fan out to watchers (excluding the actor) into
notifications; API: list (paginated, unread first), mark read/all-read; UI: bell icon with unread badge, dropdown center (actor, page, type, time; click navigates and marks read); low-frequency polling (30 s) — no push infrastructure in v1.Acceptance criteria
Technical notes
Dependencies
Depends on #41, #91, #93.
Size: ~2 days
Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add
deanden), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.Implemented in
67fb01f(pipeline green, 8/8; migration20260712000000_notificationsauto-applied on Test + Int).Generation —
NotificationsService.fanoutPageEvent(type, pageId, actorIds): everyone watching the page or its pond, minus all actors, and per watcher a read-permission re-check at delivery time (a revoked watcher gets nothing). Payload is denormalized (page/pond names + slugs, actor display names) so the center renders without joins. Never throws — a notification failure cannot break the write that caused it. Sources:VersionsService; the automatic session-close snapshots live in the collab server, which has no permission resolution — it now announces them over a new pg NOTIFY channel (page_version_created, the reverse direction of the established api→collab LISTEN/NOTIFY bus), consumed by a dedicated LISTEN client in the api (VersionEventListener, own pg connection since Prisma cannot hold LISTEN; auto-reconnect; inert under NODE_ENV=test).CommentsService.create.API —
GET /notifications(paginated, unread first via nulls-first ordering, withunreadCount),POST /notifications/:id/read(owner-scoped, 404 for foreign ids),POST /notifications/read-all.UI — bell in the top bar with an unread badge, 30 s polling (no push in v1); the dropdown lists actor/page/type/time, entries navigate and mark themselves read, plus mark-all-read. Comment notifications deep-link with
?comments=1, which the page now honors by opening the comments panel on load. Newnotificationsnamespace (de+en).mailed_atis already on the table for the #95 digests.Acceptance criteria (in
notifications.e2e.db.test.ts, 4 tests):…?comments=1and the page opens the panel.