admin: completeness + UI consistency pass

Arcadia wiring:
- home: real Overview dashboard (tenants/users/audit/health probe) replacing the inherited Vibespace welcome tiles; skeleton loaders, refresh button, registers admin context
- profile: split into Account (synced via getUser/updateUser of session user) and local Preferences; updateSessionUser keeps the appbar in sync after edits
- session: drop unused signIn mock, add updateSessionUser, refresh tests
- profile schema: drop redundant Profile.name/email (session is the source of truth)
- routes: delete orphaned resources route + lib

Auth flows that previously 404'd:
- /signup, /login/forgot, /login/reset, /login/2fa wired via @crema/arcadia-auth-ui
- shared AuthShell + AuthBrand wrapper

Assistant tools (admin-tools.ts):
- +10 tools: deactivate_tenant, set_user_status, delete_user, list_memberships, list_roles, revoke_api_key, create_user, update_user, assign_role, remove_role
- list_memberships gains user_id filter for "tenants this user belongs to" queries
- search_kb / read_chunk: new token resolution (window override → VITE_ARCADIA_SEARCH_TOKEN service token → operator session JWT → "dev"); on 401/403 emit a tailored hint based on which token was used

UI consistency:
- new PageHeader component
- AppShell.title was unrendered — dropped; first-child padding on #main-content keeps the floating actions pill from colliding with header content
- removed dead "Sign in required" fallback cards from 14 routes (AppShell already redirects)
- stripped p-6 from outer wrappers across 14 routes (was double-padding under AppShell's own p-6)
- migrated home + tenants to PageHeader

arcadia-search ergonomics:
- scripts/mint-search-token.mjs + `npm run mint:search-token` mints HS512 JWT with required tenant_id claim, upserts VITE_ARCADIA_SEARCH_TOKEN into .env.local
- README/.env document the new VITE_ARCADIA_SEARCH_URL / VITE_ARCADIA_SEARCH_TOKEN knobs
- .env.local now gitignored

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jules
2026-05-04 15:37:31 +10:00
parent 444516e900
commit 20c592dfa7
44 changed files with 1594 additions and 984 deletions

View File

@@ -1,10 +1,17 @@
import { describe, expect, it, beforeEach } from "vitest"
import { hasSession, loadSession, signIn, signOut } from "./session"
import {
hasSession,
loadSession,
persistFromArcadiaLogin,
signOut,
updateSessionUser,
} from "./session"
describe("session", () => {
beforeEach(() => {
localStorage.clear()
sessionStorage.clear()
})
it("starts unauthenticated", () => {
@@ -12,20 +19,31 @@ describe("session", () => {
expect(hasSession()).toBe(false)
})
it("rejects empty credentials", async () => {
await expect(signIn("", "")).rejects.toThrow(/required/i)
await expect(signIn("not-an-email", "pw")).rejects.toThrow(/valid email/i)
expect(hasSession()).toBe(false)
})
it("creates a session on sign-in and clears on sign-out", async () => {
const session = await signIn("alice@example.com", "hunter2")
it("persists from an arcadia login and clears on sign-out", () => {
const session = persistFromArcadiaLogin(
{ access_token: "tok-123", refresh_token: "ref-456" },
{ id: "u1", email: "alice@example.com", full_name: "Alice" },
)
expect(session.email).toBe("alice@example.com")
expect(session.token).toMatch(/^dev-/)
expect(session.name).toBe("Alice")
expect(session.token).toBe("tok-123")
expect(hasSession()).toBe(true)
expect(sessionStorage.getItem("arcadia_access_token")).toBe("tok-123")
signOut()
expect(loadSession()).toBeNull()
expect(hasSession()).toBe(false)
expect(sessionStorage.getItem("arcadia_access_token")).toBeNull()
})
it("updates the stored session identity in place", () => {
persistFromArcadiaLogin(
{ access_token: "tok" },
{ id: "u1", email: "a@x.com", full_name: "Alice" },
)
updateSessionUser({ name: "Alice Smith", email: "alice@x.com" })
const s = loadSession()
expect(s?.name).toBe("Alice Smith")
expect(s?.email).toBe("alice@x.com")
expect(s?.token).toBe("tok")
})
})