Files
josh e74bc99e94
build-and-push / build-and-push (push) Successful in 1m40s
Update README with feature overview, deploy instructions, and API reference
Expand the minimal README with sections for features, local run, tests,
Docker deploy via the Gitea registry, the Gitea Actions workflow, full
API table (now including interfaces and lookup-by-hardware-id), stack
choices, and project layout.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 17:09:02 -04:00

100 lines
3.5 KiB
Markdown

# Infrastructure
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.
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: `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
```sh
npm test
```
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 -d
```
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 `:<commit-sha>`.
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. |
| `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 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
```