---
path: /integrations
surface: tenant-admin
domain: integrations
auth: signed-in + tenant:admin (getTenantServerSession)
source: apps/oshun/tenant-admin/src/app/integrations/page.tsx
status: drafted
last_walked: '—'
---

# Integrations

## Purpose

Tenant-scoped read-only cockpit for the `integrations` workspace: shows API-key
authentication results, outbound webhook subscription matching, dead-letter
replay status, and connector health / error-budget / version-pinning — all
computed for the signed-in tenant. Backs the `integrations` workspace
(`configuration` group) in `libs/oshun/navigation/src/tenant-ia.ts`.

## Entry points

- Shell sidebar (`TenantSidebar`) — **"Integrations"** (`shortLabel`) under the
  **Configuration** group, link to `/integrations`
  (`data-workspace-id="integrations"`)
- Workspace grid on `/` (home) — list item `data-workspace-id="integrations"`
  (text only; not a link)
- Direct URL `/integrations` (bookmarkable; middleware-gated)

## Layout regions

Inside `TenantShell` (`TenantSidebar` left, `TenantHeader` top,
`<main id="tenant-main">`):

- **Header**: `TenantHeader` shows `tenant · <tenantId>` › workspace label
  **"Integrations"** (`getOshunTenantWorkspaceDefinition('integrations').label`)
- **Main**:
  `<section data-testid="tenant-integrations-panel" data-tenant-id={tenantId}>`
  - `<h1>Integrations</h1>` + subtitle paragraph
  - `.summaryGrid` — four `.summaryItem` tiles: **API key auth**, **Webhook
    matches**, **Replay status**, **Circuit**
  - `.table` — connector table: columns **Connector**, **Version**, **Error
    budget**, **Health**

## States

- [ ] **Loading** — N/A; server component renders fully-resolved fixture data in
      one pass (no client fetch, no skeleton)
- [ ] **Empty** — N/A; data is a hardcoded in-page fixture (single connector
      `Canvas LMS`), never empty
- [ ] **Populated (short)** — exactly one connector row + four summary tiles
      always render (`auth.authenticated` → "Accepted", `matchingSubscriptions`
      length, `replay.status`, `circuit.state`)
- [ ] **Populated (long)** — N/A; fixture is fixed-size (1 connector)
- [ ] **Error (recoverable)** — N/A; no runtime query to fail
- [ ] **Error (unrecoverable)** — no session →
      `redirect('/unauthorized?reason=missing-session&returnTo=/integrations')`
- [ ] **Offline** — N/A for data (SSR-rendered); shell chrome served from cache
      if SW present (verify: no SW registered in this app)
- [ ] **Gated** — `getTenantServerSession()` returns null
      (missing/invalid/expired token, or scopes fail `canEnterTenantShell`) →
      redirect to `/unauthorized`; sidebar renders this workspace `Locked` when
      `canEnterTenantWorkspace` is false (currently never, since all workspaces
      share the shell scope)
- [ ] **Standalone PWA** — verify; layout sets `themeColor #0f172a`, no manifest
      confirmed in source

## Interactions

The page itself exposes **no buttons, inputs, or links** in `<main>` — it is a
static read-only report. All interactivity is shell chrome:

- [ ] **Skip to main content** (link, `TenantShell`)
  - Function: anchors to `#tenant-main`
  - Keyboard: first focusable element; Enter/Space activates
  - Screen reader: announces "Skip to main content"
- [ ] **Sidebar workspace links** (links, `TenantSidebar`)
  - Function: navigate to each accessible workspace `path`; current item carries
    `aria-current="page"`; inaccessible items render as
    `<span aria-disabled="true">` with a **Locked** tag
  - Screen reader: announces `shortLabel` (+ "Locked" when gated)
- [ ] **Connector / summary cells** — non-interactive text/`code`/`badge`
      output; no controls

## Data & contracts

- **Reads**: no BFF/network read. The page calls pure functions from
  `@oshun/tenant-console` on in-page fixtures:
  - `authenticateApiKey({ providedTokenHash, providedIp, key: ApiKey, nowUnixSeconds })`
    → `auth.authenticated`
  - `subscriptionsForEvent([WebhookSubscription], event)` → matching count
  - `replayDelivery({ delivery: WebhookDelivery, nowUnixSeconds })` →
    `replay.status`
  - `evaluateCircuitBreaker({ connector: ConnectorRegistration, nowUnixSeconds })`
    → `circuit.state`
  - `NOW` is a frozen constant `Date.UTC(2026, 4, 11, 15)` (seconds)
- **Writes**: _None._
- **Realtime**: _None._
- **Caching**: SSR (server component); fixture is deterministic so output is
  stable per `tenantId`
- **Auth/role check**: page calls `getTenantServerSession()`
  (`apps/oshun/tenant-admin/src/lib/server-session.ts`); middleware
  (`src/middleware.ts`) redirects unauthenticated non-public paths to
  `/unauthorized`

Contracts: `ApiKey`, `ConnectorRegistration`, `WebhookDelivery`,
`WebhookSubscription` from `@oshun/tenant-console`
(`libs/oshun/tenant-console`).

## Cross-references

- Workspace definition: `libs/oshun/navigation/src/tenant-ia.ts` (`integrations`
  — group `configuration`, `requiredScopes: ['tenant:admin:*']`,
  `iconToken: 'link'`)
- Shell: `TenantShell.tsx`, `TenantSidebar.tsx`, `TenantHeader.tsx`
- Sibling routes: [members.md](members.md),
  [notifications.md](notifications.md), [policy.md](policy.md),
  [roles.md](roles.md), [status.md](status.md)
- Gate page: [unauthorized.md](unauthorized.md)
- Conventions:
  [../WALKTHROUGH/00-conventions.md](../WALKTHROUGH/00-conventions.md)

## Open questions / known gaps

- [ ] Page renders a static fixture, not the live tenant integrations registry —
      no real API-key/webhook/connector BFF endpoint is wired (V1 placeholder).
      Document the eventual BFF route once integrations data is wired
      tenant-side.
- [ ] No empty / error / long states are reachable until live data replaces the
      fixture.
- [ ] Verify whether a PWA manifest / service worker exists for tenant-admin
      (none found in `src/`).
