
Track events until they are acknowledged
Use a stored badge count for information that the counter itself owns, such as arrivals waiting to be acknowledged. Operations can increase, decrease or reset it.
The count changes through declared events rather than by querying a business collection.
Example — Acknowledge your completed actions
Your completed actions increase a personal counter. Acknowledging them clears that signal without changing the completed work.
For engineers
Register the counter and its scoped identity
Application example: count actions completed by the current user until that user acknowledges them. This is an authored counter, not a built-in producer. Put this definition in the owning shared module:
import {
buildNotificationBadgeKey,
NotificationBadgeDisplayMode,
NotificationBadgePulse,
NotificationBadgeSourceKind,
ResourcePrimaryScope,
type NotificationBadgeDefinition,
} from '@wildo-ai/saas-models';
import { IndicatorVariant } from '@wildo-ai/presets-components-models';
export const completedActionsBadge: NotificationBadgeDefinition = {
identifier: 'completed_actions',
scope: ResourcePrimaryScope.USER_SELF,
source: { kind: NotificationBadgeSourceKind.EVENT_COUNTER },
display: {
mode: NotificationBadgeDisplayMode.COUNT,
tone: IndicatorVariant.NEUTRAL,
pulse: NotificationBadgePulse.NONE,
},
};
export const completedActionsBadgeRef = buildNotificationBadgeKey(
completedActionsBadge.scope, completedActionsBadge.identifier,
);
Add the definition to the module’s notificationBadgeDefinitions. A navigation item uses completedActionsBadgeRef as its notificationBadgeRef; badge presentation connects registration to the visible consumer. The identifier alone is not the scoped key.
Move it from the operations that own those events
These are the complete badge-operation entries to place on the two existing resource operations. Import NotificationBadgeOperation from @wildo-ai/saas-models and the key from the shared module above:
// On the operation that completes one action for its initiator:
notificationBadgeOperations: [{
badgeRef: completedActionsBadgeRef,
operation: NotificationBadgeOperation.INCREMENT,
}],
// On the operation through which that user acknowledges the count:
notificationBadgeOperations: [{
badgeRef: completedActionsBadgeRef,
operation: NotificationBadgeOperation.RESET,
}],
The dispatcher reads the scope from the registered definition, then takes its owner from the operation’s initiatorIds. A user-scoped definition uses the initiator’s userId; an organization-scoped one uses their organizationId. Missing identity at that scope means no counter update. The affected record’s assignee is not a recipient selector for this declaration.
| Declared operation | Change to that owner’s count |
|---|---|
INCREMENT | Add one |
DECREMENT | Subtract one, without going below zero |
SET | Set to one |
RESET | Set to zero |
The authoring entry contains only badgeRef and operation: the dispatcher supplies the value 1. The lower-level service’s numeric argument does not add a custom amount or recipient field to this declaration.
Check the acknowledgement behavior
Starting at zero, two successful completion operations by the same user produce two; their acknowledgement operation resets it to zero. The backend pushes the updated count to that owner’s scope, and the badge hook updates its registered consumer. A different user has a different counter.
Relative changes use guarded storage arithmetic; reset is an absolute write, so a concurrent reset and increment follow their write ordering. The application decides what acknowledgement means and wires every producer. If business records already contain the truth—such as unfinished assignments—use a derived count instead of maintaining a second unread state.