# tubev — Deploy Flow Як зміна потрапляє з робочого місця → у prod. ## Two-tier model ``` Edit /home/nosfortube/frontend_/ ← work / source-of-truth │ ├──→ t1. ← test (instant, IP-allowlist) │ └──→ admin panel "site/control" ← prod деплой per-site (юзер натискає) або через Адміна ← для var.lua / нових файлів │ └──→ ← live, з CDN ``` ## Test environment — `t1.` - **Доступ:** IP-allowlist (ймовірно nginx-level, не точно). Юзер заходить через VPN щоб мати стабільний IP. - **Apply:** instant — змінив файл у `frontend_/` → видно на t1. одразу. - **Обмеження** (per-site різні): CDN off, compression off, повільніше, comments/ads можуть бути обмежені або тестові. - **AI-side:** ✅ Claude з сервера **МАЄ доступ** до t1. (server IP `185.73.222.75` у allowlist). Перевірено 2026-05-01: `curl -I https://t1.atube.sex` → 200 OK, `curl -I https://t1.hdsexvideo.xxx` → 200 OK. Можна робити HTTP probes для health-check, regression smoke, response inspection. ## Prod deploy — три шляхи ### A) Через admin panel "site control" (юзер сам, instant per-site) `https://rss.g--o.info/admin/site/control` — список усіх сайтів, кнопка викатати оновлення з тесту → прод. **Покриває:** templates `.etlua`, CSS, JS (звичайні per-site файли). **Не покриває (потрібен Адмін):** - `lib//var.lua` — нові/змінені змінні - Нові файли (yet not in admin's git) - Shared `views/static/js/lib/`, `lib2/` (cross-site impact) ### B) Через admin panels (settings / translations / sitemap) Контент-шар, не код. Самостійно, без Адміна: - Per-site settings: `https:///admin/index`, `/admin/settings` - Languages set: `https:///moderation/languages/langs` - Translations (UI strings): `https:///moderation/languages/translation/` - Sitemap: `https://rss.g--o.info/admin/site` Деталі: [ADMINS.md](ADMINS.md). ### C) Через Адміна (Орест / основний програміст) - Нові файли потрапляють у Адмінів git → kor pull/reload - `var.lua` зміни → kor reboot - Mass operations (mirror swaps, multi-site fixes) Trigger: попросити (чат / задача). ## kor reload - `lib//var.lua` зміни → потрібен **kor reboot** щоб env змінні підвантажилися - Templates `.etlua` — підхоплюються hot (без reboot) - Static assets — hot, але **CDN cache** може тримати стару версію → потрібен **cache-bust** (через `?v=` у layout — реалізовано у `~/git-save-all.sh`) ## CDN - **Custom CDN** для більшості сайтів (наявний; провайдер невідомий поки) - **Cloudflare** на двох сайтах (наприклад **8081**) — додаткове edge кешування - **При оновленні prod** для Cloudflare-сайтів: треба **purge cache** + враховувати у логіці що зміни не миттєві (cache TTL до purge) - Cache-bust через `?v=` у `layout.etlua` працює для обох (custom + CF) ### ⚠️ Stale-cache gotcha (custom CDN, 8148 confirmed 2026-05-02) Custom CDN serve-ить різні `cache-control` залежно від виду query string: | Pattern URL | s-maxage | Поведінка | |-------------|----------|-----------| | `?v=` (md5 prefix) | **31536000 (1 рік)** | "Content-addressed asset" — immutable, edge cache aggressive | | `?v=` (число, ZZZZ etc.) | 10 sec | Швидко refresh-иться | | (no query) | ~ | Звичайний cache | **Race condition при deploy:** 1. Template (layout.etlua) deploy-иться з новим `?v=` reference 2. До того як static (`ad-bundle.min.js`) сам file deploy-иться — браузер/crawler hit-ить `/ad-bundle.min.js?v=` 3. CDN cache-miss → origin ще має OLD bundle → CDN кешує OLD під новим `?v=` ключем 4. Static deploy-иться з NEW bundle, але **CDN cache stuck на 1 рік** з OLD content **Симптом:** `curl /ad-bundle.min.js` → NEW. `curl /ad-bundle.min.js?v=` → OLD. Live site поломаний. **Рішення:** - Bump bundle md5 (тривіальна зміна у source — додаткова line, build stamp): `git-save-all.sh` rebuilds → новий md5 → новий ?v= → нова cache entry → fresh - Або **purge CDN cache** (через адмін / hostiserver) - Краще довгостроково: змінити cache-bust scheme у `git-save-all.sh` щоб включав timestamp (`?v=-`) → завжди унікально Перевірка чи це сталося: `curl -sI /?v= | grep s-maxage` — якщо `31536000`, кеш заблокувався на рік. ## git-save-all.sh — git-snapshot для backup_/ `~/git-save-all.sh "msg"` ітерує `/home/w4/backup_*/`: 1. **`sync.sh` per backup** — копіює з prod (`/home/nosfortube/frontend_/`) у backup. **Tracked subset** (whitelist у sync.sh): templates (`layout.etlua`, `id_index.etlua`, `video.etlua`, banner modules), ad orchestration JS (`ad-config.js`, `ad-core.js`, `vast-preroll.js`, `ad-bundle.min.js`), player files, тести, robots.txt. Решта prod-коду — поза git. 2. **Auto-rebuild ad-bundle:** якщо будь-який з 5 source JS (`ad-config.js`, `ad-core.js`, `ad-mute.js`, `vast-preroll.js`, `ad-bootstrap.js`) новіший за `ad-bundle.min.js` → запуск `bash build-ad-bundle.sh` (terser concat+minify). 3. **Cache-bust:** md5sum bundle → перші 7 hex → `sed -i ?v=...` у `views/layout.etlua`. Idempotent (однаковий контент = однаковий хеш). 4. **Commit per backup:** message формат `YYYY-MM-DD_HH:MM - [backup_]`. Кожен backup repo окремо — N changed sites = N commits у різних repos. **Призначення:** git-tracking для recovery / audit / blame. **Не deploy mechanism.** ## Open questions - [ ] CDN — який провайдер (Cloudflare / BunnyCDN / Fastly)? Per-site чи unified? - [ ] Backup_/ покриття — чому 14 із 94 сайтів? Поширити чи це історичний субсет? (open-разом з юзером) - [ ] Headless browser (Puppeteer / Playwright) на сервері для visual regression / ad-render check — варто setup-нути на потребу?