From ac1ae5794f1bd4b0279bf45b3fd992af067ad6e9 Mon Sep 17 00:00:00 2001 From: Danila Khodjaef Date: Tue, 7 Jul 2026 14:30:38 +0300 Subject: [PATCH] Release: --- Documentation/FAC.md | 3 +- Documentation/basics.md | 1 + Documentation/deploy-dev-to-prod.md | 250 ++++++++++++++++++++++++++++ Documentation/environments.md | 2 +- 4 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 Documentation/deploy-dev-to-prod.md diff --git a/Documentation/FAC.md b/Documentation/FAC.md index eff097a..c9a9009 100644 --- a/Documentation/FAC.md +++ b/Documentation/FAC.md @@ -289,7 +289,7 @@ Expect JSON with `min_year` / `max_year`. HTML shell only from `curl` on `/` is ## Promote dev → prod (scheduled release) -~Weekly (or when explicitly releasing to prod). Not part of daily dev. +~Weekly (or when explicitly releasing to prod). Not part of daily dev. Full runbook with per-change decision matrix and rollback: [deploy-dev-to-prod.md](deploy-dev-to-prod.md). 1. Test on https://devgallery.mysuperlab.netcraze.pro 2. `npm run dev:db:backup` @@ -331,6 +331,7 @@ Remote: https://gitea.mysuperlab.netcraze.pro/Danilka/Art-gallery | Document | Contents | |----------|----------| +| [deploy-dev-to-prod.md](deploy-dev-to-prod.md) | Step-by-step release runbook (code, DB, data, images) | | [environments.md](environments.md) | Full dev/prod walkthrough | | [setup.md](setup.md) | Install, env vars, troubleshooting | | [data-and-images.md](data-and-images.md) | Catalog and image pipeline | diff --git a/Documentation/basics.md b/Documentation/basics.md index 3d06213..677b672 100644 --- a/Documentation/basics.md +++ b/Documentation/basics.md @@ -428,6 +428,7 @@ See [API.md](API.md#authentication) and [data-and-images.md](data-and-images.md# | Document | Contents | |----------|----------| | [setup.md](setup.md) | Install, database, npm scripts | +| [deploy-dev-to-prod.md](deploy-dev-to-prod.md) | Release runbook: promote dev → prod | | [DB_structure.md](DB_structure.md) | Tables and relationships | | [API.md](API.md) | REST endpoints | | [data-and-images.md](data-and-images.md) | Image pipeline and seeding | diff --git a/Documentation/deploy-dev-to-prod.md b/Documentation/deploy-dev-to-prod.md new file mode 100644 index 0000000..f2faa7d --- /dev/null +++ b/Documentation/deploy-dev-to-prod.md @@ -0,0 +1,250 @@ +# Deploy dev → prod (release runbook) + +Step-by-step guide for promoting the **development** version of Gallery to **production**. Covers code, database schema, database data, and image files. + +> **Default is dev.** This runbook is for a **scheduled release** (~weekly, or when you explicitly decide to ship). Day-to-day work stays on dev — see [environments.md](environments.md#development-first-workflow-default). If the one-time prod install is not done yet, follow [environments.md → One-time setup](environments.md#one-time-setup-full-walkthrough) and [infra/docker/DEPLOY-truenas.md](../infra/docker/DEPLOY-truenas.md) first. + +| | Dev (source) | Prod (target) | +|---|---|---| +| Database | `gallery_dev` | `gallery_prod` | +| Images | repo `data/images/` | `/mnt/BasePool/Applications/Gallery/data/images` (SMB share **`Gallery`**) | +| App | `npm run dev:web` on dev PC `:5173` | `gallery-web` container on TrueNAS `:5173` | +| URL | https://devgallery.mysuperlab.netcraze.pro | https://gallery.mysuperlab.netcraze.pro | +| Env file | root [`.env`](../.env) (`gallery_dev`) | [`infra/docker/.env.prod`](../infra/docker/.env.prod) (`gallery_prod`) | + +All commands run on the **dev PC** from the repo root (`C:\Users\SNAP\Nextcloud\Personal\Repo\Gallery`) unless a step says **TrueNAS**. + +--- + +## What changed → which steps to run + +Run only the steps that match what you changed. Steps are independent except that **code** needs a rebuilt image and **schema changes** must be applied before a **data** restore. + +| You changed… | Required steps | +|--------------|----------------| +| Application code (client/server) | 0 → 1 → 6 → 7 → 8 | +| DB schema (new `db/migrate-*.sql`, `schema.sql`) | 0 → 1 → 2 → **3** → (4 if data too) → 7 → 8 | +| Catalog data (movements, artists, paintings, influences, bios) | 0 → 2 → 4 → 8 | +| Image files (new/replaced paintings, portraits, thumbs) | 0 → 5 → 8 | +| Everything (typical weekly release) | 0 → 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 | + +--- + +## Prerequisites (per release) + +- Prod already installed once on TrueNAS (`gallery-web` app exists). +- **Docker Desktop** running on the dev PC; logged in: `docker login gitea.mysuperlab.netcraze.pro`. +- Prod env file present: [`infra/docker/.env.prod`](../infra/docker/.env.prod) with `DB_NAME=gallery_prod` (copy from [`.env.prod.example`](../infra/docker/.env.prod.example) if missing). +- SMB share mapped for image sync (per Windows session): + + ```powershell + net use \\192.168.10.122\Gallery /user:YOUR_TRUENAS_USER + ``` + +--- + +## Step 0 — Validate on dev + +**Where:** Dev PC + browser + +1. Make sure the change works on https://devgallery.mysuperlab.netcraze.pro (or `http://localhost:5173`). +2. Build the client to catch type/compile errors before shipping: + + ```powershell + npm run prod:build + ``` + +3. Sanity-check the dev API: + + ```powershell + curl.exe -sk https://devgallery.mysuperlab.netcraze.pro/api/bounds + ``` + +Do not proceed until dev is correct — prod is a copy of dev. + +--- + +## Step 1 — Commit and push code + +**Where:** Dev PC + +Commit the release so prod is reproducible and the Docker build ships the intended code. + +```powershell +git status +git add . +git commit -m "Release: " +git push origin main +``` + +--- + +## Step 2 — Back up the dev database + +**Where:** Dev PC + +Creates a data-only dump (INSERT statements) under `db/DataBackup/`. + +```powershell +npm run dev:db:backup +``` + +Output (note the exact path — you pass it to Step 4): + +``` +Backup written: db/DataBackup/gallery_dev_data_YYYYMMDD_HHMMSS.txt +Archive written: db/DataBackup/gallery_dev_data_YYYYMMDD_HHMMSS.zip +``` + +> Also back up prod before overwriting it (optional but recommended): `npm run prod:db:backup` → `db/DataBackup/gallery_prod_data_*.txt`. Keep it as a rollback point (see [Rollback](#rollback)). + +--- + +## Step 3 — Apply schema changes to prod (only if schema changed) + +**Where:** Dev PC + +The data restore in Step 4 only inserts rows — it does **not** create tables or add columns. If this release added a migration (`db/migrate-*.sql`) or changed `db/schema.sql`, the prod schema must be updated **first** so the new columns/tables exist. + +`server/migrate.js` is idempotent (schema and migrations use `IF NOT EXISTS` / additive `ALTER`s). Point it at prod for one run by overriding `DB_NAME` (all other credentials come from `.env`; the `gallery` user has rights to both databases): + +```powershell +$env:DB_NAME = "gallery_prod" +npm run dev:migrate +Remove-Item Env:\DB_NAME # restore dev default so later commands hit gallery_dev +``` + +Expect `schema.sql` + each `migrate-*.sql` to log `OK`. Re-running is safe. + +> If you prefer not to override env, temporarily set `DB_NAME=gallery_prod` in a scratch shell only — **never** edit the committed root `.env` to point at prod. + +--- + +## Step 4 — Restore dev data into prod (only if data/DB changed) + +**Where:** Dev PC + +Loads the Step 2 backup into `gallery_prod`. This **TRUNCATES all public tables** in prod first, then inserts dev's rows — prod becomes an exact copy of dev's data. + +```powershell +npm run devtoprod:db:restore -- --file db/DataBackup/gallery_dev_data_YYYYMMDD_HHMMSS.txt +``` + +Type `yes` at the confirmation prompt (or set `CONFIRM_PROD=1` to skip it in automation). + +**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`. + +--- + +## Step 5 — Sync images to prod (only if image files changed) + +**Where:** Dev PC (SMB share mapped — see Prerequisites) + +Copies `data/images/` (paintings, portraits, and `thumbs/`) from the repo to the TrueNAS volume. + +```powershell +npm run devtoprod:images +``` + +Type `yes` when prompted. Robocopy exit codes **0–7** = success. Destination: `\\192.168.10.122\Gallery\data\images`. + +> 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. + +--- + +## Step 6 — Build and push the Docker image (only if code changed) + +**Where:** Dev PC — **PowerShell as Administrator**, Docker Desktop running + +Builds the Express API + freshly built client SPA and pushes to Gitea. + +```powershell +docker login gitea.mysuperlab.netcraze.pro +npm run prod:docker:publish +``` + +- Already built and only need to push: `npm run prod:docker:push-only` +- Image tag: `gitea.mysuperlab.netcraze.pro/danilka/gallery-web:latest` +- No registry / offline: `.\infra\docker\save-for-truenas.ps1` → copy `gallery-web.tar` via the `Gallery` SMB share → on TrueNAS `sudo bash infra/docker/truenas-load-image.sh /path/to/gallery-web.tar`. + +--- + +## Step 7 — Restart gallery-web on TrueNAS (after code or schema changes) + +**Where:** TrueNAS — Web UI + +1. **Apps** → **gallery-web** → **Restart** (pulls `:latest` when `pull_policy: always`, otherwise redeploy to force a pull). +2. Wait for status **Running**. + +Data-only or image-only releases (no new image) do not require a restart, but a restart is harmless. + +--- + +## Step 8 — Verify production + +**Where:** Dev PC / browser + +Bypass the router first (should return JSON instantly), then check the public URL: + +```powershell +curl.exe -s http://192.168.10.122:5173/api/bounds +curl.exe -sk https://gallery.mysuperlab.netcraze.pro/api/bounds +``` + +Then open **https://gallery.mysuperlab.netcraze.pro/** and confirm: + +- Timeline + movement flow load; portraits appear. +- Click a portrait / movement → 3D hall renders with painting images (`/images/paintings/...`). +- **Curator login** (top-right) works with the intended credentials. + +Optional on TrueNAS shell: `bash infra/docker/truenas-verify.sh`. + +--- + +## Rollback + +| Problem | Action | +|---------|--------| +| Bad **data** release | Re-run Step 4 with the pre-release prod backup: `npm run devtoprod:db:restore -- --file db/DataBackup/gallery_prod_data_.txt` | +| Bad **code** release | Rebuild from the last good commit: `git checkout `, `npm run prod:docker:publish`, restart `gallery-web` | +| Bad **images** | Re-sync from a known-good dev copy, or pull prod back to dev with `npm run prodto:dev:images` to compare | + +Keep at least the most recent `gallery_prod_data_*.txt` from Step 2 so a data rollback is always possible. + +--- + +## Command quick reference + +| Step | Command | Runs on | +|------|---------|---------| +| 0 Validate | `npm run prod:build` | Dev PC | +| 1 Ship code | `git add . ; git commit -m "…" ; git push origin main` | Dev PC | +| 2 Backup dev | `npm run dev:db:backup` | Dev PC | +| 2 Backup prod (rollback point) | `npm run prod:db:backup` | Dev PC | +| 3 Migrate prod schema | `$env:DB_NAME="gallery_prod"; npm run dev:migrate; Remove-Item Env:\DB_NAME` | Dev PC | +| 4 Restore data → prod | `npm run devtoprod:db:restore -- --file .txt` | Dev PC | +| 5 Sync images → prod | `npm run devtoprod:images` | Dev PC (SMB) | +| 6 Build + push image | `npm run prod:docker:publish` | Dev PC (Admin) | +| 7 Restart app | Apps → gallery-web → Restart | TrueNAS UI | +| 8 Verify | `curl.exe -sk https://gallery.mysuperlab.netcraze.pro/api/bounds` | Dev PC | + +--- + +## Safety guards (built in) + +- Prod DB scripts read **only** `infra/docker/.env.prod`; dev scripts refuse `_prod` database names. +- 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. + +## Related docs + +| Document | Contents | +|----------|----------| +| [environments.md](environments.md) | Full dev/prod walkthrough, one-time setup, Keenetic | +| [infra/docker/DEPLOY-truenas.md](../infra/docker/DEPLOY-truenas.md) | TrueNAS container install and troubleshooting | +| [FAC.md](FAC.md#promote-dev--prod-scheduled-release) | Command cheat sheet | +| [data-and-images.md](data-and-images.md) | Catalog and image pipeline | diff --git a/Documentation/environments.md b/Documentation/environments.md index 64bab5f..b83a5c2 100644 --- a/Documentation/environments.md +++ b/Documentation/environments.md @@ -305,7 +305,7 @@ See also [Drunkmeyou gitea-https-keenetic-npm-setup.md](../../Drunkmeyou/Documen ## 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**. +Run this when you are ready to ship dev to production — **not** after every small change. Typical cadence: **about once a week**. Detailed step-by-step runbook (per-change decision matrix, schema migration, rollback): [deploy-dev-to-prod.md](deploy-dev-to-prod.md). **Where:** Dev PC unless noted