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.
This commit is contained in:
mAi
2026-05-15 16:32:20 +02:00
parent 023bf82dbd
commit c690113ea1
2 changed files with 113 additions and 84 deletions

View File

@@ -40,13 +40,21 @@ interface. The backend serves the UI and the API; there is no
- **Project** (`projects` table) is the top-level concept. LOFT, OFFICE,
HOMELAB, … are separate projects. One project ↔ one `.excalidraw`
drawing in mExDraw.
drawing in mExDraw. `projects.drawing_name` defaults to
`<name>.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, cable type, IO marker, and bundle is
project-scoped (`project_id` denormalised onto every row, with
`ON DELETE CASCADE` from `projects`).
- 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=<name>` matching the project's current name. 400 otherwise.
## Branch Strategy
@@ -106,7 +114,7 @@ its visual grammar:
- **Lines** = decorative only (legend separators in the seed). Ignored on
export.
Legend colours (per-project default seed when a project is created):
Legend colours (global, seeded once by migration 001):
| Type | Hex |
|---|---|