urania a773df9c46
release / release (push) Successful in 4s
v0.7.2
2026-06-26 14:23:25 +02:00
2026-06-26 11:28:25 +02:00
2026-06-22 17:47:16 +02:00
2026-06-22 17:47:16 +02:00
2026-06-26 00:31:29 +02:00
2026-06-26 00:31:29 +02:00
2026-06-22 17:47:16 +02:00
2026-06-26 14:23:25 +02:00
2026-06-22 17:47:16 +02:00
2026-06-26 09:37:33 +02:00
2026-06-26 10:40:34 +02:00
2026-06-26 14:01:38 +02:00
2026-06-22 17:47:16 +02:00
2026-06-22 17:47:16 +02:00
2026-06-22 17:47:16 +02:00
2026-06-26 09:37:33 +02:00
2026-06-22 17:47:16 +02:00
2026-06-26 00:31:29 +02:00
2026-06-26 00:31:29 +02:00
2026-06-26 10:40:34 +02:00
2026-06-26 11:17:56 +02:00
2026-06-26 09:37:33 +02:00
2026-06-22 17:47:16 +02:00
2026-06-26 14:23:25 +02:00
2026-06-26 00:31:29 +02:00
2026-06-22 17:47:16 +02:00

Nadir Web UI

SvelteKit dashboard for nadir-agent — a central web console that talks to one or many Nadir backend nodes over their typed REST API.

The agent does the system-administration work (systemd services, users, packages, networking, storage, audit, terminal, ...). This UI is the operator's view of it: sign in, register machines with their bearer token, see live host metrics on the dashboard, and drive everyday tasks from the browser.


Stack

  • SvelteKit 2 (Svelte 5, adapter-node) + TailwindCSS 4 + shadcn-svelte
  • Bun as the runtime / package manager / dev server
  • Drizzle ORM on SQLite (libSQL driver) for the UI's own state (users, machines, encrypted tokens, settings)
  • Better Auth with email/password, OAuth, optional 2FA, admin & username plugins
  • Paraglide for i18n (messages in messages/)
  • openapi-fetch + typed client generated from the nadir-agent OpenAPI spec (src/lib/server/nadir-agent/schema.d.ts)

Getting started

Prerequisites: Bun and a reachable nadir-agent instance with a machine token (see the agent README's Connecting a dashboard section).

bun install
cp .env.example .env        # then edit (see below)
bun run db:push             # creates db.sqlite from the Drizzle schema
bun run dev                 # starts on http://localhost:5173

Environment

Set in .env (validated at startup via src/lib/const/schema.ts):

Var Default Purpose
CRYPTO_SECRET (required) Encrypts machine bearer tokens at rest in the local DB
DATABASE_URL file:db.sqlite libSQL connection string
ORIGIN http://localhost:5173 Public origin (used by Better Auth)
REPOSITORY_URL (required) Gitea API URL for the nadir-agent releases; enables GET /install.sh
DISABLE_SIGNUP false Lock down registration
ENABLE_2FA false Enable the TOTP 2FA flow
ENABLE_EMAIL_AND_PASSWORD true Toggle email/password auth
SMTP_HOST - Outbound mail server hostname
SMTP_PORT - SMTP port
SMTP_USER - SMTP username
SMTP_PASS - SMTP password
SMTP_FROM - From address for verification / reset / 2FA emails
SMTP_SSL - Use SSL/TLS for SMTP

OAuth providers (optional) live in config/oauth.json and are passed straight to Better Auth's genericOAuth plugin.


Scripts

bun run dev              # vite dev server (binds --host for LAN access)
bun run dev:types        # regenerate typed client, then start dev server
bun run type:generate    # generate typed client from live nadir-agent OpenAPI spec
bun run build            # production build (adapter-node -> build/)
bun run preview          # preview the production build
bun run check            # svelte-check (must pass 0 errors before done)
bun run lint             # prettier + eslint
bun run format           # prettier --write
bun run db:push          # apply schema to the DB (dev)
bun run db:generate      # generate migration from schema changes
bun run db:migrate       # run pending migrations
bun run db:studio        # drizzle-kit studio

type:generate fetches the OpenAPI spec from the live agent configured in the script (http://100.64.0.189:9999/openapi.json by default — adjust for your environment).


Project layout

src/
  routes/
    auth/              sign-in, sign-up, forgot/reset password, 2fa, 2fa setup
    dashboard/         machine list; per-machine live dashboard
      [machineId]/
        networking/    interfaces (list/detail/configure), routes, DNS, /etc/hosts
        packages/      installed packages, available updates
        services/      service list + per-service control and logs
        storage/       active mounts, fstab entries
        system/        overview, hostname, date-time, localization, power, nadir self-update
        users/         local accounts, groups (list + detail)
    admin/             dashboard users (Better Auth admin), config
    docs/              built-in operator documentation (architecture, installation,
                       security, limitations)
    api/emailer/send/  internal SvelteKit server route for outbound email
    install.sh/        serves the nadir-agent installer shell script (enabled
                       when REPOSITORY_URL is set; returns 404 otherwise)
  lib/
    auth/              Better Auth server instance + browser client
    components/        shadcn-svelte UI + reusable dashboard panels
    remotes/           SvelteKit remote functions, one file per agent domain:
                         auth, config, machines, networking, packages,
                         pam-users, server, services, storage, system,
                         terminal, users, utils
    schemas/           valibot schemas (shared validation types)
    server/
      db/              Drizzle schema + auth-schema + encrypted column type
      emails/          nodemailer + better-svelte-email templates
      nadir-agent/     generated OpenAPI types + typed fetch client
      terminal/        SSH session management (open/stream/write/resize/close)
    paraglide/         generated i18n runtime
messages/              translation source (en.json, ...)
config/oauth.json      optional OAuth providers passed to Better Auth

Remote functions

src/lib/remotes/*.remote.ts are the SvelteKit server-side functions the browser triggers via query / command. They call the agent through nadirForMachine(machineId), which handles token decryption and 401/404/500 routing. After a mutating command, the relevant querys are .refresh()ed inside the command.

File Agent domain covered
auth.remote.ts Sign-in, sign-out, session
config.remote.ts UI application config
machines.remote.ts Machine CRUD, reordering, health batch
networking.remote.ts Interfaces, routing, DNS, /etc/hosts
packages.remote.ts Installed, updates, install/remove (SSE)
pam-users.remote.ts System user listing (PAM side)
server.remote.ts Agent self-update (POST /api/update)
services.remote.ts systemd unit list/control/logs (SSE)
storage.remote.ts Mounts, fstab entries
system.remote.ts Host info, hostname, time/tz/NTP, locale, power
terminal.remote.ts SSH terminal sessions (open/stream/write/resize/close)
users.remote.ts Local accounts + groups
utils.ts Shared helpers (not a remote file)

Database

The UI keeps its own SQLite database (Drizzle ORM, libSQL driver):

Table Contents
user Dashboard user (email, username, name, UI role, ban state)
session Better Auth sessions
account Better Auth OAuth accounts
verification Better Auth verification tokens
twoFactor TOTP secrets / backup codes
machines { id, name, address, order, token(encrypted) } — registered agent nodes
settings Key/value store for UI-side application settings

token in machines is stored with a custom encryptedText column type and is decrypted on demand (autoDecrypt: false) only when making a server-side call to the agent.


SSH Terminal

The UI includes a browser-based SSH terminal (terminal.remote.ts). Operators can open an SSH session to any registered machine's host directly from the dashboard. Sessions are managed server-side (SSH client runs in the SvelteKit server process); the browser streams output via SSE and sends keystrokes via command. Sessions are closed on disconnect or explicit closeSshTerminal.


GET /install.sh

When REPOSITORY_URL is set, the UI serves a shell installer at /install.sh that bootstraps nadir-agent on a new host. The script is generated from src/routes/install.sh/install.sh.tmpl with the release repo URL injected. If REPOSITORY_URL is not set the route returns 404 with an explanation.


Deploying

adapter-node produces a plain Node/Bun server under build/:

bun run build
PORT=3000 ORIGIN=https://nadir.example.com bun run build/index.js

Put it behind the same reverse proxy you use for nadir-agent, or co-host them. The agent's CSRF rules apply when the UI calls it cross-origin — see the agent README's Connecting a dashboard section. The recommended pattern is to call the agent server-to-server from the SvelteKit server layer; the browser never holds or sends the agent token.


License

MIT.

S
Description
No description provided
Readme 1.3 MiB
v0.7.3 Latest
2026-06-26 14:48:00 +02:00
Languages
Svelte 80.6%
TypeScript 17.7%
CSS 0.7%
Go Template 0.5%
Dockerfile 0.2%
Other 0.2%