UX-CONTENT-PACKS.md
This document defines the UX contract for Content Packs.
Goal:
- make reusable content packaging simple for authors
- keep publish/install behavior deterministic and auditable
- expose lineage clearly so operators can defend provenance without backend knowledge
Capability Baseline (Validated 2026-02-25)​
Backend-live now:
- pack management:
GET /api/v1/content-packsPOST /api/v1/content-packsGET /api/v1/content-packs/\{id\}PATCH /api/v1/content-packs/\{id\}
- item curation:
POST /api/v1/content-packs/\{id\}/itemsPATCH /api/v1/content-packs/\{id\}/items/\{itemId\}DELETE /api/v1/content-packs/\{id\}/items/\{itemId\}
- publish/install:
POST /api/v1/content-packs/\{id\}/publishPOST /api/v1/content-packs/\{id\}/revisions/\{revisionId\}/install
- provenance:
GET /api/v1/content-packs/\{id\}/revisions/\{revisionId\}/lineage
Current backend behavior to honor in UX:
- write operations require
Idempotency-Key. - pack permission gates currently reuse authoring caps:
- read:
questions.read - write:
questions.write
- read:
- publish rejects invalid state (for example empty pack).
- install creates draft evaluations/versions from published revision items.
0. Pack Doctrine (MUST)​
- Packs are reusable bundles of evaluation versions, not live links to mutable authoring state.
- Publish is the trust boundary: a revision hash and manifest are frozen at publish time.
- Install is additive and auditable: it creates imported draft content; it does not mutate source assets.
- Lineage is first-class: every install should be traceable back to revision + source evaluation version.
- UX must be version-forward and provenance-forward, not hidden behind generic "library" language.
0.1 Packs Interface Guardrails (MUST)​
- Publish/install flows must be explicit about scope and downstream impact before confirmation.
- Lineage visibility must remain first-class and accessible (keyboard/screen-reader, clear drilldown links).
- Idempotent writes must map to deterministic UX outcomes (in-progress/conflict/replay-safe states).
- Status labels must use canonical wording and avoid ambiguous publish/install synonyms.
- Mobile/iPad supports list/detail review and safe install actions; dense curation/reorder workflows may be desktop-optimized with explicit handoff.
- Error states must preserve operator trust by separating validation failures from permission/policy failures.
1. Information Architecture​
Place under authoring > Content Packs.
Primary screens:
Pack ListPack DetailPublish RevisionmodalInstall RevisionmodalRevision Lineageview
Supporting surfaces:
- evaluation version picker drawer for item add
- install result summary panel
2. Pack List UX​
API:
GET /content-packs?page=&limit=
Required table columns​
- title
- status (
draft,published,archived) - latest published revision indicator
- updated at
Required actions​
Create pack- row click -> open pack detail
Rules:
- empty state must include create CTA.
- pagination driven by
meta.page,meta.limit,meta.total.
3. Pack Detail UX​
API:
GET /content-packs/\{id\}PATCH /content-packs/\{id\}
Detail is three blocks:
- Pack metadata
- Items (curation order)
- Revisions timeline
3.1 Metadata block​
Editable fields:
titledescriptionstatus
Rules:
- save uses
PATCH+Idempotency-Key. - invalid empty updates are blocked client-side and server-side.
3.2 Items block​
Item shape:
sourceEvaluationVersionIdposmetadata
Item actions:
- add item (
POST /items) - reorder/update item (
PATCH /items/\{itemId\}) - delete item (
DELETE /items/\{itemId\})
Rules:
- reorder should display explicit order numbers and use optimistic UI with rollback on failure.
- deleting an item re-sequences remaining positions; UI must re-render returned canonical positions.
- each item should deep-link to source evaluation/version context when available.
3.3 Revisions block​
Display revisions from GET /content-packs/\{id\}:
- revision number
- created at
- manifest hash
- quick actions:
View lineageInstall
4. Publish Revision UX​
API:
POST /content-packs/\{id\}/publish
Publish modal requirements​
- show revision intent summary:
- item count
- source evaluation version IDs (or titles if resolved)
- show warning that publish freezes manifest snapshot and hash.
- require explicit confirmation action.
Response handling​
- on success (
201), append revision to timeline and mark pack status aspublished. - if validation fails (for example no items), render corrective guidance:
- "Add at least one item before publishing."
5. Install Revision UX​
API:
POST /content-packs/\{id\}/revisions/\{revisionId\}/install
Install modal requirements​
- show target revision summary:
- revision number
- manifest hash
- item count
- explain install behavior:
- imported assets are created as draft evaluations.
Install result rendering​
From response:
countitems[]with:- source evaluation version ID
- installed evaluation ID
- installed evaluation version ID
Post-install actions:
Open installed evaluationView lineage
Rules:
- installation is idempotent per key; repeated click retries must reuse the same key.
6. Revision Lineage UX (Critical)​
API:
GET /content-packs/\{id\}/revisions/\{revisionId\}/lineage
The lineage screen is the defensibility surface.
Required sections​
- Revision header
- revision number
- manifest hash
- created at
- Item provenance table
possourceEvaluationVersionId- metadata
- Install chain per item
- install IDs
- installed evaluation/version IDs
- created at
- submission linkage metrics
- Summary rollup
- install count
- submission count
- snapshot-linked submission count
UX rules​
- default sort by
pos, then install created-at descending. - every entity reference is linkable where allowed.
- include plain-language explanation of metrics:
snapshotLinkedSubmissionCountmeans submissions where snapshot evaluationVersionId matches installed version.
7. Permission and State Rules​
7.1 Capability gating​
- if user lacks
questions.read: hide packs nav entry. - if user has read but lacks
questions.write: read-only pack detail, no mutating CTAs.
7.2 Status behavior​
draft: editable, publish enabled if valid.published: editable metadata still possible, new revision publish allowed.archived: viewable; write actions should be policy-gated by capability and status rules.
8. Error and Idempotency Contract​
All pack mutations must:
- attach
Idempotency-Key - treat duplicate submissions as replay-safe
- map idempotency conflict/in-progress to deterministic retry guidance
Status semantics:
400: validation input error404: pack/revision/item not found (or scope-hidden)409: idempotency conflict/in progress500: server failure; keep operator context and allow safe retry
UX copy requirements:
- never show raw SQL or internals.
- always provide one clear next action.
9. Import and Propagation Contract (Target-State)​
Current backend supports install/lineage but does not yet expose a first-class pack import workflow or authoring propagation workflow.
9.1 Pack Import (Proposed)​
Target UX flow:
- Upload pack artifact or provide source reference
- Preview import diff
- Resolve collisions
- Apply import with deterministic idempotent job
Required preview output (target-state):
- incoming revision manifest hash
- item count and source IDs
- conflicts by type:
- name collision
- source version already present
- permission/scope conflict
Collision policies to support:
skipcreate_copyreplace_draft_only
9.2 Propagation from Updated Source (Proposed)​
Target UX flow:
- Detect published source changes that affect pack items
- Show impact summary (which pack revisions/items are affected)
- Create new candidate revision with explicit propagation choices
- Publish propagated revision and preserve prior revision history
Rules:
- propagation must always create a new revision; never mutate published revision in place.
- prior installs remain traceable to the original revision hash.
- impacted installs/submissions are shown as advisory context, not auto-mutated.
9.3 Suggested Backend Surfaces (Tracked)​
POST /api/v1/content-packs/import/previewPOST /api/v1/content-packs/import/applyPOST /api/v1/content-packs/\{id\}/propagation/previewPOST /api/v1/content-packs/\{id\}/propagation/apply
These routes are design placeholders and must be gated until backend contracts exist.
10. Shared Component Contracts​
Packs UI must reuse shared primitives:
EntityLinkfor IDs in lineage/install tables- read-only right-drawer peek on drawer-enabled surfaces
- full-page routes for primary assets (packs/evaluations/submissions)
- scope/freshness indicators on lineage data
11. Definition of Done (Content Packs UX)​
- Pack list/detail/revision/install/lineage flows are documented with concrete endpoint bindings.
- Publish and install flows include deterministic confirmation + result states.
- Lineage screen exposes provenance chain and metrics as first-class UX, not hidden diagnostics.
- Mutation flows honor idempotency key behavior and deterministic retry messaging.
- Capability gating and read-only behavior are explicitly defined.
- Link contract is applied to source versions, installs, and installed assets.
- Target-state import/propagation contracts are explicit and non-conflicting with current install/lineage behavior.