Files
Art-gallery/Documentation/environments.md
T
Danila KhodjaefandCursor 2edf577faf Add dev/prod environments with TrueNAS Docker production deploy.
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>
2026-07-04 15:15:19 +03:00

317 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`](../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)
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. **Tools****Query Tool** (or right-click `postgres` → Query Tool)
5. **File****Open**`Gallery\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):**
```powershell
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):**
```powershell
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
1. Edit `.env` (copy from `.env.example` if needed):
```env
DB_NAME=gallery_dev
PORT=3451
PUBLIC_URL=https://devgallery.mysuperlab.netcraze.pro
```
2. Run:
```powershell
cd C:\Users\SNAP\Nextcloud\Personal\Repo\Gallery
npm run 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 Settings** → **Shell**)
```bash
# 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:
```powershell
# 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.
```powershell
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)
1. **Apps** → **Discover Apps** → **Custom App** → **Install 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. **Apps** → **Settings** → register Gitea registry (`gitea.mysuperlab.netcraze.pro`, token with `read:package`)
5. Deploy → wait for **gallery-web** to show **Running**
### Step H — Verify production
**Where:** Dev PC — PowerShell (normal) or any browser
```powershell
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`](../.env) | ignored | **Dev** — `DB_NAME=gallery_dev`, `PORT=3451` |
| [`.env.example`](../.env.example) | tracked | Dev template |
| [`infra/docker/.env.prod`](../infra/docker/.env.prod) | ignored | **Prod** — migrate/restore prod scripts |
| [`infra/docker/.env.prod.example`](../infra/docker/.env.prod.example) | tracked | Prod template |
| [`infra/docker/compose.truenas.yaml`](../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
# 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:
```env
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):**
```powershell
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:**
```powershell
curl.exe -sk https://gallery.mysuperlab.netcraze.pro/api/bounds
```
See also [Drunkmeyou gitea-https-keenetic-npm-setup.md](../../Drunkmeyou/Documentation/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
1. `npm run db:backup`
2. Test on https://devgallery.mysuperlab.netcraze.pro
3. `npm run db:restore:prod -- --file db/DataBackup/gallery_dev_data_....txt` (type `yes`)
4. `npm run images:sync-to-prod`
5. **TrueNAS Web UI** → restart **gallery-web** (or `npm run docker:publish` if 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 `_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`](../deploy/nginx-gallery.conf). Production should use TrueNAS Docker on `:5173`.
Deploy details: [`infra/docker/DEPLOY-truenas.md`](../infra/docker/DEPLOY-truenas.md).