# 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: - Node.js >= 20 and npm - Docker with `buildx` - `start-cli` from Start9 (SDK): - `jq`, `make`, `git`, `sqlite3`, `rsync`, `ssh` - Reachable SSH access to your existing `workout-log` host One-time `start-cli` key setup: ```sh start-cli init-key ``` `~/.startos/config.yaml` should contain at least: ```yaml host: http://.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. ```sh ./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: ```sh 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 ```sh 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) ```sh 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: ```sh 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.