Files
arcadia-admin/CLAUDE.md
jules 938143f3f5 refactor: rename service references arcadia-app → arcadia-core
The Phoenix auth/identity/tenancy backend repo is being renamed
arcadia-app → arcadia-core (its primary OTP app is already arcadia_core).
Updates prose, doc paths, and git.sky-ai.com repo URLs. Deliberately
leaves the Rust crate arcadia-app-client and host arcadia-app.internal
(handled separately), and the kept namespace (issuer/release "arcadia").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 13:40:25 +10:00

9.6 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Admin webapp for arcadia-core. Built on the Crema design system, themed with Skyrise, started from the Vibespace starter. This file is a quick map, not a duplication of upstream docs.

What Arcadia Admin is

  • Arcadia Admin is the operator/admin UI for arcadia-core, a multi-tenant Phoenix backend. Surfaces tenant management, user/role admin, billing, audit logs, storage configs, scheduled tasks, feature flags, and platform monitoring on top of arcadia's /api/v1 and /admin/* endpoints.
  • Cloned from Vibespace — the starter for webapps in this style. Vibespace and Skyrise are the upstream sources of truth for the shell and the theme; don't backport arcadia-admin-specific changes into Vibespace unless they're broadly applicable.
  • Backend reference lives at ../reference/arcadia-core/. Treat it as read-only documentation — it's the Phoenix umbrella app that owns the OpenAPI spec, controllers, schemas, and seed data. Spec is regenerated from a running arcadia at http://localhost:4000/api/openapi via node ../lib-arcadia-core-client/scripts/sync-spec.mjs (run from this directory).
  • Skyrise (lib-theme-skyrise) is the canonical theme — premium AI-first glass, iridescent body, vivid text, Apple-spring motion. Theme tweaks belong upstream in Vibespace + Skyrise, not here.
  • The brand string lives in one place: app/lib/identity.ts (useBrand() / getBrand()). Don't hardcode "Arcadia Admin" in components, page titles, or copy.

Arcadia integration (already wired)

  • <ArcadiaProvider> in app/root.tsx reads VITE_ARCADIA_URL (default http://localhost:4000) and VITE_ARCADIA_TENANT (default default). getToken reads arcadia_access_token from sessionStorage. onUnauthorized clears the token.
  • useArcadiaClient() for typed/generic HTTP. arcadia.typed.GET("/api/v1/...") infers paths from the generated paths type; arcadia.GET<T>(path) is the generic escape hatch for spec-incomplete endpoints.
  • Loginapp/routes/login.tsx renders <LoginForm> from @crema/arcadia-auth-ui. Successful login writes tokens via persistFromArcadiaLogin() in app/lib/session.ts, which preserves the existing Session shape used by useUser / AppShell.
  • Realtime — supported by the lib but not enabled at the provider here; pass enableRealtime + userId to opt in.
  • Search admin sidecar — the /search route (app/routes/search.tsx) calls arcadia-search's privileged /admin/* surface (default 127.0.0.1:7801) via app/lib/search-admin.ts. Configured by VITE_ARCADIA_SEARCH_ADMIN_URL + VITE_ARCADIA_SEARCH_ADMIN_TOKEN; the token must match ADMIN_TOKEN on the search box. See arcadia-search/README.md § Admin sidecar.

Scripts

  • npm run dev — Vite dev server (React Router 7).

  • npm run build — production build (react-router build).

  • npm run start — serve the built app (react-router-serve ./build/server/index.js).

  • npm run typecheckreact-router typegen && tsc. See gotcha below; may crash.

  • start.sh / stop.sh — repo's preferred way to run/stop the dev server in the background.

  • npm run test — Vitest run (vibespace-inherited setup; jsdom + @testing-library/react).

App layout (app/)

  • routes/ + routes.ts — file-based React Router 7 routes (Overview, Resources, Activity, Assistant, Library, Settings).
  • components/layout/app-shell.tsx (rail + appbar + avatar dropdown), appbar.tsx, theme-toggle.tsx. Template code, not a lib — fork it freely.
  • components/assistant/message-body.tsx — markdown rendering for assistant replies + action-block pill.
  • components/scripts-dialog.tsx — ⌘⇧P script runner UI.
  • lib/identity.tsuseBrand() / useUser() (default stubs; swap for real session).
  • lib/llm-settings.ts — persisted LLM endpoint + context budget config.
  • lib/page-meta.ts, lib/utils.ts — small helpers.
  • app.css — Tailwind v4 entrypoint; theme @import first, then tailwind, then per-lib @source lines.
  • root.tsxToastProvider + CommandBusProvider wrap point.

What this is

  • React Router 7 + Tailwind v4 SPA.
  • Hybrid traditional + AI-first scaffold. Most surfaces are normal; the Assistant surface is wrapped in <AppShell theme="skyrise"> for the AI-styled mood (warm cream + ink-blue + serif prose).
  • Built on Crema libs (@crema/*-ui) cloned as sibling directories, not npm packages.
  • The @crema/action-bus lib is the foundation: anything (LLM, scripts, WebSocket, tests) can drive the UI via [data-action]-tagged elements. See docs/AI_FIRST.md.

Crema system (authoritative)

  • Lib catalog: see docs/LIBS.md for a snapshot of every @crema/*-ui lib (the ones wired into this project AND the ones available to add). Before building any UI primitive, check there first — there's a good chance a lib already does it. Refresh the snapshot with npm run sync-libs.
  • Each @crema/*-ui lib is its own git repo at https://git.sky-ai.com/CremaUIStudio/lib-<name>-ui, cloned as a sibling of this app. Edits to lib code commit to that lib's repo, not this one.
  • Themes (lib-theme-*) are CSS-only token files at the same Gitea org.
  • Live manifest (which docs/LIBS.md is generated from) is the crema-manifest repo. Gitea's raw-file HTTP URL 404s; clone instead:
    git clone --depth 1 https://git.sky-ai.com/CremaUIStudio/crema-manifest.git /tmp/crema-manifest
    cat /tmp/crema-manifest/manifest.json
    

Adding a lib after scaffold

Prefer the CLI:

crema add <lib-name>      # e.g. crema add status-ui chart-ui

It clones the lib as a sibling, adds the @source line to app/app.css, and wires tsconfig.json paths.

Manual fallback (3 edits):

  1. Clone lib-<name>-ui as a sibling.
  2. app/app.css → add @source "../../lib-<name>-ui/src";
  3. tsconfig.json paths → add "@crema/<name>-ui": ["../lib-<name>-ui/src/index.tsx"] and the /* variant.

Then run npm run sync-libs to refresh docs/LIBS.md.

Theme convention

  • A single theme (lib-theme-skyrise by default) is loaded via :root in app/app.css, first so its embedded @import url(...) Google Fonts declarations resolve to the top of the output.
  • Themes are self-contained: tokens and their font @import url(...) ship inside the theme's CSS file.
  • Per-surface alt themes can be scoped via [data-theme="<name>"] and applied with the shell's theme prop. The Assistant route already does this: <AppShell title="Assistant" theme="skyrise">…</AppShell>.
  • Components reference tokens (var(--card), bg-card, etc.), never hex values. See app/components/layout/THEME_CONTRACT.md for the full token list any theme must implement.
  • Assistant prose uses var(--font-ai-prose). Don't hard-code font families.

Coding conventions

  • lib-*-ui components use inline styles with CSS variables (style={{ background: "var(--card)", color: "var(--foreground)" }}), not Tailwind classes. App routes use Tailwind freely with theme-variable utilities (bg-card, text-muted-foreground).
  • Every shadcn-style component has a [data-slot="..."] attribute — themes target these for surface treatment overrides. Preserve them when editing libs.
  • Lib src/index.tsx files start with // PURPOSE: and // EXPORTS blocks, plus "use client" at the top. Maintain the header.
  • Don't hardcode colors. Use tokens.

Polyrepo gotchas

  • git status at this app's root only shows app changes. To see lib edits, cd ../lib-<name>-ui && git status.
  • Each repo commits and pushes separately.
  • Don't bundle lib edits into app commits.
  • Sibling libs already cloned next to this app include the full Crema set (lib-chat-ui, lib-table-ui, lib-chart-ui, lib-theme-skyrise, etc.) — check ../lib-* before adding anything new.

Marker contract (CLI-managed regions)

This repo was scaffolded from create-crema-app, which patches marker comments. Preserve them when editing:

File Marker
tsconfig.json "// CREMA:PATHS"
app/app.css /* CREMA:SOURCES */
app/routes.ts // CREMA:ROUTES
app/components/layout/app-shell.tsx // CREMA:NAV-ICONS, // CREMA:NAV-ITEMS
app/root.tsx // CREMA:PROVIDERS-IMPORTS, /* CREMA:PROVIDERS-WRAP-OPEN */, /* CREMA:PROVIDERS-WRAP-CLOSE */

Common tasks

  • Run dev: npm run dev
  • Add a UI primitive: check the manifest first; if it exists, crema add <lib>; if not, build inline and consider whether it should become a lib.
  • Add a route: create the file under app/routes/, register in app/routes.ts, add a nav entry in the sidenav (traditional) or chat shell (AI).
  • Switch theme on a route: pass theme="<name>" to <AppShell>. Default (no prop) uses the :root theme.
  • Add a script: drop a .script file into public/scripts/, register it in KNOWN_SCRIPTS in app/components/scripts-dialog.tsx if you want it in the dialog list, or invoke programmatically with runScript("<name>").
  • Make a component scriptable: add data-action="<id>". The bus auto-discovers it.

Known gotchas

  • npm run typecheck may crash with a TypeScript internal error — pre-existing in the Crema toolchain. There's no test runner here, so rely on careful reads + dev server.
  • Vite "Outdated Optimize Dep" 504s after editing vite.config.ts or tsconfig.json: stop dev, rm -rf node_modules/.vite, restart, hard-reload.
  • After editing a sibling lib's exports, the dev server sometimes needs a manual restart to pick up the new types.