Namaste Ji by Ayushman Dash

Docs / console/content-surfaces.md · mirrored from the repo

Back-office — Content Production surfaces (IA + wireframes)

Status: design / brainstorm. Low-fidelity — this fixes information architecture, states, actions, and the API contract each screen implies, not final visual design (the console already has its theme + components in apps/console). Wireframes were produced in the design session; this doc is the durable capture.

Companion to docs/CONTENT-PRODUCTION.md §14 (the surface list) — that doc owns the pipeline; this one owns how an operator sees and drives it.

Why design the UI now

The async OpenAI Batch model (up to ~48h end-to-end, partial failures, eval freshness/staleness) is hard to make legible. The screen is the forcing function for the API contract — sketching it tells us exactly which states + fields the backend must expose before we write a migration. It also honours the project’s first principle: the content pipeline is itself a product surface.

Design principles

  • Reuse the existing console (React + Vite, CDS theme, apps/console components). New surfaces are new routes, not a new app.
  • Single + bulk actions are first-class on every list (Production, Staging, Samples, Heimdall flagged, DLQ) — backed by batch endpoints, never per-row loops.
  • URL-state: tab / filters / selection persist in the URL and survive refresh (useSearchParams) — see memory ui-url-state-preservation.
  • Make the async waits legible: anywhere a thing sits in a ~24h batch, show elapsed + ETA, not just a spinner.

Information architecture

A new top-level “Content production” section in the sidebar, with a horizontal tab group:

Content production
  ├─ Production      ← batch-centric live pipeline (default)
  ├─ Staging gallery ← quarantined assets, visual QA + publish
  ├─ Samples         ← versioned sample sets + execute-batch
  ├─ Heimdall        ← quality evals (timeline, scorecards, flagged)
  └─ DLQ             ← failed shots, retry/reject   [badge: count]

RBAC gates visibility per tab (mirrors permissions.ts

  • the new perms in CONTENT-PRODUCTION.md §15); MVP = admin only.

1. Production board (default)

Question it answers: where is everything right now, and what’s stuck?

Layout

[ tabs ]
[ metric cards: Awaiting batch · Staged · Failed · Spent today ]
[ bulk bar: ☑ N selected · retry failed · hold ]   [ filters: brief ▾ · stage ▾ ]
[ batch card ]   ← one per content batch
   ☑  Diwali diyas · hi · 200 shots            [ image batch · 6h elapsed · ETA ~18h ]
      brief b7 · strategy@v7
      ▓▓▓▓▓▓ in-batch  ▓ rendered  ▓ embedding  ▓ staged  ▮ failed   (segmented bar, counts)
[ batch card ] … staged · ready for QA → [run QA] [open in staging] [retry 8]
[ batch card ] … assembling JSONL
[ legend: in batch · rendered · embedding · staged · failed ]

Key states per batch: assembling → image batch (waiting) → rendered → embed batch (waiting) → staged → in QA → published; plus a failed count. The active OpenAI phase shows elapsed + ETA (ETA ≈ submitted_at + 24h, best-effort).

Actions: select → bulk retry-failed / hold; per-batch run-QA, open-in-staging, retry-N-failed.

API contract this implies (validates generation_batch in CONTENT-PRODUCTION.md §16): one grouped query returning, per batch — { batch_id, brief_id, strategy_version, total, counts_by_stage{}, active_phase, phase_submitted_at, cost_cents, failed_count }. Bulk actions → batch endpoints (POST /batches/:id/retry, …/hold). Live updates via the run-event stream (CONTENT-PRODUCTION.md §17).


Question: what’s quarantined, does it look right, and can I publish it?

Layout: thumbnail grid of STAGED assets; left filters (brief, variety cell, eval-status: scored / flagged / un-evaluated); multi-select → bulk publish / unpublish / reject. Each tile shows the thumbnail, a tiny eval badge, and select checkbox; click → asset detail (variants, metadata, scorecard, provenance).

Contract: paged asset query with facet filters (status, brief_id, variety_cell, eval_status); thumbnail + placeholder served from R2/CF Images; publish/unpublish/reject = bulk endpoints honouring the veto (refuse UNRELEASABLE). RBAC content:publish.


3. Samples

Question: do the probes look good — ship the batch fresh, or fold the samples in?

Layout: per brief, a list of versioned sample sets (samples@v1, v2…); open one → side-by-side tiles with per-asset scorecards. Primary action Execute batch with the toggle: include approved samples (count toward brief.count, generate the remainder) vs generate fresh (samples were a probe; ignore in count).

Contract: sample_sets / sample_items (CONTENT-PRODUCTION.md §16); samples are sync-rendered (fast feedback) and quarantine-discarded unless promoted. RBAC content:sample.


4. Heimdall (quality evals)

Question: is the staged content safe to ship, and is this eval still trustworthy?

Layout

[ eval-run v5 status card ]
   84 / 1,200 sampled · stratified + risk-weighted · 95% CI ±5% · 320 staged since
   [ 27% stale ]            [ extend eval +50 ]  [ re-run (fresh) ]
[ composite-score trend across runs ]   [ v5 per-metric bars ]
   bars per eval-run                       brand-fit · aesthetic · legibility · …
   red dot = veto count (not averaged)     ▸ cultural-correctness veto: N unreleasable
[ flagged inbox ]  ☑ asset · reason (veto/low) · [view]   + bulk reject / override

The novel bits (CONTENT-PRODUCTION.md §12):

  • Freshness/staleness front-and-centrestaleness% = new_staged_since_eval / population; a STALE badge past threshold; CTAs extend eval (+N) (sequential sampling into the same run) vs re-run fresh.
  • Sampling provenance — “84/1,200 sampled, 95% CI ±5%”; drill-in lists which assets were evaluated (eval_samples).
  • Cultural-correctness veto is broken out, never averaged (CP-4) — a hard gate that blocks publish; shown as a distinct red callout + red veto-count dots on the trend.
  • Flagged inbox — only flagged/vetoed/low-sampled assets reach a human; single + bulk reject / override-veto (eval:override).

Contract: eval_runs (snapshot, sampling config, freshness), asset_scorecards, eval_samples (provenance); metrics are Langfuse prompts (CD-3). RBAC eval:read / eval:run / eval:override.


5. DLQ inbox

Question: what failed, why, and can I retry or drop it?

Layout: list of failed shots — thumbnail (if any), shot/brief, structured reason (batch per-request error, expiry, post-processing failure), attempt count; single + bulk retry (re-batches) / reject. RBAC content:retry.

Contract: shots/generation_batch error_file_id rows surfaced with reason + attempts; retry → re-assemble a fresh small batch (CONTENT-PRODUCTION.md §5.3).


Open questions

  • Live updates: poll vs SSE (the planned notification service) for the Production board’s batch-phase + counts — start with poll, move to SSE when the notification port lands (NOTIFICATION-SERVICE.md).
  • Asset detail view depth (variants, full scorecard, lineage) — its own route vs a drawer.
  • Whether Samples and Staging share one asset-grid component (likely yes).
  • Final visual pass once these IA + contracts are agreed (this doc is structure only).