d4557304a5edabf3b4d94f78e2badef44ca46c0f
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f487204b73 |
v1.2.0:1 — upgrade to Next.js 15 / React 19
Closes the remaining P1: move off Next 14 onto the CVE-patched Next 15 line (15.5.x), eliminating the framework's RSC DoS/source-exposure advisories and the middleware-auth-bypass class that applied to the 14.x auth gate. App Router on Next 15 requires React 19, so react/react-dom move to 19.x in lockstep; lucide-react and next-themes bump to their React-19-compatible releases. The code surface was the Next 15 async-request-API change: params and searchParams are now Promises. All [id] route handlers (10 files) and the four server pages that read them now await the resolved value, using a uniform re-derive idiom that leaves handler bodies untouched. cookies()/ headers() were already awaited, so no other request-API changes were needed; all routes stay dynamic, so the uncached-by-default change is a no-op. next.config.js (static CSP) and the middleware matcher are unchanged. No schema, no API contract change, no data migration. Verified: tsc + lint clean, 209 tests pass, next build succeeds with the standalone bundle tracing the Prisma engine. |
||
|
|
3f22ef7600 |
v1.1.0:9 — P2 hardening: input-validation 400s, auth rate-limit, XFF anti-spoof, non-root container
P2 batch from the 2026-06-13 full-eval (EVALUATION.md / ROADMAP.md), reviewed by the reviewer agent. App-code + packaging only; no schema or data change, existing /data untouched. Input validation: malformed JSON bodies, invalid date, and out-of-range or non-numeric pagination on /api/workouts now return 400 instead of 500. New lib/http.ts readJsonBody maps a bad body to a ZodError across the 11 CRUD routes whose catch maps ZodError to 400; me/import and admin/signups guard request.json() in an explicit try/catch. Rate limiting: POST /api/auth now shares the UI login server action's per-IP 10-per-15min cap and returns 429 + Retry-After. clientIpFromHeaders reads the rightmost (trusted-proxy-appended) X-Forwarded-For entry instead of the spoofable leftmost. Container: drops root. The entrypoint prepares /data as root, chowns it to nextjs, then exec su-exec nextjs:nodejs node server.js (su-exec added to the runner image). The container drop needs live sideload verification. |
||
|
|
55c17614b8 |
v1.0.0:7 — exercise library cleanup, photo-import removal, AI-section honesty
Library JSON cleanup (proof-of-work/prisma/exercises.seed.json)
19 exercises corrected:
- Cycling/Jump Rope/Rowing/Running: type=cardio with proper
inputFields (duration/distance/calories — no more reps/weight).
- Walking Lunge/Wall Sit/Headstand/Hip Extension: reclassified
out of cardio into bodyweight.
- Plank/Mace warmup/Hollow Body Landmine/Soccer: inputFields
fixed.
- Descriptions added for ~10 cryptic exercises (Core, Resistance
Band, Stir the pot, Slide Board, Neck Circuit, TGU, Captains
of Crush, etc.).
Reconcile-on-boot (ensureExerciseLibrary.cjs)
Changed from INSERT-OR-IGNORE to INSERT-OR-UPDATE keyed on
(userId, name). Existing rows where isCustom = 0 get
description/type/muscleGroups/inputFields/defaultWeightUnit
refreshed from the curated JSON. Rows where isCustom = 1 are
skipped — user customizations always win.
Verified end-to-end: applied patches propagate to a copy of the
user's snapshot DB; manually-tampered isCustom=1 rows survive a
second reconcile pass untouched.
PATCH /api/exercises/[id] flips isCustom -> true on user edits
Once you edit a library exercise via the in-app UI, the row's
isCustom flag becomes 1 and the boot-time reconcile leaves it
alone forever. Closes the only failure mode where a maintainer
curated-library refresh could overwrite user edits.
Photo-import (Claude vision) removed
- app/api/workouts/import/route.ts deleted.
- components/import/WorkoutImportClient.tsx deleted (orphan
component — wasn't referenced anywhere by the live UI).
- CSV import (app/main/import → page-csv.tsx →
/api/workouts/import/save) is unchanged. The save endpoint
stays — it's used by the CSV flow too.
Settings UI: "Claude AI Integration" section removed
The toggle + API key input promised "personalized workout
recommendations" that the codebase never delivered (the only
actually-wired use was the photo-import we just removed).
Schema columns User.enableClaudeAI / User.claudeApiKey stay
as harmless dead fields — they'll get cleaned up or repurposed
when the model-agnostic AI work lands. The preferences API
no longer accepts or returns those fields.
No data migration. /data on existing installs is untouched.
v1.0.0:7 promoted to current; :1-:6 in other.
|
||
|
|
ffa8e0d480 |
v1.0.0:6 — paginate workout history (infinite scroll)
Two surfaces had invisible 50-row caps that this commit removes.
Exercise history popup (clock button in WorkoutForm):
- /api/exercises/[id] now accepts ?offset=N&limit=N (default 25,
max 100) and returns { exercise, history, hasMore }. Pagination
uses take: limit + 1 to detect hasMore without a second COUNT
round-trip.
- Query rewritten to use Prisma's setLogs.some filter — single SQL
that hits the (userId, deletedAt, date) composite index, instead
of fetching all set logs then grouping in JS.
- ExerciseHistoryPopup now uses an IntersectionObserver on a
sentinel div. When sentinel scrolls into view (root: the popup
itself, not the viewport), fetches next page and appends. Status
row at the bottom shows a spinner while loading and "End of
history" when done.
- Container max height bumped from h-64 -> h-80 for a bit more
breathing room on first render.
Workout history page (/main/workouts):
- Page still server-renders the first 50 workouts (instant paint
+ correct date filter forwarding). Now uses take: PAGE_SIZE + 1
to detect hasMore.
- New WorkoutsList client component takes initial workouts +
hasMore + filter values as props. IntersectionObserver on a
sentinel below the cards auto-fetches the next page from
/api/workouts?offset=N&limit=50&q=...&dateFrom=...&dateTo=...
when scrolled to. Filters round-trip through URL params, so a
filter change re-renders the page from scratch with a fresh
first page.
- "End of history · N workouts" line shown once everything is
loaded.
Tests:
- tests/routes-exercise-history.test.ts: 6 new tests covering
auth, cross-user 404, first-page hasMore=true, second-page
hasMore=false + no overlap, set-log filter scoped to the
queried exerciseId, soft-deleted workouts excluded.
- All 87 tests pass.
No schema changes, no migration. /data untouched.
|
||
|
|
aa407b5f67 |
Rebrand to Proof of Work; multi-user 0.4 package with curated library sync
Repo cleanup - Add top-level .gitignore (was missing; node_modules, .next, *.s9pk, image.tar, seed/data/*.db, log files, etc.) and a root README. - Delete legacy start9/0.3.5/ package (StartOS 0.3.5 wrapper, no longer the deploy target). - Delete start9-example-packaging/ (template from another project). - Delete planning docs (START9_PACKAGING_LOG.md, VERSIONING.md, STARTOS_0.4_UPGRADE_PROMPT.md, ICON_FILES_INDEX.md, etc.) — info now lives in the deploy guide and code comments. - Drop the standalone Dockerfile, docker-compose.yml, ICON_*, and dev log/build artifacts from the app dir. - Drop the v0.1.0:18/19/20 version files (they belonged to the legacy workout-log package and don't apply to the new id). Rename + new package - Rename app dir workout-planner/ -> proof-of-work/. - Rename StartOS package id workout-log -> proof-of-work; the new id makes this a brand new StartOS service (clean cutover from the old one rather than in-place upgrade). - Reset version graph; v1.0.0:1 is the seeded cutover release. The Dockerfile bakes a one-time /data snapshot and docker_entrypoint.sh copies it into the new volume on truly-fresh first boot only (both /data/app.db missing AND /data/.seeded absent). - Move start9/0.4-migration/ -> start9/0.4/; the old start9/0.4/ stub is gone. Curated exercise library (multi-user-aware) - proof-of-work/prisma/exercises.seed.json is the canonical library shipped to every install (164 exercises today, dumped from the live snapshot). - proof-of-work/scripts/sync-library.cjs (npm run sync-library) refreshes the JSON from start9/0.4/seed/data/app.db after refresh_seed.sh. - proof-of-work/prisma/seed.ts now reads from the JSON instead of a hardcoded 52-exercise array; runs at Docker build time to seed the fallback DB and on first boot for fresh installs. - proof-of-work/prisma/ensureExerciseLibrary.cjs runs on every container boot (from docker_entrypoint.sh) and INSERT OR IGNOREs every library entry for every user, keyed on (userId, name). Library updates flow to existing installs on package upgrade; user-custom exercises (isCustom=true) and any colliding names are never overwritten; removed exercises stay on existing installs (additive-only). Deploy guide (start9/0.4/DEPLOY_040.md) - Rewritten end-to-end for the workout-log -> proof-of-work cutover: refresh_seed, sync-library, build, sideload, verify, rotate creds, stop the old service, then post-cutover cleanup release v1.0.0:2. |