Template UI — option A (working spec)¶
Status: in progress on
feature/template-ui, stacked onfeature/context-templates(#1404). Draft; not to merge before the demo. Decisions by Wim, 2026-10-20, on the clickable mockup "Template UI Mockups" (option A, refined).
Every context now has a template (OrganizationalUnit, LogicalApplication, Tag, Segment). This gives each template its own screen inside Contexts, and the room for the workflows that start from a context, with one of them built now.
1. Decisions¶
| Topic | Decision |
|---|---|
| Layout | Option A: the Contexts page gets a sub-tab per template — Organisation · Applications · Tags · Segments. Tags and Segments keep today's generic tree. |
| One kind of member | Unchanged rule: a context holds one kind of member. In Organisation, a switch shows one tree at a time: People (identities), Accounts (principals), Resources. Nothing is merged. |
| Unit variants | A unit that exists as several variants (people, accounts, resources — a project, a team, a customer) shows them together through SameUnitAs: a variant switch on the detail page ("Contoso · People 12 · Accounts 15 · Resources 31"); each variant opens its own context. |
| Workflow cards | Superseded 2026-10-26 (readability): no card grid. The actions moved to the page header — see §4. |
| Actions | Superseded 2026-10-26: the cards became the header's Download report and the ⋯ menu's View in matrix (§4); a unit of accounts or people got its unit report since. The original decision: two cards. View in matrix (every kind): an application or resource unit opens the matrix with its resources as columns and their holders as rows, grouped by department and folded when large; a unit of accounts or people opens it with its members as rows. Download entitlement report is on applications only: it runs the Entitlement Pivot (application-access-review) on the application itself. An organisational unit (of people, accounts or resources) gets View in matrix only — the report over a unit made no sense to readers there (decided 2026-10-20). The API still runs the Entitlement Pivot on a unit of accounts, from the report form. |
| Readiness dots | Not now. |
| Best guess | A suggested Accountable with its reason, and Confirm (sets the role) · Reject (remembered, never suggested again for that context) · Choose someone else (the existing picker). |
| Naming | Presentation-layer rename to People / Accounts is a separate PR stacked on this one. This PR already uses the words in its new screens. |
2. API¶
GET /api/contexts/:id/roles/suggestion→{ role: 'Accountable', principalId | identityId, displayName, reason, count, total }or204when the context already has an Accountable, carries no roles (Segment, Tag), or has no signal. Signals, first that gives a candidate:- People or accounts unit: the manager of the most members (
Principals.managerId/Identities.managerIdentityId), when they manage at least 40 % of the members. Reason: "manages 11 of the 14 members". - Resource unit or logical application: the account that owns the most of its resources (holders of the ControlPermission resources linked by
HasOwnership/HasAppOwnership), at least 40 %. Reason: "owns 4 of the 6 resources". - A unit of one says "the only member"; a full sweep says "all 5 members".
- A candidate rejected for this context is skipped.
POST /api/contexts/:id/roles/suggestion/rejectbody{ principalId | identityId }→ 204. Stored inContextRoleSuggestionRejections(migration 096:id,contextId→ Contexts cascade,principalId|identityId(exactly one),role,rejectedBy,rejectedAt; unique per context + holder + role). Interim: moves into claims (POC step 2) when that lands.- Confirm is the existing
PUT /api/contexts/:id/roles(Accountable). - OpenAPI entries for both routes. Permissions: read
data.read, rejectdata.write.contexts.
3. UI¶
ContextsPage: sub-tabs per template (counts from the roots list); Organisation tab gets the kind switch and shows only roots of that targetType; Applications lists LogicalApplication roots; Tags and Segments render today's tree unchanged.- Profiles (
contexts/profiles/): per template, the vocabulary (profiles.js: the Accountable's name — an application's is its Owner —, the noun, the label of its members) and the variants of the unit. - Best guess: shown inside the Accountable fact when there is no Accountable — name, reason, Confirm, Reject, Choose someone else.
- No readiness dots.
4. The page of a unit or an application¶
Decided 2026-10-26 (readability review): one column of sections, each person once, the
actions in the header. ContextDetailPage.jsx → contexts/page/ProfileBody.jsx.
- Header (
ContextDetailHeader.jsx): the breadcrumb, the name, one sentence on what it is, and who answers for it inline under it — Accountable and Responsible (ContextPeople.jsx, with the best guess and the interview suggestions; the role's meaning on hover). No Owner chip: an owner the source names but nobody matches reads "The source names “…” as the owner; no account found." while no Accountable is set. Actions: Download report (the main button, for everyone — an application's entitlement report, a unit of accounts or people's unit report;contexts/header/headerActions.js), Add information (an analyst; see Context interviews), and ⋯ (contexts/header/MoreMenu.jsx): View in matrix ↗, Adjust tree, Edit search terms, Edit, Add sub-unit, Copy link, Open as page, Back to Contexts — each where it applies. - Attention line (analysts): "2 to decide · 13 to review · 1 to correct in the source" — to decide filters People to To decide (or opens What we know for a contradiction about the unit), to review opens the review drawer, to correct opens Change requests.
- People (
contexts/people/PeopleSection.jsx): the People overview — each person once, with status, role, sources, access and the claims as icons; filters Current · Former · All (and To decide). See Context interviews → The People overview. An application keeps its Resources list (the members table) and shows People only when a source named someone. - What we know (folded to one line): the unit's own facts — description, properties, also known as, the unit as other kinds of member, More details — and, for an analyst, its own claims to review.
- Sources (analysts, folded): everything added, with Add information.
- Change requests (analysts, folded, only when there are any).
- Sub-units.
- Timeline and Risk (analysts, folded, at the foot).
The business view (no data.write.contexts, or a context owner's read-only page) gets the
header with Download report, who answers for it, People (Former included), What we know and the
sub-units: no Add information, no attention line, no review buttons, no Sources, no Timeline;
confirmed claims only. A read-only shell has no ⋯ menu (nothing in it is theirs to open).
On a narrow screen a person's row is a two-line card: the name, the roles and the status, then
the role, the sources, the access and the claim icons.
Contexts without a template (Tags, Segments) keep the generic page: the header, the description, More details, the sub-units and the members table, and the Timeline for an analyst.