# Catalyst A lightweight instance registry for tracking self-hosted infrastructure. No backend, no framework — just a browser, a SQLite database compiled to WebAssembly, and a static file server. ## Structure ``` index.html Entry point css/app.css Styles js/ config.js Service definitions and seed data db.js Data layer ui.js Rendering, modals, notifications app.js Router ``` ## Data layer All reads and writes go through five functions in `js/db.js`. This is the boundary that would be replaced when wiring Catalyst to a real backend — nothing else in the codebase touches data directly. ### `getInstances(filters?)` Returns an array of instances, sorted by name. All filters are optional. ```js getInstances() getInstances({ search: 'plex' }) getInstances({ state: 'degraded' }) getInstances({ stack: 'production' }) getInstances({ search: 'home', state: 'deployed', stack: 'production' }) ``` `search` matches against `name`, `vmid`, and `stack`. ### `getInstance(vmid)` Returns a single instance by VMID, or `null` if not found. ```js getInstance(137) // → { id, name, vmid, state, stack, ...services, createdAt, updatedAt } ``` ### `getDistinctStacks()` Returns a sorted array of unique stack names present in the registry. Used to populate the stack filter dynamically. ```js getDistinctStacks() // → ['development', 'production'] ``` ### `createInstance(data)` Inserts a new instance. Returns `{ ok: true }` on success or `{ ok: false, error }` on failure (e.g. duplicate VMID). ```js createInstance({ name: 'plex', vmid: 117, state: 'deployed', // 'deployed' | 'testing' | 'degraded' stack: 'production', tailscale_ip: '100.64.0.1', atlas: 1, argus: 1, semaphore: 0, patchmon: 1, tailscale: 1, andromeda: 0, hardware_acceleration: 1, }) ``` ### `updateInstance(id, data)` Updates an existing instance by internal `id`. Accepts the same shape as `createInstance`. Returns `{ ok: true }` or `{ ok: false, error }`. ### `deleteInstance(id)` Deletes an instance by internal `id`. Only instances on the `development` stack can be deleted — this is enforced in the UI before `deleteInstance` is ever called. --- ## Instance shape | Field | Type | Notes | |---|---|---| | `id` | integer | Internal autoincrement ID | | `vmid` | integer | Unique. Used as the public identifier and in URLs (`/instance/137`) | | `name` | string | Display name | | `state` | string | `deployed`, `testing`, or `degraded` | | `stack` | string | `production` or `development` | | `tailscale_ip` | string | Optional | | `atlas` | 0 \| 1 | | | `argus` | 0 \| 1 | | | `semaphore` | 0 \| 1 | | | `patchmon` | 0 \| 1 | | | `tailscale` | 0 \| 1 | | | `andromeda` | 0 \| 1 | | | `hardware_acceleration` | 0 \| 1 | | | `createdAt` | ISO string | Set on insert | | `updatedAt` | ISO string | Updated on every write |