Context. surface studio · domain governance · route /studio/data-retention-lifecycle-controls · auth signed-in + studio entitlement · source apps/oshun/web/src/app/studio/data-retention-lifecycle-controls/page.tsx
Last walked. 2026-06-30 real-dev-infra Playwright addendum — focused route journey verified direct admin navigation, live BFF catalog, seeded retention classification, unknown-class safe retain issue, legal-hold precedence, client-only JSON validation, live BFF 400 details, network-unreachable classify failure, catalog loading/error, non-admin fail-closed auth, pending-submit lockout, quick-action affordances, shared axe, and anonymous redirect. Evidence: WALKTHROUGH/results/v1-real-infra-run-2026-06-22.md §233; apps/oshun/web/e2e/studio-data-retention-lifecycle-controls.spec.ts
Purpose#
Classify records against their data-class retention policy with the real
lifecycle engine: the Lifecycle Classification Lane decides retain / archive /
purge by age, with legal-hold precedence that freezes a record regardless of
age. It is a live admin console wired to /v1/admin/studio/data-retention, not
an in-page simulation.
Entry points#
- Direct URL / bookmark —
/studio/data-retention-lifecycle-controls(signed-in + studio entitlement; admin scope required to evaluate) - Sibling Studio routes — reached via the quick-action panel on security-hardening-program, audit-compliance-surfaces, backup-disaster-recovery-ux, and other governance/operations pages
Layout regions#
page.tsx mounts <ShellLayout active="studio"> and renders
<StudioDataRetentionLifecycleControlsWorkspace /> followed by a single panel
of quick-action links.
- Shell:
ShellLayoutchrome with the Studio tab active - Workspace heading:
WorkspaceHeadingrenders the page<h1>"Studio Data Retention & Lifecycle Controls", followed by thedata-data-retention-summaryparagraph - Lifecycle Classification Lane: an
<h2>data-dr-lane-heading("Lifecycle Classification Lane") section with the load states and, when ready, the classify form and result table - Quick-actions panel:
data-dr-quick-actionsdata-dr-quick-action-count="5"wraps 5 siblingquickActionLinks:data-dr-quick-action="backup-disaster-recovery-ux",security-hardening-program,sdk-documentation-integration,webhooks-external-automation, andaudit-compliance-surfaces. No self-link and no Route Map panel.
States#
- Loading —
data-dr-loading("Loading retention evaluator…") - Unauthorized —
data-dr-unauthorized("Access restricted.") on 401/403 - Error —
data-dr-erroron a failed catalog GET - Ready / form —
data-dr-enums("N lifecycle actions") plus thedata-dr-formclassify form seeded withDEFAULT_PAYLOADanddata-dr-form-state="idle|pending" - Pending submit —
data-dr-submit-state="pending", disabled,aria-disabled="true", andaria-busy="true"while the evaluate POST is in flight - Result —
data-dr-resultwith thedata-dr-headline(data-dr-count="retain|archive|purge|hold"tallies), thedata-dr-recordstable ofdata-dr-record-rowrows (data-record-id,data-action,data-dr-record-action), and the optionaldata-dr-issueslist (data-dr-issue-row) - Classify error —
data-dr-evaluate-errorfor invalid JSON or a non-200 response - Offline — catalog GET fails closed to the error panel; the classify POST surfaces the generic error when the network is unreachable
- Gated — admin scope denied →
data-dr-unauthorized; the route itself is proxy-gated to signed-in + studio - Standalone PWA — renders within the shell; no URL-bar dependency
Interactions#
- Records (JSON) —
textareadata-dr-payload,aria-label="retention json", seeded withDEFAULT_PAYLOAD(records withrecordId,classId,ageDays, legal-hold, plus the policy classes) - Classify records —
buttondata-dr-submit(type="submit"); POSTs the parsed payload to/v1/admin/studio/data-retention/evaluate, settingdata-dr-resulton a 200 with a validresult, ordata-dr-evaluate-errorotherwise - Quick-action links — each
quickActionLinknavigates to its sibling Studio route (see Layout regions for the 5 targets)
Data & contracts#
- Reads:
GET /v1/admin/studio/data-retentionon mount — returns the catalog (lifecycleActions[]) - Writes:
POST /v1/admin/studio/data-retention/evaluate— returns{ summary: { retainCount, archiveCount, purgeCount, holdCount }, records[], issues[] } - Realtime: none
- Caching: client
fetchwithcache: 'no-store';buildBffAuthHeaders()attaches the bearer token; SSR shell only - Auth/role check: admin-scoped fail-closed —
admin:*oradmin:studio, 401/403 under the studio workspace gate
E2E coverage#
apps/oshun/web/e2e/studio-data-retention-lifecycle-controls.spec.tsforwardsGET /v1/admin/studio/data-retentionandPOST /v1/admin/studio/data-retention/evaluateto the live dev BFF. It covers direct admin navigation, catalog bearer forwarding, seeded classification counts (1 retain · 1 archive · 2 purge · 1 hold), unknown-class issue rendering, legal-hold precedence, malformed JSON zero-POST rejection, live BFF invalid-payload details, network-unreachable classify error, catalog loading/error state, pending-submit lockout, non-admin fail-closed state, quick-action href/touch targets, shared axe, and anonymous redirect before the workspace renders.
Cross-references#
- Parent:
../studio-overview.md - Siblings:
studio-audit-compliance-surfaces.md,studio-security-hardening-program.md,studio-enterprise-tenant-isolation.md - Component source:
apps/oshun/web/src/components/studio/StudioDataRetentionLifecycleControlsWorkspace.tsxbehind/v1/admin/studio/data-retention
Open questions / known gaps#
- Confirm whether the page will gain a breadcrumb/Route Map panel like other Studio surfaces, or keep the flat quick-action panel
- Document the persisted record source the lane should classify once it runs against a live retention store rather than a pasted JSON payload
- Manual screen-reader and installed/standalone PWA passes remain outside the automated Playwright route journey.