docs: realign design docs with deployed app, consolidate, rewrite README (#24)

* Add editable display-name field to generic integrations

Lets users set a custom name for Proxmox, Docker, AWS, Remote Desktop,
Netbird, Cloudflare, Uptime Kuma, and Weather integrations, separate
from the host/IP field, mirroring the SSH host rename pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

* Surface the new-integration name field as a labeled input

The name field for new generic integrations was a faint header input
with only placeholder text, easy to miss. Move it into the form grid
as a proper labeled "Name" field next to the other connection fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

* Add file upload for SSH private key and certificate fields

Lets users pick a key file from disk (e.g. ~/.ssh) instead of pasting
its contents into the Private Key / OPKSSH Certificate fields.

* Fix SSH private key paste corrupting multi-line PEM format

Private Key and Certificate fields were single-line <input> elements,
which strip newlines on paste and corrupt PEM-formatted keys (causing
'Unsupported key format' errors). Render them as multi-line textareas
instead so pasted keys keep their line breaks.

* Add JSON-converted bookmark import file for Archnest data import

Converts homarr-bookmarks.md into the format expected by /api/data/import.

* Auto-populate bookmark icons via favicon service in import JSON

Each bookmark now points to Google's favicon endpoint for its domain
instead of having no icon at all.

* docs: realign design docs with the deployed app, consolidate, rewrite README

README.md was badly stale (listed Terminal as "pending/on hold" and only
5 pages, when all 11 pages are built and live). Rewrote it as a detailed,
accurate map of the architecture, every page, every backend route,
every integration adapter, and the SSH subsystem, written explicitly for
this repo's actual audience (the owner + future AI sessions, never the
public).

Deleted archnest-blueprint.md and glance.md: both were pre-backend mockup
specs describing fictional config files (systems.config, infra.config,
fail2ban-driven security scoring) and placeholder data that never matched
the real implementation, and conflicted with the deployed app's actual
page count/nav/data sources. Their still-true content (color palette,
dropdown menu shape, card styling) was folded into design-decisions.md.

Rewrote design-decisions.md's "Page-Specific Notes" into a full "Page
Notes" section covering all 11 pages plus Login/Enrollment (previously
only 4 pages had notes, and those didn't reflect later changes like
Files/Tunnels/Containers/Host Metrics/Remote Desktop shipping). Each
section now states the real data source per page so it can't drift from
the code silently again.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Samuel James 2026-06-20 10:22:04 -04:00 committed by GitHub
parent 2229a8254a
commit d8286ac42b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 429 additions and 984 deletions

200
README.md
View file

@ -1,23 +1,128 @@
# ArchNest
A self-hosted ops dashboard — infrastructure monitoring, a bookmark hub for your homelab/cloud links, an embedded terminal, and system settings, all in one place. Real backend, real integrations, no mock data.
A self-hosted ops dashboard for a homelab/cloud setup: live infrastructure
monitoring across 9 real integration types, a categorized bookmark hub, a
full SSH suite (terminal, tunnels, file manager, host-to-host transfer, live
host metrics), Docker container management, and RDP/VNC/Telnet remote desktop
— all in one app, with zero mock data anywhere.
Frontend: React 19 + TypeScript + Vite, styled with Tailwind CSS v4, charts via Recharts, icons via Lucide React.
Backend: Fastify + TypeScript + SQLite (`better-sqlite3`), JWT auth, AES-256-GCM encrypted integration secrets.
**This repo is private and will never be public.** This README is written for
the owner and for any AI session picking up the project cold — it should be
detailed enough that neither needs to re-derive context from scratch.
**For a full handoff/status writeup (what's done, what's not, how to resume), see [`HANDOFF.md`](./HANDOFF.md).**
## What this is, in one paragraph
ArchNest replaced a Homarr-style bookmark dashboard plus a handful of
disconnected admin tools (Proxmox UI, Portainer, separate SSH terminals,
WinSCP-equivalents) with one app that talks directly to the underlying
systems. It started as a 6-page mockup/portfolio piece and has since grown
into an 11-page real tool with a real Fastify backend, real SSH/Docker/cloud
integrations, and no synthetic data — every number on every page comes from
a live API call, a SQLite-backed table, or an SSH command run against a
managed host.
## Current state & direction
**Live and deployed** at `archnest.snsnetlabs.com`, auto-deploying on every
merge to `main` via `.github/workflows/deploy.yml`. All 11 pages and their
backend routes are built and working — there is no pending/on-hold page.
The active area of work is **the auth system**: the user menu's
Profile/Appearance/Security links were fixed in Phase 1; Phases 2-4
(password change + sessions + login audit log, multi-user accounts,
Authentik SSO) are planned but not started — see `HANDOFF.md` for the full
phase breakdown and exactly where to resume.
If you're a fresh AI session: read this file, then `HANDOFF.md` (current
task state + standing workflow rules), then `design-decisions.md` (visual
conventions + accurate per-page implementation notes), then
`TERMIX_MIGRATION.md` (history of how the SSH/Docker/Guacamole feature set
was built) if you need historical context on a specific feature.
## Pages
| Page | Route | Status |
|------|-------|--------|
| Glance | `/` | Done — real backend data (system status, resource overview, alerts, network traffic) |
| Infrastructure | `/infrastructure` | Done — resource distribution, node status grid, cost/trend breakdown, all from real integration data. "Network" sub-tab planned as a future addition. |
| BookNest | `/booknest` | Done — categorized bookmark hub wired to the real bookmarks API |
| Terminal | `/terminal` | **Pending / on hold** — will be based on a fork of the (archived) Termix project; user has the fork and intends to hand this off to another AI session to integrate. Do not start this without explicit instruction. |
| Settings | `/settings` | Done — Profile (real user identity + avatar, editable via API), Appearance, Integrations (8 real adapters), Notifications, Data & Backup, About |
| Page | Route | What it does |
|------|-------|---------------|
| Glance | `/` | Home dashboard — system/integration health, resource overview, recent activity, shortcuts |
| Infrastructure | `/infrastructure` | Resource inventory across all integrations — distribution donut, per-resource status grid, integration health, activity |
| BookNest | `/booknest` | Categorized bookmark hub — quick access, favorites, link health, full CRUD |
| Terminal | `/terminal` | Web SSH terminal — multi-tab, split panes, tmux attach, cert auth (OPKSSH) |
| Tunnels | `/tunnels` | SSH tunnel manager — local/remote/dynamic (SOCKS5) forwarding, auto-start, live status |
| Files | `/files` | SFTP file browser/editor over managed SSH hosts, with host-to-host transfer |
| Containers | `/containers` | Docker container management — start/stop/restart/pause/remove, logs, interactive exec |
| Remote Desktop | `/remote-desktop` | RDP/VNC/Telnet sessions via a Guacamole sidecar |
| Host Metrics | `/host-metrics` | Live CPU/memory/disk/network/processes/ports/firewall/login-activity per SSH host, polled every 5s |
| Settings | `/settings` | Profile, Appearance, Security, Integrations, Notifications, Data & Backup, About — deep-linkable via `?tab=` |
| Help | `/help` | Static guided tour of every page above |
| Login / Enrollment | `/login`, `/enrollment` | Auth entry points — not in the sidebar nav |
See `archnest-blueprint.md` for the original per-page design spec and `design-decisions.md` for the visual/UX conventions and lessons learned while building each page — read that file before making layout changes, it documents *why* things are built the way they are (hero banner layering, card blend techniques, icon library gotchas, etc.).
See `design-decisions.md`'s "Page Notes" section for a detailed, per-page
breakdown of layout, real data sources, and known quirks — it's kept in sync
with the actual code, not a spec written before the page existed.
## Architecture
### Frontend (`/src`)
- React 19 + Vite + TypeScript, Tailwind CSS v4, Recharts (donuts/area
charts), Lucide React icons, React Router.
- `src/lib/api.ts` — typed fetch wrapper (`apiFetch`) + one function per
backend endpoint + matching TS interfaces. This is the contract between
frontend and backend; any new backend route needs a matching entry here.
- `src/lib/AuthContext.tsx` — auth state backed by `localStorage` (single JWT,
no session tracking yet — Phase 2 of the auth roadmap).
- `src/pages/` — one file per route (see table above), plus `Login.tsx` /
`Enrollment.tsx` for the unauthenticated/first-run flows.
- `src/components/``TopBar.tsx` (title, global search across pages/
integrations/bookmarks, user dropdown), `Sidebar.tsx` (nav + system-health
rollup widget).
- `App.tsx` — route table, plus per-route hero-banner config (`showHero`,
`heroPaddingTop`, `heroObjectPosition` lookup maps) and `topBarHeight`
lookup for pages with a subtitle (currently only BookNest).
### Backend (`/backend`)
- Fastify 5, TypeScript, ESM (`tsx` for dev, `tsc -b` for build), entrypoint
`src/server.ts`.
- `backend/src/db/index.ts` — SQLite schema + `logEvent()` audit log.
Single-user schema today (no `role` column, no multi-account concept —
see `HANDOFF.md` Phase 3).
- `backend/src/db/crypto.ts` — AES-256-GCM `encryptSecret`/`decryptSecret`,
keyed by `ARCHNEST_SECRET_KEY`.
- `backend/src/routes/` — one file per feature area:
- `auth.ts` — setup, login, profile (`/api/setup`, `/api/auth/login`,
`/api/auth/me`)
- `integrations.ts` — integration CRUD + connection testing
- `bookmarks.ts` — bookmarks + categories CRUD
- `events.ts` — activity log retrieval
- `terminal.ts` — SSH terminal WebSocket (`connect`/`input`/`resize`/
`list_tmux`/`disconnect`)
- `tunnels.ts` — SSH tunnel CRUD + connect/disconnect
- `files.ts` — SFTP list/read/write/mkdir/rename/delete/chmod/download/upload
- `docker.ts` — Docker exec WebSocket (interactive container shell)
- `guacamole.ts` — Guacamole WebSocket proxy for remote desktop
- `metrics.ts` — live host metrics endpoint
- `transfer.ts` — host-to-host file transfer orchestration (start/poll/cancel)
- `data.ts` — full backup export/import (integrations + secrets + bookmarks + tunnels)
- `backend/src/integrations/` — one adapter per type, all real (none are
stubs): `proxmox.ts`, `docker.ts`, `netbird.ts`, `cloudflare.ts`, `aws.ts`,
`uptimeKuma.ts`, `weather.ts`, `ssh.ts`, `remoteDesktop.ts`. Each implements
`testConnection()` (required) and `listResources()` (optional);
`registry.ts` maps `IntegrationType` → adapter.
- `backend/src/ssh/` — the shared SSH transport layer used by Terminal,
Files, Tunnels, Transfers, and Host Metrics:
- `connect.ts` — jump-host chaining, host-key verification, certificate auth
- `sftp.ts` — ephemeral SFTP connections for file ops
- `transfer.ts` — streamed host-to-host copy/move with progress + cancel
- `metrics/` — 10 sequential collectors (cpu, memory, disk, uptime,
network, system, processes, ports, firewall, login-stats) — sequential
on purpose, to stay under OpenSSH's `MaxSessions` limit per host.
- Docker images run on Alpine; **OpenSSL legacy provider is enabled** in
`backend/Dockerfile` (`OPENSSL_CONF=/etc/ssl/openssl-legacy.cnf`) so
old-format encrypted PEM keys (`BEGIN RSA PRIVATE KEY` + `DEK-Info`) still
decrypt under OpenSSL 3 — don't remove this without understanding why.
- **Required env vars, no defaults**: `ARCHNEST_SECRET_KEY`,
`ARCHNEST_JWT_SECRET`. The server refuses to start without both. Optional:
`ARCHNEST_DB_PATH`, `PORT`, `ARCHNEST_GUAC_CRYPT_KEY` /
`ARCHNEST_GUACD_HOST` / `ARCHNEST_GUACD_PORT`, `ARCHNEST_CORS_ORIGIN`,
`ARCHNEST_SESSION_LOG_DIR` (optional terminal session logging).
## Development
@ -34,23 +139,26 @@ npm install
ARCHNEST_SECRET_KEY=$(openssl rand -hex 32) ARCHNEST_JWT_SECRET=$(openssl rand -hex 32) npm run dev
```
Both `ARCHNEST_SECRET_KEY` (encrypts integration secrets at rest) and `ARCHNEST_JWT_SECRET` (signs auth tokens) are required env vars with no defaults — the server will refuse to start without them. `ARCHNEST_DB_PATH` optionally overrides the SQLite file location (defaults to a local path under `backend/`). `PORT` overrides the listen port (default 4000-range, check `server.ts`).
`ARCHNEST_DB_PATH` optionally overrides the SQLite file location (defaults to
a local path under `backend/`). `PORT` overrides the listen port (check
`server.ts` for the default).
Type-check both before committing:
Type-check both before committing — this is the minimum bar, not a substitute
for testing in a browser:
```bash
npx tsc --noEmit # from repo root, frontend
cd backend && npx tsc --noEmit # backend
```
Vite/the browser surface some runtime errors (e.g. missing icon exports) that the type-checker won't catch, so also smoke-test pages in a browser.
Vite/the browser surface some runtime errors (e.g. missing icon exports —
see the lucide-react gotcha in `design-decisions.md`) that the type-checker
won't catch.
## Tech Stack
**Frontend**
- React 19 + Vite + TypeScript
- React Router for routing
- Tailwind CSS v4
- Recharts (donuts, line/area charts)
- Lucide React (icons)
- React 19 + Vite + TypeScript, React Router, Tailwind CSS v4
- Recharts (donuts, line/area charts), Lucide React (icons)
- xterm.js (Terminal page terminal rendering)
**Backend**
- Fastify 5 + TypeScript, `tsx` for dev, `tsc -b` for build
@ -58,16 +166,56 @@ Vite/the browser surface some runtime errors (e.g. missing icon exports) that th
- `@fastify/jwt` for auth tokens, `bcryptjs` for password hashing
- `zod` for request validation
- AES-256-GCM (Node `crypto`) for encrypting integration secrets at rest
- Integration adapters: Proxmox, Docker, NetBird, Cloudflare, AWS, Uptime Kuma, Weather, SSH (see `backend/src/integrations/`)
- SSH client library powering the SSH transport layer (`backend/src/ssh/`)
- Guacamole Lite protocol for RDP/VNC/Telnet, proxied to a `guacd` sidecar
**Deploy target:** Docker on `racknerd1` → NPM (Nginx Proxy Manager) proxy at `archnest.snsnetlabs.com`.
**Integrations**: Proxmox, Docker, NetBird, Cloudflare, AWS, Uptime Kuma,
Weather (wttr.in), SSH, Remote Desktop (RDP/VNC/Telnet via Guacamole) — see
`backend/src/integrations/` for adapter implementations.
**Deploy target:** Docker on `racknerd1` → Nginx Proxy Manager at
`archnest.snsnetlabs.com`.
## Deployment
**Live and deployed** at `archnest.snsnetlabs.com`. The pipeline at `.github/workflows/deploy.yml` triggers on every push to `main`: it copies the repo to `racknerd1` over SCP and runs `docker compose up -d --build` there, gated on an `/api/health` check. No further setup is needed — merging a PR to `main` redeploys automatically.
**Live and deployed.** `.github/workflows/deploy.yml` triggers on every push
to `main`: builds, SCPs the repo to `racknerd1`, and runs
`docker compose up -d --build` there, gated on an `/api/health` health check.
No further setup is needed — merging a PR to `main` redeploys automatically.
If a deploy fails, check the workflow run's `deploy` job steps in order: `Pre-flight` (confirms host `.env` exists), `Copy repo to racknerd1`, `Build, restart, and clean up`, `Health check (backend /api/health)`.
`docker-compose.yml` runs 3 services: `archnest` (frontend), `archnest-backend`,
and `guacd` (remote desktop sidecar).
For reference, the one-time setup that was done to stand this up: host provisioning (Docker/Compose on `racknerd1`, deploy SSH user, `/opt/archnest` directory), `/opt/archnest/.env` populated from `.env.example` with real secrets, `RACKNERD_HOST`/`RACKNERD_USER`/`RACKNERD_SSH_KEY` added as GitHub Actions secrets, and DNS/Nginx Proxy Manager pointed at the host.
If a deploy fails, check the workflow run's `deploy` job steps in order:
`Pre-flight` (confirms host `.env` exists) → `Copy repo to racknerd1`
`Build, restart, and clean up``Health check (backend /api/health)`.
See `HANDOFF.md` for current feature work in progress (multi-user accounts, SSO, security settings).
One-time setup already done (reference only, shouldn't need repeating): host
provisioning (Docker/Compose on `racknerd1`, deploy SSH user, `/opt/archnest`
directory), `/opt/archnest/.env` populated from `.env.example` with real
secrets, `RACKNERD_HOST`/`RACKNERD_USER`/`RACKNERD_SSH_KEY` added as GitHub
Actions secrets, DNS/Nginx Proxy Manager pointed at the host.
## Documentation map
- **`README.md`** (this file) — architecture, tech stack, deployment, page list.
- **`HANDOFF.md`** — current task state, standing workflow rules (git workflow,
mock-data policy, secrets discipline), and the auth/SSO roadmap. Read this
before starting any new work session.
- **`design-decisions.md`** — visual/UX conventions (colors, typography, card
style, animations) plus a detailed, accurate-as-of-now "Page Notes" section
per page — what's actually rendered and where its data comes from. This is
the file to update whenever a page's layout or data source changes.
- **`TERMIX_MIGRATION.md`** — phase-by-phase history of how the SSH/Tunnels/
Files/Containers/Remote Desktop/Host Metrics/Transfer/Data-export feature
set was built (originally scoped as a migration from a forked Termix
project, hence the name). Useful for historical "why was it built this
way" context on those specific features.
Two older docs were deleted as part of a documentation cleanup
(`archnest-blueprint.md`, the original 6-page mockup pitch with fictional
config files and placeholder numbers; `glance.md`, an early Glance-only spec
with the same problem). Their still-accurate content (color palette,
dropdown menu shape, card styling) was folded into `design-decisions.md`,
and everything else was superseded by the real, deployed implementation
described above.

View file

@ -1,405 +0,0 @@
# ArchNest Dashboard — Blueprint
> Complete spec for a 6-page custom dashboard. Portfolio showcase piece.
---
## Global Design Language
### Color Palette
| Role | Value | Usage |
|------|-------|-------|
| Background (page) | `#0D0E10` | Near-black, warm undertone |
| Background (cards) | `#141518` | Slightly elevated surfaces |
| Background (sidebar) | `#0A0B0D` | Darker than page |
| Border (cards) | `#1E2025` | Subtle 1px card outlines |
| Border (hover/active) | `#C8A434` | Gold highlight on interaction |
| Accent (primary) | `#C8A434` | Gold — links, active states, progress bars |
| Accent (success) | `#2ECC71` | Green — operational, running, completed |
| Accent (warning) | `#E67E22` | Orange — warnings, medium alerts |
| Accent (danger) | `#E74C3C` | Red — critical, high alerts, errors |
| Text (primary) | `#E8E6E0` | Warm white/cream |
| Text (secondary) | `#7A7D85` | Muted gray — labels, timestamps |
| Text (accent) | `#C8A434` | Gold — active nav, status labels |
### Typography
| Element | Style |
|---------|-------|
| Card titles | 12-13px, uppercase, letter-spacing 1px, secondary color |
| Large numbers | 28-36px, bold, primary color |
| Body text | 14px, primary color |
| Labels/descriptions | 12-13px, secondary color |
| Nav items | 14px, secondary (gold when active) |
### Card Style
- Border radius: 12px
- Background: `#141518`
- Border: 1px solid `#1E2025`
- Padding: 20-24px
- No shadows (flat design)
- Hover: border transitions to gold (0.2s ease)
---
## Shared Components (appear on every page)
### Sidebar (fixed left, ~80px)
- **Logo**: ArchNest arch icon (gold gradient) + "ARCHNEST" text (gold, 10px caps)
- **Nav items**: icon (18px) + label (14px), active = gold text + gold left border (3px)
- **Bottom**: Green dot + "System Status" / "All Systems Operational" (gold)
**Final Nav (6 items):**
| # | Icon | Label | Route |
|---|------|-------|-------|
| 1 | grid | Glance | `/` |
| 2 | server | Infrastructure | `/infrastructure` |
| 3 | globe | Network | `/network` |
| 4 | bookmark | BookNest | `/booknest` |
| 5 | terminal | Terminal | `/terminal` |
| 6 | settings | Settings | `/settings` |
### Top Bar (~56px height)
- **Left**: Page title (bold, uppercase, 18px)
- **Center-right**: Search bar (rounded, ~300px, placeholder varies by page)
- **Right**: Bell icon (with badge) + User avatar (36px, gold ring) + "ArchNest Ops" / "Administrator" + chevron
### Hero Banner
- Full width of main content area, 12px radius, overflow hidden
- Image: `archnest-brand.png` (dark cityscape + gold arch)
- Height varies: ~200px on Glance, ~120px on sub-pages
- Not shown on Terminal or Settings pages
### Page Footer / Status Bar
- Height: ~40px, subtle top border
- Content: Contextual stats (varies per page) + "Last updated: 2m ago" (right)
---
## Interactions & Behaviors
- Sidebar nav: click navigates, gold highlight on active
- Card hover: border → gold (0.2s)
- Close buttons (X): hide/collapse cards
- "View all" links: navigate to full views
- Progress rings/bars: animated fill on load
- Sparklines: subtle animation, periodic update
---
## Responsive Behavior
- **Desktop (>1200px)**: Full layout
- **Tablet (768-1200px)**: Sidebar → icons only (~50px), cards 2-column
- **Mobile (<768px)**: Sidebar → bottom nav, cards single column
---
## Tech Stack
- React 19 + Vite + TypeScript
- Zustand (state)
- Chart.js or Recharts (sparklines, donuts, area charts)
- Lucide React (icons)
- xterm.js (terminal page)
- CSS Modules or Tailwind
- Deploy: Docker on racknerd1 → NPM proxy at archnest.snsnetlabs.com
---
## Assets
| Asset | CDN Path | Usage |
|-------|----------|-------|
| Logo | `logos/brands/archnest-logo.png` | Sidebar |
| Banner | `backgrounds/archnest-brand.png` | Hero |
| Network bg | `backgrounds/archnest-network-bg.jpg` | Network page alt |
| Geometric bg | `backgrounds/archnest-geometric-bg.jpg` | Texture overlay |
CDN base: `https://raw.githubusercontent.com/SamuelSJames/assets-public/master/`
---
## Page 1: Glance (`/`)
> Main operations dashboard — system health at a glance
### Status Cards Row (4 cards)
| Card | Icon | Number | Subtitle | Extra |
|------|------|--------|----------|-------|
| System Status | checkmark | 100% | All Systems Operational | Circular progress ring + sparkline |
| Infrastructure | server | 24 | Total Resources | 🟢24 Running 🟡0 Warning 🔴0 Critical |
| Security | shield | 2 | Active Alerts | 🟡2 Low 🟡0 Medium 🔴0 High |
| Network | nodes | 98.7% | Network Uptime | Sparkline |
### Middle Row (3 columns: 30% | 40% | 30%)
**Resource Overview** (left):
- 5 progress bars: Compute 18/24, Storage 12.4/20 TB, Database 8/12, Network 98.7%, Containers 32/40
**Recent Activity** (center):
- Backup completed (2m) | Security scan completed (8m) | Instance launched (15m) | Config updated (22m) | User login (35m)
**Top Alerts** (right):
- 🔴 High CPU Usage App Server 02 (2m)
- 🟡 Disk Space Low Database Cluster 01 (15m)
- 🟡 Unauthorized Login Web Frontend (32m)
- 🟡 SSL Cert Expiring api.archnest.io (1h)
### Bottom Row (2 columns: 65% | 35%)
**Network Traffic** (left):
- Area chart (gold gradient) + stats: Incoming 1.23 Gbps (↓12.4%), Outgoing 1.08 Gbps (↑8.7%)
**Shortcuts** (right):
- 4 icon buttons: Add Server | Create Backup | Deploy App | View Logs
### Footer Stats
- System Status 100% | 24 Resources | 2 Alerts | 98.7% Uptime
---
## Page 2: Infrastructure (`/infrastructure`)
> Monitor and manage your cloud infrastructure
### Sub-Tabs
Overview | Compute | Storage | Network | Database | Containers | Load Balancers | DNS | Backups | Tags
**Actions**: "+ Add Resource" button, gear icon
### Status Cards Row (5 cards)
| Card | Number | Subtitle | Trend |
|------|--------|----------|-------|
| Total Resources | 128 | Across all regions | ↑12.4% 7d |
| Total Cost (MTD) | $24,560.75 | Across all services | ↓8.7% month |
| Resource Health | 98.7% | Healthy | ↑2.1% 7d |
| Active Alerts | 2 | Requires attention | ↓63% 7d |
| Uptime | 99.98% | Global uptime | ↑0.01% 7d |
### Middle Row (30% | 40% | 30%)
**Resource Distribution** (left):
- Donut chart: 128 Total — Compute 38 (29.7%), Storage 24 (18.8%), Database 16 (12.5%), Network 20 (15.6%), Containers 18 (14.1%), Others 12 (9.4%)
**Infrastructure Map** (center):
- Dark world map with gold glowing dots (region markers), connection lines
- Footer: 6 Regions | 18 AZs | 128 Resources | 🟢 Live
**Top Resources by Utilization** (right):
- web-app-01 (m6i.large) 85% | api-server-02 (c6i.xlarge) 72% | db-primary (db.r6g.xlarge) 68% | cache-cluster 55% | worker-node-01 48%
### Bottom Row (35% | 35% | 30%)
**Resource Trend** (left):
- Multi-line area chart (7 days): Compute, Storage, Database, Network lines
**Cost Breakdown MTD** (center):
- Donut: $24,560.75 Total — Compute $12,450 (50.7%), Storage $5,213 (21.2%), Database $3,452 (14.1%), Network $2,134 (8.7%), Others $1,310 (5.3%)
**Recent Activity** (right):
- EC2 web-app-01 created (2m) | RDS backup (15m) | SG updated (32m) | S3 bucket created (1h) | LB updated (2h)
### Footer Stats
- AWS | 6 Regions | 18 AZs | 128 Resources | 98.7% Health | $24,560.75 MTD | 2 Alerts
---
## Page 3: Network (`/network`)
> Monitor and manage your network performance and security
### Sub-Tabs
Overview | Traffic | Topology | Devices | Interfaces | VPN | DNS | Firewalls | Load Balancers | Alerts | Reports
**Actions**: "Last 24 Hours" dropdown, "Export Report" button
### Status Cards Row (6 cards)
| Card | Number | Trend |
|------|--------|-------|
| Network Health | 98.7% "Excellent" | ↑2.3% yesterday |
| Total Traffic | 1.23 Tbps | ↑18.6% yesterday |
| Packet Loss | 0.02% | ↓0.01% yesterday |
| Active Connections | 28,457 | ↑6.7% yesterday |
| Threats Blocked | 152 | ↑12.4% yesterday (⚠) |
| Avg. Latency | 12.4 ms | ↓8.1% yesterday |
### Middle Row (25% | 50% | 25%)
**Top Talkers** (left):
- web-app-01 203.4 Gbps | db-primary 156.7 Gbps | cache-cluster 98.3 Gbps | api-gateway 76.1 Gbps | backup-server 54.8 Gbps
**Network Topology** (center):
- Dark world map with gold node dots, connection lines, glow effects
- Legend: 🟢 Live | 🟡 Warning | 🔴 Critical
- Controls: Zoom +/-, Fullscreen
**Interface Utilization + Alert Summary** (right, stacked):
- Interfaces: ethernet1/1 85%, 1/2 72%, 1/3 68%, 1/4 55%, 1/5 48% (green/gold bars)
- Alert Summary: 🔴 2 Critical | 🟡 5 Warning | 🟢 12 Info
### Bottom Row (35% | 35% | 30%)
**Traffic Over Time** (left):
- Area chart (24h): Inbound (gold), Outbound (amber), Total (teal)
- Y: 250 Gbps 1.5 Tbps, X: 00:0020:00
**Protocol Distribution** (center):
- Donut: 1.23 Tbps Total — TCP 65.2%, UDP 18.7%, ICMP 7.3%, DNS 4.1%, Others 4.7%
**Recent Events** (right):
- ethernet1/2 UP (2m) | High bandwidth web-app-01 (8m) | New device 10.0.1.45 (15m) | VPN tunnel us-west-2 (22m) | Blocked threat 185.199.108.153 (35m)
### Footer Stats
- 6 Regions | 42 Sites | 248 Devices | 1,245 Interfaces | 28,457 Connections | 98.7% Health
---
## Page 4: BookNest (`/booknest`)
> Your Digital Library — categorized bookmarks with health monitoring
### Page Stats (below title)
🔗 **312** Links | 📁 **18** Categories | ⭐ **12** Favorites
### Layout: Main (75%) + Right Sidebar (25%)
### Quick Access Row (5 cards)
| Category | Icons shown | Count |
|----------|------------|-------|
| Infrastructure | Proxmox, Cloudflare, Portainer, Cockpit, CasaOS | 5 links |
| Development | GitHub, GitLab, Gitea, VSCode, Docker | 5 links |
| AI Tools | ChatGPT, Claude, AI icons, OpenWebUI | 5 links |
| AWS | AWS service icons | 5 links |
| Networking | NetBird, Wireshark, Cisco, Ubiquiti | 5 links |
### Bookmark Groups — Row 1 (4 columns)
**Infrastructure & Self Hosted** (10 links):
CasaOS, Proxmox (pve1), Proxmox (mtr), Portainer, Cockpit, Cloudflare, NPM, NetBird, Linode, RackNerd
**Development & Code** (8 links):
GitHub, Gitea, Trillium Notes, VSCode Web, Docker Hub, GitLab, Terraform Registry, Ansible Galaxy
**Lab & Networking** (8 links):
GNS3, EVE-NG, OpenClaw, NetBird, Cisco Docs, Juniper Docs, Wireshark, iPerf3
**AWS** (8 links):
AWS Console, IAM, EC2, S3, CloudFormation, Route 53, VPC, Billing
### Bookmark Groups — Row 2 (4 columns)
**AI Tools** (7 links):
ChatGPT, Claude, Gemini, PartyRock, Perplexity, OpenWebUI, Ollama
**Learning** (6 links):
WGU, Udemy, AWS Skill Builder, YouTube, LinkedIn Learning, Coursera
**Finance** (5 links):
Bank, Budget, Investments, Retirement, Credit Cards
**Life** (6 links):
Calendar, Email, Photos, Drive, Notes, Travel
### Right Sidebar Widgets
**Favorites**: Proxmox (pve1), GitHub, AWS Console, ChatGPT, NetBird
**Recently Used**: Proxmox 5m, GitHub 15m, AWS Console 1h, Trilium 2h, GNS3 3h
**Link Health** (donut): 304 Online, 6 Warning, 2 Offline (312 total)
**Category Breakdown** (donut): Infrastructure 32%, Development 24%, AI Tools 18%, Learning 10%, Finance 8%, Life 8%
### Link Item Design
- Icon (colored, 16-20px) + Name (14px) + Star toggle (right, gold when favorited)
---
## Page 5: Terminal (`/terminal`)
> Embedded SSH terminal — no hero banner, no cards grid
### Layout: Full-height terminal viewport
### Tab Bar (top, 40px)
- Tabs: host name + colored dot (🟢 connected, ⚪ disconnected)
- Active tab: gold bottom border
- "+" button: open new connection
- Quick-connect dropdown with saved hosts
**Saved Hosts:**
| Label | Connection |
|-------|-----------|
| Pre (Audio) | ssh pre |
| Proxmox | ssh mtr |
| Linode (NPM) | ssh linode |
| RackNerd 1 | ssh racknerd1 |
| RackNerd 3 (Forge) | ssh racknerd3 |
| Studio (DevOps) | ssh studio |
### Terminal Viewport
- Font: JetBrains Mono / Fira Code, 14px
- Prompt: Gold | Commands: Warm white | Output: Secondary gray | Errors: Red | Dirs: Teal
- Cursor: Gold block, blinking
- Scrollback: 5000 lines
### Status Bar (bottom, 28px)
- 🟢 Connected | Host: `pre` | Session: 12m 34s | Shell: bash
- Right: Split pane | Fullscreen | Disconnect
### Implementation
- xterm.js for browser terminal
- Node.js WebSocket-to-SSH bridge on racknerd1
---
## Page 6: Settings (`/settings`)
> User preferences and system configuration — no hero banner
### Layout: Settings Nav (200px left) + Content (right, scrollable)
### Nav Sections
1. Profile | 2. Appearance | 3. Integrations | 4. Notifications | 5. Data & Backup | 6. About
### Profile
- Avatar (64px, gold ring) + Display Name + Role (badge) + Email + Timezone
- "Save Changes" button (gold)
### Appearance
- Theme: Dark/Light toggle
- Accent: Color swatches (Gold active, Teal, Purple, Blue, Green, Red)
- Font Size: 12-16px slider
- Sidebar: Expanded/Collapsed toggle
- Animations: On/Off
- Card Border Radius: 4-16px slider
### Integrations
| Service | Status | Config Fields |
|---------|--------|---------------|
| Proxmox | 🟢 | Host URL, API Token |
| Docker | 🟢 | Socket/remote URL |
| NetBird | 🟢 | API key |
| Cloudflare | 🟢 | API token, Zone ID |
| AWS | 🟢 | Access Key, Secret (masked), Region |
| Uptime Kuma | ⚪ | URL, API key |
| Weather API | 🟢 | Location, Units |
- Masked secrets with eye toggle, "Test Connection" per card
### Notifications
- Enable toggle | Threshold dropdown (All/Critical/Warning+) | Email toggle | Browser push | Sound + volume
### Data & Backup
- Export/Import Bookmarks (JSON) | Export Settings | Reset to Defaults (danger) | Clear Cache
### About
- App: ArchNest Dashboard v1.0.0
- Author: Samuel James
- Repo: github.com/SamuelSJames/archnest
- Stack: React 19, Vite, TypeScript
- License: MIT

View file

@ -1,225 +1,283 @@
# ArchNest — Design Decisions & Lessons Learned
# ArchNest — Design Decisions & Page Reference
> This file captures all visual/UX decisions made during Glance page development.
> Apply these consistently to ALL future pages to avoid repeated iteration.
> Living reference for visual/UX conventions and what's actually built on each page.
> Apply the Global Rules consistently to any new page. The Page Notes section
> describes the **real, deployed** implementation — not a mockup. If you change a
> page's layout or data source, update its section here in the same PR.
>
> This file replaces the old `archnest-blueprint.md` (original 6-page mockup
> pitch, since deleted — superseded by the real 11-page app below) and
> `glance.md` (original Glance spec with fictional config files like
> `systems.config`/`infra.config` that were never built — also deleted). Anything
> from those files still true (color palette, typography, card style, dropdown
> menu shape) has been folded in below.
---
## Global Rules (Apply to Every Page)
## Global Rules (apply to every page)
### Sidebar
- **Expanded width**: 200px (matches mockup proportions — needs room for labels)
- **Collapsed width**: 64px (icon only)
- **User can manually collapse/expand** via toggle button (not just responsive)
- **Main content margin-left** must match sidebar width exactly
- Expanded width: 200px. Collapsed width: 64px (icons only).
- User can manually collapse/expand via a toggle button (not just responsive breakpoints).
- Main content `margin-left` must match the sidebar width exactly.
- Bottom of sidebar: live "System Status" widget — green dot + "All Systems
Operational" or "X Issue(s) Detected", driven by polling integration status
(not the fictional ping-sweep config described in the old spec).
### Page Title (Top Bar)
- **Color**: Gold (#C8A434) — NOT white. Use inline `style={{ color: '#C8A434' }}` if Tailwind class doesn't apply
- **Font**: 18px, bold, uppercase, tracking-wide
- **No border on top bar** — blends into the page background
- Color: gold `#C8A434` — not white. Use inline `style={{ color: '#C8A434' }}`
if a Tailwind class doesn't apply.
- Font: 18px, bold, uppercase, tracking-wide.
- No border on the top bar — it blends into the page background.
- Pages with a `pageSubtitles` entry (currently only BookNest) render a larger
28px title + subtitle line instead, and the top bar grows from 56px → 72px —
see `TopBar.tsx`'s `pageSubtitles` map and `App.tsx`'s `topBarHeight` lookup,
which must be kept in sync or the layout clips/gaps.
### Colors — Use Inline Styles When Tailwind Fails
- Tailwind v4 `@theme` custom colors (text-gold, bg-card, etc.) may not always apply
- If a color isn't rendering correctly, fall back to inline `style={{ color: '#C8A434' }}`
- Always verify visually after changes
### Colors
| Role | Value |
|------|-------|
| Background (page) | `#0D0E10` |
| Background (cards) | `#141518` |
| Background (sidebar) | `#0A0B0D` |
| Border (cards) | `#1E2025` |
| Border/accent (hover/active) | `#C8A434` (gold) |
| Success | `#2ECC71` |
| Warning | `#E67E22` |
| Danger | `#E74C3C` |
| Text (primary) | `#E8E6E0` |
| Text (secondary) | `#7A7D85` |
Tailwind v4 `@theme` custom colors (`text-gold`, `bg-card`, etc.) don't always
apply reliably — fall back to inline `style={{ color: '#C8A434' }}` when a
color isn't rendering, and verify visually after changes.
### Typography
- Card titles: 10-11px, uppercase, tracking-[1.5px], secondary color, font-medium.
- Large numbers: 24-28px, bold, primary color.
- Subtitles/labels: 10-11px, secondary color.
- Body text in lists: 13px, primary color.
- Timestamps: 11px, secondary color.
### Card Style
- Border radius: 12px. Background `#141518`. Border 1px solid `#1E2025`.
- Padding: 16-24px depending on density. No shadows (flat design).
- Hover: border transitions to gold, 0.2s ease.
### Content Alignment
- **All rows must share the same horizontal padding** (`px-6` applied once at the parent container level)
- **Do NOT** use different padding for different rows — this causes misalignment
- The hero banner, status cards, middle row, and bottom row must all line up left and right edges
### Hero Banner + KPI Overlap
- Banner height: 200px
- Status cards overlap via negative margin: `-mt-12`
- Banner image: `object-cover` with `object-position: center 25%` (show the top/skyline, not center)
- Cards use `backdrop-blur-sm` and `bg-card/95` for glass effect over the banner
### KPI Card Sizing
- KPI 1 (System Status) and KPI 4 (Network): **wider**`1.3fr`
- KPI 2 (Infrastructure) and KPI 3 (Security): **standard**`1fr`
- Grid: `grid-cols-[1.3fr_1fr_1fr_1.3fr]`
- Cards have compact padding: `p-4` (not p-5 or p-6)
### No Footer
- The mockup does NOT have a footer/status bar
- Do not add one unless explicitly requested
### Target Display
- Primary design target: **16-inch screen / 1920px width**
- Lots of horizontal space available — don't constrain content width unnecessarily
- Design should feel spacious, not cramped
### Typography Sizes (smaller than default)
- Card titles: 10-11px, uppercase, tracking-[1.5px], secondary color, font-medium
- Large numbers: 24-28px, bold, primary color
- Subtitles/labels: 10-11px, secondary color
- Body text in lists: 13px, primary color
- Timestamps: 11px, secondary color
- Breakdowns: 9-10px, secondary color
- All rows in a page share the same horizontal padding (`px-6` at the parent
container level) so the hero banner, status cards, and content rows line up
left/right.
### Animations
- Card hover: border → gold, 0.2s ease
- Progress ring: animates from 0 to value in 1s
- Sparklines: draw animation 1s
- Progress bars: fill animation 0.8s
- Card hover: border → gold, 0.2s ease.
- Progress ring / sparkline: animate from 0 on load, ~1s.
- Progress bars: fill animation ~0.8s.
### Icons
- Source: Lucide React (imported per component, tree-shaken)
- Size: 14-18px depending on context
- Color: gold for active/accent, text-secondary for inactive
- Gold glow on active sidebar items: `shadow-[0_0_6px_rgba(200,164,52,0.5)]`
- Lucide React, 14-18px depending on context. Gold for active/accent, secondary
color for inactive. Gold glow on active sidebar items:
`shadow-[0_0_6px_rgba(200,164,52,0.5)]`.
- **Gotcha**: the installed lucide-react version's TypeScript types list some
brand/wordmark icons (`Github`, `Gitlab`, `Linkedin`, `Youtube`) that aren't
actually exported at runtime — `tsc --noEmit` stays clean while the page
renders blank with a runtime `SyntaxError` only visible in the Vite dev log.
Verify icon names against the package's actual exports before importing
anything brand-flavored.
### No Footer
- No page has a fixed footer/status bar. Don't add one unless explicitly requested.
### Target Display
- Primary design target: 16-inch / 1920px-wide screen. Don't constrain content
width unnecessarily — design should feel spacious.
### User Avatar & Dropdown (TopBar, every page)
- 36px circle, gold border + glow, shows uploaded avatar image or initials.
- Adjacent: display name + "Administrator" role label, chevron (rotates on open).
- Dropdown menu: header (name + email) → **Profile** (`/settings?tab=profile`)
**Appearance** (`/settings?tab=appearance`) → **Security**
(`/settings?tab=security`) → **Help & Support** (`/help`) → divider →
**Sign Out** (red, danger styling). See `TopBar.tsx`.
---
## Page-Specific Notes
## Page Notes (what's actually built, page by page)
### Glance Page
- No footer
- Status cards overlap hero banner
- Middle row: 3 equal-ish columns (30/40/30)
- Bottom row: 2 columns (65/35)
- Network Traffic card has its own background image at low opacity
- User avatar dropdown has: Profile, Appearance, Security, Help & Support, Sign Out
All pages below consume real backend data via `src/lib/api.ts` — **zero mock
data anywhere in the app.** Where a section says "real backend data," it means
an actual SQL-backed or live-polled endpoint, not a config file or static array.
### Infrastructure Page
- Hero banner rendered at the **App.tsx layout level** (not per-page), so it can extend
behind the sticky TopBar — conditional via `showHero = location.pathname === '/infrastructure'`.
TopBar and the search input are transparent on hero routes so the banner shows through.
- Hero image: `object-position: center 5%` to reveal the full arch + sky; faded out via
`linear-gradient` mask (vertical) + a `radial-gradient(ellipse 70% 100% at center, ...)`
overlay (sides/corners) — borderless, blends into page background.
- Sub-tabs trimmed to **Overview only** (Compute → Tags are future work, not built yet).
- Status cards: `rgba(10,10,12,0.5)` background (more transparent than other pages),
content centered (`justify-content/alignItems: center`) with a fixed row height (110px)
so there's breathing room instead of empty space below left-aligned content.
- Middle row (`grid-cols-[1fr_1.6fr]`): **Resource Distribution** (donut) and **Node Status**
(server tile grid). Both use the `/blank-kpi-bg.png` background art with a `cardDim`
(semi-transparent dark overlay) + `cardVignette` (radial-gradient `closest-side` blend)
combo — keeps the background pattern visible but subdued, with borders blended rather
than hard-edged. Card titles are rendered as our own text, NOT baked into the image
(baked-in labels got covered by the dim overlay).
- **Node Status** card: originally a world-map-style region dot plot, replaced with a
4-column tile grid (one tile per server, colored status dot + name) — a world map
didn't make sense for a small/single-site infra. Reuse this "small-scale" reasoning
for any future map-like cards.
- Bottom row (`grid-cols-[1.4fr_1fr_1fr]`): Resource Trend / Cost Breakdown / Recent
Activity — **left plain/regular**, no dim/vignette blending (explicit user preference,
only the middle row gets the hero-style blend). Resource Trend uses the
`/archnest-network-traffic-bg.png` background (plain, no dim/vignette) with 4 trend
lines: blue `#3B82F6` (compute), orange `#E67E22` (storage), green `#2ECC71` (database),
brown `#8B5E3C` (network).
- `cardVignette` radial-gradient must use the `closest-side` keyword (not a fixed `%`)
— otherwise straight edges of the card don't reach full opacity and a hard border line
remains visible (only corners fade correctly with a fixed percentage).
### Glance (`/`)
- Hero banner (image with radial-gradient fade mask) + KPI cards overlapping
the bottom edge via negative margin.
- 4 status cards: **System Status** (% of integrations reachable),
**Infrastructure** (resource count + health breakdown from
`api.listResources()`), **Integrations** (connected/total from
`api.listIntegrations()`), **Bookmarks** (total + favorites from
`api.listBookmarks()`).
- Middle row (3 columns): Resource Overview (top 6 resources + status),
Recent Activity (5 latest from `api.listEvents(5)`), problem/critical
resources widget.
- Bottom row: Connected Integrations grid + 4 Shortcuts buttons (to Settings,
BookNest, Infrastructure).
- No footer. Hides the hero gracefully if the banner image fails to load.
- There is **no** `systems.config`/`infra.config`/ping-sweep/fail2ban
machinery — that was speculative spec from before the backend existed.
Health figures are derived directly from each integration adapter's
`testConnection()` result, polled by the existing `/api/integrations` list.
### BookNest Page
- Hero banner reused at the App.tsx layout level (`showHero` now includes `/booknest`),
with page-specific tuning via small lookup maps in `App.tsx` keyed on `location.pathname`:
`heroPaddingTop` (how far content sits below the hero top) and `heroObjectPosition`
(horizontal/vertical crop of the arch image) — `70px` / `54% 8%` for BookNest vs.
`72px` / `center 5%` for Infrastructure. Extend these maps rather than hardcoding a
single value when a future page needs different hero framing.
- **Large hero title + subtitle**: unlike other pages, BookNest's TopBar title is NOT the
small 18px uppercase label — it's rendered at 28px with a subtitle line ("Your Digital
Library") underneath, driven by a new `pageSubtitles` map in `TopBar.tsx`. When a page
has a subtitle, the header height grows from 56px → 72px (`TopBar.tsx`), and `App.tsx`'s
`topBarHeight` lookup keeps the content section's `calc(100vh - Npx)` in sync — both
must be updated together or the layout will clip/gap.
- **Stats row lives directly under the hero subtitle** (Links / Categories / Favorites),
not in its own separate bar — matches the blueprint's hero-header block grouping.
- **"Quick Access" section label** added above the 5 quick-access category cards (gold,
same `sectionTitle` style) — the row is intentionally pulled up via a small negative
hero-padding tune so it slightly overlaps the bottom edge of the hero, like the blueprint.
- **"+ Add Bookmark" button**: same gold-fill button style as Infrastructure's "+ Add
Resource", placed inline next to the "Quick Access" label rather than the page-stats row.
- **Right sidebar spans both grid rows** (`gridRow: '1 / span 2'` in a `gridTemplateRows:
'auto 1fr'` grid) so the Favorites card can rise up near the hero while the main column's
page-stats row stays in row 1 of column 1 only — keeps the two from overlapping/clipping.
Negative margins were tried first and discarded: content pushed above the scroll
container's natural top edge gets clipped by `overflow-y-auto`, so prefer reshaping the
grid/flow over negative-margin hacks when something needs to "reach upward."
- **Sidebar cards stretch to match the main column's full height** so the last card's
(Category Breakdown) bottom border lines up with the bottom of the bookmark groups grid:
sidebar wrapper is `display:flex; flex-direction:column; height:100%` (grid's default
`align-items: stretch` already gives it the matching height), and each card uses
`flex: 1 0 auto` (Favorites gets `flex: 1.4 0 auto` to read as visibly taller, per
explicit request) so they share the leftover vertical space instead of all packing tight
at content height.
- lucide-react gotcha (see Global Rules candidate): the installed version does **not**
export brand/wordmark icons (`Github`, `Gitlab`, `Linkedin`, `Youtube`) even though
TypeScript's type declarations list them — `tsc --noEmit` stays clean while the page
renders blank with a runtime `SyntaxError` only visible in the Vite dev log. Verify
icon names against `Object.keys(require('lucide-react'))` before importing anything
brand-flavored; substitutes used here: `GitBranch`/`GitFork` (GitHub/GitLab/Gitea),
`SquarePlay` (YouTube), `Briefcase` (LinkedIn Learning).
### Infrastructure (`/infrastructure`)
- Hero banner at the `App.tsx` layout level (`showHero` includes this route),
extending behind the sticky, transparent-on-hero-routes TopBar.
- Sub-tabs: **Overview** (only enabled tab) and **Network** (disabled,
"Coming soon" — intentional, leave alone unless asked).
- 4 status cards: Total Resources, Healthy, Warnings, Critical — from
`api.listResources()`.
- Middle row: Resource Distribution (donut by integration type) + Node Status
(4-col tile grid, one tile per resource — replaced an earlier world-map
concept since a map doesn't make sense for a small/single-site setup).
- Bottom row: Integration Health list + Recent Activity (`api.listEvents(4)`).
- Card backgrounds use a `cardDim` + `cardVignette` (radial-gradient,
`closest-side` keyword — a fixed `%` leaves a visible hard edge on straight
sides) combo on the middle row only, per explicit visual preference; bottom
row stays plain/regular.
### Settings Page
- No mockup image existed for this page — built directly from the blueprint's Page 6
spec rather than iterating against a screenshot.
- Layout: fixed-width (200px) left nav listing the 6 sections (Profile, Appearance,
Integrations, Notifications, Data & Backup, About) + a scrollable content panel on
the right showing the active section. No hero banner (not in the blueprint spec for
this page, and a settings page doesn't need one).
- Active section is local component state (a string id) mapped through a
`sectionComponents` record to the corresponding section-renderer function — simplest
approach for a page with no routing/deep-linking requirement.
- Shared style helpers (`cardBase`, `sectionTitle`, `labelStyle`, `inputStyle`) plus two
small reusable components defined in the same file: `Toggle` (on/off pill switch) and
`GoldButton` (gold-filled primary / danger-outline variant) — kept local to
`Settings.tsx` rather than extracted, since no other page needs them yet.
- **Integrations** cards mask secret fields (API keys/tokens) behind dots with an eye
icon to reveal/hide, plus a "Test Connection" button per card — matches the blueprint's
explicit "masked secrets with eye toggle" instruction.
- **Avatar upload** (Profile section): the avatar circle is clickable and opens a hidden
`<input type="file" accept="image/*">` via a `useRef` + `.click()` call rather than a
visible file input — keeps the round avatar as the only visible control. On change,
`FileReader.readAsDataURL` converts the selected image to a base64 data URL stored in
component state, which becomes the circle's `backgroundImage` (cover-fit), replacing
the "AO" initials fallback. A hover-only camera-icon overlay (Tailwind `group` /
`group-hover:opacity-100`) signals the circle is clickable without cluttering the
default state. This is a frontend-only preview (no backend upload endpoint exists yet).
### BookNest (`/booknest`)
- Hero banner reused at layout level with page-specific tuning
(`heroPaddingTop`/`heroObjectPosition` lookup maps in `App.tsx`).
- Large 28px title + "Your Digital Library" subtitle (the one page using
`pageSubtitles`), header grows to 72px.
- Page stats row (Links / Categories / Favorites) + "Delete All" bulk action.
- Main column: Quick Access (top 5 categories) + bookmark groups grid (4 cols,
full CRUD with hover edit/delete/star).
- Right sidebar (spans both grid rows via `gridRow: '1 / span 2'`): Favorites,
Recently Added (5 newest), Link Health donut, Category Breakdown donut.
- Add/edit bookmark modal supports auto-detected favicons via
`guessServiceIconUrl()` or manual icon entry.
- All data from `api.listBookmarks()` / `api.listBookmarkCategories()` with
real create/update/delete calls — no local-only state.
### Terminal (`/terminal`)
- Left sidebar: SSH hosts (integrations of type `ssh`), click to connect.
- Tab bar + 1/2/4-pane split layout, each pane an independent xterm instance.
- Preferences panel (theme: ArchNest Dark/Matrix/Solarized/Midnight Blue, font
size 11-16px, font family) — stored in `localStorage`
(`archnest-terminal-prefs`), not synced server-side.
- WebSocket to `/api/terminal`: `connect`/`input`/`resize`/`list_tmux`/`disconnect`
messages; supports attaching to an existing tmux session or starting a new one.
- Certificate auth (OPKSSH) shells out to the system `ssh` binary under a pty
rather than using the JS SSH client.
- Session logging to `ARCHNEST_SESSION_LOG_DIR` is backend-supported but has
no dedicated viewer UI yet.
### Tunnels (`/tunnels`)
- List + create form for local/remote/dynamic (SOCKS5) SSH tunnels.
- Create form fields conditionally show/hide based on mode (no endpoint
host/port fields for dynamic mode).
- Status color map: stopped `#7A7D85`, connecting `#C8A434`, retrying
`#E0A030`, connected `#2ECC71`, error `#E74C3C`. Polls every 3s.
- Backed by `api.listTunnels()/createTunnel()/connectTunnel()/disconnectTunnel()/deleteTunnel()`.
### Files (`/files`)
- SSH host selector + breadcrumb-navigable SFTP directory browser.
- File editor modal: plain textarea, files up to 50MB (anything larger is
download-only). Heuristic binary detection (null bytes/control chars) decides
base64 vs. text encoding.
- Inline directory creation, rename, delete, upload, download.
- Host-to-host transfer modal: pick source file + destination host/path,
copy-or-move toggle, live progress bar fed by `api.getTransfer(id)` polling.
### Containers (`/containers`)
- Docker host selector (integrations of type `docker`) + container list.
- Per-container state badge (running/paused/exited/dead) with context-aware
action buttons (Start/Stop/Restart/Pause/Unpause/Remove) — buttons disable
themselves for invalid transitions (e.g. can't pause a stopped container).
- Live CPU/memory stats polled only for running containers.
- Logs modal (configurable tail count) and an exec modal (interactive shell via
WebSocket to `/api/docker/exec`).
### Remote Desktop (`/remote-desktop`)
- Left sidebar: hosts from integrations of type `remote_desktop`.
- Main area is a Guacamole canvas tunneled over WebSocket to `/api/guacamole`,
proxying to the `guacd` sidecar container (RDP/VNC/Telnet).
- Requires `ARCHNEST_GUAC_CRYPT_KEY` — sessions fail without it (the backend
warns on startup if it's missing).
### Host Metrics (`/host-metrics`)
- Left sidebar: SSH hosts. Selecting one starts a 5-second polling loop against
`api.getHostMetrics(integrationId)`, cleared on deselect.
- Cards: CPU/Memory/Disk gauges (color thresholds: green <75%, yellow 75-90%,
red ≥90%) + Uptime, then Network Interfaces, Processes (top 10),
Listening Ports, Firewall Rules (UFW/iptables), Login Activity.
- Backed by 10 sequential SSH-exec collectors under `backend/src/ssh/metrics/`
(cpu, memory, disk, uptime, network, system, processes, ports, firewall,
login-stats) — sequential on purpose, to avoid exceeding OpenSSH's
`MaxSessions` limit per host.
### Settings (`/settings`)
- Fixed 200px left nav, 7 sections: Profile, Appearance, Security,
Integrations, Notifications, Data & Backup, About. URL-deep-linkable via
`?tab=` (`useSearchParams`) — use this pattern for any future section.
- **Profile**: display name, email, avatar upload (`FileReader.readAsDataURL`
→ base64 data URL, persisted via `api.updateMe()` — this one *is* a real
backend round-trip, unlike the rest of the page below).
- **Appearance**: accent color swatches — **local-state only, doesn't persist
or apply anywhere** (see Known Stubs in `HANDOFF.md`).
- **Security**: password-change form + 2FA toggle — currently placeholder UI
pending the Phase 2 auth work in `HANDOFF.md`.
- **Integrations**: one card per type (Proxmox/Docker/NetBird/Cloudflare/AWS/
Uptime Kuma/Weather/Remote Desktop/SSH), each with type-specific fields
(secrets masked, eye-toggle to reveal, "Test Connection" button). Real CRUD
via `api.createIntegration()/updateIntegration()/deleteIntegration()/testIntegration()`.
- **Notifications**: toggles — placeholder, no delivery mechanism (see
Known Stubs in `HANDOFF.md`).
- **Data & Backup**: full JSON export/import of integrations + secrets +
bookmarks + tunnels via `backend/src/routes/data.ts` — this is the one
endpoint that intentionally round-trips decrypted secrets, by design, for
backup portability.
- **About**: static version/license/links info.
### Help (`/help`)
- Fully static — no backend calls. 11 guide cards (one per real page) with a
short description and tips. Update this page whenever a new page ships.
### Login (`/login`) / Enrollment (`/enrollment`)
- `Login.tsx`: username/password form → `api.login()``AuthContext`.
- `Enrollment.tsx`: two-step first-run flow — (1) create the admin account via
`api.setup()`, gated to only work while the `users` table is empty; (2)
optional "Connect Your Services" integration onboarding grid (skippable,
same integration form as Settings). Routed to based on
`GET /api/system/setup-status`.
---
## Backend (added once frontend reached "good enough" state)
## Backend Architecture (current, not aspirational)
- New `backend/` package (separate `package.json`/`tsconfig.json`, own `node_modules`,
own Dockerfile) — Fastify + TypeScript, `better-sqlite3` for storage, deployed as a
second container alongside the existing frontend container (`docker-compose.yml` now
has `archnest` + `archnest-backend`, with a named volume for the SQLite file).
- Auth: single-user, JWT-based (`@fastify/jwt`). `POST /api/setup` creates the one user
and only succeeds while the `users` table is empty — this is what powers the
first-run enrollment page. `GET /api/system/setup-status` tells the frontend whether
to show enrollment/login or the normal app.
- Integration credentials are split across two tables: `integrations` (type, name,
status, non-secret `config_json`) and `secrets` (per-key AES-256-GCM-encrypted
values, key derived from the `ARCHNEST_SECRET_KEY` env var) — keeps secrets out of any
generic "list integrations" query/response by construction, not by remembering to
redact a field.
- Each integration type has an adapter module under `backend/src/integrations/`
exporting `testConnection(config, secrets)`; `registry.ts` maps `IntegrationType`
adapter. Only `uptime_kuma` and `docker` are real so far (simple HTTP health checks);
the rest return a "not yet implemented" result until built out — this lets the
Integrations UI and `POST /api/integrations/:id/test` endpoint work end-to-end for
every type without blocking on every adapter being finished.
- Vite dev server proxies `/api``http://localhost:4000` (`vite.config.ts`) so the
frontend can call relative `/api/...` paths in both dev and prod (prod routes `/api`
to the backend container via NPM).
- Next steps (not yet done): build the enrollment/login frontend pages, strip the mock
arrays out of Glance/Infrastructure/BookNest/Settings and replace with calls to this
API, add bookmark category seeding.
- `backend/` — Fastify 5 + TypeScript (ESM, `tsx` dev / `tsc -b` build),
`better-sqlite3` for storage, deployed as its own Docker container alongside
the frontend and a `guacd` sidecar.
- Auth: single-user-schema JWT (`@fastify/jwt`) today — see `HANDOFF.md` for
the multi-user/SSO roadmap (Phases 2-4, not yet built).
- Integration credentials split across `integrations` (non-secret config) and
`secrets` (AES-256-GCM-encrypted, keyed by `ARCHNEST_SECRET_KEY`) tables —
secrets never appear in a generic "list integrations" response by
construction, not by remembering to redact a field.
- Every integration type has an adapter in `backend/src/integrations/`
implementing `testConnection()` (required) and `listResources()` (optional);
`registry.ts` maps `IntegrationType` → adapter. All 9 types
(proxmox/docker/netbird/cloudflare/aws/uptime_kuma/weather/ssh/remote_desktop)
are real, working adapters — none are stubs anymore.
- `backend/src/ssh/` is the shared SSH transport layer powering Terminal,
Files, Tunnels, Transfers, and Host Metrics: `connect.ts` (jump-host
chaining, host-key verification, cert auth), `sftp.ts` (ephemeral SFTP),
`transfer.ts` (host-to-host streamed copy/move with progress + cancel), and
`metrics/` (the 10 collectors listed above).
- Vite dev server proxies `/api``http://localhost:4000`; prod routes `/api`
to the backend container via Nginx Proxy Manager.
## Future Integration Notes
### Live Provider Data (AWS, Linode, etc.)
- All KPI/status card data (resource counts, health, pricing, budgets, cost breakdowns,
utilization, regions/map data) is currently mocked/static.
- The Infrastructure page (and likely Glance) should eventually integrate with real
cloud provider APIs — AWS, Linode, or any other VPC/cloud provider — via user-supplied
API keys, to pull live data such as:
- Resource inventory/counts and health status
- Pricing and budget/cost data (replacing the static Cost Breakdown numbers)
- Resource utilization metrics
- Region/datacenter info for the Infrastructure Map
- Design the data layer so it's provider-agnostic (a common interface/adapter per
provider) since users may connect more than one provider's API key.
- AWS/Cloudflare/NetBird/Proxmox/Uptime Kuma adapters are real but currently
surface basic resource inventory + health only — deeper cost/pricing/budget
data (mentioned in the old blueprint) is not implemented and not currently
planned; revisit only if explicitly requested.

356
glance.md
View file

@ -1,356 +0,0 @@
# Glance Page — Detailed Specification
> Purpose: The Glance page is the operational heartbeat of ArchNest. It provides an at-a-glance view of system health, resource utilization, security posture, and network connectivity across your homelab infrastructure. Every element answers a simple question: "Is everything okay right now?"
---
## Layout Structure
The Glance page uses this vertical stack (top to bottom):
1. **Top Bar** (sticky, 56px)
2. **Hero Banner** (200px, rounded, with KPI cards overlapping the bottom ~25%)
3. **Middle Row** (3 columns: 30% | 40% | 30%)
4. **Bottom Row** (2 columns: 65% | 35%)
**No footer.** The page scrolls naturally without a fixed status bar at the bottom.
---
## Top Bar
**Display:**
- Height: 56px, sticky at top, z-index above all content
- Background: Page color (#0D0E10), no border
- Left: Page title "GLANCE" (18px, bold, uppercase, primary text with subtle gold drop-shadow glow)
- Center-right: Search bar (260px, rounded-full, placeholder "Search resources...", card background)
- Right: Notification bell (with red badge count) + User avatar + dropdown trigger
### User Avatar & Dropdown Menu
**Avatar Display:**
- 32px circle with 2px gold border and subtle gold glow
- Shows initials "AO" in gold
- Adjacent: "ArchNest Ops" (12px, primary) + "Administrator" (9px, secondary)
- Chevron icon (rotates on open)
**Dropdown Menu (on click):**
- Position: Below avatar, aligned right
- Background: Card color with border, rounded-xl, shadow
- Header section: User name + email
- Menu items:
- **Profile** — navigates to Settings > Profile section
- **Appearance** — navigates to Settings > Appearance section
- **Security** — navigates to Settings > Security/Integrations section
- **Help & Support** — opens documentation/wiki link
- Divider
- **Sign Out** — logs out of session (red text, danger action)
---
## Hero Banner
**Display:**
- Full width of content area, 200px height, 12px border radius, overflow hidden
- Image: `archnest-hero-banner.png` from `/public` (local) or CDN
- Image positioning: `object-cover` with `object-position: center 30%` — prioritizes showing the upper portion (skyline/arch) rather than center-cropping
- The bottom ~25% of the banner is overlapped by the KPI status cards (negative margin)
- If image fails to load: shows card background color (#141518), no broken icon
---
## Top Row — Status KPI Cards (4 cards)
### Card Grid Layout
**IMPORTANT — Asymmetric widths:**
- KPI 1 (System Status): **1.3fr** — wider, has progress ring + sparkline
- KPI 2 (Infrastructure): **1fr** — standard width
- KPI 3 (Security): **1fr** — standard width
- KPI 4 (Network): **1.3fr** — wider, has sparkline chart
Grid: `grid-cols-[1.3fr_1fr_1fr_1.3fr]` with 12px gap.
**Card styling (all 4):**
- Background: `#141518` at 95% opacity with backdrop-blur (glass effect over banner)
- Border: 1px solid #1E2025, 12px radius
- Padding: 16px
- Hover: border transitions to gold (0.2s)
---
### 1. System Status
**What it represents:** Overall system health — a composite "green light" that confirms all critical services are reachable and all local packages/security updates are current.
**How it gets its data:**
- **Ping sweep**: Every 5 minutes, the backend pings all endpoints defined in a `systems.config` file (IP addresses of LXC containers, VMs, physical hosts, and key services). If all respond, health = 100%.
- **Package currency check**: Queries `apt` (or equivalent) on monitored hosts for pending security updates. Any pending security update reduces the percentage.
- **Calculation**: `(reachable_hosts / total_hosts) * weight_A + (up_to_date_hosts / total_hosts) * weight_B`. Default weights: 70% reachability, 30% package currency.
**Display:**
- Card title: "SYSTEM STATUS" (10px, uppercase, tracking 1.5px, secondary color, font-medium)
- Layout: Title top, then flex row with text left and ring right
- Left content:
- "All Systems" (13px, bold, primary)
- "Operational" (13px, bold, gold, italic)
- Right content: Progress Ring (44px diameter, 3px stroke, gold on dark track)
- Divider: 1px border-top, border/60 opacity
- Below divider: Sparkline (gold line chart, 20px height, no axes, showing last 12 check results)
- Footer text: "Last checked: 2m ago" (9px, secondary)
**Thresholds:**
- 100%: "All Systems Operational" (gold text)
- 8099%: "Degraded" (orange text)
- Below 80%: "Critical" (red text)
---
### 2. Infrastructure
**What it represents:** Total count of managed resources (LXC containers, VMs, Docker containers, bare-metal hosts) and their operational state.
**How it gets its data:**
- **Config-driven**: Reads from `infra.config` which contains API endpoints, SSH keys, and connection details for each resource (Proxmox API for LXC/VMs, Docker socket/API for containers, SSH for bare-metal).
- **Status polling**: Every 5 minutes, queries each resource's API or SSH to determine if it's running, stopped, or unreachable.
- **Disk usage check**: Pulls primary disk utilization from each resource. Any resource exceeding 70% disk usage triggers a warning signal.
**Display:**
- Card title: "INFRASTRUCTURE" (10px, uppercase, tracking 1.5px, secondary color)
- Icon + number row: Server icon (16px, gold) + "24" (24px, bold, primary)
- Subtitle: "Total Resources" (10px, secondary)
- Divider
- Breakdown row (9px): green dot + "24 Running" | yellow dot + "0 Warning" | red dot + "0 Critical"
**Signal logic:**
- 🟢 Running: Resource is responsive and disk < 70%
- 🟡 Warning: Resource is responsive but disk ≥ 70%, or resource response is slow (>2s)
- 🔴 Critical: Resource is unreachable or disk ≥ 90%
---
### 3. Security
**What it represents:** Active security alerts — failed intrusion attempts, brute-force attacks detected by fail2ban, and outdated security packages.
**How it gets its data:**
- **Fail2ban logs**: Queries fail2ban on each monitored host for currently banned IPs and recent ban events (last 24h).
- **Auth log monitoring**: Parses `/var/log/auth.log` (or equivalent) for failed login attempts exceeding a threshold (e.g., 5+ failures from same IP in 10 minutes).
- **Security package check**: Counts hosts with pending security-specific updates (`apt list --upgradable` filtered to security repo).
- **Alert count**: Sum of active fail2ban bans + hosts with outdated security packages.
**Display:**
- Card title: "SECURITY" (10px, uppercase, tracking 1.5px, secondary color)
- Icon + number row: Shield icon (16px, gold) + "2" (24px, bold, primary)
- Subtitle: "Active Alerts" (10px, secondary)
- Divider
- Breakdown row (9px): green dot + "2 Low" | yellow dot + "0 Medium" | red dot + "0 High"
**Severity logic:**
- Low (green): Informational — single failed login attempt, package update available
- Medium (yellow): Multiple failed attempts from same IP, security package >7 days overdue
- High (red): Active brute-force attack (10+ attempts in 5 min), critical vulnerability unpatched >14 days
---
### 4. Network
**What it represents:** Local network uptime — confirms internet connectivity and DNS resolution are functioning.
**How it gets its data:**
- **Ping probes**: Every 60 seconds, pings multiple resolvers (e.g., 1.1.1.1, 8.8.8.8, and one internal DNS) from the ArchNest host.
- **Uptime calculation**: Tracks successful/failed pings over a rolling 24-hour window. Uptime % = (successful_pings / total_pings) * 100.
- **Sparkline data**: Stores the last 24 data points (one per hour) for the mini trend chart.
**Display:**
- Card title: "NETWORK" (10px, uppercase, tracking 1.5px, secondary color)
- Icon + number row: Network icon (16px, gold) + "98.7%" (24px, bold, primary)
- Subtitle: "Network Uptime" (10px, secondary)
- Divider
- Below divider: Area sparkline chart (gold gradient fill, 24px height, no axes, 24 data points representing hourly uptime)
**Thresholds:**
- ≥99%: Healthy (no indicator needed)
- 9599%: Minor instability (orange sparkline highlight)
- <95%: Degraded (red sparkline highlight, triggers alert)
---
## Middle Row — Detail Panels (3 columns: 30% | 40% | 30%)
### 5. Resource Overview (left, 30%)
**What it represents:** Top 5 resource utilization metrics across your infrastructure — a quick view of where capacity is being consumed.
**How it gets its data:**
- Pulls from the same infrastructure polling that feeds the Infrastructure KPI
- **Compute**: Running LXC/VM count vs total allocated slots (from infra.config)
- **Storage**: Sum of used disk across all storage pools vs total capacity (e.g., Proxmox storage API, `df` on hosts)
- **Database**: Active database instances vs provisioned (PostgreSQL/MariaDB connection count or instance count)
- **Network**: Same uptime % from the Network KPI (displayed as a bar for consistency)
- **Containers**: Running Docker containers vs total defined in docker-compose or container configs
**Display:**
- Card title: "RESOURCE OVERVIEW" (uppercase, secondary color)
- Close button (X) in top-right corner
- 5 rows, each containing:
- Icon (category-specific, 16px, secondary color)
- Label (e.g., "Compute", "Storage") — 13px, primary color
- Progress bar (gold fill on dark track, rounded ends)
- Value text (e.g., "18 / 24" or "12.4 / 20 TB") — 12px, secondary color
**Bar color logic:**
- 069%: Gold (#C8A434)
- 7089%: Warning orange (#E67E22)
- 90100%: Danger red (#E74C3C)
---
### 6. Recent Activity (center, 40%)
**What it represents:** A chronological feed of the most recent system events — gives context on what just happened across the infrastructure.
**How it gets its data:**
- **Event aggregation**: Collects events from multiple sources:
- Backup completion notifications (from cron jobs or backup tools like restic/borgbackup)
- Security scan results (from scheduled ClamAV/rkhunter scans)
- Instance state changes (container start/stop/create from Proxmox/Docker APIs)
- Configuration changes (git commits to infra-as-code repos, or config file modification timestamps)
- Authentication events (successful logins from auth.log)
- **Storage**: Events stored in a lightweight local database (SQLite or JSON file) with timestamp, type, title, source, and severity.
**Display:**
- Card title: "RECENT ACTIVITY" (uppercase, secondary color)
- Close button (X) in top-right corner
- 5 items, each containing:
- Icon (event-type-specific: checkmark for completion, shield for security, play for launch, gear for config, user for login) — 14px, in a small rounded container (28px, page background)
- Event title (13px, bold, primary color) — e.g., "Backup completed"
- Source subtitle (11px, secondary color) — e.g., "Database Cluster 01"
- Relative timestamp (11px, secondary color, right-aligned) — e.g., "2m ago"
**Event ordering:** Newest first, max 5 displayed.
---
### 7. Top Alerts (right, 30%)
**What it represents:** The most urgent issues requiring attention — prioritized by severity then recency.
**How it gets its data:**
- **Alert aggregation**: Combines alerts from:
- High CPU/RAM usage events (from resource polling — any resource >85% CPU or >90% RAM for 5+ minutes)
- Disk space warnings (from Infrastructure polling — any disk >70%)
- Security events (from fail2ban/auth.log — active attacks)
- SSL certificate expiry (checks cert expiry dates for tracked domains, alerts at 30/14/7 days)
- Service down events (from System Status polling — any unreachable service)
**Display:**
- Card title: "TOP ALERTS" (uppercase, secondary color)
- "View all" link (gold, top-right) — navigates to a full alerts view
- Up to 4 items, each containing:
- Severity dot (🔴 red/large for high, 🟡 yellow for medium) — 6px diameter
- Alert title (13px, primary color, font-medium) — e.g., "High CPU Usage"
- Source subtitle (11px, secondary color) — e.g., "App Server 02"
- Relative timestamp (11px, secondary color, right-aligned) — e.g., "2m ago"
**Sort order:** High severity first, then by recency within same severity level.
---
## Bottom Row — Charts & Actions (2 columns: 65% | 35%)
### 8. Network Traffic (left, 65%)
**What it represents:** Visual representation of network throughput over the last 24 hours — helps spot unusual spikes or drops in traffic.
**How it gets its data:**
- **Interface monitoring**: Reads network interface stats (bytes in/out) from the primary gateway or router. Options:
- SNMP polling from router/switch
- `vnstat` on the ArchNest host or gateway
- Proxmox node network stats API
- **Sampling**: Records bytes in/out every 5 minutes, calculates Mbps/Gbps rate
- **Current values**: Latest sample provides the "Incoming X.XX Gbps" and "Outgoing X.XX Gbps" figures
- **Trend calculation**: Compares current hour's average to same hour yesterday for the percentage change (↑/↓)
**Display:**
- Card title: "NETWORK TRAFFIC" (uppercase, secondary color)
- Background: Custom background image (`archnest-network-traffic-bg.png`) rendered at ~20% opacity behind the chart, giving the card a unique visual identity
- Area chart (overlaid on background):
- Fill: Gold/amber gradient (top: #C8A434 at ~30% opacity, fading to transparent)
- Line: Gold (#C8A434) for inbound, amber (#E67E22) for outbound
- X-axis: 24-hour span (no visible labels)
- Y-axis: Auto-scaled (no visible labels)
- Stats (right side of chart, vertically stacked):
- "Incoming" label (11px, secondary) + "1.23 Gbps" (18px, bold, primary) + "↓ 12.4%" (11px, red)
- "Outgoing" label (11px, secondary) + "1.08 Gbps" (18px, bold, primary) + "↑ 8.7%" (11px, green)
---
### 9. Shortcuts (right, 35%)
**What it represents:** Quick-action buttons for common administrative tasks — one-click access to frequent operations.
**How it works:**
- Each shortcut triggers a predefined action or navigates to a specific workflow:
- **Add Server**: Opens a form/modal to add a new resource to `infra.config` (host IP, type, credentials)
- **Create Backup**: Triggers an on-demand backup job for a selected resource or all resources
- **Deploy App**: Opens a deployment workflow (e.g., pull latest docker-compose, restart containers)
- **View Logs**: Navigates to a log viewer or opens a terminal session with log tailing
**Display:**
- Card title: "SHORTCUTS" (uppercase, secondary color)
- 4 buttons in a horizontal row:
- Each button: Outlined/stroked icon inside a bordered rounded container (40px)
- Icon style: Lucide outlined icons (18px), secondary color, gold on hover
- Label below icon: 10px, secondary color, centered
- Container: 1px border (#1E2025), 8px radius, hover → gold border + gold icon
---
## Data Refresh & Polling Summary
| Data Source | Poll Interval | Used By |
|-------------|---------------|---------|
| System ping sweep | 5 minutes | System Status KPI |
| Package update check | 1 hour | System Status KPI |
| Infrastructure resource status | 5 minutes | Infrastructure KPI, Resource Overview |
| Disk usage per resource | 5 minutes | Infrastructure KPI, Resource Overview, Top Alerts |
| Fail2ban / auth.log | 2 minutes | Security KPI, Top Alerts |
| Security package check | 1 hour | Security KPI |
| Network ping probes | 60 seconds | Network KPI |
| Network interface throughput | 5 minutes | Network Traffic chart |
| Event log (activity) | Real-time (push) or 1 minute | Recent Activity |
| SSL cert expiry | 24 hours | Top Alerts |
| CPU/RAM per resource | 5 minutes | Top Alerts |
---
## Configuration Dependencies
| Config File | Purpose |
|-------------|---------|
| `systems.config` | List of IPs/hosts to ping for System Status |
| `infra.config` | Resource definitions with API endpoints, SSH keys, connection types |
| `alerts.config` | Threshold definitions (disk %, CPU %, failed login count, cert days) |
| `network.config` | Resolver IPs to ping, interface to monitor for traffic |
---
## Interaction Behaviors
| Element | Action | Result |
|---------|--------|--------|
| X button (Resource Overview) | Click | Hides the card for current session |
| X button (Recent Activity) | Click | Hides the card for current session |
| "View all" (Top Alerts) | Click | Navigates to full alerts list view |
| Shortcut button | Click | Triggers associated action/workflow |
| Status card | Hover | Gold border transition (0.2s) |
| Progress ring | Page load | Animates from 0 to value (1s) |
| Sparkline | Page load | Draws line animation (1s) |
| Progress bars | Page load | Fill animation (0.8s staggered) |
| User avatar/chevron | Click | Opens/closes user dropdown menu |
| Dropdown: Profile | Click | Navigates to Settings > Profile |
| Dropdown: Appearance | Click | Navigates to Settings > Appearance |
| Dropdown: Security | Click | Navigates to Settings > Security |
| Dropdown: Help & Support | Click | Opens docs/wiki link |
| Dropdown: Sign Out | Click | Ends session, returns to login |
| Click outside dropdown | Click | Closes the dropdown menu |