# mCables — Project Instructions ## Project Overview Cable-management **framework** for m's setup. Each cable-managed environment (LOFT, OFFICE, …) is a separate **mCables 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` **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. ## Goal - A reusable framework for tracking devices, ports, cables, cable types, bundles, frames — **scoped per project** (LOFT and OFFICE are separate projects, each a separate drawing). - A visual editor in the browser: switch projects, add frames/devices/ports, click ports to wire up cables, pick cable types from a per-project legend. - A one-way export from the DB to the corresponding `.excalidraw` drawing on `mxdrw.msbls.de` whenever m clicks Export — DB is authoritative, Excalidraw is the projection. - Bundle detection: parallel cables along the same path within a project get grouped + colour-bundled in the diagram. ## Architecture | Layer | Tech | Notes | |---|---|---| | DB | SQLite | `./data/mcables.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.) | ## Hierarchy - **Project** (`projects` table) is the top-level concept. LOFT, OFFICE, HOMELAB, … are separate projects. One project ↔ one `.excalidraw` drawing in mExDraw. `projects.drawing_name` defaults to `.excalidraw` server-side when omitted on create; editable later. - **Frames** sub-divide a project (LOFT has `desk`, `rack`, `media`; OFFICE has `desk`, `server`). Frames are not projects — they're zones within one drawing. - Every device, port, cable, IO marker, and bundle is **project-scoped** (`project_id` denormalised onto every row, with `ON DELETE CASCADE` from `projects`). `UNIQUE (project_id, devices.name)` — no two devices in one project share a name. - **Cable types are global.** A single shared `cable_types` table — no `project_id`. The five defaults (Power/USB/HDMI/DP/RJ45) are seeded by migration 001 once, not per project. Renaming or recolouring a type affects every project's legend immediately. - **Project deletion guardrail.** `DELETE /api/projects/:pid` requires `?confirm=` matching the project's current name. 400 otherwise. ## Branch Strategy - `main` = production-deployable. - `mai//` = worker branches via the mai workflow. - No `dev` branch — too small a project for staging. - Merge with `--no-ff` to main, delete branches after merge. ## Tech Stack - **Go** for the backend (matches m's other tools: `m`, `mai`, youpcms, mExDraw). - **SQLite** via `modernc.org/sqlite` (cgo-free → clean `scratch`/distroless container, no toolchain pain). - **mExDraw** via HTTP for diagram export. Never edit raw `.excalidraw` files directly outside the mExDraw API. - **Vanilla JS + SVG** for the frontend — no build step. JSDoc-typed. ## Deployment — mDock, raw docker (NOT Dokploy) mCables 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 Actions workflow on push to `main`, runs on the self-hosted runner on mDock with label `self-hosted:host`). - Port mapping: `7777:7777`, exposed on the LAN — no reverse proxy. - Restart policy: `unless-stopped`. - LAN URL: `http://mdock:7777`. - No auth — LAN-trusted. Local dev (no Docker): `go run ./cmd/mcables` against `./data/mcables.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 from scratch inside the tool — the seed exists so the **exporter** mimics its visual grammar: - **Devices** = rectangles with a text label. - **Ports** = small ellipses (~12×9) positioned on a device edge. Positional, *not* containerId-bound. Stroke colour = cable type. - **Cables** = arrows with `startBinding` / `endBinding` to ports or devices or IO diamonds. - **Cable types** = colour, with a legend at the top-left of the project's first frame listing the project's cable_types. - **IO markers** = small diamonds. Semantically **wall outlets / power entry points** — a cable terminating at an IO marker means "this end is plugged into a wall socket outside the diagram". They are *not* inter-frame bridges and they do *not* pair up. - **Frames** = sub-zones inside a project (`desk`, `rack`, `media`, …). - **Lines** = decorative only (legend separators in the seed). Ignored on export. Legend colours (global, seeded once by migration 001): | Type | Hex | |---|---| | Power | `#e03131` | | USB | `#2f9e44` | | HDMI | `#1971c2` | | DP | `#9c36b5` | | RJ45 | `#ffd500` | ## Out of scope (v0) - Multi-user. mCables 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 hot API endpoint. ## Worker Preferences - **First shift = inventor** (design pass): conventions, schema, API, export pipeline, mDock deploy plan, UI flows, slices. Output: `docs/design.md` + open questions for m. - **Second shift = coder** (after m's go on the design): bootstrap repo skeleton (Go module, SQLite migrations, server, exporter, frontend scaffold). Take slices 1–4 first (project CRUD, frames/devices, ports and cables, IO + cable-type editing); slice 5 (Excalidraw export) closes the round-trip. - Use **Sonnet** for both — greenfield, structure matters more than depth.