Skip to content

Feat/resource watches: Users can watch resource paths and stream the bell#308

Open
St4NNi wants to merge 20 commits into
feat/notificationsfrom
feat/resource-watches
Open

Feat/resource watches: Users can watch resource paths and stream the bell#308
St4NNi wants to merge 20 commits into
feat/notificationsfrom
feat/resource-watches

Conversation

@St4NNi

@St4NNi St4NNi commented Jul 6, 2026

Copy link
Copy Markdown
Member

Users subscribe to events on resource path prefixes and see matches in the bell as a transient activity feed. Subscriptions live on the user's notification inbox holder, holders publish their interest realm-wide, origin nodes match events locally and forward one record per interested holder, and the holder expands matches into per-subscriber inbox rows. Also adds the SSE stream endpoint so the bell updates live.

Stacked on #307 (feat/notifications); diff shows only the resource-watch commits.

Changes

  • Adds watch subscription records and a keyspace on the user's notification inbox holder.
  • Adds watch subscription CRUD on the holder with a per-user cap of 50 and normalized path prefixes; the path scheme is plain string-prefix matching on {bucket}/{key} and meta/{group_id}/{document_id}.
  • Adds GET/POST /api/v1/notifications/watches and DELETE /api/v1/notifications/watches/{id}, served from any node via holder proxy over the notification transport.
  • Adds a per-holder watch interest digest document with generation-stamped dirty markers, published debounced and last-write-wins realm-wide over document sync, mirroring the node-usage snapshots.
  • Maintains an in-memory interest table on every node, refreshed from the reconcile handlers, so event matching never reads storage.
  • Adds metadata_created and data_uploaded notification kinds.
  • Emits watch events best-effort post-success from object put, multipart completion, and metadata create; an unmatched event writes nothing and the notification path can never fail the host operation.
  • Forwards one node-addressed record per interested holder through a durable forward outbox; the holder expands it to per-subscriber transient inbox rows (30-day TTL, shared prune task) with deterministic record ids, so redelivery is idempotent and raw events are never persisted.
  • Adds GET /api/v1/notifications/stream (SSE): a wake signal fires on fresh inbox writes and mark-read, the stream pushes unread counts when the holder is local, degrades to 5s holder-polling when remote, and re-resolves the holder every 60s so it survives re-ranking.
  • Surfaces the capped flag in SSE unread events.
  • Retries watch subscription deletes on transaction conflicts.
  • Adds multi-node integration tests: a watch created via node A fires for an upload handled by node B and is visible via node C, unmatched events write nothing, and interest digests converge and retract. Plus unit coverage for routing, idempotent expansion, transport trust gating, and the SSE arms.

GitHub Issues

Notes

Known alpha limitations, called out deliberately:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant