docs(modularization): 建立模組化治理守門
All checks were successful
CD Pipeline / deploy (push) Successful in 1m36s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m36s
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# EwoooC (MOMO Pro System) — Codex 專案工作規則
|
||||
|
||||
> 版本: V13.3
|
||||
> 版本: V13.4
|
||||
> 目標: 把專案知識整理成 Codex 可低成本讀取、可持續維護、可安全落地的單一工作入口。
|
||||
|
||||
## 1. 入口原則
|
||||
@@ -131,12 +131,14 @@
|
||||
|
||||
- 部署 SOP: `docs/guides/deployment_sop.md`
|
||||
- DevOps 手冊: `docs/guides/devops_handbook.md`
|
||||
- 模組化治理: `docs/guides/modularization_governance.md`
|
||||
- AI 自動化 Session SOP: `docs/guides/ai_automation_session_sop.md`
|
||||
- AI 競價情報 SOT: `docs/AI_INTELLIGENCE_MODULE_SOT.md`
|
||||
- Agent 角色矩陣: `docs/guides/codex_agent_roles.md`
|
||||
- ADR 索引: `docs/adr/README.md`
|
||||
- Memory 索引: `docs/memory/README.md`
|
||||
- 歷史紀錄: `docs/memory/history_logs.md`
|
||||
- 程式碼模組化盤點: `docs/memory/code_modularization_inventory_20260430.md`
|
||||
- AI 自動化閉環記憶: `docs/memory/ai_automation_closure_20260429.md`
|
||||
- 憑證手冊: `docs/memory/credentials_passbook.md`
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> 本文件定義專案開發的核心準則與不可違反的規範
|
||||
> **建立日期**: 2026-01-12
|
||||
> **當前版本**: V10.20 (ElephantAlpha transient fallback 版)
|
||||
> **當前版本**: V10.21 (模組化治理守門版)
|
||||
> **最後更新**: 2026-04-30
|
||||
|
||||
---
|
||||
@@ -178,6 +178,18 @@
|
||||
|
||||
---
|
||||
|
||||
## 第六之一章:模組化治理規範
|
||||
|
||||
### 第 21.1 條:模組分層與大檔治理(強制要求)
|
||||
- ✅ **正確**:新功能必須先放入對應層級:`routes/` 只處理 HTTP/Blueprint glue,`services/` 放商業邏輯與外部 API client,`database/` 放 ORM/DB access,`utils/` 放無狀態共用工具,`templates/` 放 UI。
|
||||
- ✅ **正確**:`app.py` 只保留 Flask 初始化、Blueprint 註冊、啟動自檢、版本與全域設定;禁止新增 route、長函式或商業邏輯。
|
||||
- ✅ **正確**:現有超過 800 行的 Python 檔案視為拆分技術債,只能做 bugfix / 安全修補 / 搭橋式抽離;新增功能前應優先抽 shared service 或子模組。
|
||||
- ✅ **正確**:新增或修改導致 Python 檔案超過 600 行時,必須先評估拆模組;超過 800 行必須更新 `docs/memory/code_modularization_inventory_20260430.md` 與對應測試,並寫出拆分計畫。
|
||||
- ❌ **禁止**:把可共用邏輯藏在 route、template helper 或單一巨檔內,造成其他模組只能複製貼上。
|
||||
- **依據**:ADR-017、`docs/guides/modularization_governance.md`
|
||||
|
||||
---
|
||||
|
||||
## 第七章:程式碼品質規範
|
||||
|
||||
### 第 22 條:命名規範(強制要求)
|
||||
|
||||
@@ -29,8 +29,10 @@
|
||||
- Scheduler 例外記錄強化:清除 `scheduler.py` 靜默 `except/pass`,資源清理、EDM 可選欄位、備份 insight/通知失敗全改為可診斷 log。
|
||||
- AI metrics baseline 觀測:`/metrics` 在尚無 AI 自動化事件時仍輸出 `momo_ai_*` zero-baseline series,避免重啟後 Grafana/Prometheus 看不到 metric names。
|
||||
- ElephantAlpha transient fallback:NVIDIA NIM timeout、connection error、429 與 5xx 會嘗試下一個 fallback model;400 等非暫時性請求錯誤不重試。
|
||||
- 模組化治理守門:新增 `docs/guides/modularization_governance.md`、`docs/memory/code_modularization_inventory_20260430.md` 與 `tests/test_modularization_governance.py`,盤點並鎖住 15 個 >800 行 Python 大檔。
|
||||
|
||||
【下次待辦】
|
||||
- 依 inventory 優先拆 `routes/openclaw_bot_routes.py`、`routes/sales_routes.py`、`scheduler.py`。
|
||||
- 觀察 Prometheus scrape 後 `momo_ai_*` baseline 與非 baseline 事件序列是否持續穩定。
|
||||
- Superset panel 設定與 Smoke 摘要成效觀察。
|
||||
|
||||
|
||||
4
app.py
4
app.py
@@ -95,8 +95,8 @@ except Exception as e:
|
||||
sys_log.error(f"無法檢測磁碟空間: {e}")
|
||||
|
||||
# 🚩 系統版本定義 (備份與顯示用)
|
||||
# 🚩 2026-04-30 V10.20: ElephantAlpha transient NIM fallback
|
||||
SYSTEM_VERSION = "V10.20"
|
||||
# 🚩 2026-04-30 V10.21: Modularization governance guardrail
|
||||
SYSTEM_VERSION = "V10.21"
|
||||
|
||||
# ==========================================
|
||||
# 🔒 SQL Injection 防護函數
|
||||
|
||||
@@ -254,7 +254,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
|
||||
# ==========================================
|
||||
# 系統版本與路徑
|
||||
# ==========================================
|
||||
SYSTEM_VERSION = "V10.20"
|
||||
SYSTEM_VERSION = "V10.21"
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = PUBLIC_URL # 用於模板顯示
|
||||
|
||||
|
||||
@@ -112,3 +112,15 @@ Phase 3e(4/28-29)完成 app.py 7,386→6,590 行(-10.8%),但**僅完
|
||||
- 模板僅存 `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` 為準。
|
||||
|
||||
49
docs/guides/modularization_governance.md
Normal file
49
docs/guides/modularization_governance.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# 模組化治理指南
|
||||
|
||||
> 目的:讓 EwoooC 後續功能不再回到「單一巨檔、分類不清、共用邏輯複製貼上」的狀態。
|
||||
|
||||
## 分層規則
|
||||
|
||||
| 層級 | 放什麼 | 不放什麼 |
|
||||
|---|---|---|
|
||||
| `app.py` | Flask 初始化、Blueprint 註冊、啟動自檢、版本 | route 實作、DB 查詢、商業邏輯、排程任務 |
|
||||
| `routes/` | HTTP request/response、表單參數解析、權限 decorator、呼叫 service | 大量資料轉換、外部 API client、可重用計算 |
|
||||
| `services/` | 商業邏輯、AI pipeline、外部 API client、報表生成、可重用流程 | Flask request 物件、template rendering、route-only glue |
|
||||
| `database/` | ORM models、DB manager、schema helpers、migration baseline | HTTP/Telegram/AI side effect |
|
||||
| `utils/` | 無狀態純工具、字串/時間/安全 helper | 需要 DB/session/env-heavy 的流程 |
|
||||
| `templates/` | Jinja UI | Python business rule |
|
||||
|
||||
## 檔案尺寸規則
|
||||
|
||||
- 300 行以下:健康範圍。
|
||||
- 300-600 行:可接受,但新增功能前要確認是否能抽 service/helper。
|
||||
- 600-800 行:警戒範圍;PR/commit 需說明為何不拆。
|
||||
- 800 行以上:技術債範圍;只能做 bugfix、安全修補、或「往外抽」的過渡改動。新增功能應先拆模組。
|
||||
- 新增超過 800 行的 Python 檔案必須更新 `docs/memory/code_modularization_inventory_20260430.md`,否則 `tests/test_modularization_governance.py` 會失敗。
|
||||
|
||||
## 新功能落點決策
|
||||
|
||||
1. 先問:這是 HTTP endpoint、商業流程、DB access、外部 API、還是純工具?
|
||||
2. endpoint 只新增到對應 Blueprint,不新增到 `app.py`。
|
||||
3. route 內超過 40 行的資料處理,優先抽到 `services/`。
|
||||
4. 兩個以上 route 需要同一段邏輯時,第一次就抽 shared service,不複製貼上。
|
||||
5. service 需要 DB 時,透過既有 `DatabaseManager` / repository-style helper,不在 route 裡反覆建立 engine。
|
||||
6. AI 自動化、告警、自癒相關變更需同步檢查 `docs/AI_INTELLIGENCE_MODULE_SOT.md`。
|
||||
|
||||
## 拆大檔順序
|
||||
|
||||
優先處理「又大又承擔多種責任」的檔案:
|
||||
|
||||
1. `routes/openclaw_bot_routes.py`:拆成 route、bot command service、learning/report service、scheduler hook。
|
||||
2. `routes/sales_routes.py`:拆 dashboard/page routes、API routes、chart/query service。
|
||||
3. `scheduler.py`:拆 task registry、crawler jobs、report jobs、notification jobs。
|
||||
4. `routes/ai_routes.py` / `routes/vendor_routes.py`:把資料處理與整合邏輯移到 services。
|
||||
5. `services/ppt_generator.py`:拆 deck orchestration、chart builders、slide templates。
|
||||
|
||||
## Review 檢查表
|
||||
|
||||
- 是否新增 `@app.route`?若是,退回改 Blueprint。
|
||||
- route 是否直接包含大量 SQL、DataFrame、AI prompt 組裝或外部 API 呼叫?若是,抽 service。
|
||||
- 是否讓既有 >800 行檔案淨增加?若是,先抽模組或更新 inventory 與拆分計畫。
|
||||
- 是否新增重複 cache / DB manager / Telegram / AI client 初始化?若是,改用既有 service。
|
||||
- 是否需要更新 ADR、memory、SOT 或 guide?若是,本次 commit 一起更新。
|
||||
@@ -18,6 +18,7 @@
|
||||
| `feedback_db_metadata_import.md` | SQLAlchemy metadata / `create_all()` 漏表鐵律 | 新增 model、修 schema、排查 fresh env 漏表時 |
|
||||
| `db_connection_pool_singleton_20260430.md` | PostgreSQL `too many clients` 連線池放大事故與 DatabaseManager singleton 修正 | 排查 DB 連線數暴增、route 內反覆初始化 DatabaseManager、SQLAlchemy engine/pool 行為時 |
|
||||
| `project_phase3f_cleanup_roadmap.md` | ADR-017 執行矩陣與階段紅線 | 正在做 3f 模組化收尾時 |
|
||||
| `code_modularization_inventory_20260430.md` | Python 大檔盤點、分層規範與拆分工作項目 | 新增功能、拆大檔、審查是否違反模組化治理時 |
|
||||
| `schema_inventory_baseline.md` | DB 表分類與 drift 基線 | 要收斂 migration / ORM / raw SQL 真相時 |
|
||||
|
||||
## 關聯 Guide
|
||||
|
||||
44
docs/memory/code_modularization_inventory_20260430.md
Normal file
44
docs/memory/code_modularization_inventory_20260430.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# 程式碼模組化盤點(2026-04-30)
|
||||
|
||||
> 用途:接續 ADR-017 Phase 3f 時,快速知道哪些 Python 檔案仍是大檔技術債,以及新增功能應該放在哪個模組層。
|
||||
|
||||
## 盤點結論
|
||||
|
||||
- Python 總量:約 64,748 行。
|
||||
- 最大壓力區:`routes/` 約 21,020 行、`services/` 約 24,533 行。
|
||||
- `app.py` 已降到 1,206 行,功能定位應固定為 bootstrap / Blueprint registration / startup guard,不再承接新 route。
|
||||
- 目前仍有 15 個 Python 檔案超過 800 行;這些不是禁止修 bug,而是禁止繼續塞新功能。
|
||||
|
||||
## 超過 800 行檔案清單
|
||||
|
||||
| 行數 | 檔案 | 分類 | 拆分方向 |
|
||||
|---:|---|---|---|
|
||||
| 5543 | `routes/openclaw_bot_routes.py` | P0 巨型 Blueprint | route / bot command service / report service / scheduler hook |
|
||||
| 2653 | `routes/sales_routes.py` | P0 巨型 Blueprint | page routes / API routes / chart query service / calendar service |
|
||||
| 2644 | `scheduler.py` | P0 排程總管 | task registry / crawler jobs / report jobs / notification jobs |
|
||||
| 1662 | `routes/ai_routes.py` | P1 AI Blueprint | route glue / AI orchestration service / prompt builders |
|
||||
| 1661 | `routes/vendor_routes.py` | P1 Vendor Blueprint | route glue / vendor query service / stockout service |
|
||||
| 1345 | `services/ppt_generator.py` | P1 報表生成 service | deck orchestration / slide builders / chart builders |
|
||||
| 1339 | `services/nemoton_dispatcher_service.py` | P1 NemoTron service | NIM client / tool-call parser / action dispatcher |
|
||||
| 1300 | `services/openclaw_strategist_service.py` | P1 OpenClaw service | prompt builders / report composer / strategy rules |
|
||||
| 1206 | `app.py` | P1 bootstrap | 保持只做 app setup;繼續往 app_factory / extension setup 抽 |
|
||||
| 1079 | `routes/cicd_routes.py` | P2 CI/CD Blueprint | route glue / CI query service / deployment action service |
|
||||
| 986 | `services/telegram_bot_service.py` | P2 Telegram service | command handlers / message formatters / bot client |
|
||||
| 966 | `services/trend_crawler.py` | P2 crawler service | source adapters / parser / persistence |
|
||||
| 868 | `services/elephant_alpha_autonomous_engine.py` | P2 ElephantAlpha engine | HITL / executor / planning policy |
|
||||
| 818 | `services/import_service.py` | P2 import service | validators / import writers / report builders |
|
||||
| 805 | `routes/bot_api_routes.py` | P2 Bot API Blueprint | route glue / bot action service |
|
||||
|
||||
## 工作項目
|
||||
|
||||
1. P0:拆 `routes/openclaw_bot_routes.py`,先把非 HTTP 邏輯搬到 `services/openclaw_bot/` 子模組。
|
||||
2. P0:拆 `routes/sales_routes.py`,先把 chart/query/calendar 計算搬到 `services/sales/`。
|
||||
3. P0:拆 `scheduler.py`,建立 `jobs/` 或 `services/scheduler/` task registry。
|
||||
4. P1:把 `routes/ai_routes.py` 與 `routes/vendor_routes.py` 的資料處理移出 route。
|
||||
5. P1:把 PPT / NemoTron / OpenClaw 大 service 拆成 client、parser、composer、policy。
|
||||
6. P2:對 800-1100 行檔案採「碰到就順手抽」策略,但不可讓淨行數繼續增加。
|
||||
|
||||
## 守門
|
||||
|
||||
- `tests/test_modularization_governance.py` 會掃描所有 Python 檔案;任何新的 >800 行檔案沒有列在本 inventory 就會失敗。
|
||||
- 若檔案拆小後低於 800 行,可從本清單移除並同步更新測試。
|
||||
@@ -42,6 +42,7 @@
|
||||
- **Scheduler 例外記錄強化**: 清除 `scheduler.py` 靜默 `except/pass`,Chrome 清理、EDM optional 欄位、備份 insight/Telegram 失敗均保留 log。
|
||||
- **AI metrics baseline 觀測**: `/metrics` 在尚無 AI 自動化事件時仍輸出 `momo_ai_*` zero-baseline series,避免 app 重啟後 Grafana/Prometheus 看不到 metric names。
|
||||
- **ElephantAlpha transient fallback**: NVIDIA NIM primary model timeout、connection error、429 與 5xx 會嘗試下一個 fallback model,400 等非暫時性請求錯誤不重試。
|
||||
- **模組化治理守門**: 盤點 15 個超過 800 行 Python 大檔,新增 `docs/guides/modularization_governance.md` 與 `tests/test_modularization_governance.py`,防止未分類巨檔再長出來。
|
||||
|
||||
### 2026-04-28~29:Phase 3e 重構大戰 + daily_sales cache 隱形 bug 根除
|
||||
- **app.py 縮減 -10.8%**: 7,386 → 6,590 行,11 commits 全綠零 502。
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
| 3f-3 | scheduler 裸 `except`、EventRouter 同步告警、compose mount、vendor template_folder | 中 | 1-2h |
|
||||
| 3f-4 | 模板統一至 `templates/` 與 `web/templates/vendor_stockout/` | 低 | 2-3h |
|
||||
| 3f-5 | 孤兒 service 與 `.env.example` 收尾 | 極低 | 30m |
|
||||
| 3f-6 | 模組化治理守門:大檔 inventory、分層 guide、測試防新增巨檔 | 低 | 30m |
|
||||
|
||||
## 已校正事項
|
||||
|
||||
@@ -26,3 +27,4 @@
|
||||
- 3f-2 的 `--preload` 只降低 copy-on-write 記憶體成本,一致性仍以 DB fingerprint 為準。
|
||||
- 3f-3 必須先補 `EventRouter` 同步 facade,再把 scheduler P1/P2 失敗導入告警。
|
||||
- 3f-4 移除 ChoiceLoader fallback 前,需先清 docker-compose 舊 mount 與根目錄模板。
|
||||
- 3f-6 已將 >800 行 Python 檔案列入 `docs/memory/code_modularization_inventory_20260430.md`;未來新增巨檔需更新 inventory,否則 `tests/test_modularization_governance.py` 會失敗。
|
||||
|
||||
@@ -24,3 +24,5 @@
|
||||
| `import_routes.py` | 匯入功能 | `/api/import_excel`, `/api/import/monthly_summary` |
|
||||
|
||||
新增 route 時請優先放入對應 Blueprint,並用本機 `app.url_map` duplicate check 驗證。
|
||||
若 route 內開始出現大量資料處理、SQL、AI prompt 或外部 API 呼叫,請依
|
||||
`docs/guides/modularization_governance.md` 抽到 `services/` 或 `utils/`,不要讓 Blueprint 變成新巨檔。
|
||||
|
||||
44
tests/test_modularization_governance.py
Normal file
44
tests/test_modularization_governance.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
INVENTORY = ROOT / "docs/memory/code_modularization_inventory_20260430.md"
|
||||
GUIDE = ROOT / "docs/guides/modularization_governance.md"
|
||||
|
||||
|
||||
def _python_line_counts():
|
||||
ignored_parts = {".git", "venv", "__pycache__", ".pytest_cache"}
|
||||
for path in ROOT.rglob("*.py"):
|
||||
if any(part in ignored_parts for part in path.relative_to(ROOT).parts):
|
||||
continue
|
||||
with path.open(encoding="utf-8", errors="ignore") as handle:
|
||||
yield path.relative_to(ROOT).as_posix(), sum(1 for _ in handle)
|
||||
|
||||
|
||||
def test_large_python_modules_are_tracked_in_modularization_inventory():
|
||||
inventory = INVENTORY.read_text(encoding="utf-8")
|
||||
large_modules = {
|
||||
path: lines
|
||||
for path, lines in _python_line_counts()
|
||||
if lines >= 800
|
||||
}
|
||||
|
||||
assert large_modules, "盤點應至少包含目前既有大檔"
|
||||
missing = [
|
||||
f"{path} ({lines} lines)"
|
||||
for path, lines in sorted(large_modules.items())
|
||||
if f"`{path}`" not in inventory
|
||||
]
|
||||
assert missing == []
|
||||
|
||||
|
||||
def test_modularization_governance_is_indexed_for_codex_sessions():
|
||||
agents = (ROOT / "AGENTS.md").read_text(encoding="utf-8")
|
||||
constitution = (ROOT / "CONSTITUTION.md").read_text(encoding="utf-8")
|
||||
memory_index = (ROOT / "docs/memory/README.md").read_text(encoding="utf-8")
|
||||
|
||||
assert "docs/guides/modularization_governance.md" in agents
|
||||
assert "docs/guides/modularization_governance.md" in constitution
|
||||
assert "code_modularization_inventory_20260430.md" in agents
|
||||
assert "code_modularization_inventory_20260430.md" in memory_index
|
||||
assert GUIDE.exists()
|
||||
Reference in New Issue
Block a user