# openalice-clonelab-dashboard
## At a glance
| field | value |
|---|---|
| kind | `product` |
| priority | `—` |
| default branch | `main` |
| last activity | 2026-06-17T16:51:09+00:00 |
| features catalogued | **13** |
| runtime deps declared | **0** |

## Env drift

**Code reads, manifest omits (5):**
- `CLONELAB_API`
- `NEXT_PUBLIC_CLONELAB_API`
- `NEXT_PUBLIC_VAULT_API`
- `TENANTS_INTERNAL_URL`
- `VAULT_API`

## Features (13)

### clonelab-dashboard/components
- **`clonelab-dashboard.components.app-shell`** — Left-rail + topbar shell for authenticated pages. Uses the same .oa-rail / .oa-topbar / .oa-canvas token classes from globals.css. No Tailwind — pure CSS custom properties from the design system.  
  *src/components/AppShell.tsx:2*
- **`clonelab-dashboard.components.brand-mark`** — Two-circle Mandelbrot mark — the OpenAlice logomark. Mirrors embed-app BrandMark exactly (same SVG, same class).  
  *src/components/BrandMark.tsx:2*

### clonelab-dashboard/create-self
- **`clonelab-dashboard.create-self.flow`** — Multi-step self-clone creation flow: 1. Liveness capture (STUB — placeholder token, honest disclosure) 2. Name + vault draft (POST /v1/identities with subject_kind: self) 3. Media upload (photos / voice / text — sent to POST .../ingest) 4. Pipeline progress poll (GET /v1/ingest/{job}) — 7 stages 5. Sealed soul result The liveness step is honest: the UI captures a placeholder token and CLEARLY tells the user that real biometric verification is not yet wired (backend stub). The marker value "liveness-stub-v0" is sent so the backend pipeline receives it and can run its own stub logic. onMouseEnter/onMouseLeave are style helpers on interactive articles — safe for client components but not idiomatic for server components.  
  *src/app/create/self/SelfCloneFlow.tsx:2*

### clonelab-dashboard/create-synthetic
- **`clonelab-dashboard.create-synthetic.flow`** — Synthetic NPC generator: 1. Create vault draft (subject_kind: random) 2. POST /v1/synthetic with seed + identity_id 3. Show generated NPC + poll job → sealed soul result (same 7 stages) No liveness check — synthetic souls have no real person behind them. The seed makes the NPC reproducible; leaving it blank lets the backend pick a random one (which is then shown so the user can reproduce it).  
  *src/app/create/synthetic/SyntheticFlow.tsx:2*

### clonelab-dashboard/lib
- **`clonelab-dashboard.lib.auth-client`** — Server-side proxy to openalice-tenants auth surface. Mirrors embed-app/src/lib/authClient.ts — same API contract, same error types. Runs server-side only; plaintext password never touches the browser.  
  *src/lib/authClient.ts:2*
- **`clonelab-dashboard.lib.clonelab-api`** — Server-side typed client for openalice-clone-lab HTTP API. Routes consumed: POST /v1/identities/{id}/ingest  — enqueue an ingest job (JWT-gated) GET  /v1/ingest/{job}            — poll job status + per-stage progress POST /v1/synthetic               — seed → synthetic NPC ingest + seal Base URL: CLONELAB_API env var (default http://localhost:3994). Auth: JWT Bearer from the session cookie. The 7 pipeline stages (in order): intake → visual → voice → style → knowledge → consent → seal Each stage may be: pending | running | done | skipped | failed  
  *src/lib/clonelab-api.ts:2*
- **`clonelab-dashboard.lib.clonelab-client`** — Client-side shared helpers for the creation flows (self + synthetic). This is the browser-side counterpart to the `server-only` clonelab-api.ts: the creation flows are `"use client"` components that call vault + clone-lab DIRECTLY from the browser using the JWT handed down as a prop, so they cannot import the `server-only` module. This module consolidates the helpers that were previously duplicated verbatim across SelfCloneFlow.tsx and SyntheticFlow.tsx: - apiPost / apiGet   — typed fetch wrappers ({ ok, data } | { ok, message }) - IngestStage / JobStatus — the shared status shapes the poll loop fills - STAGE_LABELS / StageIcon / StageRow — the 7-stage pipeline UI The 7 pipeline stages (in order): intake → visual → voice → style → knowledge → consent → seal Each stage may be: pending | running | done | skipped | failed No `server-only` import here — this code runs in the browser. The JWT it carries is the same one already in the authenticated session cookie; the pages pass it to the client components intentionally (same origin, behind auth) so the browser can talk to the backend directly.  
  *src/lib/clonelab-client.tsx:2*
- **`clonelab-dashboard.lib.session`** — Session management — HttpOnly cookie carrying the tenant JWT. Mirrors embed-app/src/lib/session.ts exactly (same cookie name, same security posture). The login server action writes the cookie; every server-side data-fetch reads it.  
  *src/lib/session.ts:2*
- **`clonelab-dashboard.lib.vault-api`** — Server-side typed client for openalice-vault HTTP API. Routes consumed: POST /v1/identities         — create a draft soul (self | random) GET  /v1/identities         — list owner's souls (newest first) Base URL: VAULT_API env var (default http://localhost:3992). Auth: JWT Bearer from the session cookie — passed in as a parameter so this module is a pure HTTP wrapper without cookie access.  
  *src/lib/vault-api.ts:2*

### clonelab-dashboard/login
- **`clonelab-dashboard.login.actions`** — Server actions for login + signup. Mirrors embed-app/login/actions.ts exactly — same error-collapsing policy (no field-level leaks), same HttpOnly cookie write via setSessionCookie.  
  *src/app/login/actions.ts:4*

### clonelab-dashboard/page
- **`clonelab-dashboard.page.create`** — Class chooser — pick Self, Synthetic, or see the "other-clone" blocked notice. Honest copy per §3 of the product design doc: - Self: liveness required (stub in M1, honest disclosure) - Synthetic: free, no real person - Other-clone: default-deny, not available  
  *src/app/create/page.tsx:2*
- **`clonelab-dashboard.page.login`** — Split-screen auth: brand panel (dark-sakura, left) + auth card (cream, right). Mirrors embed-app login/page.tsx structure + visual language exactly. Tabs: Sign in | Create account. No SSO tab (Cloning Lab is direct-auth only).  
  *src/app/login/page.tsx:2*
- **`clonelab-dashboard.page.souls`** — Souls list — GET /v1/identities from the vault API. Shows all souls the authenticated owner has created. Redirects to /login if no session exists.  
  *src/app/souls/page.tsx:2*

---

*Generated by [openalice-atlas](https://atlas.blal.pro) — single source of truth for the openalicelabs ecosystem.*
