From b8801fd1d559ff41edbd31df202abd48e053cb2e Mon Sep 17 00:00:00 2001 From: sheepdestroyer Date: Wed, 8 Jul 2026 16:34:00 +0200 Subject: [PATCH 1/3] docs: document boy as production deployment user in README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index b7c839ba..2c5aa78f 100644 --- a/README.md +++ b/README.md @@ -356,6 +356,15 @@ The stack also supports **semantic** (vector-similarity) caching via `vector_sto ## 5. Setup & Deployment Instructions +### Production Deployment User +For secure production deployments, the gateway services are configured to run under a dedicated, sudoless service account: +- **User**: `boy` +- **Home Directory**: `/mnt/DATA/boy` +- **Security Profile**: Completely sudoless (no administrative or `wheel` group privileges) to minimize container breakout risks. +- **Service Persistence**: Systemd user lingering is enabled (`loginctl enable-linger boy`) to allow the rootless services to start at boot and run persistently without active user sessions. +- **Access**: Configured for direct SSH administration via authorized public keys in `/mnt/DATA/boy/.ssh/authorized_keys`. +- **Rootless Podman**: Fully configured with container subuids/subgids and a user-level Docker-compatible API socket (`podman.socket` listening at `/run/user/1002/podman/podman.sock`). + ### Prerequisites 1. **Llama-Server Active**: Verify that your local user-level GPU-accelerated server is active: ```bash From 32e36a9695aaeee018e0184d3d66a792bcab95ad Mon Sep 17 00:00:00 2001 From: sheepdestroyer Date: Wed, 8 Jul 2026 17:33:55 +0200 Subject: [PATCH 2/3] chore: make dashboard paths relative for subdirectory reverse proxy and document boy user SSH alias --- README.md | 2 +- router/main.py | 4 ++-- router/static/visualizer.html | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2c5aa78f..2ea27ae5 100644 --- a/README.md +++ b/README.md @@ -362,7 +362,7 @@ For secure production deployments, the gateway services are configured to run un - **Home Directory**: `/mnt/DATA/boy` - **Security Profile**: Completely sudoless (no administrative or `wheel` group privileges) to minimize container breakout risks. - **Service Persistence**: Systemd user lingering is enabled (`loginctl enable-linger boy`) to allow the rootless services to start at boot and run persistently without active user sessions. -- **Access**: Configured for direct SSH administration via authorized public keys in `/mnt/DATA/boy/.ssh/authorized_keys`. +- **Access**: Configured for direct SSH administration via authorized public keys in `/mnt/DATA/boy/.ssh/authorized_keys`. An SSH host configuration has been added to `~/.ssh/config` so you can connect simply via `ssh boy` (and a shell shortcut alias `boy` has been added to `~/.bashrc` to quickly access the host shell). - **Rootless Podman**: Fully configured with container subuids/subgids and a user-level Docker-compatible API socket (`podman.socket` listening at `/run/user/1002/podman/podman.sock`). ### Prerequisites diff --git a/router/main.py b/router/main.py index e7d356cc..f73c5289 100644 --- a/router/main.py +++ b/router/main.py @@ -3501,7 +3501,7 @@ async def get_dashboard(): @@ -3596,7 +3604,7 @@ async def get_dashboard():
System Control Center
- 📊 Dataset Visualizer + 📊 Dataset Visualizer
diff --git a/router/static/visualizer.html b/router/static/visualizer.html index 08730bfa..a66054df 100644 --- a/router/static/visualizer.html +++ b/router/static/visualizer.html @@ -109,10 +109,12 @@

Select a prompt from the list

let currentFilter = 'all'; let selectedIdx = -1; +const apiBase = window.location.pathname.includes('/static/') ? '../' : './'; + // Load data async function init() { try { - const resp = await fetch('../data/classified_dataset.json'); + const resp = await fetch(apiBase + 'data/classified_dataset.json'); const raw = await resp.json(); dataset = raw.prompts || []; // Extract global stats from combined dataset @@ -127,7 +129,7 @@

Select a prompt from the list

// Load benchmark results if available try { - const resp = await fetch('../data/benchmark_results.json'); + const resp = await fetch(apiBase + 'data/benchmark_results.json'); benchmark = await resp.json(); // Map benchmark results to dataset by index } catch(e) { @@ -136,7 +138,7 @@

Select a prompt from the list

// Load annotations try { - const resp = await fetch('../data/annotations.json'); + const resp = await fetch(apiBase + 'data/annotations.json'); const serverAnn = await resp.json(); annotations = { ...serverAnn, ...annotations }; } catch(e) { @@ -351,7 +353,7 @@

✎ Human Review

// Save to localStorage localStorage.setItem('classifier-annotations', JSON.stringify(annotations)); // Auto-sync by posting to dashboard save endpoint - fetch('../dashboard/save-annotations', { + fetch(apiBase + 'dashboard/save-annotations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(annotations),