Skip to content

SwissHD: Technical Setup & Configuration

Implementation procedures and configuration standards for the SwissHD dashboard within a Node.js runtime environment.


1. Overview

SwissHD is configured through declarative YAML files and environment variable definitions. Visual layouts, categories, and service cards are modified without recompiling application source code, while sensitive API tokens and credentials remain isolated within server-side environment files.

  • Status: Active
  • Target Environment: Linux / Windows / macOS (Node.js >= 20.0.0)

2. Requirements & Prerequisites

Necessary components or states prior to implementation:

  • Node.js: Version 20.0.0 or higher.
  • Package Manager: npm (v9.0.0 or higher).
  • API Access: Valid authentication tokens, API keys, or login credentials for target homelab services.
  • Network Routing: Unrestricted network reachability from the backend server to internal homelab subnets or Tailscale IP addresses.

3. Implementation Procedure

A. Environment Configuration

  1. Clone the repository and install dependencies for both root and subpackages:

    git clone https://github.com/onthecouch/swisshd.git
    cd swisshd
    npm install
    

  2. Copy the template environment file to create the local secrets configuration:

    cp .env.example .env.local
    

  3. Populate .env.local with authentication tokens and API keys required by active modules (see Section 4).

B. Local Development Servers

  1. Execute the Vite frontend development server in the primary terminal (serves UI at http://localhost:3000):

    npm run dev
    

  2. Execute the Express backend server in a secondary terminal (runs API on port 3001):

    npm run server
    

Note: The internal Vite proxy (vite.config.ts) automatically forwards all client requests matching /api/* to http://localhost:3001. Local development execution sets NODE_TLS_REJECT_UNAUTHORIZED=0 automatically to permit communication with self-signed SSL certificates on local homelab services.


4. Configuration Standards

Settings are managed according to two distinct files based on security requirements:

File Content Type Server Restart Required?
public/config.yaml Visible UI settings (service names, clickable links, color palettes, typography) No (hot-reloaded on browser refresh)
.env.local Secret authentication tokens, passwords, and API keys Yes (backend process restart required)

A. UI Configuration (public/config.yaml)

1. Title and Background System

dashboard:
  title: Homelab.
  icon: /logo.png

background:
  image: /bw.jpg
  opacity: 0.15

2. Color Palette Definitions

Hexadecimal values define the dark slate foundation and status accent colors:

theme:
  bg: "#202124"
  text: "#e8e2d0"
  accent:
    yellow: "#F2CD60"
    mint: "#6DEcb9"
    orange: "#FF9E64"
    pink: "#F04770"
    cyan: "#3DD6F5"
    violet: "#9E86FF"

3. Typography Configuration

Assign Google Fonts or local font families loaded from public/font/:

fonts:
  display: "Bricolage Grotesque"
  body: "Inter"
  mono: "Maple Mono"

4. Service Declarations

Declare active services under the services array. Each entry requires a unique id corresponding to a backend integration module:

services:
  - id: adguard_pve
    name: AdGuard Home
    url: http://[ADGUARD_IP]:[PORT]/
    category: Services
    labels:
      primary: queries
      secondary: blocked

  - id: filebrowser
    name: FileBrowser Quantum
    url: https://[FILEBROWSER_URL]/
    category: Storage
    labels:
      primary: files
      secondary: used

  • id: Unique identifier mapped by the backend Express server (backend/server.js) to attach telemetry handlers and credentials.
  • name: Display string rendered on the dashboard card.
  • url: Hyperlink target opened when the card is clicked.
  • apiUrl: (Optional) Override endpoint utilized by the backend if the polling address differs from the web navigation URL.
  • category: Navigation tab grouping string.
  • labels: Text descriptors for primary and secondary metric values returned by the API.

B. Secret Environment Variables (.env.local)

Define secret credentials in .env.local for local execution. In production CI/CD deployments, define these exact variable names within GitHub Actions Repository Secrets:

# Proxmox VE
PVE_1_AUTH="PVEAPIToken=USER@PAM!TOKENID=SECRET"
PVE_2_AUTH="PVEAPIToken=USER@PAM!TOKENID=SECRET"

# Kubernetes (K3s)
K3S_AUTH="Bearer YOUR_K3S_SERVICE_ACCOUNT_TOKEN"

# AdGuard Home
ADGUARD_PVE_USERNAME=admin
ADGUARD_PVE_PASSWORD=secret_password

# Media Stack (*Arr Stack & Torrents)
SONARR_API_KEY=your_api_key
RADARR_API_KEY=your_api_key
LIDARR_API_KEY=your_api_key
BAZARR_API_KEY=your_api_key
PROWLARR_API_KEY=your_api_key
QBITTORRENT_USERNAME=admin
QBITTORRENT_PASSWORD=secret_password
JELLYFIN_API_KEY=your_api_key

# Infrastructure & Tools
ARGOCD_TOKEN=your_jwt_token
GRAFANA_API_KEY=glsa_your_api_key
N8N_API_KEY=n8n_api_your_key
NOCODB_URL=http://[NOCODB_IP]:[PORT]
NOCODB_API_KEY=your_api_key
IMMICH_API_KEY=your_api_key
NETALERTX_API_KEY=your_api_key
AUTHENTIK_API_KEY=your_api_key
BACKREST_USERNAME=admin
BACKREST_PASSWORD=secret_password
NPM_EMAIL=admin@example.com
NPM_PASSWORD=secret_password
PORTAINER_API_KEY=ptr_your_key
PBS_API_TOKEN=USER@PAM!TOKENID
PBS_API_SECRET=secret_token
FILEBROWSER_TOKEN=your_quantum_api_token

C. Backend Control Architecture

The server control layer (backend/server.js) initializes Express on port 3001 and parses public/config.yaml.

  1. Service Registration: The server maps every entry in config.services to its corresponding module inside backend/modules/<name>/service.js.
  2. Concurrent Polling: When /api/dashboard is requested, the backend executes all registered service polling functions concurrently using Promise.allSettled.
  3. Caching Layer: Individual module handlers wrap API requests in an in-memory cache (lib/cache.js) with configured TTLs (typically 15 to 60 seconds) to prevent API rate-limiting or service exhaustion during frequent frontend polling.
  4. Activity Journal: The backend records status changes and collector events in SQLite, exposes GET /api/activity, and supports timeline purge through DELETE /api/activity.

D. Logs & Activity Journal (SQLite)

SwissHD incorporates a lightweight, zero-dependency operational event journal powered by the Node.js native node:sqlite (DatabaseSync) module.

1. Database Architecture

  • Engine: Built-in node:sqlite (DatabaseSync API), requiring no external driver dependencies.
  • WAL Mode: Write-Ahead Logging (WAL) is enabled at initialization to support high-performance concurrent reads and writes.
  • Persistence: The database file is written to backend/activity.db (git-ignored). In containerized environments, the location defaults to the /data mount point (configurable via DB_PATH environment variable) to ensure persistence across pod restarts using a Kubernetes PVC.
  • Retention Policy: A background worker runs every 24 hours to purge records older than the configured threshold (env variable ACTIVITY_RETENTION_DAYS, defaulting to 180 days, with a strict floor of 7 days).

2. Database Schema

The database maintains three tables:

  • activities: Append-only operational event log.
    • Fields: id (INTEGER PRIMARY KEY), timestamp (INTEGER), service_id (TEXT), type (TEXT), level (TEXT), message (TEXT), metadata (TEXT/JSON string).
  • service_states: Persists status state for consecutive failures tracking and status changes.
    • Fields: service_id (TEXT PRIMARY KEY), consecutive_failures (INTEGER), status (TEXT), last_changed (INTEGER).
  • collector_cursors: Stores incremental state tracking pointers for background event collectors.
    • Fields: collector_name (TEXT PRIMARY KEY), cursor_val (TEXT/JSON/Timestamp), last_run (INTEGER).

3. API Control Layer

  • Read Endpoint (GET /api/activity?limit=N): Queries and returns the last N records from the activities table.
  • Delete Endpoint (DELETE /api/activity): Drops all rows from activities and collector_cursors tables, clearing the visible timeline dashboard log immediately.

4. Frontend Integration

  • Worker Loop: An activity worker checks all service health states every 60 seconds, recording transitions (e.g. from OK to OFFLINE) to the database.
  • Log Presentation: Logs render as a modular timeline sortable by timestamp, status, and service name, using 15-item client-side pagination.
  • Detail Drawers: Expanding a log row displays a specialized detail viewer (e.g., PBS backup summaries, single PBS backups, ArgoCD sync events, ArgoCD health events, service status incidents, or generic metadata key-value grids) based on the event type attribute.

5. Verification

System health and operational correctness are validated through these procedures:

  1. Execute npm run build and confirm zero TypeScript compilation or bundler errors occur.
  2. Navigate to http://localhost:3000 and confirm the grid interface renders with the configured typography and color scheme.
  3. Inspect network requests in the browser developer tools; confirm /api/dashboard returns HTTP 200 with JSON payload containing active metrics.
  4. Confirm /api/dashboard/meta returns the discovered service registry.
  5. Verify /api/activity?limit=100 returns journal records or an empty list.
  6. Verify browser console logs remain clean of HTTP 401 (Unauthorized), 403 (Forbidden), or CORS routing errors.
  7. Confirm individual cards display formatted telemetry corresponding to their YAML definitions (e.g., FileBrowser displaying 27.9 GB / 1.8 TB).

6. Troubleshooting

Symptom Root Cause Technical Resolution
Card displays ONLINE without metrics Missing integration mapping Verify the service id in config.yaml matches an active integration name exactly.
Card displays OFFLINE or fetch_failed Unreachable endpoint Confirm network routing to the target IP/URL; verify target service SSL certificates.
HTTP 401 / 403 errors in backend logs Invalid secret credential Check .env.local token syntax; ensure API keys have not expired or lost permissions.
FileBrowser displays 500 source not provided Multi-source Quantum setup Ensure backend is running v0.12.1+ with automatic /api/settings?property=sources discovery.
Local frontend cannot reach /api/dashboard Proxy misconfiguration Confirm vite.config.ts includes the proxy rule forwarding /api to http://localhost:3001.