V1 Web PWA · Surface walkthrough

Studio · Review and Approval Workflows

A per-surface walkthrough of the V1 Web PWA studio surface: layout, states, interactions, data, and cross-references.

walked
9sections5 minread

On this page

Context. surface studio · domain collaboration · route /studio/review-approval-workflows · auth signed-in + studio entitlement · source apps/oshun/web/src/app/studio/review-approval-workflows/page.tsx

Last walked. 2026-06-29 review-approval-workflows real-BFF addendum — Playwright now covers the admin-scoped route render, real approval-workflow catalog GET, default workflow POST/evaluate result, stage table semantics, quick-action targets, loading/error/unauthorized states, malformed JSON client block, live BFF 400 detail, pending submit lockout, and anonymous redirect-before-render. Evidence: WALKTHROUGH/results/v1-real-infra-run-2026-06-22.md §223; spec: apps/oshun/web/e2e/studio-review-approval-workflows.spec.ts. 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; content re-verified 2026-06-03 against current source

Purpose#

Operate review and approval workflows as a live, admin-scoped BFF console. The workspace (StudioReviewApprovalWorkflowsWorkspace) wires a single Approval Gate Lane to the real multi-stage approval-gate evaluator via /v1/admin/studio/approval-workflow: each stage is evaluated for quorum (required approvals), required-role satisfaction, and reject-override; the workflow rollup reports approved/pending/rejected stage counts and points at the current (first non-approved) stage. This is a real domain computation, not a simulation.

Entry points#

  • Studio root (/studio) — discoverable as a collaboration workspace
  • Quick-action links from sibling workspaces (asset preview pipeline, file/media ingestion, commenting/annotation, presence, real-time collaboration, activity/change feeds)
  • Direct URL / bookmark — yes

Layout regions#

page.tsx mounts ShellLayout active="studio", renders StudioReviewApprovalWorkflowsWorkspace, then a single panel containing 6 sibling quickAction links. There is no Route Map panel on this page.

  • Shell header — from ShellLayout
  • Workspace <h1> — "Studio Review & Approval Workflows" (WorkspaceHeading), followed by a data-review-approval-summary paragraph describing the evaluation
  • Approval Gate Lane (<h2> data-aw-lane-heading "Approval Gate Lane") — the catalog/loading/unauthorized/error states, the evaluate form, and the result
  • Quick-actions panelpanel with 6 quickAction links to sibling workspaces (no self-link, no Route Map), anchored by data-review-approval-quick-actions, data-review-approval-quick-action-count="6", and one data-review-approval-quick-action="<workspace-id>" per link

States#

  • Loadingdata-aw-loading "Loading workflow evaluator…" while the GET catalog request is in flight (outcome === null)
  • Unauthorizeddata-aw-unauthorized "Access restricted." on 401/403 (admin scope required); shows the BFF message or "Studio admin scope required to evaluate the workflow."
  • Errordata-aw-error "Could not load the workflow evaluator." on any non-OK catalog response or network failure
  • Ready (form) — catalog loaded; data-aw-enums shows the stage-status and workflow-status counts (for the shipped catalog: 3 stage statuses · 3 workflow statuses), and the data-aw-form form renders
  • Result — after a successful POST, data-aw-result renders the workflow headline + per-stage table
  • Evaluate validation errordata-aw-evaluate-error for invalid JSON, network unavailable, or a non-200 POST (shows the POST detail)
  • Pending evaluate POST — form flips data-aw-form-state="evaluating", submit is disabled with aria-disabled="true" / aria-busy="true" and label "Evaluating workflow…" until the response returns
  • Anonymous user — redirected to /welcome?redirect=%2Fstudio%2Freview-approval-workflows before the workspace root renders

Interactions#

Approval Gate Lane form#

  • Workflow (textarea data-aw-payload, aria-label="workflow json") — seeded with a default JSON payload:

    ```ts
    { stages: [{ stageId, name, requiredApprovals, requiredRole?, approvals: [{ approver, role, decision }] }] }
    ```
    
  • Evaluate workflow (button data-aw-submit, type="submit") — submitEvaluate parses the JSON (rejecting invalid JSON with data-aw-evaluate-error) and POSTs to /v1/admin/studio/approval-workflow/evaluate

  • Client-side malformed JSON block — invalid JSON surfaces "Payload must be valid JSON." and does not send a POST

  • Live BFF invalid payload branch — valid JSON with stages: [] reaches the BFF and surfaces detail: "stages must be a non-empty array"

  • Touch target — the textarea and submit button have measurable boxes; the submit control is ≥44px tall

Result#

  • Headline (data-aw-headline, data-workflow-status) — renders: Workflow {workflowStatus} · current stage: <data-aw-current-stage> · {approvedStages} approved · {pendingStages} pending · {rejectedStages} rejected
  • Stages table (data-aw-stages) — one data-aw-stage-row per stage with data-stage-id, data-status, plus data-aw-stage-name, data-aw-stage-status, data-aw-stage-approvals ({approveCount} (need {approvalsNeeded})), and data-aw-stage-role-ok cells
  • Reject-override precedence — the default fixture proves stage st3 renders rejected even though it has one approval and needs zero more approvals, because one reviewer rejected; workflow status is therefore rejected
  • Current-stage pointer — the default fixture renders current stage st2 (the first non-approved stage)

Quick actions#

  • Open Asset Preview Pipeline workspace
  • Open File and Media Ingestion workspace
  • Back to Commenting and Annotation System workspace
  • Back to Presence and Cursor Systems workspace
  • Back to Real-Time Collaboration Substrate workspace
  • Back to Activity and Change Feeds workspace

Data & contracts#

  • GET catalog: /v1/admin/studio/approval-workflow — fetched on mount with buildBffAuthHeaders() and cache: 'no-store'; returns { stageStatuses[], workflowStatuses[] }

  • POST verb: /v1/admin/studio/approval-workflow/evaluate with body:

    ts
    { stages: [{ stageId, name, requiredApprovals, requiredRole?, approvals: [{ approver, role, decision }] }] }
    

    Returns a 200 result with stages[], workflowStatus, currentStageId, and summary{ approvedStages, pendingStages, rejectedStages }, or a detail error.

  • Persistence: evaluated workflows are stateless in this lane today. The browser posts a payload and renders the returned verdict; no persisted workflow id, audit id, or review queue mutation is returned by this BFF route.

  • Realtime: none — request/response only

  • Client fetch: direct fetch with cache: 'no-store'; no client-side caching

  • Auth/role check: admin-scoped, fail-closed at the BFF (admin:* | admin:studio; 401/403); reached through the signed-in + studio route gate

Cross-references#

E2E coverage#

  • apps/oshun/web/e2e/studio-review-approval-workflows.spec.ts — signed-in admin /studio/review-approval-workflows render; real approval-workflow catalog GET with admin bearer; default workflow evaluate POST through the live BFF; rejected workflow headline/current-stage/summary; all four default stage rows with status, approval counts, and role satisfaction; six quick-action links and target sizes; catalog loading/error; client-side malformed JSON zero-POST; live BFF 400 invalid-payload detail; pending POST disabled/busy state; non-admin 403 fail-closed; anonymous redirect-before-render.
  • apps/oshun/web/e2e/studio-route-render-smoke.spec.ts — broad Studio route render and accessibility smoke coverage includes this route, but does not replace the focused real-BFF workflow spec above.

Open questions / known gaps#

  • Confirm whether evaluated workflows persist their verdicts, or whether the lane stays a stateless evaluator — today it is stateless request/response only
  • Document the reject-override precedence relative to quorum and required-role satisfaction — reject wins first; otherwise quorum plus required-role approval is needed for a stage to become approved
  • Live screen-reader and touch-device manual passes remain outside the automated route spec