Default all day-to-day work to gallery_dev and devgallery; add Cursor rule and update docs, env examples, and deploy guide for scheduled prod promotion.
14 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 |
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 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 images:sync-to-prod |
| Build + push Docker image | Dev PC | PowerShell as Administrator | admin (for LAN hosts entry) | npm run 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 db:split-databases
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 migratecreates auth tables and bootstraps the first curator whenusersis empty. -
Run:
cd C:\Users\SNAP\Nextcloud\Personal\Repo\Gallery npm run 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 images:sync-to-prod
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 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 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 db:sync-from-prod |
| Pull prod images to dev | npm run images:sync-from-prod |
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.
Where: Dev PC unless noted
- Finish and test on https://devgallery.mysuperlab.netcraze.pro
npm run db:backupnpm run db:restore:prod -- --file db/DataBackup/gallery_dev_data_....txt(typeyes) — skip if only code changed and prod DB should stay as-isnpm run images:sync-to-prod— skip if no new/changed imagesnpm run 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 db:split-databases |
Dev PC PowerShell | Same split (needs PGUSER=postgres) |
npm run db:sync-from-prod |
Dev PC PowerShell | Clone prod → dev |
npm run db:backup |
Dev PC PowerShell | Dev backup |
npm run db:restore:prod |
Dev PC PowerShell | Restore into prod |
Image sync
| Command | Where | Direction |
|---|---|---|
npm run images:sync-to-prod |
Dev PC PowerShell | Dev → TrueNAS volume |
npm run images:sync-from-prod |
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.