Vellum/web
mithral 051169a18a Documentation, and make a fresh clone actually work
Docs
- docs/ARCHITECTURE.md: how the pieces fit and why. The request path, the six
  enforced layers, the data model, the scanner, the job queue, direct-play
  playback, and the three protocol surfaces over one application.
- docs/decisions/: seven ADRs with the alternatives that were rejected —
  SQLite-with-a-seam, direct-play-only, mark-missing-never-delete, the modular
  monolith, the one item-access chokepoint, the table-backed queue, and
  fixed-width timestamps.
- README: the layout section was stale (it predated catalog, home, scanner,
  providers, engine, probe, playback, apitoken, arch and the dto packages) and
  now lists what exists, plus links to the new docs.

Two real bugs, both found by verifying the docs instead of trusting them

1. The CLI could not run on a fresh install. `Config.Validate` created the data
   and config directories, but the CLI never called it, so `vellum user add` —
   the recovery path when you are locked out — failed with "unable to open
   database file" until the server had booted at least once. Split the directory
   creation into `Config.EnsureDirs`, call it from the CLI, and keep the media
   root check out of it: an admin command must not fail because a library is
   unmounted. The CLI tests now point DBPath inside DataDir, exactly as
   LoadConfig derives it, so they exercise the fresh-install path; removing
   EnsureDirs fails three of them.

2. A fresh clone could not build at all. `//go:embed all:dist` fails to compile
   when web/dist is absent, and web/.gitignore expected a `dist/.gitkeep` that
   was never created. Added it, so a clone builds and the server logs
   "web UI not embedded; run the frontend build to include it" — the intended
   behaviour for someone who only wants the API.

Also: the httpapi tests depended on a built frontend and FAILED rather than
skipping, so the suite was red on any fresh clone. findAsset and readAsset now
skip with a message naming the missing step. They still RUN when a bundle is
present (verified: zero skips here), so they have not been quietly disabled.

Verified from a simulated clone of tracked files only: go build exit 0, 25
packages pass, the server boots and applies all 12 migrations, and the CLI
creates a user and takes a backup. gofmt clean, vet exit 0, svelte-check 0/0.
2026-10-12 00:18:11 -04:00
..
dist Documentation, and make a fresh clone actually work 2026-10-12 00:18:11 -04:00
public Apply the brand: charcoal, blue-violet, purple, and the real logo 2026-10-10 17:41:49 -04:00
src Waves 7-8: playback engine selection, and missing files you can see 2026-10-11 14:36:55 -04:00
.gitignore Web UI: Svelte app, embedded into the binary 2026-10-09 16:40:58 -04:00
embed.go Web UI: Svelte app, embedded into the binary 2026-10-09 16:40:58 -04:00
index.html Make the brand the only theme 2026-10-11 13:41:55 -04:00
package.json web: type process.env in vite.config (add @types/node) 2026-10-10 16:33:05 -04:00
pnpm-lock.yaml web: type process.env in vite.config (add @types/node) 2026-10-10 16:33:05 -04:00
pnpm-workspace.yaml Web UI: Svelte app, embedded into the binary 2026-10-09 16:40:58 -04:00
README.md Web UI: Svelte app, embedded into the binary 2026-10-09 16:40:58 -04:00
svelte.config.js Web UI: Svelte app, embedded into the binary 2026-10-09 16:40:58 -04:00
tsconfig.json web: type process.env in vite.config (add @types/node) 2026-10-10 16:33:05 -04:00
vite.config.ts dev: fix the Vite proxy and add a one-command dev runner 2026-10-10 16:32:32 -04:00

Vellum web

Svelte 5 + Vite + TypeScript single-page app. It is built to a static bundle in dist/ and embedded into the Go binary, so all asset paths are relative (base: './' in vite.config.ts).

Commands

pnpm install
pnpm dev      # dev server on :5173, proxying /api to :7788
pnpm build    # writes dist/
pnpm check    # svelte-check

Run the Go server on :7788 (make run from the repo root) and pnpm dev proxies API and health requests to it, so cookies and sessions behave exactly as they will in production.

Layout

src/
  main.ts                 entry point
  App.svelte              login gate -> shell
  app.css                 design tokens and base styles
  lib/
    api.ts                typed client; mirrors the Go handlers
    session.ts            auth + library stores
    nav.ts                view state
    components/
      Login.svelte
      Shell.svelte        nav + view switch
      Libraries.svelte    library list, create, scan, delete
      LibraryView.svelte  item grid with covers
      Reader.svelte       epub.js reader with progress sync
      Users.svelte        admin user management

The reader resumes from a spine index, which is why progress positions are integers: it round-trips through the polymorphic progress table without needing a text column.