First Class Modules
Notifications
Provides recipient-scoped alerts with unread filtering, detail, dismissal, source-record context, relations, activity, and source favorites.
module.notificationsUse Notifications for personal awareness of events, assignments, changes, and workflow outcomes that do not require the richer ownership lifecycle of Universal Inbox.
The bundled renderer key is module.notifications. First-class means BuildWithHQ supplies a native, typed, secured runtime experience inside normal app provisioning and the signed-in user's existing permissions.
What it does
Provides recipient-scoped alerts with unread filtering, detail, dismissal, source-record context, relations, activity, and source favorites.
Key capabilities
- Search current-recipient notifications and filter unread items.
- Open bounded detail and mark or dismiss notification state.
- Show a permitted source title, location, relations, and activity.
- Favorite an authorized source record directly from the notification.
Common uses
- Assignment, mention, publication, and status-change alerts.
- Workflow completion, failure, or approval attention.
- Personal reminders that link back to the canonical source record.
How it connects
Notifications point to native source records across modules. Use Universal Inbox for shared triage, ownership, SLA, and AI action preparation; use Notifications for recipient-scoped awareness.
Where applicable, its records use the universal RecordId conventions so they can participate in secured relationships, activity history, favorites, dynamic fields, notifications, Inbox attention, and global search without copying the source record.
Security and data boundary
Only rows for the current recipient and app/account are returned. Linked source metadata appears only after its normal DataRole and location checks; the browser cannot submit recipient or permission authority.
- The authenticated service derives the SaaS app, tenant account, user, DataRole, and location scope; browser identifiers are never authorization proof.
- The page editor composes React components with validated data bindings. Those bindings call typed runtime APIs, whose application services execute reviewed stored procedures.
- List, search, detail, relation, activity, favorite, and write operations reapply their required server-side permissions.
Add it to an app
- Open the SaaS app in the Developer Console and identify the user journey and page where this module belongs.
- Add the validated
module.notificationsmodule block through the supported page/template authoring flow. - Configure the module with the page editor's React components and validated data bindings; the bindings call authenticated platform APIs backed by reviewed stored procedures.
- Place the page in the correct user-type menus and assign existing DataRole, record, field, and location permissions.
- Test list, detail, search, empty, denied, stale-update, and cross-location behavior before publishing an exact version.
Build a professional Notifications dashboard
These six registry-backed presentation blocks let a designer turn the secured Notifications API into a complete admin page without writing a chart, grid, status badge, empty state, or timeline from scratch. The normal operational API begins at /api/modules/notifications; a dashboard-wide count or trend should come from a separate purpose-built presentation binding so the browser never downloads a broad record population to calculate one number.
The ZIP contains this feature's fictional design composition at pages/first-class/notifications-sample.json, its executable authenticated page at pages/first-class/notifications-live.json, and the catalog-driven FirstClassPresentationGallery.tsx. Use the sample only for visual design. The live page calls the real native API and reviewed stored procedures under the signed-in user's scope.
| Payload kind | Runtime block | Useful Notifications projection |
|---|---|---|
metric-set | core.metric-strip | Unread, action-needed, received, read, and priority counts |
entity-list | core.entity-list | Newest notifications whose source is still visible |
progress-list | core.progress-list | Distribution by source, priority, or state |
series-chart | core.series-chart | Received, read, dismissed, and actioned events |
data-grid | core.presentation-grid | One bounded personal notification page |
timeline | core.timeline | Creation, delivery, read, dismiss, source action, and expiry |
Copy/paste design preview: all six blocks
This complete static page document renders immediately in Puck/Monaco and is useful while styling a template. Its names, counts, dates, and IDs are fictional design fixtures; static preview values are not live tenant facts.
Copy the complete six-block page JSON
{
"blocks": [
{
"_id": "notifications-metrics",
"_type": "core.metric-strip",
"props": {
"title": "Notification center",
"asOfUtc": "2026-09-04T18:00:00Z",
"items": [
{
"key": "unread",
"label": "Unread",
"value": 24,
"format": "number",
"tone": "warning"
},
{
"key": "action",
"label": "Action needed",
"value": 6,
"format": "number",
"tone": "danger"
},
{
"key": "today",
"label": "Received today",
"value": 41,
"format": "number",
"tone": "primary"
},
{
"key": "read",
"label": "Read today",
"value": 29,
"format": "number",
"tone": "success"
}
]
},
"children": []
},
{
"_id": "notifications-recent",
"_type": "core.entity-list",
"props": {
"title": "Recent notifications",
"hasMore": true,
"items": [
{
"id": "notifications-sample-1",
"recordId": "notifications-record-1",
"primary": "Checklist awaiting signoff",
"secondary": "North Wing closeout - Work Orders",
"status": {
"key": "action-needed",
"label": "Action needed",
"tone": "warning"
},
"trailing": "5 min ago"
},
{
"id": "notifications-sample-2",
"recordId": "notifications-record-2",
"primary": "Checklist awaiting signoff - Follow-up",
"secondary": "North Wing closeout - Work Orders - Updated two hours ago by the assigned owner",
"status": {
"key": "in-review",
"label": "In review",
"tone": "primary"
},
"trailing": "Today"
},
{
"id": "notifications-sample-3",
"recordId": "notifications-record-3",
"primary": "Checklist awaiting signoff - West region",
"secondary": "North Wing closeout - Work Orders - Related to three visible records at the Reno location",
"status": {
"key": "on-track",
"label": "On track",
"tone": "success"
},
"trailing": "3 related"
},
{
"id": "notifications-sample-4",
"recordId": "notifications-record-4",
"primary": "Checklist awaiting signoff - Customer response",
"secondary": "North Wing closeout - Work Orders - Waiting for an external response before work can continue",
"status": {
"key": "scheduled",
"label": "Scheduled",
"tone": "warning"
},
"trailing": "Tomorrow"
},
{
"id": "notifications-sample-5",
"recordId": "notifications-record-5",
"primary": "Checklist awaiting signoff - Regional operations review with a deliberately long title",
"secondary": "North Wing closeout - Work Orders - This deliberately longer supporting line verifies wrapping, truncation, responsive spacing, and dense dashboard behavior.",
"status": {
"key": "needs-attention",
"label": "Needs attention",
"tone": "danger"
},
"trailing": "Review",
"tertiary": "Long-content fixture: verify keyboard focus, wrapping, narrow columns, and mobile overflow before publishing."
},
{
"id": "notifications-sample-6",
"recordId": "notifications-record-6",
"primary": "Checklist awaiting signoff - Completed preview",
"secondary": "North Wing closeout - Work Orders - Closed after review with its related evidence retained",
"status": {
"key": "complete",
"label": "Complete",
"tone": "success"
},
"trailing": "Closed"
}
]
},
"children": []
},
{
"_id": "notifications-bystatus",
"_type": "core.progress-list",
"props": {
"title": "Notifications by source",
"items": [
{
"key": "work",
"label": "Work Orders",
"value": 11,
"maximum": 24,
"displayValue": "11",
"tone": "primary",
"status": {
"key": "work",
"label": "Work Orders",
"tone": "primary"
}
},
{
"key": "checklists",
"label": "Checklists",
"value": 8,
"maximum": 24,
"displayValue": "8",
"tone": "warning",
"status": {
"key": "checklists",
"label": "Checklists",
"tone": "warning"
}
},
{
"key": "conversations",
"label": "Conversations",
"value": 5,
"maximum": 24,
"displayValue": "5",
"tone": "success",
"status": {
"key": "conversations",
"label": "Conversations",
"tone": "success"
}
}
]
},
"children": []
},
{
"_id": "notifications-trend",
"_type": "core.series-chart",
"props": {
"title": "Notification activity",
"variant": "bar",
"defaultPeriodKey": "d7",
"periods": [
{
"key": "d7",
"label": "7 days",
"labels": [
"Fri",
"Sat",
"Sun",
"Mon",
"Tue",
"Wed",
"Thu"
],
"series": [
{
"key": "primary",
"label": "Received",
"tone": "primary",
"values": [
8,
5,
4,
12,
15,
11,
17
]
},
{
"key": "secondary",
"label": "Read",
"tone": "success",
"values": [
6,
4,
3,
9,
12,
10,
14
]
}
]
}
]
},
"children": []
},
{
"_id": "notifications-table",
"_type": "core.presentation-grid",
"props": {
"title": "Your notifications",
"columns": [
{
"key": "notification",
"label": "Notification",
"type": "text",
"align": "left"
},
{
"key": "source",
"label": "Source",
"type": "text",
"align": "left"
},
{
"key": "priority",
"label": "Priority",
"type": "status",
"align": "left"
},
{
"key": "state",
"label": "State",
"type": "status",
"align": "left"
},
{
"key": "created",
"label": "Created",
"type": "date",
"align": "left"
}
],
"rows": [
{
"id": "notifications-row-1",
"recordId": "notifications-record-1",
"cells": {
"notification": "Checklist awaiting signoff",
"source": "Work Orders",
"priority": {
"key": "high",
"label": "High",
"tone": "danger"
},
"state": {
"key": "unread",
"label": "Unread",
"tone": "warning"
},
"created": "2026-09-04T17:55:00Z"
}
},
{
"id": "notifications-row-2",
"recordId": "notifications-record-2",
"cells": {
"notification": "Checklist awaiting signoff - Follow-up",
"source": "Work Orders",
"priority": {
"key": "in-review",
"label": "In review",
"tone": "primary"
},
"state": {
"key": "in-review",
"label": "In review",
"tone": "primary"
},
"created": "2026-09-04T15:42:00Z"
}
},
{
"id": "notifications-row-3",
"recordId": "notifications-record-3",
"cells": {
"notification": "Checklist awaiting signoff - West region",
"source": "Work Orders",
"priority": {
"key": "on-track",
"label": "On track",
"tone": "success"
},
"state": {
"key": "on-track",
"label": "On track",
"tone": "success"
},
"created": "2026-09-04T12:18:00Z"
}
},
{
"id": "notifications-row-4",
"recordId": "notifications-record-4",
"cells": {
"notification": "Checklist awaiting signoff - Customer response",
"source": "Work Orders",
"priority": {
"key": "scheduled",
"label": "Scheduled",
"tone": "warning"
},
"state": {
"key": "scheduled",
"label": "Scheduled",
"tone": "warning"
},
"created": "2026-09-03T21:07:00Z"
}
},
{
"id": "notifications-row-5",
"recordId": "notifications-record-5",
"cells": {
"notification": "Checklist awaiting signoff - Regional operations review with a deliberately long title",
"source": "Work Orders - This deliberately longer supporting line verifies wrapping, truncation, responsive spacing, and dense dashboard behavior.",
"priority": {
"key": "needs-attention",
"label": "Needs attention",
"tone": "danger"
},
"state": {
"key": "needs-attention",
"label": "Needs attention",
"tone": "danger"
},
"created": "2026-09-03T16:31:00Z"
}
},
{
"id": "notifications-row-6",
"recordId": "notifications-record-6",
"cells": {
"notification": "Checklist awaiting signoff - Completed preview",
"source": "Work Orders",
"priority": {
"key": "complete",
"label": "Complete",
"tone": "success"
},
"state": {
"key": "complete",
"label": "Complete",
"tone": "success"
},
"created": "2026-09-02T19:14:00Z"
}
}
],
"page": {
"pageNumber": 1,
"pageSize": 6,
"totalRecords": 24,
"totalIsExact": true,
"hasMore": true
}
},
"children": []
},
{
"_id": "notifications-timeline",
"_type": "core.timeline",
"props": {
"title": "Notification activity",
"hasMore": true,
"items": [
{
"id": "notifications-event-1",
"recordId": "notifications-record-1",
"occurredUtc": "2026-09-04T17:58:00Z",
"title": "Notification read",
"description": "Checklist awaiting signoff was marked read.",
"actor": "You",
"tone": "success"
},
{
"id": "notifications-event-2",
"recordId": "notifications-record-2",
"occurredUtc": "2026-09-04T15:42:00Z",
"title": "Notification read - Follow-up",
"description": "Checklist awaiting signoff was marked read. Updated two hours ago by the assigned owner.",
"actor": "Avery Patel",
"tone": "primary"
},
{
"id": "notifications-event-3",
"recordId": "notifications-record-3",
"occurredUtc": "2026-09-04T12:18:00Z",
"title": "Notification read - West region",
"description": "Checklist awaiting signoff was marked read. Related to three visible records at the Reno location.",
"actor": "Sam Rivera",
"tone": "success"
},
{
"id": "notifications-event-4",
"recordId": "notifications-record-4",
"occurredUtc": "2026-09-03T21:07:00Z",
"title": "Notification read - Customer response",
"description": "Checklist awaiting signoff was marked read. Waiting for an external response before work can continue.",
"actor": "Maya Chen",
"tone": "warning"
},
{
"id": "notifications-event-5",
"recordId": "notifications-record-5",
"occurredUtc": "2026-09-03T16:31:00Z",
"title": "Notification read - Regional operations review with a deliberately long title",
"description": "Checklist awaiting signoff was marked read. This deliberately longer supporting line verifies wrapping, truncation, responsive spacing, and dense dashboard behavior.",
"actor": "Automation",
"tone": "danger"
},
{
"id": "notifications-event-6",
"recordId": "notifications-record-6",
"occurredUtc": "2026-09-02T19:14:00Z",
"title": "Notification read - Completed preview",
"description": "Checklist awaiting signoff was marked read. Closed after review with its related evidence retained.",
"actor": "Jordan Lee",
"tone": "success"
}
]
},
"children": []
}
]
}Copy/paste React composition
Copy InteractivePresentationComponents.tsx and its optional CSS from the Professional Foundation Developer Kit, then add this module-specific composition. It is semantic and unstyled by default; pass styled after importing interactive-presentation-components.css for the supplied polished foundation. Either version accepts only a bounded already-authorized document and fails closed through the shared strict parsers.
import {
EntityList,
MetricStrip,
PresentationGrid,
ProgressList,
SeriesChart,
Timeline,
} from "./InteractivePresentationComponents";
export interface NotificationsPresentationData {
readonly metrics: unknown;
readonly recent: unknown;
readonly byStatus: unknown;
readonly trend: unknown;
readonly table: unknown;
readonly timeline: unknown;
}
export interface NotificationsPresentationProps {
/** Pass only the already-authorized presentation document returned by the API. */
readonly data?: NotificationsPresentationData | null;
readonly loading?: boolean;
readonly error?: boolean;
readonly styled?: boolean;
/** Record identity is navigation context; the detail API must authorize it again. */
readonly onOpenRecord?: (recordId: string) => void;
}
export function NotificationsPresentation({
data,
loading = false,
error = false,
styled = false,
onOpenRecord,
}: NotificationsPresentationProps) {
if (error) return <p role="alert">The Notifications presentation could not be loaded.</p>;
if (loading || !data) return <p role="status">Loading Notifications presentation...</p>;
return (
<main className={styled ? "bwhq-api-example" : undefined}>
<header>
<p>Notifications</p>
<h1>Notification center</h1>
<p>Unread attention, priority, source modules, delivery state, and recent notification activity.</p>
</header>
<MetricStrip data={data.metrics} styled={styled} />
<div className={styled ? "bwhq-api-example__split" : undefined}>
<ProgressList data={data.byStatus} styled={styled} />
<EntityList data={data.recent} styled={styled} onOpenRecord={onOpenRecord} />
</div>
<SeriesChart data={data.trend} styled={styled} />
<PresentationGrid data={data.table} styled={styled} onOpenRecord={onOpenRecord} />
<Timeline data={data.timeline} styled={styled} onOpenRecord={onOpenRecord} />
</main>
);
}
Copy the live, authenticated module page
This document has no placeholder key and needs no invented endpoint. Save it to a page and add that page to a User Type menu. The registered native component calls /api/modules/notifications, uses the current tenant session, and preserves the module's real list, detail, create/update, pagination, empty, loading, and error behavior. Dynamic Records discovers the organization's real tenant-owned modules when no module key is configured.
Copy the executable live page
{
"blocks": [
{
"_id": "notifications-live",
"_type": "module.notifications",
"props": {},
"children": []
}
]
}The server derives SaaS app, organization, user, DataRoles, locations, module-specific membership/privacy, and any AI-read gate from verified identity. A returned identifier can select a detail target, but the detail or write endpoint authorizes it again. Page layout, status, tone, totals, action names, and identifiers never grant authority.
Notify only when the recipient can act or benefit. High-volume events should roll up into an Inbox queue, digest, or dashboard rather than producing alert fatigue.
A renderer being bundled in the tenant application does not make its data visible in every app. The server returns only components and records authorized for the current app and signed-in user; unavailable or unauthorized blocks fail closed.
Capability review: 2026-09-14. For exact current technical availability, use the generated API Map and first-class module inventory.