---
title: Backoffice
description: Operators sign in with Okta; the backoffice server calls the API as itself.
sidebar:
  order: 4
---

The backoffice reads shop data only through the `/v1/ops/*` procedures. Its adapter calls the typed client
(`client.ops.orders.search(input, { context: { token, headers: { operator, traceparent } } })`); `problemOf` maps a
failure to `ShopDataError(error, status, detail)`, a timeout to `shop_unavailable` (503) and a credential failure to
`shop_credentials` (503). The Okta persona checks (`docs/okta-personas.md`) need a real Okta org.

```mermaid
sequenceDiagram
  autonumber
  participant O as Operator browser
  participant BO as Backoffice
  participant Okta as Okta
  participant A0 as Auth0
  participant API as Shop API
  participant Domain as Domain functions
  participant Audit as Backoffice audit DB
  O->>BO: Open dashboard
  BO->>Okta: OIDC sign-in
  Okta-->>BO: Verified subject, email and groups
  BO->>BO: Resolve operator session and operatorAction role check
  BO->>A0: Cached client_credentials token, ops:read
  A0-->>BO: Backoffice M2M token
  BO->>API: GET /v1/ops/* with Bearer, Operator and traceparent
  API->>API: Check dedicated client, scope and strict attribution
  API->>Domain: OperatorActor and parsed query
  Domain->>Domain: Require viewer role, read D1 or read-only Management API
  Domain-->>API: Allowlisted result or stable error
  API-->>BO: Result and attributed completion log
  BO->>Audit: One operatorAction audit row, including errors or denial
  BO-->>O: Page data or existing failure state
```

The backoffice keeps Okta sign-in, role checks, operator sessions and `operator_audit_events` in its own `DB`.
`ShopData` has only an API adapter. Overview composes four concurrent
reads; customer detail composes three. The token supplier coalesces issuance and caches tokens in memory and the
Workers Cache API. API problems preserve their original codes in audit rows and page states.

The wire format is bounded to 2 KB:

```text
Operator: v1.<unpadded base64url of UTF-8 JSON>
{ sub, email, name: string | null, roles: ["viewer", "auditor"], sid: "ops_…" }
```

`roles` may contain zero to two allowed roles; domain reads require `viewer`. The schema rejects extra keys,
unknown versions, malformed encoding and invalid session identifiers. Only the dedicated backoffice client may
send `Operator`; its token cannot carry guest or website session context headers. Storefront and MCP callers are
refused on every ops route, even if their token claims `ops:read`.

**The backoffice client secret is the authority; the header supplies attribution only.** Possession of that secret
permits all operator reads and can claim any staff identity. This does not provide per-person API authorization.
The backoffice audit row remains the system of record. API logs add `api_operator_call` with operation, staff
subject, email, session, status, request ID and valid trace context. They never include order or customer responses.
Trace/request identifiers remain distinct from the non-secret owned action ID. Public claims alone cannot establish a
trusted service hop; actual private sender facts and the API response request ID are paired at read time.

Customer identities come from the API's read-only `ops_management` Management client, whose grant is exactly
`read:users`. The backoffice itself has no shop database or Management binding; it binds only its own audit and
session database.

## Diagnostic investigation

Auditors read normalized ShopDatabase diagnostics through the API, without a direct ShopDatabase binding. The separate
named `BackofficeAudit` private entrypoint accepts only backoffice-owned observations. Source/producer/simulation and
actual executing service/runtime remain distinct from the collecting API. No historical ledger backfill is performed.
The local ledger stays the source of truth and awaited access gate; its new successful entries project best effort.

Event, actor-chain, timeline and health reads require the live auditor session and local gate. Raw header/token release
also requires an admitted API release event; neither gate can be bypassed if storage is unavailable. The six-tab right-hand
sheet retains investigation context and offers Events/Flow. Its credential cache is ephemeral and raw responses are
private/no-store. Reader auditing cannot prevent replay of intentionally retained non-cookie capabilities.

All three histories have30-day expiry: diagnostics, customer activity and local operator access. The backoffice's hourly
handler cleans its own ledger; API cleanup remains separate. See [diagnostic investigations](/runbooks/audit-investigations)
for bounded capture, cursor/Flow evidence, credential authority, stream setup and restore policy.
