M3 Review→Publish UI (#77): one-column flow, searchable pickers, fig/feat tags, e2e

- Review screen: slug-resolved species/wcat groupers, case-insensitive attrs,
  fig-*/feat-* tag pickers (METADATA-30/40), AI-assist labels + AI bubbles.
- App orchestrator: single writable flow store, capture→review→publish, Resume boot.
- API client (slabs.ts) mirroring live backend routes; Blob name fix.
- Playwright e2e (7 tests, hermetic mock): canvas PNG seed, client-UUID mock,
  SKU blur commit, ready-state reactive fix; expect timeout 4s, 2 workers.
- e2e green 7/7 in 6s; check_requirements + check_coverage PASS.
This commit is contained in:
Ty
2026-09-20 14:34:24 -07:00
parent 2e2be48154
commit 1133201f30
12 changed files with 1996 additions and 275 deletions
+34
View File
@@ -14,6 +14,32 @@
- Subagents run on one local GPU and cannot handle concurrency. Invoke one at a time; never in parallel.
## Build & test (verified commands)
Frontend (`frontend/`, Svelte 4 + Vite + TS, no router):
```
cd frontend && npm install
npm run test # node --import tsx --test src/**/*.test.ts (unit)
npm run build # tsc --noEmit && vite build (type-check + build)
npm run test:e2e # playwright test (see Pitfalls: mocks the API)
```
Backend (`backend/`, FastAPI + stdlib sqlite, no ORM, deps pinned in `backend/requirements.txt`):
```
cd backend && python -m pytest tests/ -q
uvicorn backend.app:app --host 127.0.0.1 --port 18081
```
No Makefile, no CI workflows, no Gitea CI — nothing runs in a pipeline; the only automation is the local commands above plus the human UAT walk (`deploy/uat_walk.sh`).
## Conventions
- The LIVE FastAPI routes in `backend/*.py` are the API source of truth; `docs/contracts/API.md` is aspirational and can drift (it describes a polling model the backend never shipped). Read the router, not the doc, before wiring a client.
- Frontend is one Svelte app, no router: `App.svelte` switches on a `writable` flow store. Screens live under `frontend/src/<area>/`.
- Commit subjects: `feat(scope): …` / `fix(scope): …` / `test(scope): …` / `chore(scope): …`, often citing a requirement ID or Gitea number.
## Gates (must pass before claiming work complete)
Run from repo root:
@@ -25,6 +51,14 @@ python tools/check_coverage.py
Exit 0 on both = pass.
## Pitfalls
- E2E mocks the API: `tests/e2e/*.spec.ts` use Playwright `page.route('**/api/v1/**')` with fixture ids — there is **no live backend** under e2e. A green `test:e2e` is not proof the real backend works; that's the human `deploy/uat_walk.sh` (real Woo, never a mock — QUALITY-105).
- Ports on the 5060 UAT host (192.168.1.202): FastAPI `18083`, FE `18082`/`10881` are typically already up (compose on `deploy/docker-compose.yml`). Check before binding; don't assume `18081` is free.
- `SLAB_UAT_UNMASK_SECRETS=1` makes `GET /settings` return decrypted Woo/inference secrets — dev-test only, never set in prod (SETTINGS-75 masking is the default).
- Never hardcode live Woo category/term ids into app code (QUALITY-105 / METADATA-5); resolve groupers by slug (`species`, `wcat`) at runtime.
- `tsc` won't catch Svelte template errors; `npm run build` (which runs `tsc --noEmit`) is the real type gate for the frontend.
## Pointers (read these for everything else)
- Docs map and shipped status: `docs/README.md`