Skip to main content
Site Architecture

User Portal

Internal documentation for authenticated user pages including the portal hub, access command center, unified dashboard, editor, workbench, and settings

February 23, 2026

User Portal

Core authenticated pages for member-level users include /user, /user/access, /user/dashboard, /user/editor, /user/workbench, /user/sites, /user/settings, and /user/email. All use SSR, require an authenticated session, and render with CosmicLayout + UserSidebar (collapsible, localStorage-persisted state).

User Portal Index (/user)

Hub page with quick actions into the unified dashboard, access command page, editor, and workbench. Quick links are feature-aware and derived from the authenticated user payload.

Access Command (/user/access)

Travel-aware endpoint launcher for curated homelab surfaces (MasaiMara, Casablanca, Margaritaville, Titan/Plex, graph endpoints). Endpoint resolution order is:

  1. User quickLinks from /admin/users
  2. Service registry URLs from /admin/homelab / service-registry
  3. Curated fallback URLs (where configured)

Each resolved endpoint is labeled by reachability mode:

  • public (Cloudflare/public URL)
  • tailscale (100.x or .ts.net)
  • lan (10.x/172.16-31.x/192.168.x/localhost)
  • unknown (missing or invalid URL mapping)

This page is intended as a practical command surface for remote travel scenarios without forcing ad-hoc VPN reconfiguration.

Unified Dashboard (/user/dashboard)

Primary personalized dashboard for all users, including Bogart. This route is authenticated (portal:view) and supports admin impersonation via ?as=user@example.com.

Main sections:

  • Adaptive routing model with travel region profile and policy mode
  • Site matrix for MasaiMara, Margaritaville, and Casablanca with control + file surfaces
  • Service cockpit (Plex, Unraid files, Synology files, graphs, downloads)
  • Container panel seeded from mapped services and optionally hydrated from /api/mm-argobox/containers when permissions allow

Link resolution is dynamic and template-driven. The route maps user quick links + registered services against keyword templates in:

  • src/lib/unified-dashboard-template.ts

Bogart-specific link alias:

  • /user/bogart/dashboard (redirects to /user/dashboard)

Code Editor (/user/editor)

Browser-based CodeMirror 6 editor with multi-tab file editing. Each tab shows the filename and a modified indicator dot for unsaved changes. A repository selector dropdown loads the file tree for any Gitea repo the user has access to, and a collapsible tree view navigates the directory structure.

Syntax highlighting covers HTML, CSS, JavaScript, TypeScript, JSX, TSX, JSON, YAML, Markdown, Astro, and SVG via CodeMirror 6 language extensions. Saving via Ctrl+S commits directly to Gitea with SHA tracking for optimistic concurrency -- if the SHA has drifted, the save is rejected with a conflict error.

Method Endpoint Purpose
GET /api/user/files List repo contents or fetch file content with SHA
PUT /api/user/files Save file -- commits to Gitea with SHA-based conflict detection

GET accepts repo, path, and ref (branch) query parameters. PUT body includes repo, path, content, sha, and optional message.

AI Workbench (/user/workbench)

AI chat interface with an immersive full-viewport layout (CosmicLayout with hideHeader/hideFooter). Models are fetched dynamically from /api/user/models (list varies by role). Responses stream via SSE with real-time markdown rendering and syntax-highlighted code blocks with copy buttons.

Chat history persists in localStorage (last 50 messages). Suggested prompts display when the conversation is empty. Messages POST to /api/user/chat with the selected model, history, and new message.

My Sites (/user/sites)

Site management page using SiteCard components. Each card displays:

  • Sync status -- real-time badge from /api/user/site-status showing Gitea-to-GitHub mirror state
  • Mirror mode -- Auto-sync (pushes on commit) or Manual
  • Deploy button -- triggers POST to /api/user/deploy for a Cloudflare Pages build
  • Recent commits -- latest messages and timestamps from Gitea
  • Status badge -- Cloudflare Pages deployment state (success, building, failed)

Settings (/user/settings)

Auth: SSR with resolveAuthState() + portal:view permission gate. Previously unprotected (no SSR, no auth) — fixed 2026-03-08.

User preference configuration with auto-save to /api/user/preferences (500ms debounce, no save button).

Widget preferences -- SortableJS drag-and-drop order and visibility toggles persist in user preferences.

Theme colors -- primary and secondary color pickers with gradient preview. Defaults: #06b6d4 (cyan) primary, #8b5cf6 (violet) secondary. Injected as CSS custom properties at runtime.

Default landing page -- choose between portal index, editor, or workbench as the /user destination. Sidebar collapsed toggle -- sets initial UserSidebar state, seeds the localStorage key.

Admin Preview Flow

Admin user preview for member dashboards is wired to:

  • /user/dashboard?as=<user-email>
  • /user/access?as=<user-email>

The ?as= impersonation param is threaded through:

  1. Page data — both dashboard.astro and access.astro resolve impersonated user's quickLinks, services, display name from KV
  2. SidebarUserSidebar.astro client-side JS appends ?as= to all sidebar links
  3. LayoutCosmicLayout.astro resolves impersonated user's features from KV for sidebar visibility
  4. Hero buttons — dashboard hero links include ?as= param

This is used by /admin/users Preview buttons to validate exactly what a specific member will see after profile/service changes.

user-portaleditorworkbenchdashboardsettingsauthentication