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
This commit is contained in:
mAi
2026-05-16 15:35:42 +02:00
parent 2b4c574508
commit c206a331ec
34 changed files with 144 additions and 145 deletions

View File

@@ -15,7 +15,7 @@ data
# Build artefacts # Build artefacts
bin bin
/mcables /cablegui
# Editor cruft # Editor cruft
.vscode .vscode

2
.gitignore vendored
View File

@@ -8,7 +8,7 @@ data/*.db-shm
# Build artefacts # Build artefacts
bin/ bin/
/mcables /cablegui
# Editor # Editor
.vscode/ .vscode/

View File

@@ -1,11 +1,11 @@
# mCables — Project Instructions # CableGUI — Project Instructions
## Project Overview ## Project Overview
Cable-management **framework + solver** for m's setup. m declares his Cable-management **framework + solver** for m's setup. m declares his
**devices** and the **connection requirements** between them ("NAS must **devices** and the **connection requirements** between them ("NAS must
connect to Switch via RJ45"). mCables runs a solver that emits the cable connect to Switch via RJ45"). CableGUI runs a solver that emits the cable
plan + bundle recommendations. mCables is a **schematic**, not a plan + bundle recommendations. CableGUI is a **schematic**, not a
physical-routing tool — cables are straight lines between endpoints; the physical-routing tool — cables are straight lines between endpoints; the
"maximum bundling" objective is satisfied by the endpoint-pair rule "maximum bundling" objective is satisfied by the endpoint-pair rule
(when two or more cables share the same A↔B endpoint pair, group them (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. plan, but the solver is the headline.
Each cable-managed environment (LOFT, OFFICE, …) is a separate 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 drawing. The framework provides a visual web interface backed by a Go
HTTP API and SQLite, plus an export pipeline that writes `.excalidraw` HTTP API and SQLite, plus an export pipeline that writes `.excalidraw`
files via mExDraw. 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 **No CLI.** Frontend-first — every interaction is through the visual
interface. The backend serves the UI and the API; there is no 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 ## Goal
@@ -53,7 +54,7 @@ interface. The backend serves the UI and the API; there is no
| Layer | Tech | Notes | | 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. | | 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. | | 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.) | | 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.) |
@@ -112,14 +113,14 @@ interface. The backend serves the UI and the API; there is no
## Deployment — mDock, raw docker (NOT Dokploy) ## 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 as a **plain docker-compose service**. Dokploy is for public mlake/mRiver
stuff; mDock uses raw `docker compose` per the conventions of the existing stuff; mDock uses raw `docker compose` per the conventions of the existing
mDock services (mgreen, mgeo, msports-garmin, paperless, …). mDock services (mgreen, mgeo, msports-garmin, paperless, …).
- Repo layout on mDock: `/home/m/stacks/mcables/` with `docker-compose.yml`, - Repo layout on mDock: `/home/m/stacks/cablegui/` with `docker-compose.yml`,
`data/` bind-mount, secrets in `/home/m/secrets/mcables/.env`. `data/` bind-mount, secrets in `/home/m/secrets/cablegui/.env`.
- Image: `mgit.msbls.de/m/mcables:latest` (built and pushed by a Gitea - 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 Actions workflow on push to `main`, runs on the self-hosted runner on
mDock with label `self-hosted:host`). mDock with label `self-hosted:host`).
- Port mapping: `7777:7777`, exposed on the LAN — no reverse proxy. - 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`. - LAN URL: `http://mdock:7777`.
- No auth — LAN-trusted. - 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 ## Seed drawing — visual grammar reference, **not** a runtime importer
`mxdrw.msbls.de/draw/Cable-Management.excalidraw` is **reference material `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 from scratch inside the tool — the seed exists so the **exporter** mimics
its visual grammar: its visual grammar:
@@ -163,13 +164,13 @@ Legend colours (global, seeded once by migration 001):
## Out of scope (v0) ## Out of scope (v0)
- Multi-user. mCables is m-only. - Multi-user. CableGUI is m-only.
- Auth / sharing — LAN-trusted on mDock. - Auth / sharing — LAN-trusted on mDock.
- Mobile / responsive — desktop browser only. - Mobile / responsive — desktop browser only.
- Cable inventory beyond visual structure (no length, no purchase history, - Cable inventory beyond visual structure (no length, no purchase history,
no SKU). Strictly visual structure for v0. no SKU). Strictly visual structure for v0.
- Import from `.excalidraw` at runtime. If a one-shot migration is ever - 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. hot API endpoint.
## Worker Preferences ## Worker Preferences

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1.7 # 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 # 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. # and a distroless/static runtime is all we need.
@@ -17,20 +17,20 @@ COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build \ RUN CGO_ENABLED=0 GOOS=linux go build \
-trimpath \ -trimpath \
-ldflags="-s -w" \ -ldflags="-s -w" \
-o /out/mcables \ -o /out/cablegui \
./cmd/mcables ./cmd/cablegui
FROM gcr.io/distroless/static-debian12:nonroot FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /app WORKDIR /app
COPY --from=build /out/mcables /app/mcables COPY --from=build /out/cablegui /app/cablegui
ENV MCABLES_ADDR=0.0.0.0:7777 \ ENV CABLEGUI_ADDR=0.0.0.0:7777 \
MCABLES_DB=/app/data/mcables.db CABLEGUI_DB=/app/data/cablegui.db
EXPOSE 7777 EXPOSE 7777
# Run as UID:GID 1000:1000 to match m on mDock — the bind-mounted # 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 # to it without chowning the host dir. distroless/static-debian12 accepts
# arbitrary numeric UIDs; the Go binary doesn't need a /etc/passwd entry. # arbitrary numeric UIDs; the Go binary doesn't need a /etc/passwd entry.
USER 1000:1000 USER 1000:1000
ENTRYPOINT ["/app/mcables"] ENTRYPOINT ["/app/cablegui"]

View File

@@ -1,14 +1,14 @@
.PHONY: build run test typecheck fmt clean .PHONY: build run test typecheck fmt clean
BIN := bin/mcables BIN := bin/cablegui
PKG := ./... PKG := ./...
build: build:
@mkdir -p bin @mkdir -p bin
go build -trimpath -ldflags="-s -w" -o $(BIN) ./cmd/mcables go build -trimpath -ldflags="-s -w" -o $(BIN) ./cmd/cablegui
run: run:
go run ./cmd/mcables go run ./cmd/cablegui
test: test:
go test -race $(PKG) go test -race $(PKG)

View File

@@ -1,9 +1,9 @@
# mCables # CableGUI
Cable-management **framework** for m's setup — visual web editor backed by Cable-management **framework** for m's setup — visual web editor backed by
a single Go binary + SQLite, generating Excalidraw drawings via mExDraw. 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 *project*; each project is backed by exactly one `.excalidraw` drawing on
mxdrw.msbls.de. mxdrw.msbls.de.
@@ -23,7 +23,7 @@ end-to-end; the SVG canvas is intentionally empty until slice 2.
## Run it ## Run it
```sh ```sh
go run ./cmd/mcables go run ./cmd/cablegui
# open http://localhost:7777 # open http://localhost:7777
``` ```
@@ -31,18 +31,18 @@ Or built:
```sh ```sh
make build make build
./bin/mcables ./bin/cablegui
``` ```
The binary serves the frontend from an embedded `web/static/` and the 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 ### Environment
| Var | Default | Notes | | Var | Default | Notes |
|---|---|---| |---|---|---|
| `MCABLES_ADDR` | `0.0.0.0:7777` | Listen address. | | `CABLEGUI_ADDR` | `0.0.0.0:7777` | Listen address. |
| `MCABLES_DB` | `./data/mcables.db` | SQLite path. Parent dir is created on boot. | | `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_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_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. | | `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 ## Deploy to mDock
mCables runs on **mDock** at `http://mdock:7777` as a docker-compose CableGUI runs on **mDock** at `http://mdock:7777` as a docker-compose
service under `/home/m/stacks/mcables/`. Pattern matches the other service under `/home/m/stacks/cablegui/`. Pattern matches the other
mDock services (mgreen-journal, mgeo, msports-garmin, …) — no Dokploy, mDock services (mgreen-journal, mgeo, msports-garmin, …) — no Dokploy,
no reverse proxy, LAN-trusted. no reverse proxy, LAN-trusted.
### Manual deploy (first roll) ### Manual deploy
1. **Build + push the image** (from any host with docker; today the 1. **Build + push the image** (image now lives under `m/` in Gitea):
image lives in mAi's Gitea namespace because mAi doesn't have write
access to `m/`):
```sh ```sh
docker build -t 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-mai \ awk '/machine mgit.msbls.de/{getline; getline; print $2}' ~/.netrc \
| docker login mgit.msbls.de -u mAi --password-stdin | docker login mgit.msbls.de -u m --password-stdin
docker push mgit.msbls.de/mai/mcables:latest docker push mgit.msbls.de/m/cablegui:latest
``` ```
2. **Prepare directories on mDock** (one-time): 2. **Prepare directories on mDock** (one-time):
```sh ```sh
ssh mdock 'mkdir -p /home/m/stacks/mcables/data /home/m/secrets/mcables \ ssh mdock 'mkdir -p /home/m/stacks/cablegui/data /home/m/secrets/cablegui \
&& touch /home/m/secrets/mcables/.env \ && touch /home/m/secrets/cablegui/.env \
&& chmod 0600 /home/m/secrets/mcables/.env' && chmod 0600 /home/m/secrets/cablegui/.env'
scp docker-compose.yml mdock:/home/m/stacks/mcables/docker-compose.yml scp docker-compose.yml mdock:/home/m/stacks/cablegui/docker-compose.yml
``` ```
3. **Pull + start**: 3. **Pull + start**:
```sh ```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: 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 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 ### 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 (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 UID 1000:1000 to align with `m:m` ownership on mDock — DB files end
up owned by `m`, the host user. up owned by `m`, the host user.

View File

@@ -11,14 +11,14 @@ import (
"syscall" "syscall"
"time" "time"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
"mgit.msbls.de/m/mcables/internal/server" "mgit.msbls.de/m/cablegui/internal/server"
"mgit.msbls.de/m/mcables/web" "mgit.msbls.de/m/cablegui/web"
) )
func main() { func main() {
addr := envOr("MCABLES_ADDR", "0.0.0.0:7777") addr := envOr("CABLEGUI_ADDR", "0.0.0.0:7777")
dbPath := envOr("MCABLES_DB", "./data/mcables.db") dbPath := envOr("CABLEGUI_DB", "./data/cablegui.db")
if err := os.MkdirAll(filepath.Dir(dbPath), 0o755); err != nil { if err := os.MkdirAll(filepath.Dir(dbPath), 0o755); err != nil {
log.Fatalf("mkdir data dir: %v", err) log.Fatalf("mkdir data dir: %v", err)
@@ -41,7 +41,7 @@ func main() {
} }
go func() { 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) { if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("listen: %v", err) log.Fatalf("listen: %v", err)
} }

View File

@@ -1,20 +1,20 @@
# mCables — production compose for mDock. # CableGUI — production compose for mDock.
# Lives at /home/m/stacks/mcables/docker-compose.yml on mDock. # Lives at /home/m/stacks/cablegui/docker-compose.yml on mDock.
# Matches the existing mDock service patterns (mgreen, mgeo, …). # Matches the existing mDock service patterns (mgreen, mgeo, …).
services: services:
mcables: cablegui:
image: mgit.msbls.de/m/mcables:latest image: mgit.msbls.de/m/cablegui:latest
container_name: mcables container_name: cablegui
restart: unless-stopped restart: unless-stopped
ports: ports:
- "7777:7777" - "7777:7777"
environment: environment:
- TZ=Europe/Berlin - TZ=Europe/Berlin
- MCABLES_ADDR=0.0.0.0:7777 - CABLEGUI_ADDR=0.0.0.0:7777
- MCABLES_DB=/app/data/mcables.db - CABLEGUI_DB=/app/data/cablegui.db
env_file: env_file:
# MEXDRAW_USER + MEXDRAW_PASS for the mxdrw HTTP Basic Auth on export. # MEXDRAW_USER + MEXDRAW_PASS for the mxdrw HTTP Basic Auth on export.
- /home/m/secrets/mcables/.env - /home/m/secrets/cablegui/.env
volumes: volumes:
- /home/m/stacks/mcables/data:/app/data - /home/m/stacks/cablegui/data:/app/data

View File

@@ -1,4 +1,4 @@
# mCables — Design v4.1 # CableGUI — Design v4.1
Cable-management **framework + solver** for m's setup. Inventor shift 1 Cable-management **framework + solver** for m's setup. Inventor shift 1
design, revised through v2 (rescope to multi-project framework), v3 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**. **v4.1 — six locked answers from m's v4 review**.
> **What changed in v4.1** (tight pass on v4) > **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 > straight lines between endpoints; the solver and the renderer do not
> care about paths, trunks, frame edges, or cable-tray polylines. > care about paths, trunks, frame edges, or cable-tray polylines.
> "Maximum bundling" reduces to the v3 rule: **≥2 cables between the > "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 Sources: the live `Cable-Management.excalidraw` on mxdrw.msbls.de (used as
the *visual-grammar reference*, not a bootstrap import target), 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: conventions (§10). v4 driven by m's product-vision clarification:
> "we provide a cable manager — I say what devices we have, the app tells > "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" > 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 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 plan + bundle recommendations. The manual editor stays (it's the only way
to inspect + tweak the plan) but is no longer the primary surface. 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. > without applying; default applies.
> - **Solver objective: maximum bundling** (§5b.1). Schematic only: when > - **Solver objective: maximum bundling** (§5b.1). Schematic only: when
> two or more cables share the same endpoint pair, group them into one > 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 > not a routing tool. v4.1 strips all path/trunk language from the v4
> draft. > draft.
> - **UI: device-type dropdown** on device-create, **Connection > - **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. > bundle-rendering polish.
> >
> **What carried over from v3 (unchanged in v4)** > **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)`. > `.excalidraw` drawing. `UNIQUE(projects.name)`.
> - `cable_types` is global. Migration 001 seeds Power/USB/HDMI/DP/RJ45. > - `cable_types` is global. Migration 001 seeds Power/USB/HDMI/DP/RJ45.
> - `devices` UNIQUE(project_id, name); `frame_id` nullable; FrameRef > - `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 `<name>.excalidraw`. > - `projects.drawing_name` auto-defaults to `<name>.excalidraw`.
> - `DELETE /api/projects/:pid?confirm=<name>` guardrail. > - `DELETE /api/projects/:pid?confirm=<name>` guardrail.
> - No cable inventory metadata; visual + connectivity structure only. > - No cable inventory metadata; visual + connectivity structure only.
> - DB at `./data/mcables.db` (gitignored). Bind `0.0.0.0:7777` LAN, no auth. > - DB at `./data/cablegui.db` (gitignored). Bind `0.0.0.0:7777` LAN, no auth.
> - Deploy on mDock under `/home/m/stacks/mcables/`, raw docker-compose. > - Deploy on mDock under `/home/m/stacks/cablegui/`, raw docker-compose.
> >
> **What's superseded in v4** > **What's superseded in v4**
> - The "manual draw-a-cable port-to-port" flow from v3 §7 is *kept* as a > - 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 `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 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. looks like the seed.
Concrete numbers from the live file (180 elements): 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 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 cable type. They are not children of the device in the Excalidraw sense
(no `containerId`/`boundElements` link) — purely positional. When we (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. 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 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 (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 ## 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 Driver: **`modernc.org/sqlite`** (cgo-free — clean cross-compile, simple
Dockerfile). Dockerfile).
@@ -609,8 +609,8 @@ cascade does **not** touch `cable_types` (no FK to projects).
## 3. Go HTTP API ## 3. Go HTTP API
Single binary `cmd/mcables`, `net/http`, no router framework. Listens on Single binary `cmd/cablegui`, `net/http`, no router framework. Listens on
`0.0.0.0:7777` by default (overridable via `MCABLES_ADDR`). Static frontend `0.0.0.0:7777` by default (overridable via `CABLEGUI_ADDR`). Static frontend
from `embed.FS` at `/`, JSON API under `/api/`. from `embed.FS` at `/`, JSON API under `/api/`.
``` ```
@@ -780,7 +780,7 @@ generated scene JSON.
## 4. Export — DB → Excalidraw (visual-grammar conformance) ## 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. drawing's grammar is the contract.
### 4.1 Element mapping ### 4.1 Element mapping
@@ -798,7 +798,7 @@ drawing's grammar is the contract.
### 4.2 Element IDs are stable across exports ### 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 via `crypto/rand` → 21-char Excalidraw-style ID). On re-export the same row
reuses the same ID. This means: 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 ### 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, straight lines between endpoints; the solver has no model of walls,
floors, cable trays, or path geometry. "Maximum bundling" therefore floors, cable trays, or path geometry. "Maximum bundling" therefore
reduces to a single rule on the schematic: 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 ▼ 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, - DB → Excalidraw: **manual** button "Export to Excalidraw" in the header,
per project. Calls `POST /api/projects/:pid/sync/export`. per project. Calls `POST /api/projects/:pid/sync/export`.
- Excalidraw → DB: **not implemented** in v0. Anything m draws in - 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 This keeps the v0 scope tight: no conflict resolution, no element-diff
import, no auto-debounce. mExDraw keeps its own version history (git 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. the editor keeps working against the local DB.
Post-MVP, import returns as a one-shot migration tool (separate 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. 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 │ │ │ Legend │ │
@@ -1254,7 +1254,7 @@ Slices 9+ (not promised for the first coder shift):
- Cable inventory metadata (length/SKU) if m later wants it. - Cable inventory metadata (length/SKU) if m later wants it.
- Dark mode. - 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, routing, cable-tray polylines, frame-edge corridors, wall-axis bundling,
3D, anything that treats a cable as more than a labelled endpoint pair. 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: 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 Cables are straight lines between endpoints. The solver does not
route, the renderer does not route, and "maximum bundling" reduces to route, the renderer does not route, and "maximum bundling" reduces to
the endpoint-pair rule (§5b.1). Anything resembling a path, trunk, 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 - Host port mappings: deliberately collision-free across the host. Existing
high ports in use include 3300 (mgreen), 3077 (paperless-ai), 7878 high ports in use include 3300 (mgreen), 3077 (paperless-ai), 7878
(radarr), 8082 (mgeo-tileserver), 8989 (sonarr), 9696 (prowlarr). (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/<project>-data:/app/data` is the canonical - Bind-mount volumes: `/home/m/<project>-data:/app/data` is the canonical
pattern (mgreen). For project-local data we put `data/` *next to* the 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: 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/<project>/.env` (msports-garmin - Secrets via `env_file: /home/m/secrets/<project>/.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 - No reverse proxy on mDock. Services expose ports directly on the LAN
(mDock = `192.168.178.131` / Tailscale `mdock`). Public exposure goes via (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 - Auto-deploy via the Gitea Actions self-hosted runner already installed
on mDock (`/home/m/act-runner/`, label `self-hosted:host`). Push to on mDock (`/home/m/act-runner/`, label `self-hosted:host`). Push to
`main` → workflow on mDock → `docker compose up --build -d`. `main` → workflow on mDock → `docker compose up --build -d`.
### Repo layout for mCables ### Repo layout for CableGUI
``` ```
mCables/ CableGUI/
├── cmd/mcables/main.go # Go binary ├── cmd/cablegui/main.go # Go binary
├── internal/ ├── internal/
│ ├── db/ # migrations + store │ ├── db/ # migrations + store
│ ├── importer/ # post-MVP only (not in MVP) │ ├── importer/ # post-MVP only (not in MVP)
@@ -1336,7 +1336,7 @@ mCables/
│ ├── main.js # ES module entry │ ├── main.js # ES module entry
│ ├── style.css │ ├── style.css
│ └── lib/... # SVG helpers, store, components │ └── lib/... # SVG helpers, store, components
├── data/ # mCables runtime DB lives here (gitignored) ├── data/ # CableGUI runtime DB lives here (gitignored)
│ └── .gitkeep │ └── .gitkeep
├── docs/design.md # this file ├── docs/design.md # this file
├── Dockerfile ├── Dockerfile
@@ -1361,37 +1361,37 @@ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
COPY . . COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \ 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 FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /app WORKDIR /app
COPY --from=build /out/mcables /app/mcables COPY --from=build /out/cablegui /app/cablegui
ENV MCABLES_ADDR=0.0.0.0:7777 ENV CABLEGUI_ADDR=0.0.0.0:7777
ENV MCABLES_DB=/app/data/mcables.db ENV CABLEGUI_DB=/app/data/cablegui.db
USER nonroot:nonroot USER nonroot:nonroot
EXPOSE 7777 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 ```yaml
services: services:
mcables: cablegui:
image: mgit.msbls.de/m/mcables:latest image: mgit.msbls.de/m/cablegui:latest
container_name: mcables container_name: cablegui
restart: unless-stopped restart: unless-stopped
ports: ports:
- "7777:7777" - "7777:7777"
environment: environment:
- TZ=Europe/Berlin - TZ=Europe/Berlin
- MCABLES_ADDR=0.0.0.0:7777 - CABLEGUI_ADDR=0.0.0.0:7777
- MCABLES_DB=/app/data/mcables.db - CABLEGUI_DB=/app/data/cablegui.db
- MEXDRAW_BASE_URL=https://mxdrw.msbls.de - MEXDRAW_BASE_URL=https://mxdrw.msbls.de
env_file: env_file:
- /home/m/secrets/mcables/.env # contains MEXDRAW_TOKEN - /home/m/secrets/cablegui/.env # contains MEXDRAW_TOKEN
volumes: 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`). LAN URL: `http://mdock:7777` (or `http://192.168.178.131:7777`).
@@ -1412,15 +1412,15 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Build image - 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 - name: Push image
run: | run: |
echo "${{ secrets.GITEA_TOKEN }}" | \ echo "${{ secrets.GITEA_TOKEN }}" | \
docker login mgit.msbls.de -u mAi --password-stdin 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 - name: Up
run: | run: |
cd /home/m/stacks/mcables cd /home/m/stacks/cablegui
docker compose pull docker compose pull
docker compose up -d docker compose up -d
``` ```
@@ -1428,7 +1428,7 @@ jobs:
### Local-development run (no Docker) ### 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 typecheck # tsc --noEmit on web/
make test # go test ./... make test # go test ./...
``` ```

2
go.mod
View File

@@ -1,4 +1,4 @@
module mgit.msbls.de/m/mcables module mgit.msbls.de/m/cablegui
go 1.25.5 go 1.25.5

View File

@@ -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 // 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. // and the HTTP layer take a *Store, never a raw *sql.DB.
package db package db

View File

@@ -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. -- A project IS a drawing. LOFT and OFFICE are separate projects.
-- One project ↔ one .excalidraw file in mExDraw. -- One project ↔ one .excalidraw file in mExDraw.

View File

@@ -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). -- v4 — device-type catalog. Built-in types live globally (project_id NULL).
-- Per-project custom types use project_id = X. -- Per-project custom types use project_id = X.

View File

@@ -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. -- 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". -- The solver's input: "device A must connect to device B via cable type T".

View File

@@ -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 -- A template is a named recipe of (device_types + requirements) that
-- bootstraps a project from blank to solver-ready in one apply call. -- bootstraps a project from blank to solver-ready in one apply call.

View File

@@ -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). -- 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 -- Multi-plug N exposes Power × (N+1) ports — one input + N outputs. The

View File

@@ -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), -- 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 -- but m's physical IOx-* devices are power strips (1 power input on

View File

@@ -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 -- 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 -- runs from its `from` endpoint → its clamps in `ord` sequence → its

View File

@@ -13,7 +13,7 @@ import (
"math/big" "math/big"
"sort" "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 // 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{ scene := &Scene{
Type: "excalidraw", Type: "excalidraw",
Version: 2, Version: 2,
Source: "mcables", Source: "cablegui",
Elements: els, Elements: els,
AppState: AppState{ AppState: AppState{
GridSize: nil, GridSize: nil,

View File

@@ -5,7 +5,7 @@ import (
"strings" "strings"
"testing" "testing"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
// deterministic id generator for tests // deterministic id generator for tests

View File

@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "net/http"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
type cableEndpointBody struct { type cableEndpointBody struct {

View File

@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "net/http"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
type clampCreate struct { type clampCreate struct {

View File

@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "net/http"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
type connReqCreate struct { type connReqCreate struct {

View File

@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "net/http"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
type deviceTypePortBody struct { type deviceTypePortBody struct {

View File

@@ -12,8 +12,8 @@ import (
"strings" "strings"
"time" "time"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
"mgit.msbls.de/m/mcables/internal/exporter" "mgit.msbls.de/m/cablegui/internal/exporter"
) )
// syncExport runs the project's snapshot through the exporter, persists // 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 == "" { if user == "" || pass == "" {
writeJSON(w, http.StatusBadRequest, errorBody{ writeJSON(w, http.StatusBadRequest, errorBody{
Error: "MEXDRAW_USER / MEXDRAW_PASS not set", 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 return
} }

View File

@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "net/http"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
// ---------------------------------------------------------------- frames // ---------------------------------------------------------------- frames

View File

@@ -6,7 +6,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
type handlers struct { type handlers struct {

View File

@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "net/http"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
type ioMarkerCreate struct { type ioMarkerCreate struct {

View File

@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "net/http"
"mgit.msbls.de/m/mcables/internal/db" "mgit.msbls.de/m/cablegui/internal/db"
) )
type portCreate struct { type portCreate struct {

View File

@@ -7,10 +7,10 @@ import (
"io/fs" "io/fs"
"net/http" "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 // embedded frontend at /. The frontend FS should be rooted such that
// "index.html" is at its root. // "index.html" is at its root.
func New(store *db.Store, frontend fs.FS) http.Handler { func New(store *db.Store, frontend fs.FS) http.Handler {

View File

@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net/http" "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) { func (h *handlers) solve(w http.ResponseWriter, r *http.Request) {

View File

@@ -3,12 +3,12 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>mCables</title> <title>CableGUI</title>
<link rel="stylesheet" href="/style.css" /> <link rel="stylesheet" href="/style.css" />
</head> </head>
<body> <body>
<header class="topbar"> <header class="topbar">
<span class="brand">mCables</span> <span class="brand">CableGUI</span>
<div class="project-picker"> <div class="project-picker">
<label for="project-select" class="sr-only">Project</label> <label for="project-select" class="sr-only">Project</label>
<select id="project-select" aria-label="Active project"> <select id="project-select" aria-label="Active project">

View File

@@ -1,4 +1,4 @@
// mCables frontend entry — vanilla ES module, no build step. // CableGUI frontend entry — vanilla ES module, no build step.
// //
// Slice 2 adds: frame + device rendering, +Frm/+Dev tools, drag-to-position, // Slice 2 adds: frame + device rendering, +Frm/+Dev tools, drag-to-position,
// inline naming, inspector for selection. State stays minimal: one // inline naming, inspector for selection. State stays minimal: one

View File

@@ -1,5 +1,5 @@
// Package web bundles the frontend (HTML/JS/CSS) into the Go binary // Package web bundles the frontend (HTML/JS/CSS) into the Go binary
// via embed.FS so deploying mCables means shipping one file. // via embed.FS so deploying CableGUI means shipping one file.
package web package web
import ( import (