---
path: /isis/civitai-intake
surface: admin
domain: isis
auth: signed-in (admin)
source: apps/oshun/admin/src/app/isis/civitai-intake/page.tsx
status: drafted
last_walked: '—'
---

# Isis ops · Civitai intake

## Purpose

Operator review queues for ingesting Civitai model versions (§24.2): license
inspector, preview gallery, NSFW flag, sha256 hash, lineage, compatibility
report; license-decision actions; staging-recipe binding; audit trail. Backed by
`@isis/ai-providers/civitai-intake`.

## Entry points

- Direct URL — `/isis/civitai-intake` (the `/isis` parent has no index page;
  only the eight named children resolve, per `shell/02-routing-layouts.md`)
- Not in the canonical admin IA (`OSHUN_ADMIN_WORKSPACE_MODEL`); no sidebar
  entry from `AdminSidebar` (which is populated by
  `listOshunAdminWorkspaceDefinitions`)
- External runbooks / deep links to the Isis ops admin area

## Layout regions

The page does NOT wrap the body in `AdminShell`. Server component calls three
loaders in parallel (`loadIntakeEntries`, `loadIntakeOperatorId`,
`loadIntakeSearchCandidates` from `./intake-loader`) and renders
`<IntakeQueuePanel>` directly:

- **IntakeQueuePanel**:
  - **Queue tabs** — one tab per `ReviewQueue` in `REVIEW_QUEUES` from
    `@isis/ai-providers/civitai-intake`; default active `'intake'`
  - **Entry list** — entries filtered to `currentQueue === active`,
    keyboard-navigable; `selectedIdx` indexes into the filtered list
  - **Search box** — filters `operatorSearchCandidates` by title / creator
    attribution / asset type / license tag / sha256 (max 8 results)
  - **Note draft** + **Recipe id draft** inputs for the selected entry
  - **Decision buttons** —
    `applyReviewDecision({ entry, decision, reviewerId, nowUnixSeconds, stagingRecipeId })`
  - **Import affordance** — `requestImport(candidate)` runs
    `evaluateIntakeCandidate` and may set `importMessage` if a reject-on-intake
    verdict fires

## States

- [ ] Anonymous → global middleware redirects to `/unauthorized` (this route is
      NOT in `PUBLIC_PATHS`)
- [ ] Loaders return entries → list renders; first entry selected
- [ ] Loaders return empty → list empty; `selected` is null
- [ ] Search query trims to empty → first 5 candidates shown
- [ ] Search query non-empty → up to 8 results matching title / attribution /
      type / license / sha256
- [ ] Decision applied to selected entry → `setEntries` updates the in-memory
      list (the panel is client-state-driven; no BFF write visible from this
      component)
- [ ] Import candidate evaluates as `reject-on-intake` → `setImportMessage`
      shows the issues
- [ ] Import candidate already present in `entries` → no duplicate added
      (guarded by `entries.some` check)

## Interactions

- [ ] **Queue tab** (per `ReviewQueue`)
  - Function: sets `active` queue; filters list
- [ ] **Entry row** (button)
  - Function: sets `selectedIdx`
- [ ] **Search input**
  - Function: updates `search`; filters `operatorSearchCandidates`
- [ ] **Note draft input**
- [ ] **Recipe id draft input**
- [ ] **Decision buttons** — one per `ReviewDecision`; trigger
      `decide(decision)` which calls `applyReviewDecision`
- [ ] **Import button** — per search-result candidate; calls
      `requestImport(candidate)`

## Data & contracts

- **Reads**:
  - `loadIntakeEntries()` → `readonly ReviewQueueEntry[]`
  - `loadIntakeOperatorId()` → `string`
  - `loadIntakeSearchCandidates()` → `readonly CivitaiIntakeCandidate[]`
  - All three from
    `apps/oshun/admin/src/app/isis/civitai-intake/intake-loader.ts`
- **Writes**: in-component state only (`setEntries`); no BFF write observed in
  the panel source. The `applyReviewDecision` pure function from the contract
  produces an updated entry that is swapped into local state
- **Realtime**: _None._
- **Auth/role check**: only the global middleware (the page does NOT call
  `getAdminServerSession` or check `canEnterAdminWorkspace`). The operator id
  comes from `loadIntakeOperatorId()`

## Cross-references

- Shell: `shell/02-routing-layouts.md` (sub-route patterns table)
- Note: this route is OUTSIDE the canonical admin IA — it does not appear in
  `OSHUN_ADMIN_WORKSPACE_MODEL`, has no `requiredScopes`, no sidebar entry. The
  eight `/isis/*` routes form a parallel Isis-ops surface
- Related Isis routes (same admin area): `isis-comfy-nodes.md`,
  `isis-lora-training.md`, `isis-model-merging.md`, `isis-output-gallery.md`,
  `isis-runpod-endpoints.md`, `isis-voice-cloning.md`, `isis-workflow-editor.md`
- Related V1 PWA route (provenance side): customer Isis routes at
  `WALKTHROUGH/customer/.../studio/` (operator vs. customer Isis surfaces share
  underlying contracts but have separate UIs)
- Library: `@isis/ai-providers/civitai-intake` exports — `REVIEW_QUEUES`,
  `applyReviewDecision`, `createReviewEntry`, `evaluateIntakeCandidate`,
  `isApprovedForManagedStorage`, `isBlockedFromRuntime`
- Component source:
  `apps/oshun/admin/src/app/isis/civitai-intake/IntakeQueuePanel.tsx`

## Open questions / known gaps

- [ ] No session / scope check at the page level; only middleware. Document
      whether the Isis-ops surfaces should adopt the canonical
      `getAdminServerSession` + scope-gating pattern
- [ ] `setEntries` mutations are local — verify there is a separate BFF write
      path (likely outside this panel) that persists decisions
- [ ] The intake loader file `intake-loader.ts` couples this route to fixture /
      production loaders; document the binding strategy
