Files
ewoooc/docs/adr/ADR-017-modularization-cleanup-roadmap.md
2026-05-13 16:15:06 +08:00

137 lines
9.5 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.
# ADR-017: 模組化收尾路線圖Phase 3f
- **狀態**: Accepted
- **日期**: 2026-04-29
- **觸發**: 12 Agent 全景盤點debugger / refactor-specialist / critic / db-expert / explorer
- **相關 ADR**: ADR-008188 拓撲、ADR-011資源隔離、ADR-016cache fingerprint
- **相關 Memory**: `docs/memory/project_phase3f_cleanup_roadmap.md``docs/memory/feedback_db_metadata_import.md``docs/memory/history_logs.md`
## 背景
Phase 3e4/28-29完成 app.py 7,386→6,590 行(-10.8%),但**僅完成「搬檔」,未完成「拆乾淨」**。12 Agent 盤點揭露 6 個面向的殘留問題,且發現新的 critical 風險DB metadata import 漏洞、孤兒表)。
## 完成度真相2026-04-29 盤點基線)
| 維度 | 完成度 | 真相 |
|------|--------|------|
| 路由搬檔41 條 → 28 BP| 68% | 13 條 app.py 獨有未遷移 |
| 路由「拆乾淨」 | **0%** | app.py 41 條一條未刪28 條與 BP 同 URL 雙寫,由 first-registered-wins 決定行為 |
| `USE_MODULAR_ROUTES` 開關 | **0%** | `register_blueprints()` 從未被 app.py 呼叫,整套設計死碼 |
| services/ 模組化 | ~95% | 唯一乾淨3 個孤兒 service0 引用)|
| 模板統一 | ~50% | 三目錄並存 + 1 空檔 + 3 死檔 + 2 TemplateNotFound 風險 |
| DB schema vs Model | ~60% | manager.py import 漏 3 模組6 張表有 SQL 無 ORMrealtime_sales_monthly 孤兒 |
## 實作狀態補記2026-05-13
上表是 2026-04-29 立案時的盤點基線;後續整改已把多個 HIGH 項目落地並加上回歸守門:
- `app.py` 已收斂為 Flask bootstrap / Blueprint registration / 啟動自檢active `@app.route` 為 0並由 `tests/test_phase3f_cleanup_contracts.py::test_app_py_stays_blueprint_only_for_routes` 守住。
-`USE_MODULAR_ROUTES``register_blueprints()``MODULAR_ENDPOINTS`、duplicate cleanup shim 已移除;`routes/__init__.py` 僅保留 package docstring。
- DB metadata / migration 覆蓋已由 `tests/test_migration_metadata_coverage.py` 與啟動自檢守住v5 observability / Market Intel 等表不再只靠手動口述。
- 模板路徑已收斂為 `templates/``web/templates/vendor_stockout/`;根層 placeholder `templates/list.html` 已刪除並有測試防回歸。
- 大檔治理仍未結案:`routes/openclaw_bot_routes.py``routes/admin_observability_routes.py``routes/sales_routes.py``scheduler.py` 仍超過 800 行,後續只能做 bugfix、安全修補或往外抽模組。
## 決策
執行 **Phase 3f 五階段收尾**,總工期估 12-15 小時(不含驗證),每階段獨立 commit、每階段 critic 審查、每階段先 SSH 驗證 production。
### Phase 3f-0DB metadata 救急30 分鐘,最高優先)
1. `database/manager.py` 補完 import
- `permission_models`Permission, UserPermission
- `vendor_models` 補 VendorList / VendorEmail / EmailSendLog
- `ai_models` 顯式 import 4 個 AI history/template class
- `autoheal_models` 顯式 import 7 個 AIOps class移除 `ai_models.py` re-export shim
2. 處置 `realtime_sales_monthly` 孤兒表:
- 選項 A`database/realtime_sales_models.py`(推薦,補 ORM 一致性)
- 選項 B移除 `app.py:693` 的 importmetrics 不依賴此 model
3. PostgreSQL 與 SQLite 初始化都執行全域 `Base.metadata.create_all()`PostgreSQL 路徑以 process-local guard + advisory lock 保護,避免一般流量重複碰 DDL
4. `app.py` 啟動加 metadata self-check缺表直接 `SystemExit`
5. `docker/postgres/init/01-init.sql``realtime_sales_monthly` 欄位同步 ORM避免 fresh volume 先由 init.sql 建出窄表後 create_all 無法補欄位
**驗收**Base.metadata 含全 34 個 tablecreate_all 在新環境零漏。
### Phase 3f-1路由雙註冊徹底解4-6 小時P9 切分)
**策略**:保留 Blueprint刪 app.py 對應 `@app.route`28 條13 條 app.py 獨有遷至 BP。實作順序要先處理 API shadow、次要頁面與 `/brand_assets`,首頁 `/` 最後動,因為多處 `url_for('index')` 仍依賴 app endpoint name。
子任務(按 BP 分組獨立 commit
| Sprint | 範圍 | 動作 |
|--------|------|------|
| 3f-1-a | dashboard_bp | 刪 app.py:722 `/`;確認 BP 版可用 |
| 3f-1-b | edm_bp | 刪 app.py:1029, 1280 兩條 |
| 3f-1-c | export_bp | 刪 app.py:1431-1905 共 9 條;補 `/api/export/excel/seasonality_detail` 進 BP |
| 3f-1-d | api_bp | 刪 app.py:2219-2451 共 6 條 trigger/run |
| 3f-1-e | import_bp | 刪 app.py:2691, 2980 兩條 |
| 3f-1-f | monthly_bp | 刪 app.py:3076, 3083 兩條 |
| 3f-1-g | sales_bp | 刪 app.py:3592-5809 共 7 條;**同時刪 routes/sales_routes.py 6 處 wrapper174-348**,把實作搬進 BP |
| 3f-1-h | system routes 補強 | 現有 `system_bp``/api/system` prefix公開 URL`/health` `/metrics` `/logs` `/settings` 等)需新建無 prefix 的 `system_public_bp` 或拆成 public/internal 兩個 BP不能直接塞進現有 `system_bp``/abc_analysis/detail``sales_bp`。 |
| 3f-1-i | 死碼清除 | 刪 `routes/__init__.py:32-177` 整套register_blueprints / MODULAR_ENDPOINTS / is_endpoint_modular / cleanup_duplicate_routes+ `config.py:244-254` USE_MODULAR_ROUTES |
**驗收**
- `app.url_map.iter_rules()` 任一 (rule, methods) 皆唯一
- 啟動加 self-checkduplicate detect 直接 raise SystemExit
- 全 endpoint smoke testcritic 監督)
### Phase 3f-2Cache 統一2-3 小時)
1. Dockerfile + docker-compose.yml gunicorn 加 `--preload`,只作為 COW 記憶體優化,不作為一致性保證
2. 新建 `services/cache_manager.py` 套用 ADR-016 fingerprint 模式
3. 移除三處重複 `_SALES_*_CACHE` 定義app.py:82, routes/sales_routes.py:32, services/cache_service.py:16→ 統一 import `services.cache_manager`
4. `clear_cache` endpoint 從「N-POST 廣播」改「DB fingerprint pull」已在 daily_sales bp 完成,擴及 sales
### Phase 3f-3穩定性補強1-2 小時)
1. 先在 `services/event_router.py` 補同步安全 facade`notify_failure()` / `dispatch_sync()`),因現有 `EventRouter` 只有 async `dispatch()`scheduler 直接呼叫會掉告警
2. scheduler.py 7 處裸 `except: pass`line 243, 254, 582, 587, 653, 890, 1222改為 `except Exception as e: logger.exception(...)`P1/P2 經 EventRouter 同步 facade 強制告警
3. docker-compose.yml 刪 7 條死路徑 mountvendor_routes.py / vendor_stockout_*.html
4. routes/vendor_routes.py:28-30 template_folder 改用絕對路徑,移除靠 Flask fallback 的脆弱依賴
### Phase 3f-4模板統一2-3 小時)
1. 補 2 個 TemplateNotFound`trends.html`trend_routes.py:33`login_history.html`user_routes.py:40→ 找回或停用對應 endpoint
2.`web/templates/sales_analysis.html`0-byte 空檔)
3. 刪 3 個雙寫死檔:`web/templates/brand_assets.html``web/templates/growth_analysis.html`、根目錄 `logs.html`
4. 根目錄 11 個 *.html 全搬 `templates/`,確認 docker-compose 舊 mount 已清理後,再移除 `app.py:185-188` ChoiceLoader 的 BASE_DIR fallback
5. `web/templates/` 僅留 `vendor_stockout/` 子目錄vendor_bp 自帶 template_folder
### Phase 3f-5死碼清除30 分鐘)
1. 確認並刪除 3 個孤兒 service
- `services/elephant_alpha_decision_router.py`
- `services/telegram_ai_integration.py`
- `services/watcher_agent.py`
2. `.env.example` 補齊 15+ 個程式碼實際讀但 example 缺的變數AIDER_*, ELEPHANT_ALPHA_*, HEAL_SSH_*, NVIDIA_API_KEY 等)
## 風險與回滾
每階段獨立 commitCI/CD 失敗自動回滾(依賴 ADR-014 防線。Phase 3f-1 為高風險區,必須:
1. 先在本機 `python app.py` 啟動驗證 url_map 無重複
2. critic 審 diff 過關
3. 部署後 SSH 健康檢查 `/health` + 抽測 5 條核心 endpoint
## 不做的事
- 不做模組化開關設計回填USE_MODULAR_ROUTES 已死,直接刪)
- 不做 ORM 全面遷移25 張無 SQL migration 軌跡的 table 留待 Phase 4
- 不在 3f-0 修 `docker/postgres/init/01-init.sql` 與 ORM 的 `products` 中文欄位 schema drift這是 Phase 4 migration 題
- 不做 openclaw_bot_routes.py5,543 行)拆解(留 Phase 4
- 不撤換 NGROK Token統帥 2026-04-29 明示先忽略)
## 完成定義
- app.py < 5,000 行
- url_map 零重複
- create_all 新環境零漏表
- 模板僅存 `templates/` + `web/templates/vendor_stockout/`
- gunicorn `--preload` 啟用、cache 跨 worker 一致
- scheduler 7 處 except 全改、docker-compose mount 全清
## 2026-04-30 補充決策:模組化治理守門
Phase 3f 已陸續完成 DB metadata、路由註冊、cache、scheduler、模板與 orphan cleanup 的多個收斂項目,但 line-count 盤點仍顯示 15 個 Python 檔案超過 800 行。為避免後續功能開發再次把 route / service 寫成巨檔,本 ADR 補充以下守門規則:
1. `app.py` 只保留 Flask app bootstrap、Blueprint registration、啟動自檢、版本與全域設定不得新增 route 或商業邏輯。
2. `routes/` 必須保持 thin controller重複邏輯需抽到 `services/``utils/`
3. 超過 800 行的 Python 檔案列入 `docs/memory/code_modularization_inventory_20260430.md`只能做安全修補、bugfix、或往外抽模組新增功能應先拆分。
4. 新增 Python 檔案超過 600 行需提出拆分理由;超過 800 行需同步更新 inventory 與測試。
5. `tests/test_modularization_governance.py` 是守門測試:新巨檔沒有被盤點會失敗。
詳細操作規則以 `docs/guides/modularization_governance.md` 為準。