Files
vtube/docs/RECOMMENDATIONS.md

21 KiB
Raw Permalink Blame History

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.


🚨 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:

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 (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 виняток. 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_/ 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 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 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 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 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):

-- 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:

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.

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.