---
id: standard-pages
class: b2
sourced: 2026-07-12
source: "b2b-ux-patterns ch.12"
license: open
---
# Pass: standard pages

**Inputs:** per meta-object page — `standardPage` (settings | profile | notifications | audit-object | audit-global | user-management | roles-permissions | seats-licenses | billing | integrations); plus signals — `notificationDelivery`, `ssoScimProvisioning`, `complianceBuyer`, `recordLevelAccess`, `externalSystemMapping`.
**Owns:** `archetypes`, `requiredMechanics`, `clarifications`.
**Output artifact:** the settings/profile/notifications/audit/admin/integration pages every B2B product ships regardless of domain — each generated by the earlier passes as an index, detail, or form over a meta-object (users, roles, notifications, audit events, connections), not hand-designed. The full settings scope/subject/risk taxonomy is the `settings` pass; this pass names the pages and their contracts.

## The rule

**Standard pages are not exempt from the method — they are the method applied to meta-objects.** Each is an index, a detail page, or a form over users, roles, notifications, audit events, or connections, and carries the same archetype, state matrix, and viewer-context obligations as any domain surface.

**Profile is a detail page** over the User object where viewer = subject: identity fields, avatar, credentials/security (password, 2FA, sessions), and pointers into personal-scope settings.

**The notifications page is a derived index, not a primary object.** Asset-level verbs (watch, subscribe, assign, @mention) combined with the viewer's relationships produce notification records; the page is their index — reverse-chronological, read/unread, filterable by type, each item deep-linking to the record and moment that produced it. For operational products this index doubles as a **work-router** ("what needs me"), so treat its ordering and grouping with index-level seriousness. Beside it lives the **notification preferences matrix** (personal scope): event types × delivery channels, with batching cadence per cell (instant / hourly / daily digest / off) plus a global mute — load-bearing, because getting batching wrong is a top reason users disengage.

**Audit has two surfaces, both outputs of the Logged history class at different scopes.** Per-object history is the record-scoped timeline on every detail page. The **global audit log** is an org-scope, append-only index of who-did-what-when across security-relevant actions — logins, permission changes, deletions, exports, setting changes, and every impersonation session (impersonation is always logged, no exceptions) — filterable by actor/action/object/time, searchable, exportable; for SOC2/enterprise buyers it is a purchase criterion, not an afterthought.

**Admin pages are indexes and forms over the org's meta-objects.** User management (invite — noting SSO/SCIM may provision users externally, so the invite form is not the only entry point — role assignment, deactivation) must trigger an **ownership-transfer flow** on deactivation: reassign the departing user's records before the account closes, or orphaned records are guaranteed. Roles & permissions is the admin surface for the access layers, paired with **impersonation/view-as** — once record- and field-level access exist, "log in as this user" is the only practical way to debug what a person actually sees. Seats & licenses render "X of Y seats used," pending invites, and reclaim-on-deactivation. Billing is brief here; customer-facing usage/billing surfaces are deferred.

**Integrations resolve to objects, never a free-floating layer.** External data always maps to objects and fields: a connect flow (OAuth or keys, workspace scope), a **field-mapping editor** (their "Company" ↔ your "Account," with sync direction and frequency per mapping), and **connection health** (status, last successful sync, error counts, per-connection sync logs as an index of sync events); synced fields carry their origin declaration wherever they render. When a standard-page request omits which meta-object it is over, its contract cannot be derived: clarify.

```json decision-table
{"pass": "standard-pages", "rows": [
  {"when": {"standardPage": "settings"}, "then": {"archetypes": {"mustInclude": ["settings"]}, "requiredMechanics": {"mustInclude": ["three-scope-split", "per-scope-edit-permissions"]}}, "reason": "settings-is-a-scope-tree"},
  {"when": {"standardPage": "profile"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["viewer-equals-subject", "credentials-security-section"]}}, "reason": "profile-is-a-detail-page-over-user"},
  {"when": {"standardPage": "notifications"}, "then": {"archetypes": {"mustInclude": ["browse", "queue"]}, "requiredMechanics": {"mustInclude": ["notification-index-deep-links", "read-unread-state", "notification-preferences-matrix", "global-mute"]}}, "reason": "notifications-is-a-derived-index-and-router"},
  {"when": {"notificationDelivery": true}, "then": {"requiredMechanics": {"mustInclude": ["event-type-by-channel-matrix", "per-cell-batching-cadence"]}}, "reason": "batching-matrix-is-load-bearing"},
  {"when": {"standardPage": "audit-global"}, "then": {"archetypes": {"mustInclude": ["browse"]}, "requiredMechanics": {"mustInclude": ["append-only-audit-log", "impersonation-always-logged", "filter-actor-action-object-time", "audit-exportable"]}}, "reason": "global-audit-is-a-compliance-index"},
  {"when": {"standardPage": "audit-object"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["record-scoped-history-timeline"]}}, "reason": "per-object-history-is-the-detail-timeline"},
  {"when": {"standardPage": "user-management"}, "then": {"archetypes": {"mustInclude": ["browse", "creation-flow"]}, "requiredMechanics": {"mustInclude": ["ownership-transfer-on-deactivation", "role-assignment"], "mustNotInclude": ["orphaned-records-on-deactivation"]}}, "reason": "deactivation-must-transfer-ownership"},
  {"when": {"ssoScimProvisioning": true}, "then": {"requiredMechanics": {"mustInclude": ["external-provisioning-entry-point"], "mustNotInclude": ["invite-form-only-entry-point"]}}, "reason": "sso-scim-provisions-outside-the-invite-form"},
  {"when": {"standardPage": "roles-permissions"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["permission-impact-surface", "impersonation-view-as"]}}, "reason": "roles-need-a-view-as-debugger"},
  {"when": {"recordLevelAccess": true}, "then": {"requiredMechanics": {"mustInclude": ["impersonation-view-as", "impersonation-banner", "impersonation-audit-logged"]}}, "reason": "view-as-is-the-only-honest-access-debugger"},
  {"when": {"standardPage": "seats-licenses"}, "then": {"requiredMechanics": {"mustInclude": ["seats-used-of-total", "pending-invites", "reclaim-on-deactivation"]}}, "reason": "seats-render-as-metered-usage"},
  {"when": {"standardPage": "integrations"}, "then": {"requiredMechanics": {"mustInclude": ["connect-flow", "field-mapping-editor", "connection-health-log"]}}, "reason": "integrations-resolve-to-objects-and-fields"},
  {"when": {"externalSystemMapping": true}, "then": {"requiredMechanics": {"mustInclude": ["field-mapping-editor", "sync-direction-per-mapping", "synced-field-provenance"]}}, "reason": "external-mapping-is-object-mapped"},
  {"when": {"complianceBuyer": true}, "then": {"requiredMechanics": {"mustInclude": ["append-only-audit-log", "audit-exportable"]}}, "reason": "audit-log-is-a-purchase-criterion"},
  {"when": {"standardPage": "__absent__"}, "then": {"clarifications": ["standard-page-subject-unspecified"]}, "reason": "contract-derives-from-the-meta-object"}
]}
```
