# CableGUI 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 CableGUI *project*; each project is backed by exactly one `.excalidraw` drawing on mxdrw.msbls.de. ## Status Slice 1 — bootstrap shipped. Projects + global cable types are end-to-end; the SVG canvas is intentionally empty until slice 2. | Slice | What's in it | Status | |---|---|---| | 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 | ## Run it ```sh go run ./cmd/cablegui # open http://localhost:7777 ``` Or built: ```sh make build ./bin/cablegui ``` The binary serves the frontend from an embedded `web/static/` and the JSON API under `/api/`. SQLite lives at `./data/cablegui.db` by default. ### Environment | Var | Default | Notes | |---|---|---| | `CABLEGUI_ADDR` | `0.0.0.0:7777` | Listen address. | | `CABLEGUI_DB` | `./data/cablegui.db` | SQLite path. Parent dir is created on boot. | | `MEXDRAW_BASE_URL` | `https://mxdrw.msbls.de` | Base URL for mExDraw export. | | `MEXDRAW_USER` | (unset) | Username for the mxdrw HTTP Basic Auth on export. Required. | | `MEXDRAW_PASS` | (unset) | Password for the mxdrw HTTP Basic Auth on export. Required. | ### Tests ```sh make test # go test -race ./... ``` Store-level tests cover projects + cable-types CRUD, the `drawing_name` auto-default, the `?confirm=` 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 ".excalidraw" GET /api/projects/:pid → {project, cable_types, frames, devices, …} PATCH /api/projects/:pid ← partial DELETE /api/projects/:pid?confirm= ← 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 ``` ## Deploy to mDock CableGUI runs on **mDock** at `http://mdock:7777` as a docker-compose service under `/home/m/stacks/cablegui/`. Pattern matches the other mDock services (mgreen-journal, mgeo, msports-garmin, …) — no Dokploy, no reverse proxy, LAN-trusted. ### Manual deploy 1. **Build + push the image** (image now lives under `m/` in Gitea): ```sh docker build -t mgit.msbls.de/m/cablegui:latest . awk '/machine mgit.msbls.de/{getline; getline; print $2}' ~/.netrc \ | docker login mgit.msbls.de -u m --password-stdin docker push mgit.msbls.de/m/cablegui:latest ``` 2. **Prepare directories on mDock** (one-time): ```sh ssh mdock 'mkdir -p /home/m/stacks/cablegui/data /home/m/secrets/cablegui \ && touch /home/m/secrets/cablegui/.env \ && chmod 0600 /home/m/secrets/cablegui/.env' scp docker-compose.yml mdock:/home/m/stacks/cablegui/docker-compose.yml ``` 3. **Pull + start**: ```sh ssh mdock 'cd /home/m/stacks/cablegui && docker compose pull && docker compose up -d' ``` 4. **Verify** from any LAN host: ```sh curl http://mdock:7777/api/healthz # → {"status":"ok"} curl http://mdock:7777/api/cable-types # → the 5 seeded types ``` To **update** to a new build: rebuild + push the image, then `ssh mdock 'cd /home/m/stacks/cablegui && docker compose pull && docker compose up -d'`. ### Persistence SQLite lives at `/home/m/stacks/cablegui/data/cablegui.db` on the host (bind-mounted into the container at `/app/data`). Container runs as UID 1000:1000 to align with `m:m` ownership on mDock — DB files end up owned by `m`, the host user. `docker compose restart` keeps the data intact (tested 2026-05-15). ### Automation — follow-up task This first roll is **manual**. A Gitea Actions workflow on the self-hosted runner already on mDock (`/home/m/act-runner/`, label `self-hosted:host`) — build → push → `docker compose up -d` on every push to `main` — is a separate task per the design's §10. Tracking spawned by the head if/when wanted. ## 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.