---
path: /studio/aja/content-security
surface: studio
domain: aja
auth: signed-in + studio entitlement
source: apps/oshun/web/src/app/studio/aja/content-security/page.tsx
status: walked
last_walked:
  '2026-07-26 authority-boundary runtime coverage — unbound deploy authority,
  disabled mutations, responsive layout, and automated WCAG 2.1 AA scan'
---

# Studio Aja · Content Security

## Purpose

Leaf lane console for content access governance. The catalog is always
available, but decisions are authoritative only when the BFF is explicitly bound
to an owning deploy service that the delivery/decrypt path consumes. The default
deployment is currently unbound: it reports
`aja_content_security_authority_not_configured`, disables all controls, and
returns 503 for direct mutation requests. `ContentSecurityStore` is retained
only as an explicitly injected process-local test/development adapter.

## Entry points

- **Direct URL / bookmark** — `/studio/aja/content-security`.
- **Studio nav** — Domain-bridge studios section of `/studio`.
- **Embedded** — appears as the Content Security Lane inside
  `/studio/aja/asset-storage`.
- **Sibling quick-actions** — Content Moderation, Consent Management, Privacy
  Protection, Data Retention.

## Layout regions

`page.tsx` renders inside `<ShellLayout active="studio">`:

- **Breadcrumb panel** (`data-aja-content-security-breadcrumbs`):
  `<nav aria-label="Aja Content Security breadcrumbs">` → `Studio` (link) /
  `Aja` (plain text) / `Content Security` (`aria-current="page"`).
- **Workspace** `<StudioAjaContentSecurityWorkspace />`:
  - `<h1>` "Aja Content Security Workspace" + summary
    (`data-aja-content-security-summary`).
  - The access-control lane (states below).
- **Route Map panel** (`data-aja-content-security-route-map`, `<h2>` "Route
  Map"): 6 `STUDIO_AJA_CONTENT_SECURITY_ROUTE_MAP` entries (path + purpose) —
  primary, scenes, exports, revisions, parity, governance.
- **Quick-action lane**: five `Link.quickAction` anchors (no self-link).

## States

The lane fetches `GET /v1/admin/aja/content-security` on mount.

- [ ] **Loading** — `data-aja-cs-loading` "Loading access controls…".
- [ ] **Unauthorized** — `data-aja-cs-unauthorized` (401/403; default message
      "Aja workspace scope required to view content security.").
- [ ] **Error** — `data-aja-cs-error` (non-2xx, malformed, or network).
- [ ] **Ready (controls)** — `data-aja-cs-controls` with the resource/grantee
      inputs + permission select + Grant/Check/Revoke buttons.
- [x] **Authority unavailable** — `data-aja-authority-status="content-security"`
      names the boundary; all fields and mutation buttons are disabled and emit
      no request.
- [ ] **Grant result** — `data-aja-cs-grant-result` (`data-aja-cs-active`).
- [ ] **Check result** — `data-aja-cs-check-result` (`data-aja-cs-allowed` +
      effective permissions).

## Interactions

### Access-control controls (`data-aja-cs-controls`)

These controls are enabled only when `authority.configured` is true.

- [ ] **resourceId** — input `data-aja-cs-field-resource` (default
      `resource-1`).
- [ ] **granteeId** — input `data-aja-cs-field-grantee` (default `user-1`).
- [ ] **permission** — select `data-aja-cs-field-permission` (options from the
      catalog `permissions`).
- [ ] **Grant** — `data-aja-cs-grant`; fires
      `POST /v1/admin/aja/content-security/grants` (`resourceType: 'content'`,
      `granteeType: 'user'`, `createdBy: 'studio-operator'`).
- [ ] **Check** — `data-aja-cs-check`; fires
      `POST /v1/admin/aja/content-security/check`.
- [ ] **Revoke** — `data-aja-cs-revoke` (disabled until a grant exists); fires
      `POST /v1/admin/aja/content-security/grants/{id}/revoke`.

### Route Map

- [ ] **Route entries** (6) — non-interactive listing.

### Quick-action lane

- [ ] **"Open Aja Content Moderation workspace"** →
      `/studio/aja/content-moderation`
- [ ] **"Open Aja Consent Management workspace"** →
      `/studio/aja/consent-management`
- [ ] **"Open Aja Privacy Protection workspace"** →
      `/studio/aja/privacy-protection`
- [ ] **"Open Aja Data Retention workspace"** → `/studio/aja/data-retention`
- [ ] **"Back to Studio workspace index"** → `/studio`

## Data & contracts

- **Reads**: `GET /v1/admin/aja/content-security` (catalog: `authority`,
  `permissions`, `resourceTypes`, `granteeTypes`).
- **Writes**: `POST …/grants`, `POST …/check`, `POST …/grants/{id}/revoke`;
  valid requests return 503 while the deploy authority is unbound.
- **Realtime**: none.
- **Caching**: client fetch on mount (`cache: 'no-store'`); SSR shell.
- **Auth/role check**: BFF endpoints admin-scoped + fail-closed (401/403 →
  unauthorized render); route gated signed-in + studio via proxy.

## Cross-references

- Parent: [`../../studio-overview.md`](../../studio-overview.md)
- Aggregator that embeds this lane:
  [`./studio-aja-asset-storage.md`](./studio-aja-asset-storage.md)
- Siblings (quick-actions): `/studio/aja/content-moderation`,
  `/studio/aja/consent-management`, `/studio/aja/privacy-protection`,
  `/studio/aja/data-retention`
- Component sources:
  - `apps/oshun/web/src/components/studio/StudioAjaContentSecurityWorkspace.tsx`
  - `apps/oshun/web/src/components/studio/StudioAjaContentSecurityRouteMap.ts`

## Open questions / known gaps

- [ ] Bind an owning access-control service used by real delivery, sharing, and
      decrypt enforcement paths before enabling decisions in production.
- [ ] Route Map lists `scenes`/`exports`/`revisions`/`parity`/`governance` child
      routes that are not yet implemented as pages.
