Admin, Debug & Misc Shell
This area covers 20 features. Watch the walkthrough, then use the reference below — each feature links to the exact moment it appears (▶).
Who this is for: Platform admin / developer. Each feature below lists the role/permission it requires.
Features
Admin Console — Overview Tab ▶ 00:00
As a platform admin, I want to see cross-tenant site-wide statistics at a glance, so that I understand system health and usage.
How it works. User navigates to /admin (access gated by platform admin check). The Overview tab loads and displays stat cards: Orgs count, Teams count, Users count, Active projects count, Archived projects count, and Active users in last 7 days. Stats load via getAdminOverview() API and are displayed in a 6-column grid. If not an admin, user is redirected to /.
Key files
src/pages/AdminConsole.tsx:78-195src/pages/AdminConsole.tsx:355-362
Admin Console — Orgs Tab ▶ 00:00
As a platform admin, I want to view all organizations with their ownership and membership stats, so that I can audit the multi-tenant structure.
How it works. User clicks 'Orgs' tab. Page loads table with columns: Org name, Owner username, Member count, Project count, Created date. Each org row has an 'Open' button that navigates to that org's overview (platform admin sees owner-level access to all orgs). Table displays empty message if no orgs exist.
Key files
src/pages/AdminConsole.tsx:197-218
Admin Console — Teams Tab ▶ 00:00
As a platform admin, I want to see all teams organized by their parent org, so that I can audit group structure across the platform.
How it works. User clicks 'Teams' tab. Teams are grouped by org (order preserved from API). Each org group shows a section header with org name and team count. A table under each section lists: Team (relative path, with leading org stripped), Members count, Projects count, Created date. Empty state shows message if no teams exist.
Key files
src/pages/AdminConsole.tsx:220-246src/pages/AdminConsole.tsx:50-69
Admin Console — Users Tab ▶ 00:00
As a platform admin, I want to see all users with their email, org membership, and activity, so that I can monitor user engagement and access.
How it works. User clicks 'Users' tab. Page displays table with columns: Username (with display name in parentheses if available), Email, Org count, Last active date, Joined date. All dates formatted via fmtDate helper. No pagination visible; all users from getAdminUsers() API are shown.
Key files
src/pages/AdminConsole.tsx:248-260
Admin Console — Projects Tab ▶ 00:00
As a platform admin, I want to view all projects with validation progress and status, so that I can see translation completion across tenants.
How it works. User clicks 'Projects' tab. Page displays table with columns: Project name (clickable link to /projects/:id for active projects; plain text for archived), Org name, Creator username, Validation % (cells validated / total cells), Word count (formatted with commas), Status ('Active' or 'Archived'). Archived projects show no link.
Key files
src/pages/AdminConsole.tsx:262-283src/pages/AdminConsole.tsx:45-46
Admin Console — Activity Tab ▶ 00:00
As a platform admin, I want to see a global activity feed with user actions and descriptions, so that I can audit what has happened across the platform.
How it works. User clicks 'Activity' tab. Page displays table with columns: When (timestamp), User (username or user ID fallback), Type (event type string), Description (free-text description). Most recent 200 activity records from getAdminActivity(jwt, 200) are shown. All dates formatted via fmtDate.
Key files
src/pages/AdminConsole.tsx:285-296
Admin Console — Admins Tab ▶ 00:00
As a platform admin, I want to see the allowlist of platform admins and their account status, so that I know who has unrestricted access.
How it works. User clicks 'Admins' tab. Page displays explanatory text stating that platform admins are allowlisted in PLATFORM_ADMINS (wrangler.toml) and redeploy is required to change. A table shows: Username (with display name in parentheses), Account status ('Registered' or red 'No account'), Email, Last active date, Joined date. Usernames and emails fallback gracefully if null. Dates show '—' if null.
Key files
src/pages/AdminConsole.tsx:298-324
Admin Console — Compute / Credits Tab ▶ 00:00
As a platform admin, I want to monitor and configure per-org credit budgets and spending, so that I can manage cost and prevent runaway agent sessions.
How it works. User clicks 'Compute / Credits' tab. Page loads with explanatory text about credit pricing and cap enforcement. Table displays per-org rows with: Org name, Daily total spend, Daily agent spend (highlighted in amber), Weekly total spend, Weekly agent spend (highlighted), Editable daily cap input, Editable weekly cap input, Enforce toggle (log-only vs hard-blocking), Show to org toggle (reveal panel to org maintainers). Each spend cell shows formatted credit amount + progress bar (color: green/amber/red based on % used). Agent rail is visually emphasized. Caps and toggles are inline-editable; changes save on blur/click. If no orgs, shows 'No orgs found.' message.
Key files
src/pages/AdminConsole.tsx:326-330src/components/admin/AdminCreditsSection.tsx:27-103
Debug View ▶ 00:00
As a developer, I want to inspect all local projects and their configuration, so that I can debug project structure and state.
How it works. User navigates to /debug. If no :id param, page calls listProjects() and renders the full project list as JSON in a <pre> block. If :id is provided and path is /settings/debug, calls getProject(id) and renders project + completionSettings + username as JSON. Otherwise calls getProject(id) and renders project + files as JSON. Loading state shows 'Loading...' in pre block until data arrives. Output is always valid JSON.
Key files
src/components/DebugView.tsx:5-42
Version Badge — Floating ▶ 00:00
As a developer or user, I want to see the current app version and build SHA at a glance, so that I know what version I'm running.
How it works. On routes without a left rail (dashboard, onboarding, join, settings, non-workspace pages), a floating badge appears bottom-left showing version and branch/SHA (e.g., 'v0.1.2 · main · abc123def'). Clicking the badge copies full build info to clipboard (title: 'v0.1.2 · main · abc123def\nbuild: main@abc123def'). Badge text changes to 'Copied' with a check icon for 1.5 seconds. Hovering shows tooltip with copy instructions. Badge does not appear on pages with left rail (AppShell sidebar pages) to avoid duplication with VersionTag.
Key files
src/components/VersionBadge.tsx:108-146src/components/VersionBadge.tsx:32-41
Version Tag — In-Flow (Left Rail Footer) ▶ 00:00
As a developer or user, I want to see the current app version in the left sidebar footer, so that I know the running version while working.
How it works. On routes with a left rail (AppShell sidebar, ProjectWorkspace, etc.), a version tag button appears at the foot of the sidebar (mt-auto). Text shows version label (e.g., 'v0.1.2 · main · abc123def'). Clicking copies full build info to clipboard and shows 'Copied' state for 1.5 seconds. Hovering shows tooltip with copy instructions. Text is small (font-mono, text-[10px]), muted color, and truncates on small widths.
Key files
src/components/VersionBadge.tsx:66-102src/components/AppShell.tsx:90-96src/components/LeftDock.tsx:350-356
Update Banner ▶ 00:00
As a user, I want to know when a new app version is available, so that I can refresh to get the latest features and fixes.
How it works. useUpdateCheck() hook polls /version.json every 60 seconds (in production only; skipped in dev). If the server's SHA differs from the current __APP_SHA__, UpdateBanner component appears as a fixed bottom-left button (z-30) showing 'Update available' with a refresh icon. The dot pulse animation draws attention. Clicking the button calls window.location.reload(). Banner is hidden if already running latest version.
Key files
src/components/UpdateBanner.tsx:5-24src/hooks/useUpdateCheck.ts:7-35
Report a Problem Button ▶ 00:00
As a user, I want to easily report bugs or issues without leaving the app, so that I can quickly surface problems I encounter.
How it works. Small flag icon button appears at the foot of the left rail/dock (next to VersionTag). Clicking opens ReportProblemDialog. Button has tooltip 'Report a problem' and is small/unobtrusive (text-muted-foreground/50, hover highlights to muted-foreground/70).
Key files
src/components/ReportProblemButton/ReportProblemButton.tsx:13-37src/components/AppShell.tsx:95src/components/LeftDock.tsx:354
Report a Problem Dialog ▶ 00:00
As a user, I want to describe what went wrong and have it automatically captured with context, so that the team can investigate my issue.
How it works. Dialog opens with title 'Report a problem' and description explaining consent state. User types free-text description in textarea. Auto-captured context shown: current route, active project ID (if any), active file ID (if any). If analytics enabled, shows 'Send report' button that submits via captureReportProblem() (PostHog event with replay URL if available). If analytics disabled, shows 'Copy report' button (copies plain-text report to clipboard) and amber warning explaining analytics are off. After submission, shows 'Thanks — report received' message with session replay URL if available. Cancel button closes dialog. Dialog resets state on close.
Key files
src/components/ReportProblemButton/ReportProblemDialog.tsx:36-151src/lib/report-problem.ts:35-79
Status Bar — Project Health & Cell Progress ▶ 00:00
As a translator, I want to see the overall health of my project and progress at a glance, so that I understand translation completion and quality.
How it works. At the bottom of the workspace, a footer shows: (1) Health ring (0-100 circle indicator; colors: red ≤33, amber 34-66, green ≥67) with health number inside; (2) Decay breakdown popover on hover/click showing 'X% of cells need attention' and top 8 'biggest drags' (cells sorted by descending decay). Stale source count displayed separately if > 0. (3) Summary stats: 'N cells · M translated (P%)' + badge showing unvalidated count (amber) and validated count (green) if > 0.
Key files
src/components/StatusBar.tsx:14-54src/components/HealthRing.tsx:10-63src/components/DecayBreakdown.tsx:26-98
Health Ring Indicator ▶ 00:00
As a user, I want a compact visual indicator of health/decay status, so that I can quickly assess quality at a glance.
How it works. SVG circle (customizable size, default 20px) with stroke showing health 0-100 as arc. Color coded: red (health 0-33), amber (34-66), green (67-100). At 0 health, ring is hidden but SVG box still occupies space (no layout shift). Transitions smoothly when health changes (0.5s ease). Optional center content (icon) rendered absolutely centered.
Key files
src/components/HealthRing.tsx:10-63
Decay Breakdown Popover ▶ 00:00
As a translator, I want to understand which cells are dragging down project health, so that I can prioritize fixes.
How it works. Popover triggered by hover on health ring (delay 300ms, close delay 120ms) or on-click. Shows: (1) 'PROJECT HEALTH' label + percentage; (2) 'X% of cells need attention' summary (cells with decay above warn threshold, default 0.3); (3) Optional 'N cell(s) with stale source' row if staleSourceCount > 0; (4) 'Biggest drags' section listing top 8 cells sorted by descending decay (ascending health), each clickable to jump to cell if callback provided, each showing cell label and health %. If no cells need attention, shows 'No cells need attention.' message.
Key files
src/components/DecayBreakdown.tsx:26-98src/lib/health/decay-engine.ts (implied by DECAY_DEFAULTS.decayWarnThreshold)
Workspace Status Bar ▶ 00:00
As a user, I want a flexible status bar component that can display custom left and right content, so that different workspace views can show relevant info.
How it works. Minimal wrapper component rendering horizontal flex layout with three sections: left content (min-width flex-shrink-0), spacer (flex-1), right content (shrink-0). Passed as ReactNode props. Used for workspace-specific status displays.
Key files
src/components/WorkspaceStatusBar.tsx:8-16
Platform Admin Access Gate ▶ 00:00
As a platform operator, I want admin features to be restricted to allowlisted users, so that only authorized personnel can access sensitive endpoints.
How it works. usePlatformAdmin() hook checks current JWT via getAdminMe(jwt) API call at mount. Sets isAdmin state to true/false and loading state. AdminConsole route mounts with platform admin gate: if !loading && !isAdmin, redirects to /. Non-admin access to /admin navigates to / via Navigate component. Server enforces PLATFORM_ADMINS allowlist on every /api/v2/admin/* call (403 if not listed).
Key files
src/hooks/usePlatformAdmin.ts:15-57src/pages/AdminConsole.tsx:78-157
Navigation Title Derivation ▶ 00:00
As a user, I want browser history (back/forward popover) to show descriptive page titles, so that I can navigate to specific pages by name.
How it works. deriveNavTitle(pathname) maps routes to human-readable labels: '/' → 'Home', '/projects' → 'Projects', '/admin' → 'Admin console', '/project/:id' → 'Editor', '/project/:id/settings' → 'Project settings', '/project/:id/rules' → 'Checks & rules', etc. Unknown routes title-case the last path segment. Used by NavHistoryControls popover to label history entries.
Key files
src/lib/navigation/deriveTitle.ts:10-70