Commit Graph

7 Commits

Author SHA1 Message Date
mAi
28a376a7f3 fix(ui+server): tool cursor wins on canvas children; no-cache static assets
Issue 1 — cursor lies about armed tool. .svg-draggable { cursor: grab }
on frame/device rects beat the .canvas-wrap.tool-device #canvas {
cursor: crosshair } rule because element-level wins over descendant.
m saw "grab" hovering a frame with +Dev armed and thought the tool was
broken even though clicks routed correctly after the previous fix. Add
a descendant rule with !important so tool-armed wraps any child cursor:
  .canvas-wrap.tool-frame  #canvas *,
  .canvas-wrap.tool-device #canvas * { cursor: crosshair !important; }

Issue 2 — stale browser cache after each redeploy. http.FileServerFS
served embedded assets with no Cache-Control header, so browsers held
on to the previous main.js/style.css until hard-reload. New noCache
middleware on the static handler emits Cache-Control: no-cache. Note:
embedded FS files have zero ModTime, so http.FileServer suppresses
Last-Modified — every fetch is a fresh 200 rather than a 304. Fine at
~30KB of JS+CSS, and fixes the staleness problem completely.

Middleware is wrapped only around the static handler. /api/* responses
write their own headers and aren't touched.

Verified locally:
  curl -I /main.js   → Cache-Control: no-cache
  curl -I /style.css → Cache-Control: no-cache + contains the new rule
  curl -I /api/healthz → unaffected (no Cache-Control from us)
go test -race ./... still green.
2026-05-15 20:38:48 +02:00
mAi
21bf00566c feat: http handlers — frames + devices CRUD under /api/projects/:pid/
All 8 endpoints (list, create, patch, delete) for both resources. Path
params parsed via Go 1.22 ServeMux PathValue.

devicePatch uses json.RawMessage for frame_id so the wire format
distinguishes:
  - key absent       → leave as-is
  - "frame_id": null → clear (device leaves all frames)
  - "frame_id": 42   → move to that frame
parseFrameRef translates that into the store's db.FrameRef tri-state.

Sentinel-error mapping unchanged (writeError covers ErrInvalidInput,
ErrConflict, ErrNotFound, etc.). Cross-project frame_id refs surface as
400.
2026-05-15 18:17:43 +02:00
mAi
cf1671e8c1 feat: db store — frames + devices CRUD, project-scoped
Snapshot now populates frames + devices from the DB (slice 1 left them as
empty arrays).

Frame store:
- CreateFrame requires positive width/height; rejects empty name; UNIQUE
  (project_id, name) collisions surface as ErrConflict via mapWriteErr.
- GetFrame is project-scoped — wrong-project read returns ErrNotFound.
- UpdateFrame applies a partial; project_id is not exposed (moving a
  frame across projects would orphan its devices).
- DeleteFrame relies on the schema's ON DELETE SET NULL to drop
  devices' frame_id refs cleanly; verified by test.

Device store:
- CreateDevice defaults color to #1e1e1e if blank; rejects empty name,
  non-positive size; validates frame_id is in the same project (returns
  ErrInvalidInput on cross-project ref).
- UpdateDevice uses a FrameRef tri-state for frame_id so callers can
  distinguish "leave alone" from "clear to NULL" from "move to frame X".
- Cross-project frame_id on PATCH is rejected with ErrInvalidInput.
- ListDevices supports an optional frame_id filter.

13 new table-driven tests, all green with -race.
2026-05-15 18:16:33 +02:00
mAi
905c75c6db test+docs: store coverage + README for slice 1
Adds table-driven store tests:
- projects: drawing_name auto-default, explicit-name accept, empty-name
  reject, duplicate-name conflict, ordered list, GetProject not-found,
  partial PATCH semantics, blank-drawing-name re-default on PATCH,
  ?confirm=<name> guardrail (wrong / empty / correct), snapshot returns
  the 5 globally-seeded cable_types
- cable_types: 5 seeded with the legend colours, global UNIQUE(name),
  rename + recolour, RESTRICT-blocked delete when a cable references the
  type (with count surfaced via CountCablesUsingType), unused delete
  succeeds, project deletion does NOT cascade into cable_types

go test -race ./... passes. Updates README.md with run instructions,
env vars, the slice-1 API surface, and the slice roadmap.
2026-05-15 16:48:29 +02:00
mAi
1e3988161b feat: http server — net/http (Go 1.22 ServeMux), /api/healthz + projects + cable-types, JSON errors 2026-05-15 16:45:29 +02:00
mAi
255d52e7c4 feat: db store — projects + cable_types CRUD with sentinel errors and confirm-name guardrail 2026-05-15 16:45:29 +02:00
mAi
cd34dde133 feat: db migrations runner + 001_init.sql (full v3 schema, 5 cable_types seeded) 2026-05-15 16:45:29 +02:00