create mvp path
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# notifications — the in-app feed and unread badge
|
||||
|
||||
> Client seam `client/src/services/notifications/` · `USE_NOTIFICATIONS_MOCK = false` (**real**) · 4 server ops
|
||||
> Last verified: 2026-07-30 against commit `d3ec723` and swagger.v1.json (2026-07-29).
|
||||
|
||||
Server-raised, user-scoped notifications. In-app only — there is no push channel and no email channel.
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Verdict |
|
||||
| --- | --- | --- |
|
||||
| GET | `/api/v1/notifications/get_notifications` | wired · paginated |
|
||||
| GET | `/api/v1/notifications/get_unread_count` | wired — polled for the bell badge |
|
||||
| POST | `/api/v1/notifications/mark_notification_read` | wired |
|
||||
| POST | `/api/v1/notifications/mark_all_read` | wired |
|
||||
|
||||
All `[Authorize]`. No phantoms. The domain maps 1:1.
|
||||
|
||||
## Shape rules the JSON does not express
|
||||
|
||||
- **`dataJson` is a string containing JSON**, not an object. It is the deep-link payload: the client parses
|
||||
it (`parse.ts`) and resolves a route from it (`deepLink.ts`), both with unit tests, and **falls back to
|
||||
an inert notification rather than throwing** on anything unrecognised. A notification whose payload
|
||||
cannot be parsed still renders — it just is not tappable.
|
||||
- **Unread count is a separate read, not derived from the list.** The badge must be correct without
|
||||
fetching a page, so `get_unread_count` is its own cheap query.
|
||||
- **`mark_all_read` is a bulk write**; the client invalidates both the list and the count keys, and does not
|
||||
patch items locally.
|
||||
- The feed is **day-grouped in the UI** with Shamsi headers — a client-side transform over UTC
|
||||
`createdAt`. The server sends no grouping.
|
||||
- Notifications are raised through a self-committing facade (`DispatchAsync`) that runs **after** the
|
||||
originating handler's `CommitAsync` — so a notification never exists for a transaction that rolled back.
|
||||
|
||||
## Enums
|
||||
|
||||
`type` is a **bare string** on the wire and the vocabulary is open-ended by design — new server-side
|
||||
notification types must not break an older client. The client models the *payload* as a discriminated
|
||||
union (`NotificationData`, keyed on a `kind` inside `dataJson`) and treats an unknown `type` as
|
||||
non-actionable rather than an error.
|
||||
|
||||
Consequence for the server: **adding a notification type is safe; changing an existing type's `dataJson`
|
||||
shape is not.** The deep-link parser keys off the payload, not the type string.
|
||||
|
||||
## Open REQs
|
||||
|
||||
| REQ | Status | Effect |
|
||||
| --- | --- | --- |
|
||||
| REQ-054 | deferred, non-blocking | No web push for new booking requests. The nurse dashboard's 15 s poll remains the only signal. Nothing was built for it |
|
||||
Reference in New Issue
Block a user