建立项目级标杆文档 docs/_overview/ 作为产品全景索引, 解决"PRD 零碎、文档膨胀、跨子系统调研无入口"的问题。 主要内容: - 00-index 总索引 + 维护协议 + 与 CLAUDE.md 关系 - 01-product-overview 产品全景脑图(6 角色 / 6 子系统 / 数据流 / 7 业务概念 / 8+1 AI 矩阵 / 22 术语) - 02a-miniprogram-page-matrix 小程序 21 页业务指纹 - 02b-adminweb-page-matrix admin-web 19 路由业务指纹 - 03-test-spec 测试规范 (L1-L5 分层 + 走查模板 + 75-95 case 估算) - 04-doc-conflicts 39 条冲突索引(P0×8 / P1×13 / P2×13 + 5 子项) - 04a/b/c-conflicts-*-detail 业务故事卡(7 字段:关联/逻辑/影响/选项/判定) - 05-orphan-pages-cleanup admin-web 6 孤儿页面处置(1 归档 + 4 保留) - WAVES-MASTER-PLAN.md 全 Wave 主计划(0-5,共 22-32 工作日) - WAVE-1-KICKOFF.md Wave 1 实施 kickoff - GLOBAL-DECISION-DASHBOARD.md 全局决策仪表板 反馈调研产物: - 04a-feedback/ P0 两轮反馈(8+8 项决策 + D-1/2/3 + F-1/2 子代理产出) - 04b-feedback/ P1 两轮反馈(13+1+5 项 + E-1/2/3/4 + G-1/2 子代理产出) - 04c-feedback/ P2 反馈(13 项 + 5 子项 + H-1/2/3 子代理产出) - NEO-DECISIONS-LOG 累积决策记录 关键追加发现 8 处 D Bug(原蓝本 0): - P0-3 看板沙箱接入(Wave 1 W1-T1) - P0-5 致命 1 (4 处 fdw_etl 残留, 已修 commit17f045a) - P0-5 致命 2 (JWT aud 缺失, 已修 commit17f045a) - P0-6 clearAllTasks 守卫 (Wave 3) - P0-8 DBViewer 黑名单漏 (已修 commit17f045a) - P1-3 task-detail 跳转传 task_id 而非 customer_id - P2-7 board-finance 隐式 null - 2 个独立 Bug (page_context.created_at + ClueCategory 字典) 参考: docs/_overview/00-index.md
24 KiB
P0-5 工程规范一致性全览
调研时间:2026-05-04 触发:Neo 在 P0-5 反馈"matching.py 直连 ETL 偏离规范"基础上提出 — 找到全项目类似情况,给个全览,并制定工程规范化和一致性的实施方案 关联:
04a-feedback/P0-5-matching-evolution.md(本调研为其下游) 性质:只调研不实施,产物为治理路线图
一、规范基线清单(共 14 条)
来源:CLAUDE.md(根 / 子模块) + 已知 spec / BD 手册 + 历史审计。
| # | 规范 | 来源 | 关键判定 |
|---|---|---|---|
| R1 | 业务库通过 FDW 只读访问 ETL,不直连 ETL 库 | apps/backend/CLAUDE.md "ETL 数据通过 FDW 映射的 app.v_* RLS 视图访问" |
后端不应直接 psycopg2.connect 到 etl_feiqiu |
| R2 | DWS / 取数禁用 consume_money,统一用 items_sum(ledger_amount) |
feiqiu CLAUDE.md / DWD-DOC 规则 1 | SELECT / 计算 / 返回字段不应包含 consume_money |
| R3 | DWD/DWS 视图必须双 schema(原 schema + app schema 同步建) | db/CLAUDE.md RLS 双 schema 模板 |
后端可走 app.v_*,但 dws.v_* 必须存在等价镜像 |
| R4 | 后端响应统一通过 ResponseWrapperMiddleware 包装 | apps/backend/CLAUDE.md |
不应有路由用 JSONResponse/response_class 显式绕过 |
| R5 | JWT 三类 aud(admin/miniapp/tenant-admin)严格隔离 |
apps/backend/CLAUDE.md JWT 双认证表 |
签发与校验都必须设置/校验 aud 字段 |
| R6 | AI 应用调用走 dispatcher 调度,不直接调 DashScope SDK | apps/backend/CLAUDE.md AI 集成 |
业务路由不应自行构造 DashScopeClient 调 Application.call |
| R7 | 配置分层 .env < .env.local < 环境变量 < CLI 参数,禁止生产代码硬编码主机/凭据 | 根 CLAUDE.md | 业务源码不应出现硬编码 IP/URL/密钥 |
| R8 | 测试不连生产库,用 TEST_*_DSN/load_dotenv 加载根 .env |
根 CLAUDE.md "测试与验证环境规范" | 测试不应引用 PG_DSN/APP_DB_DSN |
| R9 | 小程序参数命名 camelCase 对外、snake_case 内部 | 通用约定 | 后端 SnakeCase → CamelModel 自动转,前端取 camelCase |
| R10 | 审计记录全部归 docs/audit/changes/,不写入子模块 |
根 CLAUDE.md "文件归属规则" | 子模块下不应出现 docs/audit/ |
| R11 | _archived/ 目录禁止读取或参考 |
根 CLAUDE.md | 不应被 grep/read,不应被新代码引用 |
| R12 | apps/demo-miniprogram/(MOCK 标杆)禁改 |
根 CLAUDE.md | 30 天内不应有 commit 触及 |
| R13 | shared 包跨子项目共享 enums/money/datetime_utils | 根 CLAUDE.md / 推断 | 子项目不应重复定义同名工具 |
| R14 | DWD/DWS 字段命名约定:ETL 用 tenant_member_id / site_assistant_id,业务可用 member_id / assistant_id(已映射) |
feiqiu CLAUDE.md fdw_queries.py:48-58 |
跨层混用应有显式映射注释 |
二、偏离点全集(按规范分组)
2.1 R1 · FDW / 跨库访问
关键背景:H2(2026-03-20)规范变更后,业务后端"直连 ETL 库 + RLS 视图"已成为事实标准(fdw_queries._fdw_context() 模式)。R1 当前的写法"业务库通过 FDW 访问 ETL"在 apps/backend/CLAUDE.md 中实际已过期,应在治理时同步修订。但即便按事实标准衡量,仍存在多处偏离。
偏离点 1 — apps/backend/app/services/matching.py:62(P0-5 主体)
- 现状:用
_fdw_context(None, site_id)直连 ETL,未传入业务库 conn,bd_str降级为系统今天而非 RuntimeContext.business_date - 偏离类型:绕过 RuntimeContext 透传(P0-5 选项 B 主张"补 FDW 外部表"消除直连)
- 影响:沙箱模式下日期上界裁剪失效(若 site 启用沙箱,匹配读到未来助教/员工)
偏离点 2 — apps/backend/app/database.py:175 get_etl_write_connection() + services/task_generator.py:1107
- 现状:后端写入 ETL 关系指数表(
get_etl_write_connection()是可写连接,无 RLS,task_generator 直接执行 INSERT) - 偏离类型:严重违反 R1(规范明确"FDW 只读访问 ETL")
- 影响:业务后端越权写 ETL 库,绕过 ETL Loader 流程,数据所有权混乱
偏离点 3 — apps/backend/app/database.py:109 get_etl_global_readonly_connection() + routers/etl_status.py:44
- 现状:全局只读连接,不设置
app.current_site_id,直连 ETL 库读全局状态 - 偏离类型:绕过 RLS 隔离(规范前提"直连必带 RLS")
- 影响:潜在跨门店数据泄露(若被业务路由误调)
偏离点 4-7 — H2 改造遗漏的"伪 FDW"代码(实际必坏)
| 文件 | 行号 | 现状 | 严重度 |
|---|---|---|---|
routers/tenant_users.py |
425, 450 | etl_conn = get_etl_readonly_connection(site_id) 后 SQL 写 FROM fdw_etl.v_dim_assistant/v_dim_staff |
P0 — 必失败 |
routers/tenant_excel.py |
390, 407 | 同上,SQL 写 fdw_etl.v_dim_assistant/v_dim_staff |
P0 — 必失败 |
routers/tenant_clues.py |
113, 119 | 同上,SQL 写 fdw_etl.v_dim_member |
P0 — 必失败 |
致命点:这些查询连接的是 etl_feiqiu 库,而 fdw_etl schema 只存在于 zqyy_app 业务库 → 必报 schema "fdw_etl" does not exist → 当前被 try/except 静默吞,接口表面正常但永远返回空列表。这是 P0-5 同类(H2 改造遗漏)的高危偏离。
2.2 R2 · consume_money 字段
偏离点 8 — apps/backend/app/services/fdw_queries.py:1173/1208/1226
- 现状:
get_member_consumption_orders()SELECT 仍包含sh.consume_money,GROUP BY 也带,字典返回"consume_money": float(...)给前端 - 偏离类型:R2"DWS 取数禁用 consume_money"违反
- 用途反查:
customer_service.py:385用于"原价/折扣价"对比展示(原价 = consume_money,实付 = total_amount) - 评估:业务有真实需求(展示"划线价"),但取自 DWD 原始 consume_money 仍属于规范偏离 → 应在 BD 手册更新口径或加 view 层封装
偏离点 9 — apps/etl/connectors/feiqiu/tasks/utility/dws_build_order_summary_task.py:23
- 现状:用
(COALESCE(sh.consume_money, 0) = 0 AND COALESCE(sh.pay_amount, 0) > 0) AS recharge_order_flag识别充值订单 - 偏离类型:R2 在判定逻辑中使用 consume_money(非金额计算,但仍是该字段)
- 评估:判定语义合理(充值单消费金额必为 0),但应文档化为"R2 例外:仅作零值判定,不参与金额计算"
2.3 R3 · DWS 双 schema 视图
偏离点 10 — DWS schema 仅暴露 4 个视图,app schema 暴露 50+(规模性偏离)
db/etl_feiqiu/schemas/dws.sql 中 dws.v_* 仅 4 条:
dws.v_dws_coach_area_hours(L1206)dws.v_dws_finance_area_daily(L1227)dws.v_dws_finance_board_cache(L1267)dws.v_member_recall_priority(L1292)
db/etl_feiqiu/schemas/app.sql 中 app.v_dws_*/app.v_dwd_*/app.v_dim_*/app.v_cfg_* 共约 50 条。
DWS 基表共有 38 张(L46-L1027),意味着 ~34 张表只在 app schema 暴露 RLS 视图,违反 R3"双 schema"。
- 偏离类型:R3 规模性违反
- 影响:运维直查
dwsschema 时只能看到原始基表(无门店过滤),易出错;新建 RLS 视图必须双 schema 的规则反复被忽视 - 历史标记:
memory/MEMORY.md提到"踩坑 2026-03-29 DWS RLS 双 schema 强制规则"已存在,但执行不严
2.4 R4 · ResponseWrapperMiddleware
评估:无显式偏离,中间件设计良好
app/middleware/response_wrapper.py:33-37 中间件已自动跳过:
text/event-stream(SSE)- 非
application/json - 非 2xx
xcx_chat.py:344 / tenant_excel.py:954 用 StreamingResponse(SSE / 文件下载),由中间件自动跳过包装,不算偏离。
2.5 R5 · JWT aud 严格隔离
偏离点 11 — apps/backend/app/auth/jwt.py:42-50 admin/miniapp 签发完全不带 aud 字段
payload = {
"sub": str(user_id),
"site_id": site_id,
"type": "access",
"exp": expire,
} # 无 aud!
只有 tenant_auth.py:69/93 显式设置 "aud": "tenant-admin"。意味着:
-
admin-web 与小程序 token 在 payload 层无法区分
-
auth/dependencies.py:124 decode_access_token()也没校验 aud -
结果:小程序 token 理论上可被用于 admin 端点(若仅依赖
decode_access_token+ roles 检查,roles 分类不严就破防) -
偏离类型:P0 — 安全性偏离 R5
-
影响:跨端横向越权风险
-
修复成本:中(需小程序/admin-web 同步重新签发 token + 后端 verify 接受多 aud)
2.6 R6 · AI 应用走 dispatcher
偏离点 12 — 多处直接构造 DashScopeClient 调用
| 文件 | 行号 | 用途 |
|---|---|---|
app/main.py |
145 | lifespan 内全局单例(合理,作为 dispatcher 注入源) |
app/services/chat_service.py |
734 | _get_dashscope_client() 工厂 + :644 直接 SSE 流式调用百炼 |
app/services/note_service.py |
71 | 单点客户端实例化(走 App6 直接调用) |
app/routers/xcx_chat.py |
408 | 同上,xcx_chat.py:203 SSE 直接调 |
- 偏离类型:R6 部分违反
- 评估:SSE 流式回复天然不能走 dispatcher 的 run_step(dispatcher 设计是同步整段 reply),目前实现合理。但
note_service直调 App6 应改走 dispatcher - 影响:绕过熔断/限流/预算追踪,但 client 内部已有部分保护
- 修复成本:小(note_service 改走 dispatcher;chat_service SSE 路径标记为合理偏离)
2.7 R7 · 配置硬编码
偏离点 13 — apps/etl/connectors/feiqiu/config/defaults.py:30
- 现状:
"base_url": "https://pc.ficoo.vip/apiprod/admin/v1"硬编码飞球 API - 评估:作为 default 合理,允许 .env 覆盖;不算严格偏离
偏离点 14 — apps/etl/connectors/feiqiu/scripts/refresh_json_and_audit.py:22 / full_api_refresh_v2.py:27
- 现状:
API_BASE = "https://pc.ficoo.vip/apiprod/admin/v1/"模块顶层硬编码,无 env 读取分支 - 偏离类型:R7 违反
- 影响:迁移到飞球新域名/沙箱时改不动;一次性脚本性质风险低
- 修复成本:小
偏离点 15 — apps/etl/connectors/feiqiu/orchestration/flow_runner.py:255
- 现状:
backend_url = os.getenv("BACKEND_API_URL", "http://127.0.0.1:8000")— fallback 到本机 - 评估:合理(开发期默认),且有 env 覆盖
偏离点 16 — apps/admin-web/vite.config.ts:11 与 playwright.config.ts:21
- 现状:proxy target / playwright baseURL 硬编码
localhost:8000/localhost:5173 - 评估:合理(开发工具配置,非生产代码)
2.8 R8 · 测试不连生产库
偏离点 17 — apps/backend/tests/tests/unit/test_backfill_script.py:29
- 现状:
with patch.dict("os.environ", {"APP_DB_DSN": "postgresql://test:test@localhost/test"})— 用APP_DB_DSN而非TEST_APP_DB_DSN - 偏离类型:R8 违反(变量名错误,虽然值是假 DSN)
- 影响:命名混淆,易让人以为生产 DSN 也能用;真跑会因 patch 顺序问题潜在风险
- 修复成本:极小
偏离点 18 — 测试 load_dotenv 检查
apps/backend/tests/tests/integration/ 下两个 e2e 测试 import load_dotenv,实际加载根 .env(包含 PG_DSN/APP_DB_DSN),依赖 cwd 决定加载哪个 .env。如果集成测试在 backend cwd 跑,会加载 apps/backend/.env.local(其内 CORS_ORIGINS=http://localhost:5173 但未必有 TEST_*_DSN 覆盖) → 风险:误连生产库
- 偏离类型:R8 潜在违反
- 修复成本:中(需 conftest 强制注入 TEST_*_DSN 校验)
2.9 R9 · 命名风格
偏离点 19 — 小程序 task-list.ts:586,628,647 内部混用 camelCase / snake_case
const memberId = (target as any).memberId ?? (target as any).member_id // L586
const userId = (authUser as any).userId // L628
后端 CamelModel 应自动转成 camelCase 输出,小程序兜底读 snake_case 表明历史上后端字段未走 CamelModel。需逐字段确认:
-
是否后端
xcx_*路由全部走CamelModel.model_dump(by_alias=True)? -
现状部分 service 直接
dict返回(如tenant_users.py:441 .model_dump(by_alias=True)写了,但routers/xcx_*是否一致?) -
偏离类型:R9 部分违反(已知 P1-9 反馈)
-
修复成本:中
偏离点 20 — member_id vs tenant_member_id 混用
ETL 库 DWD 字段名 tenant_member_id(fdw_queries.py:48 注释明确),业务 API 对外是 member_id。
fdw_queries.py 内 SELECT/JOIN 都正确映射(tenant_member_id = %s → 返回 member_id),小程序 API 用 memberId。
- 评估:已有显式映射,符合 R14(DWD 字段命名约定),不算偏离;但映射散落在 200+ 行,易遗漏
2.10 R10 · 审计文件归属
偏离点 21 — apps/backend/tests/tests/_archived/
- 现状:子模块测试目录下有
_archived/(test_ai_app2.py / test_ai_apps_prompt.py / test_ai_clue_writer.py) - 偏离类型:R11 + R10 违反(子模块下不应有
_archived/,此为旧 Cursor 时代的产物) - 修复成本:小(整体移到根
_DEL/或者评审后删除)
偏离点 22 — apps/backend/tests/tests/ 嵌套异常
- 现状:
apps/backend/tests/与apps/backend/tests/tests/同时存在并各有重复测试文件(test_auth_jwt.py 出现在两层) - 偏离类型:目录结构混乱 / 历史迁移残留
- 影响:pytest 重复执行 / 修改时不知改哪个版本
- 修复成本:小(取舍后删一份)
偏离点 23 — apps/etl/connectors/feiqiu/tests/unit/unit/
- 现状:
tests/unit/unit/三层嵌套,任务测试文件有 task_test_utils.py 同名重复 - 偏离类型:同 22
- 修复成本:小
评估:apps/etl/connectors/feiqiu/scripts/audit/
- 现状:模块内
scripts/audit/是审计工具(scanner.py / inventory_analyzer.py 等),不是审计记录 - 评估:不算偏离(R10 限定的是审计记录,工具放模块内合理)
2.11 R11/R12 · _archived/ 与 demo-miniprogram/
偏离点 24 — demo-miniprogram 30 天内被修改
git log 显示:
f2e0de8(2026-05-02 反向迁移) — 改apps/demo-miniprogram/AGENTS.md81e4173(2026-04-29) — 改同文件2a7a5d6(2026-04-15~20) — 改project.miniapp.json/project.private.config.json- 偏离类型:R12 违反(MOCK 标杆原则上禁改)
- 评估:
AGENTS.md是 AI 环境文件,反向迁移期间清理可理解;project.miniapp.json改动需要审视
_archived/ 目录读取
pre_read_archived_block.py hook 已强阻断,无新违反
2.12 R13 · shared 包共用
未发现明显偏离。packages/shared/ 提供 enums/money/datetime_utils,各子项目正常 import,无重复定义。
三、偏离点严重度矩阵
| # | 偏离点 | 规范 | 原因 | 影响范围 | 修复成本 | 优先级 | 风险 |
|---|---|---|---|---|---|---|---|
| 1 | matching.py 不传 conn | R1 | 历史 H2 改造速度优先 | 单点 | 小 | Wave 1 | 中 |
| 2 | get_etl_write_connection + task_generator 写 ETL | R1 | 紧急修复(关系指数回写) | 模块 | 中 | Wave 2 | 高 |
| 3 | get_etl_global_readonly_connection 无 RLS | R1 | 设计偏好(系统监控) | 单点 | 小 | 长期 | 低 |
| 4-7 | tenant_users/excel/clues 残留 fdw_etl.* SQL(必坏) | R1 | H2 改造遗漏 | 模块 | 小 | 立即(P0) | 高 |
| 8 | fdw_queries 返回 consume_money 给前端 | R2 | 业务划线价需求 | 单点 | 中 | Wave 3 | 中 |
| 9 | dws_build_order_summary 用 consume_money 判定 | R2 | 充值单零值判定 | 单点 | 极小 | 文档化 | 低 |
| 10 | DWS schema 30+ 视图缺双 schema 镜像 | R3 | 不知规范 / 历史遗留 | 全局 | 大 | Wave 5 | 中 |
| 11 | jwt.py 不带 aud,decode 不验 aud | R5 | 设计偏好(单 secret) | 全局 | 中 | 立即(P0) | 高 |
| 12 | note_service 直调 DashScopeClient | R6 | 紧急功能 | 单点 | 小 | Wave 2 | 低 |
| 13-14 | 飞球 API 地址硬编码 | R7 | 一次性脚本 | 单点 | 极小 | 长期 | 低 |
| 17 | test_backfill_script 用 APP_DB_DSN | R8 | 命名错误 | 单点 | 极小 | 立即 | 低 |
| 18 | 集成测试 .env 加载顺序 | R8 | 配置不严 | 模块 | 中 | Wave 1 | 中 |
| 19 | 小程序 camelCase/snake_case 混用兜底 | R9 | 历史 P1-9 已知 | 模块 | 中 | Wave 3 | 低 |
| 21 | tests/tests/_archived/ | R10/R11 | 历史迁移残留 | 单点 | 极小 | 立即 | 低 |
| 22 | tests/tests/ 嵌套重复 | R10 | 历史迁移残留 | 模块 | 小 | 立即 | 中 |
| 23 | feiqiu tests/unit/unit/ 嵌套 | R10 | 历史迁移残留 | 模块 | 小 | 立即 | 低 |
| 24 | demo-miniprogram 30 天内改动 | R12 | AGENTS.md 迁移 | 单点 | 0 | 文档化(可接受) | 低 |
统计:24 个偏离点,其中 P0 立即 4 类(偏离 4-7、11、17、21、22、23),Wave 协同 5 类(1、2、8、12、18、19),长期 2 类(3、10、13-14),可接受文档化 3 类(9、20、24)。
四、统一治理方案
4.1 立即治理项(D-Bug 类,数据/安全风险)
治理 A · 修复 4 处必坏的 fdw_etl.* 残留(对齐 P0-5 主体)
| 文件 | 行 | 改法 |
|---|---|---|
routers/tenant_users.py:431 |
fdw_etl.v_dim_assistant |
→ app.v_dim_assistant |
routers/tenant_users.py:456-457 |
fdw_etl.v_dim_staff / v_dim_staff_ex |
→ app.v_dim_staff / app.v_dim_staff_ex |
routers/tenant_excel.py:394 |
fdw_etl.v_dim_assistant |
→ app.v_dim_assistant |
routers/tenant_excel.py:411 |
fdw_etl.v_dim_staff |
→ app.v_dim_staff |
routers/tenant_clues.py:119 |
fdw_etl.v_dim_member |
→ app.v_dim_member |
后续应改用 _fdw_context() 而非裸 get_etl_readonly_connection(统一拥有 business_date GUC)。
治理 B · JWT aud 标准化(R5)
auth/jwt.py:42payload 增"aud": "miniapp"(小程序签发)- 新建
auth/admin_jwt.py给 admin-web 签发,设"aud": "admin" dependencies.py:124 decode_access_token接受audience参数,FastAPI 依赖按路由前缀分流- 测试覆盖:miniapp token 调 admin 端点必须 401,反之亦然
治理 C · 测试目录单轨化
| 操作 |
|---|
apps/backend/tests/tests/_archived/ → 评审后删除或移到根 _DEL/ |
apps/backend/tests/tests/ 与 apps/backend/tests/ 合并(保留较新版本) |
apps/etl/connectors/feiqiu/tests/unit/unit/ 同上 |
test_backfill_script.py:29 把 APP_DB_DSN 改为 TEST_APP_DB_DSN |
4.2 Wave 协同项
| Wave | 关联偏离 | 治理措施 |
|---|---|---|
| Wave 1(matching FDW 重建) | 偏离 1、18 | P0-5 选项 B 实施时,顺带把 _fdw_context 改为 must 接 conn,集成测试 conftest 强制注入 TEST_*_DSN |
| Wave 2(关系指数 / AI 流水线) | 偏离 2、12 | task_generator 关系指数回写 ETL → 改走 ETL 内置 task(由 ETL 主动消费 biz 的关系信号);note_service 改走 dispatcher |
| Wave 3(对外 API 一致性) | 偏离 8、19 | 引入 view_dwd_order_with_orig_price 封装 consume_money 划线逻辑,前端字段统一 camelCase 强校验 |
| Wave 5(数据库治理) | 偏离 10 | 编写 tools/db/check_dws_dual_schema.py 扫描 dws 基表 vs dws.v_* 视图差集,补齐 30+ 镜像;CI 加守护测试 |
4.3 长期治理项
L1 · 修订 R1 文字(apps/backend/CLAUDE.md)
事实上 H2 后已统一直连 ETL,规范文字应改为:
ETL 数据通过
_fdw_context(conn, site_id)直连 ETL 库 + RLS 视图访问;fdw_etl.*外部表已废弃,新代码禁用。
L2 · 编写 scripts/audit/check_engineering_consistency.py
零 token 静态扫描脚本,检查项:
- grep
fdw_etl\.在apps/backend/app/下应零结果(白名单注释除外) - grep
audience=在 jwt 签发函数应非空 - grep
consume_money在 backend service / ETL 任务中应有 BD 手册引用 - 双 schema 视图差集(对比
dws.v_*与app.v_dws_*) - 测试目录嵌套 /
_archived/子模块违规 localhost/127.0.0.1在生产源码白名单外
接入 scripts/audit/prescan.py,合并到 /audit 流程
L3 · DWS 双 schema 历史补齐
约 30+ 个 app.v_dws_* 视图需补 dws.v_dws_* 镜像,生成迁移文件 db/etl_feiqiu/migrations/2026-XX-XX__dws_dual_schema_backfill.sql,逆序 DROP 写入回滚。
4.4 可接受偏离项(文档化归档)
| 偏离 | 理由 | 文档化位置 |
|---|---|---|
9 (dws_build_order_summary 用 consume_money 零值判定) |
仅作零值标记,不参与金额计算,业务语义清晰 | apps/etl/connectors/feiqiu/CLAUDE.md 增"R2 例外清单" |
| chat_service SSE 直调 DashScopeClient | 流式 reply 无法走 dispatcher run_step 抽象 | apps/backend/CLAUDE.md 增"R6 例外:SSE 流式直连" |
| 20 (member_id ↔ tenant_member_id 映射) | 已在 fdw_queries.py 集中映射,无散点违反 | 已在 fdw_queries.py:48-58 注释 |
| 24 (demo-miniprogram AGENTS.md) | 反向迁移产物,与代码逻辑无关 | 在 CLAUDE.md R12 加"例外:AGENTS.md / project config 文件可随迁移调整" |
五、CI / 自动化校验建议
5.1 静态规则(零 token)
| 检查 | 工具 | 失败动作 |
|---|---|---|
fdw_etl\. 在 apps/backend/app/ |
grep + CI | 拒绝合并 |
签发 JWT 必带 aud 字段 |
tools/audit/check_jwt_aud.py |
拒绝合并 |
dws 基表 vs dws.v_* 视图差集 |
tools/db/check_dws_dual_schema.py |
warning(>0 个差集) |
测试 from app.config import APP_DB_DSN 等违规导入 |
grep | 拒绝合并 |
_archived/ 子模块嵌套 |
find / glob | 警告 |
5.2 提交期 hook
新增 .claude/hooks/pre_commit_engineering_consistency.py:
- pre-commit 阶段调上述静态扫描脚本
- 命中即阻断并打印偏离点 + R 编号
5.3 周期性体检
scripts/audit/weekly_consistency_report.py:
- 每周生成本表(同此文档结构)
- 输出到
docs/audit/engineering_consistency_<YYYY-MM-DD>.md - diff 比上周新增/消除的偏离
六、给 Neo 的决策清单
按优先级倒序请 Neo 决策:
决策 D1(立即 / 高风险)
- 是否同意 P0 治理 A:修复 4 处
fdw_etl.*残留(tenant_users/excel/clues),改为app.v_*?这是真 bug,生产环境必坏,目前被 try/except 静默吞。 - 是否同意 P0 治理 B:JWT aud 标准化(jwt.py 加
aud,decode 加 audience 校验)?需后端+小程序+admin-web 三端协同发版。 - 是否同意 P0 治理 C:删除
apps/backend/tests/tests/_archived/、合并tests/tests/嵌套?
决策 D2(随 Wave 协同)
- Wave 1 P0-5 选项 B 实施时,是否一并把
_fdw_context(None, ...)改为强制传 conn?(避免 business_date 降级) - Wave 2:task_generator 写 ETL 关系指数表 → 改为"ETL 主动消费 biz 信号"还是保留
get_etl_write_connection?后者需在 R1 中明确"例外清单"。
决策 D3(长期治理)
- DWS 双 schema 30+ 视图历史补齐 → 何时启动?(估计需要 1-2 个工作日)
- 是否增加
.claude/hooks/pre_commit_engineering_consistency.py提交期阻断? - 周期性体检报告 → 接入
/audit还是独立 weekly?
决策 D4(规范文字修订)
- R1 在
apps/backend/CLAUDE.md是否改写为"H2 后规范"(直连 ETL + RLS,弃用 fdw_etl.*)? - R2 是否在 feiqiu CLAUDE.md 增"零值判定例外清单"?
- R6 是否增"SSE 流式直连例外"?
附录 A · 调研覆盖范围与方法
| 维度 | 覆盖工具 | 命中数 |
|---|---|---|
| FDW / 跨库 | grep get_etl_*_connection、fdw_etl\.、_fdw_context |
19 文件 |
| 响应包装 | grep JSONResponse / response_class / StreamingResponse |
2 文件(SSE 合理) |
| JWT aud | grep audience= / aud['"] / verify_token |
4 文件 |
| AI 调用 | grep DashScopeClient( / dashscope. |
4 直调点 |
| RLS 双 schema | grep `^CREATE.*VIEW (dws | app).` |
| consume_money | grep | 9 处 |
| 配置硬编码 | grep localhost / 127.0.0.1 / https?:// |
18 行 |
| 测试连库 | grep PG_DSN / APP_DB_DSN / TEST_*_DSN |
1 单测违规 |
| 命名混用 | grep 小程序 member_id / memberId / userId |
20 文件 |
| 审计/归档 | ls 子模块 docs/audit、_archived/ |
3 处嵌套违规 |
| demo-miniprogram | git log 30 天 | 4 commits |
未覆盖维度(后续补):
- shared 包重复定义检查(R13)
- xcx_* 路由是否全部走 CamelModel(R9 深度抽样)
- ETL DWD 12 条强制规则(feiqiu CLAUDE.md)逐项审计
附录 B · 与既有反馈交叉引用
| 本文偏离 | 关联反馈 | 关联文件 |
|---|---|---|
| 偏离 1 | P0-5 反馈主体 | 04a-feedback/P0-5-matching-evolution.md |
| 偏离 11 | (新发现 / 未在 P0/P1 列表) | — |
| 偏离 19/20 | P1-9 散落 memberId | 04b-feedback/P1-12-scattered-memberid.md |
| 偏离 4-7 | (新发现 / 高危) | — |
| 偏离 10 | 已知"DWS RLS 双 schema 踩坑"(memory 2026-03-29) | MEMORY.md |
(全文 ~570 行)