Federation & Multi-User Portal
Cross-network health monitoring, per-user dashboard profiles, and the federation of Milky Way and Andromeda into a unified portal
Federation & Multi-User Portal
Arcturus-Prime federates two homelab networks — Milky Way (Milky Way, local) and Andromeda (Andromeda, remote) — into a single portal. Each user sees a personalized dashboard with services, widgets, and theme colors tailored to their role and network affinity.
Networks
| Network | Galaxy | Location | Connectivity |
|---|---|---|---|
| Milky Way | Milky Way | Local (10.42.0.0/24) | Direct LAN |
| Andromeda | Andromeda | Remote (192.168.20.0/24) | Tailscale + CF Tunnels |
Services on Andromeda are accessed through Cloudflare Tunnels from Meridian-Host or via the mm-Arcturus-Prime proxy. Services on Milky Way are accessed through the primary tunnel on Altair-Link or directly on LAN.
Federation Health API
GET /api/federation/health checks both networks in parallel and returns filtered status.
Request
Requires authentication. Returns only services the authenticated user has access to.
Response
{
"networks": {
"milky-way": { "online": true, "serviceCount": 12 },
"andromeda": { "online": true, "serviceCount": 8 }
},
"userServices": [
{ "id": "plex-bogie", "label": "Plex", "network": "andromeda", "status": "up" },
{ "id": "rutorrent-bogie", "label": "ruTorrent", "network": "andromeda", "status": "up" }
]
}
Health Check Sources
| Network | Source | Timeout |
|---|---|---|
| Andromeda | mm-Arcturus-Prime /api/health (container count) | 8s |
| Milky Way | Uptime Kuma /api/status-page/public (heartbeats) | 8s |
Both checks run with Promise.allSettled — one network failing does not block the other. Results are cached for 30 seconds with stale-while-revalidate at 60 seconds.
Dashboard Profiles
Profiles define which widgets a user sees, their ordering, and theme colors. Ten built-in profiles ship with Arcturus-Prime:
Role-Based Profiles
| Profile | Widgets | Theme | Default For |
|---|---|---|---|
admin | All 13 widgets | Cyan/Violet | Admin role |
member | sites, deploy, media suite, editor, workbench | Blue/Cyan | Member role |
demo | sites, plex, tautulli | Slate/Blue | Demo role |
homelab | infra-status, docker-containers, vm-status | Green/Cyan | — |
creator | sites, deploy, editor, workbench | Amber/Violet | — |
media | plex, rutorrent, audiobookshelf, tautulli | Pink/Violet | — |
bea | sites, cf-pages, ai-chat | Pink/Rose | — |
User-Specific Profiles
| Profile | Widgets | Theme | Network |
|---|---|---|---|
bogie-command | quick-launch, plex, audiobookshelf, rutorrent, tautulli, grafana-embed, storage-overview, speedtest | Cyan/Teal | Andromeda |
bogie-infra | storage-overview, network-status, grafana-embed | Green/Cyan | Andromeda |
mauve | quick-launch, plex, rutorrent, audiobookshelf, ai-chat | Pink/Violet | Milky Way |
Profiles are stored in KV at data:dashboard-profiles and managed through /admin/dashboard-profiles.
Widget Registry
Eighteen widgets are available across four categories. Each widget can be gated by role, feature flag, or service assignment.
Infrastructure
| Widget | Requires | Component |
|---|---|---|
infra-status | Admin role | DashInfraStatus.astro |
docker-containers | Admin role | DashDockerContainers.astro |
vm-status | Admin role | DashVmStatus.astro |
storage-overview | unraid-dashboard service | Inline (polls /api/mm-Arcturus-Prime/dashboard) |
network-status | — | Inline (polls /api/federation/health) |
Media
| Widget | Requires | Component |
|---|---|---|
plex | plex service | DashPlex.astro |
rutorrent | rutorrent service | DashRutorrent.astro |
audiobookshelf | audiobookshelf service | DashAudiobookshelf.astro |
tautulli | tautulli service | DashTautulli.astro |
Sites
| Widget | Requires | Component |
|---|---|---|
sites | sites feature | DashSites.astro |
deploy-status | sites feature | DashDeployStatus.astro |
cf-pages | sites feature | DashCfPages.astro |
Tools
| Widget | Requires | Component |
|---|---|---|
editor | editor feature | DashEditor.astro |
workbench | workbench feature | DashWorkbench.astro |
ai-chat | — | DashAiChat.astro |
quick-launch | — | Inline (renders user’s quickLinks) |
grafana-embed | grafana service | Inline (iframe) |
speedtest | speedtest service | Inline (iframe) |
Inline Widgets
Five widgets render inline in the dashboard without a dedicated Astro component:
- Quick Launch — grid of large tappable buttons from the user’s
quickLinksarray (defined in their KV user record) - Grafana Embed — iframe pointing to the user’s Grafana dashboard in kiosk mode
- Speedtest — iframe embedding Speedtest Tracker
- Storage Overview — polls
/api/mm-Arcturus-Prime/dashboardevery 60 seconds, shows disk usage bars - Network Status — polls
/api/federation/healthevery 60 seconds, shows galaxy status dots
User Records
Two new fields were added to UserRecord and AuthUser in src/lib/roles.ts:
| Field | Type | Purpose |
|---|---|---|
networkAffinity | 'milky-way' | 'andromeda' | User’s primary network |
quickLinks | QuickLink[] | Quick Launch widget buttons |
A QuickLink has: label, url, icon (FA class), and optional serviceId.
Example User Records
bogie (member, Andromeda):
- Services: plex, rutorrent, audiobookshelf, tautulli, grafana, speedtest, unraid-dashboard
- Profiles: bogie-command, bogie-infra
- Quick Links: Plex, Audiobooks, Downloads, Grafana, Unraid
mauve (member, Milky Way):
- Services: plex, rutorrent, audiobookshelf
- Profiles: mauve
- Quick Links: Plex, Audiobooks, Downloads
Security Model
- Service URLs are resolved server-side in SSR — unauthorized users never see them in page source
- The service registry enforces per-user filtering before any URL is rendered
- The mm-Arcturus-Prime proxy injects the Bearer token server-side — it is never exposed to the browser
- Restart API checks both service assignment AND container running state
- Each CF Tunnel hostname has its own CF Access policy with email allowlists
- Dual-layer auth: Cloudflare Access (edge) + Arcturus-Prime RBAC (application)
Files
| File | Purpose |
|---|---|
src/lib/service-registry.ts | Service definitions, KV storage, resolution |
src/lib/widget-registry.ts | Widget metadata and filtering |
src/lib/dashboard-profiles.ts | Profile definitions and KV storage |
src/lib/roles.ts | UserRecord with networkAffinity, quickLinks |
src/pages/api/federation/health.ts | Cross-network health aggregation |
src/pages/api/admin/services.ts | Admin CRUD for service registry |
src/pages/api/user/service-restart.ts | Safe restart with admin-disable protection |
src/pages/api/mm-Arcturus-Prime/[...path].ts | Proxy with member read-only access |
src/pages/dashboard/index.astro | Dashboard with per-user widget rendering |