15 KiB
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(reportsapp_env,app_version,image_tag,git_sha,db_name) - Prod image selection: set
IMAGE_TAGin TrueNAS app env /infra/docker/.env.prod - Release push tag: set
release.imageTagininfra/deploy/devtoprod.config.json
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 repo’s 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)
Step A — Stop Gallery on the dev PC
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-web → Stop
Step B — Split the database (pgAdmin)
Where: Dev PC — pgAdmin (not TrueNAS shell)
- Open pgAdmin.
- Add/connect to server:
- Host:
192.168.10.122 - Port:
5432 - Maintenance database:
postgres - Username:
postgres(superuser — notgallery) - Password: your postgres password
- Host:
- Tree: Servers → your server → Databases → click
postgres - Tools → Query Tool (or right-click
postgres→ Query Tool) - File → Open →
Gallery\db\split-dev-prod-pgadmin.sql - Run each STEP separately (highlight from
-- STEP Nthrough that section, press F5 / Execute):Step Action STEP 0 Pre-flight — should show database GallerySTEP 1 Terminate connections STEP 2 ALTER DATABASE "Gallery" RENAME TO gallery_prod(use lowercase variant only if STEP 0 showedgallery)STEP 3 CREATE DATABASE gallery_dev WITH TEMPLATE gallery_prod(wait ~1–2 min)STEP 4 GRANTto usergallerySTEP 5 Verify — should show gallery_prodandgallery_devSTEP 6 New Query Tool on gallery_dev(not postgres!) —SELECT current_database()thenSELECT 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 C:\Users\SNAP\Nextcloud\Personal\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 C:\Users\SNAP\Nextcloud\Personal\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
-
Edit
.env(copy from.env.exampleif needed):DB_NAME=gallery_dev PORT=3451 PUBLIC_URL=https://devgallery.mysuperlab.netcraze.pro SESSION_SECRET=your-long-random-secret SESSION_COOKIE_SECURE=false CURATOR_USERNAME=curator CURATOR_PASSWORD=your-secure-passwordnpm run dev:migratecreates auth tables and bootstraps the first curator whenusersis empty. -
Run:
cd C:\Users\SNAP\Nextcloud\Personal\Repo\Gallery npm run dev:migrate npm run dev:web -
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 Settings → Shell)
# 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 C:\Users\SNAP\Nextcloud\Personal\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 C:\Users\SNAP\Nextcloud\Personal\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)
- Apps → Discover Apps → Custom App → Install via Docker Compose
- Paste contents of
infra/docker/compose.truenas.yamlfrom the repo - Replace
YOUR_POSTGRES_PASSWORDwith thegalleryuser password - Replace
REPLACE_WITH_LONG_RANDOM_SECRETandREPLACE_WITH_SECURE_PASSWORDforSESSION_SECRETandCURATOR_PASSWORD - Apps → Settings → register Gitea registry (
gitea.mysuperlab.netcraze.pro, token withread:package) - Deploy → wait for gallery-web to show Running
- Run
npm run dev:migrateagainstgallery_prodif 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 | Dev — DB_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
SESSION_COOKIE_SECURE=false
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 |
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.
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
- Finish and test on https://devgallery.mysuperlab.netcraze.pro
npm run devtoprod:thumbnails— skip if no painting/portrait images changednpm run dev:db:backupnpm run devtoprod:db:restore -- --file db/DataBackup/gallery_dev_data_....txt(typeyes) — skip if only code changed and prod DB should stay as-isnpm run devtoprod:images— skip if no new/changed imagesnpm run prod:docker:publish— required when application code changed- TrueNAS Web UI → restart gallery-web
- 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 |
Image sync
| Command | Where | Direction |
|---|---|---|
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
_proddatabase names without--prod - Destructive prod ops require typing
yesorCONFIRM_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.