Context. surface tenant-admin · domain meta · route / · auth signed-in (tenant) + scope:tenant:admin:{tenantId} (or tenant:admin:*) · source apps/oshun/tenant-admin/src/app/page.tsx
Last walked. —
Purpose#
Arrival view for the tenant cockpit: it greets the signed-in tenant admin with
their tenant id and lists every tenant-admin workspace (label + primary job) so
they can jump into members, identity, policy, audit, and the rest. It is the
home workspace defined in @oshun/navigation
(OSHUN_TENANT_WORKSPACE_MODEL).
Entry points#
- Direct URL
/(default landing after a tenant session is issued). /handoff"Continue to tenant home →" link (after IdP issues a tenant-scoped session — see handoff.md)./unauthorized→/handoff?returnTo=/chain once a session exists.- Shell sidebar Core › Home item (
TenantSidebar,shortLabel: 'Home').
Layout regions#
Wrapped in <TenantShell session currentWorkspaceId="home">:
- Sidebar (
TenantSidebar): Oshun brand + "Tenant cockpit" mode, tenant id label, three groups (Core / Governance / Configuration) of workspace links. - Header (
TenantHeader):tenant · <tenantId>badge › workspace label ("Tenant home"); user id on the right. - Main (
#tenant-main,data-testid="tenant-home-page"):<h1>Tenant home</h1>- Welcome paragraph containing
<code data-testid="tenant-home-tenant-id">. <section aria-labelledby="tenant-workspace-grid-heading">with<h2 id="tenant-workspace-grid-heading">Workspaces</h2>and a<ul data-testid="tenant-workspace-grid">of all 13 workspace definitions.
States#
- Loading — N/A; server component renders synchronously from
getTenantServerSession()+listOshunTenantWorkspaceDefinitions()(no client fetch, no Suspense boundary). - Empty — N/A; the workspace list is sourced from a static model
(
OSHUN_TENANT_WORKSPACE_IDS, 13 entries) and is never empty. - Populated (short) — N/A; the list is always exactly the 13 canonical workspaces.
- Populated (long) — N/A; fixed-length static list.
- Error (recoverable) — N/A; no query to fail.
- Error (unrecoverable) — no in-page handler; a thrown render error
surfaces via Next's default error boundary (no custom
error.tsx). - Offline — N/A as a write/fetch concern; the page is fully server rendered. (verify: no service worker registered for tenant-admin.)
- Gated — no session →
getTenantServerSession()returnsnull→redirect('/unauthorized?reason=missing-session&returnTo=/'). Middleware redirects unauthenticated requests first (defense-in-depth duplicate). - Standalone PWA — N/A;
layout.tsxsetsrobots: { index: false }and a viewport but ships no manifest/installability. (verify.)
Interactions#
- Workspace list items (
<li data-workspace-id={definition.id}>)- Function: render-only — each shows
<strong>{label}</strong> — {primaryJob}for all 13 workspaces. The list items are NOT links (navigation links live in the sidebar; see Cross-references). - Keyboard: not focusable (plain text).
- Screen reader: announced as list items under the "Workspaces" heading.
- Touch target: N/A (non-interactive).
- Mobile (≤ 640 px): inherits
TenantShelllayout. - Disabled when: N/A.
- Offline behavior: N/A (static).
- Telemetry: None.
- Function: render-only — each shows
- Shell-level interactions (sidebar links, skip link) are documented in
Cross-references and belong to
TenantShell.
Data & contracts#
- Reads:
getTenantServerSession()(cookieoshun-tenant-session, parsed byparseTenantSessionToken) →TenantServerSession;listOshunTenantWorkspaceDefinitions()from@oshun/navigation→OshunTenantWorkspaceDefinition[]. No BFF call. - Writes: None.
- Realtime: None.
- Caching: SSR (dynamic — reads request cookies via
next/headers). - Auth/role check:
middleware.ts(redirects to/unauthorizedwhen the cookie is missing/invalid) + page-levelgetTenantServerSession()which callscanEnterTenantShell(scopes, tenantId)— requirestenant:admin:*ortenant:admin:{tenantId}.
Cross-references#
- Workspace/IA model:
libs/oshun/navigation/src/tenant-ia.ts(OSHUN_TENANT_WORKSPACE_MODEL,home= groupcore, path/). - Shell components:
apps/oshun/tenant-admin/src/components/TenantShell.tsx,TenantSidebar.tsx,TenantHeader.tsx. - Sibling routes: agents.md, audit.md,
content.md, data.md, handoff.md,
help.md, identity.md. Workspaces without files
yet:
/members,/roles,/integrations,/policy,/notifications,/status. - Operator-admin counterpart shell pattern:
../ADMIN_WALKTHROUGH/workspaces/operations/analytics.md.
Open questions / known gaps#
- Sidebar groups in
TenantSidebarcover onlycore,governance,configuration(13 workspaces). Confirm the home-page list (all 13 vialistOshunTenantWorkspaceDefinitions) and sidebar grouping stay in sync. - No custom
error.tsx/not-found.tsx/loading.tsxinsrc/app— confirm whether Next defaults are acceptable for tenant-admin. - List items are non-navigable; verify intent that home is purely an index and all navigation is via the sidebar.