Repository navigation
Add notification counts in the header and the security events view - #2590
Merged
Merged
Conversation
pournasserian
added a commit
that referenced
this pull request
Oct 19, 2026
…ostgreSQL (#2642) Closes #2635 ## What Follow-up from the independent review of #2590 (F-DSK, #2422). On PostgreSQL, signed-in pages failed most of the time with "A second operation was started on this context instance". - **`NotificationLinks`** reads the header counts through a service scope of its own. The layout renders while the page loads its data, and the two used to share the request's `DbContext`. The caller is still the request's, because the initiator comes from the `HttpContext`. - **An index on `AuditEvents (Operation, Timestamp)`**, with migrations for SQLite and PostgreSQL, generated after v2's latest. The security view lists and counts a few operations across the whole log, and no index covered `Operation`. - **`CONTRIBUTING.md`** states the rule: a component that loads data next to the page reads through a scope of its own. ## Why - **A scope, not a `DbContext` factory.** The directories and the unit of work share one context per scope by design (ADR-0005). Only components that run beside the page need their own, and today that is the header counts. #2639 applies the same rule to the picker's searches. - **SQLite hid it.** Its async calls finish synchronously, so no host test ever overlapped two queries. The new page test runs on both providers. ## Tests - `SignedInPageTests`, on SQLite and PostgreSQL: loads every signed-in page five times, with a set awaiting review, an entry, an asset and their pages. Without the fix it fails on PostgreSQL. - Every SEC-08 event the code appends today is appended by the code that owns it and read back from `/security` with the kind and name of who did it, so a renamed operation fails a test: - `SecurityEventTests`, on both providers: - an agent over its calls cap, over MCP; - an agent over its items-per-set and sets-per-day caps, over MCP; - an agent refused a move it can't make; - a key issued and revoked; - a user created, disabled and enabled; - a routing rule created, revised, activated and deactivated. - `PasswordResetTests`: a reset link issued and used. - `ExternalSignInTests`: a sign-in linked through the provider. - `SecurityRows` reads the view's rows for all three. - The header counts follow a set into review and out of it, and follow security events as they are appended. - The axe check covers `/security` with more than a page of events, so the table, badges, links and pager are checked. `dotnet build -warnaserror`, the unit and bUnit suite, the browser tests, the integration suite on SQLite and PostgreSQL and markdownlint pass locally. No new package and no new project reference. ## Checklist - [x] Linked to an issue a maintainer has confirmed - [x] Targets `v2` - [x] Tests or docs updated where behaviour changed - [x] No tool-generated co-author trailers or footers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2587
What
The fifth slice of F-DSK (#2422): in-app notification counts (DSK-05) and the security events view on the desk (SEC-08).
FluentCMS.Core.Audit):SecurityEvents.Operations: the operations SEC-08 names.IAuditEventLists: a page of the log with any of the given operations, newest first, optionally since a time, with the total.CountAsyncgives the total alone. A bad window fails withoffset_invalidorlimit_invalid, and no operations withaudit_operations_missing. It is separate fromIAuditReader, which streams the log oldest first for exports.FluentCMS.Core.Desk):IDeskQueues.CountAsync(queue)counts one queue, so the header does not count all six.AuditEventListsin its own file, SQL overAuditEventsas inAuditReader.NotificationLinksin the header replaces the plain Desk link./security: the events newest first, in pages of 50. Each row has the time, a sentence for the operation, who acted (agent, person or system badge and name) and the subject, linked to its audit history. The rows rove like the desk's./security.Why
NotificationLinks.SecurityWithinis the one place to change it.Tests
Unit:
DeskQueuesTests: one queue is counted on its own, stale facts included.SecurityEventsViewTests:Integration:
/securitylists both newest first, links the credential's history and leaves out the change set events. The header counts one set awaiting the owner and two security events. An anonymous request goes to sign-in./securitytoo, in both directions and themes.dotnet build -warnaserrorand the full suite with the browser tests pass locally against apostgres:17container as well as SQLite. No new package and no new project reference.Checklist
v2