From 103ba3cb5dcfd70acf4286d4b378e3217e72bddc Mon Sep 17 00:00:00 2001 From: Rene De Ren Date: Wed, 20 May 2026 11:05:06 +0200 Subject: [PATCH] build: tighten Docker setup for local-stack parity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Dockerfile: npm ci (uses package-lock for reproducible installs) - CMD now: migrate → seed (idempotent) → start. Gated by SEED_ON_BOOT. - docker-compose: name: helix, healthcheck on /, OAuth env defaults to empty so `docker compose up` works without a .env (public pages render; sign-in fails until OAuth is configured). - README: explicit "Run it locally — two ways" section. Docker first (production-like), native Node second. Documents port-conflict workaround and Gitea OAuth setup. Co-Authored-By: Claude Opus 4.7 (1M context) --- Dockerfile | 9 +++--- README.md | 71 ++++++++++++++++++++++++++++++++++++++-------- docker-compose.yml | 15 ++++++++-- 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4a751f4..ca6c075 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,8 +9,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ python3 make g++ \ && rm -rf /var/lib/apt/lists/* -COPY package.json package-lock.json* ./ -RUN npm install --include=dev +COPY package.json package-lock.json ./ +RUN npm ci --include=dev COPY . . RUN npm run build @@ -39,5 +39,6 @@ COPY --from=build --chown=node:node /app/scripts ./scripts USER node EXPOSE 3000 -# Run migrations then start the SvelteKit Node server. -CMD ["sh", "-c", "node scripts/migrate.js && node build"] +# Run migrations + seed (idempotent INSERT OR IGNORE) then start the server. +# Set SEED_ON_BOOT=false in production once you've added real content. +CMD ["sh", "-c", "node scripts/migrate.js && { [ \"$SEED_ON_BOOT\" = \"false\" ] || node scripts/seed.js; } && node build"] diff --git a/README.md b/README.md index 4fbe551..5202fde 100644 --- a/README.md +++ b/README.md @@ -17,18 +17,57 @@ to the `RnD` Gitea organisation; viewing is open. - **Gitea OAuth2** for authoring (no passwords stored) - Pure **SVG + CSS** helix animation — no WebGL -## Local development +## Run it locally — two ways + +### 1. Docker (production-like, recommended for testing) + +Mirrors how the EVOLV stack is exercised locally. One command, named volume +for SQLite, healthcheck wired: ```bash -nvm use # picks up .nvmrc → Node 20 -cp .env.example .env -# Fill in GITEA_CLIENT_ID and GITEA_CLIENT_SECRET (see "Gitea OAuth setup" below) +cd /path/to/helix +docker compose up -d --build # build image + start container +docker compose logs -f helix # tail logs +# → http://localhost:3000 +``` + +If port 3000 is in use (Node-RED, another dev server, …) pick another: + +```bash +HELIX_PORT=3030 \ + ORIGIN=http://localhost:3030 \ + GITEA_REDIRECT_URI=http://localhost:3030/auth/gitea/callback \ + docker compose up -d --build +# → http://localhost:3030 +``` + +Useful commands: + +```bash +docker compose ps # status + health +docker inspect helix --format '{{.State.Health.Status}}' +docker compose exec helix sh # shell into the container +docker compose exec helix sqlite3 /data/helix.db # inspect the DB +docker compose down # stop (keeps the volume) +docker compose down -v # stop + DELETE all data +``` + +The SQLite database lives in the **`helix_helix-data`** named volume at +`/data/helix.db`. Migrations + the idempotent seed both run on every boot. +Once you have real content, set `SEED_ON_BOOT=false` in your env to stop +re-seeding the demo entries. + +### 2. Native Node (faster dev loop, hot reload) + +```bash +nvm use # .nvmrc → Node 20 (Tailwind v3 also works on 18) +cp .env.example .env # fill in Gitea OAuth — see below npm install -npm run db:generate # produces drizzle/0000_*.sql from the schema -npm run db:migrate # applies migrations to ./helix.db -npm run db:seed # adds example projects + posts so the landing page isn't empty -npm run dev # http://localhost:3000 +npm run db:generate # generate drizzle/0000_*.sql from the schema +npm run db:migrate # apply migrations to ./helix.db +npm run db:seed # idempotent demo content +npm run dev # http://localhost:5173 ``` ## Gitea OAuth setup @@ -58,15 +97,23 @@ origins can be embedded inline on a project page. Add a hostname (no scheme, no path) and redeploy. Hosts not on the list render as a "Open in new tab" card instead — never blindly iframed. -## Production deploy (Docker) +## Production deploy + +Same compose file as local. On the production host: ```bash -cp .env.example .env # fill in Gitea OAuth + ORIGIN +cp .env.example .env +# Set: ORIGIN=https://your-host, GITEA_REDIRECT_URI=https://your-host/auth/gitea/callback, +# GITEA_CLIENT_ID, GITEA_CLIENT_SECRET (from a separate prod OAuth app) docker compose up -d --build ``` -The SQLite database lives in the `helix-data` named volume at `/data/helix.db`. -Back it up with `docker compose exec helix sqlite3 /data/helix.db .dump`. +Put a TLS-terminating reverse proxy (nginx/caddy/traefik) in front of port 3000. +Back up the volume periodically: + +```bash +docker compose exec helix sqlite3 /data/helix.db .dump | gzip > helix-backup-$(date +%F).sql.gz +``` ## Project layout diff --git a/docker-compose.yml b/docker-compose.yml index ab275ee..be5873c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,9 @@ +name: helix + services: helix: - build: . + build: + context: . container_name: helix restart: unless-stopped ports: @@ -11,12 +14,18 @@ services: ORIGIN: ${ORIGIN:-http://localhost:3000} DATABASE_URL: /data/helix.db GITEA_BASE_URL: ${GITEA_BASE_URL:-https://gitea.wbd-rd.nl} - GITEA_CLIENT_ID: ${GITEA_CLIENT_ID} - GITEA_CLIENT_SECRET: ${GITEA_CLIENT_SECRET} + GITEA_CLIENT_ID: ${GITEA_CLIENT_ID:-} + GITEA_CLIENT_SECRET: ${GITEA_CLIENT_SECRET:-} GITEA_REDIRECT_URI: ${GITEA_REDIRECT_URI:-http://localhost:3000/auth/gitea/callback} GITEA_ALLOWED_ORG: ${GITEA_ALLOWED_ORG:-RnD} volumes: - helix-data:/data + healthcheck: + test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"] + interval: 15s + timeout: 5s + retries: 4 + start_period: 10s volumes: helix-data: