---
path: /studio/background-jobs-progress-ux
surface: studio
domain: operations
auth: signed-in + studio entitlement
source: apps/oshun/web/src/app/studio/background-jobs-progress-ux/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; body
  re-derived 2026-06-03 from current source (lane-console architecture)'
---

# Studio · Background Jobs and Progress UX

## Purpose

Compute a scheduler snapshot with the real deterministic job-scheduler engine:
each job is resolved to a derived status (succeeded / running / runnable /
blocked-on-dependencies / retry-pending / exhausted) honouring `dependsOn`
gating and retry budgets, runnable jobs are dispatched by priority into the free
`maxConcurrency` slots, and the whole set is rolled up into an overall progress
percent plus per-subject issues. The workspace
(`StudioBackgroundJobsProgressUxWorkspace`) is an admin lane console that loads
the scheduler catalog on mount and posts a jobs payload for scheduling.

## Entry points

- **Studio root** (`/studio`) — discoverable as an operations workspace
- **Sibling quick actions** — Asset Preview Pipeline, File and Media Ingestion,
  Review and Approval Workflows, and Activity and Change Feeds workspaces link
  in/out
- **Direct URL / bookmark** — yes

## Layout regions

`page.tsx` mounts `ShellLayout active="studio"`, renders
`StudioBackgroundJobsProgressUxWorkspace`, then a single `panel` of 4
`quickAction` links. There is no breadcrumb and no Route Map panel on this route.

- **Workspace heading** (`<h1>` via `WorkspaceHeading`): "Studio Background Jobs
  & Progress"
- **Summary** (`data-background-jobs-summary`): dependency-gated statuses,
  retry/exhaustion, priority dispatch, progress rollup
- **Job Scheduler Lane** (`<h2>` `data-bj-lane-heading`): the load-states +
  scheduling form + result region
- **Footer quick actions** (`panel`): 4 sibling `quickAction` links

## States

- [ ] **Loading** — `data-bj-loading` "Loading job scheduler…" while the catalog
      request is in flight
- [ ] **Unauthorized** — `data-bj-unauthorized` "Access restricted." on a
      401/403 (admin scope required)
- [ ] **Error** — `data-bj-error` "Could not load the job scheduler." on a
      non-OK catalog response or network failure
- [ ] **Ready (form)** — catalog loaded: `data-bj-enums` states / derived-statuses
      counts + the `data-bj-form` JSON form
- [ ] **Result** — `data-bj-result` with the progress / dispatch / running /
      blocked headline, the per-job table, and an issues list
- [ ] **Validation** — `data-bj-schedule-error` for invalid JSON or a non-200
      schedule response

## Interactions

### Job Scheduler Lane (form)

- [ ] **Jobs JSON** (`textarea` `data-bj-payload`, `aria-label` "jobs json") —
      payload of `{ maxConcurrency, jobs[{ jobId, state, priority, attempts,
      maxAttempts, progress, dependsOn[] }] }`
- [ ] **Compute schedule** (`button` `data-bj-submit`, `type=submit`) — POSTs the
      parsed payload to `\`${BJ_ENDPOINT}/schedule\``

### Result region

- [ ] **Headline** (`data-bj-headline`) — `data-bj-overall-progress` percent,
      `data-bj-dispatch-count`, running and blocked counts
- [ ] **Jobs table** (`data-bj-jobs`) — rows `data-bj-job-row` with `data-status`
      + `data-will-dispatch`, cell `data-bj-job-status`
- [ ] **Issues list** (`data-bj-issues`) — rows `data-bj-issue-row` with
      `data-issue-code` + `data-issue-subject` (rendered only when present)

### Footer quick actions

- [ ] **Back to Asset Preview Pipeline workspace** →
      `/studio/asset-preview-pipeline`
- [ ] **Back to File and Media Ingestion workspace** →
      `/studio/file-media-ingestion`
- [ ] **Back to Review and Approval Workflows workspace** →
      `/studio/review-approval-workflows`
- [ ] **Back to Activity and Change Feeds workspace** →
      `/studio/activity-change-feeds`

## Data & contracts

- **Reads**: GET `/v1/admin/studio/background-jobs` (catalog: `jobStates`,
  `jobStatuses`) on mount
- **Writes**: POST `/v1/admin/studio/background-jobs/schedule`
- **Realtime**: none
- **Client fetch**: `buildBffAuthHeaders()`, `cache: 'no-store'`,
  abort-on-unmount
- **Auth/role check**: admin-scoped, fail-closed (401/403 → unauthorized); route
  is signed-in + studio via the proxy gate

## Cross-references

- Parent: [`../studio-overview.md`](../studio-overview.md)
- Sibling:
  [`studio-resilience-error-ux.md`](./studio-resilience-error-ux.md),
  [`studio-observability-operational-dashboards.md`](./studio-observability-operational-dashboards.md),
  [`studio-metrics-analytics-instrumentation.md`](./studio-metrics-analytics-instrumentation.md)
- Source:
  `apps/oshun/web/src/components/studio/StudioBackgroundJobsProgressUxWorkspace.tsx`

## Open questions / known gaps

- [ ] Confirm where the `/v1/admin/studio/background-jobs` BFF route sources its
      scheduler engine (module + which `admin:*` scopes)
- [ ] Document whether the snapshot is purely an evaluator or whether dispatched
      jobs are actually enqueued anywhere downstream
