Make dev->prod deploy work for non-superuser role and fix image sync.

restore-db-data.js: fall back to multi-pass insert when the DB role cannot set session_replication_role, and parse multi-line INSERT values (bios) as whole statements. sync-images-to-prod.ps1: fix SMB root variable typo and fail fast with guidance when the share is not mapped. Document SMB mapping, non-superuser restore, and a troubleshooting table in the release runbook.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Danila Khodjaef
2026-07-07 15:26:35 +03:00
co-authored by Cursor
parent ac1ae5794f
commit 313666a4ab
3 changed files with 141 additions and 13 deletions
+32
View File
@@ -132,12 +132,21 @@ npm run devtoprod:db:restore -- --file db/DataBackup/gallery_dev_data_YYYYMMDD_H
Type `yes` at the confirmation prompt (or set `CONFIRM_PROD=1` to skip it in automation).
The restore loads rows in two ways automatically:
- **Fast path** — if the DB role may set `session_replication_role` (superuser, or a PG 15+ `GRANT SET ON PARAMETER`), foreign-key checks are disabled for a single-pass load.
- **Multi-pass fallback** — the `gallery` role is **not** a superuser, so you will see `note: ... using multi-pass insert`. Rows whose foreign keys are not yet satisfied are retried on later passes until everything loads. No action needed.
Multi-line values (e.g. artist bios with embedded newlines) are parsed as whole statements, so long text restores correctly.
**Caveats — prod tables are replaced by dev's contents:**
- `users` and `curator_audit_log` are overwritten. The **dev curator account and password become the prod login**, and prod audit history is replaced. Make sure the dev curator credentials are the ones you want in prod.
- The `session` table is truncated, so any active prod curator sessions are logged out.
- The target is guarded: the restore refuses to run unless the database name ends with `_prod` and only reads `infra/docker/.env.prod`.
> **Optional** — to use the faster single-pass load, have the postgres superuser run this once in pgAdmin (role-global, covers dev and prod): `GRANT SET ON PARAMETER session_replication_role TO gallery;`
---
## Step 5 — Sync images to prod (only if image files changed)
@@ -146,12 +155,23 @@ Type `yes` at the confirmation prompt (or set `CONFIRM_PROD=1` to skip it in aut
Copies `data/images/` (paintings, portraits, and `thumbs/`) from the repo to the TrueNAS volume.
**Map the share in this Windows session first** (a fresh terminal has no mapping — robocopy will fail with `ERROR 5 Access is denied` otherwise):
```powershell
net use \\192.168.10.122\Gallery /user:YOUR_TRUENAS_USER # prompts for password
Test-Path "\\192.168.10.122\Gallery" # must print True
```
Then sync:
```powershell
npm run devtoprod:images
```
Type `yes` when prompted. Robocopy exit codes **07** = success. Destination: `\\192.168.10.122\Gallery\data\images`.
Alternatively, let the script map the share by exporting credentials first: `$env:SMB_USER="…"; $env:SMB_PASSWORD="…"` before running.
> Thumbnails are files, generated on dev (`npm run dev:regenerate-thumbnails` / `dev:regenerate-portrait-thumbs`) and shipped here — prod does **not** regenerate them. Regenerate on dev **before** this step if needed.
---
@@ -240,6 +260,18 @@ Keep at least the most recent `gallery_prod_data_*.txt` from Step 2 so a data ro
- Prod restore/backup require typing `yes` (or `CONFIRM_PROD=1`).
- `npm run dev:migrate` targets whatever `DB_NAME` is set — always `Remove-Item Env:\DB_NAME` after Step 3 so later commands stay on dev.
## Troubleshooting
| Symptom | Cause | Fix |
|---------|-------|-----|
| `/api/bounds` returns `{"min_year":null,"max_year":null}` on prod | `gallery_prod` has schema but no data | Run Step 4 (restore); confirm rows with a count query on `art_movements` / `paintings` |
| `robocopy ... ERROR 5 (0x00000005) Access is denied` on Step 5 | SMB share not mapped/authenticated in this Windows session | `net use \\192.168.10.122\Gallery /user:YOUR_TRUENAS_USER`, verify `Test-Path`, then re-run. If still denied after auth, fix TrueNAS dataset ACL (`chown -R 1001:1001`, grant the SMB user write) |
| Restore: `permission denied to set parameter "session_replication_role"` | DB role is not superuser | Handled automatically (multi-pass insert). For the fast path, superuser runs `GRANT SET ON PARAMETER session_replication_role TO gallery;` |
| Restore: `unterminated quoted string` | Old parser split multi-line values (bios) | Fixed — statements are accumulated until quotes balance; update to latest `scripts/restore-db-data.js` |
| `git push` → `Failed to authenticate user` (Gitea) | Git Credential Manager cached an expired token | Clear it: `"protocol=https`nhost=gitea.mysuperlab.netcraze.pro`n" \| git credential reject`, then push again to re-prompt |
| Prod tables empty after a failed restore | Restore truncates **before** inserting; a mid-run error leaves tables empty | Dev is untouched — just re-run Step 4 |
| `502 / 504` on the public prod URL | Keenetic upstream wrong (IP/port/protocol) | `192.168.10.122:5173`, protocol **http**; verify LAN `curl.exe -s http://192.168.10.122:5173/api/bounds` first |
## Related docs
| Document | Contents |