# Workshop — machine library, fault finder, community fixes

Build a section of isaac1804.com at `/machines`: a reference for the machines in
my workshop that explains how each one works, then helps diagnose it when it
does not, and lets visitors add the fix that actually worked.

## Content

- 12 machines: FDM 3D printer, diode laser cutter, CNC router, drill press,
  bandsaw, wood lathe, soldering station, multimeter, FPV quad, VEX IQ robot,
  air compressor, hot-wire cutter.
- Each machine: chain of energy/information (input → output), mechanism steps,
  subsystems that fail, safety lines, owner notes, and a fault finder.
- Fault finder entries are symptom (in the user's words) → most likely causes →
  what to measure → the fix. 58 entries total.
- A six-step diagnostic method page: stop, reproduce, narrow, measure, change one
  thing, write it down.

## Behaviour

- Library with category filters and search over names, symptoms and subsystems.
- Machine page with the fault finder as accordions, owner notes, safety block,
  and community fixes attached per symptom.
- Visitors submit a fix from any fault card (anonymous). Submissions are held for
  moderation. Isaac approves or rejects from a console behind a key, and can post
  directly as the owner.
- Approved fixes show on that symptom and in the all-fixes stream, sortable by
  newest or most helped; one vote per visitor per fix.

## Technical

- Cloudflare Worker + KV on the same domain, route `isaac1804.com/machines/*`,
  page and API on one origin. Vanilla HTML/CSS/JS, hash routing, no build step.
- Seed content compiled into the Worker (JS modules), never in KV, so a deploy
  cannot erase it. KV holds approved tips, the pending queue and overrides only.
- Every visitor write is rate limited, deduplicated, honeypot-guarded, and
  length-checked on the server.
- Approved-tip and pending feeds are single JSON keys read with `get()` so an
  approval is visible immediately instead of after the KV list cache expires.

## Verify

Post → queue → approve → visible → vote → delete, all against production; then
Playwright at 1440 / 768 / 390 checking console errors, 4xx, overflow and that
the mobile nav is at the bottom of the viewport. Read the screenshots by eye.

## V2 — machines that are not in the list

The seed catalogue is fixed at twelve. Visitors can add the rest:

- **Form** (`#/add`): name, exact model, category, one-line description, optional energy path,
  up to six faults (symptom / likely causes / what to check / the fix), up to three photos, optional name.
- **Model matters**: the same machine with a different board or bearing fails differently, and the
  rating plate is the only reliable identifier in a photo.
- **Photos**: no R2 on this account. Client decodes to canvas, long edge 1400 px, JPEG q0.72,
  steps down until the data URL fits ~600 KB. Server sniffs magic bytes (JPEG/PNG/WebP), 700 KB
  decoded cap, one `img:<id>` KV key each, served from `/api/img/<id>` as `immutable`, `nosniff`.
- **Moderation**: a second queue (`i:pmachines`) separate from fixes. Approve assigns a unique slug
  (`-2`, `-3` on collision), writes `m:<slug>`, and updates `i:machines` so the library sees it at once.
  Reject deletes the image keys with the record. Owner submissions skip the queue.
- **Undo**: deleting a built-in machine tombstones it; `POST /api/restore-machine` puts it back and the
  admin Machines tab lists removals with a Restore button.
