Skip to content

UI/UX Enterprise Standards

Status: Approved — canonical for platform console UI work
Last updated: 2026-06-10
Applies to: TenancyEngine.Console, TenaBill.Web console, VectraLabel app, future platform consoles

Principles

  1. Mobile-first — layouts must work on narrow viewports without trapping users in centered overlays.
  2. Enterprise-grade editing — multi-field entities use dedicated surfaces (pages, side panels, inline expansion), not popup CRUD.
  3. Feature surface matches domain size — large configuration domains get their own nav section and sub-routes.
  4. Table row actions navigate — primary create/edit flows go to a route; they do not open a modal by default.

Default: NO modals for create, edit, or view flows

Do not use Modal, Dialog, or centered popups for:

  • Creating or editing records with more than one field
  • Viewing entity detail that users may bookmark or share
  • Configuration wizards for offerings, plans, entitlements, billing, templates, branding, API keys, team roles, or application settings

Allowed uses (narrow exceptions)

UsePattern
Destructive confirmationSmall confirm dialog (delete, revoke, disable webhook) — prefer typed confirm for high-risk actions
Single-field micro-editOne inline field or toggle with immediate save
Mobile pickersBottom sheet or drawer — not a centered modal
Impersonation / security gateShort confirmation with context (who, why, duration)

Mobile-first overlays

On viewports < 768px:

  • Prefer full-page forms or slide-over panels (master-detail)
  • Use bottom sheets for pickers and short confirmations
  • Avoid fixed-width centered modals that clip content or trap scroll

Edit patterns (enterprise)

ComplexityPatternExample
Simple scalarInline edit / click-to-editToggle enabled, rename slug with validation
Few fields on list contextInline expansion panel (accordion row)Quick status change on a table row
Multi-field entityDetail page or side panel (master-detail)Tenant settings, webhook config, API key metadata
Genuinely multi-stepWizard / stepper only when steps are realSignup, onboarding, first-time merchant setup
DestructiveConfirm dialog (not a full edit modal)Revoke key, delete user, disable webhook

Anti-pattern: Stacking multiple modals on one page for features, roles, claims, offerings, environments — each should be a tab section with inline or routed edit.


Feature surface area rules

Large domains get own nav section + sub-pages (never modal CRUD):

DomainExpected structure
Offerings / platform plans / entitlementsList → plan/offering detail → tabs (features, pricing, entitlements, marketing)
Billing & subscriptionsBilling overview → plan change (inline or dedicated step), invoices as sub-routes
Email templates & notificationsCategory list → full-page editor (already correct pattern)
Support / communications (future)Ticket list → ticket detail thread
Custom domains / brandingSettings section → domain wizard page, branding preview page
API keys, webhooksList page → create on /new or side panel; revoke = confirm only
Team & roles / permissionsTeam list → member detail / invite page; roles as admin sub-section
Application configurationApp list → app detail page with tabs; sub-entities as tab sections or nested routes

Standard flow

List page  →  Detail page  →  Configuration tabs / sections
     ↑              ↑
  "Add" navigates   Row click navigates (not modal)

Table row primary actions: navigate to /console/.../:id or /console/.../:id/edit, not setShowModal(true).


Console patterns to follow (good)

PatternLocationWhy
Platform plans list + cardsTenancyEngine.Console/src/pages/PlatformPlansPage.tsxRead-only grid, SectionCard, links outward — no modal CRUD
Platform email templatesTenancyEngine.Console/src/pages/PlatformEmailTemplatesPage.tsxCategory via query param, full-page editor, preview inline
TenaBill email templatesTenaBill.Web/src/pages/console/EmailTemplatesPage.tsxSame category + editor model (one small modal for send-test only)
App detail tabs (structure)TenancyEngine.Console/src/pages/ApplicationDetailPage.tsxTabbed detail layout is correct — modals inside tabs are the problem
Destructive confirm onlyTenaBill.Web/src/pages/console/ApiKeysPage.tsxRevoke uses modal for confirm, not for create/edit
Plan change confirmTenaBill.Web/src/pages/console/BillingPage.tsxConfirmation before mutation — acceptable

Shared form UX (all consoles): @platform/form-uiFriendlyFormError, EmailField + signInHref, debounced field checks (~450ms), password strength aligned with Identity options.


Anti-patterns in current codebase (refactor candidates)

Grep target: Modal, Dialog, popup in console src/.

TenancyEngine.Console — top modal-heavy pages

RankFileModal count (approx.)Issue
1src/pages/ApplicationDetailPage.tsx~11Features, roles, claims, offerings, environments, destructive actions — all modal CRUD on a detail page
2src/pages/TenantsPage.tsx3Tenant create/edit in modals; should be detail routes or expansion
3src/pages/ApplicationsPage.tsx3Application create/edit in modals
4src/components/AppTenantsPanel.tsx3Tenant linkage modals on app context
5src/pages/OrganizationsPage.tsx3Org create/edit modals

Also flagged: UsersPage.tsx (2), TenantUsersTable.tsx + ImpersonateUserModal.tsx (impersonation confirm — keep narrow), ApiKeysPage.tsx (1 confirm — OK).

TenaBill.Web console — modal usage

TB is mostly aligned: confirmations on ApiKeys, Webhooks, Billing. Exception:

RankFileIssue
1src/pages/console/CatalogPage.tsxCreate/edit catalog items in modals — should be catalog item detail page or side panel
2src/pages/console/EmailTemplatesPage.tsxSend-test modal — acceptable micro-action
3–5ApiKeysPage, WebhooksPage, BillingPageConfirm-only — keep

Implementation checklist

When implementing or reviewing UI work:

  • [ ] Read this document before UI work
  • [ ] No new modals for large CRUD unless explicitly tagged micro-edit or confirm-destructive in the task
  • [ ] Large features = dedicated routes — offerings, plans, entitlements, templates, branding, webhooks, team, app config
  • [ ] List → detail → tabs for multi-field entities
  • [ ] Mobile check — no centered modal for primary flows; use drawer/sheet or full page
  • [ ] Table actions navigate, not open modal
  • [ ] PermissionGate / platformPermissions / consolePermissions on gated actions
  • [ ] Loading + error states on every async surface
  • [ ] Tests in same change as feature — unit (+ integration for HTTP)

Reviewer auto-REJECT

Reviewers must reject when:

  • New Modal/Dialog for multi-field create/edit on large domains
  • Mutating API without permission checks (RequirePermissionAsync, PlatformPermissionChecker, TB console guards)
  • New public logic with no tests for non-trivial behavior
  • Incomplete feature (half UI, no API, or vice versa when task required both)
  • Breaks existing E2E/console patterns or repo conventions
  • Automated verification gate failed (dotnet test / npm run build)

TenancyEngine platform documentation