86 lines
4.1 KiB
Markdown
86 lines
4.1 KiB
Markdown
# ⚽ Premier Gunner
|
|
|
|
A kid-friendly, mobile-friendly soccer training tracker. Gunner logs what he trains each
|
|
day, plans his week, chases goals, and watches the **Road to London** thermometer fill up
|
|
toward the reward: a trip to see Arsenal play in person. Installable as a PWA on his phone.
|
|
|
|
## Features
|
|
|
|
- **Single-password login** — everything lives behind one password.
|
|
- **Daily logging** — tap a category pill, bump the metric steppers (juggles, minutes,
|
|
shots, …), add optional notes. Almost no typing.
|
|
- **Categories Gunner controls** — Juggling, Left Foot, Shooting, Soccer Tennis, Dribbling
|
|
Drills, Soccer Golf, Backyard with Dad, 1-on-1 with Elijah, EPA Agility & Speed — and he
|
|
can add/edit/archive his own in Settings.
|
|
- **Weekly planning** — set objectives for upcoming days; stick to them or change his mind.
|
|
- **Dashboard** — total sessions, training days, streaks, a GitHub-style calendar heatmap,
|
|
a radar chart of training spread, line charts of improvement over time, goal progress
|
|
bars, and the main-goal thermometer.
|
|
- **Goals** — overall or per-category, by number of sessions, personal best, or running
|
|
total. Flag one as the ⭐ main goal to drive the thermometer.
|
|
- **PWA** — installable, offline app shell, custom Arsenal-red cannon icon.
|
|
|
|
## Tech
|
|
|
|
Node.js + Fastify + better-sqlite3 on the backend; a no-build vanilla-JS PWA frontend with
|
|
Chart.js (vendored locally). All data in a single SQLite file. No external services.
|
|
|
|
## Run locally
|
|
|
|
```bash
|
|
npm install
|
|
PG_PASSWORD=your-password npm start
|
|
# open http://localhost:3000 (default password is "gunner" if PG_PASSWORD is unset)
|
|
```
|
|
|
|
To start fresh, stop the server and delete the `data/` folder — categories and the starter
|
|
goals re-seed on next boot.
|
|
|
|
## Configuration (environment variables)
|
|
|
|
| Var | Default | Purpose |
|
|
| ------------------ | ------------------ | -------------------------------------------------- |
|
|
| `PG_PORT` | `3000` | HTTP port |
|
|
| `PG_HOST` | `0.0.0.0` | Bind address |
|
|
| `PG_DATA_DIR` | `./data` | Where the SQLite DB + WAL live (persist this!) |
|
|
| `PG_PASSWORD` | `gunner` (dev) | Plaintext password, hashed on first boot |
|
|
| `PG_PASSWORD_HASH` | — | Pre-computed bcrypt hash (preferred for prod) |
|
|
| `PG_COOKIE_SECRET` | auto-generated | Session cookie signing secret (persisted if unset) |
|
|
| `PG_SESSION_DAYS` | `30` | How long a login stays valid |
|
|
|
|
The password can also be changed in-app under ⚙️ Settings.
|
|
|
|
## Phase 2 — not yet built
|
|
|
|
These were intentionally deferred (see the plan in chat):
|
|
|
|
1. **StartOS 0.4.0 service package** — wrap this in an s9pk so it installs on Start9, with
|
|
`PG_DATA_DIR` mounted on a persistent volume and the password exposed as a service config
|
|
field. Serve it on the clearnet domain via Start9 pages + StartTunnel.
|
|
Docs: https://docs.start9.com/packaging/0.4.0.x/ · https://docs.start9.com/start-tunnel/1.0.x/
|
|
2. **DGX Spark (Qwen3.6) AI coach** — a server-side proxy to the OpenAI-compatible endpoint
|
|
that, on login, reviews Gunner's objectives + full history and suggests what to train and
|
|
how to plan ahead; plus on-demand drill ideas per category. Kept server-side so the
|
|
endpoint and any key never reach the browser.
|
|
|
|
## Project layout
|
|
|
|
```
|
|
src/
|
|
server.js Fastify app, auth gate, route wiring
|
|
config.js env-driven config + data dir
|
|
db.js SQLite connection + schema bootstrap
|
|
schema.sql tables
|
|
seed.js default categories + starter goals
|
|
auth.js password hashing, sessions
|
|
routes/ auth, categories, entries, plans, goals, stats
|
|
public/
|
|
index.html app shell (tabs: Today / Plan / Stats / Goals)
|
|
login.html
|
|
css/styles.css
|
|
js/app.js views: logging, planning, goals, settings
|
|
js/dashboard.js charts, heatmap, thermometer
|
|
js/api.js fetch wrapper
|
|
manifest.webmanifest, sw.js, icons/
|
|
```
|