# Roadmap — what V3 onwards might include
Planning document, not a delivery commitment. It frames where V2 sits today, what modern notification platforms typically provide, and which capabilities are plausible next steps for this service if product demand appears.
For architecture of the current system, see DESIGN.md. For resilience options already sketched, see High availability.
# Where we are (V2)
V2 is a standalone in-app notification inbox:
| Capability | Status |
|---|---|
| Server/API-key publish to a user inbox | Done |
| User list / unread / mark read / delete | Done |
Idempotent publish (dedupeKey) |
Done |
| OIDC auth + publisher scopes / API keys | Done |
| Typed npm client (retry, ETag polling, React hooks) | Done |
| Legacy product V1 HTTP compatibility | Done (/api/Notification/*) |
| Email, SMS, push, WhatsApp, Slack | Out of scope |
| User preferences / mute / digest | Out of scope |
| Realtime push (WebSocket / SSE) | Out of scope (polling + ETag) |
| Pre-built bell UI / preference centre | Out of scope |
| Workflows, templates, campaigns | Out of scope |
That is intentional. V2 fixed the embedded Video Library inbox (auth, dedupe, standalone service, client reliability). It is product notification infrastructure for an in-app feed, not a full multi-channel engagement suite.
Current HTTP surface: /v2/notifications…. A future major API would likely live under /v3 (or stay compatible and version capabilities behind feature flags) — naming is TBD when the first breaking change is real.
# What “modern notification platforms” are
Industry products fall into two layers people often confuse:
┌─────────────────────────────────────────────────────────────┐
│ Notification infrastructure (orchestration) │
│ Knock · Novu · Courier · SuprSend · similar │
│ workflows · preferences · templates · in-app feed · │
│ fan-out · digests · provider failover · observability │
└───────────────────────────┬─────────────────────────────────┘
│ hands off delivery to
┌───────────────────────────▼─────────────────────────────────┐
│ Channel providers (pipes) │
│ Email: SES / Resend / Postmark / SendGrid │
│ SMS: Twilio / MessageBird │
│ Push: FCM / APNs / OneSignal │
│ Chat: Slack / Teams / WhatsApp Business │
└─────────────────────────────────────────────────────────────┘
Orchestration platforms (Knock, Novu, Courier, etc.) typically sell:
- One trigger API — fire an event; the platform decides channels, order, and fallbacks.
- Workflows — delays, conditions, batching/digests, cancel-on-read, branch on open/click.
- Templates — per-channel copy/layout; often editable by non-engineers.
- Preferences — per-user (and often per-tenant) channel and category opt-in/out, quiet hours.
- In-app feed + UI kits — bell, feed, preference centre components.
- Multi-channel delivery — email, SMS, push, chat, webhooks — via your provider accounts.
- Observability — per-message timeline: queued → sent → delivered → opened → failed.
- Tenancy / environments — sandbox vs prod, tenant branding, RBAC for operators.
Engagement / marketing platforms (Braze, OneSignal journeys, Klaviyo-style) emphasise campaigns, segments, and growth metrics more than transactional product events. Inovus products are closer to the transactional / product-notification side (case updates, assessments, reviews) than broadcast marketing.
V2 today is roughly the in-app feed + publish API slice of an orchestration platform — without channels, workflows, or preference UI.
# Capability map — us vs typical platforms
| Capability | Typical platforms | Inovus V2 | Candidate for V3+? |
|---|---|---|---|
| In-app inbox CRUD | Yes | Yes | Extend (archive, categories) |
| Idempotent / deduped events | Common | Yes (dedupeKey) |
Keep as core contract |
| Multi-channel send | Core product | No | High interest if apps need email/push |
| Workflows / journeys | Core product | No | Medium — only if producers outgrow code |
| User preference centre | Core product | No | High — before any second channel |
| Digests / batching | Common | No | Medium — reduces noise |
| Realtime inbox updates | Common | Polling | Medium — SSE when latency matters |
| Drop-in React bell UI | Common | Data hooks only | Medium — optional package |
| Templates (email/push) | Common | No | With channels |
| Delivery receipts / activity log | Common | API logs only | Medium — ops + support |
| Batch / bulk publish | Common | Loop + dedupe | Low until a producer needs it |
| Tenant branding / isolation | B2B focus | Multi-issuer ready; one DB | Later — true multi-tenant |
| Marketing campaigns / segments | Engagement tools | No | Likely never (wrong product) |
# Guiding principles for V3+
- Stay the system of record for the inbox — even if email/push are added, the in-app row should remain the durable “what the user was told” record unless we deliberately split concerns.
- Preferences before channels — shipping email without mute/category controls creates support load and compliance risk (especially in healthcare-adjacent products).
- Orchestrate, don’t own every pipe — prefer adapters to SES/FCM/Twilio over building SMTP or APNs ourselves.
- Demand-driven milestones — DESIGN.md’s YAGNI list still applies; build when a named producer or product has a concrete need.
- Don’t become a marketing cloud — segments, A/B campaigns, and growth analytics belong elsewhere unless the business explicitly pivots.
# Candidate themes (V3 onwards)
Themes are ordered by how often real products hit them, not by a fixed release train. Several can ship as additive V2.x features; only breaking contract changes need a hard /v3.
# 1. Richer inbox semantics
Why: Users and apps outgrow binary read/unread.
Possible additions:
- Categories / topics (
assessment,system,billing) for filtering and preferences - Archive / snooze (soft state; retention still applies)
- Severity-driven sorting or “needs attention” views
- Actor / subject fields (who did what to which entity) beyond opaque
metadata - Expiry / TTL per notification (in addition to global retention cron)
Trigger: Multiple apps need shared filter UI, or support asks for “hide without delete”.
# 2. User preferences and quiet hours
Why: Table stakes once anything leaves the in-app feed; also useful for in-app-only mute of noisy categories.
Possible model:
- Per user: global mute, per-category channel matrix (in-app / email / push)
- Quiet hours + timezone
- Default policies per
sourceor category (e.g. security alerts cannot be fully muted)
Trigger: Before first outbound email/SMS/push goes live.
# 3. Multi-channel delivery (email → push → chat)
Why: Users aren’t always in the SPA; clinical and ops workflows often need email or mobile push.
Possible shape:
Publish event
→ create/update in-app notification (always, if preference allows)
→ enqueue channel jobs (email / push / …) honouring preferences
→ provider adapters + retries + dead-letter
Phased rollout that matches industry practice:
| Phase | Channels | Notes |
|---|---|---|
| A | Email (transactional) | Highest value for B2B SaaS; SES/Resend/Postmark |
| B | Web Push / mobile push | Needs device token registry |
| C | Slack / Teams | Useful for staff tools, not patients |
| D | SMS / WhatsApp | Costly; reserve for high-urgency |
Keep provider failover and per-message delivery status in mind from day one of channel work, even if v1 of channels is email-only.
Trigger: A product owner requires “email me when X” with a real volume estimate.
# 4. Workflows, digests, and cancellation
Why: Modern platforms differentiate on logic, not just send.
Examples relevant to Inovus:
- Digest: “N new assessment comments in the last hour” → one email + one inbox item
- Delay + cancel: remind in 24h unless the case was already opened
- Escalation: in-app first; email if still unread after N hours
- Fan-out: one domain event → many recipients (batch API or queue)
Implementation options:
- Code-owned workflows in producer apps (simplest; stays YAGNI-friendly)
- Declarative workflows in this service (Knock/Novu-style) when many apps need the same patterns
Trigger: Three or more producers re-implement the same delay/digest/escalate logic.
# 5. Realtime delivery
Why: Polling is proven and cheap; some UX wants sub-second bell updates.
Options already noted in DESIGN.md / HA docs:
- SSE or WebSocket via Cloudflare Durable Objects (or similar), behind the existing client
subscribe()API - Supabase Realtime only if we accept coupling and Cognito≠Supabase JWT constraints
Trigger: Measured UX requirement for < a few seconds latency, not “realtime because platforms have it”.
# 6. Client and UI kit
Why: Competitors ship embeddable inbox + preference centre; we ship data hooks only.
Possible packages:
- Headless hooks stay default
- Optional
@inovus-medical/notifications/ui(or similar): accessible bell, feed, empty states, preference panel — themeable, no hard Totum branding lock-in - Better multi-tab sync (BroadcastChannel) and visibility-aware polling
Trigger: Two or more apps copy-paste the same bell implementation.
# 7. Producer DX and throughput
Why: Platforms invest heavily in the send path.
Possible additions:
POST /v2/notifications/batch(or/v3) for fan-out- Queue-backed publish (Cloudflare Queues) for spikes and channel fan-out
- Idempotent workflow keys (cancel/replace in-flight digests)
- Official server SDKs beyond the isomorphic fetch client (if non-TS producers appear)
- Richer OpenAPI examples and contract tests for channel payloads
Trigger: Sustained publish rate or fan-out size that makes per-row HTTP loops painful (DESIGN.md already cites ~>10/sec sustained as a revisit point).
# 8. Observability and support tooling
Why: “Did the user get it?” is the first question in production incidents.
Possible additions:
- Per-notification delivery timeline (inbox created, email queued/sent/bounced)
- Admin/support lookup by
userGuid+dedupeKey(strictly audited) - Metrics: publish rate, unread age, channel failure rate, preference opt-out rates
- Correlation IDs from producer → inbox → channel send
Trigger: Support cannot answer delivery questions from existing Worker/Supabase logs.
# 9. Tenancy, environments, and compliance hardening
Why: B2B notification platforms treat tenancy as a first-class object.
Possible additions:
- Explicit tenant/org dimension on notifications and preferences
- Separate staging/prod notification projects (already partly true via Worker envs)
- Data residency / retention policies per tenant
- Stronger audit trails for publish and preference changes
- Align with whatever Inovus needs for SOC2 / clinical safety narratives
Trigger: A second business unit or customer requires isolation beyond “different Cognito issuers”.
# Suggested sequencing (if we pursue V3 broadly)
A pragmatic order that matches how Knock/Novu/Courier-shaped systems grow, while respecting our medical/B2B context:
1. Categories + preferences (+ quiet hours)
2. Email channel + delivery status (transactional only)
3. Digests / delay-and-cancel for the noisiest producers
4. Optional UI kit (bell + preference centre)
5. Realtime subscribe transport
6. Push / chat channels as demand appears
7. Declarative workflows only if code-owned flows proliferate
8. Deeper tenancy / compliance as org structure requires
Items can be skipped or reordered. A thin batch publish or SSE slice can jump the queue if a single producer is blocked.
# Explicit non-goals (unless strategy changes)
- Replacing company-wide marketing automation (newsletters, cart-style journeys, ad audiences)
- Owning email/SMS provider infrastructure end-to-end (we should wrap vendors)
- Guaranteeing mobile OS-level push without app teams owning FCM/APNs credentials and consent UX
- Pixel-perfect parity with Knock/Novu/Courier feature matrices — we should stay right-sized for Inovus products
# How to use this document
| Audience | Use |
|---|---|
| Product | Prioritise themes against real user/producer pain; ignore shiny multi-channel until preferences exist |
| Engineering | Treat sections as option sketches; new work still needs DESIGN updates + changesets for the client |
| Agents / implementers | Do not build from this file alone — wait for an explicit implementation brief |
When a theme is green-lit, update DESIGN.md (scope + trade-offs), add acceptance criteria, and decide whether the HTTP API stays on /v2 (additive) or needs a /v3 break.
# Related reading
- DESIGN.md — current V2 architecture and explicit out-of-scope list
- Why V2 — why the standalone inbox exists
- High availability — resilience options that overlap with scale/realtime work
- App integration — how producers and SPAs use V2 today
- Industry references for vocabulary (not endorsements): Knock, Novu, Courier, OneSignal (push/engagement-leaning)