DIP1-01 · 架构设计¶
文档编号:DOC-D00-D1-01 / DIP1-01(ARC) 版本:V2.0 创建日期:2026-08-09 最近更新:2026-08-09 维护人:TL / DT 决策审批人:TL + SPO 关联文档:TND-E V1.1 §5.3、DIP1-00 README、QMD、CPT-D、MDS-D
V2.0 重大变更:前端从 Next.js PWA 升级为 React Native 原生 App(师傅端 + 客户端);运营后台保留 Next.js Web;跳过阶段1 飞书对接,直接实施阶段2。详见 ADR-002 / ADR-006 / ADR-007。
一、设计原则(五条铁律,违反须提交变更申请)¶
| # | 原则 | 含义 | 实践落地 |
|---|---|---|---|
| P1 | DDD 四层分离 | 领域层必须是纯 Python,不依赖 FastAPI/SQLAlchemy 等任何框架 | Code Review 检查 domain/ 模块 import,禁止引入 fastapi / sqlalchemy |
| P2 | 依赖倒置 | 领域层定义 Repository 端口(ABC 抽象基类),基础设施层实现,应用层依赖端口不依赖实现 | domain/*/ports.py 定义接口,infrastructure/db/repositories.py 实现 |
| P3 | 模块化单体优先,服务化按需 | 阶段 1-2 单体部署,不拆微服务;信号触发拆分(TND-E §6.3.2) | 代码层模块边界清晰,接口通信仅通过 Application Service;禁止跨模块 DB Join |
| P4 | 配置外置,业务参数一律进 DB | 报价系数、派单阈值、结算规则不得硬编码代码 | mds_params_config 配置表 + OPR 后台配置页面 + 缓存 Redis |
| P5 | 字段命名兼容 MVP-FS | 所有 snake_case 字段名与飞书多维表格保持完全一致,CSV→DB 零改名 | 见 DIP1-02 §字段映射表 |
二、系统分层架构(C4 容器视角)¶
flowchart TD
subgraph USER["用户层(3 类核心 + 2 类扩展)"]
U1["OPR 运营后台用户<br/>(成文·黄·洪·司徒)"]
U2["WKR 师傅<br/>(香港安装师傅)"]
U3["CST 客户<br/>(香港终端消费者)"]
U4["DLV 配送(扩展)"]
U5["PRT 合作方(扩展)"]
end
subgraph FE["前端容器层(Web + RN 双引擎)"]
FE1["OPR 运营后台<br/>Next.js 14 SSR<br/>apps/opr-admin<br/>(PC Web 保留)"]
FE2["WKR 师傅 App<br/>React Native + Expo<br/>apps/wkr-app<br/>(iOS+Android 原生)"]
FE3["CST 客户 App<br/>React Native + Expo<br/>apps/cst-app<br/>(iOS+Android 原生)"]
end
subgraph API_GW["接口层(FastAPI)"]
GW1["REST API 路由<br/>interfaces/api/*_router.py"]
GW2["Webhook 回调<br/>interfaces/webhooks/*.py"]
AUTH["JWT + RBAC 鉴权中间件"]
RATE["限流 + 日志 + Trace 中间件"]
end
subgraph APP_LAYER["应用层(Application Use Case)"]
APP1["报价用例<br/>QuoteApplicationService"]
APP2["跟踪用例<br/>OrderApplicationService"]
APP3["主数据用例<br/>MasterDataApplicationService"]
APP4["派单用例<br/>DispatchApplicationService"]
APP5["结算用例<br/>SettlementApplicationService"]
APP6["AI 融合用例<br/>AIIntegrationService"]
end
subgraph DOMAIN_LAYER["领域层(Domain,纯 Python)"]
D1["QSV 报价上下文<br/>实体 + 值对象 + 报价策略接口"]
D2["CPT 跟踪上下文<br/>实体 + 8 阶段状态机 + 采集物约束"]
D3["MDS 主数据上下文<br/>Worker/Customer/Category/Building 实体"]
D4["DSP 派单上下文<br/>匹配算法接口 + 派单规则"]
D5["PAY 结算上下文<br/>对账规则 + 发票实体"]
D6["共享内核<br/>Money/DateTimeRange/Address VO + 领域事件"]
end
subgraph INFRA_LAYER["基础设施层(实现 Domain 端口)"]
INF1["PostgreSQL 16<br/>SQLAlchemy 2.0 ORM + Alembic"]
INF2["Redis 7<br/>缓存 + 异步任务队列 + 分布式锁"]
INF3["Cloudflare R2<br/>照片/附件对象存储(S3 兼容)"]
INF4["飞书开放平台 SDK<br/>Bitable API + IM 机器人"]
INF5["LLM API<br/>听写助手/报价建议/师傅推荐/照片质检"]
INF6["日志 + 监控 + 告警<br/>Logfire/Sentry/Prometheus"]
end
USER --> FE
FE -->|"HTTPS + JSON"| API_GW
API_GW --> APP_LAYER
APP_LAYER -->|"调用端口接口"| DOMAIN_LAYER
INFRA_LAYER -->|"实现端口接口"| DOMAIN_LAYER
style USER fill:#D4AF78,stroke:#004046,color:#004046
style FE fill:#457b9d,stroke:#004046,color:#fff
style API_GW fill:#004046,stroke:#004046,color:#fff
style APP_LAYER fill:#2a9d8f,stroke:#004046,color:#fff
style DOMAIN_LAYER fill:#2a9d8f,stroke:#004046,color:#fff
style INFRA_LAYER fill:#555,stroke:#004046,color:#fff
2.1 各层职责¶
| 层 | 职责 | 允许做 | 禁止做 |
|---|---|---|---|
| Interfaces 接口层 | 对外暴露 REST API/Webhook、参数校验(Pydantic)、鉴权、异常映射 HTTP 状态码 | 路由定义、依赖注入 Application Service、DTO ↔ 领域对象转换 | 写任何业务逻辑(如"阶段 3 是否可跳阶段 4"这类判断必须下沉到领域层) |
| Application 应用层 | 用例编排、事务边界、DTO 组装、调用多个领域服务/仓储 | 调用领域服务 + 仓储端口、发送领域事件、跨上下文协调 | 写业务规则;不得跨模块直接查表;不得 import SQLAlchemy/FastAPI |
| Domain 领域层 | 核心业务规则、实体状态不变量、领域服务、仓储端口定义 | 定义 Entity/VO/Aggregate/Domain Service/Repository Port/Domain Event | 引用任何框架(FastAPI/SQLAlchemy/Redis);访问外部资源;不做 ORM Mapping |
| Infrastructure 基础设施层 | 实现仓储端口、对接飞书/AI/R2 外部系统、ORM 映射、消息队列、缓存 | SQLAlchemy Model 定义、飞书 SDK 封装、S3 Client、Celery Task | 写业务规则;实现逻辑必须通过 Domain 定义的端口回归 |
三、限界上下文映射(Context Mapping)¶
| 上下文 | 简称 | 上游/下游 | 关系模式 | 交互方式 |
|---|---|---|---|---|
| 报价 | QSV | — | 核心独立上下文 | 报价计算独立,不依赖其他上下文状态 |
| 跟踪 | CPT | 下游(消费 QSV 报价结果;消费 MDS 师傅/客户信息;消费 DSP 派单结果) | Customer-Supplier + ACL(防腐层) | QSV 生成 Quote 后,CPT 持有 quote_id 引用;师傅/客户信息通过 Application Service 查 MDS |
| 主数据 | MDS | 上游(为 QSV/CPT/DSP/PAY 提供师傅/品类/楼宇/客户档案 ID) | Published Language(统一 ID 规范) | 所有引用一律用 worker_id / customer_id / category_code / building_id,禁止冗余复制字段 |
| 派单 | DSP | 下游(消费 WKR 画像)→ 上游(发布派单结果给 CPT) | Customer-Supplier | DSP 生成 assignment_id → CPT 阶段 L2 写入 |
| 结算 | PAY | 下游(消费 CPT 完工数据 + WKR 费率 + QSV 报价) | Conformist(严格跟随 QSV/CPT 模型) | 统一 order_id 对账 |
flowchart LR
MDS["MDS 主数据<br/>[上游 Published Language]"] -->|worker_id/category_code| QSV["QSV 报价"]
MDS -->|worker_id/customer_id/building_id| DSP["DSP 派单"]
QSV -->|quote_id + final_amount| CPT["CPT 跟踪"]
DSP -->|assignment_id| CPT
CPT -->|order_id + stage_data + worker_id| PAY["PAY 结算"]
MDS -->|worker_rate_level| PAY
style MDS fill:#fbf1dc,stroke:#D4AF78,color:#8B6F3E
style PAY fill:#457b9d,stroke:#004046,color:#fff
style CPT fill:#2a9d8f,stroke:#004046,color:#fff
反腐层(ACL):CPT 调用 QSV/MDS 时必须通过 Application Service 的防腐接口,禁止直接引入 QSV 的 SQLAlchemy Model 或其他上下文内部类。
四、物理部署架构(阶段 1 → 阶段 2 演进)¶
4.1 阶段 2:Cloudflare + VPS + App Store(直接阶段2,跳过飞书)¶
flowchart LR
DNS["DNS<br/>hk2026.com.hk(Cloudflare)"]
CF["Cloudflare CDN + WAF + 缓存"]
subgraph PAGES["Cloudflare Pages(OPR Web)"]
FE_O["OPR 后台<br/>opr.hk2026.com.hk<br/>Next.js SSR"]
end
subgraph APP_STORE["应用商店(RN 双端)"]
APP_IOS["App Store<br/>WKR App + CST App<br/>iOS 14+"]
APP_AND["Google Play<br/>WKR App + CST App<br/>Android 9+"]
end
subgraph EXPO["Expo 云服务"]
EAS["EAS Build + Submit<br/>云端构建+自动提审"]
OTA["Expo Updates<br/>JS Bundle 热更新"]
PUSH["Expo Notifications<br/>APNs + FCM 统一推送"]
end
subgraph HK_VPS["香港 VPS(阿里云/腾讯云轻量,4C8G 起步)"]
DOCKER["Docker Engine"]
BE["Backend API<br/>api.hk2026.com.hk<br/>FastAPI + Uvicorn 单容器"]
PG["PostgreSQL 16<br/>Container + 定期备份到 R2"]
RD["Redis 7<br/>Container"]
PUSH_SVC["Push Service<br/>Expo Push + 模板渲染"]
end
R2["Cloudflare R2<br/>附件存储 assets.hk2026.com.hk"]
LLM["LLM API<br/>OpenAI/国产大模型"]
DNS --> CF
CF --> PAGES
CF -->|"/api/* 反代"| BE
PAGES -->|"数据请求"| BE
APP_IOS -->|"HTTPS + JWT"| BE
APP_AND -->|"HTTPS + JWT"| BE
APP_IOS --> OTA
APP_AND --> OTA
BE --> PUSH
PUSH --> APP_IOS
PUSH --> APP_AND
EAS --> APP_IOS
EAS --> APP_AND
BE --> PG
BE --> RD
BE --> R2
BE --> LLM
BE --> PUSH_SVC
成本预估(阶段 2):香港 VPS ≈ 300-600 HKD/月 + Cloudflare 免费档 + Expo 免费档(EAS Build 30 次/月足够)+ Apple Developer $99/年 + Google Play $25 一次性 + 域名 ≈ 100 HKD/年。
4.2 未来扩展:高可用 + 服务化(按需拆分)¶
- 数据库:PostgreSQL 一主一从(只读副本,OPR 查询报表走从库)
- 后端:拆分为 2-3 个服务(AI 服务 + PAY 结算优先独立),容器编排用 Docker Compose 或最小化 K3s
- 前端:新增 DLV/PRT 端,继续 RN 复用组件
- 消息队列:新增 Kafka 或 RabbitMQ(订单事件异步解耦)
- 阶段0 飞书对接:若 MVP-FS 飞书方案实际运行后需要数据沉淀,按 DIP1-P1 文档启动飞书 SDK 对接(本文档保留供未来使用)
五、非功能需求(NFR)¶
| 维度 | 阶段 2 目标(直接阶段2) | 度量方法 |
|---|---|---|
| 性能 | QSV 报价 P95 < 200ms;CPT 列表查询 P95 < 500ms | Locust 压测 + Logfire |
| 可用性 SLA | ≥ 99.9%(每月 ≤ 43 分钟不可用) | Uptime Kuma 监控 |
| 并发 | 支撑 500-1000 并发用户(OPR 10 + WKR 100 + CST 800+) | Locust + 实际业务压测 |
| 数据安全 | PDPO 合规审计通过;客户/师傅手机号 AES-256 加密;RBAC + RLS 行级权限;R2 签名 URL;AI 调用脱敏 | 渗透测试 + PDPO 自查表 |
| 可维护性 | 单元测试覆盖率 ≥ 80%;架构守护测试(防止领域层依赖框架);CI 全绿才能合并 | SonarQube + CI Gate |
| 可观测性 | 全链路 Trace(OpenTelemetry)+ 移动端崩溃监控(Sentry RN SDK)+ 业务指标 | Logfire + Grafana + Sentry |
| 国际化 | 繁/简/英三语切换(i18n 框架 + 词典) | Next-intl + i18next |
| 移动端兼容性 | WKR/CST App 兼容 iOS 14+ / Android 9+(React Native 原生) | BrowserStack + 真机抽样 |
| 移动端离线 | WKR 师傅端 L6 拍照离线缓存 ≥ 24h;弱网自动重试上传 | 离线场景测试 |
| 推送送达率 | APNs + FCM 推送送达率 ≥ 95%;点击率 ≥ 30% | Expo Notifications Dashboard |
| App 启动性能 | 冷启动 ≤ 2s;热启动 ≤ 0.5s | Flipper 性能 profiling |
| OPR 后台兼容 | Chrome 90+ / Safari 14+ / Edge 90+ | BrowserStack |
六、架构演进信号与决策树(什么情况下从单体拆服务)¶
flowchart TD
A["模块化单体运行<br/>阶段 1 稳定 2 个月"] --> B{触发信号?}
B -->|"单模块部署冲突 ≥ 3 次/月<br/>(康威定律)"| C["按团队边界拆服务"]
B -->|"单一模块 CPU/内存<br/>使用率持续 > 70%"| D["单模块独立扩容<br/>(优先 PAY/AI 服务)"]
B -->|"某模块数据库连接<br/>占总连接 > 60%"| E["拆独立服务+独立 DB Schema<br/>(优先 MDS/QSV 读多)"]
B -->|"上线新端 CST/DLV/PRT<br/>接口请求量翻倍"| F["引入 BFF 层,按端定制 API<br/>(TND-E §6.3.1)"]
B -->|"无强信号"| Z["维持单体<br/>不拆 = 省钱省复杂度"]
style Z fill:#2a9d8f,stroke:#004046,color:#fff
架构底线:任何拆分决策必须由 TL 书面发起、SPO 审批;拆分前先完成「单体内部优化」(SQL 慢查询、缓存命中率、异步队列消峰)——可单体优化的一律不拆服务。
七、技术风险与对策¶
| 风险 | 概率 | 影响 | 对策 |
|---|---|---|---|
| RN 原生模块冲突(第三方库版本不兼容) | 中 | 中 | Expo managed workflow 统一版本;冲突时降级 bare workflow;每周依赖审计 |
| App Store / Google Play 审核被拒 | 中 | 高 | 提前遵守审核指南(PDPO 隐私政策、苹果登录选项、安卓目标 API 级别);首次提审预留 2 周缓冲 |
| Expo 限制(部分原生能力需 bare workflow) | 低 | 中 | managed 优先;必要时 eject 到 bare;保留原生扩展能力 |
| 师傅端 L6 拍照离线场景复杂(弱网/无网/电量) | 高 | 中 | AsyncStorage 本地队列 + NetInfo 网络监听 + 指数退避重试;照片压缩 WebP 减少体积 |
| BE/FE 核心开发招聘不到位 | 高 | 高 | Code Agent 全栈实施 + DT AI 协同;司徒兜底关键模块;前端 RN 部分可分阶段交付 |
| 推送送达率不达标(iOS 静默推送限制) | 中 | 中 | Expo Notifications 统一通道;关键通知走高优先级;送达率监控告警 |
| 师傅照片/视频存储成本爆炸(每日 100 单 × 每单 20 张) | 低 | 中 | Cloudflare R2 零出口费;前端 WebP 压缩;超过 90 天自动降冷 |
| 数据库 DDL 变更回滚风险 | 中 | 高 | Alembic 双脚本(upgrade + downgrade);CI dry-run;上线前全站备份;重大变更凌晨窗口 |
八、决策记录(Architecture Decision Records,ADR)¶
关键架构决策须记录,便于未来回溯为什么"这么选"。
| ADR # | 决策 | 日期 | 决策人 | 理由 |
|---|---|---|---|---|
| ADR-001 | 选 Python FastAPI 而非 Go/Node 后端 | 2026-08-09 | TL + SPO | ① AI 生态最成熟(Pandas/LLM 工具链);② 司徒 Python 熟练度最高;③ 报价/派单算法代码可读性强 |
| ADR-002 | 选 React Native + Expo 而非 Next.js PWA(V2.0 重写) | 2026-08-09 | TL + SPO | ① 原生体验远超 PWA(动画/手势/启动速度);② 深度集成相机/推送/离线/生物识别;③ 香港师傅 Android 为主,PWA 留存率低;④ Expo 一站式 OTA/构建/推送;⑤ 运营后台保留 Next.js(PC Web 场景更佳) |
| ADR-003 | PostgreSQL 而非 MySQL | 2026-08-09 | TL | ① JSONB 原生存储采集物和灵活字段;② 窗口函数(派单匹配算法)更强;③ 未来 GIS 扩展(PostGIS) |
| ADR-004 | 模块化单体先行,不直接微服务 | 2026-08-09 | TL + SPO | ① 团队 < 10 人,微服务复杂度 > 收益;② 业务规则未稳定,拆分边界可能错误 |
| ADR-005 | 香港 VPS + Cloudflare,不上 AWS/GCP | 2026-08-09 | TL + BO | ① 成本低一个数量级;② 香港 VPS 访问延迟更低;③ GCP/AWS 香港区域价格贵 |
| ADR-006 | 选 Expo managed workflow 而非纯 RN CLI | 2026-08-09 | TL | ① EAS Build 云端构建免本地 Xcode/Android Studio;② Expo Updates OTA 热更新 JS Bundle;③ Expo Notifications 统一 APNs+FCM;④ Expo SDK 统一依赖版本减少冲突 |
| ADR-007 | 客户端 CST 纳入阶段2 范围(原 Out of Scope) | 2026-08-09 | TL + SPO | ① 全干系方平台目标需要客户端参与;② RN 复用师傅端组件成本低;③ 客户端是口碑营销与推荐闭环的关键触点;④ 询价→下单→评价全流程数字化 |
| ADR-008 | 跳过阶段1 飞书对接,直接实施阶段2 | 2026-08-09 | TL + SPO | ① 飞书方案(阶段0)实际运行情况待观察;② 直接做原生 App 避免飞书 SDK 投入打水漂;③ 飞书对接文档 DIP1-P1 保留,未来按需启动;④ Code Agent 全栈聚焦阶段2 目标 |
修订记录¶
| 版本 | 日期 | 修订人 | 修订内容 |
|---|---|---|---|
| V1.0 | 2026-08-09 | DT | 初始化:DDD 四层分层 + 限界上下文映射 + 阶段 1/2 部署架构 + 7 条 NFR + 5 条 ADR |
| V2.0 | 2026-08-09 | DT | 前端架构升级为 React Native:C4 容器图前端层改为 3 端(opr-admin Web + wkr-app RN + cst-app RN);部署架构新增 App Store/Google Play + Expo EAS/OTA/Notifications;NFR 新增移动端离线/推送/启动性能/兼容性 4 项;技术风险新增 RN/审核/离线/推送 4 项;ADR-002 重写(RN 替代 Next.js PWA)+ 新增 ADR-006(Expo)/ADR-007(客户端纳入)/ADR-008(跳过飞书) |
本文件为 DIP1 架构设计(DOC-D00-D1-01 V2.0),前端采用 React Native + Expo(师傅端+客户端原生)+ Next.js(运营后台 Web)双引擎架构。