Files
Neo-ZQYY/docs/architecture/backend-architecture.md

13 KiB
Raw Blame History

后端架构文档 — FastAPI 服务层

更新日期2026-03-19RNS1.3 三看板接口 + CONFIG-1 技能类型) 位置: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 入驻审核
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 + FDW
performance_service.py get_overview()get_records(),绩效汇总与明细 FDW
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 + FDW
coach_service.py 助教详情(COACH-1):绩效/收入/任务分组/TOP客户/历史月份RNS1.2 新增) biz.coach_tasks + biz.notes + FDW
fdw_queries.py ETL RLS 视图查询集中封装,直连 ETL 库 + SET LOCAL app.current_site_id 门店隔离 app.v_* (ETL 直连)
task_generator.py 定时任务:基于 WBI/NCI/RS 指数自动生成助教任务 biz + FDW
task_expiry.py 定时任务:检测过期任务并标记 inactive biz.coach_tasks
recall_detector.py 事件驱动ETL 数据更新后检测召回完成 biz + FDW
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 新增) FDW + 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_monthly_summary
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" }

6. 关键设计决策

  • 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 视图隔离