test+docs: store coverage + README for slice 1

Adds table-driven store tests:
- projects: drawing_name auto-default, explicit-name accept, empty-name
  reject, duplicate-name conflict, ordered list, GetProject not-found,
  partial PATCH semantics, blank-drawing-name re-default on PATCH,
  ?confirm=<name> guardrail (wrong / empty / correct), snapshot returns
  the 5 globally-seeded cable_types
- cable_types: 5 seeded with the legend colours, global UNIQUE(name),
  rename + recolour, RESTRICT-blocked delete when a cable references the
  type (with count surfaced via CountCablesUsingType), unused delete
  succeeds, project deletion does NOT cascade into cable_types

go test -race ./... passes. Updates README.md with run instructions,
env vars, the slice-1 API surface, and the slice roadmap.
This commit is contained in:
mAi
2026-05-15 16:48:29 +02:00
parent c13000ee7e
commit 905c75c6db
2 changed files with 362 additions and 25 deletions

106
README.md
View File

@@ -1,37 +1,93 @@
# mCables
Cable management for m's setup — visual interface + SQLite inventory, generating + updating Excalidraw diagrams via mExDraw.
Cable-management **framework** for m's setup — visual web editor backed by
a single Go binary + SQLite, generating Excalidraw drawings via mExDraw.
Each cable-managed environment (LOFT, OFFICE, …) is a separate mCables
*project*; each project is backed by exactly one `.excalidraw` drawing on
mxdrw.msbls.de.
## Status
Bootstrap. Architecture sketch below; implementation pending.
Slice 1 — bootstrap shipped. Projects + global cable types are
end-to-end; the SVG canvas is intentionally empty until slice 2.
## Goal
Track devices, ports, and cables across m's setups (server rack, office, living room). Generate / update Excalidraw diagrams from the inventory. Detect bundles of parallel cables. Visualise cable types by colour (RJ45, DP, HDMI, USB, Power, …).
m's existing drawing is the seed: https://mxdrw.msbls.de/draw/Cable-Management.excalidraw — devices are rectangles, ports are ellipses positioned on the device, cables are arrows from port to port, cable type is encoded via colour with a legend.
## Architecture sketch
| Layer | Tech | Role |
| Slice | What's in it | Status |
|---|---|---|
| Storage | SQLite (`~/.m/mcables.db`) | `devices`, `ports`, `cables`, `cable_types`, `bundles`, `frames` |
| Backend | Go | HTTP API serving the visual frontend, mExDraw integration for diagram I/O |
| Frontend | Visual web UI | Browser-based editor (no CLI). Add/edit devices and cables, see live preview |
| Output | mExDraw via MCP | Render + update Excalidraw drawings |
| Project tracking | mBrian `topic-mcables` | Decisions, status, links to drawings — not the data itself |
| 1 | Project CRUD, global cable types, empty SVG canvas, project picker | ✅ |
| 2 | Frames + devices, drag-to-position | pending |
| 3 | Ports + cables (click-port → click-port) | pending |
| 4 | IO markers + cable-type editing | pending |
| 5 | Export to mxdrw.msbls.de | pending |
## Tech decisions (open)
## Run it
- Frontend stack — vanilla TS + small UI lib, or a framework (Svelte / Preact)?
- Diagram import from the existing `Cable-Management.excalidraw` — one-shot migration script that parses bindings → DB rows.
- Layout algorithm for bundle suggestions — parallel cables along the same path get bundled visually.
```sh
go run ./cmd/mcables
# open http://localhost:7777
```
These get resolved in the first design pass.
Or built:
## Refs
```sh
make build
./bin/mcables
```
- m's seed drawing: https://mxdrw.msbls.de/draw/Cable-Management.excalidraw
- mExDraw MCP: `mcp__mexdraw__*`
- Related: mBrian `topic-msbls` (infrastructure inventory)
The binary serves the frontend from an embedded `web/static/` and the
JSON API under `/api/`. SQLite lives at `./data/mcables.db` by default.
### Environment
| Var | Default | Notes |
|---|---|---|
| `MCABLES_ADDR` | `0.0.0.0:7777` | Listen address. |
| `MCABLES_DB` | `./data/mcables.db` | SQLite path. Parent dir is created on boot. |
| `MEXDRAW_BASE_URL` | (unset) | Used by slice 5 export — not consumed yet. |
| `MEXDRAW_TOKEN` | (unset) | Bearer for the mExDraw export. Not consumed yet. |
### Tests
```sh
make test # go test -race ./...
```
Store-level tests cover projects + cable-types CRUD, the
`drawing_name` auto-default, the `?confirm=<name>` guardrail on
`DELETE /api/projects/:pid`, and the `ON DELETE RESTRICT` on a
referenced cable type.
## API (slice 1)
```
GET /api/healthz → 200 {"status":"ok"}
GET /api/projects → [Project, …]
POST /api/projects ← {name, drawing_name?, description?}
drawing_name defaults to "<name>.excalidraw"
GET /api/projects/:pid → {project, cable_types, frames, devices, …}
PATCH /api/projects/:pid ← partial
DELETE /api/projects/:pid?confirm=<name> ← confirm must equal current name
GET /api/cable-types → [CableType, …] (global)
POST /api/cable-types ← {name, color}
PATCH /api/cable-types/:id ← partial — affects every project
DELETE /api/cable-types/:id ← 409 in_use if any cable references it
```
## Design + project conventions
- `docs/design.md` — full v3 design (schema, API, importer/export
conventions, slices, mDock deploy notes).
- `CLAUDE.md` — project instructions for mai workers.
## Architecture
| Layer | Tech |
|---|---|
| DB | SQLite via `modernc.org/sqlite` (cgo-free), WAL, FKs on |
| Backend | Go 1.22+ `net/http` ServeMux pattern routing, single binary |
| Frontend | Vanilla ES modules + SVG, no build step, embedded via `embed.FS` |
| Export (slice 5) | mExDraw HTTP API on mxdrw.msbls.de |
LAN-trusted, no auth.