From 19535a076384c67b3a1c589ae9ec7bb78ce9ad9d Mon Sep 17 00:00:00 2001 From: OoO Date: Thu, 30 Apr 2026 14:12:21 +0800 Subject: [PATCH] =?UTF-8?q?chore(cleanup):=20=E7=A7=BB=E9=99=A4=20legacy?= =?UTF-8?q?=205888=20=E6=B8=AC=E8=A9=A6=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AUTO_IMPORT_README.md | 4 +- CONSTITUTION.md | 2 +- GOOGLE_DRIVE_SETUP.md | 4 +- TODO_NEXT_STEPS.txt | 1 + app.py | 6 +- config.py | 2 +- docs/AI_INTELLIGENCE_MODULE_SOT.md | 2 +- docs/memory/history_logs.md | 1 + tests/main_test.py | 124 ------------------------ tests/test_google_drive.py | 2 +- tests/test_google_drive_auth.py | 2 +- tests/test_phase3f_cleanup_contracts.py | 27 ++++++ 12 files changed, 41 insertions(+), 136 deletions(-) delete mode 100644 tests/main_test.py diff --git a/AUTO_IMPORT_README.md b/AUTO_IMPORT_README.md index 23e1001..40a7561 100644 --- a/AUTO_IMPORT_README.md +++ b/AUTO_IMPORT_README.md @@ -72,7 +72,7 @@ pip install -r requirements.txt └── 當日業績/ ``` -2. 開啟網頁介面:http://localhost:5888/auto_import +2. 開啟網頁介面:http://localhost/auto_import 3. 設定: - **Google Drive 資料夾路徑**:`業績報表/當日業績` @@ -118,7 +118,7 @@ python3 test_google_drive.py ### 監控進度 -開啟:http://localhost:5888/auto_import +開啟:http://localhost/auto_import 可以看到: - ✅ 匯入配置 diff --git a/CONSTITUTION.md b/CONSTITUTION.md index d5d329b..ef88f0b 100644 --- a/CONSTITUTION.md +++ b/CONSTITUTION.md @@ -2,7 +2,7 @@ > 本文件定義專案開發的核心準則與不可違反的規範 > **建立日期**: 2026-01-12 -> **當前版本**: V10.21 (模組化治理守門版) +> **當前版本**: V10.22 (Legacy 5888 入口清理版) > **最後更新**: 2026-04-30 --- diff --git a/GOOGLE_DRIVE_SETUP.md b/GOOGLE_DRIVE_SETUP.md index 1d3d02d..9a50642 100644 --- a/GOOGLE_DRIVE_SETUP.md +++ b/GOOGLE_DRIVE_SETUP.md @@ -126,7 +126,7 @@ drive_service.authenticate() ### 5.2 在系統中配置路徑 -1. 開啟瀏覽器,前往:http://localhost:5888/auto_import +1. 開啟瀏覽器,前往:http://localhost/auto_import 2. 在「匯入配置」區域設定: - **Google Drive 資料夾路徑**:`業績報表/當日業績` - **檔案名稱模式**:`即時業績_當日`(選填,用於過濾檔案) @@ -268,7 +268,7 @@ tail -f logs/system.log | grep AutoImport ### 查看匯入統計 -前往網頁介面:http://localhost:5888/auto_import +前往網頁介面:http://localhost/auto_import ### 查詢排程統計 diff --git a/TODO_NEXT_STEPS.txt b/TODO_NEXT_STEPS.txt index 2d708cc..96f5e03 100644 --- a/TODO_NEXT_STEPS.txt +++ b/TODO_NEXT_STEPS.txt @@ -30,6 +30,7 @@ - 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 大檔。 + - Legacy 5888 入口清理:刪除 `tests/main_test.py` standalone Flask 死碼,測試與自動匯入文件改用 Port 80 入口。 【下次待辦】 - 依 inventory 優先拆 `routes/openclaw_bot_routes.py`、`routes/sales_routes.py`、`scheduler.py`。 diff --git a/app.py b/app.py index 1f6f803..9ec4edf 100644 --- a/app.py +++ b/app.py @@ -26,7 +26,7 @@ sys.path.insert(0, BASE_DIR) # 自動檢核並建立必要目錄 try: - for folder in ['database', 'services', 'crawler', 'logs', 'data', 'web/templates', 'web/static']: + for folder in ['database', 'services', 'crawler', 'logs', 'data', 'templates', 'web/static']: folder_path = os.path.join(BASE_DIR, folder) if not os.path.exists(folder_path): os.makedirs(folder_path) @@ -95,8 +95,8 @@ except Exception as e: sys_log.error(f"無法檢測磁碟空間: {e}") # 🚩 系統版本定義 (備份與顯示用) -# 🚩 2026-04-30 V10.21: Modularization governance guardrail -SYSTEM_VERSION = "V10.21" +# 🚩 2026-04-30 V10.22: Legacy standalone test and port cleanup +SYSTEM_VERSION = "V10.22" # ========================================== # 🔒 SQL Injection 防護函數 diff --git a/config.py b/config.py index b729674..a55e4a6 100644 --- a/config.py +++ b/config.py @@ -254,7 +254,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.21" +SYSTEM_VERSION = "V10.22" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/docs/AI_INTELLIGENCE_MODULE_SOT.md b/docs/AI_INTELLIGENCE_MODULE_SOT.md index f758bd1..065fb5d 100644 --- a/docs/AI_INTELLIGENCE_MODULE_SOT.md +++ b/docs/AI_INTELLIGENCE_MODULE_SOT.md @@ -2,7 +2,7 @@ > **最後更新**: 2026-04-30 (台北時間) > **狀態**: 🟢 四 AI Agent 自動化閉環已落地 — EventRouter / AutoHeal / OpenClaw Memory / ElephantAlpha bridge / Prometheus metrics / Smoke Dashboard / Smoke Trend Management / Telegram Summary / Grafana provisioning / Prometheus scrape / CD Gunicorn 掛載具測試覆蓋 -> **適用版本**: V10.20 ElephantAlpha transient fallback 版 +> **適用版本**: V10.22 Legacy 5888 入口清理版 --- diff --git a/docs/memory/history_logs.md b/docs/memory/history_logs.md index 8ca7ba0..8757fd8 100644 --- a/docs/memory/history_logs.md +++ b/docs/memory/history_logs.md @@ -43,6 +43,7 @@ - **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`,防止未分類巨檔再長出來。 +- **Legacy 5888 入口清理**: 刪除 `tests/main_test.py` standalone Flask 死碼,測試與自動匯入文件改用 Port 80 `/auto_import` 入口。 ### 2026-04-28~29:Phase 3e 重構大戰 + daily_sales cache 隱形 bug 根除 - **app.py 縮減 -10.8%**: 7,386 → 6,590 行,11 commits 全綠零 502。 diff --git a/tests/main_test.py b/tests/main_test.py deleted file mode 100644 index cc26aba..0000000 --- a/tests/main_test.py +++ /dev/null @@ -1,124 +0,0 @@ -import os -from flask import Flask, render_template, session, redirect, url_for, send_from_directory -from database.manager import DatabaseManager -from auth import init_auth_routes, login_required -from config import SECRET_KEY, DATA_DIR, LOG_DIR, EXCEL_EXPORT_DIR - -# --- 1. 初始化路徑與 Flask --- -BASE_DIR = os.path.abspath(os.path.dirname(__file__)) -TEMPLATE_DIR = os.path.join(BASE_DIR, 'web', 'templates') -STATIC_DIR = os.path.join(BASE_DIR, 'web', 'static') - -app = Flask(__name__, - template_folder=TEMPLATE_DIR, - static_folder=STATIC_DIR) - -app.secret_key = SECRET_KEY - -# 初始化權限路由 -init_auth_routes(app) - -# 初始化資料庫管理員 -db_mgr = DatabaseManager() - -def get_db_size(): - """獲取資料庫實體檔案大小""" - db_path = os.path.join(DATA_DIR, 'momo_database.db') - if os.path.exists(db_path): - size_bytes = os.path.getsize(db_path) - return f"{size_bytes / (1024 * 1024):.2f} MB" - return "0.00 MB" - -# --- 2. 路由定義 --- - -@app.route('/') -@login_required -def dashboard(): - """主看板:包含統計數據與商品明細清單""" - stats = { - "total_products": 0, - "price_changes": 0, - "db_size": get_db_size() - } - recent_products = [] - - session_db = db_mgr.Session() - try: - from database.models import Product, PriceRecord - from datetime import datetime - from sqlalchemy import desc - - # A. 計算統計數據 - stats["total_products"] = session_db.query(Product).count() - - today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) - stats["price_changes"] = session_db.query(PriceRecord).filter( - PriceRecord.timestamp >= today_start - ).count() - - # B. 抓取最新 50 筆商品明細 - # 邏輯:抓取 Product,並針對每個 Product 找出最後一筆價格 - products_query = session_db.query(Product).order_by(Product.id.desc()).limit(50).all() - - for p in products_query: - # 取得該商品在 PriceRecord 表中最新的一筆紀錄 - latest_price_rec = session_db.query(PriceRecord)\ - .filter_by(product_id=p.id)\ - .order_by(desc(PriceRecord.timestamp))\ - .first() - - recent_products.append({ - "category": p.category, - "name": p.name, - "price": f"{latest_price_rec.price:,.0f}" if latest_price_rec else "N/A", - "url": p.url, - "time": latest_price_rec.timestamp.strftime('%m/%d %H:%M') if latest_price_rec else "-" - }) - - except Exception as e: - app.logger.error(f"❌ 看板數據讀取失敗: {e}") - finally: - session_db.close() - - return render_template('dashboard.html', stats=stats, products=recent_products) - -@app.route('/logs') -@login_required -def view_logs(): - """日誌查看頁面""" - log_path = os.path.join(LOG_DIR, 'system.log') - content = "⚠️ 尚無日誌紀錄。" - if os.path.exists(log_path): - try: - with open(log_path, 'r', encoding='utf-8') as f: - f.seek(0, os.SEEK_END) - size = f.tell() - f.seek(max(0, size - 15000)) # 讀取最後 1.5 萬字元 - content = f.read() - except Exception as e: - content = f"讀取日誌出錯: {e}" - return render_template('logs.html', log_content=content) - -@app.route('/download/') -@login_required -def download_excel(filename): - """Excel 報表下載""" - return send_from_directory(EXCEL_EXPORT_DIR, filename) - -# --- 3. 啟動自我檢查 --- - -if __name__ == '__main__': - print("\n" + "="*50) - print("🚀 MOMO 伺服器啟動中...") - print(f"📂 模板目錄: {TEMPLATE_DIR}") - - # 檢查核心檔案 - for f in ['dashboard.html', 'login.html']: - path = os.path.join(TEMPLATE_DIR, f) - status = "✅ 存在" if os.path.exists(path) else "❌ 缺失" - size = f"({os.path.getsize(path)} bytes)" if os.path.exists(path) else "" - print(f" - {f}: {status} {size}") - - print("="*50 + "\n") - - app.run(host='0.0.0.0', port=5888, debug=True) \ No newline at end of file diff --git a/tests/test_google_drive.py b/tests/test_google_drive.py index a1a3787..61a5b42 100644 --- a/tests/test_google_drive.py +++ b/tests/test_google_drive.py @@ -90,7 +90,7 @@ def main(): print("=" * 60) print() print("🌐 開啟網頁介面查看詳細資訊:") - print(" http://localhost:5888/auto_import") + print(" http://localhost/auto_import") print() diff --git a/tests/test_google_drive_auth.py b/tests/test_google_drive_auth.py index b5e6bff..64adf08 100644 --- a/tests/test_google_drive_auth.py +++ b/tests/test_google_drive_auth.py @@ -49,7 +49,7 @@ try: print("Token 已儲存至: config/google_token.pickle") print() print("現在可以:") - print(" 1. 在網頁介面測試連接: http://localhost:5888/auto_import") + print(" 1. 在網頁介面測試連接: http://localhost/auto_import") print(" 2. 執行測試腳本: python3 test_google_drive.py") print() else: diff --git a/tests/test_phase3f_cleanup_contracts.py b/tests/test_phase3f_cleanup_contracts.py index d353dae..77bc06e 100644 --- a/tests/test_phase3f_cleanup_contracts.py +++ b/tests/test_phase3f_cleanup_contracts.py @@ -84,11 +84,38 @@ def test_tracked_backup_artifacts_stay_removed(): "app.py.backup_login_required", "vendor_stockout_list.html.backup", "database/edm_dashboard.html", + "tests/main_test.py", ] assert [path for path in forbidden_artifacts if (ROOT / path).exists()] == [] +def test_active_code_no_longer_references_legacy_5888_port(): + active_paths = [ + ROOT / "app.py", + ROOT / "tests", + ROOT / "AUTO_IMPORT_README.md", + ROOT / "GOOGLE_DRIVE_SETUP.md", + ] + + offenders = [] + for active_path in active_paths: + paths = active_path.rglob("*") if active_path.is_dir() else [active_path] + for path in paths: + if ( + not path.is_file() + or path == Path(__file__).resolve() + or "__pycache__" in path.parts + or path.suffix == ".pyc" + ): + continue + content = path.read_text(encoding="utf-8", errors="ignore") + if "5888" in content: + offenders.append(str(path.relative_to(ROOT))) + + assert offenders == [] + + def test_executable_scripts_do_not_use_remove_orphans(): script_paths = [ ROOT / "scripts",