2026-06-22 17:47:16 +02:00
|
|
|
# Nadir Web UI
|
|
|
|
|
|
|
|
|
|
SvelteKit dashboard for [nadir-agent](https://tea.urania.dev/urania/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, 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** (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)
|
|
|
|
|
- **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](https://bun.com) and a reachable nadir-agent instance with
|
|
|
|
|
a machine token (see the agent README's *Connecting a dashboard* section).
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
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) |
|
|
|
|
|
| `DISABLE_SIGNUP` | `false` | Lock down registration |
|
|
|
|
|
| `ENABLE_2FA` | `false` | Enable the TOTP 2FA flow |
|
|
|
|
|
| `ENABLE_EMAIL_AND_PASSWORD` | `true` | Toggle email/password auth |
|
|
|
|
|
| `SMTP_*` | - | Outbound mail for verification / reset / 2FA |
|
|
|
|
|
|
|
|
|
|
OAuth providers (optional) live in `config/oauth.json` and are passed straight
|
|
|
|
|
to Better Auth's `genericOAuth` plugin.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Scripts
|
|
|
|
|
|
|
|
|
|
```sh
|
2026-06-23 01:20:45 +02:00
|
|
|
bun run dev # vite dev server
|
|
|
|
|
bun run type:generate # generate typed client for nadir-agent
|
|
|
|
|
bun run build # production build (adapter-node -> build/)
|
|
|
|
|
bun run preview # preview the production build
|
|
|
|
|
bun run check # svelte-check
|
|
|
|
|
bun run lint # prettier + eslint
|
|
|
|
|
bun run format # prettier --write
|
|
|
|
|
bun run db:push # apply schema to the DB
|
|
|
|
|
bun run db:generate # generate migration from schema changes
|
|
|
|
|
bun run db:migrate # run pending migrations
|
|
|
|
|
bun run db:studio # drizzle-kit studio
|
2026-06-22 17:47:16 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Project layout
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
src/
|
|
|
|
|
routes/
|
|
|
|
|
auth/ sign-in, sign-up, forgot/reset password, 2fa setup
|
|
|
|
|
dashboard/ machine list and per-machine live dashboard
|
|
|
|
|
system/ date/time, localization
|
|
|
|
|
admin/ users, config
|
|
|
|
|
api/ internal endpoints (e.g. emailer)
|
|
|
|
|
lib/
|
|
|
|
|
auth/ Better Auth server + client
|
|
|
|
|
components/ shadcn-svelte UI + dashboard panels (cpu, network, storage, ...)
|
|
|
|
|
machines/ valibot schemas
|
|
|
|
|
remotes/ SvelteKit remote functions (server.remote.ts, machines.remote.ts, ...)
|
|
|
|
|
server/
|
|
|
|
|
db/ Drizzle schema + custom encrypted column type
|
|
|
|
|
emails/ nodemailer + better-svelte-email templates
|
|
|
|
|
nadir-agent/ generated OpenAPI types + typed client
|
|
|
|
|
paraglide/ generated i18n runtime
|
|
|
|
|
messages/ translation source (en, ...)
|
|
|
|
|
config/oauth.json optional OAuth providers passed to Better Auth
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Deploying
|
|
|
|
|
|
|
|
|
|
`adapter-node` produces a plain Node/Bun server under `build/`:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
MIT.
|