A generated matching card arrived on a phone with three identical definitions (the generation guards now drop those), but there was no way to get past a bad card from inside a session. The feed chrome (deck study, review, mistakes and exam) now has the red "!" control: one tap records the question, skips to the next card and shows an Undo toast. - lib/question-reports.ts: the local list (freezmo.reports.v1, zod on read, capped 200) is the skip state — reported cards leave every session type, count as "not attempted" in the results instead of wrong, and Undo takes a report back. A deck where everything is reported stays studiable so it can be regenerated. - POST /api/reports appends one JSON line per report to REPORTS_DIR/reports.jsonl (shared/freezmo/reports in production, the dev data dir in dev). Deliberately write-only: the question text is readable on the server (that is the point — prompt tuning) but never over HTTP, since the app has no auth. Best effort: offline reports stay local. - The button: a red outlined rounded square with "!", the chrome's control size, in both feed headers (hidden on the results slide). - config: REPORTS_DIR + RATE_LIMIT_REPORTS (20); the deploy creates the shared reports dir; the dev unit and AGENTS.md note the new server data location. - Suites: phase-1 (append + validation + no GET), phase-2 (button, toast, server POST, local copy, skip counter, hidden next session, Undo, exam pool). SW -> freezmo-v38.
3.2 KiB
3.2 KiB
AGENTS.md — working rules for this repo
Freezmo has two environments. Every session — human or agent — follows these rules. They are not optional: production is the app the user actually uses.
Environments
| Dev (this working tree) | Production | |
|---|---|---|
| Path | ~/freezmo (where you edit) |
~/freezmo-prod/current (release symlink) |
| Service | freezmo-dev.service |
freezmo.service |
| Port | 3217 (http://<lan-ip>:3217, LAN only) |
3207 + the public URL |
| Build folder | .next-dev (hot reload) |
.next/standalone inside the release |
| Data | ~/freezmo/.freezmo-dev/ |
~/freezmo-prod/shared/freezmo/ |
| Env | ~/freezmo/.env.local |
~/freezmo-prod/shared/env.local |
| Identity | DEV badge, dev favicon/theme, "Freezmo Dev" PWA | normal |
Dev runs next dev with hot reload; all live, real-time changes go there.
Production only ever runs a pushed, verified commit deployed by
scripts/deploy.sh (releases under ~/freezmo-prod/releases/, last 5 kept,
scripts/rollback.sh to go back).
Rules
- During a task, only the dev instance updates. Never restart or rebuild
production mid-task; production changes only through
scripts/deploy.shat the very end. - Never build into a running instance's folder. The dev service owns
.next-dev;npm run build(used by the test suites' spawned instances) owns.next; a release build owns its own release directory. Any build or test that needs a production build uses a temporary directory and port. - At the end of a task: run
npm run lint,npm run test:e2eandnpm run build, bump the service-worker cache (public/sw.js), update the README, commit, push tomain, then runscripts/deploy.sh. Production only ever runs a pushed, verified commit. scripts/deploy.shis the only deploy path. It refuses a dirty tree, refuses commits that aren't onorigin/main, runs lint + build + the full e2e suite against the new release on a temporary port, switches thecurrentsymlink atomically, health-checks/api/healthzfor the new commit and rolls back automatically on failure.- The Ollama API key never leaves the browser. It must never appear in
exports, sync payloads, share links, logs, URLs,
.envfiles committed to the repo, or release directories. Server data (sync blobs, push subscriptions, question reports) lives only undershared/. - Both languages, always. Every user-facing string goes into
lib/i18n-dict.tsin en and cs (the i18n test enforces key parity). - Phones are first-class: ≤639px layouts, 44px touch targets, 16px inputs, safe-area padding; verify at 360px and 390px as well as desktop.
- Versioned storage, never lose data. Deck/homework/chat schemas are validated with zod on read; backups and sync share the same payload schema.
- The test suites live in
tests/(npm run test:e2e, filterable:npm run test:e2e -- chat). Add or extend a suite for every feature; a green suite set is part of "done". Diagnostics that are not gates:tests/bubble-perf.mjs,tests/model-compare.mjs. - Keep the service worker honest: bump
CACHE_VERSIONinpublic/sw.jsfor every user-visible deploy (the deploy itself does not do this).