6.2 KiB
Start9 Packaging Log: Workout Log (from example to working 0.3.5 wrapper)
This file records exactly what was adapted from start9-example-packaging to package workout-planner for a Start9 server on StartOS 0.3.5 (Raspberry Pi / ARM64).
It is written as reusable documentation so you can repeat this process for future apps.
0) Goal and constraints
- Target now: StartOS
0.3.5on Raspberry Pi. - Future target: StartOS
0.4.0when stable. - Priority: package should work now, while keeping data layout and wrapper structure easy to migrate later.
1) What was reviewed first
Reviewed the existing example wrapper in start9-example-packaging/0.3.5:
manifest.yamlMakefileDockerfiledocker_entrypoint.shhealthcheck.shinstructions.mdREADME.mdDEPLOY_035.md
Then reviewed the app in workout-planner:
- App Docker build/runtime behavior (
workout-planner/Dockerfile) - DB shape + config (
prisma/schema.prisma,DATABASE_URLusage) - Health endpoint (
/api/health) - Seed/default user (
prisma/seed.ts)
2) New Start9 wrapper scaffold created
Created a new folder (separate from your example):
start9/0.3.5/start9/0.4/(planning placeholder)
Files created in start9/0.3.5:
manifest.yamlDockerfiledocker_entrypoint.shhealthcheck.shMakefileinstructions.mdREADME.mdDEPLOY_035.mdLICENSEicon.png(copied from app icon assets)
Also created:
start9/0.4/README.md(migration intent notes)
3) Key packaging design decisions
3.1 Keep persistent data in /data
To make upgrades/migrations safer, wrapper mounts Start9 volume at /data and stores SQLite DB at:
/data/app.db
This is the most important continuity contract for migration to a future wrapper.
3.2 Keep runtime app files out of persistent volume
App code/binaries stay in image layers; only state goes in /data. This prevents app updates from overwriting user data.
3.3 Health checks use app endpoint
Wrapper health check calls:
http://127.0.0.1:${PORT}/api/health
This checks both server and DB connectivity (as implemented by your app).
3.4 Backup/restore copies whole /data
Manifest backup/restore actions copy /data <-> /backup to align with Start9 expectations and keep DB safe.
3.5 Future 0.4.0 migration posture
Added explicit notes to preserve:
- package id (
workout-log) where compatible - DB path contract (
/data/app.db) - backup semantics
4) Runtime wiring added for first boot
In docker_entrypoint.sh:
- Ensures
/dataexists. - Uses
/data/app.dbasDATABASE_URLtarget. - If
/data/app.dbdoes not exist on first run, copies a seeded template DB from image (/app/prisma/data/app.db). - Starts app with
node /app/server.js.
Why this matters:
- First launch has a ready DB + default user.
- Subsequent restarts/upgrades keep existing
/data/app.dbuntouched.
5) Build issues discovered and fixes applied
Issue A: Prisma/OpenSSL runtime failure on ARM musl
Observed error during ARM container validation:
- Prisma engine expected OpenSSL compatibility; DB access failed.
Fix applied in wrapper Dockerfile:
- Install
opensslin builder stage. - Install
opensslin runner stage.
Result:
- Prisma client loads correctly at runtime.
Issue B: First-run DB missing tables (main.User does not exist)
Root cause:
- Repo
.dockerignoreexcludes local.dbfiles, so no seeded DB was copied from source tree.
Fix applied in wrapper Dockerfile build stage:
- Generate Prisma client.
- Create temporary DB:
DATABASE_URL=file:/tmp-seed/app.db npx prisma db push --skip-generate - Seed it:
DATABASE_URL=file:/tmp-seed/app.db npm run db:seed - Copy seeded DB into image:
/app/prisma/data/app.db
Result:
- First boot can copy seeded DB into
/data/app.db. - Health endpoint reports DB connected.
6) Validation steps run
Successfully validated:
-
ARM image build from wrapper:
make -C start9/0.3.5 image-arm
-
Local smoke run from built image tar:
docker load -i start9/0.3.5/image.tar- run container and query
/api/health
Final smoke result:
- HTTP
200 - JSON contained
status: okanddatabase: connected
7) Why start-sdk pack failed on this machine
start-sdk pack failed with:
fatal: not a git repository (or any of the parent directories): .git
Meaning:
start-sdkexpects to run from inside a Git repository so it can compute metadata (commit/hash).
This is unrelated to your app logic; it is a packaging environment requirement.
8) What “Step 1” means (plain English)
When I said “initialize under git,” I meant:
- The folder where you run
start-sdk packmust be inside a Git repo.
If your Workout-log folder is just a normal folder today, do this once:
cd /Users/macpro/Projects/Workout-log
git init
git add .
git commit -m "Initial commit for Start9 packaging"
After that, this should work:
make -C start9/0.3.5 package
You do not need your local dev server on port 3000 running for packaging. Packaging builds a Docker image and .s9pk artifact separately.
9) Install flow on StartOS 0.3.5
- Build package:
cd /Users/macpro/Projects/Workout-log
make -C start9/0.3.5 package
- In StartOS UI (0.3.5), sideload:
start9/0.3.5/workout-log.s9pk
-
Install + start service.
-
Open service UI and login:
admin@local/workout123
-
Change password immediately.
-
Run a manual backup.
10) Reusable checklist for your next app
Use this sequence next time:
- Copy known-good wrapper structure (
manifest,Dockerfile,entrypoint,healthcheck, docs, makefile). - Define persistent data contract first (
/data/...). - Ensure first boot initializes DB/schema (migration or seeded template).
- Verify health endpoint checks both app + DB.
- Build ARM image and smoke-test locally before Start9 sideload.
- Ensure repo is a Git repo before
start-sdk pack. - Document migration invariants for future StartOS versions (ID, DB path, backup format).
11) Files to edit before publishing/distributing
In start9/0.3.5/manifest.yaml, replace placeholder values:
wrapper-repoupstream-reposupport-sitemarketing-sitelicense(if you choose MIT or another license)