# What is this?
Inovus Notifications is a standalone in-app notification service. Think of it as a shared mailbox that any Inovus product can write into, and that every signed-in user can read from.
# The problem it solves
Most products eventually need something like:
“Tell this user that their review is ready — and let them see it later in a bell dropdown, mark it read, or click through.”
Without a shared service, every app invents its own table, its own webhook, its own half-broken polling, and its own security shortcuts. That’s what V1 looked like inside Video Library: it worked for one app, then became hard to reuse safely.
V2 is that capability extracted into one place — so Assess, Video Library, and future apps share one inbox model, one auth story, and one npm client.
# What you get
| Capability | In plain English |
|---|---|
| Publish | A backend (or privileged caller) creates a notification for a user |
| Inbox | That user lists their notifications, newest first |
| Badge | Cheap unread count for the bell icon |
| Lifecycle | Mark one/all read, mark unread, delete |
| Idempotency | Safe retries via dedupeKey (no double notifications) |
| Live-ish updates | Client polls ~every 30s with cheap 304 Not Modified responses |
| Typed client | @inovus-medical/notifications handles tokens, retries, and polling |
# What it is not
Being clear about boundaries saves a lot of confusion:
| Not this service | Where it lives instead |
|---|---|
| Toast / snackbar UI (“Saved!” for 3 seconds) | Your app’s toast library |
| Bell dropdown styling / Totum branding | Your app’s UI components |
| Click-to-navigate routing | Your app reads actionUrl and navigates |
| Email, SMS, or push notifications | Out of scope (for now) |
| Instant WebSocket “realtime” | Honest polling (~30s by default) |
| User login / Cognito pools | You already have those — we verify the tokens |
Tip: If all you need is a temporary success banner after a button click, use a toast. If the user should still see the message after refreshing the page, use this service.
# Mental model
Every notification is a small record addressed to one user:
┌─────────────────────────────────────────────┐
│ Notification │
│ • who: userGuid (Cognito sub) │
│ • what: title + body │
│ • tone: severity (info/success/…) │
│ • where: optional actionUrl │
│ • from: source (derived from the token) │
│ • dedupe: optional dedupeKey │
│ • state: read / unread │
└─────────────────────────────────────────────┘
Users only ever see their own inbox. Publishers can write to any user (with the right token). Regular users can also create a notification for themselves via a safe self-publish path (handy for “job finished in this browser” style flows).
# Who talks to whom?
sequenceDiagram participant Job as Backend job participant API as Notifications API participant DB as Database participant App as Browser app participant User as End user Job->>API: POST /v1/notifications (M2M token) API->>DB: store row for userGuid API-->>Job: 201 created User->>App: opens app / looks at bell App->>API: GET /v1/notifications (user token) API->>DB: list for token.sub API-->>App: items + unreadCount App-->>User: render bell UI
# Roles (very important)
| Role | Who | What they can do |
|---|---|---|
| User | Anyone with a valid Cognito access token | Read/manage own inbox; optionally self-publish to themselves |
| Publisher | M2M app client (scope) or user in a publisher group | Publish notifications to any user |
Regular end users do not need publisher privileges just to see the bell. That’s intentional.
# Is this for me?
Yes, if you:
- Need persistent in-app notifications across one or more Inovus apps
- Already authenticate users with Cognito
- Want retries and polling handled for you
Maybe later / not yet, if you:
- Only need ephemeral toasts
- Need true push/SSE latency under a second (polling is the current design)
- Need email/SMS channels
When you’re ready to try it in code, continue to Getting started. To understand the pieces first, see Components.