Files
Stirling-PDF/frontend/portal/MOCKS.md
T
Reece BrowneandGitHub 2b05865a84 Portal: unified-design surfaces (Policies, Users, Components, Agent Builder, Editor deploy) + Settings rebuild (#6696)
Builds the remaining developer-portal surfaces from the unified design
and rebuilds Settings, on top of the portal scaffold merged in #6686.
All tier-aware, mock-driven (MSW), componentised with Storybook
coverage. Touches only `frontend/portal` + `frontend/shared` — the
editor is untouched.

## New surfaces
- **Policies** — org-wide governance across the five categories
(Ingestion / Security / Compliance / Routing / Retention) with a
designer + per-doc-type overrides
- **Users** — members, roles, invite, tier-scaled SSO/SCIM access
- **Components** — embeddable `@stirling/*` SDK catalogue with
per-action pricing
- **Getting Started** — three-step funnel (use case → analyse a document
→ API key + snippets)
- **Agent Builder** — agent lifecycle (scenarios, tool modes,
evals/golden-sets, versions), reached from Sources
- **Editor deployment** — deploy/pair/operate the editor (targets,
pairing, health, credential rotation, air-gapped bundle), reached from
Infrastructure

## Reworks
- **Documents** → review/approval queue (confidence, extractions, audit
drawer, zero-standing-access elevation); the doc-type catalogue is
retained as a second tab
- **Pipelines** → golden-set pass column + "Promoted from the Editor"
section
- **Infrastructure** → new **Models** tab; deeper **Security** (managed
/ BYOK / HYOK + SOC 2 / ISO 27001 / HIPAA / GDPR / PCI attestations)
- **Home** → "What runs on your PDFs" policy summary + tier-aware
processing-status strip + pipeline-fork wizard

## Settings & shared
- New shared **`SettingsShell`** (grouped left-nav + content pane),
modelled on the editor's account-settings modal so both apps can
converge on one layout
- Portal **Settings** rebuilt on it as scoped sections — Account /
Workspace / Admin (Authentication, Active sessions, Early access)

## Brand
- Adopt the editor's brand mark + favicon; sidebar reads **Stirling
Processor**; app-switcher labels the active app "Processor"

## Mock contract
- Every surface follows the 3-layer pattern (typed `api/*` → MSW handler
→ fixtures); new endpoints documented in `MOCKS.md`. The read contract
is backend-ready; writes are marked `// TODO(backend): <METHOD> <path>`.

## Verification
- tsc (portal + shared) ✓ · eslint ✓ · dpdm (no circular) ✓ ·
`build:portal` ✓ · `storybook:build` ✓ · Prettier ✓

## Deferred (noted, not in scope)
- Unified shell / auth / role→surface routing / Workspace=Plan
(architectural epic)
- Tier rename (Editor / Processor / Bespoke) and the Usage flat-pricing
+ PAYG quick-amounts + Bespoke modal
- Editor adopting the shared `SettingsShell`; converting marked
write-stubs into live `api/` seams
2026-06-18 10:28:03 +00:00

5.7 KiB

Portal data layer — mock backend & handover

The portal is mock-driven. Every screen fetches real HTTP requests through a thin typed API layer; in dev and Storybook those requests are intercepted by MSW and answered with fixture data. Pointing the portal at a real backend is a matter of not registering MSW — no component or API-layer code changes.

The three layers

view (useAsync)  ──►  api/<surface>.ts  ──►  httpJson(fetch)  ──►  MSW handler (dev)   ──►  fixture builder
                          (the contract)                          └► real backend (prod) ─┘
  1. api/<surface>.ts — thin, typed httpJson wrappers. This is the backend contract. Each function documents its endpoint (method, path, query params) and its response type. Nothing else in the app issues fetches.
  2. mocks/handlers/<surface>.ts — MSW handlers that answer those endpoints with mocks/<surface>.ts fixtures. Registered in mocks/handlers/index.ts.
  3. mocks/<surface>.ts — fixture builders and the canonical TS types (re-exported through api/<surface>.ts, so consumers import types from api/).

api/http.ts is the single fetch wrapper (sets headers, throws HttpError on non-2xx). Views consume via useAsync() + useSectionFlags() (hooks/useAsync.ts).

Conventions (consistent across every surface)

  • Tier: tier-specific endpoints take ?tier=free|pro|enterprise. The view passes useTier().tier and refetches on change (useAsync(fn, [tier])).
  • Latency: handlers await delay(120) to exercise loading/skeleton states.
  • Read-only today: surfaces are GET-driven. The few writes (mark-all-read, op run) exist; composer "Deploy", connect-source wizard, and create-key are demo shells (local state, no submit endpoint yet) — wire these to real POSTs during backend integration.

Swapping in a real backend

  1. Stop registering MSW (mocks/browser.ts / the dev bootstrap) — or gate it on an env flag (it's already dev-only via import.meta.env.DEV).
  2. Make httpJson hit your API origin (add a baseURL/proxy in api/http.ts).
  3. Match the response shapes in api/<surface>.ts (the exported types are the spec).
  4. Delete mocks/ once parity is confirmed. Optionally relocate the types from mocks/<surface>.ts into api/ (or a types/ module) so they no longer live beside fixtures — purely cosmetic; the api/ re-exports already shield consumers.

Endpoint catalogue

Surface Method & path Query API fn Response type
Home GET /v1/home/kpis tier fetchHomeKpis KpiEntry[]
Home GET /v1/analytics/usage — fetchUsageSeries UsageSeriesResponse
Home GET /v1/activity — fetchRecentActivity ActivityEvent[]
Home GET /v1/regions/health — fetchRegionHealth RegionHealth[]
Home GET /v1/onboarding — fetchOnboarding OnboardingStep[]
Users GET /v1/users tier fetchUsers UsersResponse
Documents GET /v1/documents tier fetchDocuments DocumentsResponse
Pipelines GET /v1/pipelines · POST /v1/pipelines/:id/promote-to-policy tier fetchPipelines · promoteToPolicy PipelinesResponse
Policies GET/POST /api/v1/policies · GET/DELETE /api/v1/policies/{id} · POST /api/v1/policies/{id}/run — fetchPolicies · savePolicy · deletePolicy · runPolicy PoliciesResponse · Policy
Agent Builder GET /v1/agents tier fetchAgents AgentsResponse
Sources GET /v1/sources tier fetchSources SourcesResponse
Components GET /v1/components tier fetchComponents ComponentsResponse
Infrastructure GET /v1/infrastructure/deployments tier fetchDeployments DeploymentsResponse
Infrastructure GET /v1/infrastructure/api-keys tier fetchApiKeys ApiKey[]
Infrastructure GET /v1/infrastructure/security tier fetchSecurity SecurityConfig
Infrastructure GET /v1/infrastructure/models tier fetchModels ModelsResponse
Infrastructure GET /v1/infrastructure/storage tier fetchStorage StorageConfig
Infrastructure GET /v1/infrastructure/audit-log tier fetchAuditLog AuditLogResponse
Usage & Billing GET /v1/billing/usage — fetchBillingUsage UsageSeriesResponse
Usage & Billing GET /v1/billing/summary tier fetchBillingSummary BillingSummary
Usage & Billing GET /v1/billing/plans — fetchPlanOptions PlanOption[]
Usage & Billing GET /v1/billing/history tier fetchBillingHistory BillingHistoryRow[]
Developer Docs GET /v1/docs/nav — fetchDocsNav DocsNavSection[]
Editor GET /v1/editor/deployment tier fetchEditorDeployment EditorDeploymentResponse
Settings GET /v1/settings tier fetchSettings UserSettings
Notifications GET /v1/notifications · POST /v1/notifications/mark-all-read — — Notification[]
Ops GET /v1/ops/featured · POST /v1/ops/:opId/run — — —
Assistant GET /v1/assistant/suggestions · POST /v1/assistant/messages — — —
Search GET /v1/search/quick-actions — — —

Catalogue generated from mocks/handlers/*.ts. The api/<surface>.ts JSDoc on each function is the authoritative per-endpoint reference.

Policies targets the real backend base /api/v1/policies (Stirling's PolicyController) rather than the mock /v1/... convention — its contract mirrors the live policy engine, so MSW can be dropped with no code change.