Operator Backoffice
What this covers / who it's for. The central operator surface as it exists today: what operators (staff of the platform, not of any tenant) can actually do, through which endpoints, under which roles. For who operators are and how they log in, see Personas & access.
An API-first surface — by deliberate choice
The backoffice is API-first today. The original operator UI (Laravel starter-kit Livewire screens) was deliberately removed because it wrote to the database directly, bypassing the command bus that guarantees permission checks and audit records. Any operator UI is being rebuilt on top of the JSON:API below, where every mutation goes through the bus. Until then, "the backoffice" means this API plus a set of operator console commands — there is no operator web UI beyond login and the Horizon dashboard shell.
Every backoffice endpoint runs centrally (cross-tenant), on the operator session guard, behind MFA-capable login; sensitive mutations additionally demand step-up MFA (a fresh re-proof of identity, minutes old, not the login from this morning).
What operators can do today
All under /api/v1/backoffice/*; each capability is owned by its module (linked README has the
endpoint-level specifics).
| Capability | What it covers | Owning module |
|---|---|---|
| Session & MFA | Login, logout, MFA enrolment/management, step-up | authentication |
| Staff management | List operators, change roles, deactivate/reactivate (step-up; a last-super-admin guard prevents locking everyone out) | backoffice |
| Operator invitations | Invite, list, revoke; public accept endpoint for invitees | backoffice |
| Operator role CRUD | Create/update/delete operator roles from the permission catalog (step-up; seeded default roles are protected from edits) | backoffice |
| Compliance operations | Cases (assign, note, escalate, risk, disposition, close), account freeze/unfreeze/close, SAR maker/checker, CTR candidates + filings, travel-rule records, SLA/case metrics and funnel | compliance |
| Support lookups | Read-only tenant directory + per-tenant overview, per-tenant accounts & balances, cross-tenant customer and transaction lookup | support |
| Task-run ledger | Read-only visibility into every tracked background run (fleet sweeps, statement generation): status, per-unit failures, stale triage | task-runner |
| Document forward failures | Read-only register of documents whose forward to the finance rail failed and needs triage | documents |
| Horizon dashboard | Queue health: workers, throughput, failed jobs | backoffice |
Read-only where it should be. The support lookups, task-run ledger, and forward-failure register are deliberately read-only. Cross-tenant reads are by design — operators bypass tenant isolation — but every per-tenant read is explicitly scoped in code, and provider identifiers are accepted as search inputs yet never shown back.
Acting on what you see is console-first. Retrying or cancelling a background run
(tasks:retry / tasks:cancel) and similar interventions are operator console commands, not API
endpoints, until an operator UI needs them.
Roles seeded out of the box
Operator access is permission-gated per action; roles are bundles of permissions. Five defaults ship (see the backoffice README for the exact grants):
| Role | Intended for |
|---|---|
super-admin | Full catalog + a global bypass. The break-glass role. |
operator | General operations: tenant directory, payments/reports views, staff visibility. |
compliance | Audit view/export, payment views + approval, reports. |
platform-support | Fleet support: cross-tenant lookups, tenant directory, task-run triage. |
platform-compliance | Cross-tenant compliance review: KYB/AML/sanctions views, global audit view, cross-tenant reads. |
Two guarantees worth knowing as product facts:
- Privilege escalation is blocked and recorded. Granting
super-adminrequires already being a super-admin; a non-super-admin's attempt is rejected (INSUFFICIENT_PLATFORM_PRIVILEGE) and the attempt itself becomes a durable, tamper-evident audit record — even though the action never happened. More generally, no operator can hand out a permission they do not themselves hold. - Sensitive operator actions require step-up MFA: role changes, staff deactivation, freezes, SAR submission, case dispositions, and role CRUD all re-challenge the operator.
Ship-state honesty
- The operator UI does not exist yet — the API and console are the real surface today.
- The Horizon dashboard gate ships as a stub: outside local development its access allowlist is empty, so no operator can open it in a deployed environment until the gate is wired to real operator identities (a deploy-bound task).
- An operator notification inbox store exists but has no read surface yet (see Notifications & comms).