Skip to content

feat: Add global Notifications management (admin endpoints + Svelte UI)#2256

Merged
niemyjski merged 15 commits into
mainfrom
niemyjski/add-svelte-notifications-management
May 29, 2026
Merged

feat: Add global Notifications management (admin endpoints + Svelte UI)#2256
niemyjski merged 15 commits into
mainfrom
niemyjski/add-svelte-notifications-management

Conversation

@niemyjski
Copy link
Copy Markdown
Member

@niemyjski niemyjski commented May 26, 2026

Summary

Adds system notifications management: persistent banners, release announcements, and force-client-refresh — all via new admin endpoints on StatusController and a Svelte 5 admin UI.

What changed

Backend

  • NotificationService (new): cache-backed system notification storage + WebSocket publishing
  • StatusController — 2 new endpoints + publish flag on existing:
    • GET /api/v2/notifications/settings (new) — active notification + env fallback config
    • POST /api/v2/notifications/force-refresh (new) — force-reload all connected clients
    • POST/DELETE /api/v2/notifications/system?publish=true — existing + publish flag (default true, backward compat)
  • NotificationSettingsResponse (new record): typed DTO for settings endpoint

Frontend (Svelte 5)

  • system-notification-banner.svelte (new): 3-tier message resolution (realtime WebSocket → persisted API → env fallback); added to (app)/+layout.svelte
  • /system/notifications page (new): admin UI with Set/Clear/Send Release/Force Refresh dialogs
  • api.svelte.ts and models.ts: TanStack Query wrappers for all notification endpoints
  • routes.svelte.ts: Bell icon + Notifications entry under System

Tests

  • 19 backend integration tests (StatusControllerTests.cs)
  • 9 frontend unit tests covering 3-tier message resolution
  • Controller manifest snapshot updated for 2 new endpoints

Breaking changes

None. All existing endpoints behave identically. The publish parameter defaults to true.

OpenSpec

Designed in openspec/changes/add-svelte-notifications-management/.

niemyjski and others added 3 commits May 26, 2026 16:15
Extract NotificationService from StatusController to centralize notification
logic (system notifications, release notifications, force refresh) while
maintaining full backward compatibility with existing StatusController endpoints.

Backend:
- NotificationService with get/set/clear system notification and send release
- 5 new admin endpoints under /admin/notifications (GET settings, PUT/DELETE
  system, POST release, POST force-refresh)
- Admin DTOs for request/response models
- DI registration in Bootstrapper

Frontend:
- Notification feature module with models and TanStack Query API layer
- NotificationBanners component in app layout for system/release messages
- Admin page at /system/notifications with dialog-based actions
- Nav entry in system routes

Tests:
- 13 backend integration tests covering auth, validation, and legacy compat
- 6 frontend unit tests for notification event logic
- HTTP test samples for all admin endpoints

Co-authored-by: Claude <noreply@anthropic.com>
[Consumes("application/json")] on an endpoint with optional body causes
ASP.NET Core to return 404 when called without Content-Type header.
Since the request body is nullable/optional, remove the constraint.

Added test: ForceRefresh_WithNoBody_UsesDefaultMessage

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…system-notifications

Architectural cleanup:
- Removed duplicate admin endpoints from AdminController — StatusController
  already had these endpoints with proper auth
- Added GET /notifications/settings and POST /notifications/force-refresh
  to StatusController where they belong
- Added 'publish' query param to POST/DELETE system notification (backward
  compatible, defaults to true)
- Deleted NotificationModels.cs — use existing ValueFromBody + query param
  patterns instead of custom DTOs
- Renamed frontend feature from 'notifications' to 'system-notifications'
- Renamed component from 'notification-banners' to 'system-notification-banner'
- Moved tests from AdminNotificationTests to StatusControllerTests (with AAA)
- Deleted admin-notifications.http, added samples to status.http
- Updated OpenSpec tasks to reflect final architecture

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a global system-notifications management feature: backend NotificationService plus two new StatusController endpoints (GET notifications/settings, POST notifications/force-refresh) and a publish flag on the existing set/clear endpoints, a Svelte 5 admin page at /system/notifications, a global banner component that resolves messages from realtime WebSocket → persisted API → env fallback, and accompanying tests and OpenSpec docs.

Changes:

  • Extract notification logic into NotificationService and refactor StatusController to delegate, adding notifications/settings, notifications/force-refresh, and a publish query param.
  • Add Svelte system-notification-banner (mounted in (app)/+layout.svelte) and a /system/notifications admin page with TanStack Query API wrappers and models.
  • Add backend integration tests, frontend unit tests, HTTP samples, and an OpenSpec proposal/design/spec/tasks set.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Exceptionless.Core/Services/NotificationService.cs New service centralizing cache + message-bus notification operations.
src/Exceptionless.Core/Bootstrapper.cs Registers NotificationService as a singleton.
src/Exceptionless.Web/Controllers/StatusController.cs Delegates to NotificationService; adds settings, force-refresh, and publish flag.
tests/Exceptionless.Tests/Controllers/StatusControllerTests.cs Adds tests for new endpoints and publish=false.
tests/http/status.http HTTP samples for force-refresh and settings.
src/Exceptionless.Web/ClientApp/src/lib/features/system-notifications/models.ts Frontend types for settings response.
src/Exceptionless.Web/ClientApp/src/lib/features/system-notifications/api.svelte.ts TanStack Query wrappers for notification endpoints.
.../components/system-notification-banner.svelte Global banner with realtime/persisted/env-fallback resolution.
.../components/system-notification-banner.test.ts Unit tests (currently only exercise CustomEvent semantics).
src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte Mounts SystemNotificationBanner in the app layout.
src/Exceptionless.Web/ClientApp/src/routes/(app)/system/notifications/+page.svelte New admin management page with action dialogs.
src/Exceptionless.Web/ClientApp/src/routes/(app)/system/routes.svelte.ts Adds Bell-icon nav entry for global admins.
openspec/changes/add-svelte-notifications-management/* Proposal, design, spec, tasks for the change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread openspec/changes/add-svelte-notifications-management/specs/notifications/spec.md Outdated
Comment thread tests/Exceptionless.Tests/Controllers/StatusControllerTests.cs
Comment thread tests/Exceptionless.Tests/Controllers/StatusControllerTests.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/StatusController.cs Outdated
- Regenerate controller-manifest.json with new endpoints (CI RCA)
- Add typed NotificationSettingsResponse record (replaces anonymous object)
- Fix validation: empty message returns 400 BadRequest (was 404 NotFound)
- Rename misleading test names to match actual behavior
- Strengthen publish=false test to verify cache persistence
- Extract resolveDisplayMessage() into testable utility
- Rewrite frontend tests to actually cover resolution logic
- Update OpenSpec spec to reflect StatusController architecture

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@niemyjski niemyjski requested a review from Copilot May 27, 2026 12:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Comment thread src/Exceptionless.Web/ClientApp/src/lib/features/notifications/models.ts Outdated
Comment thread src/Exceptionless.Web/Controllers/StatusController.cs Outdated
Comment thread src/Exceptionless.Web/ClientApp/src/lib/features/notifications/api.svelte.ts Outdated
…esh with no message

- Replace boolean string interpolation in query strings with URLSearchParams
- forceRefreshClientsMutation: omit body entirely when no message is provided,
  so the no-body backend code path is exercised from the UI (not just tests)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.

Comment thread openspec/changes/add-svelte-notifications-management/design.md Outdated
…/prefer-svelte-reactivity lint rule

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

niemyjski and others added 3 commits May 28, 2026 06:52
- Fix self-reload race on force refresh: admin initiating tab now delays
  window.location.reload() by 1500ms via force-refresh-coordinator.ts flag;
  all other clients still reload immediately
- Add MaxNotificationMessageLength = 1000 cap to PostSystemNotificationAsync,
  PostReleaseNotificationAsync, and ForceRefreshAsync; add frontend maxlength={1000}
  on all textareas
- Rename system-notification-banner.test.ts → resolve-message.test.ts (tests only
  cover resolveDisplayMessage, not the banner component)
- Add force-refresh-coordinator.test.ts with 4 tests for the flag module
- Clarify resolve-message.ts docstring: null realtime skips persisted but still
  shows env fallback; empty strings treated as absent
- Update OpenSpec design.md, proposal.md, spec.md, tasks.md to reflect actual
  StatusController implementation (not AdminController as originally proposed)
- Merge origin/main (81 files changed, no conflicts)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
message parameter is non-nullable ValueFromBody<string>; use message.Value?.Length
instead of message?.Value?.Length to avoid false positive null dereference warning

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 2 comments.

Comment thread src/Exceptionless.Web/Controllers/StatusController.cs Outdated
niemyjski and others added 2 commits May 28, 2026 13:08
- Rename feature folder: system-notifications -> notifications
- Rename component: SystemNotificationBanner -> Notifications
- Remove NotificationSettingsResponse DTO (use anonymous object)
- Remove force-refresh-coordinator (consumeSelfInitiatedFlag hack)
- Remove resolveDisplayMessage (over-engineered resolution)
- Remove MaxNotificationMessageLength validation (unwanted)
- Use useEventListener from runed (project pattern)
- Simplify banner: just show message or fallback like legacy Angular
- Add newline before return after control statements
- Revert .gitignore gstack addition
- Remove maxlength from textareas

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@niemyjski niemyjski force-pushed the niemyjski/add-svelte-notifications-management branch from d450ee9 to 01956a3 Compare May 29, 2026 01:14
- Remove /notifications/settings endpoint (unnecessary complexity)
- Use typography components (H2, Muted, P) instead of raw HTML
- Restore original NotFound() response for empty notification message
- Delete unused NotificationSettings model
- Remove settings endpoint tests
- Regenerate controller manifest

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@niemyjski niemyjski force-pushed the niemyjski/add-svelte-notifications-management branch from 01956a3 to 346e78f Compare May 29, 2026 01:15
- Remove POST notifications/force-refresh endpoint (unnecessary)
- Remove forceRefreshClientsMutation and UI card/dialog
- Fix notification banner icon alignment (items-center, remove mt-0.5)
- Remove force-refresh tests and .http samples
- Regenerate controller manifest

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread tests/Exceptionless.Tests/Controllers/StatusControllerTests.cs Outdated
Comment thread .gitignore Outdated
Comment thread src/Exceptionless.Web/Controllers/StatusController.cs Outdated
niemyjski added 2 commits May 28, 2026 20:29
Co-authored-by: Blake Niemyjski <bniemyjski@gmail.com>
@niemyjski niemyjski merged commit debb19e into main May 29, 2026
6 checks passed
@niemyjski niemyjski deleted the niemyjski/add-svelte-notifications-management branch May 29, 2026 01:31
@github-actions
Copy link
Copy Markdown

Code Coverage

Package Line Rate Branch Rate Complexity Health
Exceptionless.Insulation 25% 23% 203
Exceptionless.Web 73% 62% 3920
Exceptionless.AppHost 18% 9% 82
Exceptionless.Core 69% 63% 7820
Summary 68% (13531 / 19857) 62% (7117 / 11568) 12025

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.

2 participants