Files
Neo-ZQYY/docs/architecture/backend-architecture.md
Neo 6f8f12314f feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本
包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:03:48 +08:00

16 KiB
Raw Permalink Blame History

后端架构文档 — FastAPI 服务层

更新日期2026-03-23DevTrace 全链路日志模块) 位置:apps/backend/ 框架FastAPI + psycopg2同步连接池 数据库:zqyy_app(业务库)+ etl_feiqiuETL 库,直连只读访问)


1. 模块交互总览

graph TB
    subgraph "微信小程序"
        MP[miniprogram pages]
    end

    subgraph "管理后台"
        ADMIN[admin-web]
    end

    subgraph "FastAPI 后端"
        subgraph "路由层 (routers/)"
            R_AUTH[xcx_auth]
            R_TASKS[xcx_tasks]
            R_NOTES[xcx_notes]
            R_PERF[xcx_performance]
            R_CUST[xcx_customers<br/>CUST-1, CUST-2]
            R_COACH[xcx_coaches<br/>COACH-1]
            R_CHAT[xcx_ai_chat]
            R_CACHE[xcx_ai_cache]
            R_ADMIN[admin_*]
        end

        subgraph "服务层 (services/)"
            S_TM[task_manager<br/>任务 CRUD + 列表扩展]
            S_PS[performance_service<br/>绩效概览 + 明细]
            S_NS[note_service<br/>备注 CRUD + 评分]
            S_CS[customer_service<br/>客户详情 + 服务记录]
            S_CO[coach_service<br/>助教详情]
            S_FDW[fdw_queries<br/>FDW 查询集中封装]
            S_TG[task_generator<br/>任务自动生成]
            S_TE[task_expiry<br/>过期检测]
            S_RD[recall_detector<br/>召回完成检测]
            S_WX[wechat<br/>微信登录/Token]
        end

        subgraph "中间件 + 认证"
            MW[ResponseWrapperMiddleware]
            AUTH[JWT + require_approved]
        end
    end

    subgraph "数据库"
        BIZ[(zqyy_app<br/>biz / auth / public)]
        ETL[(etl_feiqiu<br/>直连 app.v_*)]
    end

    MP --> R_AUTH & R_TASKS & R_NOTES & R_PERF & R_CUST & R_COACH & R_CHAT
    ADMIN --> R_ADMIN

    R_TASKS --> S_TM
    R_PERF --> S_PS
    R_NOTES --> S_NS
    R_CUST --> S_CS
    R_COACH --> S_CO
    R_CHAT --> S_TM

    S_TM --> S_FDW
    S_PS --> S_FDW
    S_CS --> S_FDW
    S_CO --> S_FDW
    S_TM --> BIZ
    S_PS --> BIZ
    S_NS --> BIZ
    S_CS --> BIZ
    S_CO --> BIZ
    S_FDW --> ETL

    style S_FDW fill:#9f9,stroke:#333
    style S_PS fill:#9f9,stroke:#333
    style R_PERF fill:#9f9,stroke:#333
    style S_CS fill:#9f9,stroke:#333
    style S_CO fill:#9f9,stroke:#333
    style R_CUST fill:#9f9,stroke:#333
    style R_COACH fill:#9f9,stroke:#333

2. 路由模块清单

路由文件 前缀 说明
xcx_auth.py /api/xcx/auth 微信登录、Token 刷新、入驻申请
xcx_tasks.py /api/xcx/tasks 任务列表(TASK-1)、详情(TASK-2)、pin/unpin、abandon/restore
xcx_notes.py /api/xcx/notes 备注 CRUD含 score 评分)
xcx_performance.py /api/xcx/performance 绩效概览(PERF-1)、明细(PERF-2)
xcx_customers.py /api/xcx/customers 客户详情(CUST-1)、客户服务记录(CUST-2)RNS1.2 新增)
xcx_coaches.py /api/xcx/coaches 助教详情(COACH-1)RNS1.2 新增)
xcx_board.py /api/xcx/board 助教看板(BOARD-1)、客户看板(BOARD-2)、财务看板(BOARD-3)RNS1.3 新增)
xcx_config.py /api/xcx/config 技能类型配置(CONFIG-1)RNS1.3 新增)
xcx_ai_chat.py /api/xcx/ai AI 对话SSE 流式)
xcx_ai_cache.py /api/xcx/ai-cache AI 缓存查询
admin_applications.py /api/admin/applications 入驻审核
admin_dev_trace.py /api/admin/dev-trace 开发调试全链路日志(日期/请求/详情/清理/设置/覆盖率8 端点)
auth.py /api/auth 管理后台登录
member_retention_clue.py /api/member-retention-clue 维客线索
ops_panel.py /api/ops 运维面板
business_day.py /api/business-day 营业日配置

3. 服务层模块清单

服务文件 职责 数据源
task_manager.py 任务 CRUD、get_task_list_v2()get_task_detail() biz.coach_tasks + ETL 直连
performance_service.py get_overview()get_records(),绩效汇总与明细 ETL 直连
note_service.py 备注创建(含 score、AI 占位、回访触发 biz.notes
customer_service.py 客户详情(CUST-1)、客户服务记录(CUST-2)RNS1.2 新增) biz.coach_tasks + biz.ai_cache + biz.notes + public.member_retention_clue + ETL 直连
coach_service.py 助教详情(COACH-1):绩效/收入/任务分组/TOP客户/历史月份RNS1.2 新增) biz.coach_tasks + biz.notes + ETL 直连
fdw_queries.py ETL RLS 视图查询集中封装,直连 ETL 库 + SET LOCAL app.current_site_id 门店隔离 app.v_* (ETL 直连)
task_generator.py 定时任务:基于 WBI/NCI/RS 指数自动生成助教任务 biz + ETL 直连
task_expiry.py 定时任务:检测过期任务并标记 inactive biz.coach_tasks
recall_detector.py 事件驱动ETL 数据更新后检测召回完成 biz + ETL 直连
note_reclassifier.py 事件驱动:召回完成后回溯重分类备注 biz.notes
wechat.py 微信 code2session、Token 管理 外部 API
role.py 角色权限查询 auth.*
scheduler.py 触发器调度引擎 biz.trigger_jobs
board_service.py 三看板编排:get_coach_board()get_customer_board()get_finance_board(),含日期范围/环比/排序/分页/降级RNS1.3 新增) ETL 直连 + biz.coach_tasks
application.py 入驻申请处理 auth.applications

4. FDW 查询封装fdw_queries.py

所有跨库查询集中在此模块,确保 DWD-DOC 强制规则统一实施。

⚠️ 架构变更2026-03-18不再使用 zqyy_app 的 fdw_etl.* foreign table改为通过 get_etl_readonly_connection(site_id) 直连 ETL 库查询 app.v_* RLS 视图。原因:postgres_fdw 不传递自定义 GUC 参数到远端连接,导致 RLS 视图的 current_setting('app.current_site_id') 在远端未设置而报错。

所有函数通过 _fdw_context() 上下文管理器:创建 ETL 直连 → SET LOCAL app.current_site_id → 执行查询 → 关闭连接。

函数 用途 DWD-DOC 规则
get_member_info() 批量查询会员姓名/手机号 DQ-6JOIN v_dim_member
get_member_balance() 批量查询储值卡余额 DQ-7JOIN v_dim_member_card_account
get_last_visit_days() 批量查询距上次到店天数 废单排除is_delete = 0
get_salary_calc() 助教绩效/档位/收入 收入用 gross_salary费用用 base_income + bonus_income
get_service_records() 服务记录明细(分页) 收入用 ledger_amount + DQ-6 + 废单排除
get_service_records_for_task() 特定客户服务记录 同上
get_consumption_60d() 客户近 60 天消费金额RNS1.2 新增) 收入用 ledger_amountitems_sum+ 废单排除
get_relation_index() 客户与助教关系指数列表RNS1.2 新增) 来源 v_dws_member_assistant_relation_index
get_consumption_records() 客户消费记录嵌套查询RNS1.2 新增) items_sum + DWD-DOC 规则 2 + 废单排除
get_total_service_count() 客户累计服务总次数RNS1.2 新增) 废单排除is_delete = 0
get_coach_60d_stats() 助教对客户近 60 天统计RNS1.2 新增) 废单排除is_delete = 0
get_assistant_info() 助教基本信息RNS1.2 新增) 来源 v_dim_assistant
get_salary_calc_multi_months() 批量多月绩效数据RNS1.2 新增) 来源 v_dws_assistant_salary_calc
get_monthly_customer_count() 各月不重复客户数RNS1.2 新增) 废单排除is_delete = 0
get_coach_top_customers() 助教 TOP 客户RNS1.2 新增) DQ-6 + DQ-7 + items_sum + 废单排除
get_customer_service_records() 客户按月服务记录RNS1.2 新增) DQ-6 + items_sum + 废单排除
get_all_assistants() BOARD-1按技能筛选助教列表RNS1.3 新增) v_dim_assistant
get_salary_calc_batch() BOARD-1批量查询当期/上期绩效RNS1.3 新增) items_sum + assistant_pd/cx_money
get_top_customers_for_coaches() BOARD-1按亲密度 Top3 客户 + 四级 emojiRNS1.3 新增) DQ-6 + v_dws_member_assistant_relation_index
get_coach_sv_data() BOARD-1助教客源储值数据RNS1.3 新增) v_dws_assistant_recharge_commission
get_customer_board_recall() BOARD-2召回维度WBI 降序RNS1.3 新增) v_dws_member_winback_index + DQ-6
get_customer_board_potential() BOARD-2潜力维度SPI 降序RNS1.3 新增) v_dws_member_spending_power_index
get_customer_board_balance() BOARD-2余额维度RNS1.3 新增) v_dim_member_card_account + DQ-7
get_customer_board_recharge() BOARD-2充值维度RNS1.3 新增) v_dwd_recharge_order
get_customer_board_recent() BOARD-2最近到店维度RNS1.3 新增) v_dws_member_visit_detail
get_customer_board_spend60() BOARD-260 天消费维度RNS1.3 新增) items_sum 口径
get_customer_board_freq60() BOARD-260 天频次维度 + weeklyVisitsRNS1.3 新增) v_dws_member_consumption_summary
get_customer_board_loyal() BOARD-2忠诚度维度RS 降序RNS1.3 新增) v_dws_member_assistant_relation_index
get_customer_assistants() BOARD-2批量查询客户关联助教RNS1.3 新增) 含亲密度 + 当前跟进置顶
get_finance_overview() BOARD-3经营一览 8 项指标RNS1.3 新增) v_dws_finance_daily_summary + items_sum
get_finance_recharge() BOARD-3预收资产储值卡 + 赠送卡矩阵RNS1.3 新增) v_dws_finance_recharge_summary
get_finance_revenue() BOARD-3应计收入结构RNS1.3 新增) v_dws_finance_income_structure + discount_detail
get_finance_cashflow() BOARD-3现金流入RNS1.3 新增) v_dws_finance_daily_summary + 互斥规则 7
get_finance_expense() BOARD-3现金流出 4 子分组RNS1.3 新增) v_dws_finance_expense_summary + platform_settlement
get_finance_coach_analysis() BOARD-3助教分析basic + incentiveRNS1.3 新增) v_dws_assistant_salary_calc
get_skill_types() CONFIG-1技能类型配置RNS1.3 新增) ETL cfg 表

列名映射design.md 理想名 → 实际 FDW 视图列名)

RLS 视图直接暴露 DWD/DWS 原始列名,后端代码在 SQL 中使用 AS 别名转换。

v_dwd_assistant_service_log(基于 dwd.dwd_assistant_service_log,非 _ex 表):

代码语义 实际列名 说明
id assistant_service_id 服务记录主键
assistant_id (WHERE) site_assistant_id 与 salary_calc.assistant_id 同源
member_id tenant_member_id 会员 ID
is_trash = false is_delete = 0 整数类型0=正常
settle_time create_time 结算时间
start_time start_use_time 开始使用时间
end_time last_use_time 最后使用时间
service_hours income_seconds / 3600.0 折算工时(计算字段)
service_hours_raw real_use_seconds / 3600.0 原始工时(计算字段)
income (items_sum) ledger_amount 收入金额
course_type skill_name 课程类型
table_name site_table_id 仅有台桌 ID无名称

v_dws_assistant_salary_calc

代码语义 实际列名 说明
calc_month salary_month date 类型,存储为 YYYY-MM-01
coach_level assistant_level_name 档位名称
tier_index tier_id 档位 ID
basic_hours base_hours 基础课时
total_hours effective_hours 有效总工时
total_income gross_salary 总收入
basic_rate base_course_price 基础课单价
incentive_rate bonus_course_price 激励课单价
bonus_money sprint_bonus 冲刺奖金
assistant_pd_money_total base_income 基础课总收入
assistant_cx_money_total bonus_income 激励课总收入

注意:tier_nodestotal_customersnext_tier_*tier_completed 在视图中不存在,后端使用默认值或从其他数据源推算。

5. 数据流向

小程序请求
  → JWT 认证 (require_approved)
  → 路由层 (routers/)
  → 服务层 (services/)
  → 业务库 (zqyy_app) 直连
  → ETL 库 (etl_feiqiu) 直连只读app.v_* RLS 视图)
  → 响应包装 (ResponseWrapperMiddleware)
  → { code: 0, data: ..., message: "ok" }

7. Trace 全链路日志模块(app/trace/

开发调试专用的全链路请求追踪模块,覆盖 HTTP 请求、SSE 流式响应、WebSocket 连接、后台 Job、异常/错误、数据库连接生命周期和中间件层。日志以 JSON Lines 格式写入本地文件系统,仅用于开发调试。

模块结构

文件 职责
config.py TraceConfig 配置类,从环境变量读取(DEV_TRACE_*支持运行时动态修改API 更新后即时生效,重启回退 .env 值)
context.py TraceContext + TraceSpan 数据模型,基于 contextvars.ContextVar 实现请求级隔离23 种 span_type
writer.py JSON Lines 日志写入器,按日期分目录(YYYY-MM-DD/)、按小时分文件(trace_YYYY-MM-DD_HH.jsonl),单文件 10MB 自动轮转,维护 _index.json 索引
cleanup.py 日志自动清理,按 DEV_TRACE_LOG_RETENTION_DAYS 保留天数删除过期目录,每日凌晨自动执行
middleware.py TraceMiddleware ASGI 中间件,拦截 xcx_* 路由前缀请求,创建 TraceContext记录 HTTP_IN/HTTP_OUT/MIDDLEWARE span写入响应头X-Request-ID 等)
decorators.py @trace_service 装饰器Service 层函数追踪(模块名、函数名、参数、返回值摘要、耗时)
db_wrapper.py 数据库连接生命周期追踪,包装 cursor.execute()DB_QUERY、get_connection()DB_CONN、连接关闭DB_CONN_RELEASE、异常DB_ERROR
error_handler.py 异常/错误全链路追踪,集成全局异常处理器,记录 ERROR spanHTTPException + 未捕获异常 + 堆栈摘要)
sse_wrapper.py SSE 流式响应追踪SSE_START/SSE_EVENT/SSE_END/AI_CALL/AI_ERROR每 10 token 记录一次避免 span 爆炸
ws_wrapper.py WebSocket 连接追踪WS_CONNECT/WS_MESSAGE/WS_DISCONNECTtrace_type 为 "ws"
job_wrapper.py 后台 Job 执行追踪JOB_START/JOB_END/JOB_ERROR包装 lifespan 中注册的 4 个 job handler
coverage.py 覆盖率扫描器,通过 AST 解析检测路由/Service/Job/SSE/WS 五个维度的追踪覆盖情况,启动时自动扫描,支持手动刷新

数据流

xcx_* 请求 / SSE / WebSocket / 后台 Job
  → TraceMiddleware / sse_wrapper / ws_wrapper / job_wrapper
  → 创建 TraceContextcontextvars
  → AUTH span鉴权层
  → @trace_service spanService 层)
  → DB_QUERY / DB_CONN span数据库层
  → ERROR span异常处理器
  → TraceWriter 异步写入 .jsonl 文件
  → admin_dev_trace API 读取并展示

管理 API

admin_dev_trace.py 路由(/api/admin/dev-trace8 个端点admin 角色鉴权)提供日志查询、手动清理、运行时设置修改和覆盖率扫描能力。前端 DevTrace 页面(apps/admin-web/src/pages/DevTrace.tsx)提供可视化操作界面。

8. 关键设计决策

  • ETL 直连:所有 ETL 查询封装在 fdw_queries.py,通过 _fdw_context() 直连 ETL 库查询 app.v_* RLS 视图(不使用 FDW foreign table因 postgres_fdw 不传递自定义 GUC
  • 优雅降级扩展字段lastVisitDays/balance/aiSuggestion查询失败返回 null不影响核心响应
  • camelCase 转换:所有小程序端响应通过 CamelModel 自动转换为 camelCase
  • 门店隔离:业务库通过 site_id 参数过滤ETL 查询通过 SET LOCAL app.current_site_id + RLS 视图隔离