Split PostgreSQL into gallery_dev and gallery_prod, add Docker/Gitea deploy tooling, SMB image sync, pgAdmin split script, dev:web on Keenetic :5173, and operator docs. Co-authored-by: Cursor <cursoragent@cursor.com>
12 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 |
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 -
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 - Apps → Settings → register Gitea registry (
gitea.mysuperlab.netcraze.pro, token withread:package) - Deploy → wait for gallery-web to show Running
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.
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
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
Where: Dev PC unless noted
npm run db:backup- Test on https://devgallery.mysuperlab.netcraze.pro
npm run db:restore:prod -- --file db/DataBackup/gallery_dev_data_....txt(typeyes)npm run images:sync-to-prod- TrueNAS Web UI → restart gallery-web (or
npm run docker:publishif code changed)
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.