MIGRATION_PLAYBOOK.md: discovery-driven plan з conditional branches (player/spot-rotation/R7-responsive/CSS-sync) + Phase 3 universal post-checks + anti-patterns з 8161 lessons
This commit is contained in:
@@ -105,6 +105,7 @@ git pull --rebase # ЗАВЖДИ перед роботою у bac
|
||||
| **[docs/SITES.md](docs/SITES.md)** | Таблиця 14 backup-tracked ports × домен × cluster × outlier flags |
|
||||
| **[docs/DEPLOY.md](docs/DEPLOY.md)** | Test t1.* ↔ prod flow, admin role, kor reload, cache-bust |
|
||||
| **[docs/ADS.md](docs/ADS.md)** | adspyglass інтеграція (skeleton — наповнюємо) |
|
||||
| **[docs/MIGRATION_PLAYBOOK.md](docs/MIGRATION_PLAYBOOK.md)** | Discovery-driven план для migration наступного site (player / banners / sidebar / CSS) з conditional branches |
|
||||
| **[docs/PERFORMANCE.md](docs/PERFORMANCE.md)** | PSI targets, rules, per-site scorecard (skeleton) |
|
||||
| **[docs/INTERLINKING.md](docs/INTERLINKING.md)** | Cross-site linking strategy (skeleton) |
|
||||
| **[docs/ADMINS.md](docs/ADMINS.md)** | Admin panels: translations, comments, site config (skeleton) |
|
||||
|
||||
187
docs/MIGRATION_PLAYBOOK.md
Normal file
187
docs/MIGRATION_PLAYBOOK.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# tubev — Site Migration Playbook
|
||||
|
||||
**Призначення:** robust план для міграції / refactor наступного site (player, banners, sidebar responsive, etc.). Не лінійний — **discovery-driven** з conditional branches. Кожен пункт може бути SKIP якщо feature відсутня.
|
||||
|
||||
> Спирається на досвід з 8148 (PlayerJS pilot), 8161 (full migration + R7 responsive sidebar), 8081 (videojs10 + bannersBlocks reference). Доповнення — у [ADS.md § Migration checklist](ADS.md#migration-checklist--legacy-videojs4--modern-playerjs--ad-bundle).
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Discovery (ОБОВ'ЯЗКОВО спершу)
|
||||
|
||||
Перед будь-якими правками — Claude **запитує юзера** + інспектує наявний site, фіксує scope. Без цього — risk hidden assumptions.
|
||||
|
||||
### A) Scope decisions (запитати юзера)
|
||||
|
||||
| # | Питання | Why it matters |
|
||||
|---|---------|---------------|
|
||||
| A1 | **Чи мігруємо player?** (videojs4 → PlayerJS / videojs10 / залишаємо?) | Якщо ні — skip Phase 3 player. |
|
||||
| A2 | **Чи замінюємо ad spot IDs?** (rotation / new account) — якщо так, дай mapping таблицю. | Якщо ні — skip banner spot rewrite. |
|
||||
| A3 | **Чи треба responsive sidebar→grid swap (R7-style)?** | Tільки якщо site має sidebar з ads AND junior-grid (related/recommended thumbs). |
|
||||
| A4 | **Чи зробити уніфікацію критичних inline + index.css?** | За замовчуванням так — запобігає FOUC. |
|
||||
| A5 | **Spec for site** — щось унікальне (custom player, ASG-bypass, GDPR overlay, etc.)? | Невідомі вимоги дізнаємось ранo, не пізно. |
|
||||
|
||||
### B) Site inspection (Claude робить empirically)
|
||||
|
||||
| # | Check | Tool / Command |
|
||||
|---|-------|----------------|
|
||||
| B1 | URL pattern для video page | grep `id_index` references у layout, парсинг `mysettings.location_css == "id"` block |
|
||||
| B2 | Player generation у DOM | `curl t1.<domain>/<video-url>` → grep `videojs\|PlayerJS\|pjs_container` |
|
||||
| B3 | Native banners серед thumbs (1thumb_a-f чи інший module чи нема) | `grep -rn 'native_allpg_1thumb\|render.*banners' views/modules/related_video.etlua views/modules/recommended_video.etlua` |
|
||||
| B4 | Sidebar layout (vi-side-col? інший?) | `grep -n 'embed_sidebar\|vi-side-col\|sidebar_adspy' views/id_index.etlua` |
|
||||
| B5 | Cols-change button (для bannersBlocks observer scope) | `grep -rn 'changeNumberCols\|data-changecolumns' views/` |
|
||||
| B6 | CSS layers — `index.css` + критичні `views/css/css_<page>.etlua` | `ls views/css/css_*.etlua` |
|
||||
| B7 | Shared lib references — `views/static/js/lib/` git submodule? | `cd views/static/js/lib && git remote -v` |
|
||||
| B8 | Cooldown regex у `layout.etlua` (popunder spot ID hardcoded) | `grep 'asgsl\|_popRr' layout.etlua` |
|
||||
| B9 | `c` counter call безпеки (`if(typeof c==="function")`) | grep `tb.start_events_v2` у `id_index.etlua` |
|
||||
| B10 | `lazyLoadFunc` defined inline | `grep -c 'function lazyLoadFunc' layout.etlua views/static/js/main.min.js` |
|
||||
|
||||
**Output Discovery phase:** короткий summary — "Site X: player Y, banners Z (mapping pending), sidebar W, cols-button A/N, etc." → юзер confirms scope перед Phase 2.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Conditional Task Branches
|
||||
|
||||
Кожна гілка SKIP-нулагається якщо Discovery показав feature відсутньою. **Кожна = окремий atomic commit.**
|
||||
|
||||
### Branch P (Player migration) — якщо A1=yes
|
||||
|
||||
→ повний 30+ checkpoint список у [ADS.md § Migration checklist](ADS.md#migration-checklist--legacy-videojs4--modern-playerjs--ad-bundle).
|
||||
- Inline lazysizes wrapper якщо main.min.js його не містить (R3).
|
||||
- `if(typeof c==="function")` guard (counter race fix).
|
||||
- foreign 8148 classes (`vdo-blk-*`) → site-native (`vi-limiter` etc.) (R5).
|
||||
- Playwright probe → pageerrors empty.
|
||||
|
||||
### Branch S (Spot ID rotation) — якщо A2=yes
|
||||
|
||||
- Replace IDs у `views/static/js/ad-config.js` (popunder.spot, vast.spot).
|
||||
- Replace `(?:^|\|)<id>=` regex у `layout.etlua` (must sync з ad-config!).
|
||||
- Replace IDs у `views/modules/banners/*adspy*.etlua` (footer/header/middle/sidebar/native).
|
||||
- 1thumb_a..f spots якщо site має those modules.
|
||||
- Per-site inventory таблицю — додати у [ADS.md § Per-site spot inventory](ADS.md#per-site-spot-inventory).
|
||||
- Build bundle → cache-bust md5.
|
||||
- ad-test → 6/6 PASS на новий popunder/vast spots.
|
||||
|
||||
### Branch R7 (Responsive sidebar→grid) — якщо A3=yes
|
||||
|
||||
Передумови: site має sidebar (`.vi-side-col` чи аналог) з ad slots AND grid (`#related_video_block` чи similar) з thumbs.
|
||||
|
||||
1. **Уніфікувати DOM IDs** sidebar slots (mobile + desktop templates обидва використовують ті самі ID — `sdd_a`/`sdd_b`).
|
||||
2. **Move banner-load logic** з template `<script>` у `id_index.etlua` inline → один місто, server-side `isMobile()` choose spot pair, callback `() => bannersBlocks.calc()`.
|
||||
3. **Inject `bannersBlocks` JS** з activateWidth (1024 default), main block selector (`#related_video_block`), thumb selector (`.video-item:not(.js-iframe_banner)`).
|
||||
4. **Banner wrapper class** — match site thumb structure (8161 = `<div class="video-item">`, 8081 = `<figure>`). Inspect 1 existing thumb DOM.
|
||||
5. **iframe transform scale** = thumbW / banner_natural_width (default 300) для banner content fit.
|
||||
6. **Wrapper height** = scaled height (250 * scale) для row consistency.
|
||||
7. **CSS hide empty sidebar:** `@media(max-width:<activateWidth>px){.<sidebar-class>{display:none}}` у обидва index.css + critical css_<page>.etlua.
|
||||
8. **MutationObserver:**
|
||||
- `mainBlock` — childList + class/style attrs (lazy-load thumbs)
|
||||
- `document.body` — attributes ['class'] (cols-change button updates body class — без observer banners stale)
|
||||
9. **Defer init** до DOMContentLoaded якщо script render-иться перед grid block.
|
||||
10. **Debounce calc** ~150ms на frequent events.
|
||||
|
||||
### Branch C (Critical CSS sync) — якщо A4=yes (default)
|
||||
|
||||
Кожна правка `views/static/css/index.css` → перевірити чи selector існує у відповідному `views/css/css_<page>.etlua` → дзеркалити rule. Без цього FOUC. Memory: `feedback_critical_inline_css_sync`.
|
||||
|
||||
### Branch X (Site-specific) — якщо A5 показав щось
|
||||
|
||||
Custom план залежно від спецификy. Документуй у session notes.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Universal post-checks (ALWAYS, незалежно від Branch)
|
||||
|
||||
Усі ці checkpoints — обов'язкові, незалежно від scope. Вони catch генеричні regressions.
|
||||
|
||||
### CSS / DOM
|
||||
- [ ] `index.css` + critical inline `css_<page>.etlua` мають однакові rules для торкнутих selectors.
|
||||
- [ ] No duplicate DOM IDs на сторінці (Playwright probe `Array.from(document.querySelectorAll('[id]')).map(e=>e.id)` + count duplicates).
|
||||
- [ ] No foreign-site classes (8148 `vdo-blk-*` etc.) у site-specific files.
|
||||
|
||||
### JS / errors
|
||||
- [ ] Playwright headless `pageerror` array empty при load video page (timeout 8s).
|
||||
- [ ] No `c is not defined` у inline `start_events_v2` (counter race).
|
||||
- [ ] No `lazyLoadFunc is not defined` у timeline-pjs (якщо використовується).
|
||||
- [ ] No `c2.min.js: Unexpected identifier` (re-minify якщо source edit).
|
||||
- [ ] Console clean: no ASGB loader errors.
|
||||
|
||||
### Ad pipeline
|
||||
- [ ] `ad-test "<test_url>"` → 6/6 PASS.
|
||||
- [ ] VAST endpoint returns `<Ad>` (curl) — не empty `<VAST/>` no-fill.
|
||||
- [ ] Popunder endpoint returns `renderSpot` JSON.
|
||||
- [ ] CDN serves fresh bundle (`curl t1/static/js/ad-bundle.min.js | grep spot:` reflects новий config).
|
||||
- [ ] adspyglass dashboard show графік не падає (ручний check 1-2h після deploy).
|
||||
|
||||
### Responsive (якщо Branch R7 активний)
|
||||
- [ ] Width > activateWidth: banners у sidebar slots, sidebar visible.
|
||||
- [ ] Width <= activateWidth: banners у grid (зайве sidebar hidden), no overlap з thumbs, row heights consistent.
|
||||
- [ ] Resize transition (drag window narrow → wide → narrow): banners move properly, no duplicate, no orphan.
|
||||
- [ ] Cols-change button click: banners recalc + reposition.
|
||||
- [ ] Hard-refresh test (browser cache `max-age=3600`): нові правила apply.
|
||||
|
||||
### Player (якщо Branch P активний)
|
||||
- [ ] Click play → VAST pre-roll shows (after popunder cooldown set on first visit).
|
||||
- [ ] After VAST done → main video starts via `_revealPjs()` callback.
|
||||
- [ ] Tooltip likes/dislikes над player chrome (z-index battle won).
|
||||
- [ ] Timeline thumb hover → play icon shown.
|
||||
- [ ] iOS Safari: `.no-js`/`.js` swap robitь native controls hidden.
|
||||
|
||||
### Diff / commit hygiene
|
||||
- [ ] Atomic commits — 1 commit per logical change (Branch P / S / R7 / C / X = окремий commit).
|
||||
- [ ] Commit messages пояснюють "WHY", не лише "WHAT".
|
||||
- [ ] `~/git-save-all.sh` (якщо є backup_<port>) виконано.
|
||||
- [ ] Push до origin (якщо SSH key authorized).
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Production verification
|
||||
|
||||
- [ ] Юзер натискає button у `https://rss.g--o.info/admin/site/control` для prod deploy.
|
||||
- [ ] 5-10 хв — adspyglass dashboard продовжує показувати impressions.
|
||||
- [ ] Кейс real-юзер test (попросити reload + перевірити likes/timeline/banners visually).
|
||||
|
||||
---
|
||||
|
||||
## Anti-patterns (не повторювати помилок 8161 migration)
|
||||
|
||||
1. **Скопіювати foreign classes (`vdo-blk-lmtr`) тільки тому що 8148 так робить.** Site має native equivalent — використовуй його. R5 урок.
|
||||
2. **Append external JS file (`tb.append_script`) коли можна inline.** Зайвий HTTP request. R3 урок.
|
||||
3. **Edit тільки `index.css` без критичного `css_<page>.etlua`.** FOUC на first paint. Юзер скаржиться. Урок 2026-05-04.
|
||||
4. **Compound bash chains з fail-prone steps** (`cd && head wrong-file`). Червоні errors дратують юзера. Урок 2026-05-04.
|
||||
5. **Single-line snippet output форсити.** Терминал word-wrap ламає copy → file workflow краще. Урок 2026-05-04.
|
||||
6. **Early-return у calc() тільки на widthLine** — не зловити thumb width зміну (button cols toggle). Має track обидва. R7 урок.
|
||||
7. **observe лише `mainBlock` без body** — cols-button updates body class, banners stale. R7 урок.
|
||||
8. **Брати template з memory без verify** — пишемо у memory одразу коли юзер каже "це знадобиться", не після compaction. Урок 2026-05-04.
|
||||
|
||||
---
|
||||
|
||||
## Cheat-sheet команд
|
||||
|
||||
```bash
|
||||
# Discovery
|
||||
grep -rn 'PATTERN' /home/nosfortube/frontend_<port>/views/
|
||||
|
||||
# Test ad pipeline
|
||||
ad-test "https://t1.<domain>/v/<id>/<slug>"
|
||||
|
||||
# Empirical browser probe (write to /tmp first, не до /home/w4/playwright-tests/)
|
||||
node /tmp/probe-X.mjs
|
||||
|
||||
# Build ad bundle (8148-only — інші sites копіювати pipeline)
|
||||
bash views/static/js/build-ad-bundle.sh
|
||||
|
||||
# Snippet delivery до VSCode
|
||||
cat > /home/nosfortube/orest/snippet.txt << EOF
|
||||
...
|
||||
EOF
|
||||
```
|
||||
|
||||
## Memory rules що activate-яться під час migration
|
||||
|
||||
- `feedback_critical_inline_css_sync` — CSS dual-layer
|
||||
- `feedback_clean_bash_no_red` — Read tool > head/cat
|
||||
- `feedback_use_bots_proactively` — gocc1/gocc2 для audit/research parallel
|
||||
- `feedback_pre_push_subagent` — code-reviewer на diff перед push
|
||||
- `feedback_clipboard_snippet_workflow` — snippet → file
|
||||
- `reference_native_banner_templates` — ASG ExoClick / TrafficStars wrappers
|
||||
- `reference_ad_regression_tool` — ad-test usage
|
||||
- `project_player_roadmap` — generation map sites
|
||||
Reference in New Issue
Block a user