admin-parity-fixesrun.md01_define/output/spec.mdSeveral web admin surfaces diverge from the demo reference, leaving the admin persona's config-readiness
experience inconsistent between the two apps. This advances the Refine the Bridge initiative (Q2 2026
objective O1 — vendor engagement / admin config readiness): admins onboarding a tenant hit half-built
surfaces where demo shows a finished flow. Concretely: /admin/users/invite is a redirect stub
("invites managed in settings") instead of demo's real invite form + pending-invites list; /admin/users
lacks demo's "Access control" summary card; the SLA settings tab lacks demo's 3 summary tiles; the "General"
settings tab is a raw key/value registry editor rather than demo's structured tenant Profile form; and
the automations surface is inconsistently named "Escalation" (web) vs "Automations" (demo), so
ConfigGapsPanel hrefs pointing at it are brittle.
Bring these admin surfaces to demo parity:
/admin/users/invite with the demo-style invite form (email +
role assignment) wired to the real Clerk invitation mechanism via a server action, plus a
pending-invites list populated from real pending Clerk invitations for the tenant. Keep the demo form
design; the send and the list are backed by Clerk, not mock data./admin/users (total users / roles
assigned / missing roles), presented as in demo and derived from the data the users page already has.ConfigGapsPanel href so it resolves to the renamed surface.Use the shared DetailPageShell for consistent page headers.
/admin/users/invite renders a real invite form (email + role) that sends a real Clerk invitation on
submit, plus a pending-invites list populated from real pending Clerk invitations (not a redirect stub)./admin/users shows the "Access control" summary card (total users / roles assigned / missing roles),
matching demo's presentation.ConfigGapsPanel href resolves to it (no broken links).admin-settings-hub.none — invite wiring (real Clerk), naming ("Automations"), and the SLA/access-control data source (demo presentation from existing page data) were all settled at Define.
02_build/output/notes.mdapps/web/app/(app)/admin/users/invite/page.tsx: replaced the redirect stub with a
two-column layout — an invite form and a real pending-invitations list. The list is loaded
server-side from client.organizations.getOrganizationInvitationList({ organizationId, status: ["pending"] }).apps/web/app/(app)/admin/users/invite/actions.ts (new): inviteUser server action —
admin-gated via resolveActionContext, sends a real Clerk invitation with
createOrganizationInvitation using the app's org:<role> convention and the current user as inviter.apps/web/app/(app)/admin/users/invite/_components/invite-user-form.tsx (new): client form
(email + role select) calling the action, with toast + inline error and router.refresh() so the
pending list updates on success. Roles offered = GRANTABLE_ROLES (customer excluded).apps/web/components/admin/users/access-control-summary.tsx (new): async server component that
derives total users / roles assigned / missing roles via the existing
deriveAdminPeople(userService.listTenantDirectory(tenantId)) and renders the shared
RolesPermissionsCard (the platform's canonical "Access control summary" card). Streamed with a
Suspense fallback.apps/web/app/(app)/admin/users/page.tsx: renders the summary above the users table.apps/web/app/(app)/admin/settings/sla/_components/sla-summary-tiles.tsx (new): three tiles —
Stages covered / Default timers / Overall status — matching the demo's presentation, fed by the
same slaConfigService.getSlaConfigSummary(tenantId) the admin dashboard already derives.apps/web/app/(app)/admin/settings/sla/page.tsx: loads the summary alongside definitions and
renders the tiles above the config manager.apps/web/app/(app)/admin/settings/general/page.tsx: replaced the raw registry editor with a
structured Profile form. Initial values read real data: name from the tenant (Clerk org name),
website from tenant.profile.website, timezone from the timezone registry key, plan from
Clerk metadata, and the remaining fields from their profile.* tenant settings.apps/web/app/(app)/admin/settings/general/profile-schema.ts (new): zod schema + the
TENANT_PROFILE_SETTING_KEYS map + TenantProfileValues type (kept out of the "use server"
file so the module can export non-async values).apps/web/app/(app)/admin/settings/general/actions.ts (new): saveTenantProfile — upserts the
profile fields into tenant_settings (the settings hub's "create on first edit" idiom) and writes
the display name to the Clerk organisation (updateOrganization), its real home.apps/web/app/(app)/admin/settings/general/_components/profile-form.tsx (new): client form with
Identity / Plan & contact / Regional defaults sections mirroring the demo Profile panel.Standardised the user-facing label on "Automations" while keeping URL slugs and internal
identifiers (/admin/escalation, getEscalationConfig, escalation category id, component names)
unchanged — so every route, redirect, and href keeps resolving.
tabs-config.ts), settings page heading (settings/escalation/page.tsx),
dashboard card title + footer + row label (escalation-rules-card.tsx), and the config form's
toggle label + toast (escalation-config-form.tsx).settings-config.ts) and the settings panel header
(panels.tsx); the demo's dashboard/nav surface was already "Automations"./admin/users/invite renders a real invite form + pending-invites list wired to Clerk (not a redirect stub)./admin/users shows the access-control summary card (total users / roles assigned / missing roles).ConfigGapsPanel hrefs resolve (they point at /admin/{sla,setup,integrations,users,commercial}, all live; no escalation href exists there).createOrganizationInvitation,
getOrganizationInvitationList, updateOrganization) verified against the resolved @clerk/backend
types; org:<role> matches the existing membership-write idiom.updateOrganization, which
mirrors back onto tenant.name on the next load. The other profile fields persist to
tenant_settings (profile.* keys + the existing timezone key) — no model change, no migration.escalation on purpose (route-policies, redirects, and
revalidatePath targets are unchanged); only user-facing labels moved to "Automations".org:<role> invitation roles assume those roles exist in the Clerk
instance — consistent with the existing membership-update code that already writes org:<role>.03_release/output/changelog.mdYour admin area picks up a set of practical upgrades. You can now invite a new team member straight from users & roles — enter their email, choose a role, and watch who's still to accept in a pending-invitations list. The users page now opens with an access-control summary: total users, roles assigned, and any required roles still missing. Your SLA settings show three summary tiles — stages covered, whether default timers are set, and overall status — above the detailed timers. The general settings tab is now a structured organisation profile (name, legal name, plan, support email, website, timezone, region and fiscal year) in place of the raw settings list. And the escalation area is now called Automations everywhere, so it's easier to find.
03_release/output/investor-update.mdWho it's for: Admins operating a tenant What shipped: A real teammate-invite flow, a structured organisation profile form, and at-a-glance access-control and SLA summaries — with the escalation area renamed Automations across the product. Why it matters: Sharper admin config readiness advances Refine the Bridge's dashboard usability, supporting Objective 1 — product-market fit with vendor partners.
Dig deeper: <merged-PR URL> · <changelog entry URL>