diff --git a/README.md b/README.md index 6cf749b..3684894 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,28 @@ # Infrastructure -A small internal tool for tracking servers. Search hosts by hardware ID, hostname, or asset ID; manage where they live (site / room / position) and what kind of server they are. Browser UI plus a JSON API. +A small internal tool for tracking servers. Look up a host by **hardware ID**, **hostname**, or **asset ID** and see where it lives (site / room / position), what kind of server it is, and how it's wired into the network. -## Run +Built as a single Node process that serves a vanilla-JS UI and a JSON API from one port. SQLite for storage. No auth — runs on a trusted internal network. + +## Features + +- One search box, three searchable fields. Single match jumps straight to the host page. +- Per-host **network interface** tracking — name, MAC, IPv4, CIDR, link/duplex — with format-validating regex. +- Lookup tables for **sites**, **rooms**, and **server types**, managed inline from the UI. +- Same JSON API for browsers and scripts; schemas validated in, serialized out. + +## Run locally + +Requires Node 22+ (uses the built-in `node:sqlite` and `node:test`). ```sh npm install npm start ``` -UI on `http://localhost:3000`, API at `http://localhost:3000/api`. +UI: `http://localhost:3000` · API: `http://localhost:3000/api` + +First boot seeds one site, one room, and a handful of server types so the dropdowns aren't empty. ## Test @@ -17,25 +30,70 @@ UI on `http://localhost:3000`, API at `http://localhost:3000/api`. npm test ``` -## Docker +21 tests run against an in-process Fastify instance backed by an in-memory SQLite database. + +## Deploy + +Compose pulls the prebuilt image from the Gitea container registry: ```sh -docker compose up --build +docker compose up -d ``` -Data persists in the `infrastructure-data` named volume. +This pulls `gitea.thewrightserver.net/josh/infrastructure:latest` and mounts a named volume at `/app/data` for the SQLite file. To grab a new build: + +```sh +docker compose pull && docker compose up -d +``` + +### CI + +[`.gitea/workflows/build.yml`](.gitea/workflows/build.yml) runs on every push to `main`: + +1. Install deps and run the test suite. +2. If green, log in to `gitea.thewrightserver.net` using the `REGISTRY_TOKEN` repo secret. +3. Build the image and push two tags: `:latest` and `:`. + +Set `REGISTRY_TOKEN` under **Repo → Settings → Actions → Secrets** to a Personal Access Token with `write:package` scope. ## API | Method | Path | Notes | |---|---|---| -| GET | `/api/hosts?q=` | Substring search across `hardware_id`, `hostname`, `asset_id`. Capped at 200 results. | -| GET | `/api/hosts/:id` | Fetch one. | -| POST | `/api/hosts` | Create. | -| PUT | `/api/hosts/:id` | Replace. | -| DELETE | `/api/hosts/:id` | Hard delete. | +| `GET` | `/api/hosts?q=…` | Substring search across `hardware_id`, `hostname`, `asset_id`. Capped at 200. | +| `GET` | `/api/hosts/:id` | Fetch one by numeric ID. | +| `GET` | `/api/hosts/by-hardware-id/:hwid` | Fetch by hardware ID — what the detail page uses. | +| `POST` | `/api/hosts` | Create. | +| `PUT` | `/api/hosts/:id` | Replace. | +| `DELETE` | `/api/hosts/:id` | Hard delete (cascades to the host's interfaces). | +| `GET` | `/api/interfaces?host_id=N` | List interfaces for a host. | +| `GET` | `/api/interfaces/:id` | Fetch one. | +| `POST` | `/api/interfaces` | Create. Required: `host_id`, `name`. Optional: `mac_address`, `ip_address`, `subnet`, `link_speed`. | +| `PUT` | `/api/interfaces/:id` | Replace. | +| `DELETE` | `/api/interfaces/:id` | Hard delete. | | `*` | `/api/sites[/:id]` | Site CRUD. | | `*` | `/api/rooms[/:id]` | Room CRUD (`?site_id=` filter on GET). | | `*` | `/api/server-types[/:id]` | Server-type CRUD. | -Errors: `{ error, details? }` with status 400 / 404 / 409 / 500. +Errors are uniform: `{ error, details? }` with status `400` / `404` / `409` / `500`. + +## Stack + +- **Node 22** + `node:sqlite` + `node:test` — no `better-sqlite3`, no `vitest` +- **Fastify 5** with built-in JSON Schema validation +- **Vanilla HTML / CSS / JS** — no framework, no bundler + +## Layout + +``` +src/ + server.js Fastify bootstrap, /api mount, SPA fallback + db.js schema, prepared statements, query API + schemas.js JSON Schema definitions + sqlite-errors.js maps SQLite constraint violations to 400/409 + routes/ hosts, interfaces, sites, rooms, server-types +public/ + index.html app.css app.js +tests/ + *.test.js one suite per resource +```