diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0451329 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,67 @@ +# 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=gunner npm start`. Default dev password is `gunner` (logs a warning). +- **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=gunner 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 — do not add a GitHub remote. (Repo currently has **no remote**; branch is `master`.) +- 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.6` → `0.1.7`); packaging-only → bump the revision (`0.1.6:0` → `0.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. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file