8 Commits

Author SHA1 Message Date
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
mAi
fca9fb0a0f design(v5): cable routing via clamps — §11
m's bundling primitive: a clamp is a physical anchor on the canvas;
cables route through clamps in order; cables that share a consecutive
clamp pair are visibly bundled on that segment. Overlap is the bundle —
no detection pass.

Section covers:
- 11.1 Schema: clamps table + cable_clamps join, migration 007. Clamps
  carry frame_id so frame-drag carries them.
- 11.2 Cable rendering: <polyline> through [from, clamp₁..n, to];
  endpoint-replug handles stay on first/last vertices.
- 11.3 Bundle visualisation: shared segments rendered as a 2+N px
  striped line; clamp icon shows ×N count when shared. Computed live
  on every renderCanvas — O(C·N̄), trivial at v0 scale.
- 11.4 UI: +Clamp tool (C shortcut), mid-segment drag-to-snap (snap
  radius ~16 px / zoom), clamp inspector, right-click remove-from-cable.
- 11.5 Existing bundles table: keep, repurpose. Implicit bundles are
  derived from shared clamp segments; explicit named bundles still live
  in the table.
- 11.6 Solver coupling: v0 solver still emits straight cables; m
  hand-routes after. v5.1 future work for solver-suggested clamps.
- 11.7 Export: clamps export as small grey diamonds; cable arrows use
  Excalidraw's points array for mid-vertices. Bundle stripes are
  viewer-only (Excalidraw can't represent them losslessly).
- 11.8 API additions: clamp CRUD, attach/detach/reorder cable clamps.
  Snapshot grows clamps + cable_clamps arrays.
- 11.9 Five open questions for m (icon shape, snap radius scaling,
  cascade-on-delete confirm, stripe order, solver respect for manual
  clamp routing).
- 11.10 6-step slice plan post-approval.

DESIGN v5 READY FOR REVIEW
2026-05-16 13:19:55 +02:00
mAi
f1af2820e1 fix(catalog): migration 006 — IOx-* and Multi-plug-* are power strips
m's actual hardware: IOx-3/6/8 are power strips, not USB hubs. v4 seeded
them as Power × 1 + USB × N which doesn't match reality. Multi-plug 3-6
and Wifi-plug from v5 lumped every Power port on the same bottom edge
without distinguishing input from outputs.

Migration 006 wipes and re-seeds the port profile for all 8
power-distribution types with the canonical 2-row layout:

  Power In  × 1 on top    (back, sort_order 0)
  Power Out × N on bottom (front, sort_order 1)

N for each:
  IOx-3 / Multi-plug 3 → 3
  IOx-6 / Multi-plug 6 → 6
  IOx-8                → 8
  Multi-plug 4         → 4
  Multi-plug 5         → 5
  Wifi-plug            → 1 (pass-through outlet)

Existing device instances keep their already-seeded ports per design
§2.3 (ports are instance-owned). m needs to delete + recreate any
IOx-* / Multi-plug-* / Wifi-plug instances to pick up the new layout.

Tests:
- TestSeed_PortProfiles: comments updated; totals unchanged (Power In 1
  + Power Out N matches old Power 1 + USB N / Power N).
- TestSeed_PowerHubs (was TestSeed_PowerCatalog, rewritten): table-drives
  all 8 affected types. Asserts exactly 2 port rows — top/Power In/1 and
  bottom/Power Out/N — plus kind/icon for the v5 catalog entries.

Design §2.2 catalog table refreshed to match.
2026-05-16 11:03:32 +02:00
mAi
e42b351280 docs: design v4.1 — schematic-only bundling, setup templates folded in
Tight pass on m's review of v4 (single commit per head's instruction).

Six locked answers integrated:

1. mCables is a schematic, not a physical-routing tool. Stripped
   'trunk', 'frame-edge corridor', 'cable tray', 'path optimisation'
   from §5b.1, §5b.2, §7, §8, §9. Bundling reduces to the v3 endpoint-
   pair rule: ≥2 cables between the same A↔B endpoint pair → group as
   one bundle. Anything path-shaped is "out of scope, period" (§8).
2. Solver button-only for v0 (no change). Live-solve parked at 9+.
3. Unmet-requirement quick-fix: red badge on the affected device in the
   inspector with a single "+ Add <type> port to <device> and re-solve"
   button per §5b.4. New endpoint
   POST /api/projects/:pid/devices/:id/ports-and-resolve chains the
   port insert + the solve re-run in one transaction.
4. Setup templates fold INTO v4.1. New §2.4 with the schema for
   setup_templates + setup_template_devices + setup_template_requirements
   (migration 004), 3 built-in templates seeded (Living Room, Home
   Office, Server Rack). New API: GET /api/setup-templates,
   POST /api/projects/:pid/apply-template. New UI flow: "or start from
   a template" section in the New Project modal + an "Apply template"
   action on empty projects. Built-in catalog grows to 14 types
   (adds Screen, Keyboard, Mouse).
5. Catalog SQL seed in migration 002 (no change).
6. Promote-to-manual: explicit button on cable inspector (no change).

§8 slice 6 absorbs the templates work alongside the solver MVP.
§9 closes all six v4 questions; no open design questions remain.
Trailer changes to "DESIGN v4.1 READY FOR REVIEW".

CLAUDE.md mirrors: schematic-only framing, 14-type catalog, setup
templates as a first-class feature, quick-fix UX note.
2026-05-16 00:03:19 +02:00
mAi
e862a06e9d docs: design v4 — solver-as-core, hybrid device-type catalog, requirements
Big rescope driven by m's product-vision clarification: mCables is a
cable-management framework with a solver as its core value prop, not a
manual draw-and-click editor. m declares devices + required connections
between them; the solver emits the cable plan + bundle recommendations,
optimising for maximum bundling.

Schema additions (migrations 002 + 003):
- device_types (catalog) — built-ins (project_id NULL) + project-custom
  (project_id non-null). 11 built-in types seeded with default port
  profiles (NAS, PC, Mac, TV, Soundbar, Switch, fritz, ChromeCast,
  SteamLink, IOx-3/6/8, Notebook).
- device_type_ports (profile rows: cable_type × count × edge).
- devices.type_id (nullable). Picking a type seeds ports once;
  instance-owned thereafter (no retroactive re-seed).
- connection_requirements (per-project, from/to device + preferred type
  + must_connect flag, with order-normalised pair_lo/pair_hi for
  duplicate prevention).
- cables.auto (slice 5.5 migration) — distinguishes solver-owned cables
  from user-drawn ones.

API additions:
- GET /api/device-types (built-ins only, read-only) and
  GET /api/projects/:pid/device-types (built-ins + project-custom merged)
- POST/PATCH/DELETE under /api/projects/:pid/device-types (project-custom
  only; built-ins are 403)
- /api/projects/:pid/connection-requirements full CRUD
- POST /api/projects/:pid/solve with ?preview=1 — pure-function solver
  (greedy port allocation, endpoint-pair bundling for v0); returns
  add[], remove[], bundles_added[], unsatisfied[], warnings[]

Solver algorithm (§5b):
- Read project devices + ports + connection_requirements + manual cables
- Assign each requirement a (port_a, port_b) using the preferred cable
  type (or auto-pick if exactly one type matches both ends)
- Bundle by endpoint-pair (v3 rule, applied to auto cables only)
- Surface unsatisfied requirements per class (no compat type / ambiguous
  type / no free port) — does NOT auto-add ports; UI quick-fix instead
- ?preview=1 returns the diff without writing; default applies in a tx

UI additions:
- Device-create modal: type dropdown (built-ins grouped by kind, then
  project-custom, then "Custom (no type)" for the v3 freeform fallback)
- Left-sidebar Requirements section with + Requirement button
- Header Solve button (S keybinding) → preview modal → Apply
- Inspector for selected device: type, ports grid, unmet requirements
  with red badges + quick-fix actions
- Inspector for selected auto cable: driving requirement, parent bundle,
  Promote-to-manual button

Slice reshape (§8):
- Slices 1, 2 shipped. v4 inserts: 4 = catalog + type-aware device create,
  4.5 = catalog management, 5 = requirements CRUD + UI, 6 = solver MVP +
  Solve button. Old "manual port + manual cable draw" slides to slice 7
  as a tweak path on solver output. Export becomes slice 8.

Six new open questions (§9) for m to gate before slice 4:
1. Path source (auto-route through frame edges / user cable-trays /
   Steiner-tree)?
2. Live-solve vs. button-only?
3. UX when solver has no compatible port pair?
4. Setup templates in v4 or post-MVP?
5. Catalog as code seed or JSON file?
6. Auto-promote vs. explicit Promote-to-manual on solver cable edits?

CLAUDE.md updated to reflect the solver-core framing, hybrid catalog,
connection-requirements model, and auto/manual cable distinction.

Trailer changes to "DESIGN v4 READY FOR REVIEW".
2026-05-15 23:57:22 +02:00
mAi
c690113ea1 docs: design v3 — global cable_types, device UNIQUE, delete guardrail
Tight pass on round-4 answers (single commit per head's request):

- cable_types is GLOBAL — drop project_id, UNIQUE(name). Migration 001
  seeds the 5 defaults once; POST /api/projects no longer seeds them.
  API moves to top-level /api/cable-types. Renaming/recolouring affects
  every project. CASCADE from projects does not touch cable_types.
- devices: UNIQUE (project_id, name) added.
- projects: drawing_name defaults to "<name>.excalidraw" server-side
  on POST when omitted; editable via PATCH.
- DELETE /api/projects/:pid requires ?confirm=<name>; server checks
  name match, returns 400 if missing or mismatched.
- io_markers: no type_id (Power-by-convention, UI soft-warn). Confirmed
  v0 stance.
- Bundles ignored on export — carries over from v2.
- §0 changelog rewritten as "what changed in v3 / what carried over".
- §2 schema rewritten; FK-shape paragraph updated to call out the one
  global table.
- §3 endpoints: cable-types moved to top level; POST/DELETE projects
  show new defaults + guardrail semantics.
- §4 export table notes cable_types pulled from global.
- §7 "edit cable type" flow gains the cross-project-effect banner +
  ON DELETE RESTRICT inline-error UX.
- §8 slice 1 rewritten: no per-project seeding; legend reads global.
- §9 all six v2 questions marked resolved with the v3 answer per item.
- Trailer changes to "DESIGN v3 READY — coder shift gated".
- CLAUDE.md mirrors: global cable_types, device UNIQUE per project,
  drawing_name default, delete guardrail.
2026-05-15 16:32:20 +02:00
mAi
b734e7f874 docs: design v2 — framework rescope, mDock deploy, no runtime importer
Revision after m's answers (2026-05-15):

- mCables is a framework. Top-level `projects` table; LOFT and OFFICE
  are separate projects, each backed by one drawing. project_id is
  denormalised onto every row for cheap project-scoped queries; CASCADE
  from projects wipes a project's whole subgraph.
- IO diamonds are wall-outlet terminators (type=Power), not inter-frame
  bridges. paired_with_id removed.
- No runtime importer. The seed Cable-Management.excalidraw is the
  visual-grammar reference for the exporter only. /api/sync/import is
  dropped from MVP; only /api/sync/export remains (one-way, manual).
- No cable inventory fields. Strictly visual structure for v0.
- DB at ./data/mcables.db (project-local, gitignored).
- Deploy: raw docker on mDock under /home/m/stacks/mcables/ (NOT Dokploy).
  Conventions verified live (mgreen, mgeo, msports-garmin patterns).
  Port 7777, container_name mcables, image from Gitea registry, Gitea
  Actions self-hosted runner builds + deploys on push to main.
- Bind 0.0.0.0:7777 on the LAN. No auth.
- UI gains a projects picker; all CRUD endpoints scoped under
  /api/projects/:pid/.
- Slices re-planned: empty bootstrap → frame+device → port+cable →
  IO+cable-type editing → export.
- Open questions trimmed; six new ones (drawing-name policy, device
  uniqueness, non-Power IO, bundle export, cross-project cable types,
  delete guardrail).

Ends with DESIGN v2 READY FOR REVIEW.
2026-05-15 16:13:24 +02:00
mAi
f429111462 docs: design pass 1 — schema, API, importer, sync, slices
Inventor shift 1. Reads the live Cable-Management.excalidraw on
mxdrw.msbls.de, lands on:

- vanilla JS modules + SVG diagram (no build step) served by a single
  Go binary with embed.FS
- SQLite schema with frames, devices, ports, cable_types, cables,
  io_markers, bundles (cgo-free driver)
- HTTP API under /api/, /api/state as the editor's one-shot loader
- importer that respects port-on-edge geometry (ports are positional,
  not containerId-bound) and resolves arrow endpoints to port/device/IO
- bundle detection MVP: same-endpoints-pair → suggestion
- sync model: DB authoritative, Excalidraw is a projection, manual
  import/export buttons with element-ID stability and conflict flagging
- five vertical slices for the coder shift, smallest end-to-end first
- nine open questions for m before code starts

Ends with DESIGN READY FOR REVIEW.
2026-05-15 12:26:27 +02:00