Initial commit for Start9 packaging
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
# Deploy on StartOS 0.3.5 (Raspberry Pi)
|
||||
|
||||
## 1) Build package on your Mac
|
||||
```bash
|
||||
cd /Users/macpro/Projects/Workout-log
|
||||
make -C start9/0.3.5 package
|
||||
```
|
||||
|
||||
This creates:
|
||||
- `start9/0.3.5/image.tar`
|
||||
- `start9/0.3.5/workout-log.s9pk`
|
||||
|
||||
## 2) Upload package to StartOS
|
||||
1. Open the StartOS web UI.
|
||||
2. Go to Services -> Sideload Package (0.3.5 menu naming may vary).
|
||||
3. Upload `workout-log.s9pk`.
|
||||
4. Install and start the service.
|
||||
|
||||
## 3) First run
|
||||
1. Open the service UI.
|
||||
2. Log in with `admin@local` / `workout123`.
|
||||
3. Change password and run one manual backup.
|
||||
|
||||
## 4) Data persistence contract
|
||||
- App DB path: `/data/app.db`
|
||||
|
||||
Because this lives in the persistent service volume, restarts and wrapper upgrades should not erase data.
|
||||
|
||||
## 5) Preparing for StartOS 0.4.0 migration
|
||||
1. Run a StartOS backup before migration.
|
||||
2. Keep `/data/app.db` contract unchanged in the future 0.4 wrapper.
|
||||
3. Preserve package id (`workout-log`) when possible to simplify migration continuity.
|
||||
@@ -0,0 +1,47 @@
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk add --no-cache openssl
|
||||
|
||||
COPY workout-planner/package.json workout-planner/package-lock.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY workout-planner/ ./
|
||||
RUN npx prisma generate
|
||||
RUN mkdir -p /tmp-seed \
|
||||
&& DATABASE_URL=file:/tmp-seed/app.db npx prisma db push --skip-generate \
|
||||
&& DATABASE_URL=file:/tmp-seed/app.db npm run db:seed
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk add --no-cache dumb-init curl openssl \
|
||||
&& addgroup -S nodejs -g 1001 \
|
||||
&& adduser -S nextjs -u 1001 -G nodejs
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
HOSTNAME=0.0.0.0 \
|
||||
PORT=3000 \
|
||||
WORKOUT_DATA_DIR=/data \
|
||||
WORKOUT_DB_PATH=/data/app.db \
|
||||
WORKOUT_SEED_DB_PATH=/app/prisma/data/app.db
|
||||
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
|
||||
COPY --from=builder --chown=nextjs:nodejs /tmp-seed/app.db /app/prisma/data/app.db
|
||||
COPY start9/0.3.5/docker_entrypoint.sh /usr/local/bin/docker_entrypoint.sh
|
||||
COPY start9/0.3.5/healthcheck.sh /usr/local/bin/healthcheck.sh
|
||||
|
||||
RUN chmod +x /usr/local/bin/docker_entrypoint.sh /usr/local/bin/healthcheck.sh \
|
||||
&& mkdir -p /data \
|
||||
&& chown -R nextjs:nodejs /app /data
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
ENTRYPOINT ["dumb-init", "--", "/usr/local/bin/docker_entrypoint.sh"]
|
||||
@@ -0,0 +1,4 @@
|
||||
All rights reserved.
|
||||
|
||||
This StartOS packaging wrapper and associated project materials are provided for
|
||||
internal/private use unless otherwise licensed by the repository owner.
|
||||
@@ -0,0 +1,23 @@
|
||||
PKG_ID := workout-log
|
||||
PKG_VERSION := 0.1.0.0
|
||||
REPO_ROOT := $(abspath ../..)
|
||||
WRAPPER_DIR := $(CURDIR)
|
||||
IMAGE_NAME := start9/$(PKG_ID)/main:$(PKG_VERSION)
|
||||
|
||||
.PHONY: image-arm package verify clean
|
||||
|
||||
image-arm:
|
||||
docker buildx build --platform=linux/arm64 \
|
||||
-f $(WRAPPER_DIR)/Dockerfile \
|
||||
-t $(IMAGE_NAME) \
|
||||
-o type=docker,dest=$(WRAPPER_DIR)/image.tar \
|
||||
$(REPO_ROOT)
|
||||
|
||||
package: image-arm
|
||||
start-sdk pack
|
||||
|
||||
verify:
|
||||
start-sdk verify s9pk $(PKG_ID).s9pk
|
||||
|
||||
clean:
|
||||
rm -f $(WRAPPER_DIR)/image.tar $(WRAPPER_DIR)/$(PKG_ID).s9pk
|
||||
@@ -0,0 +1,23 @@
|
||||
# Start9 Wrapper (0.3.5)
|
||||
|
||||
This directory contains the StartOS 0.3.5 package wrapper for Workout Log.
|
||||
|
||||
## Build prerequisites
|
||||
- Docker with buildx
|
||||
- `start-sdk` installed on build machine
|
||||
|
||||
## Build package
|
||||
```bash
|
||||
cd /Users/macpro/Projects/Workout-log
|
||||
make -C start9/0.3.5 package
|
||||
```
|
||||
|
||||
## Verify package
|
||||
```bash
|
||||
cd /Users/macpro/Projects/Workout-log
|
||||
make -C start9/0.3.5 verify
|
||||
```
|
||||
|
||||
## Outputs
|
||||
- `start9/0.3.5/image.tar`
|
||||
- `start9/0.3.5/workout-log.s9pk`
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
DATA_DIR="${WORKOUT_DATA_DIR:-/data}"
|
||||
DB_PATH="${WORKOUT_DB_PATH:-$DATA_DIR/app.db}"
|
||||
SEED_DB_PATH="${WORKOUT_SEED_DB_PATH:-/app/prisma/data/app.db}"
|
||||
|
||||
mkdir -p "$DATA_DIR"
|
||||
|
||||
if [ ! -f "$DB_PATH" ]; then
|
||||
if [ -f "$SEED_DB_PATH" ]; then
|
||||
cp "$SEED_DB_PATH" "$DB_PATH"
|
||||
else
|
||||
# Fallback if seed DB is unavailable.
|
||||
touch "$DB_PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
export DATABASE_URL="file:$DB_PATH"
|
||||
export NODE_ENV="${NODE_ENV:-production}"
|
||||
export HOSTNAME="${HOSTNAME:-0.0.0.0}"
|
||||
export PORT="${PORT:-3000}"
|
||||
|
||||
exec node /app/server.js
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
PORT="${PORT:-3000}"
|
||||
curl -fsS "http://127.0.0.1:${PORT}/api/health" >/dev/null
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
# Workout Log (StartOS 0.3.5)
|
||||
|
||||
## What this package does
|
||||
- Runs Workout Log as a private web app.
|
||||
- Persists all app data in the StartOS service volume (`/data`).
|
||||
- Exposes web UI/API on internal port `3000`.
|
||||
|
||||
## First launch
|
||||
1. Open the service UI from StartOS.
|
||||
2. Log in with default credentials: `admin@local` / `workout123`.
|
||||
3. Immediately change the password from inside the app (recommended).
|
||||
4. Run a manual StartOS backup after initial setup.
|
||||
|
||||
## Data safety
|
||||
- Database path in container: `/data/app.db`.
|
||||
- All persistent state is kept under `/data` for upgrade-safe persistence.
|
||||
|
||||
## Upgrade and migration note
|
||||
This 0.3.5 wrapper keeps runtime data separate from app/runtime files using `/data`.
|
||||
That makes migration to a future StartOS 0.4.0 wrapper straightforward as long as the
|
||||
wrapper continues to use the same data path contract.
|
||||
@@ -0,0 +1,94 @@
|
||||
id: workout-log
|
||||
title: Workout Log
|
||||
version: 0.1.0.0
|
||||
release-notes: >-
|
||||
Initial StartOS 0.3.5 package wrapper for Workout Log.
|
||||
license: Proprietary
|
||||
wrapper-repo: https://github.com/your-org/workout-log-startos
|
||||
upstream-repo: https://github.com/your-org/workout-log
|
||||
support-site: https://github.com/your-org/workout-log/issues
|
||||
marketing-site: https://github.com/your-org/workout-log
|
||||
build: ["make image-arm"]
|
||||
|
||||
description:
|
||||
short: Self-hosted workout planning and logging app.
|
||||
long: >-
|
||||
Workout Log is a self-hosted web app for planning workouts, logging sets,
|
||||
tracking progress, and managing exercises. This package keeps runtime data in
|
||||
the StartOS service volume for upgrade-safe persistence and future migration.
|
||||
|
||||
assets:
|
||||
license: LICENSE
|
||||
icon: icon.png
|
||||
instructions: instructions.md
|
||||
docker-images: image.tar
|
||||
|
||||
main:
|
||||
type: docker
|
||||
image: main
|
||||
entrypoint: docker_entrypoint.sh
|
||||
args: []
|
||||
mounts:
|
||||
main: /data
|
||||
|
||||
health-checks:
|
||||
main:
|
||||
name: API health
|
||||
success-message: Workout Log API is responding.
|
||||
type: docker
|
||||
image: main
|
||||
entrypoint: healthcheck.sh
|
||||
args: []
|
||||
inject: true
|
||||
|
||||
config: ~
|
||||
dependencies: {}
|
||||
|
||||
volumes:
|
||||
main:
|
||||
type: data
|
||||
|
||||
interfaces:
|
||||
main:
|
||||
name: Web Interface
|
||||
description: Browser UI and API for Workout Log.
|
||||
tor-config:
|
||||
port-mapping:
|
||||
80: "3000"
|
||||
lan-config:
|
||||
443:
|
||||
ssl: true
|
||||
internal: 3000
|
||||
ui: true
|
||||
protocols: [tcp, http, https]
|
||||
|
||||
backup:
|
||||
create:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
rm -rf /backup/*
|
||||
cp -a /data/. /backup/
|
||||
mounts:
|
||||
main: /data
|
||||
BACKUP: /backup
|
||||
restore:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
cp -a /backup/. /data/
|
||||
mounts:
|
||||
main: /data
|
||||
BACKUP: /backup
|
||||
|
||||
actions: {}
|
||||
@@ -0,0 +1,10 @@
|
||||
# Start9 Wrapper (0.4.0 planning)
|
||||
|
||||
This directory is reserved for the future StartOS 0.4.0 wrapper.
|
||||
|
||||
Migration intent from 0.3.5:
|
||||
- Keep package id as `workout-log` when StartOS 0.4.0 migration rules allow it.
|
||||
- Preserve persistent data contract at `/data/app.db`.
|
||||
- Reuse the same backup/restore semantics so migration is low-risk.
|
||||
|
||||
When 0.4.0 is stable, adapt manifest/build interfaces to the 0.4 schema and validate with the relevant Start9 docs.
|
||||
@@ -0,0 +1,235 @@
|
||||
# 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.5` on Raspberry Pi.
|
||||
- Future target: StartOS `0.4.0` when 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.yaml`
|
||||
- `Makefile`
|
||||
- `Dockerfile`
|
||||
- `docker_entrypoint.sh`
|
||||
- `healthcheck.sh`
|
||||
- `instructions.md`
|
||||
- `README.md`
|
||||
- `DEPLOY_035.md`
|
||||
|
||||
Then reviewed the app in `workout-planner`:
|
||||
|
||||
- App Docker build/runtime behavior (`workout-planner/Dockerfile`)
|
||||
- DB shape + config (`prisma/schema.prisma`, `DATABASE_URL` usage)
|
||||
- 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.yaml`
|
||||
- `Dockerfile`
|
||||
- `docker_entrypoint.sh`
|
||||
- `healthcheck.sh`
|
||||
- `Makefile`
|
||||
- `instructions.md`
|
||||
- `README.md`
|
||||
- `DEPLOY_035.md`
|
||||
- `LICENSE`
|
||||
- `icon.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 `/data` exists.
|
||||
- Uses `/data/app.db` as `DATABASE_URL` target.
|
||||
- If `/data/app.db` does 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.db` untouched.
|
||||
|
||||
## 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 `openssl` in **builder** stage.
|
||||
- Install `openssl` in **runner** stage.
|
||||
|
||||
Result:
|
||||
|
||||
- Prisma client loads correctly at runtime.
|
||||
|
||||
## Issue B: First-run DB missing tables (`main.User` does not exist)
|
||||
|
||||
Root cause:
|
||||
|
||||
- Repo `.dockerignore` excludes local `.db` files, so no seeded DB was copied from source tree.
|
||||
|
||||
Fix applied in wrapper `Dockerfile` build stage:
|
||||
|
||||
1. Generate Prisma client.
|
||||
2. Create temporary DB: `DATABASE_URL=file:/tmp-seed/app.db npx prisma db push --skip-generate`
|
||||
3. Seed it: `DATABASE_URL=file:/tmp-seed/app.db npm run db:seed`
|
||||
4. 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:
|
||||
|
||||
1. ARM image build from wrapper:
|
||||
- `make -C start9/0.3.5 image-arm`
|
||||
|
||||
2. 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: ok` and `database: 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-sdk` expects 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 pack` must be inside a Git repo.
|
||||
|
||||
If your `Workout-log` folder is just a normal folder today, do this once:
|
||||
|
||||
```bash
|
||||
cd /Users/macpro/Projects/Workout-log
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial commit for Start9 packaging"
|
||||
```
|
||||
|
||||
After that, this should work:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
1. Build package:
|
||||
|
||||
```bash
|
||||
cd /Users/macpro/Projects/Workout-log
|
||||
make -C start9/0.3.5 package
|
||||
```
|
||||
|
||||
2. In StartOS UI (0.3.5), sideload:
|
||||
|
||||
- `start9/0.3.5/workout-log.s9pk`
|
||||
|
||||
3. Install + start service.
|
||||
|
||||
4. Open service UI and login:
|
||||
|
||||
- `admin@local` / `workout123`
|
||||
|
||||
5. Change password immediately.
|
||||
|
||||
6. Run a manual backup.
|
||||
|
||||
## 10) Reusable checklist for your next app
|
||||
|
||||
Use this sequence next time:
|
||||
|
||||
1. Copy known-good wrapper structure (`manifest`, `Dockerfile`, `entrypoint`, `healthcheck`, docs, makefile).
|
||||
2. Define persistent data contract first (`/data/...`).
|
||||
3. Ensure first boot initializes DB/schema (migration or seeded template).
|
||||
4. Verify health endpoint checks both app + DB.
|
||||
5. Build ARM image and smoke-test locally before Start9 sideload.
|
||||
6. Ensure repo is a Git repo before `start-sdk pack`.
|
||||
7. 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-repo`
|
||||
- `upstream-repo`
|
||||
- `support-site`
|
||||
- `marketing-site`
|
||||
- `license` (if you choose MIT or another license)
|
||||
|
||||
Reference in New Issue
Block a user