jules c2730e3c77 profile: real avatar upload + storage form fix
- Add a digital-objects client (uploadFile: open session → PUT to
  presigned URL → complete) and a profile client (getProfile,
  updateProfile, pickAvatarUrl variant resolver).
- Wire profile.tsx avatar upload to use the real flow: validate
  image+size, upload to digital_objects tagged "avatar", PATCH
  /api/v1/profile with avatar_digital_object_id, mirror the resolved
  URL into local prefs so the existing <AvatarImage> binding keeps
  working. Show Uploading… state and an inline error banner. Clear
  detaches via avatar_digital_object_id: null.
- Fix the storage form sending the wrong field name for the local
  backend — arcadia's StorageConfig changeset requires `base_path`,
  not `path`. The 422 was silent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 08:02:52 +10:00

Arcadia Admin

Admin webapp for arcadia-core — the multi-tenant Phoenix backend. Built on the Crema design system with the Skyrise theme and started from the Vibespace starter.

Surfaces tenant management, user/role administration, billing, audit logs, storage configs, scheduled tasks, feature flags, and platform monitoring on top of arcadia's /api/v1 and /admin/* endpoints.

Quick start

npm install
npm run dev

Open http://localhost:5173. The app talks to arcadia at http://localhost:4000 by default; override with VITE_ARCADIA_URL in .env.local.

To use it for real:

  1. Have arcadia running locally (see ../reference/arcadia-app/DEV_SETUP.md).
  2. Visit /login and sign in with admin credentials. In dev seeds: admin@example.com / AdminP@ssw0rd (tenant default).

Configuration

Env var Default Purpose
VITE_ARCADIA_URL http://localhost:4000 Base URL of arcadia-core.
VITE_ARCADIA_TENANT default Tenant id sent as X-Tenant-ID. Override per-deployment.
VITE_ARCADIA_SEARCH_URL http://127.0.0.1:7800 Base URL of arcadia-search (Tantivy).
VITE_ARCADIA_SEARCH_TOKEN (unset) Service-principal JWT for the assistant's search_kb/read_chunk tools. Set this when arcadia-search runs in AUTH_MODE=jwt and doesn't share its signing secret with the arcadia issuing operator session tokens. When unset, the operator's own session JWT is used (works only with matched signing keys).

What's in here

App shell

app/components/layout/app-shell.tsx — left rail + appbar + avatar dropdown. Brand identity in app/lib/identity.ts (name: "Arcadia Admin", icon: Shield). The shell is template code, not a lib — fork it freely as admin features are added.

Arcadia client + auth UI

  • @crema/arcadia-client — typed HTTP client (generic + openapi-fetch-backed client.typed), Phoenix Channels realtime, error normalization. Mounted at the root via <ArcadiaProvider>.
  • @crema/arcadia-auth-ui — login / signup / password reset / 2FA forms, themed via Skyrise tokens. The /login route renders <LoginForm>.

Skyrise theme

lib-theme-skyrise — premium AI-first glass: iridescent body, frosted-glass surfaces, vivid text, Apple-spring motion. Default 18px root.

Surface tints (body[data-surface="snow|stone|sage|slate"]) and dark mode (html.dark) work out of the box via the existing pickers in the appbar.

Command bus

@crema/action-bus — every interactive element has data-action="<id>" so admin flows can be scripted, e2e-tested, or driven by an LLM through a single bus. See docs/AI_FIRST.md.

Sibling repos

your-workspace/
  arcadia-admin/                ← this repo
  vibespace/                    ← starter that this was cloned from
  reference/arcadia-app/        ← Phoenix backend (read-only reference)
  lib-arcadia-client/
  lib-arcadia-auth-ui/
  lib-action-bus/
  lib-aifirst-ui/
  lib-chat-ui/
  lib-llm-ui/
  lib-notification-ui/
  lib-theme-skyrise/

Dev scripts

Command What it does
npm run dev Vite dev server
npm run build Production build
npm run start Serve the built app
npm run typecheck react-router typegen && tsc
npm run test Vitest run
bash start.sh / bash stop.sh Run dev server in the background

Conventions

  • Brand strings, not literals. Use useBrand().name — never hardcode "Arcadia Admin".
  • [data-action="<id>"] on every interactive element. Naming: nav-*, appbar-*, tenants-*, users-*, audit-*, etc.
  • Tokens, not values. bg-card, text-foreground, var(--primary) — never hex.
  • Lib edits commit to each lib's own repo. git status here only shows app-level changes.

Further reading

  • docs/AI_FIRST.md — command-bus / DSL system tour
  • app/components/layout/THEME_CONTRACT.md — token contract every theme must satisfy
  • CLAUDE.md — orientation for an LLM working in this repo
  • ../reference/arcadia-app/ — backend (DEV_SETUP, controllers, OpenAPI source-of-truth)
Description
No description provided
Readme 2.3 MiB
Languages
TypeScript 97.3%
CSS 1.6%
JavaScript 1%