Files
vtube/docs/RECOMMENDATIONS.md

359 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# tubev — Recommendations Backlog
**⚠️ Це РЕКОМЕНДАЦІЇ, не PLANS.** Кожен пункт виявлено через audit (gocc1+2+3+4 на 2026-04-30) і чекає developer-go перед виконанням. goboss періодично нагадує про unprocessed items на session start.
Типи: **REFACTOR** (структурна зміна без зміни поведінки) / **CLEANUP** (видалення dead code) / **BUG** (неправильна поведінка) / **FEATURE** (нове). Деталі: [REFACTOR_RULES.md](REFACTOR_RULES.md).
---
## 🚨 HIGH severity — Security
### S1. SRI / integrity для third-party JS *(BUG/FEATURE)*
**Where:** layout*.etlua усіх 14 сайтів
**Files:** `ajax.googleapis.com/.../jquery.min.js`, `cdn.jsdelivr.net/...flatpickr/pikaday`, `verifycdn.agego.com/v1/verify.js`, `https://a5.g--o.info`, `https://t1.tubev.sex/static/js/{interdata.min,sync}.js`
**Why:** Compromise CDN → arbitrary JS у браузері користувача. Особливо `agego.com`, `g--o.info` — third-party без вашого контролю.
**What:** pin-version + `integrity="sha384-..."` для кожного CDN script ABO self-host.
**Effort:** M (2-4h per site, batch'ами)
**Status:** OPEN. Чекає developer-go.
### S2. Origin audit obfuscated JS *(BUG)*
**Where:** 10+ файлів random-name JS, не у sync.sh
**Files:** `c24c4cd9.js`, `N7Ym4F.js`, `popa.js`, `f4T4s.js`, `gD0A3.js`, `qDap9.js`, `mo.js`, `aOKM9.js`, `9qFdXQ7.js`, `gk5LT.js`, `PxqbeCb.js`, `k3KL5.js`
**Sites:** 8084, 8085, 8102, 8107, 8112, 8126, 8131
**Why:** Підозріло на adblock-bypass payloads ABO malicious drop. Нема git track, нема sync.sh entry, обфусковані імена.
**What:** Audit походження. Якщо ваші → перейменувати + покласти у sync.sh + git track. Якщо невідомі → видалити після перевірки що active loading не залежить.
**Effort:** S (1-2h)
**Status:** OPEN. Питання до developer: ваші чи невідомі?
---
## 🟡 MEDIUM severity
### M1. 8112 — два GA properties в одному gtag *(BUG)*
**Where:** `backup_8112/views/modules/ga/ga.etlua`
**Why:** gtag config містить одночасно `G-CQN2KFSXSG` і `G-WW50B2EGSJ` → дані пишуться на 2 property. Imовірний bug — не сумісно з legitimate analytics workflow.
**What:** Підтвердити з developer який ID правильний. Видалити інший.
**Effort:** XS (15 min)
**Status:** OPEN. Питання до developer.
### M2. site_domain / GA ID / CDN host → config *(REFACTOR)*
**Where:** layout/header `.etlua` всіх 14 сайтів
**Why:** Site domain hardcoded у CSP `form-action`, `preconnect`, partner logo links. GA IDs hardcoded. CDN hosts hardcoded. Зараз — по N літералів у кожному layout. Drift-prone.
**What:** Створити `views/config/site.lua` (або еквівалент Lua module) з constants:
```lua
return {
domain = "hdsexvideo.xxx",
ga_id = "G-CQN2KFSXSG",
cdn_pic = "cdn-pic.hdsexvideo.xxx",
cdn_video = "...",
partners = { "fulltube.xxx", "nu-bay.com", ... },
}
```
Layout uses `<%= site.domain %>`, `<%= site.ga_id %>`.
**Effort:** M (4-6h)
**Status:** OPEN.
### M3. CSP — meta → HTTP header *(REFACTOR)*
**Where:** layout*.etlua з `<meta http-equiv="Content-Security-Policy" ...>`
**Why:** meta-CSP не може встановити `frame-ancestors` / `report-uri`, повільніший за HTTP header. Зараз 8084 (та інші) використовують meta.
**What:** Перенести у nginx config. Може треба developer-side change бо nginx config не наш scope.
**Effort:** S frontend-side / depends backend
**Status:** OPEN. Залежить від developer.
### M4. modules/video.etlua → shared partial *(REFACTOR)*
**Where:** `views/modules/video.etlua` × 14/14 сайтів
**Why:** 67-77% common lines, найвища similarity з усіх модулів. 14 окремих копій що data-loop ідентичний, але class names + tweaks per site.
**What:**
- Extract base partial з `<%= include 'modules/video_base' %>`
- Per-site theme = CSS overrides (не template fork)
- Shared params: `<%= video, css_class, lazy_load %>`
**Effort:** M (4-6h)
**Status:** OPEN. **Найбільший SSOT win** з усіх refactor candidates.
### M5. 8081 layout split *(REFACTOR)*
**Where:** `backup_8081/views/layout.etlua` (1223 рядки monolithом)
**Why:** Outlier. Median решти ~200 рядків. Усі profile_*.etlua унікальні тут — 8081 has different architecture (NL agego, premium fork).
**What:** Розбити на partials аналогічно іншим 13 сайтам (header.etlua + footer.etlua + bottom_block.etlua + main.etlua).
**Effort:** L (8-12h, ПІСЛЯ M4 — щоб 8081 теж пристосувався до shared video partial)
**Status:** OPEN. Залежність: M4.
### M6. 8112 static/ duplicate tree *(CLEANUP/REFACTOR)*
**Where:** `backup_8112/static/{js,css,img,jsplayer,player,trade-th,tmp}``backup_8112/views/static/...`
**Why:** Дві ідентичні копії (md5-confirmed). Один live, інший stale.
**What:** З'ясувати який referenced (читай OpenResty config якщо доступно, або питай developer). Видалити інший.
**Effort:** M (2-4h, потребує OpenResty config check)
**Status:** OPEN. Питання до developer.
### M7. 8085 submodule drift *(BUG)*
**Where:** `backup_8085/views/static/js/lib`
**Why:** Modified submodule reference (`m` у git status). Submodule гілка drift'нула від трекованого коміту. Або локальний edit, або prod оновив submodule а tracking — ні.
**What:** З'ясувати з developer: rollback або commit поточний state.
**Effort:** XS (15 min)
**Status:** OPEN. Питання до developer.
### M8. 8086 sync drift — 30+ legacy файлів *(CLEANUP)*
**Where:** `backup_8086/views/`
**Why:** Sync.sh селективно копіює ~25 файлів, але диск містить ~30+ legacy не у sync.sh: `asdadsasd.html`, `layout_bak_25-05-18.etlua`, `id_index_copy_with_cjannels.etlua`, `del___search_top.etlua`, `header_with_country_if.etlua`, `layout_copy_withads.etlua`, plus 24+ модулів.
**What:**
1. Audit чи щось з цього reference'ed у живому layout/modules
2. Unreferenced → видалити
3. Sync 8086 на rsync-парадигму (Group A) — `--delete` зачистить решту
**Effort:** S (1-2h)
**Status:** OPEN.
### M9. 8112 untracked drift *(CLEANUP/BUG)*
**Where:** `backup_8112/{rotator/,lib/,nginx.conf,nginx.conf.compiled,redirect_*.nginx}`
**Why:** Untracked у git, але присутні на disk. `rotator/` має 40+ файлів `1_<lang>.txt` (i18n) + `cats.txt` symlink → `/home/nosfortube/frontend_8112/rotator/data/cats.txt`. backup mirror'ить prod app structure частково.
**What:** Or:
- Додати у sync.sh + git track (якщо потрібно у backup)
- Виключити (`gitignore` + не sync) (якщо не потрібно)
**Effort:** S (1h)
**Status:** OPEN. Питання до developer.
---
## 🟢 LOW severity / cleanup
### C1. Видалити DEL_* tombstones *(CLEANUP)*
**Where:** 24 файли × 6 сайтів
**Files:** `DEL_channel_id.etlua`, `DEL_friend_list.etlua`, `DEL_lang.etlua`, `DEL_lang_mob.etlua`
**Sites:** 8100, 8102, 8107, 8112, 8131, 8133
**Why:** Префікс DEL_ явно signals tombstone, але файли досі живуть. Шум grep-у, ризик випадкового деплою.
**Effort:** XS (15 min)
**Status:** OPEN.
### C2. Видалити backup-via-rename артефакти *(CLEANUP)*
**Where:** ~30 файлів з пробілами / " copy" / "with ads" / "without ads" / "with titles"
**Files:** Окремі категорії:
- `header copy bongo link 25_10_22.etlua` × 5 сайтів (8084, 8085, 8112, 8126, 8131; з typo `bogolink` на 8112)
- `id_index copy_ads_actual.etlua` × 2 (8084, 8085)
- `cat_list_thumb with ads.etlua` × 10 (8112)
- `* with titles.etlua` × 5 (8100)
- `untitled file` × 2 (8126)
- `my copy.js`, `machine copy.js`, etc. × 8
**Why:** File names з пробілами ламають shell scripts. Версії повинні бути у git.
**Effort:** S (1h)
**Status:** OPEN.
### C3. Видалити legacy `*_old/` dirs *(CLEANUP)*
**Where:** `backup_8085/views/static/{js_old/,img_old/}` (6+25 файлів)
**Why:** "_old" — explicit legacy marker.
**Verification:** `grep -rn "js_old\|img_old" backup_8085/` → 0 матчів = safe to delete.
**Effort:** XS (30 min)
**Status:** OPEN.
### C4. Видалити legacy UA-* GA *(CLEANUP)*
**Where:** `views/modules/ga/ga.etlua`, `static/js/ga.js`, `layout-orig.etlua`
**Sites:** 8081, 8086, 8100, 8112, 8126
**Why:** Universal Analytics EOL 2023-07-01. UA-* IDs не shipping data, але збільшують attack surface (extra script tag) і гасять performance.
**Files з UA-:** `UA-128492434-7`, `UA-109631925-*`, `UA-105546426-7` (7 унікальних)
**Effort:** XS (30 min)
**Status:** OPEN.
### C5. Видалити paginator_old / video_test варіанти *(CLEANUP)*
**Where:** `views/modules/`
**Sites:** 8084 і 8085
**Files:** `paginator_old.etlua`, `cat_list_thumb_test.etlua`, `cat_index_test.etlua`, `main_list_test.etlua`, `video_test.etlua`, `counters.min.test.js` (8133)
**Why:** Tests / older versions у prod tree.
**Effort:** XS (15 min)
**Status:** OPEN.
### C6. Уніфікувати sync.sh на rsync *(REFACTOR)*
**Where:** 7 selective sites: 8081, 8086, 8112, 8120, 8129, 8133, 8148
**Why:** 7 з 14 уже на ідентичному rsync template (74a6acb…). 7 інших роблять те саме через ad-hoc whitelists. Drift-magnet, важко synced модулі для нових сайтів.
**What:** Замінити selective `cp` allowlists на 12-line rsync template. Виняток — 8148 build-step (виносити окремо в `build.sh`).
**Effort:** S (1h)
**Status:** OPEN.
### C7. 8148 — винести build з sync.sh *(REFACTOR)*
**Where:** `backup_8148/sync.sh` (виконує `sed -i` MUTATION на prod source)
**Why:** sync.sh не повинен мутувати джерело. Build step і sync — різні concerns.
**What:**
- `build.sh` робить ad-bundle build + md5 + sed
- `sync.sh` робить тільки rsync mirror
- Pipeline: `build.sh && sync.sh` — explicit ordering
**Effort:** S (1h)
**Status:** OPEN.
### C8. Naming convention enforcement *(FEATURE/REFACTOR)*
**Where:** Pre-commit hook (per-repo) ABO server-side guard
**Why:** Запобігти повторного появи pробілів у file names, " copy", DEL_*, _test*, obfuscated random names. Інакше backlog буде відновлюватися.
**What:**
- Pre-commit script blocks: `[ a-zA-Z0-9_./-]` чорний список (тільки лат+цифри+`_./- `)
- Block `^DEL_`, `*test*` у production paths
- Document у [docs/NAMING.md](NAMING.md) (TODO P4)
**Effort:** S (1h script + 1h documentation)
**Status:** OPEN.
### C9. Min/non-min JS policy *(REFACTOR)*
**Where:** `c2.{js,min.js}`, `main.{js,min.js}`, `my.{js,min.js}`, `jquery-3.2.1.{js,min.js}` etc.
**Why:** Production = тільки `.min.js`. Dev = source. Зараз обидва у репо — шумно.
**What:** Pre-commit minifier ABO build-step pipeline. Source у `src/`, minified у `static/js/`.
**Effort:** M (3-5h, build pipeline)
**Status:** OPEN. Потенційно потребує developer-side build infrastructure.
### C10. CSS file naming standardization *(REFACTOR)*
**Where:** 8084 (no `views/css/` folder), 8086 (`styles.etlua` instead of `css_<page>.etlua`), 8148 (no folder)
**Why:** 11/14 use `css_<page>.etlua` pattern → решта 3 не вписуються.
**What:** Привести 8084/8086/8148 до `css_<page>.etlua` convention. Якщо вони мають окрему причину (8148 — sprite-driven, не split per page) — задокументувати у [SITES.md](SITES.md) виняток.
**Effort:** S (1-2h)
**Status:** OPEN.
### C11. Cross-site partner logos через config *(REFACTOR)*
**Where:** `header*.etlua`, layout footer-блоки 7 сайтів
**Sites:** 8084, 8085, 8086, 8100, 8102, 8126, 8131
**Why:** Hardlinks на партнерські сайти (`fulltube.xxx`, `hdsexvideo.xxx`, `nu-bay.com`, `gaypornhd.xxx`, `xxxtube1.com`, `fullhdxxx.com`, `maturesexmovies.xxx`) — кожен layout має свої literals.
**What:** Винести у `views/config/partners.lua` як array. Layout iterates.
**Effort:** S (1-2h, після M2 site.lua)
**Status:** OPEN. Залежність: M2.
---
## 🛠 INFRASTRUCTURE / Workflow
### W1. Hook conflict — Claude editing у `/home/nosfortube/` *(BUG/FEATURE)* ✅ DONE 2026-05-02
**Resolution:** Granular policy реалізована у `guard-readonly.sh` + `guard-bash.sh`. ALLOW `frontend_<port>/` (digits-only) + `orest/`. DENY lang variants, frontend_core, .git, system paths. Backup попередніх hooks: `.bak.2026-05-02`. Test matrix: 19/19 readonly + 18/19 bash (1 pre-existing sed-i regex limitation).
### W2. backup_<port>/ scope — 14 із 94 сайтів *(FEATURE)*
**Where:** `/home/w4/backup_*/`
**Problem:** git-tracking покриває 14 сайтів, інші 80 без recovery. Можливі причини: історичний субсет / pilot / залишки старого етапу.
**Options:**
- Зберегти 14 (subset для критичних сайтів)
- Поширити на всі 94 (масовий setup `sync.sh` + initial commits)
- Замінити на централізований моніторинг + adminskий git
**Effort:** L якщо поширити (ініт repos + sync.sh per site + перші commits).
**Status:** OPEN. Залежить від наскільки git-history важливий vs adminove ownership.
### W3. PSI automonitoring *(FEATURE)*
**Where:** Future infra
**Problem:** Поточний PSI check — manual через pagespeed.web.dev, не systematic. Регресії можуть бути непомічені до next ad-revenue падіння.
**What:** PSI API + cron → daily snapshot + history db + alert при падінні. Або Lighthouse-CI на t1.* після deploy.
**Effort:** M-L (setup ~6-12h)
**Status:** DEFERRED (in-mind, не пріоритет — поки adspyglass dashboard як signal).
---
## 📚 DOC items
### D1. ad-bundle source files location
**Where:** [ADS.md § Source files](ADS.md#source-files)
**What:** Знайти де живуть 5 source JS-файлів (`ad-config.js`, `ad-core.js`, `ad-mute.js`, `vast-preroll.js`, `ad-bootstrap.js`) — `frontend_<port>/views/static/js/` чи shared. Записати у ADS.md.
**Effort:** XS (15 min, `find /home/nosfortube/ -name 'ad-config.js'`)
**Status:** OPEN — потрібен hook resolution (W1) щоб дослідити.
### D2. Mirror swap mechanism
**Where:** [ADS.md § Open questions](ADS.md#open-questions-for-developer) Q3
**What:** Зрозуміти як Адмін заміняє banned mirror — через ad-config.js mass replace, runtime config, чи інше. Записати у ADS.md.
**Effort:** S (питання до developer + 1 example)
**Status:** OPEN.
### D3. CDN provider
**Where:** [DEPLOY.md § Open questions](DEPLOY.md#open-questions)
**What:** Який CDN на prod (Cloudflare / BunnyCDN / Fastly / custom). Per-site або unified.
**Effort:** XS (питання до developer)
**Status:** OPEN.
### D4. Template ad-zone pattern
**Where:** [ADS.md § Template integration](ADS.md#template-integration)
**What:** 1 sample template fragment з ad-zone для розуміння placement pattern.
**Effort:** XS (показати 5-10 рядків з template)
**Status:** OPEN.
---
## Reminders cadence
goboss перевіряє цей файл **на початку кожної session** і нагадує developer-у:
- Скільки items OPEN (по severity)
- Що було додано з минулої session
- Найдешевші items (XS-S) — пропонувати спершу
- Найпріоритетніші (HIGH) — окремо помічати
Items з статусом `DONE`, `WONTFIX`, `DEFERRED` переходять у footer цього файлу (history), щоб не плутатися з активним backlog.
---
## DONE / WONTFIX / DEFERRED
*(порожньо — поки нічого не виконано)*
---
*Last update: 2026-05-01 (W1-W3 workflow + D1-D4 doc items added).*
*Initial backlog: 2026-04-30 (gocc1+2+3+4 audits).*
## D-canonical-archive — Canonical points to `/v/` instead of archive URL pattern (13 sites)
**Зона:** Backend (admin/dev) — потребує kor reboot.
**Symptom:** На archive routes (`/v/arch/`, `/v-cache/`, `/v/stored/`, etc. per CSV new-url-pattern) canonical link генерується як `/v/<id>/...` (standard) замість archive URL. Robots `noindex,follow` правильно set, але canonical не reflects archive.
**Root cause:** `views/id_index.etlua` line ~90 hardcodes `/v/` у canonical generation. Frontend не має access до runtime URL (`ngx.var.uri` not accessible у etlua context, `mysettings.cur_uri` not set).
**Reference (8161 has partial setup):**
- `var.archive_video_dir = "/v-arch/"`
- `var.canonical_without_archive = 1` — explicit strip → canonical = standard `/v/` (BY DESIGN для 8161)
- `app.lua` line 2408-2409 використовує `archive_video_dir` для URL formation
**Fix per site (13 sites — крім 8161 яке by design strip):**
```lua
-- lib/<port>/var.lua
var.archive_video_dir = "<new-pattern-per-CSV>" -- e.g. "/v/arch/" для 8159
var.canonical_without_archive = 0 -- canonical KEEPS archive prefix
var.nofollow_on_archive = 1 -- if not already
```
Per CSV `new-url-pattern` column:
| Port | new-url-pattern |
|------|-----------------|
| 8159 | /v/arch/ |
| 8163 | /v-cache/ |
| 8158 | /v/stored/ |
| 8151 | /v/old/ |
| 8160 | /v/storage/ |
| 8153 | /v/archive/ |
| 8154 | /v/unlisted/ |
| 8155 | /v/shelved/ |
| 8156 | /v/disabled/ |
| 8157 | /v/bin/ |
| 8162 | /v-storage/ |
| 8150 | /video/old/ |
| 8152 | /v/parked/ |
Plus `subrouter.lua` route registration якщо missing — verify each site handles archive route.
**Verify post-deploy:**
```bash
curl -sL "https://www.<domain>/<archive-pattern><id>/<slug>" | grep -oE 'rel="canonical" href="[^"]+"'
# Expected: href="https://www.<domain>/<archive-pattern><id>/<slug>" (canonical=archive URL)
```
**Frontend template** (`id_index.etlua`) можливо потребує adjustment коли backend exposes `mysettings.cur_archive_path` чи similar — depending on app.lua implementation.
Reported 2026-05-05 by user audit на 8159 → bug confirmed на ВСІХ 13 sites with archive routing setup.
## D-canonical-archive-regression — REGRESSION у нових `getLinks()` (~20 sites)
**Update 2026-05-05:** Audit deeper показав що це **regression**, не intended config.
**Reference (correct behavior — pre-batch sites):**
- broxxx.com (8133), pornv.xxx (8120): same `var.canonical_without_archive=1`, але archive route → `getLinks()` повертає `cur_canonical=""` → layout skip emit → **no canonical on archive**
- Це matching intent variable name "canonical_without_archive" = "canonical видається без archive context, тобто на archive не emit-иться".
**Bug (regression — newer sites):**
- 8161, 8159, 8163, 8158, 8151, 8152, 8153, 8154, 8155, 8156, 8157, 8158, 8160, 8162, 8140, 8141, 8142, 8145, 8148, 8149: same config `=1`, але archive route → `cur_canonical=<standard URL stripped>` → canonical EMITS до /v/.
- Це over-engineered — backend strips archive prefix замість returning empty.
**Scope:** 20 sites confirmed: 8140, 8141, 8142, 8145, 8148, 8149, 8151, 8152, 8153, 8154, 8155, 8156, 8157, 8158, 8159, 8160, 8161, 8162, 8163, 8150 (weird). Different `getLinks()` implementations у `lib/<port>/content.lua`.
**Fix (backend dev task):**
- Identify які content.lua versions мають regression.
- Patch `getLinks()` to return `cur_canonical=""` when `canonical_without_archive=1` AND archive route.
- Match broxxx/pornv behavior (старий правильний reference).
- kor reboot per site.
**Verify:** після fix на archive URL — `<link rel="canonical">` має бути absent (як у broxxx/pornv).
Reported 2026-05-05 by user audit. Frontend template OK — issue у `getLinks()` core return value.