Files
premier-gunner/AGENTS.md
T
Keysat 9f9358d64b Document current state and roadmap
- AGENTS.md: add Current state section; record Gitea origin; scrub the
  dev password example to a placeholder and the deploy host to a config
  reference.
- Add ROADMAP.md for longer-term backlog and deferred decisions.
2026-06-13 15:00:20 -05:00

6.7 KiB

AGENTS.md

Kid-friendly soccer training tracker PWA for one player ("Gunner"), packaged as a StartOS 0.4.x .s9pk service.

Stack (versions that matter)

  • Backend: Node.js (ESM, "type":"module") + Fastify 5, better-sqlite3 11, bcryptjs 3, @fastify/cookie 11, @fastify/static 8. No build step.
  • Frontend: vanilla-JS PWA — no framework, no bundler. Chart.js v4 vendored at public/vendor/chart.umd.min.js. Service worker at public/sw.js.
  • Packaging (s9pk/): @start9labs/start-sdk 1.5.3 (TypeScript), bundled with @vercel/ncc, packed with start-cli (0.4.0-beta). Targets StartOS 0.4.x. Image built locally via Dockerfile (Node 22), x86_64 only.

Commands

Run from repo root unless noted.

  • Run (dev): npm run dev (node --watch) or npm start — listens on PG_PORT (default 3000). Local: PG_PORT=3344 PG_PASSWORD=<dev-password> npm start. If PG_PASSWORD is unset, the app uses a built-in dev fallback and logs a warning — set it explicitly.
  • Seed defaults: npm run seed (only seeds an empty DB).
  • Tests: none configured — TODO. Verify manually: boot against a temp DB and hit the API, e.g. PG_DATA_DIR=/tmp/pg PG_PORT=3399 PG_PASSWORD=<dev-password> node src/server.js then curl/login. No single-test runner — TODO.
  • Lint (root): none configured — TODO.
  • Typecheck + format (s9pk): cd s9pk && npm run check (tsc --noEmit) and npm run prettier.
  • Build .s9pk: cd s9pk && npm ci && make (vendors the app, builds the image, packs premier-gunner_x86_64.s9pk).
  • Deploy to StartOS: cd s9pk && make install (installs newest .s9pk to the host in ~/.startos/config.yaml). Status reaches installed via start-cli package list.

Directory layout

  • src/ — backend. server.js (Fastify app + /api/* auth gate), config.js (env), db.js (applies schema.sql + runs migrations), schema.sql, seed.js, auth.js, routes/{auth,categories,entries,plans,goals,stats}.js.
  • public/ — frontend. index.html, login.html, js/{app.js,api.js,dashboard.js}, css/styles.css, sw.js, manifest.webmanifest, icons/, vendor/.
  • s9pk/ — StartOS package. Dockerfile, Makefile (edit here), s9pk.mk (do not edit), startos/ (manifest/, main.ts, interfaces.ts, actions/, fileModels/store.ts, versions/current.ts, i18n/), instructions.md, README.md, TODO.md.
  • s9pk/app/ — generated copy of the app made by make prep; gitignored, do not edit.
  • data/ — runtime SQLite (premier-gunner.db); gitignored.

Data model notes

  • Metrics live in category_metrics; kind is one of count | duration | score | decimal. Records are track_record (bool) + record (REAL) on the metric; bumped automatically when a logged value beats them (respecting higher_is_better).
  • Entries: one row per logged session (entries, with note); metric readings in entry_values.

Config (env-var names only — never hardcode secrets)

PG_HOST, PG_PORT, PG_DATA_DIR, PG_PASSWORD, PG_PASSWORD_HASH, PG_COOKIE_SECRET, PG_SESSION_DAYS. NODE_ENV=production enables the Secure session cookie (requires HTTPS). On StartOS, PG_PASSWORD is injected from store.json and is authoritative (re-hashed every boot); change it via the "Set Login Password" action.

Conventions

  • Commits: imperative subject; body only when the "why" isn't obvious; author is the user, no AI attribution. No Co-Authored-By/"Generated with" trailers.
  • Remote: self-hosted Gitea, not GitHub — origin is configured in .git/config (an SSH URL; keep it out of tracked files). Do not add a GitHub remote. Branch is master; push after committing.
  • Match existing file conventions; small reviewable diffs; comments explain why.
  • Verify browser-observable changes before shipping (run it, check no console errors).

Always

  • Bump s9pk/startos/versions/current.ts version on every rebuild that changes anything — StartOS won't register an update otherwise. Code change → bump semver (0.1.60.1.7); packaging-only → bump the revision (0.1.6:00.1.6:1).
  • Bump the CACHE constant in public/sw.js whenever frontend assets change, so installed PWAs update.
  • For DB changes, edit schema.sql (fresh installs) and add an idempotent migration in src/db.js guarded by a settings flag (existing DBs) and update src/seed.js.
  • Run cd s9pk && npm run check after editing startos/*.ts.
  • Keep i18n in sync: every i18n('x') must be a key in startos/i18n/dictionaries/default.ts, with all indices present for es_ES, de_DE, pl_PL, fr_FR in translations.ts, or tsc fails.

Never

  • Never edit s9pk/s9pk.mk (plumbing) or s9pk/app/ (generated). Makefile overrides go above the include s9pk.mk line.
  • Never rely on schema.sql alone for changes to existing databases — CREATE TABLE IF NOT EXISTS won't ALTER; add a migration.
  • Never build/ship aarch64 — target is x86_64 only (ARCHES := x86, manifest arch: ['x86_64']).
  • Never add AI co-authorship trailers to commits; never add a GitHub remote; never force-push or commit to a shared branch unless asked.
  • Never commit secrets, data/, node_modules/, or *.s9pk (all gitignored). Reference env-var names instead.

Gotchas

  • start-cli (and make install) needs a git repo with at least one commit — it stamps the build with the git hash.
  • make install picks the newest *.s9pk by mtime; with x86-only there's just one.
  • Migrations key off a flag row in the settings table (e.g. migr_records_scores); pick a new flag name per migration.

Current state

Live on StartOS (deploy host set in ~/.startos/config.yaml host:, not in this repo) at v0.1.6:0; make install deploys and the PWA self-updates via the in-app banner. Pushed to self-hosted Gitea (origin).

  • Working: daily logging, weekly planning, goals + thermometer, dashboard (streak calendar, radar, line/series charts, records), personal-best records (auto + manual set), per-session notes, EPA Max/Weighted Speed, tap-to-type number fields, full category/metric management in Settings, "Set Login Password" action.
  • In progress: none — all requested features are built, committed, and deployed.
  • Decided, not yet done: reconcile in-app password change with the StartOS action (env wins on restart); optional "log another" for a second same-category session in a day. See ROADMAP.md.
  • Known issues: changing the password from the app's own Settings reverts on restart under StartOS — use the action.
  • Next steps: (1) set a real login password via the "Set Login Password" action; (2) confirm speed unit (mph vs km/h); (3) decide whether to add a "log another" same-category session.