Files
proof-of-work/start9/0.4/DEPLOY_040.md
T
Keysat 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.
2026-05-08 20:12:25 -05:00

9.0 KiB

Deploy Proof of Work on StartOS 0.4 (sideload)

This guide walks the maintainer through cutting over from the legacy workout-log package to the new proof-of-work package. They share the same upstream code and on-disk schema, but proof-of-work is a brand new StartOS service (different package id), so StartOS treats it as a fresh install. Data preservation is handled by baking a one-time snapshot of your live workout-log /data volume into the proof-of-work v1.0.0:1 image and copying it into the new volume on first boot.

Your existing workout-log install stays running and untouched the whole time. The cutover is one-way only after you stop and uninstall it; until then you can fall back to it.

NEVER click Uninstall on either package mid-cutover. Uninstall destroys the volume. Use Stop instead. Only Uninstall after you've verified proof-of-work is happy.


0) Prereqs on your build machine

You need:

One-time start-cli key setup:

start-cli init-key

~/.startos/config.yaml should contain at least:

host: http://<your-04-host>.local

make install uses this to push the .s9pk to the target.


1) Refresh the seed snapshot from your live workout-log host

The repo includes start9/0.4/seed/data/app.db as a placeholder so the build works without network access, but for an actual cutover you should pull a fresh snapshot from your live host first.

./start9/0.4/refresh_seed.sh embassy@embassy.local

For a 0.3.5 host this auto-detects /embassy-data/package-data/volumes/workout-log/data/main/. For a 0.4 host pass the volume path explicitly as arg 2 — get it from start-cli package shell workout-log and df inside the container, or from the StartOS docs.

Refresh prints expected row counts and runs PRAGMA integrity_check. If anything looks off, fix the source before proceeding.


2) (Optional) Refresh the curated exercise library JSON

The shared library that ships with the package is generated from the same snapshot. After refresh_seed.sh, regenerate the JSON if you've added new exercises in the running app:

cd proof-of-work
npm run sync-library
git diff prisma/exercises.seed.json   # eyeball the new rows

Commit the JSON change before building so it's baked into the image.


3) Build the package

cd start9/0.4
npm ci
make clean
make x86

On success you'll get an artifact at:

start9/0.4/proof-of-work_x86_64.s9pk

4) Sideload on the 0.4 host

Option A — make install (fastest)

make install

Option B — StartOS web UI

  1. Open the StartOS 0.4 web UI on the target host.
  2. System -> Sideload Service.
  3. Upload start9/0.4/proof-of-work_x86_64.s9pk.
  4. Click Install, then Start.

workout-log and proof-of-work will appear as two separate services in the UI. Both can be running simultaneously — they have different volumes, different ports the SDK assigns, and no shared state.


5) First-boot verification

5a. Confirm the seed branch ran

In Services -> Proof of Work -> Logs, or via CLI:

start-cli package logs proof-of-work | grep '\[entrypoint\]'

On the very first boot you should see:

[entrypoint] no /data/app.db and no .seeded marker; copying baked cutover seed from /app/seed/data/app.db
[entrypoint] ensuring curated exercise library is present for every user
[ensure-library] processed 1 user(s) x 164 exercise(s) (164 INSERT OR IGNORE statements)
[entrypoint] launching Next.js on :3000 with DATABASE_URL=file:/data/app.db

Subsequent boots:

[entrypoint] /data/app.db already present; live data is the source of truth
[entrypoint] found .seeded: seeded from baked cutover snapshot at 2026-...
[ensure-library] processed N user(s) x 164 exercise(s)

5b. Log into the app

Open the web UI from the StartOS service page and log in with the same credentials you used on the legacy workout-log install (the bcrypt hash came over with the snapshot, so existing passwords keep working).

Default seed credentials (only on a brand-new install with no baked seed): admin@local / workout123 — change immediately via the action in section 6.

5c. Spot-check the data

  • Workouts count matches your old install (run-counts in the refresh_seed.sh output were the source of truth).
  • Exercise library shows your 164 exercises.
  • Open a recent workout and confirm set logs match.

5d. Run a StartOS backup

Services -> Proof of Work -> Backup -> Create Backup. Confirm it completes. This validates Backups.ofVolumes('main') wiring on the new package.


6) Rotate admin credentials

Stop the service first (action is gated on allowedStatuses: only-stopped):

  1. Services -> Proof of Work -> Stop
  2. Actions -> Change admin credentials
  3. Fill in new email, new password, confirm. Submit.
  4. Start the service and log in with the new credentials.

7) Stop the legacy workout-log service

Once you've used proof-of-work for at least a session and confirmed nothing's missing:

  1. Services -> Workout Log -> Stop

DO NOT Uninstall yet. Keeping the old service installed (just stopped) preserves its /data volume in case you need to re-pull the snapshot or roll back. Once you're confident (a week is plenty), Uninstall to free the volume.


8) Post-cutover cleanup release (v1.0.0:2)

After a few days running on proof-of-work with no surprises, ship a cleanup release that:

  • Strips COPY start9/0.4/seed/data /app/seed/data from the Dockerfile.
  • Strips the seed-copy branch out of docker_entrypoint.sh (keep the fallback DB branch and the ensure-library step).
  • Leaves seed/ and refresh_seed.sh on disk as historical artifacts.
  • Adds startos/versions/v1.0.0.2.ts (empty up/down migrations) and promotes it to current in the version graph; v1.0.0:1 moves to other.

Reason: once /data is the sole source of truth, a baked seed in the image becomes a foot-gun — removing it eliminates any chance of a future upgrade accidentally stomping live data.


9) Library updates after cutover (steady state)

# add new exercises in the running app, then:
./start9/0.4/refresh_seed.sh embassy@embassy.local
cd proof-of-work && npm run sync-library
git add prisma/exercises.seed.json
# bump the build rev in start9/0.4/startos/versions, add a new version file,
# commit, then:
cd start9/0.4 && make clean && make x86 && make install

On every upgrade, every user on the instance picks up the new exercises on first boot via the INSERT OR IGNORE step. Custom exercises a user added themselves are never overwritten.


10) Troubleshooting

Symptom Likely cause Fix
Login fails with your workout-log password Snapshot was pulled from a stale source Re-run refresh_seed.sh against your live host and rebuild.
Workouts missing after cutover Same Same.
/data/app.db is empty after first boot .seeded marker present without the DB (corrupted prior boot) start-cli package shell proof-of-work, rm /data/.seeded, restart.
Service never reaches Ready Port 3000 not listening Check logs: Prisma or Next.js threw at boot. Verify the DB file isn't zero bytes.
[ensure-library] WARNING sqlite3 failed to apply the curated library Inspect /data/app.db and the JSON. Boot continues; library updates skipped this cycle.
Container exits immediately Build context wrong — proof-of-work/ not visible to Docker Run make from start9/0.4/, not the repo root.
make x86 fails with No rule to make target .git/HEAD s9pk.mk's awk grabbed two id: matches and concatenated BASE_NAME Confirm manifest/index.ts has only one id: line. The shipped s9pk.mk uses {print $$2; exit} which already guards this.
Docker fails with ERROR: failed to build: resolve : lstat start9: no such file or directory dockerBuild.dockerfile was set to a path including start9/0.4/ The shipped manifest sets dockerfile: './Dockerfile'. The dockerfile field is resolved relative to the package dir, not relative to workdir.

11) Data-preservation summary

  • Volume name (main), mount path (/data), DB path (/data/app.db), internal port (3000): identical to the legacy workout-log package.
  • Package id changed: workout-log -> proof-of-work. StartOS treats this as a brand new service. Migration is via the baked seed in v1.0.0:1, not via in-place upgrade.
  • Seed only writes to /data on truly-fresh first boot (both app.db missing AND .seeded marker absent).
  • Library updates (new exercises) flow to every user on every upgrade via additive INSERT OR IGNORE. Never deletes; never overwrites a user's own custom exercises.
  • StartOS Backup captures /data in full.
  • Uninstall destroys /data. The alertUpdate copy reminds users.