diff --git a/.dockerignore b/.dockerignore index 1d6736b..df810d3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,7 +15,7 @@ data # Build artefacts bin -/mcables +/cablegui # Editor cruft .vscode diff --git a/.gitignore b/.gitignore index e48bf79..e2f4a2c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ data/*.db-shm # Build artefacts bin/ -/mcables +/cablegui # Editor .vscode/ diff --git a/CLAUDE.md b/CLAUDE.md index a96930d..b6b1ada 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,11 +1,11 @@ -# mCables — Project Instructions +# 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"). mCables runs a solver that emits the cable -plan + bundle recommendations. mCables is a **schematic**, not a +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 @@ -13,16 +13,17 @@ 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 -**mCables project**, and each project is backed by exactly one Excalidraw +**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` +**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 -`mcables` shell binary intended for humans. +`cablegui` shell binary intended for humans. ## Goal @@ -53,7 +54,7 @@ interface. The backend serves the UI and the API; there is no | Layer | Tech | Notes | |---|---|---| -| DB | SQLite | `./data/mcables.db` (project-local, gitignored). Driver: `modernc.org/sqlite` (cgo-free). | +| 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/.excalidraw` with `Authorization: Bearer $MEXDRAW_TOKEN`. (The `mcp__mexdraw__*` MCP tools are not currently configured for this project — workers use the raw HTTP API.) | @@ -112,14 +113,14 @@ interface. The backend serves the UI and the API; there is no ## Deployment — mDock, raw docker (NOT Dokploy) -mCables runs on **mDock** (`192.168.178.131` on the LAN, Tailscale `mdock`) +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/mcables/` with `docker-compose.yml`, - `data/` bind-mount, secrets in `/home/m/secrets/mcables/.env`. -- Image: `mgit.msbls.de/m/mcables:latest` (built and pushed by a Gitea +- 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. @@ -127,12 +128,12 @@ mDock services (mgreen, mgeo, msports-garmin, paperless, …). - LAN URL: `http://mdock:7777`. - No auth — LAN-trusted. -Local dev (no Docker): `go run ./cmd/mcables` against `./data/mcables.db`. +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**. mCables does **not** auto-ingest it. m will rebuild LOFT and OFFICE +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: @@ -163,13 +164,13 @@ Legend colours (global, seeded once by migration 001): ## Out of scope (v0) -- Multi-user. mCables is m-only. +- 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 `mcables-migrate` CLI tool is the right shape, not a + needed, a separate `cablegui-migrate` CLI tool is the right shape, not a hot API endpoint. ## Worker Preferences diff --git a/Dockerfile b/Dockerfile index 2b899fb..233a621 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1.7 # -# mCables — single-stage build → distroless runtime image. +# CableGUI — single-stage build → distroless runtime image. # go.mod requires go 1.25; modernc.org/sqlite is pure Go so CGO_ENABLED=0 # and a distroless/static runtime is all we need. @@ -17,20 +17,20 @@ COPY . . RUN CGO_ENABLED=0 GOOS=linux go build \ -trimpath \ -ldflags="-s -w" \ - -o /out/mcables \ - ./cmd/mcables + -o /out/cablegui \ + ./cmd/cablegui FROM gcr.io/distroless/static-debian12:nonroot WORKDIR /app -COPY --from=build /out/mcables /app/mcables +COPY --from=build /out/cablegui /app/cablegui -ENV MCABLES_ADDR=0.0.0.0:7777 \ - MCABLES_DB=/app/data/mcables.db +ENV CABLEGUI_ADDR=0.0.0.0:7777 \ + CABLEGUI_DB=/app/data/cablegui.db EXPOSE 7777 # Run as UID:GID 1000:1000 to match m on mDock — the bind-mounted -# /home/m/stacks/mcables/data is owned by m:m, so the container can write +# /home/m/stacks/cablegui/data is owned by m:m, so the container can write # to it without chowning the host dir. distroless/static-debian12 accepts # arbitrary numeric UIDs; the Go binary doesn't need a /etc/passwd entry. USER 1000:1000 -ENTRYPOINT ["/app/mcables"] +ENTRYPOINT ["/app/cablegui"] diff --git a/Makefile b/Makefile index 3be29d6..ccbfa95 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,14 @@ .PHONY: build run test typecheck fmt clean -BIN := bin/mcables +BIN := bin/cablegui PKG := ./... build: @mkdir -p bin - go build -trimpath -ldflags="-s -w" -o $(BIN) ./cmd/mcables + go build -trimpath -ldflags="-s -w" -o $(BIN) ./cmd/cablegui run: - go run ./cmd/mcables + go run ./cmd/cablegui test: go test -race $(PKG) diff --git a/README.md b/README.md index ebd853b..b7bcd78 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# mCables +# 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 mCables +Each cable-managed environment (LOFT, OFFICE, …) is a separate CableGUI *project*; each project is backed by exactly one `.excalidraw` drawing on mxdrw.msbls.de. @@ -23,7 +23,7 @@ end-to-end; the SVG canvas is intentionally empty until slice 2. ## Run it ```sh -go run ./cmd/mcables +go run ./cmd/cablegui # open http://localhost:7777 ``` @@ -31,18 +31,18 @@ Or built: ```sh make build -./bin/mcables +./bin/cablegui ``` The binary serves the frontend from an embedded `web/static/` and the -JSON API under `/api/`. SQLite lives at `./data/mcables.db` by default. +JSON API under `/api/`. SQLite lives at `./data/cablegui.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. | +| `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. | @@ -78,37 +78,35 @@ DELETE /api/cable-types/:id ← 409 in_use if any cable references ## Deploy to mDock -mCables runs on **mDock** at `http://mdock:7777` as a docker-compose -service under `/home/m/stacks/mcables/`. Pattern matches the other +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 (first roll) +### Manual deploy -1. **Build + push the image** (from any host with docker; today the - image lives in mAi's Gitea namespace because mAi doesn't have write - access to `m/`): +1. **Build + push the image** (image now lives under `m/` in Gitea): ```sh - docker build -t mgit.msbls.de/mai/mcables:latest . - awk '/machine mgit.msbls.de/{getline; getline; print $2}' ~/.netrc-mai \ - | docker login mgit.msbls.de -u mAi --password-stdin - docker push mgit.msbls.de/mai/mcables:latest + 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/mcables/data /home/m/secrets/mcables \ - && touch /home/m/secrets/mcables/.env \ - && chmod 0600 /home/m/secrets/mcables/.env' - scp docker-compose.yml mdock:/home/m/stacks/mcables/docker-compose.yml + 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/mcables && docker compose pull && docker compose up -d' + ssh mdock 'cd /home/m/stacks/cablegui && docker compose pull && docker compose up -d' ``` 4. **Verify** from any LAN host: @@ -119,11 +117,11 @@ no reverse proxy, LAN-trusted. ``` To **update** to a new build: rebuild + push the image, then -`ssh mdock 'cd /home/m/stacks/mcables && docker compose pull && docker compose up -d'`. +`ssh mdock 'cd /home/m/stacks/cablegui && docker compose pull && docker compose up -d'`. ### Persistence -SQLite lives at `/home/m/stacks/mcables/data/mcables.db` on the host +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. diff --git a/cmd/mcables/main.go b/cmd/cablegui/main.go similarity index 79% rename from cmd/mcables/main.go rename to cmd/cablegui/main.go index 923ba27..5ddc36a 100644 --- a/cmd/mcables/main.go +++ b/cmd/cablegui/main.go @@ -11,14 +11,14 @@ import ( "syscall" "time" - "mgit.msbls.de/m/mcables/internal/db" - "mgit.msbls.de/m/mcables/internal/server" - "mgit.msbls.de/m/mcables/web" + "mgit.msbls.de/m/cablegui/internal/db" + "mgit.msbls.de/m/cablegui/internal/server" + "mgit.msbls.de/m/cablegui/web" ) func main() { - addr := envOr("MCABLES_ADDR", "0.0.0.0:7777") - dbPath := envOr("MCABLES_DB", "./data/mcables.db") + addr := envOr("CABLEGUI_ADDR", "0.0.0.0:7777") + dbPath := envOr("CABLEGUI_DB", "./data/cablegui.db") if err := os.MkdirAll(filepath.Dir(dbPath), 0o755); err != nil { log.Fatalf("mkdir data dir: %v", err) @@ -41,7 +41,7 @@ func main() { } go func() { - log.Printf("mcables listening on %s (db=%s)", addr, dbPath) + log.Printf("cablegui listening on %s (db=%s)", addr, dbPath) if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("listen: %v", err) } diff --git a/docker-compose.yml b/docker-compose.yml index ee82285..429c68a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,20 +1,20 @@ -# mCables — production compose for mDock. -# Lives at /home/m/stacks/mcables/docker-compose.yml on mDock. +# CableGUI — production compose for mDock. +# Lives at /home/m/stacks/cablegui/docker-compose.yml on mDock. # Matches the existing mDock service patterns (mgreen, mgeo, …). services: - mcables: - image: mgit.msbls.de/m/mcables:latest - container_name: mcables + cablegui: + image: mgit.msbls.de/m/cablegui:latest + container_name: cablegui restart: unless-stopped ports: - "7777:7777" environment: - TZ=Europe/Berlin - - MCABLES_ADDR=0.0.0.0:7777 - - MCABLES_DB=/app/data/mcables.db + - CABLEGUI_ADDR=0.0.0.0:7777 + - CABLEGUI_DB=/app/data/cablegui.db env_file: # MEXDRAW_USER + MEXDRAW_PASS for the mxdrw HTTP Basic Auth on export. - - /home/m/secrets/mcables/.env + - /home/m/secrets/cablegui/.env volumes: - - /home/m/stacks/mcables/data:/app/data + - /home/m/stacks/cablegui/data:/app/data diff --git a/docs/design.md b/docs/design.md index 87d2391..10d2e47 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,4 +1,4 @@ -# mCables — Design v4.1 +# CableGUI — Design v4.1 Cable-management **framework + solver** for m's setup. Inventor shift 1 design, revised through v2 (rescope to multi-project framework), v3 @@ -6,7 +6,7 @@ design, revised through v2 (rescope to multi-project framework), v3 **v4.1 — six locked answers from m's v4 review**. > **What changed in v4.1** (tight pass on v4) -> 1. **mCables is a schematic, not a physical-routing tool.** Cables are +> 1. **CableGUI is a schematic, not a physical-routing tool.** Cables are > straight lines between endpoints; the solver and the renderer do not > care about paths, trunks, frame edges, or cable-tray polylines. > "Maximum bundling" reduces to the v3 rule: **≥2 cables between the @@ -33,13 +33,13 @@ design, revised through v2 (rescope to multi-project framework), v3 Sources: the live `Cable-Management.excalidraw` on mxdrw.msbls.de (used as the *visual-grammar reference*, not a bootstrap import target), -`mai-memory` (`mcables`, `m`), and the live mDock services for deploy +`mai-memory` (`cablegui`, `m`), and the live mDock services for deploy conventions (§10). v4 driven by m's product-vision clarification: > "we provide a cable manager — I say what devices we have, the app tells > me how to bundle cables and how the most efficient connection looks like" -mCables shifts from a manual draw-and-click editor to a **solver** that +CableGUI shifts from a manual draw-and-click editor to a **solver** that takes a list of devices + the connections m needs and emits the cable plan + bundle recommendations. The manual editor stays (it's the only way to inspect + tweak the plan) but is no longer the primary surface. @@ -60,7 +60,7 @@ to inspect + tweak the plan) but is no longer the primary surface. > without applying; default applies. > - **Solver objective: maximum bundling** (§5b.1). Schematic only: when > two or more cables share the same endpoint pair, group them into one -> bundle. No path or trunk geometry — mCables is a wiring schematic, +> bundle. No path or trunk geometry — CableGUI is a wiring schematic, > not a routing tool. v4.1 strips all path/trunk language from the v4 > draft. > - **UI: device-type dropdown** on device-create, **Connection @@ -72,7 +72,7 @@ to inspect + tweak the plan) but is no longer the primary surface. > bundle-rendering polish. > > **What carried over from v3 (unchanged in v4)** -> - mCables is a framework: top-level `projects`, each backed by one +> - CableGUI is a framework: top-level `projects`, each backed by one > `.excalidraw` drawing. `UNIQUE(projects.name)`. > - `cable_types` is global. Migration 001 seeds Power/USB/HDMI/DP/RJ45. > - `devices` UNIQUE(project_id, name); `frame_id` nullable; FrameRef @@ -81,8 +81,8 @@ to inspect + tweak the plan) but is no longer the primary surface. > - `projects.drawing_name` auto-defaults to `.excalidraw`. > - `DELETE /api/projects/:pid?confirm=` guardrail. > - No cable inventory metadata; visual + connectivity structure only. -> - DB at `./data/mcables.db` (gitignored). Bind `0.0.0.0:7777` LAN, no auth. -> - Deploy on mDock under `/home/m/stacks/mcables/`, raw docker-compose. +> - DB at `./data/cablegui.db` (gitignored). Bind `0.0.0.0:7777` LAN, no auth. +> - Deploy on mDock under `/home/m/stacks/cablegui/`, raw docker-compose. > > **What's superseded in v4** > - The "manual draw-a-cable port-to-port" flow from v3 §7 is *kept* as a @@ -97,7 +97,7 @@ to inspect + tweak the plan) but is no longer the primary surface. `Cable-Management.excalidraw` on mxdrw.msbls.de is **not** ingested at runtime. It is the visual-grammar reference we lock the export onto so that -when m rebuilds LOFT and OFFICE inside mCables, the exported `.excalidraw` +when m rebuilds LOFT and OFFICE inside CableGUI, the exported `.excalidraw` looks like the seed. Concrete numbers from the live file (180 elements): @@ -128,7 +128,7 @@ Three observations about the seed's visual grammar — these constrain the 1. **Ports sit on a device edge as small ellipses (~12×9)**, coloured by cable type. They are not children of the device in the Excalidraw sense (no `containerId`/`boundElements` link) — purely positional. When we - export from mCables we mimic that: port ellipse at `(device.x + + export from CableGUI we mimic that: port ellipse at `(device.x + port.x_offset, device.y + port.y_offset)`, stroke colour = type colour. 2. **Cable arrows bind to elements**. In the seed: 44 endpoints to ellipses (ports), 12 to whole rectangles (device-level, no specific port), 3 to @@ -161,7 +161,7 @@ painful: switch to Preact-via-CDN-ESM (still no build step). Not v0. ## 2. SQLite schema -`./data/mcables.db` (project-local, gitignored). WAL mode, FKs on. +`./data/cablegui.db` (project-local, gitignored). WAL mode, FKs on. Driver: **`modernc.org/sqlite`** (cgo-free — clean cross-compile, simple Dockerfile). @@ -609,8 +609,8 @@ cascade does **not** touch `cable_types` (no FK to projects). ## 3. Go HTTP API -Single binary `cmd/mcables`, `net/http`, no router framework. Listens on -`0.0.0.0:7777` by default (overridable via `MCABLES_ADDR`). Static frontend +Single binary `cmd/cablegui`, `net/http`, no router framework. Listens on +`0.0.0.0:7777` by default (overridable via `CABLEGUI_ADDR`). Static frontend from `embed.FS` at `/`, JSON API under `/api/`. ``` @@ -780,7 +780,7 @@ generated scene JSON. ## 4. Export — DB → Excalidraw (visual-grammar conformance) -mCables generates a `.excalidraw` scene from a project's rows. The seed +CableGUI generates a `.excalidraw` scene from a project's rows. The seed drawing's grammar is the contract. ### 4.1 Element mapping @@ -798,7 +798,7 @@ drawing's grammar is the contract. ### 4.2 Element IDs are stable across exports -Every mCables row carries `excalidraw_id` (TEXT, generated on first export +Every CableGUI row carries `excalidraw_id` (TEXT, generated on first export via `crypto/rand` → 21-char Excalidraw-style ID). On re-export the same row reuses the same ID. This means: @@ -866,7 +866,7 @@ left strictly alone — the solver only adds and removes its own. ### 5b.1 Objective: maximum bundling — schematic only -mCables is a **schematic**, not a physical-routing tool. Cables are +CableGUI is a **schematic**, not a physical-routing tool. Cables are straight lines between endpoints; the solver has no model of walls, floors, cable trays, or path geometry. "Maximum bundling" therefore reduces to a single rule on the schematic: @@ -988,7 +988,7 @@ triggers a debounced re-solve) is parked at slice 9+ as an opt-in. ``` ┌─────────────────────┐ - │ mCables DB (truth) │ + │ CableGUI DB (truth) │ └──────────┬──────────┘ │ export ▼ @@ -998,11 +998,11 @@ triggers a debounced re-solve) is parked at slice 9+ as an opt-in. └────────────────────────┘ ``` -- mCables UI → DB: synchronous (every drag/add/remove persists immediately). +- CableGUI UI → DB: synchronous (every drag/add/remove persists immediately). - DB → Excalidraw: **manual** button "Export to Excalidraw" in the header, per project. Calls `POST /api/projects/:pid/sync/export`. - Excalidraw → DB: **not implemented** in v0. Anything m draws in - Excalidraw stays in Excalidraw until he redraws it in mCables. + Excalidraw stays in Excalidraw until he redraws it in CableGUI. This keeps the v0 scope tight: no conflict resolution, no element-diff import, no auto-debounce. mExDraw keeps its own version history (git @@ -1012,7 +1012,7 @@ When mxdrw is unreachable: the export button shows a tooltip and disables; the editor keeps working against the local DB. Post-MVP, import returns as a one-shot migration tool (separate -`mcables-migrate` CLI tool, not part of the running server) for seeding +`cablegui-migrate` CLI tool, not part of the running server) for seeding new projects from existing `.excalidraw` files. --- @@ -1023,7 +1023,7 @@ The editor lives at `/`. Layout: ``` ┌────────────────────────────────────────────────────────────────────┐ -│ mCables [LOFT ▾ projects-picker] [Export] [+ Project] │ ← header +│ CableGUI [LOFT ▾ projects-picker] [Export] [+ Project] │ ← header ├────────┬───────────────────────────────────────────────────────────┤ │ │ │ │ Legend │ │ @@ -1254,7 +1254,7 @@ Slices 9+ (not promised for the first coder shift): - Cable inventory metadata (length/SKU) if m later wants it. - Dark mode. -Out of scope, period (would change mCables's mental model): path +Out of scope, period (would change CableGUI's mental model): path routing, cable-tray polylines, frame-edge corridors, wall-axis bundling, 3D, anything that treats a cable as more than a labelled endpoint pair. @@ -1264,7 +1264,7 @@ routing, cable-tray polylines, frame-edge corridors, wall-axis bundling, The six v4 questions are now answered. Locked answers: -1. **Where do paths come from?** → **Nowhere — mCables is a schematic.** +1. **Where do paths come from?** → **Nowhere — CableGUI is a schematic.** Cables are straight lines between endpoints. The solver does not route, the renderer does not route, and "maximum bundling" reduces to the endpoint-pair rule (§5b.1). Anything resembling a path, trunk, @@ -1307,25 +1307,25 @@ before writing this: - Host port mappings: deliberately collision-free across the host. Existing high ports in use include 3300 (mgreen), 3077 (paperless-ai), 7878 (radarr), 8082 (mgeo-tileserver), 8989 (sonarr), 9696 (prowlarr). - **Port 7777 is free** — taking it for mCables. + **Port 7777 is free** — taking it for CableGUI. - Bind-mount volumes: `/home/m/-data:/app/data` is the canonical pattern (mgreen). For project-local data we put `data/` *next to* the compose file so a `git pull && docker compose up -d` is the whole deploy: - `/home/m/stacks/mcables/data:/app/data`. + `/home/m/stacks/cablegui/data:/app/data`. - Secrets via `env_file: /home/m/secrets//.env` (msports-garmin - pattern). mCables only needs `MEXDRAW_TOKEN` for export. + pattern). CableGUI only needs `MEXDRAW_TOKEN` for export. - No reverse proxy on mDock. Services expose ports directly on the LAN (mDock = `192.168.178.131` / Tailscale `mdock`). Public exposure goes via - mlake/Dokploy + Caddy when needed — out of scope for mCables (LAN-only). + mlake/Dokploy + Caddy when needed — out of scope for CableGUI (LAN-only). - Auto-deploy via the Gitea Actions self-hosted runner already installed on mDock (`/home/m/act-runner/`, label `self-hosted:host`). Push to `main` → workflow on mDock → `docker compose up --build -d`. -### Repo layout for mCables +### Repo layout for CableGUI ``` -mCables/ -├── cmd/mcables/main.go # Go binary +CableGUI/ +├── cmd/cablegui/main.go # Go binary ├── internal/ │ ├── db/ # migrations + store │ ├── importer/ # post-MVP only (not in MVP) @@ -1336,7 +1336,7 @@ mCables/ │ ├── main.js # ES module entry │ ├── style.css │ └── lib/... # SVG helpers, store, components -├── data/ # mCables runtime DB lives here (gitignored) +├── data/ # CableGUI runtime DB lives here (gitignored) │ └── .gitkeep ├── docs/design.md # this file ├── Dockerfile @@ -1361,37 +1361,37 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \ - -o /out/mcables ./cmd/mcables + -o /out/cablegui ./cmd/cablegui FROM gcr.io/distroless/static-debian12:nonroot WORKDIR /app -COPY --from=build /out/mcables /app/mcables -ENV MCABLES_ADDR=0.0.0.0:7777 -ENV MCABLES_DB=/app/data/mcables.db +COPY --from=build /out/cablegui /app/cablegui +ENV CABLEGUI_ADDR=0.0.0.0:7777 +ENV CABLEGUI_DB=/app/data/cablegui.db USER nonroot:nonroot EXPOSE 7777 -ENTRYPOINT ["/app/mcables"] +ENTRYPOINT ["/app/cablegui"] ``` -### docker-compose.yml (on mDock at `/home/m/stacks/mcables/`) +### docker-compose.yml (on mDock at `/home/m/stacks/cablegui/`) ```yaml services: - mcables: - image: mgit.msbls.de/m/mcables:latest - container_name: mcables + cablegui: + image: mgit.msbls.de/m/cablegui:latest + container_name: cablegui restart: unless-stopped ports: - "7777:7777" environment: - TZ=Europe/Berlin - - MCABLES_ADDR=0.0.0.0:7777 - - MCABLES_DB=/app/data/mcables.db + - CABLEGUI_ADDR=0.0.0.0:7777 + - CABLEGUI_DB=/app/data/cablegui.db - MEXDRAW_BASE_URL=https://mxdrw.msbls.de env_file: - - /home/m/secrets/mcables/.env # contains MEXDRAW_TOKEN + - /home/m/secrets/cablegui/.env # contains MEXDRAW_TOKEN volumes: - - /home/m/stacks/mcables/data:/app/data + - /home/m/stacks/cablegui/data:/app/data ``` LAN URL: `http://mdock:7777` (or `http://192.168.178.131:7777`). @@ -1412,15 +1412,15 @@ jobs: steps: - uses: actions/checkout@v4 - name: Build image - run: docker build -t mgit.msbls.de/m/mcables:latest . + run: docker build -t mgit.msbls.de/m/cablegui:latest . - name: Push image run: | echo "${{ secrets.GITEA_TOKEN }}" | \ docker login mgit.msbls.de -u mAi --password-stdin - docker push mgit.msbls.de/m/mcables:latest + docker push mgit.msbls.de/m/cablegui:latest - name: Up run: | - cd /home/m/stacks/mcables + cd /home/m/stacks/cablegui docker compose pull docker compose up -d ``` @@ -1428,7 +1428,7 @@ jobs: ### Local-development run (no Docker) ``` -make run # go run ./cmd/mcables → :7777 against ./data/mcables.db +make run # go run ./cmd/cablegui → :7777 against ./data/cablegui.db make typecheck # tsc --noEmit on web/ make test # go test ./... ``` diff --git a/go.mod b/go.mod index 50ee899..6c1149f 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module mgit.msbls.de/m/mcables +module mgit.msbls.de/m/cablegui go 1.25.5 diff --git a/internal/db/db.go b/internal/db/db.go index 417eac4..25515ac 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -1,4 +1,4 @@ -// Package db owns SQLite access for mCables: migrations runner + the +// Package db owns SQLite access for CableGUI: migrations runner + the // query layer (store.go). The Store wraps a *sql.DB with helpers; tests // and the HTTP layer take a *Store, never a raw *sql.DB. package db diff --git a/internal/db/migrations/001_init.sql b/internal/db/migrations/001_init.sql index 6cfe14b..27efafc 100644 --- a/internal/db/migrations/001_init.sql +++ b/internal/db/migrations/001_init.sql @@ -1,4 +1,4 @@ --- mCables v3 initial schema. See docs/design.md §2. +-- CableGUI v3 initial schema. See docs/design.md §2. -- A project IS a drawing. LOFT and OFFICE are separate projects. -- One project ↔ one .excalidraw file in mExDraw. diff --git a/internal/db/migrations/002_device_catalog.sql b/internal/db/migrations/002_device_catalog.sql index 7b26bd7..187e0df 100644 --- a/internal/db/migrations/002_device_catalog.sql +++ b/internal/db/migrations/002_device_catalog.sql @@ -1,4 +1,4 @@ --- mCables v4 device-type catalog. See docs/design.md §2.1 + §2.2. +-- CableGUI v4 device-type catalog. See docs/design.md §2.1 + §2.2. -- v4 — device-type catalog. Built-in types live globally (project_id NULL). -- Per-project custom types use project_id = X. diff --git a/internal/db/migrations/003_connection_requirements.sql b/internal/db/migrations/003_connection_requirements.sql index ea65fb8..d2e13ef 100644 --- a/internal/db/migrations/003_connection_requirements.sql +++ b/internal/db/migrations/003_connection_requirements.sql @@ -1,4 +1,4 @@ --- mCables v4.1 connection requirements + solver-owned cable flag. +-- CableGUI v4.1 connection requirements + solver-owned cable flag. -- See docs/design.md §2.1 + §2 connection_requirements + §5b.3. -- The solver's input: "device A must connect to device B via cable type T". diff --git a/internal/db/migrations/004_setup_templates.sql b/internal/db/migrations/004_setup_templates.sql index 94f16c4..a140cbc 100644 --- a/internal/db/migrations/004_setup_templates.sql +++ b/internal/db/migrations/004_setup_templates.sql @@ -1,4 +1,4 @@ --- mCables v4.1 setup templates. See docs/design.md §2.4. +-- CableGUI v4.1 setup templates. See docs/design.md §2.4. -- -- A template is a named recipe of (device_types + requirements) that -- bootstraps a project from blank to solver-ready in one apply call. diff --git a/internal/db/migrations/005_catalog_power.sql b/internal/db/migrations/005_catalog_power.sql index 222f63c..fde2c16 100644 --- a/internal/db/migrations/005_catalog_power.sql +++ b/internal/db/migrations/005_catalog_power.sql @@ -1,4 +1,4 @@ --- mCables v5 — catalog: power-distribution devices. +-- CableGUI v5 — catalog: power-distribution devices. -- Adds 5 built-in device_types (project_id NULL, built_in=1). -- -- Multi-plug N exposes Power × (N+1) ports — one input + N outputs. The diff --git a/internal/db/migrations/006_fix_power_hubs.sql b/internal/db/migrations/006_fix_power_hubs.sql index 257fbbc..a4df106 100644 --- a/internal/db/migrations/006_fix_power_hubs.sql +++ b/internal/db/migrations/006_fix_power_hubs.sql @@ -1,4 +1,4 @@ --- mCables v6 — fix IOx-* and Multi-plug-* + Wifi-plug port profiles. +-- CableGUI v6 — fix IOx-* and Multi-plug-* + Wifi-plug port profiles. -- -- v4 seeded the IOx-3 / IOx-6 / IOx-8 as USB hubs (Power × 1 + USB × N), -- but m's physical IOx-* devices are power strips (1 power input on diff --git a/internal/db/migrations/007_clamps.sql b/internal/db/migrations/007_clamps.sql index e9ff97b..2d49f35 100644 --- a/internal/db/migrations/007_clamps.sql +++ b/internal/db/migrations/007_clamps.sql @@ -1,4 +1,4 @@ --- mCables v5 — cable routing via clamps. See docs/design.md §11. +-- CableGUI v5 — cable routing via clamps. See docs/design.md §11. -- -- A clamp is a physical anchor placed on the canvas. A cable's polyline -- runs from its `from` endpoint → its clamps in `ord` sequence → its diff --git a/internal/exporter/exporter.go b/internal/exporter/exporter.go index aad0fd4..2c1eedc 100644 --- a/internal/exporter/exporter.go +++ b/internal/exporter/exporter.go @@ -13,7 +13,7 @@ import ( "math/big" "sort" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) // Scene is the top-level Excalidraw file format. Keys mirror what the @@ -537,7 +537,7 @@ func BuildScene(snap *db.Snapshot, nowMilli int64, genID func() string) (*Scene, scene := &Scene{ Type: "excalidraw", Version: 2, - Source: "mcables", + Source: "cablegui", Elements: els, AppState: AppState{ GridSize: nil, diff --git a/internal/exporter/exporter_test.go b/internal/exporter/exporter_test.go index 1a6385f..2fbd79c 100644 --- a/internal/exporter/exporter_test.go +++ b/internal/exporter/exporter_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) // deterministic id generator for tests diff --git a/internal/server/cables.go b/internal/server/cables.go index bd51b6c..2d16914 100644 --- a/internal/server/cables.go +++ b/internal/server/cables.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) type cableEndpointBody struct { diff --git a/internal/server/clamps.go b/internal/server/clamps.go index f5719b6..8c80208 100644 --- a/internal/server/clamps.go +++ b/internal/server/clamps.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) type clampCreate struct { diff --git a/internal/server/connection_requirements.go b/internal/server/connection_requirements.go index 017b7f8..6a899ba 100644 --- a/internal/server/connection_requirements.go +++ b/internal/server/connection_requirements.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) type connReqCreate struct { diff --git a/internal/server/device_types.go b/internal/server/device_types.go index da30ddd..909987d 100644 --- a/internal/server/device_types.go +++ b/internal/server/device_types.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) type deviceTypePortBody struct { diff --git a/internal/server/export.go b/internal/server/export.go index 9f85147..ac6a30a 100644 --- a/internal/server/export.go +++ b/internal/server/export.go @@ -12,8 +12,8 @@ import ( "strings" "time" - "mgit.msbls.de/m/mcables/internal/db" - "mgit.msbls.de/m/mcables/internal/exporter" + "mgit.msbls.de/m/cablegui/internal/db" + "mgit.msbls.de/m/cablegui/internal/exporter" ) // syncExport runs the project's snapshot through the exporter, persists @@ -34,7 +34,7 @@ func (h *handlers) syncExport(w http.ResponseWriter, r *http.Request) { if user == "" || pass == "" { writeJSON(w, http.StatusBadRequest, errorBody{ Error: "MEXDRAW_USER / MEXDRAW_PASS not set", - Details: "Add MEXDRAW_USER and MEXDRAW_PASS to /home/m/secrets/mcables/.env on mDock and restart the container — mxdrw expects HTTP Basic Auth", + Details: "Add MEXDRAW_USER and MEXDRAW_PASS to /home/m/secrets/cablegui/.env on mDock and restart the container — mxdrw expects HTTP Basic Auth", }) return } diff --git a/internal/server/frames_devices.go b/internal/server/frames_devices.go index 50be46b..b03d942 100644 --- a/internal/server/frames_devices.go +++ b/internal/server/frames_devices.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) // ---------------------------------------------------------------- frames diff --git a/internal/server/handlers.go b/internal/server/handlers.go index b1704c4..4c08f55 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -6,7 +6,7 @@ import ( "net/http" "strconv" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) type handlers struct { diff --git a/internal/server/io_markers.go b/internal/server/io_markers.go index 5568e0f..151c362 100644 --- a/internal/server/io_markers.go +++ b/internal/server/io_markers.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) type ioMarkerCreate struct { diff --git a/internal/server/ports.go b/internal/server/ports.go index 057c202..a2a66b5 100644 --- a/internal/server/ports.go +++ b/internal/server/ports.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) type portCreate struct { diff --git a/internal/server/server.go b/internal/server/server.go index 9c66c52..e3e14b5 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -7,10 +7,10 @@ import ( "io/fs" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) -// New returns an http.Handler serving the mCables API at /api/ and the +// New returns an http.Handler serving the CableGUI API at /api/ and the // embedded frontend at /. The frontend FS should be rooted such that // "index.html" is at its root. func New(store *db.Store, frontend fs.FS) http.Handler { diff --git a/internal/server/solver.go b/internal/server/solver.go index f5484cf..65bdf69 100644 --- a/internal/server/solver.go +++ b/internal/server/solver.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "mgit.msbls.de/m/mcables/internal/db" + "mgit.msbls.de/m/cablegui/internal/db" ) func (h *handlers) solve(w http.ResponseWriter, r *http.Request) { diff --git a/web/static/index.html b/web/static/index.html index 36b1048..11059d3 100644 --- a/web/static/index.html +++ b/web/static/index.html @@ -3,12 +3,12 @@ - mCables + CableGUI
- mCables + CableGUI