Skip to Content

← All archived runs

Run: admin-parity-fixes

run.md

Run: admin-parity-fixes

  • branch: claude/admin-parity-fixes-g2sm6u
  • pr: #707

01_define/output/spec.md

Spec: Admin page parity fixes

  • slug: admin-parity-fixes
  • personas: Admin
  • touches: apps/web/app/(app)/admin/users, apps/web/app/(app)/admin/settings/{sla,general}, apps/web/app/(app)/admin/escalation, apps/web/app/(app)/admin/settings/_components/tabs-config.ts, apps/web/components/admin/dashboard/config-gaps-panel.tsx, apps/demo/components/dashboard/admin/settings
  • complexity: complex

Problem

Several 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.

Proposed change

Bring these admin surfaces to demo parity:

  • Invite — replace the redirect stub at /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.
  • Access control card — add demo's "Access control" summary card to /admin/users (total users / roles assigned / missing roles), presented as in demo and derived from the data the users page already has.
  • SLA tiles — add demo's 3 summary tiles (Stages covered / Default timers / Overall status) above the SLA config manager on the SLA settings tab, matching demo's presentation from the values the page already holds.
  • General → Profile form — replace the raw registry editor on the General settings tab with a structured tenant Profile form matching demo's fields: name, legal name, plan, support email, website, timezone, region, fiscal year.
  • Naming — standardize the automations surface on "Automations" across both apps: rename the web "Escalation" settings tab label/route and the demo stray "Automations"/"Escalation" labels so the two agree, and update every ConfigGapsPanel href so it resolves to the renamed surface.

Use the shared DetailPageShell for consistent page headers.

Acceptance criteria

  • /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.
  • The SLA settings tab shows the 3 summary tiles (Stages covered / Default timers / Overall status) above the config manager, matching demo's presentation.
  • The General settings tab shows a structured Profile form (name / legal name / plan / support email / website / timezone / region / fiscal year) in place of the registry editor.
  • The automations surface is named "Automations" consistently across web and demo, and every ConfigGapsPanel href resolves to it (no broken links).

Out of scope

  • Rebuilding the settings IA as the grouped hub — owned by stub admin-settings-hub.
  • Web-only CRUD catalogues (industries / services / statuses / products / role-templates) — lean-subset, not this run.
  • Any change to demo's underlying mock-data model beyond the naming alignment above.

Open questions

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.md

Build notes: admin-parity-fixes

  • commits: feat: admin-parity-fixes — invite form, access-control + SLA summaries, Profile form, Automations naming

What changed

Invite form + pending-invites list (real Clerk)

  • apps/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).

Access-control summary card on /admin/users

  • 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.

SLA summary tiles

  • 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.

Structured Profile form on General settings

  • 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.

"Automations" naming (web + demo)

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.

  • Web: settings tab label (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).
  • Demo: settings-hub category label (settings-config.ts) and the settings panel header (panels.tsx); the demo's dashboard/nav surface was already "Automations".
  • Left as-is (deliberately): the per-stage "Escalation" toggle inside the SLA config manager — that's a distinct SLA property, not the automations surface.

Acceptance criteria status

  • /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).
  • SLA settings tab shows the 3 summary tiles above the config manager.
  • General settings shows a structured Profile form (name / legal name / plan / support email / website / timezone / region / fiscal year).
  • "Automations" naming is consistent across both apps; ConfigGapsPanel hrefs resolve (they point at /admin/{sla,setup,integrations,users,commercial}, all live; no escalation href exists there).

Verify result

  • Mechanical checks (format · lint · typecheck · build) run in CI + the Vercel preview, not here.
  • No check is expected to fail. Clerk backend signatures (createOrganizationInvitation, getOrganizationInvitationList, updateOrganization) verified against the resolved @clerk/backend types; org:<role> matches the existing membership-write idiom.

Notes for review

  • Display name → Clerk org. Editing the Profile display name calls 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.
  • Naming scope. URL slugs stayed escalation on purpose (route-policies, redirects, and revalidatePath targets are unchanged); only user-facing labels moved to "Automations".
  • Invite roles. Custom 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.md


title: Invite teammates, edit your organisation profile, and see access and SLA at a glance date: 2026-07-27T14:50:00Z personas: [admin] slug: admin-parity-fixes pr: https://github.com/sustentus/sustentus/pull/707

Invite teammates, edit your organisation profile, and see access and SLA at a glance

Your 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.md

Admins can now run organisation setup end to end in-product

Who 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>