# 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):
  <https://docs.start9.com/packaging/0.4.0.x/environment-setup.html>
- `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://<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.

```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.
