Add curator authentication with audit logging and fix empty 3D gallery sessions.

Introduce session-based curator login, gate debug/checkup routes, log mutations to curator_audit_log, and keep guest hall preload public. Fix gallery view mounting so WebGL halls render reliably after navigation.
This commit is contained in:
Danila Khodjaef
2026-07-06 00:17:01 +03:00
parent aa31a2aa6e
commit 9da065acbe
27 changed files with 1252 additions and 112 deletions
+24 -6
View File
@@ -26,6 +26,12 @@ cp .env.example .env
| `PUBLIC_URL` | Public URL (dev: `https://devgallery.mysuperlab.netcraze.pro`; prod: `https://gallery.mysuperlab.netcraze.pro`) |
| `TRUST_PROXY` | Set to `true` when behind nginx/reverse proxy (honours `X-Forwarded-*`) |
| `IMAGE_DIR` | Root for cached images (default `./data/images`) |
| `SESSION_SECRET` | Random string for signed session cookies (required for curator login) |
| `SESSION_COOKIE_SECURE` | `false` for local HTTP dev; `true` in prod behind HTTPS |
| `CURATOR_USERNAME` | Bootstrap only — first curator account name (default `curator`) |
| `CURATOR_PASSWORD` | Bootstrap only — password for first curator when `users` table is empty |
`.env` is git-ignored; never commit passwords.
Optional script tuning:
@@ -34,8 +40,6 @@ Optional script tuning:
| `MIN_PAINTINGS` | `expand-catalog` | Minimum paintings per artist (default `6`) |
| `FETCH_MAX_WAIT_SEC` | `fetch-images` | Max seconds per painting in batch runs (default `10`) |
`.env` is git-ignored; never commit passwords.
## Install
```bash
@@ -62,6 +66,14 @@ npm run seed # eras, movements, artists, flagship paintings (one per artis
If migration fails with permission errors, grant schema rights to the app user first (see [DB_structure.md](DB_structure.md)).
### Curator accounts (auth migration)
`npm run migrate` applies `db/migrate-auth.sql` (`users`, `curator_audit_log`, `session` tables). When the `users` table is empty and `CURATOR_USERNAME` / `CURATOR_PASSWORD` are set in `.env`, the first curator account is created automatically.
After migrate, sign in from the site header (**Curator login**). Debug mode, Checkup, and all mutating debug APIs require an active curator session. Anonymous visitors browse the timeline and 3D halls without logging in.
See [API.md — Authentication](API.md#authentication) and [basics.md — Developer tools](basics.md#developer-tools-image-audit).
### Recommended post-seed steps
After a fresh seed, run these to match a fully populated local install:
@@ -129,10 +141,11 @@ Production runs as **`gallery-web`** on TrueNAS at **https://gallery.mysuperlab.
Quick deploy checklist:
1. One-time DB split in **pgAdmin** on dev PC: [`db/split-dev-prod-pgadmin.sql`](../db/split-dev-prod-pgadmin.sql)
2. Dev `.env``DB_NAME=gallery_dev`, `PORT=3451`, `PUBLIC_URL=https://devgallery.mysuperlab.netcraze.pro`
3. `net use \\192.168.10.122\Gallery``npm run images:sync-to-prod`
4. `npm run docker:publish` → TrueNAS Custom App from `infra/docker/compose.truenas.yaml`
5. Keenetic: both domains → `:5173`, protocol to device **`http`**, correct IP per environment
2. Dev `.env``DB_NAME=gallery_dev`, `PORT=3451`, `PUBLIC_URL=https://devgallery.mysuperlab.netcraze.pro`, plus auth vars (`SESSION_SECRET`, `CURATOR_*`)
3. `npm run migrate` on dev and prod DBs (includes auth tables + bootstrap curator)
4. `net use \\192.168.10.122\Gallery``npm run images:sync-to-prod`
5. `npm run docker:publish` → TrueNAS Custom App from `infra/docker/compose.truenas.yaml` (set auth env in compose)
6. Keenetic: both domains → `:5173`, protocol to device **`http`**, correct IP per environment
### Legacy deployment (optional)
@@ -254,3 +267,8 @@ After clone: copy `.env.example` → `.env`, install dependencies, run [one-time
| Movement gallery shows generic cream walls | Stale client build | `cd client && npm run build`; hard-refresh browser |
| Windows overlap paintings in movement wing | Stale client | Rebuild client — windows are placed only on side walls in gaps between frames |
| Influence thumbnails cropped on painting detail | Stale client build | `npm run build` — panels use `object-fit: contain` for full image |
| **Curator login** fails / always guest | Auth tables missing or wrong password | Set `SESSION_SECRET` + `CURATOR_PASSWORD` in `.env`, run `npm run migrate`, restart server |
| Debug / Checkup returns **401** | Not signed in as curator | **Curator login** (top-right); session cookie `gallery.sid` must be sent (`credentials: include`) |
| Debug works in UI but API rejects | Stale server without auth middleware | Restart `npm run dev:web` or `npm run dev:server` after pulling auth changes |
| **Empty screen** entering 3D hall (header missing) | Stale client before gallery-session fix | Hard-refresh; pull latest client — hall renders from `view` state, not only `gallerySession` |
| 3D hall black after returning from painting detail | WebGL context lost while hall was hidden | Hard-refresh; latest client remounts canvas when hall becomes active again |