Some checks failed
CD Pipeline / deploy (push) Failing after 59s
- 建立 Gitea Actions CD pipeline (.gitea/workflows/cd.yaml) - 部署模式: rsync Python 檔案至 188 → docker restart (volume mount) - Dockerfile/requirements 變動時自動重建 Docker image - 部署通知: Telegram (開始/成功/失敗) - 健康檢查: https://mo.wooo.work/health (最多 5 次重試) - 同步最新 CLAUDE.md / ADR-008 / memory (2026-04-19) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
155 lines
5.6 KiB
Markdown
155 lines
5.6 KiB
Markdown
# 路由模組重構說明
|
||
|
||
## 概述
|
||
|
||
此目錄包含從 `app.py` 中分離出來的路由模組,採用 Flask Blueprint 架構。
|
||
這樣的模組化設計使得代碼更易於維護、測試和擴展。
|
||
|
||
## 模組清單
|
||
|
||
| 模組 | 狀態 | 說明 | 路由 |
|
||
|------|------|------|------|
|
||
| `system_routes.py` | ✅ 獨立 | 系統管理 | `/settings`, `/logs`, `/health`, `/metrics`, `/api/backup` 等 |
|
||
| `edm_routes.py` | ✅ 獨立 | EDM 儀表板 | `/edm`, `/festival` |
|
||
| `monthly_routes.py` | ✅ 獨立 | 月結分析 | `/monthly_summary_analysis`, `/api/monthly_summary_data` |
|
||
| `dashboard_routes.py` | ✅ 獨立 | 首頁看板 | `/`, `/brand_assets` |
|
||
| `daily_sales_routes.py` | ✅ 獨立 | 當日業績 | `/daily_sales`, `/daily_sales/export*` |
|
||
| `api_routes.py` | ✅ 已獨立 | 通用 API | `/api/run_task`, `/api/history/*` 等 |
|
||
| `export_routes.py` | ✅ 已獨立 | 匯出功能 | `/api/export/*` |
|
||
| `import_routes.py` | ✅ 已獨立 | 匯入功能 | `/api/import_excel`, `/api/import/monthly_summary` |
|
||
| `sales_routes.py` | ⚡ 延遲導入 | 業績分析 | `/sales_analysis`, `/growth_analysis`, `/api/sales_analysis/*` |
|
||
|
||
## 啟用模組
|
||
|
||
### 方法一:修改 config.py(推薦)
|
||
|
||
在 `config.py` 中設定 `USE_MODULAR_ROUTES`:
|
||
|
||
```python
|
||
USE_MODULAR_ROUTES = {
|
||
'system': True, # 啟用 system_routes
|
||
'edm': True, # 啟用 edm_routes
|
||
'monthly': True, # 啟用 monthly_routes
|
||
'dashboard': True, # 啟用 dashboard_routes
|
||
'daily_sales': True, # 啟用 daily_sales_routes
|
||
'api': False, # api_routes 有依賴,暫不啟用
|
||
'export': False, # export_routes 有依賴,暫不啟用
|
||
'import': False, # import_routes 有依賴,暫不啟用
|
||
'sales': False, # sales_routes 有依賴,暫不啟用
|
||
}
|
||
```
|
||
|
||
### 方法二:環境變數
|
||
|
||
可透過環境變數覆蓋設定(待實作)。
|
||
|
||
## 運作原理
|
||
|
||
1. **Blueprint 註冊**:`routes/__init__.py` 中的 `register_blueprints()` 函數根據 `USE_MODULAR_ROUTES` 設定決定是否註冊各模組的 Blueprint。
|
||
|
||
2. **重複路由清理**:`app.py` 底部的 `cleanup_duplicate_routes()` 函數會在所有路由定義完成後,移除與已啟用 Blueprint 重複的路由。
|
||
|
||
3. **優先順序**:Blueprint 中的路由優先於 app.py 中的同名路由。
|
||
|
||
## 模組依賴說明
|
||
|
||
### 完全獨立模組
|
||
- `system_routes.py`
|
||
- `edm_routes.py`
|
||
- `monthly_routes.py`
|
||
- `dashboard_routes.py` - 提供 `get_consolidated_data`, `get_dashboard_stats`
|
||
- `daily_sales_routes.py`
|
||
|
||
這些模組不依賴 app.py 中的任何函數或變數。
|
||
|
||
### 已獨立化的模組(使用 services 或其他獨立模組)
|
||
- `api_routes.py`:
|
||
- 使用 `services/task_runner.py` 中的 `run_momo_task_with_notification`
|
||
- 使用 `routes/dashboard_routes.py` 中的 `get_dashboard_stats`
|
||
- `export_routes.py`:
|
||
- 使用 `routes/dashboard_routes.py` 中的 `get_consolidated_data`
|
||
- 使用 `services/cache_service.py` 中的快取變數
|
||
- `import_routes.py`:
|
||
- 使用 `services/cache_service.py` 中的 `_SALES_DF_CACHE`, `_SALES_PROCESSED_CACHE`
|
||
|
||
### 延遲導入模組
|
||
- `sales_routes.py`:
|
||
- `growth_analysis()` 已完全獨立
|
||
- 其他 API 函數使用延遲導入從 app.py 取得(函數邏輯複雜,暫不遷移)
|
||
|
||
## 開發指南
|
||
|
||
### 新增路由模組
|
||
|
||
1. 在 `routes/` 目錄建立新的 Python 檔案
|
||
2. 定義 Blueprint:
|
||
```python
|
||
from flask import Blueprint
|
||
my_bp = Blueprint('my_module', __name__)
|
||
```
|
||
3. 在 `routes/__init__.py` 中加入註冊邏輯
|
||
4. 在 `config.py` 的 `USE_MODULAR_ROUTES` 中加入控制項
|
||
|
||
### 從 app.py 遷移路由
|
||
|
||
1. 複製路由函數到對應模組
|
||
2. 將 `@app.route` 改為 `@blueprint_name.route`
|
||
3. 確認所有導入正確
|
||
4. 測試模組可正常導入:`python -c "from routes.xxx import xxx_bp"`
|
||
5. 在 `MODULAR_ENDPOINTS` 中記錄端點名稱
|
||
|
||
## 測試
|
||
|
||
測試模組是否正常運作:
|
||
|
||
```bash
|
||
# 測試所有模組導入
|
||
python -c "
|
||
from routes.system_routes import system_bp
|
||
from routes.edm_routes import edm_bp
|
||
from routes.monthly_routes import monthly_bp
|
||
from routes.dashboard_routes import dashboard_bp
|
||
from routes.daily_sales_routes import daily_sales_bp
|
||
print('All independent modules imported successfully!')
|
||
"
|
||
|
||
# 測試完整應用(啟用所有獨立模組)
|
||
python -c "
|
||
import config
|
||
config.USE_MODULAR_ROUTES = {
|
||
'system': True, 'edm': True, 'monthly': True,
|
||
'dashboard': True, 'daily_sales': True,
|
||
'api': False, 'export': False, 'import': False, 'sales': False
|
||
}
|
||
import app
|
||
print(f'Total routes: {len(list(app.app.url_map.iter_rules()))}')
|
||
"
|
||
```
|
||
|
||
## 已知問題
|
||
|
||
### 模板 url_for 端點名稱問題
|
||
|
||
當啟用模組化路由時,端點名稱會從 `'index'` 變為 `'dashboard.index'`。
|
||
這會導致模板中的 `url_for('index')` 調用失敗。
|
||
|
||
**影響範圍**:
|
||
- `index.html` 中的 `url_for('index', ...)`
|
||
- `edm_dashboard.html` 中的 `url_for('edm_dashboard', ...)`
|
||
|
||
**解決方案**(需在啟用模組前執行):
|
||
1. 在模板中使用完整的端點名稱,如 `url_for('dashboard.index', ...)`
|
||
2. 或在 app.py 中加入端點別名
|
||
|
||
**注意**:目前預設所有模組皆禁用(`USE_MODULAR_ROUTES` 全為 False),
|
||
因此不會影響正常使用。此問題只會在手動啟用模組後出現。
|
||
|
||
## 變更歷史
|
||
|
||
- **2026-01-18**:
|
||
- 初始版本,建立 9 個路由模組,5 個獨立模組可直接啟用
|
||
- 修復 url_for 端點名稱問題,新增 `register_endpoint_aliases()` 函數
|
||
- 處理有依賴的模組 (api, export, import),使用獨立 services 模組
|
||
- 新增 `services/task_runner.py` 封裝爬蟲任務執行邏輯
|
||
- 所有 9 個模組已啟用並通過測試
|