Files
CableGUI/CLAUDE.md
mAi c206a331ec rename: mCables → CableGUI (project + repo + image + paths)
Full project rename per m's call. Single atomic commit because the
codebase rename is a coupled change — go module path, env vars, DB
default, Docker artefact names, and on-disk mDock paths all flip
together.

- go.mod: module mgit.msbls.de/m/mcables → mgit.msbls.de/m/cablegui
- cmd/mcables → cmd/cablegui (git mv)
- All Go imports rewritten to the new module path
- Env vars: MCABLES_ADDR/MCABLES_DB → CABLEGUI_ADDR/CABLEGUI_DB
- DB default path: data/mcables.db → data/cablegui.db
- Dockerfile + docker-compose.yml: image, container_name, env vars,
  bind-mount /home/m/stacks/mcables → /home/m/stacks/cablegui,
  secrets /home/m/secrets/mcables → /home/m/secrets/cablegui
- Makefile: bin target + run/build commands point at cmd/cablegui
- .gitignore + .dockerignore: /mcables → /cablegui
- README, docs/design.md, CLAUDE.md: prose + paths + image name
- web/static/index.html: <title> + brand
- web/static/main.js + web/web.go: header comment
- internal/exporter: Scene.Source "mcables" → "cablegui"
- internal/server/export.go: error-detail secrets path
- internal/db/migrations/*.sql: header comments (mCables vN → CableGUI vN)

Memory group_id kept as "mcables" to preserve existing memory continuity.
Documented as historical in CLAUDE.md.

go build ./... clean; go test -race ./... green
2026-05-16 15:35:42 +02:00

189 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CableGUI — Project Instructions
## Project Overview
Cable-management **framework + solver** for m's setup. m declares his
**devices** and the **connection requirements** between them ("NAS must
connect to Switch via RJ45"). CableGUI runs a solver that emits the cable
plan + bundle recommendations. CableGUI is a **schematic**, not a
physical-routing tool — cables are straight lines between endpoints; the
"maximum bundling" objective is satisfied by the endpoint-pair rule
(when two or more cables share the same A↔B endpoint pair, group them
into one bundle). The visual editor is still there for tweaking the
plan, but the solver is the headline.
Each cable-managed environment (LOFT, OFFICE, …) is a separate
**CableGUI project**, and each project is backed by exactly one Excalidraw
drawing. The framework provides a visual web interface backed by a Go
HTTP API and SQLite, plus an export pipeline that writes `.excalidraw`
files via mExDraw.
**Memory group_id:** `mcables` (kept historical — all prior memories live
under this id; renaming would orphan them)
**No CLI.** Frontend-first — every interaction is through the visual
interface. The backend serves the UI and the API; there is no
`cablegui` shell binary intended for humans.
## Goal
- A reusable framework for tracking devices, ports, cables, cable types,
bundles, frames — **scoped per project** (LOFT and OFFICE are separate
projects, each a separate drawing).
- A **solver** that, given the project's devices + connection
requirements, emits the cable plan + bundle recommendations.
Objective: maximum bundling via the endpoint-pair rule (schematic
only — no path/trunk/cable-tray modelling).
- A **hybrid device-type catalog**: 14 built-in types (NAS, PC, Mac,
Notebook, TV, Soundbar, Switch, fritz, ChromeCast, SteamLink,
IOx-3/6/8, Screen, Keyboard, Mouse) with default port profiles,
extensible per project. Picking a type on device-create seeds the
device's ports automatically; m overrides per instance.
- **Setup templates** for bootstrapping a project from blank to
solver-ready: built-ins 'Living Room', 'Home Office', 'Server Rack'
stamp their device-types + connection requirements in one transaction.
- A visual editor for switching projects, adding frames/devices,
declaring requirements, running the solver, and tweaking the
resulting plan. Unmet requirements get a one-click quick-fix
("+ Add &lt;type&gt; port to &lt;device&gt; and re-solve").
- A one-way export from the DB to the corresponding `.excalidraw`
drawing on `mxdrw.msbls.de` whenever m clicks Export — DB is
authoritative, Excalidraw is the projection.
## Architecture
| Layer | Tech | Notes |
|---|---|---|
| DB | SQLite | `./data/cablegui.db` (project-local, gitignored). Driver: `modernc.org/sqlite` (cgo-free). |
| Backend | Go | `net/http` HTTP API + static frontend via `embed.FS`. Standard library + minimal deps. Single binary. |
| Frontend | Vanilla JS modules + SVG, no build step | TypeScript types via JSDoc, optional `tsc --noEmit` in CI. Preact-via-CDN-ESM is the documented fallback if vanilla state gets painful — no build step either way. |
| Diagram I/O | mExDraw HTTP API | `PUT https://mxdrw.msbls.de/api/drawings/<name>.excalidraw` with `Authorization: Bearer $MEXDRAW_TOKEN`. (The `mcp__mexdraw__*` MCP tools are not currently configured for this project — workers use the raw HTTP API.) |
## Hierarchy
- **Project** (`projects` table) is the top-level concept. LOFT, OFFICE,
HOMELAB, … are separate projects. One project ↔ one `.excalidraw`
drawing in mExDraw. `projects.drawing_name` defaults to
`<name>.excalidraw` server-side when omitted on create; editable later.
- **Frames** sub-divide a project (LOFT has `desk`, `rack`, `media`;
OFFICE has `desk`, `server`). Frames are not projects — they're zones
within one drawing.
- Every device, port, cable, IO marker, bundle, and **connection
requirement** is **project-scoped** (`project_id` denormalised onto
every row, with `ON DELETE CASCADE` from `projects`).
`UNIQUE (project_id, devices.name)` — no two devices in one project
share a name.
- **Cable types are global.** A single shared `cable_types` table —
no `project_id`. The five defaults (Power/USB/HDMI/DP/RJ45) are seeded
by migration 001 once, not per project. Renaming or recolouring a type
affects every project's legend immediately.
- **Device types are hybrid.** `device_types` is one global table with
`project_id` NULL for the 11 built-in catalog rows (seeded by
migration 002) and `project_id = current` for project-custom types.
Each `device_type` carries a `device_type_ports` profile that seeds
`ports` rows when a device of that type is created. m can extend the
catalog per project; built-ins are read-only from the API.
- **Connection requirements** (`connection_requirements` table) are the
solver's input. m declares "from_device ↔ to_device, preferred cable
type, must_connect"; the solver assigns ports and emits cables.
- **Project deletion guardrail.** `DELETE /api/projects/:pid` requires
`?confirm=<name>` matching the project's current name. 400 otherwise.
- **Solver-owned vs. user-owned cables.** `cables.auto = 1` = created by
the solver and replaceable on re-solve. `auto = 0` = hand-drawn by m,
left alone by the solver. PATCHing endpoint or type of an auto cable
promotes it to manual (explicit "Promote to manual" button in the
inspector, per design v4 §5b.3).
## Branch Strategy
- `main` = production-deployable.
- `mai/<worker>/<slug>` = worker branches via the mai workflow.
- No `dev` branch — too small a project for staging.
- Merge with `--no-ff` to main, delete branches after merge.
## Tech Stack
- **Go** for the backend (matches m's other tools: `m`, `mai`,
youpcms, mExDraw).
- **SQLite** via `modernc.org/sqlite` (cgo-free → clean `scratch`/distroless
container, no toolchain pain).
- **mExDraw** via HTTP for diagram export. Never edit raw `.excalidraw`
files directly outside the mExDraw API.
- **Vanilla JS + SVG** for the frontend — no build step. JSDoc-typed.
## Deployment — mDock, raw docker (NOT Dokploy)
CableGUI runs on **mDock** (`192.168.178.131` on the LAN, Tailscale `mdock`)
as a **plain docker-compose service**. Dokploy is for public mlake/mRiver
stuff; mDock uses raw `docker compose` per the conventions of the existing
mDock services (mgreen, mgeo, msports-garmin, paperless, …).
- Repo layout on mDock: `/home/m/stacks/cablegui/` with `docker-compose.yml`,
`data/` bind-mount, secrets in `/home/m/secrets/cablegui/.env`.
- Image: `mgit.msbls.de/m/cablegui:latest` (built and pushed by a Gitea
Actions workflow on push to `main`, runs on the self-hosted runner on
mDock with label `self-hosted:host`).
- Port mapping: `7777:7777`, exposed on the LAN — no reverse proxy.
- Restart policy: `unless-stopped`.
- LAN URL: `http://mdock:7777`.
- No auth — LAN-trusted.
Local dev (no Docker): `go run ./cmd/cablegui` against `./data/cablegui.db`.
## Seed drawing — visual grammar reference, **not** a runtime importer
`mxdrw.msbls.de/draw/Cable-Management.excalidraw` is **reference material
only**. CableGUI does **not** auto-ingest it. m will rebuild LOFT and OFFICE
from scratch inside the tool — the seed exists so the **exporter** mimics
its visual grammar:
- **Devices** = rectangles with a text label.
- **Ports** = small ellipses (~12×9) positioned on a device edge.
Positional, *not* containerId-bound. Stroke colour = cable type.
- **Cables** = arrows with `startBinding` / `endBinding` to ports or
devices or IO diamonds.
- **Cable types** = colour, with a legend at the top-left of the project's
first frame listing the project's cable_types.
- **IO markers** = small diamonds. Semantically **wall outlets / power
entry points** — a cable terminating at an IO marker means "this end is
plugged into a wall socket outside the diagram". They are *not*
inter-frame bridges and they do *not* pair up.
- **Frames** = sub-zones inside a project (`desk`, `rack`, `media`, …).
- **Lines** = decorative only (legend separators in the seed). Ignored on
export.
Legend colours (global, seeded once by migration 001):
| Type | Hex |
|---|---|
| Power | `#e03131` |
| USB | `#2f9e44` |
| HDMI | `#1971c2` |
| DP | `#9c36b5` |
| RJ45 | `#ffd500` |
## Out of scope (v0)
- Multi-user. CableGUI is m-only.
- Auth / sharing — LAN-trusted on mDock.
- Mobile / responsive — desktop browser only.
- Cable inventory beyond visual structure (no length, no purchase history,
no SKU). Strictly visual structure for v0.
- Import from `.excalidraw` at runtime. If a one-shot migration is ever
needed, a separate `cablegui-migrate` CLI tool is the right shape, not a
hot API endpoint.
## Worker Preferences
- **Inventor shifts** (design passes): conventions, schema, API, export
pipeline, mDock deploy plan, UI flows, slices. Output: `docs/design.md`
+ open questions for m. v1v4 are versioned in the doc's header callout.
- **Coder shifts** (after m's go on a design version): build to the
current design.md. Current state: slice 1 (project CRUD + global
cable_types) and slice 2 (frames + devices + drag) are merged; design
v4 reshapes slices 3+ (IO + cable-type editing → device-type catalog →
device-type manage → connection-requirements UI → solver → manual
port/cable draw → export). See `docs/design.md` §8 for the current
sequence.
- Use **Sonnet** for both — structure matters more than depth.