Files
2meet-data-optimizer/PLAN.md
T

278 lines
18 KiB
Markdown
Raw 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.
# PLAN — 2meet Data Optimizer (核心)
> 完整四階段拆分計畫見 `~/.claude/plans/wp-data-optimizer-2meet-data-optimizer-zesty-liskov.md`
---
## Current state
- **Version**: 0.1.0 (scaffold + 4 phase 完成 2026-05-15)
- **Phase**: 全 4 phase 已完成
- **Source**: 從 `wp-data-optimizer v2.16.0` 提煉
---
## Phase 0 ✅ — 骨架建立 (2026-05-15)
- [x] 12 plugin 目錄結構(核心 + 11 AddOn
- [x] 主檔 `2meet-data-optimizer.php` + Plugin Header
- [x] `includes/class-tmdo-bootstrap.php` stub
- [x] `uninstall.php` stub
- [x] `composer.json`
- [x] `.gitignore`
- [x] 7 件 MDREADME / PLAN / CHANGELOG / DEPLOY / SECURITY / DESIGN / CLAUDE
---
## Phase 1 ✅ — Core v0.1.0 (2026-05-15)
- [x] rsync 從 wp-data-optimizer 複製 ~110 個核心檔案,排除 HP/WC/LP/2meet 整合
- [x] 檔名 `class-wpdo-*``class-tmdo-*`(含 abstract / interface / trait
- [x] sed 內容批次 rename`WPDO_``TMDO_`class + 常數,hook/table/option 前綴 `wpdo_` 保留共用)
- [x] 常數 `TMDO_PLUGIN_DIR``TMDO_PATH` 等對齊
- [x] Text-domain `'wp-data-optimizer'``'2meet-data-optimizer'`
- [x] 主檔重寫成完整 loaderrequire chain ~150 行)
- [x]`tmdo_run()` boot 函式 + `plugins_loaded:4` action
- [x]`late-bind safety net` (priority 30) 確保 AddOn listener 收到 hook
- [x]`includes/class-tmdo-back-compat.php` — 80+ class_alias + 8 常數 alias + 9 hook dual-fire
- [x] 移除 `register_hivepress_defaults()` (193 行) → 搬到 HP AddOn
- [x] 把 core 內所有 HP/WC/LP 整合 class 引用加 `class_exists` 守門
- [x] PHP lint111 files PASS
- [x] Live test`wp tmdo doctor` 全 PASS、`wp wpdo` (alias) 通
**Phase 1 DoD:✅ 全達標**(除舊 unit/integration test 套件需後續 phase 1 follow-up
---
## Phase 2 ✅ — Hub + Spoke AddOn v0.1.0 (2026-05-15)
### Hub AddOn (`2meet-data-optimizer-hub-addon`)
- [x] `TMDO_Hub_Bootstrap` 主啟動類別
- [x] `TMDO_Hub_Vendor_Field` — 註冊 `_2meet_global_vendor_id` (hp_vendor / cold zone / indexed)
- [x] `TMDO_Hub_Custom_Tables` — 註冊 12 張 `2mhc_*` 自訂表(fallback 列表 + delegate to hub-core helper if available
- [x] dual-emit 支援 (`tmdo_*` + `wpdo_*` 兩個 hook 路徑)
- [x] PHP lint PASS
### Spoke AddOn (`2meet-data-optimizer-spoke-addon`)
- [x] `TMDO_Spoke_Bootstrap` 主啟動類別
- [x] `TMDO_Spoke_SSO_Group` — 註冊 user entity `sso` group7 欄位 → wp_wpdo_user_sso
- [x] `TMDO_Spoke_Custom_Tables` — 註冊 `2mso_sso_config` / `2mso_user_mapping`
- [x] `TMDO_Spoke_CLI::sync()` — 從舊 `_tmso_*` usermeta 遷移
- [x] `TMDO_Spoke_CLI::force_logout()` — 設置 token_expires_at = 過去
- [x] CLI 雙命名空間:`wp tmdo spoke-*` + `wp wpdo spoke-*`
- [x] PHP lint PASS
**Phase 2 Live test 結果:**
- ✅ Hub: 12 hub tables 全部 OK
- ✅ Spoke: SSO group 7 fields registered, 2 tables registered
- ✅ CLI: `wp tmdo spoke-sync --dry-run` 跑通,`spoke-force-logout --user-id=1 --dry-run` 跑通
---
## Phase 3 ✅ — HP + WC + LP AddOn v0.1.0 (2026-05-15)
### HivePress AddOn (`2meet-data-optimizer-hivepress-addon`, ~7,400 行)
- [x] 複製 13 adaptercore / reviews / bookings / messages / memberships / requests / favorites / statistics / tags / seo / social-links / blocks / marketplace
- [x] 複製 7 HPCT interceptorreviews / messages / favorites / memberships / statistics / requests / listing-meta
- [x] 複製 5 query interceptorreviews / messages / memberships / requests / listing-meta
- [x] 複製 補助組件(bootstrap framework / detector / conflict-guard / comment-router / cron-optimizer / attribute-bridge / suitability-scorer / benchmark / rest
- [x] 複製 admin tab + CLI namespace
- [x] 複製 HP transient filter / HPCT import / Listing Stats / term-comment-fields
- [x] `TMDO_HP_Bootstrap` outer bootstrap(避免與 inner family bootstrap class 衝突)
- [x] PHP lint46 files PASS
### WooCommerce AddOn (`2meet-data-optimizer-woocommerce-addon`, ~1,316 行)
- [x] 複製 4 個 WC 整合檔
- [x] `TMDO_Woocommerce_Bootstrap` 載入 + register
- [x] PHP lint PASS
### LatePoint AddOn (`2meet-data-optimizer-latepoint-addon`, ~151 行)
- [x] 複製 LatePoint interceptor
- [x] `TMDO_Latepoint_Bootstrap` 載入 + register_hooks
- [x] PHP lint PASS
**Phase 3 Live test 結果:**
- ✅ Plugin 全 active
- ✅ Hot zone 20 fields registeredmostly WC product/order
- ✅ Cold zone 3 fields
- ✅ Total 23 fields
- ✅ HP no-op when HivePress not installeddetector check
---
## Phase 4 ✅ — 6 個 2meet 家族 AddOn v0.1.0 (2026-05-15)
| AddOn | Source | Status |
|---|---|---|
| infocards | class-tmdo-infocards.php | ✅ |
| bookings | class-tmdo-bookings.php | ✅ |
| quotation | class-tmdo-quotation.php | ✅ |
| mobile-bridge | class-tmdo-mobile-bridge.php | ✅ |
| collab | class-tmdo-collab.php | ✅ |
| playlist | class-tmdo-playlist.php | ✅ |
每個 AddOn 都有:
- `TMDO_{Module}_Bootstrap` 啟動類別
- 核心整合 class(從 wp-data-optimizer 搬入)
- partner detection (early return if target plugin not installed)
- `register()``wpdo_register_fields` / `wpdo_register_custom_tables`
**Phase 4 Live test 結果:**
- ✅ 6 AddOn 全 active
- ✅ Target plugin 未安裝時正確 no-op (designed behavior)
- ✅ 0 fatal、0 lint error
---
## 整體驗收(2026-05-15 末)
| 指標 | 結果 |
|---|---|
| 12 plugin active | ✅ |
| PHP lint 全 files | ✅ **203 files PASS** |
| `wp tmdo` CLI | ✅ 18 個 subcommand 全 listed |
| `wp wpdo` alias CLI | ✅ 通 |
| `wp tmdo doctor` | ✅ system tables 全綠 + 14 partner tables 註冊 |
| `wp tmdo status` | ✅ 23 fields registered |
| SSO group 7 欄位 | ✅ 全 7 欄位(含 hub_global_user_id searchable |
| Hub-addon 12 表 | ✅ 全 12 表存在 + doctor PASS |
| Spoke-addon 2 表 | ✅ 註冊 OKDB 表 missing 是 spoke-sso 從未啟用之故) |
| WC 20 表 | ✅ 註冊 OKDB 表 missing 是 WC 未安裝) |
| 6 family AddOn no-op | ✅ target 未安裝時正確 early return |
---
## Lessons learned
### Phase 1
- rsync 的 `--exclude``tests/``tools/` top-level 不生效(因為 source 路徑沒這個前綴),需後續 rm -rf 清理
- sed 全檔大寫 `WPDO_``TMDO_` 不影響 hook/table/option 小寫前綴 `wpdo_`,確保資料相容
- 主檔的 require chain 無法以 sed 自動產出(需手動寫,因為 require 路徑與檔名變動)
- TMDO_Core::run() 內有 8 處對「整合層 class」的硬引用,需逐個加 `class_exists` 守門
- `class_alias()` 對 trait 與 interface 不適用(需 wrapping wrapper,留 Phase 1 follow-up
- WP 6.5+ `Requires Plugins:` 強制檢查 Plugin Name 而非 slughub-core / spoke-sso 仍寫死 `Requires Plugins: wp-data-optimizer` 故無法直接啟用 → Phase 5 計畫請求 hub-core / spoke-sso 端更新或加 `or 2meet-data-optimizer` 邏輯
### Phase 2
- inner Hub class `TMDO_Hub_Bootstrap` 需與 outer AddOn bootstrap 區分名稱(衝突避免)
- `TMDO_Entity_Registry::register_group()` 是公開 API;其他 read methods (`get_group_fields` not `get_fields`) 命名不直觀
### Phase 3
- HP family 內部已有 `TMDO_HivePress_Bootstrap` classv3.0.0 family bootstrap),故 outer AddOn bootstrap 改名 `TMDO_HP_Bootstrap` 避免衝突
### Phase 4
- 所有 family integration class 皆有 partner detection (e.g. `class_exists('TMEETIC_Plugin')`) → AddOn 無需自己重複偵測
---
## Phase 5 follow-up 執行狀態(2026-05-15
| # | 項目 | 狀態 |
|---|---|---|
| 1 | **Tests 套件搬遷**`tests/unit/``tests/integration/` 重命名 + path 修正 | ✅ **完成** |
| 2 | PHPCS 套件:補 phpcs.xml.dist + WordPress coding standards | ⬜ 待執行 |
| 3 | **PHPUnit bootstrap**:完整重建 unit/integration test 環境 | ✅ **完成** |
| 4 | DB version migration`TMDO_DB_VERSION` 對齊 `SCHEMA_VERSION = '2.0.0'` | ✅ **完成** |
| 5 | `Requires Plugins: 2meet-data-optimizer` — 12 個 AddOn + brandcards header 全部更新 | ✅ **完成** |
| 6 | Trait/interface alias wrappers`Trait_TMDO_Anti_EAV_Aware` 等 | ✅ **完成** |
| 7 | Doctor callback signature 修正 | ✅ **完成** |
| 8 | 打包驗收:`scripts/package-plugin.sh` 12 次 10 終檢 PASS | ⬜ 待執行 |
### #1 + #3 完成摘要(2026-05-15
**Unit tests373/373 GREEN771 assertions**
- `phpunit.xml` 已建立,bootstrap `tests/bootstrap.php` 完整重建
- 32 個 unit test 檔從 `wp-data-optimizer` 搬遷,全部 `class-wpdo-``class-tmdo-` 修正
- bootstrap 新增:minimal filter registry`$GLOBALS['_wp_filter_callbacks']`)、全域 FSM bypass filter、`TMDO_Listing_Stats` stub、`esc_sql``addslashes()`
- 跳過 HP/WC/LP 專屬 testHivePress/*、WooCommerceIntegrationTest、ListingStatsTest
**Integration tests398/398 GREEN1139 assertions**
- `phpunit-integration.xml` 已建立,bootstrap `tests/integration/bootstrap.php` 完整重建
- 35 個 integration test 檔搬遷(跳過 HivepressIntegrationTest × 3、WCTermCountFilterTest、ListingMetaInterceptorTest、TermCommentBackfillTest
- bootstrap 新增:`wp_upload_dir()``wp_mkdir_p()``TMDO_Listing_Stats` stub
- 移除 `WarmArchiveIntegrationTest` 的 listing_stats 2 個方法(需真實 HP AddOn
- 移除 `RestApiIntegrationTest` 的 post_view increment + rate-limit 2 個方法(同上)
---
## Backport wp-data-optimizer v3.0.1v3.4.62026-07-31 起)
完整計畫:`~/.claude/plans/a-data-www-studio-wp-local-dev-wp-conten-imperative-wind.md`
背景:B 分叉自 A **v3.0.0**2026-05-15 11:40),A 其後又走了 92 個 commit 到 v3.4.6,無一回流。目標是全量對齊後讓 `wp-data-optimizer` 退休。
| 階段 | 內容 | 狀態 |
|---|---|---|
| 0 | 回歸網:composer dev 依賴、test bootstrap FSM guard、`failOnWarning=true`、12 個 repo `git init` | ✅ 2026-07-31unit 379 / integration 398 全綠) |
| 1 | 安全與正確性 A1A1413 個 admin GET→POST、REST allowlist、DDL 白名單、Logger 3-arity fatal…) | ✅ 2026-07-31 |
| 2 | DDL 與並發 B1B4warm UNIQUE KEY → Zone_Cold save_patch → Zone_Warm increment | ✅ 2026-07-31 |
| 3 | 架構回填(Zone_Router + Routing_Predicate13 個 Migration Phase 類別) | ✅ 2026-07-31 |
| 4 | 相容層 E1E7(雙向 hook 橋、57 個 AddOn alias、38 個 CLI 子指令、選單 slug | ✅ 2026-07-31 |
| 5 | AddOn 同步 F1F5Standard_Post_Interceptor、HP detector v3.4.5、WC | ✅ 2026-07-31 |
| 6 | 功能與診斷 PR-Gcrypto 健檢、doctor_callback ABI、15 個 usermeta 欄位…) | ✅ 2026-07-31**Settings 分區 AJAX 未做**,見下) |
| 7 | 全域清理與 CIstrict_types、phpcs.xml、phpstan + baseline、gitea workflows | 🔶 strict_types / PHPCS / PHPStan / 3 個 workflow / ci-package.sh ✅;**測試補齊(剩 36 檔,多為 HP/WC)、文件移植未做** |
| 退休 | 兩站台切到 B、移除 A、B 升 1.0.0 | 🔶 dev30 已切換並驗證通過;dev 未切、A 未移除、版本未升 |
### dev30 實機驗證結果(2026-07-31
環境:`2meet-brandcards` 1.8.3 / `2meet-hub-core` 1.16.0 / `2meet-spoke-sso` 1.15.0 同時啟用;HivePress / WooCommerce 未安裝,故只啟用核心 + hub-addon + spoke-addon。
| 項目 | A v3.0.0(切換前) | B v0.1.0(切換後) |
|---|---|---|
| `doctor` | 33 個 `[OK]` + 15 個 WC 表 MISSING 警告 | **49 個 `[OK]`、All checks passed** |
| 姊妹外掛自訂表 | 36 張 OK | 36 張 OK(含 brandcards 的 `doctor_callback` 回傳訊息) |
| 新健檢 | 無 | `Backup dir blocked (HTTP 404)``Crypto key derivable` 皆 OK |
逐項確認:
- **alias**15 個核心類別 + trait + interface + `wpdo_run()` + `WPDO_VERSION` 全部可用
- **CLI**`wp tmdo bridge-status / crypto-status / mode-audit``wp wpdo *` 兩條路徑都通(38 個子指令)
- **anti-EAV 寫入**`WPDO_API::set_entity()``wp_wpdo_user_sso.known_login_ips` 寫入成功(A14 生效)
- **audit**`wp_wpdo_audit``group_name` / `action` / `trace_id`UUIDv4)皆有值(A11/A12 生效)
- **REST allowlist**:註冊 `show_in_rest => false` 的欄位不出現在 `get_rest_visible_hot_columns()`A5/A6 生效)
- **doctor_callback ABI 變更**brandcards 既有 callback 在 1 參數簽章下仍正常
- 前台 HTTP 200`_load_textdomain_just_in_time` notice 僅出現在 `wp plugin activate` 當下(啟用鉤子早於 `init`),一般請求與前台皆無
**實機才抓到的 fatal**`TMDO_Logger::trace_id()` 在 B 提煉時遺漏,而 `Audit_Logger::write_row()` 會呼叫它。A12 把 Audit_Logger 掛上後,任何一次受管 meta 寫入都會 fatal。PHPUnit 沒有覆蓋 audit 寫入路徑 → 這類「跨模組才會踩到」的缺口只有實機能發現。
### 尚未完成(follow-up
1. **Settings 分區 AJAX 儲存**A v3.0.2):`ajax_save_settings_section()` + 7 個 `save_section_*()` + `admin/assets/wpdo-settings.js`。B 目前是一次存全部的 inline `update_option` 巨塊,功能可用,屬 UX 改善。其中 `save_section_hp_transient` / `save_section_wc_term_count` 對應 AddOn 已移除的設定,移植時要拆掉或加 `class_exists` 守衛。
2. ~~CI workflow~~ ✅ 三個檔已建,但 **B 沒有 git remote**,要推上 gitea 才會實際執行;推上去後還需設 repo secret `TMDO_TEST_DB_PASS`、var `RELEASE_GITEA_URL`、secret `RELEASE_TOKEN`,並開 main branch protection。11 個 AddOn 的 CI 仍未建。
3. ~~`scripts/ci-package.sh`~~ ✅(委派共用 `package-plugin.sh`,實測 10 項終檢全 PASS
4. **補剩餘 36 個測試檔**:已補 `HookBusIntegrationTest`14+ 新寫 `AuditLoggerIntegrationTest`4)。`TermCommentBackfillTest` 實際 require HP AddOn 檔案,屬 HP AddOn 測試套件;其餘 32 個 HivePress/WC 測試需先為兩個 AddOn 建 `phpunit.xml` + bootstrap。
5. **文件移植**`readme.txt``CONTEXT.md``docs/`ENTITY_ADAPTER_COOKBOOK、INTEGRATION_PATTERN_DECISION、2 篇 ADR)。
6. **實機驗證與退休切換**:兩站台目前仍跑 Adev = v3.4.6、dev30 = v3.0.0),B 家族 12 個外掛全 inactive,尚未做過 `wp tmdo doctor` 實機驗證。
### ABI / 行為變更(升級須知)
- `doctor_callback` 由 3 參數改為 1 參數(表名)——AddOn 若註冊過該 callback 需同步。
- `wpdo_capture_before_value` 預設 `true``false`,每次受管寫入省一次 DB read;需要 `value_before` 的消費者(audit log)要 `add_filter( 'wpdo_capture_before_value', '__return_true' )`
- `wpdo_allow_mass_column_clear` 現為 opt-in`delete_all=true` 的整欄清空預設被拒。
- 選單 slug 由 `2meet-data-optimizer` 改回 `wp-data-optimizer`
### Lessons learnedbackport
- **階段 0 的初始 git 快照已包含階段 0 的修復**composer.json / 兩個 bootstrap / phpunit.xml / HealthCronTest),不是純粹的 pre-change 現況。要看純現況請比對 A 或 `dist/` 內的 v0.1.0 ZIP。
- `composer update` 後 autoload 出現 `WPDO_Entity_Adapter_Interface` 三重宣告警告(`includes/adapters/interface-entity-adapter.php``back-compat/interface-wpdo-entity-adapter-alias.php``back-compat/trait-wpdo-anti-eav-aware-alias.php`)→ 階段 4 E2 要刪掉重複的那一份。
- `TMDO_FSM_GUARD_DISABLED` 兩個 test bootstrap 原本都沒 define,但 `class-tmdo-feature-flags.php:128` 會檢查它 → 強制 FSM 轉換的測試會被 guard 擋掉(A 在 v3.4.6 踩過同一個坑)。
- integration 測試需要 `TMDO_TEST_DB_PASS`(或 `WPDO_TEST_DB_PASS`)環境變數,DB 為本機 `wp_wpdo_test`
- **跑完 `scripts/ci-package.sh``package-plugin.sh` 後要重跑 `composer install`**:打包流程內含 `composer install --no-dev`,會把 `vendor/bin/{phpunit,phpcs,phpstan}` 移掉,之後任何測試指令都會 "No such file or directory"。
- **A 不是照抄對象,有兩處自身缺陷不可照搬**:
1. `A/includes/engine/class-wpdo-hook-bus.php:511,522` 傳 3 個 string 給 `Logger::warning( string $event, array $context )` → A 有 `strict_types`mass-clear 路徑必炸。B 用正確簽章。
2. `A/admin/class-wpdo-dashboard-widget.php:191``wpdo_postmeta_cleanup` 仍是 `wp_nonce_url` GET 連結,但其 handler 已只收 POST → 該按鈕在 A 是壞的。B 改成 form。
- B 有 7 處 `Logger::error( 'event', array(...) )` 兩參數呼叫(4 個 stress tester、auto-promoter、conflict-detector、hook-bus),全部是 array→string 的 TypeError。用 token 掃描器(`scan_logger.php`)找出來的,肉眼與 grep 都容易漏。
- `Zone_Warm::set()` 改 upsert 後,**測試表也要有 `UNIQUE KEY ui_post_meta`**,否則 integration 會出現「set 沒覆蓋舊值」的假失敗。
- **B 的 unit bootstrap 會載入 `Member_Fields` / `Post_Fields`A 的不會**。這使 Entity_Registry 在測試啟動時就有註冊 group,從 A 移植過來、假設「registry 為空」的測試(`MigrationPhaseRemainingTest`)會真的走進 `dbDelta` 而爆掉。修法是在該測試 setUp 以 reflection 清空 registry **並移除 `wpdo_register_entity_fields` listener**phase 內部會再 fire 一次)。
- **快取類重構必定連帶測試隔離工作**:`Routing_Predicate::flush_cache()`SyncBridgeEntityGuardTest)與 `Schema_Manager::flush_table_exists_cache()`PostMigrationTest / PostEntityLifecycleTest)兩處都是 A 事後才補的,移植時要一起帶,否則出現「表被 drop 但快取說還在」的假錯誤。
- **B 自身的 slug 不一致**`MENU_SLUG``2meet-data-optimizer`,但 help-tabs / setup-wizard / conflict-monitor / 3 個 template 共 10+ 處硬編碼 `page=wp-data-optimizer` → 這些連結原本全部 404。已統一回 `wp-data-optimizer`(與 wpdo_ 表/option/cron/hook/CLI 命名空間一致)。
- **雙向 hook 橋會暴露 test bootstrap 的 stub 缺口**:單向時 `do_action_ref_array()` 從未被走到,改雙向後兩個 bootstrap 都要補這個 stub。
- **AddOn 的 alias 必須各自做**:核心 back-compat 在 `plugins_loaded:4` 執行,AddOn 在 `:6` 才載入類別,核心的 alias 表涵蓋不到它們(57 個整合層類別先前完全沒有 `WPDO_` 名稱)。
- **PHP 無法 `class_alias()` 介面**。`WPDO_Migration_Phase_Interface` 沒有雙向 alias 的乾淨解法(單向 `extends` wrapper 無法讓 `instanceof` 成立),該契約是核心內部擴充點,測試改用 `TMDO_` 正式名稱即可。
---
## Git tag plan
- `v0.1.0` — 本 releasePhase 0-4 完成)
- `v0.1.1` — Phase 5 follow-uptests / PHPCS / packaging
- `v0.2.0` — WPDO_ deprecation notice + wpdo → tmdo migration CLI