Files
Art-gallery/Documentation/environments.md
T

16 KiB
Raw Blame History

Development and production environments

Gallery uses one PostgreSQL server on TrueNAS (192.168.10.122) with two databases. The dev PC (192.168.10.70) runs npm run dev:web on port 5173, published at https://devgallery.mysuperlab.netcraze.pro via Keenetic.

Environment Database Public URL App host
Development gallery_dev https://devgallery.mysuperlab.netcraze.pro Dev PC 192.168.10.70:5173
Production gallery_prod https://gallery.mysuperlab.netcraze.pro TrueNAS container 192.168.10.122:5173

Version tracking:

  • Runtime version endpoint: /api/version (reports app_env, app_version, image_tag, git_sha, built_at, db_name)
  • npm run prod:docker:publish auto-creates a release tag like 20260709-155412-f72ddcc (build time + git commit), pushes it and latest
  • Version metadata is baked into the Docker image; TrueNAS only needs gallery-web:latest with pull_policy: always

Development-first workflow (default)

All day-to-day work happens on dev. Code edits, database changes, catalog updates, image fixes, migrations, and testing use gallery_dev, the repos data/images/, and https://devgallery.mysuperlab.netcraze.pro (or http://localhost:5173 on the dev PC).

Production is not updated on every change. Promote to prod on a regular cadence (typically about once a week) or when you explicitly decide to release:

Phase Where What
Daily Dev PC + gallery_dev Feature work, fixes, seed/migrate, curator edits, image pipeline
Release Dev PC → TrueNAS Backup dev → restore prod DB (if data changed) → sync images → docker:publish → restart gallery-web

Unless a task explicitly says prod or production, assume the target is dev — including when asking an assistant to change, fix, or modify code, data, or the database.

Never point the dev PC .env at gallery_prod. Prod-only files (infra/docker/.env.prod, db:restore:prod, images:sync-to-prod) are for scheduled releases, not routine development.


Where to run what (quick reference)

Step Machine Interface Privilege What
Stop dev servers Dev PC 192.168.10.70 PowerShell (normal) your user Close dev:web / dev:server / dev:client terminals
DB split (one-time) Dev PC pgAdmin → Query Tool on postgres postgres superuser db/split-dev-prod-pgadmin.sql step by step
Dev migrate / dev:web Dev PC PowerShell (normal) your user npm run dev:migrate, npm run dev:web
Image dir on TrueNAS TrueNAS 192.168.10.122 Shell (SSH or UI → System Settings → Shell) root / sudo bash infra/docker/truenas-setup.sh
Copy images to prod Dev PC PowerShell (normal) SMB \\192.168.10.122\Gallery net use then npm run devtoprod:images
Build + push Docker image Dev PC PowerShell as Administrator admin (for LAN hosts entry) npm run prod:docker:publish
Install prod app TrueNAS Web UI → Apps → Custom App admin Paste infra/docker/compose.truenas.yaml
Verify prod Dev PC or TrueNAS PowerShell / browser any curl.exe -sk https://gallery.mysuperlab.netcraze.pro/api/bounds

You do not need psql on TrueNAS. Database work is done from pgAdmin on the dev PC connected to 192.168.10.122:5432.


One-time setup (full walkthrough)

Where: Dev PC — PowerShell or open terminal tabs (no admin needed)

Close anything using ports 5173, 3451, or 3520:

  • Stop npm run dev:web, npm run dev:server, npm run dev:client
  • If prod container already runs on TrueNAS: TrueNAS Web UI → Apps → gallery-webStop

Step B — Split the database (pgAdmin)

Where: Dev PC — pgAdmin (not TrueNAS shell)

  1. Open pgAdmin.
  2. Add/connect to server:
    • Host: 192.168.10.122
    • Port: 5432
    • Maintenance database: postgres
    • Username: postgres (superuser — not gallery)
    • Password: your postgres password
  3. Tree: Servers → your server → Databases → click postgres
  4. ToolsQuery Tool (or right-click postgres → Query Tool)
  5. FileOpenGallery\db\split-dev-prod-pgadmin.sql
  6. Run each STEP separately (highlight from -- STEP N through that section, press F5 / Execute):
    Step Action
    STEP 0 Pre-flight — should show database Gallery
    STEP 1 Terminate connections
    STEP 2 ALTER DATABASE "Gallery" RENAME TO gallery_prod (use lowercase variant only if STEP 0 showed gallery)
    STEP 3 CREATE DATABASE gallery_dev WITH TEMPLATE gallery_prod (wait ~12 min)
    STEP 4 GRANT to user gallery
    STEP 5 Verify — should show gallery_prod and gallery_dev
    STEP 6 New Query Tool on gallery_dev (not postgres!) — SELECT current_database() then SELECT count(*) FROM paintings

If STEP 2 fails with “database already exists”, STEP 0 likely already shows gallery_prod — skip STEP 2 and continue from STEP 3 (skip STEP 3 too if gallery_dev exists).

Alternative (dev PC with psql installed):

cd T:\Repo\Gallery
psql -h 192.168.10.122 -U postgres -d postgres -f db/split-dev-prod.sql

Alternative (Node, postgres password in env):

cd T:\Repo\Gallery
$env:PGHOST="192.168.10.122"; $env:PGUSER="postgres"; $env:PGPASSWORD="YOUR_POSTGRES_PASSWORD"
npm run infra:db:split-dev-prod

Step C — Configure dev PC and test

Where: Dev PC — PowerShell (normal), repo root

  1. Edit .env (copy from .env.example if needed):

    DB_NAME=gallery_dev
    PORT=3451
    PUBLIC_URL=https://devgallery.mysuperlab.netcraze.pro
    SESSION_SECRET=your-long-random-secret
    CURATOR_USERNAME=curator
    CURATOR_PASSWORD=your-secure-password
    

    Omit SESSION_COOKIE_SECURE so cookies follow the request scheme (TRUST_PROXY + HTTPS → Secure). Set true/false to force. npm run dev:migrate creates auth tables and bootstraps the first curator when users is empty. Reset password later with npm run dev:reset-curator.

  2. Run:

    cd T:\Repo\Gallery
    npm run dev:migrate
    npm run dev:web
    
  3. Open https://devgallery.mysuperlab.netcraze.pro (or http://localhost:5173 on the dev PC)

Step D — Prepare prod image folder on TrueNAS

Where: TrueNAS — Shell (SSH to 192.168.10.122, or TrueNAS UI → System SettingsShell)

# Copy script to TrueNAS first, or paste commands manually:
mkdir -p /mnt/BasePool/Applications/Gallery/data/images/portraits
mkdir -p /mnt/BasePool/Applications/Gallery/data/images/paintings/thumbs
chown -R 1001:1001 /mnt/BasePool/Applications/Gallery
chmod -R u+rwX,g+rwX /mnt/BasePool/Applications/Gallery

Or from a checkout on TrueNAS: bash infra/docker/truenas-setup.sh

Step E — Copy images dev → prod volume

Where: Dev PC — PowerShell (normal), repo root

Requires SMB share Gallery/mnt/BasePool/Applications/Gallery on TrueNAS.

Connect to the share first (once per Windows session), then sync:

# Map share (use your TrueNAS SMB user/password)
net use \\192.168.10.122\Gallery /user:YOUR_TRUENAS_USER

cd T:\Repo\Gallery
npm run devtoprod:images

UNC destination: \\192.168.10.122\Gallery\data\images

Type yes when prompted. First run copies ~1000+ files (several minutes).

If net use fails, open \\192.168.10.122\Gallery in File Explorer and sign in, then retry.

Step F — Build and push Docker image

Where: Dev PC — PowerShell as Administrator (for fast LAN push to Gitea)

Prerequisites: Docker Desktop running, logged in to Gitea.

cd T:\Repo\Gallery
docker login gitea.mysuperlab.netcraze.pro
npm run prod:docker:publish

Use normal PowerShell with -SkipHosts if you already added 192.168.10.122 gitea.mysuperlab.netcraze.pro to C:\Windows\System32\drivers\etc\hosts.

Step G — Install production on TrueNAS

Where: TrueNAS — Web UI (browser)

  1. AppsDiscover AppsCustom AppInstall via Docker Compose
  2. Paste contents of infra/docker/compose.truenas.yaml from the repo
  3. Replace YOUR_POSTGRES_PASSWORD with the gallery user password
  4. Replace REPLACE_WITH_LONG_RANDOM_SECRET and REPLACE_WITH_SECURE_PASSWORD for SESSION_SECRET and CURATOR_PASSWORD
  5. AppsSettings → register Gitea registry (gitea.mysuperlab.netcraze.pro, token with read:package)
  6. Deploy → wait for gallery-web to show Running
  7. Run npm run dev:migrate against gallery_prod if auth tables are not yet applied (or migrate from dev PC with prod env)

Step H — Verify production

Where: Dev PC — PowerShell (normal) or any browser

curl.exe -sk https://gallery.mysuperlab.netcraze.pro/api/bounds
curl.exe -s http://192.168.10.122:5173/api/bounds

Open https://gallery.mysuperlab.netcraze.pro/ — timeline and sample painting images should load. Click an artist portrait or movement label to enter a 3D hall. Curator login (top-right) unlocks debug mode and Checkup.


Environment files

File Git Purpose
.env ignored DevDB_NAME=gallery_dev, PORT=3451
.env.example tracked Dev template
infra/docker/.env.prod ignored Prod — migrate/restore prod scripts
infra/docker/.env.prod.example tracked Prod template
infra/docker/compose.truenas.yaml tracked TrueNAS Custom App

Never point dev .env at gallery_prod. Prod scripts refuse dev env files.


Dev public access (Keenetic)

Where: Keenetic router Web UI (not dev PC)

Field Value
Domain devgallery.mysuperlab.netcraze.pro
Upstream IP 192.168.10.70
Upstream port 5173
Protocol to device http (not https)
Preserve Host ON

Vite on the dev PC speaks plain HTTP only. Keenetic terminates HTTPS from the browser, then must forward HTTP to 192.168.10.70:5173.

If Protocol to device is https, Keenetic tries TLS against Vite → 502 Bad Gateway (Server: Web server).

Verify from dev PC (servers must be running: npm run dev:web):

# PowerShell: curl is an alias — use curl.exe for -k, or Invoke-WebRequest
curl.exe -s -o NUL -w "HTTP %{http_code}`n" http://192.168.10.70:5173/
curl.exe -sk -o NUL -w "HTTP %{http_code}`n" https://devgallery.mysuperlab.netcraze.pro/

# Or native PowerShell (skip cert check):
Invoke-WebRequest -Uri https://devgallery.mysuperlab.netcraze.pro/ -SkipCertificateCheck | Select-Object StatusCode

Expect HTTP 200 (not 502).

.env: use the same scheme as the browser URL. If Keenetic serves HTTPS publicly:

PUBLIC_URL=https://devgallery.mysuperlab.netcraze.pro
TRUST_PROXY=true
SESSION_SECRET=your-long-random-secret

Omit SESSION_COOKIE_SECURE for auto Secure cookies behind Keenetic HTTPS. Prod (infra/docker/.env.prod): set SESSION_COOKIE_SECURE=true and the same SESSION_SECRET / CURATOR_* vars on the TrueNAS app environment.

Restart npm run dev:web after changing PUBLIC_URL.


Production public access (Keenetic)

Where: Keenetic router Web UI

Field Value
Domain gallery.mysuperlab.netcraze.pro
Upstream IP 192.168.10.122 (TrueNAS — not the dev PC)
Upstream port 5173
Protocol to device http (container speaks HTTP, not HTTPS)
Preserve Host ON

The prod container listens on plain HTTP on port 5173. Keenetic terminates HTTPS from the browser and must forward HTTP to TrueNAS.

Verify the app first (bypass Keenetic):

curl.exe -s http://192.168.10.122:5173/api/bounds

Expect JSON immediately (~200). If this works but the public URL returns 502/504, the Keenetic rule is wrong (IP, port, or https to device).

Then verify public URL:

curl.exe -sk https://gallery.mysuperlab.netcraze.pro/api/bounds

See also Drunkmeyou gitea-https-keenetic-npm-setup.md — same Keenetic HTTPS → HTTP upstream pattern.


Daily development

Where: Dev PC — PowerShell (normal), repo root

Task Command
Public dev URL (Keenetic) npm run dev:web
Fast local HMR (no Keenetic) npm run dev:server + npm run dev:client
Refresh dev DB from prod npm run prodto:dev:db
Pull prod images to dev npm run prodto:dev:images
Merge dev ↔ prod catalog + images (incremental) npm run harmonize — see harmonize-dev-prod.md

Promote dev → prod (scheduled release)

Run this when you are ready to ship dev to production — not after every small change. Typical cadence: about once a week.

For incremental dev ↔ prod merge (both sides edited), use harmonize-dev-prod.md instead of full restore.

One command (recommended): copy infra/deploy/devtoprod.config.example.json to infra/deploy/devtoprod.config.json, edit it, then npm run devtoprod:release or deploy-dev-to-prod.cmd. See deploy-dev-to-prod.md → One-command release.

Manual steps: detailed runbook (per-change decision matrix, schema migration, rollback): deploy-dev-to-prod.md.

Where: Dev PC unless noted

  1. Finish and test on https://devgallery.mysuperlab.netcraze.pro
  2. npm run devtoprod:thumbnails — skip if no painting/portrait images changed
  3. npm run dev:db:backup
  4. npm run devtoprod:db:restore -- --file db/DataBackup/gallery_dev_data_....txt (type yes) — skip if only code changed and prod DB should stay as-is
  5. npm run devtoprod:images — skip if no new/changed images
  6. npm run prod:docker:publish — required when application code changed
  7. TrueNAS Web UI → restart gallery-web
  8. Verify https://gallery.mysuperlab.netcraze.pro

Database scripts

Command Where Purpose
pgAdmin + split-dev-prod-pgadmin.sql Dev PC pgAdmin One-time split (recommended)
npm run infra:db:split-dev-prod Dev PC PowerShell Same split (needs PGUSER=postgres)
npm run prodto:dev:db Dev PC PowerShell Clone prod → dev
npm run dev:db:backup Dev PC PowerShell Dev backup
npm run devtoprod:db:restore Dev PC PowerShell Restore into prod
npm run harmonize Dev PC PowerShell Bidirectional catalog + image merge — harmonize-dev-prod.md
npm run harmonize:db Dev PC PowerShell DB merge only
npm run harmonize:images Dev PC PowerShell Image merge + artists/paintings checkup/path sync + regenerate thumbs on both sides

Image sync

Command Where Direction
npm run harmonize Dev PC PowerShell Bidirectional merge (mtime newer wins) — harmonize-dev-prod.md
npm run devtoprod:release Dev PC PowerShell Full config-driven promote (see deploy-dev-to-prod.md)
npm run devtoprod:thumbnails Dev PC PowerShell Rebuild painting + portrait thumbs on dev before promote
npm run devtoprod:images Dev PC PowerShell Dev → TrueNAS volume
npm run prodto:dev:images Dev PC PowerShell TrueNAS → dev repo

Safety guards

  • Prod restore reads only infra/docker/.env.prod
  • Dev backup refuses _prod database names without --prod
  • Destructive prod ops require typing yes or CONFIRM_PROD=1

Legacy deployment

Node on dev PC :3520 + nginx → Vite :5173 is optional; see deploy/nginx-gallery.conf. Production should use TrueNAS Docker on :5173.

Deploy details: infra/docker/DEPLOY-truenas.md.