fix(backend): 生产入口补齐 CORS 与 health,两路入口收敛到共享实现
## 部署验证发现的严重问题
本轮装机后实测发现:加在 app/main.py 的修复**在生产完全不生效**——
部署位 /health 只返回 {status, time}、CORS 预检返回 405,而源码明明是新版。
根因:仓库有**两条后端启动路径**——
Services/kuaixun-service/app/main.py uvicorn app.main:app(开发/手册)
Scripts/bin/newsflash_backend.py **生产实际入口**,自建 FastAPI(...),
从不 import app.main
后者自己 app = FastAPI(...)、只 import 各 router,并自己注册了 /health。
因此 apply_cors / apply_exception_catch / apply_security_stack / 增强 health /
init_db 重试全部空转。而 app/database.py 的改动(now() 时间基准、双检锁、
连接超时)因为被 import 而生效——一半生效一半不生效,最难察觉。
## 修复
1. newsflash_backend.py 装三层中间件,顺序(由内到外):
exception_catch → ResponseCache → RequestLog → security_stack → cors
(后者必须最外,否则 500 响应拿不到跨源响应头)
2. health 载荷抽到 app/health.py::build_health_payload(),两个入口共用,
避免再次分叉
3. app/main.py 的 health 只做路由注册,转调共享实现
## 途中踩到并绕开的两个坑
- **命名冲突**:Scripts/bin/common.py(模块)与 kuaixun-service/common/(包)同名,
且 common 已被 `from common import ...` 缓存,故
`from common.security import ...` 报 "ModuleNotFoundError: 'common' is not a package"。
改为按 __file__ 推导路径 + importlib 显式加载。
- **路径推导**:不能用 common.KXS_HOME,它在 bundle 下解析为 Contents/Services/...
(缺 Resources 层级),实测 FileNotFoundError。改用
os.path.dirname(os.path.dirname(abspath(__file__))) 得到 Contents/Resources。
## 顺带修正 health 的 ready 语义
ready 表示「SQLAlchemy 建表完成」。生产入口走 db_pool(pymysql 池),不负责建表,
ready 恒为 False → 健康检查对完全可用的服务持续报 degraded,反向误导运维。
改为 ok = connected and drift_ok and not(init_failed),
即连通性与时区基准是硬判据,ready 只作诊断信息。
## 部署位实测(修复后)
GET /health → {"status":"ok",
"db":{"ready":false,"connected":true,"error":null,
"timebase_drift_seconds":0.274},
"ws_connections":0,"time":"2026-10-27T00:31:13"}
OPTIONS /api/v1/news/live (Origin: http://tauri.localhost) → 200
access-control-allow-origin: http://tauri.localhost
access-control-allow-headers: ... X-API-Key ...
access-control-allow-credentials: true
业务接口 GET /api/v1/news/live?limit=1 → 返回真实快讯数据
测试:test_timebase.py 的 health 用例改为 patch app.database 模块属性
(health 内部按模块属性取值),435 passed。