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>
This commit is contained in:
Danila Khodjaef
2026-07-04 15:15:19 +03:00
co-authored by Cursor
parent 02d238b043
commit 2edf577faf
34 changed files with 1742 additions and 80 deletions
+126
View File
@@ -0,0 +1,126 @@
-- =============================================================================
-- Gallery: one-time split Gallery → gallery_prod + gallery_dev
-- =============================================================================
--
-- WHERE TO RUN: pgAdmin on your **dev PC** (192.168.10.70)
-- NOT on TrueNAS shell — psql is not required on TrueNAS.
--
-- BEFORE YOU START (dev PC, normal PowerShell in repo folder):
-- 1. Stop Gallery if running: close terminals with dev:web / dev:server / dev:client
-- 2. Stop the prod container on TrueNAS if it already exists (Apps → gallery-web → Stop)
--
-- pgAdmin SETUP:
-- 1. Open pgAdmin
-- 2. Register server (if needed):
-- Host: 192.168.10.122
-- Port: 5432
-- Maintenance database: postgres
-- Username: postgres ← must be superuser, NOT gallery
-- Password: (your postgres password)
-- 3. In the tree: Servers → (your server) → Databases → **postgres**
-- 4. Right-click **postgres** → Query Tool
-- 5. File → Open → select this file (db/split-dev-prod-pgadmin.sql)
-- 6. Run in order: highlight STEP 0 → Execute (F5), then STEP 1, STEP 2, …
--
-- IMPORTANT: Run each STEP block separately (highlight one STEP section, F5).
-- CREATE DATABASE (STEP 3) must NOT run inside a transaction with other steps.
--
-- AFTER SUCCESS:
-- On dev PC (normal PowerShell, repo root):
-- npm run migrate
-- npm run dev:web
-- Open http://devgallery.mysuperlab.netcraze.pro
--
-- =============================================================================
-- =============================================================================
-- STEP 0 — Pre-flight (read-only). Run this first.
-- Expected before split: one row with datname = Gallery
-- Expected after split: gallery_prod and gallery_dev
-- =============================================================================
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database
WHERE datname IN ('Gallery', 'gallery', 'gallery_prod', 'gallery_dev')
ORDER BY datname;
-- =============================================================================
-- STEP 1 — Disconnect all clients from Gallery databases
-- Run on database: postgres
-- =============================================================================
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname IN ('Gallery', 'gallery', 'gallery_prod', 'gallery_dev')
AND pid <> pg_backend_pid();
-- =============================================================================
-- STEP 2 — Rename legacy database → gallery_prod
-- Run on database: postgres
-- Skip this step if STEP 0 already shows gallery_prod (split already done).
-- Run ONLY ONE of the two ALTER lines below (whichever matches STEP 0):
-- =============================================================================
-- Use this if STEP 0 showed datname = Gallery (capital G):
ALTER DATABASE "Gallery" RENAME TO gallery_prod;
-- OR use this if STEP 0 showed datname = gallery (all lowercase) — comment out the line above:
-- ALTER DATABASE gallery RENAME TO gallery_prod;
-- =============================================================================
-- STEP 3 — Clone gallery_dev from gallery_prod
-- Run on database: postgres
-- Skip if gallery_dev already exists in STEP 0.
-- Takes 12 minutes for ~1000 paintings. Do not run twice.
-- =============================================================================
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'gallery_prod'
AND pid <> pg_backend_pid();
CREATE DATABASE gallery_dev WITH TEMPLATE gallery_prod;
-- =============================================================================
-- STEP 4 — Grants for app user
-- Run on database: postgres
-- =============================================================================
GRANT ALL PRIVILEGES ON DATABASE gallery_dev TO gallery;
GRANT ALL PRIVILEGES ON DATABASE gallery_prod TO gallery;
-- =============================================================================
-- STEP 5 — Verify databases (read-only)
-- Run on database: postgres
-- Expected: gallery_prod and gallery_dev (Gallery gone)
-- =============================================================================
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database
WHERE datname IN ('Gallery', 'gallery', 'gallery_prod', 'gallery_dev')
ORDER BY datname;
-- =============================================================================
-- STEP 6 — Verify row count
--
-- *** IMPORTANT: Query Tool must be connected to gallery_dev, NOT postgres ***
--
-- In pgAdmin:
-- 1. Close this Query Tool tab (or ignore postgres connection)
-- 2. Tree: Servers → your server → Databases → **gallery_dev**
-- 3. Right-click **gallery_dev** → Query Tool ← new tab, new connection
-- 4. Paste and run ONLY the two lines below (F5)
--
-- If current_database() is not gallery_dev, you will get "relation paintings does not exist"
-- =============================================================================
SELECT current_database() AS connected_to; -- must show: gallery_dev
SELECT count(*) AS painting_count FROM paintings; -- expect ~1088
+27
View File
@@ -0,0 +1,27 @@
-- One-time dev/prod database split on TrueNAS PostgreSQL.
--
-- Preferred: pgAdmin on dev PC — open db/split-dev-prod-pgadmin.sql (step-by-step).
-- Alternative (if psql is installed): psql -h 192.168.10.122 -U postgres -d postgres -f db/split-dev-prod.sql
--
-- NOTE: CREATE DATABASE cannot run inside a DO block; this file uses standalone statements.
-- Disconnect clients
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname IN ('Gallery', 'gallery', 'gallery_prod', 'gallery_dev')
AND pid <> pg_backend_pid();
-- Rename legacy → gallery_prod (run ONE of these; comment out the other)
ALTER DATABASE "Gallery" RENAME TO gallery_prod;
-- ALTER DATABASE gallery RENAME TO gallery_prod;
-- Disconnect from prod before template clone
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'gallery_prod' AND pid <> pg_backend_pid();
-- Clone dev from prod (skip if gallery_dev already exists)
CREATE DATABASE gallery_dev WITH TEMPLATE gallery_prod;
GRANT ALL PRIVILEGES ON DATABASE gallery_dev TO gallery;
GRANT ALL PRIVILEGES ON DATABASE gallery_prod TO gallery;