---
path: /trust-safety
surface: admin
domain: safety
auth: signed-in (admin) + scope:admin:workspace:moderation
source: apps/oshun/admin/src/app/trust-safety/page.tsx
status: drafted
last_walked: '—'
---

# Safety · Trust and safety

## Purpose

Moderation cockpit: runs moderation, appeal, crisis, cloned-voice,
avatar-deception, and image-moderation queues with deterministic outcomes and
clear explanations. `operatorPromise`: "Trust and safety operators always know
why a rule fired, who handled it, and what the appeal path is."

## Entry points

- Sidebar item **"Trust & Safety"** (AdminSidebar — safety group)
- Inbox → trust-safety handoff (`inbox → trust-safety` per
  `OSHUN_ADMIN_WORKSPACE_RELATIONSHIPS`) — "Operator opens a moderation, appeal,
  or crisis item from the unified inbox."
- Lilith → trust-safety handoff (`lilith → trust-safety`) — "A flagged
  reputation row requires case review or enforcement."
- Child route: `/trust-safety/voice-abuse` — see `trust-safety-voice-abuse.md`

## Layout regions

Inside `AdminShell`:

- `<WorkspaceEntryPoint workspaceId="trust-safety" ...>`
- When `detail.accessible`, ten panels in this order (each gated by its own
  `detail.accessible &&` ternary so the entry-point fallback
  - panels both render in the happy path):
  * `<TrustSafetyMetricsDashboard dashboard={snapshot.metricsDashboard}>`
  * `<CrisisEscalationList escalations={snapshot.crisisEscalations}>`
  * `<ModerationContentList queues={snapshot.queues} items={snapshot.contentItems}>`
  * `<UserReportsList reports={snapshot.userReports}>`
  * `<ClonedVoiceReviewList reviews={snapshot.clonedVoiceReviews}>`
  * `<AvatarDeceptionReviewList reviews={snapshot.avatarDeceptionReviews}>`
  * `<ImageModerationReviewList reviews={snapshot.imageModerationReviews}>`
  * `<OffenderHistoryList histories={snapshot.offenderHistories}>`
  * `<AppealQueueList appeals={snapshot.appealCases}>`
  * `<SafetyRuleHitsPanel rules={snapshot.safetyRuleHits}>`

`snapshot` is built by `extractModerationSnapshot(detail.result.value)`.

## States

- [ ] Anonymous → middleware redirect to
      `/unauthorized?reason=missing-session&returnTo=/trust-safety`
- [ ] Signed-in (admin) without `admin:*`, `admin:studio`, or
      `admin:workspace:moderation` → `WorkspaceEntryPoint` "Access not granted";
      ten panels hidden
- [ ] Scope ok + BFF ok → all ten panels render with snapshot data
- [ ] Scope ok + BFF `workspace-unavailable` → entry-point "Workspace data
      unavailable"; panels hidden
- [ ] Empty per-queue lists → each panel renders its own empty state (handled
      per component)
- [ ] `bffWorkspaceId` is `moderation` (not `trust-safety`) — the workspace id
      on the page is the IA id but the BFF endpoint is
      `/v1/admin/workspaces/moderation` (see Data & contracts)

## Interactions

Top-level interactive elements live inside each child panel; ten sections in
total. The page itself exposes no buttons or inputs.

- [ ] **TrustSafetyMetricsDashboard** — non-interactive metrics tiles
- [ ] **CrisisEscalationList** — escalation rows with status / SLA
- [ ] **ModerationContentList** — primary content queue with per-row decision
      actions
- [ ] **UserReportsList** — user-submitted reports
- [ ] **ClonedVoiceReviewList** — cloned-voice review rows (overlap with Iris
      voice work — see `trust-safety-voice-abuse.md` and
      `../../isis/isis-voice-cloning.md`)
- [ ] **AvatarDeceptionReviewList** — avatar deception cases
- [ ] **ImageModerationReviewList** — image moderation cases
- [ ] **OffenderHistoryList** — prior actions per offender
- [ ] **AppealQueueList** — appeal cases
- [ ] **SafetyRuleHitsPanel** — per-rule firing counts / details

## Data & contracts

- **Reads**: `loadWorkspaceDetail('trust-safety', session)` →
  `/v1/admin/workspaces/moderation` (note the IA id is `trust-safety` but
  `bffWorkspaceId === 'moderation'` per `admin-ia.ts`); snapshot via
  `extractModerationSnapshot(detail.result.value)` provides ten collections
  matching the panel ordering above
- **Writes**: per-panel (moderation decisions, appeal disposition, rule
  overrides); endpoints owned by individual panel components
- **Realtime**: _None at page level._
- **Auth/role check**: middleware + page
  (`canEnterAdminWorkspace(scopes, 'trust-safety')` → required scopes
  `['admin:*', 'admin:studio', 'admin:workspace:moderation']`)

## Cross-references

- Shell: `shell/01-app-shell.md`, `shell/04-workspace-pattern.md`
- Workspace definition: `libs/oshun/navigation/src/admin-ia.ts` (`trust-safety`
  — `kind: 'moderation-center'`, `operatorRelationship: 'protect'`,
  `bffWorkspaceId: 'moderation'`)
- Child route: `trust-safety-voice-abuse.md`
- Handoff origins (`from → trust-safety`): `../governance/inbox.md`, `lilith.md`
- Handoff destinations (`trust-safety → …`): `../governance/policy.md`,
  `lilith.md`, `../operations/support.md`
- Library: `apps/oshun/admin/src/lib/moderation-detail.ts`
- Component sources: `apps/oshun/admin/src/components/` — ten panels matching
  layout regions above

## Open questions / known gaps

- [ ] The `bffWorkspaceId` mapping (`trust-safety` → `moderation`) should be
      documented in `shell/04-workspace-pattern.md`'s open questions; it is one
      of several BFF-id != IA-id cases
- [ ] Ten panels on a single page is heavy — confirm whether any are tabbed /
      collapsible (the page code renders them flat)
- [ ] Confirm `ClonedVoiceReviewList` relationship with the voice-abuse child
      route and the isis voice-cloning admin route — overlapping concerns
