# Notifications Nav Group — Design **Date:** 2026-05-19 **Goal:** Consolidate all notification-related Central UI pages into a dedicated **Notifications** left-menu section, split the combined Outbox page into a report and a KPIs page, give Notification Lists a proper home, and add a per-source-site KPI breakdown. ## Background Notification-related UI is currently scattered: | Page | Route | Nav section | Policy | |---|---|---|---| | SMTP Configuration | `/admin/smtp` | Admin | RequireAdmin | | Notification Outbox (KPI tiles **+** filterable table) | `/monitoring/notification-outbox` | Monitoring | RequireDeployment | | Notification Lists | `/design/notification-lists/...` (form only) | none — table embedded in the External Systems page | RequireDesign | The Outbox page mixes KPI tiles and the filterable `Notifications`-table report on one page. Notification Lists has no list page of its own — its table is bolted onto `ExternalSystems.razor`. KPI infrastructure (`NotificationKpiRequest`/`Response`, `INotificationOutboxRepository.ComputeKpisAsync`) is global-only, despite CLAUDE.md stating KPIs are "global + per-source-site". ## Architecture A new **Notifications** left-menu section consolidates these pages. Routes move to a consistent `/notifications/*` prefix. The combined Outbox page is split into two. Notification Lists gets a dedicated page. A bounded backend addition supplies per-source-site KPIs. No actor topology, persistence, or message-evolution rules change beyond the additive KPI contracts. ## 1. Nav menu New `Notifications` section in `NavMenu.razor`, placed **between Deployment and Monitoring**. Final section order: Dashboard, Admin, Design, Deployment, Notifications, Monitoring, Audit Log. | Menu item | Route | Policy | |---|---|---| | SMTP Configuration | `/notifications/smtp` | RequireAdmin | | Notification Lists | `/notifications/lists` | RequireDesign | | Notification Report | `/notifications/report` | RequireDeployment | | Notification KPIs | `/notifications/kpis` | RequireDeployment | Each item is wrapped in its own per-item `AuthorizeView` policy (same pattern the Monitoring section already uses for its mixed-role items). The section header is a plain `div` — every authenticated user holds at least one of Admin/Design/Deployment, so the header always has ≥1 visible child and cannot be orphaned. SMTP Configuration is **removed** from the Admin section; Notification Outbox is **removed** from the Monitoring section. ## 2. SMTP Configuration Move `Components/Pages/Admin/SmtpConfiguration.razor` → `Components/Pages/Notifications/SmtpConfiguration.razor`. Route `/admin/smtp` → `/notifications/smtp`. Page content, `RequireAdmin` policy, and the `SmtpConfiguration` namespace alias are unchanged. ## 3. Notification Lists (new page) New `Components/Pages/Notifications/NotificationLists.razor` (`/notifications/lists`, RequireDesign): a `DataTable` of notification lists with Add and per-row Edit actions, plus an empty state — extracted verbatim from the notification-lists block currently in `ExternalSystems.razor`. - `NotificationListForm.razor` routes move: `/design/notification-lists/create` → `/notifications/lists/create`, `/design/notification-lists/{Id:int}/edit` → `/notifications/lists/{Id:int}/edit`. Its "Back" navigation targets `/notifications/lists`. - The notification-lists section is **removed** from `ExternalSystems.razor`, leaving that page purely external systems. The three `/design/notification-lists/...` navigate-links in `ExternalSystems.razor` are removed with it. ## 4. Notification Report New `Components/Pages/Notifications/NotificationReport.razor` (`/notifications/report`, RequireDeployment), split from the existing `Monitoring/NotificationOutbox.razor`. Retains the full filter bar, the paginated `Notifications`-table query (`NotificationOutboxQueryRequest`), and the per-row Retry/Discard actions. The **KPI tile row is removed** from this page. `Components/Pages/Monitoring/NotificationOutbox.razor` and its Monitoring nav entry are **deleted**. ## 5. Notification KPIs New `Components/Pages/Notifications/NotificationKpis.razor` (`/notifications/kpis`, RequireDeployment) with a manual Refresh button. Two parts: 1. **Global tiles** — the existing 5: Queue Depth, Stuck, Parked, Delivered Last Interval, Oldest Pending Age. 2. **Per-source-site breakdown table** — one row per site with the same five metrics, so operators can see which site is backing up. ### Backend addition for per-site KPIs Bounded, additive, follows the existing global-KPI pattern: - `INotificationOutboxRepository.ComputePerSiteKpisAsync(...)` → returns a per-site collection (a new `SiteNotificationKpiSnapshot` record carrying the source site id plus the five metrics). Implemented in `NotificationOutboxRepository`. - New message pair in `Messages/Notification/NotificationOutboxQueries.cs`: `PerSiteNotificationKpiRequest` / `PerSiteNotificationKpiResponse` (additive — honors message-evolution rules). - A handler in `NotificationOutboxActor` for the new request, mirroring the existing `NotificationKpiRequest` handler. - A `CommunicationService.GetPerSiteNotificationKpisAsync(...)` method mirroring `GetNotificationKpisAsync`. Per CLAUDE.md, KPIs remain point-in-time computed from the `Notifications` table — no time-series store, no historical charts (YAGNI). ## 6. Health dashboard `Monitoring/Health.razor` keeps its KPI tile row unchanged. A "View details →" link is added from that tile row to `/notifications/kpis`. ## Error handling Unchanged from the current Outbox page: KPI/query faults surface as an inline warning alert (`Success == false` → `ErrorMessage`); the site-name lookup degrades gracefully to raw site ids. Per-site KPI faults are reported the same way. ## Testing - bUnit component tests for `NotificationLists`, `NotificationReport`, `NotificationKpis`, and the moved `SmtpConfiguration` page. - A `NavMenu` test asserting the Notifications section renders and that per-item visibility honors Admin/Design/Deployment roles. - Repository tests for `ComputePerSiteKpisAsync`. - Actor test for the `PerSiteNotificationKpiRequest` handler. - `CommunicationService` test for `GetPerSiteNotificationKpisAsync`. ## Out of scope - Historical/trend KPI charts (no time-series store). - Any change to notification delivery, store-and-forward, or the `Notifications` table schema. - Renaming the Notification Outbox **component** (#21) — only the UI page names change.