初始化文档

This commit is contained in:
QG
2026-03-24 16:13:32 +08:00
commit dc34a1536e
11 changed files with 1015 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
# **2.1 系统架构设计原则**
本章节规定了 CPS 研发团队在进行系统设计和架构演进时应遵循的核心指导原则。我们的目标是构建**高内聚、低耦合、易于演进且对开发者友好**的软件系统。
### **2.1.1 架构与框架边界原则**
**核心理念:对外统一规范,对内顺应框架(求同存异)。**
很多团队在追求“跨语言/跨框架统一”时,往往会造出过度抽象的中间层,导致“对抗框架”的现象。我们主张明确界定“宏观系统架构”与“微观框架实现”的边界:
* **系统间(宏观边界):遵循绝对统一的标准。**
* 微服务之间、前后端之间的通信,必须遵循团队统一的 API 规范(如 RESTful / gRPC、统一的鉴权机制、统一的链路追踪TraceId和日志埋点标准。
* 系统间的交互应当是语言无关、框架无关的。
* **系统内(微观落地):优先顺应所选框架的最佳实践。**
* **避免过度抽象:** 不要为了所谓的“框架无关性”去生搬硬套。例如,在 Spring Boot 中应当充分利用其依赖注入DI和注解生态@Transactional);在 Django 中应当拥抱其强大的 ORM 和信号机制。
* **不强求内部绝对一致:** 如果团队同时存在 Java 和 Python 栈,不要强求 Python 按照 Java 的厚重分层来写,也不要强求 Java 采用 Python 的极简脚本流。尊重并利用每种语言/框架的原生优势。
### **2.1.2 微服务与单体划分原则与边界**
**核心理念:单体优先,演进式拆分,警惕“分布式单体”。**
* **默认选择:模块化单体 (Modular Monolith)**
* 对于新业务或探索型项目,默认采用**模块化单体**架构。通过良好的包划分Package/Module和代码审查来保持内部逻辑的隔离而不是一上来就拆分物理微服务。
* **微服务拆分的触发条件(何时拆分?):**
* **隔离性要求:** 核心高可用业务(如交易链路)与边缘易错业务(如报表导出)需要物理隔离,防止边缘业务 OOM 拖垮核心逻辑。
* **扩展性要求Scale** 计算密集型模块(需要大量 CPU与 IO 密集型模块(需要大内存/高并发连接)需要采用不同的扩容策略。
* **独立部署与演进:** 某些模块变更极其频繁,而核心模块要求极度稳定,通过拆分实现独立发版。
* **康威定律(团队规模):** 单一代码库的协同开发人数过多,导致大量的代码冲突和发布阻塞。
* **拆分边界与底线:**
* **禁止跨库 JOIN** 微服务必须拥有独立的数据库(或独立的 Schema。如果两个服务频繁需要跨库 JOIN说明它们本该是一个服务。
* **避免网状依赖:** 服务间的调用链路应尽量保持单向或树状,严禁出现 A 调用 BB 调用 CC 又调用 A 的循环依赖。
### **2.1.3 分层架构与灵活决策原则**
**核心理念:没有银弹。架构必须匹配业务阶段与框架特性,绝不为了分层而分层。**
软件分层的唯一目的是**隔离变化,控制复杂度**(将业务复杂度与技术实现复杂度剥离开来)。在实际落地时,团队必须基于以下基本原则,**结合项目实际情况进行灵活决策并在架构决策记录ADR中予以说明**。
#### **1\. 分层设计的通用底线原则(必须遵守)**
* **关注点分离 (Separation of Concerns)** 无论采用何种架构,必须严格区分“协议处理(如 HTTP/RPC”、“业务逻辑计算”和“数据持久化”。**严禁在 Controller/View 层直接拼接 SQL也严禁在数据访问层包含核心业务判断。**
* **单向依赖流 (Unidirectional Dependency)** 上层可以依赖下层(或外层依赖内层),**绝对禁止**下层反向依赖上层(例如:数据库持久化类绝不能引入 API 层的 request 对象或状态码)。
* **演进式设计 (Evolutionary Design)** 架构是长出来的,不是一开始就设计完美的。允许系统从简单的 CRUD 逐渐重构为复杂的领域驱动模型,前提是模块间的边界清晰。
#### **2\. 因地制宜的模式选择建议(灵活应用)**
以下模式是我们的“架构工具箱”,严禁教条主义,应根据业务场景的实际痛点组合或选择使用:
* **场景 A敏捷交付与数据驱动型业务后台管理、报表、内容发布**
* **决策建议:拥抱框架原生的 MVC / MTV 模式,追求效率。**
* 如果使用 Spring Boot可以采用经典的 Controller \-\> Service \-\> Mapper。Service 作为事务边界,处理所有逻辑。
* 如果使用 Django / Rails应当顺应框架特色采用\*\*“胖模型、瘦视图 (Fat Model, Skinny View)”\*\*。利用框架内置的 ORM、信号量和 Serializer 快速打通 CRUD不要强行造一个虚伪的 Service 层。
* **场景 B核心交易与复杂规则型业务订单流转、促销计价、资产核心**
* **决策建议:采用 领域驱动设计 (DDD) 或 干净架构/六边形架构,保护业务资产。**
* 将复杂的业务规则收拢到独立于任何框架的**领域层 (Domain Layer)** 中(纯粹的 POJO/POCO
* 基础设施如数据库、Redis、MQ通过**依赖倒置 (DIP)** 接入。即使未来从 MySQL 换到 MongoDB或者从 Spring 换到其他框架,核心业务规则代码一行都不需要改。
* **场景 C多端展现或前端聚合诉求强烈的业务同时支持 App、小程序、复杂 Web 端)**
* **决策建议:引入 BFF (Backend for Frontend) 层。**
* 不要让底层的核心微服务为了适配某个特定的 UI 而妥协返回臃肿的数据。
* 在前端与核心服务之间建立 BFF 层专门负责接口聚合、字段裁剪、格式化。BFF 归属前端/客户端团队主导,底层服务归属后端团队主导。
* **场景 D读写模型严重不平衡存在性能瓶颈秒杀扣减与复杂商品详情查询**
* **决策建议:局部或全局引入 CQRS命令与查询职责分离。**
* 写操作走复杂的领域模型,保证数据一致性(写入主库)。
* 读操作绕过所有复杂的业务对象,直接通过原生 SQL 或缓存Redis/ES构建扁平的 DTO 输出给前端,实现极致的性能。
### **2.1.4 依赖与解耦原则**
**核心理念:降低变更成本,控制爆炸半径。**
* **依赖倒置原则 (DIP \- Dependency Inversion Principle)**
* 高层模块不应该依赖低层模块,两者都应该依赖其抽象(接口)。
* *实践:* 业务逻辑代码不应直接实例化具体的数据库仓储类或第三方 API 客户端而是通过构造器注入Constructor Injection接口方便后续的替换和单元测试Mock
* **事件驱动与异步解耦:**
* **区分核心流与旁路流:** 主业务流程(如“用户下单”)应当是同步的;而非核心流程(如“下单后发送短信通知”、“增加积分”)应当通过**事件总线 (Event Bus)** 或 **消息队列 (MQ)** 异步解耦。
* *底线:* 旁路流的失败(如短信网关宕机)绝对不能导致主业务流程的回滚或失败。
* **防腐层设计 (ACL \- Anti-Corruption Layer)**
* 在对接老旧的遗留系统或不可控的第三方外部 API如支付网关、SaaS 接口必须在系统边界建立防腐层Adapter/Facade
* *实践:* 将外部混乱的数据模型在防腐层转换为系统内部干净的标准模型,防止外部概念“污染”我们的核心业务代码。外部接口升级时,只需修改防腐层即可。

View File

@@ -0,0 +1,155 @@
# **2.2 API 接口设计规范**
API 是前后端、微服务之间沟通的**核心契约**。优秀的 API 设计不仅能大幅降低沟通成本,还能提升系统的稳定性和可维护性。一旦 API 契约对外发布,就必须保持向前兼容。
### **2.2.1 协议选型与设计原则**
根据不同的业务场景,我们支持以下三种主要的接口协议,严禁在不恰当的场景滥用协议:
#### **1\. RESTful API (默认首选)**
适用于绝大多数 Web 端、App 端的外部接口以及常规业务交互。
* **面向资源:** URL 必须全部使用**名词**的复数形式,严禁在 URL 中包含动词(如 /get-users 是错误示范,应为 GET /users。名词推荐使用短横线分隔Kebab-case如 /user-profiles
* **HTTP 动词语义化:**
* GET查询资源幂等绝对不能产生副作用如修改数据
* POST创建新资源非幂等。
* PUT全量更新资源幂等。
* PATCH局部更新资源。
* DELETE删除资源。
* **版本控制:** API 必须具备版本号,推荐放在 URL 路径中(如 /api/v1/users以便于后续重大重构时的平滑迁移。
* **务实原则:** 追求“实用级” RESTLevel 2不强求满足极致的 HATEOASLevel 3返回一堆超链接避免过度设计增加前端解析负担。
#### **2\. gRPC (内部微服务首选)**
适用于**后端微服务之间**的高频、内部通信。
* **优势:** 基于 HTTP/2 和 Protobuf强类型约束序列化体积小性能远超 HTTP+JSON。
* **规约:** 严禁将 gRPC 服务直接暴露给公网 Web/App 端(除非有特定的 API Gateway 或 gRPC-Web 转换层)。对外一律暴露 RESTful 或 GraphQL。
#### **3\. GraphQL (复杂聚合场景可选)**
适用于 BFF聚合层或前端对数据灵活性要求极高、且存在严重“过度获取(Over-fetching)”或“获取不足(Under-fetching)”的复杂场景。
* **规约:** 不要在简单的 CRUD 业务中引入 GraphQL它会极大地增加后端的 N+1 查询优化难度和权限控制复杂度。必须在架构决策ADR中经过严格评审后方可使用。
### **2.2.2 统一的请求头 (Headers) 与鉴权机制**
为了实现全链路追踪、多语言支持和统一的安全管控,所有 HTTP 请求必须遵循以下 Headers 规范:
#### **1\. 标准请求头列表**
* Authorization: 鉴权 Token必须。格式为 Bearer \<Token\>。
* X-Request-Id (或 Trace-Id): 全链路追踪 ID。由网关或客户端生成后端原样透传并在日志中打印这是排查线上客诉的唯一生命线。
* X-Client-Type: 客户端类型(如 iOS, Android, Web, MiniProgram用于后端进行渠道统计或特定逻辑下发。
* X-Client-Version: 客户端版本号(如 1.0.5),用于后端做兼容性控制。
* Accept-Language: 多语言标识(如 zh-CN, en-US用于国际化错误提示。
#### **2\. 鉴权机制 (JWT)**
* 系统默认采用 **JWT (JSON Web Token)** 进行无状态鉴权。
* **安全性底线:**
* 严禁在 JWT 的 payload 中携带用户密码、敏感业务数据等隐私信息JWT 仅防篡改,不防窃听,前端可直接 Decode
* Token 必须设置合理的过期时间Access Token 建议 2 小时内Refresh Token 建议 7 天)。
* 登出Logout或踢人操作必须依赖 Redis 黑名单机制Token 屏蔽),不能仅靠客户端删除 Token。
### **2.2.3 标准响应数据格式 (Response 包装类)**
*注:考虑到不同技术栈和框架的差异(如 Django DRF 原生倾向于直接返回资源 JSON 而不包外层,或者 GraphQL 有其自有的结构),本章节定义的 Response 包装格式为**推荐规范**。建议团队根据实际业务需求与框架特性灵活决策。一旦选定,同一项目/子系统内必须保持格式一致,避免前端解析困难。*
#### **1\. 推荐标准外层结构(如需包装)**
如果业务决定采用统一包装格式,建议结构如下:
{
"code": 20000, // 业务状态码(非 HTTP 状态码)
"message": "success", // 面向开发者的提示信息 / 面向用户的国际化错误提示
"data": { ... }, // 实际的业务数据(对象或数组)
"traceId": "9b1deb4d..." // 必返当前请求的追踪ID方便前端直接带此ID报障
}
#### **2\. 分页数据标准结构与实现方案**
分页的实现方式多种多样,不同的框架往往有其自带的最佳实践(如 Spring Data 的 Page 接口Django DRF 的 PageNumberPagination 或 CursorPagination。在此仅作**推荐与指导性建议**。
团队在设计分页接口时应根据具体的业务端Admin Web 或 App 瀑布流)选择合适的方法:
**方案 A传统页码分页 (Offset/Limit)**
* **适用场景:** 后台管理系统 (Admin)、PC 端数据表格(允许用户指定跳到第 N 页)。
* **推荐返回结构示例:**
{
"data": {
"list": \[ {...}, {...} \], // 当前页的数据列表
"total": 150, // 总条数 (注意:数据量极大时 count() 会有性能瓶颈)
"page": 1, // 当前页码
"pageSize": 20, // 每页大小
"hasNext": true // 是否还有下一页
}
}
**方案 B游标分页 (Cursor-based / Keyset Pagination)**
* **适用场景:** 移动端 App 的“无限滚动”瀑布流、社交动态流。能有效解决数据实时增删导致的“数据重复出现”或“数据漏滑”问题,且性能极佳。
* **推荐返回结构示例:**
{
"data": {
"list": \[ {...}, {...} \], // 当前页的数据列表
"next\_cursor": "eyJpZCI6IDE1MiwgImNyZWF0ZV90aW1lIjogIjIwMjM..." // 用于请求下一页的游标 (通常是 Base64 编码的最后一条数据标识)
}
}
*规约提醒:不强制所有分页结构完全统一,但后端在输出分页数据时,应顺应其所用框架的原生分页器能力,并在 Swagger/API 文档中清晰标明采用的分页模式。*
#### **3\. Null 值与空值规约 (极度容易引发 NPE 和前端白屏)**
不论外层是否包装,实际数据体中的空值处理应遵循:
* **集合/数组:** 如果列表为空,必须返回空数组 \[\]**严禁返回 null**。
* **对象:** 如果对象为空,可以返回 {} 或 null需与前端约定好
* **字符串:** 如果字符串为空,必须返回 ""**严禁返回字符串 "null"**。
* **布尔值:** 严禁使用 0/1 替代 true/falseJSON 必须保持类型严谨。
### **2.2.4 全局错误码 (Error Codes) 分配与定义字典**
*注:对于敏捷开发或复杂度一般的单体项目,维护庞大的五位数业务错误码字典往往会带来过高的管理成本。因此,本节为**推荐规范**。团队应根据项目规模灵活决策:轻量级项目完全可以仅依靠“标准 HTTP 状态码 \+ 清晰明确的 message”来处理异常如果业务链路较长需要精细化区分错误类型则推荐引入以下错误码规范。*
我们需要明确区分 **HTTP 协议状态码****业务错误码**
#### **1\. HTTP 状态码规约(代表网络与网关层面的状态)**
后端必须正确使用 HTTP 状态码,严禁将所有请求都返回 200 OK即使系统内部发生了致命异常。
* 200 OK: 请求成功,业务逻辑被执行。
* 400 Bad Request: 参数校验失败(如缺少必填字段,格式错误)。
* 401 Unauthorized: 鉴权失败Token 缺失、无效或过期)。前端收到后应统一跳转登录页。
* 403 Forbidden: 权限不足Token 有效,但当前角色无权操作)。
* 404 Not Found: 路由不存在(资源未找到)。
* 429 Too Many Requests: 触发限流,请稍后重试。
* 500 Internal Server Error: 后端发生了未捕获的严重异常(代码 Bug 或数据库宕机)。
#### **2\. 业务错误码规约 (Response Body 中的 code 字段,若启用包装类)**
若团队决定启用全局错误码,推荐采用 **5 位数字****纯字符串枚举**(如 USER\_NOT\_FOUND。以 5 位数字为例A-BB-CC。
* **A (1位):系统级分类**
* 2成功。
* 4客户端调用错误业务约束拦截
* 5服务端内部错误业务预期内的异常
* **BB (2位):模块或子系统编号**
* 00全局公共错误。
* 01用户中心。
* 02订单中心。
* **CC (2位):具体错误序号**
**全局核心字典示例:**
* 20000: 业务执行成功。
* 40000: 客户端错误通配。
* 40102: 账户已被冻结。
* 40202: 账户余额不足。
* 50000: 服务器内部错误通配。
*规约:如果决定使用错误码,则禁止在代码中硬编码(如 return new Response(40102, "被冻结")),必须统一定义在 ErrorCodeEnum 枚举类中集中管理。*

View File

@@ -0,0 +1,88 @@
# **2.3 数据库与存储设计规范**
数据库与缓存是系统最核心的底座。代码可以随时重构,但糟糕的数据结构一旦上线并积累了大量数据,重构成本将是毁灭性的。本规范旨在确保数据结构的**可读性、扩展性及高并发下的性能稳定**。
*注:本章节主要以关系型数据库(如 MySQL/PostgreSQL及 Redis 为基准,其他 NoSQL 存储可参照核心思想灵活应用。*
### **2.3.1 表结构与字段设计规范**
#### **0\. 框架原生范式顺应原则 (极其重要)**
许多现代 Web 框架及其绑定的 ORM如 Django ORM, Ruby on Rails ActiveRecord, Spring Data JPA 等)拥有自己强烈推崇的数据库设计范式(例如:特定的表名生成规则、默认的审计字段命名 created\_at、隐含的关联表主外键逻辑
* **规约:** 在此重申“避免对抗框架”的原则。如果项目高度依赖此类重型全栈框架,**请优先遵守框架的原生数据库约定**,以最大化利用框架的内置生态和开发效率;但对于使用 MyBatis, GORM, SQLAlchemy 等轻量级或自定义程度较高的 ORM 项目,则**必须严格遵守**下述通用的结构与命名规范。
#### **1\. 命名规范(通用红线)**
* **表名与字段名:** 必须全部使用**小写字母**,单词之间使用下划线 \_ 分隔Snake Case。严禁使用驼峰命名或拼音。
* **表名要求:** 必须是名词建议增加业务模块前缀。例如sys\_user系统模块-用户、ord\_order订单模块-订单)。
* **禁用保留字:** 严禁使用数据库保留字(如 desc, order, match, key 等)作为表名或字段名。
#### **2\. 字段设计与类型选择**
* **主键设计:** \* 默认推荐使用 BIGINT 配合**雪花算法 (Snowflake ID)** 或单调递增的分布式 ID 作为主键,有利于分库分表。
* 若为中小型单体项目,允许使用数据库自增 AUTO\_INCREMENT。
* **强烈不建议**使用无序的 UUID 字符串作为主键(会导致 B+ 树频繁页分裂,严重影响写入性能)。
* **金额类型:** 涉及财务、金额的字段,**必须**使用 DECIMAL如 DECIMAL(10,2))或将元转为分存储为 BIGINT。**绝对禁止**使用 FLOAT 或 DOUBLE会产生精度丢失
* **布尔与枚举值:** 建议使用 TINYINT(1) 或 TINYINT(4)。字段命名建议以 is\_ 或 has\_ 开头(如 is\_deletedhas\_attachments并在注释中明确写清枚举含义如 0:否, 1:是)。
* **字符串类型:** 定长使用 CHAR变长使用 VARCHAR。尽量避免使用 TEXT 或 BLOB如必须使用建议将此类大字段**垂直拆分**到附属表中,以免拖慢主表的查询效率。
* **字符集:** 默认强制使用 utf8mb4以完美支持 Emoji 表情和生僻字;排序规则推荐使用 utf8mb4\_general\_ci。
#### **3\. 必备的审计字段**
所有核心业务表,强烈建议包含以下四个基础审计字段(*注:若所用框架有内置约定的字段名如 created\_at / updated\_at则以框架约定为准*
* id: 主键。
* create\_time: 创建时间(推荐 DATETIME 或 TIMESTAMP默认值 CURRENT\_TIMESTAMP
* update\_time: 更新时间(默认值 CURRENT\_TIMESTAMP ON UPDATE CURRENT\_TIMESTAMP
* is\_deleted: 逻辑删除标记0正常1删除。*注意使用逻辑删除时需仔细评估与唯一索引Unique Key的冲突问题。*
### **2.3.2 索引建立原则与慢查询规避**
慢查询是导致数据库 CPU 飙升、系统雪崩的头号元凶。开发人员在编写 SQL 时必须脑中有 B+ 树的结构。
#### **1\. 索引建立原则 \[推荐规范\]**
* **控制索引数量:** 单表索引数量建议不超过 5 个。索引不是越多越好,过多的索引会严重拖慢 INSERT/UPDATE 的性能。
* **高区分度优先:** 尽量在区分度高的列上建立索引(如 user\_idorder\_no。**不要**在性别、状态这类只有少数几个值的列上单独建立索引。
* **拥抱联合索引(最左前缀法则):** \* 频繁一起查询的多个字段,应建立联合索引,而非多个单列索引。
* 联合索引的设计必须遵循**最左前缀法则**。例如索引为 (a, b, c),那么 WHERE a=?、WHERE a=? AND b=? 会走索引,但 WHERE b=? AND c=? 绝对不会走该联合索引。
* **覆盖索引优先:** 尽量让查询的列直接包含在联合索引中,避免“回表”操作,极大提升查询效率。
#### **2\. 慢查询规避红线(必须遵守)**
* **禁止 SELECT \*** 只查询业务需要的字段。SELECT \* 会导致无法使用覆盖索引,并增加网络传输负担。
* **禁止左模糊查询:** LIKE '%keyword' 或 LIKE '%keyword%' 会导致索引全表扫描。如需全文检索,请引入 ElasticSearch。右模糊 LIKE 'keyword%' 是允许的(可走索引范围查询)。
* **禁止在索引列上做计算或函数操作:** 例如 WHERE YEAR(create\_time) \= 2023 会导致索引失效。应改写为 WHERE create\_time \>= '2023-01-01' AND create\_time \< '2024-01-01'。
* **隐式类型转换会导致索引失效:** 如果字段类型是 VARCHAR但查询时写成了 WHERE phone \= 13800138000数字类型MySQL 会隐式转换导致全表扫描。必须加引号WHERE phone \= '13800138000'。
* **警惕深分页问题:** LIMIT 100000, 20 会让数据库扫描 100020 行数据然后丢弃前十万行。
* *解决建议:* 限制最大允许跳页数,或者结合 2.2 章节推荐的“游标分页Cursor”机制如 WHERE id \> last\_max\_id LIMIT 20
### **2.3.3 Redis 缓存设计规范**
Redis 虽然快,但不当的使用会导致内存泄漏和严重的并发故障。
#### **1\. 键值 (Key) 命名规范**
为了防止不同业务线的 Key 产生冲突,且便于在可视化工具(如 RDM中分类查看Key 必须遵循**层级命名法则**
* **格式:** 项目名:模块名:实体名:唯一标识
* **示例:** \* 用户信息缓存cps:user:info:10086
* 订单防重放锁cps:order:lock:REQ\_99823
* **规范:** 全部小写或大写(团队统一即可,推荐小写),严禁包含空格、换行或特殊字符,长度尽量控制在 64 字节以内以节省内存。
#### **2\. Value 设计规范**
* **控制大 KeyBigKey** 单个 String 类型的 Value 不应超过 10KBHash、List、Set 元素个数不应超过 5000 个。大 Key 在删除或传输时会阻塞 Redis 单线程模型。
* **选择合适的数据结构:** \* 简单的全量缓存用 String (配合 JSON 序列化)。
* 如果只需要频繁更新或读取对象的某几个字段,应使用 Hash避免频繁的完整 JSON 序列化和反序列化开销。
#### **3\. 缓存生命周期与高可用防范(极其重要)**
* **强制设置过期时间 (TTL)** **绝不允许**向 Redis 写入永久不过期的业务缓存(配置类或基准字典除外)。否则 Redis 内存迟早被撑爆。
* **防范缓存雪崩 (Cache Avalanche)** \* **问题:** 大量缓存在同一时刻集体过期,导致巨量请求瞬间全部打向数据库,击穿 DB。
* **对策:** 在设置 TTL 时,必须**加上一个随机的抖动时间**(例如,基础过期时间 2 小时 \+ 随机 0\~300 秒)。
* **防范缓存穿透 (Cache Penetration)** \* **问题:** 黑客恶意查询一个数据库中绝对不存在的值(如 id=-1导致缓存永远不命中所有请求全打到 DB。
* **对策:** 即使数据库返回 Null也要把这个 Null 值缓存进 Redis设置一个较短的 TTL如 5 分钟);或者引入布隆过滤器 (Bloom Filter) 提前拦截。
* **防范缓存击穿 (Cache Breakdown)** \* **问题:** 某一个“极其热点”的 Key 突然过期的一瞬间,上万个并发请求发现缓存未命中,同时去查询 DB 并尝试重写缓存,导致 DB 崩溃。
* **对策:** 使用分布式锁(如 Redisson控制只让一个线程去查询 DB 并重建缓存,其他线程等待;或针对极度热点的数据设置“逻辑过期”而非物理过期。

View File

@@ -0,0 +1,128 @@
# **Python 编码与开发规范**
Python 是一门极其灵活的动态语言,但“灵活”在大型团队协作中往往意味着“灾难”。本规范以 **PEP 8** 为基石,全面拥抱 **现代 Python (3.9+)** 的类型注解系统,并强制依赖自动化工具链来消除代码风格争议。
## **命名约定与基础风格**
**核心理念:代码是写给人看的,顺便交给机器执行。**
* **变量与函数(变量/方法):** 强制使用 snake\_case下划线命名
\# 推荐
user\_account\_list \= \[\]
def fetch\_user\_data():
...
* **类名Classes** 强制使用 PascalCase大驼峰命名
class PaymentService:
...
class UserNotFoundError(Exception):
...
* **常量Constants** 强制使用 SCREAMING\_SNAKE\_CASE全大写加下划线定义在模块顶部。
* **私有与受保护属性:** \* 单下划线 \_private\_var表示内部使用软性约束仅作提示
* 双下划线 \_\_strict\_private触发名称改写Name Mangling除非极特殊情况如防止子类重写**日常业务开发中不推荐使用**,以免增加调试难度。
## **现代工程化工具链 (强制执行)**
**核心理念:能用工具自动修复的风格问题,绝不在 Code Review 中浪费时间口舌。**
项目中必须配置并使用以下工具链(推荐通过 pre-commit 钩子强制拦截不合规代码):
1. **项目与依赖管理uv (核心基石)**
* 摒弃传统的 pip、virtualenv 或臃肿的 Poetry全面拥抱由 Astral 团队用 Rust 编写的 uv。
* 它统一了虚拟环境管理、依赖解析和项目运行。使用 uv init 初始化项目uv add 添加依赖uv run 执行脚本,极大提升开发构建体验。
2. **综合 Linter 与格式化Ruff**
* 同样是 Astral 团队出品的极速工具,完美兼容并替代了 Flake8、isort 和 BlackRuff 目前已内置极速 formatter。团队统一在 pyproject.toml 中配置 Ruff 规则。
3. **静态类型检查Mypy**
* 开启严格模式。核心业务模块必须通过 Mypy 检查,不允许出现 Any 泛滥的情况。
## **类型注解 (Type Hinting) 规范**
**核心理念:动态一时爽,重构火葬场。所有业务接口、函数签名必须带有完整的类型注解。**
* **基础类型约束:** 充分利用 Python 3.9+ 的内置泛型(如 list, dict不再需要 from typing import List, Dict和 Python 3.10+ 的联合类型操作符 |。
\# 推荐写法 (Python 3.10+)
def process\_user\_data(user\_id: int | str, tags: list\[str\]) \-\> dict\[str, Any\]:
pass
* **可选类型:** 当参数或返回值可能为空时,必须使用 Optional\[T\] 或 T | None。
def find\_user(email: str) \-\> User | None:
pass
* **避免 Any 滥用:** 凡是写 Any 的地方,意味着放弃了类型检查。对于复杂的数据结构,应当优先定义 TypedDict 或数据模型类。
## **核心编码与设计范式**
### **1\. 数据模型设计 (Pydantic 与 Dataclass 的明确边界)**
**警惕过度设计:** 绝对不要为了用而用,将整个系统“全盘 Pydantic 化”。Pydantic 实例化时的类型强转和校验是有显著性能开销的,强行铺满内部逻辑会带来极大的工作量和性能负担。
* **必须使用 Pydantic 的场景(防腐层/系统边界):**
* 外部 API 的请求体与响应体验证(如 FastAPI 集成)。
* 外部配置文件的解析加载。
* 从不可靠来源(如第三方消息队列)消费的复杂 JSON 结构。
from pydantic import BaseModel, EmailStr
class UserCreateRequest(BaseModel):
name: str
email: EmailStr \# 外部输入,必须靠 Pydantic 严防死守
age: int | None \= None
* **必须使用 @dataclass 或 TypedDict 的场景(系统内部):**
* 内部 Service 函数之间的参数流转。
* 从数据库 ORM 查询出来、组装准备传给下一层的纯内部 DTO。
* 这些数据已经是“绝对可信”的,使用标准库的 @dataclass 可以实现近乎 O(1) 的轻量实例化,绝不增加无谓的校验负担。
### **2\. 函数参数设计 (关键字传参)**
* 当函数参数超过 3 个,或者包含容易混淆的布尔值时,**强制使用 \* 迫使调用方使用关键字传参**。
\# 规范示例调用此函数时age 和 is\_active 必须带上参数名
def create\_user(name: str, email: str, \*, age: int, is\_active: bool \= True) \-\> User:
pass
\# 调用端:
create\_user("John", "john@test.com", age=25, is\_active=False) \# 必须写明 age= 和 is\_active=
### **3\. 异常处理规约**
* **禁止吞噬异常:** 绝不允许出现 except Exception: pass 这种掩耳盗铃的代码。
* **自定义异常层次:** 模块应当抛出特定业务领域的异常(如继承自 ValueError 的 OrderNotFoundError而不是直接抛出裸露的 Exception。
### **4\. 资源释放与安全**
* **强制使用上下文管理器:** 文件读写、网络会话(如 requests.Session、数据库连接必须使用 with 语句包裹,确保资源(哪怕在异常抛出时)能被正确关闭。
## **性能优化与防坑指南**
Python 性能上限不高,但不良写法会导致下限极低:
* **查找操作慎用 List拥抱 Set/Dict**
* if item in my\_list: 的时间复杂度是 O(n)。对于包含上百个元素的成员判断,**必须**将集合初始化为 Set 或 Dict以达到 O(1) 的查找性能。
* **大数据流拥抱生成器 (Generators)**
* 当处理百万级行数的 CSV 或大量数据库记录时,严禁将数据一次性加载到内存的 List 中。**必须使用 yield**。
def process\_large\_file(filename: str):
with open(filename, 'r') as file:
for line in file:
yield process\_line(line) \# 内存中始终只有一行数据
* **海量实例的内存优化:**
* 当需要实例化上百万个轻量级对象时,必须在类中声明 \_\_slots\_\_ \= \['attr1', 'attr2'\],这能节约约 40% 的内存消耗(阻止 Python 为每个实例创建 \_\_dict\_\_
## **单元测试规范**
* **测试框架选型:** 统一使用 pytest废弃 Python 自带的厚重 unittest 类式写法。并通过 uv run pytest 执行。
* **测试用例结构:** 遵循 Arrange \- Act \- Assert (准备-执行-断言) 三段式结构。
* **Mock 的边界:** 严禁在单元测试中发起真实的 HTTP 网络请求或连接真实的 MySQL 数据库。必须使用 unittest.mock.patch 或 pytest-mock 对外部 IO 依赖进行拦截和模拟。
def test\_get\_user\_info(mocker):
\# Arrange: 拦截外部数据库调用
mocker.patch('myproject.database.fetch', return\_value={"id": 1, "name": "Test"})
\# Act
user \= get\_user\_info(1)
\# Assert
assert user.name \== "Test"

View File

@@ -0,0 +1,83 @@
# **框架开发实施规范 (Django/DRF)**
本规范专为基于 Django 与 Django REST Framework (DRF) 的后端项目制定。
**执行策略**:本规范采用“限制优先”原则。默认不提供多实现方案;未在本文明确允许的绕过做法,一律视为不合规。
## **工程配置与生态集成 (Settings & Ecosystem)**
系统底座的配置与外部集成应当保持极度的干净、安全,并充分借力开源社区。
### **环境解耦与凭证安全**
* **配置解耦**:严禁将所有配置揉在单个 settings.py 中。必须使用多环境配置拆分(推荐 django-split-settings严格划分通用配置、组件配置与环境独立配置。
* **凭证安全红线**:密钥(如 SECRET\_KEY, DB\_PASSWORD, API Keys必须从环境变量或配置中心动态读取**严禁**在代码库中硬编码。
### **生态复用与外部集成**
* **严禁重复造轮子**Django 和 DRF 拥有极其成熟的第三方开源生态。对于标准化的通用需求,**必须**优先集成成熟的第三方库。例如使用 djangorestframework-simplejwt 处理 Token使用 django-filter 处理复杂查询过滤。
* **代理层无状态**:若系统作为中间层代理外部 API如大模型网关代理视图禁止落库复杂的业务状态。
* **认证逻辑收口**:对接外部系统的身份认证逻辑(如 LDAP、API Key必须严格收拢在 DRF 的 Authentication 类或 Django 的中间件中,**绝对禁止**在业务 View 中直接读取 Request Headers 做条件分流。
## **数据层规范 (Models & Serializers)**
数据层负责实体定义与输入输出的格式化。清晰、防抖的数据层是系统性能的保障。
### **模型定义与约束**
* **显式定义主键与审计**:不推荐使用庞大的公共抽象基类隐式继承。业务 Model 应当显式定义主键和必备的审计字段(如 created\_at, updated\_at避免基类变更带来全局副作用。
* **字段防空红线**字符型字段CharField, TextField禁止设置 null=True必须设为 default=''。
* **外键明确声明**:使用 ForeignKey 关联时必须显式指定清晰的 related\_name。
* **物理删除优先**默认优先使用物理删除。仅当业务明确要求审计追溯时引入逻辑删除is\_deleted。若启用逻辑删除必须配合使用带条件的唯一约束以防止重复插入冲突。
### **序列化层红线 (Serializers)**
* **禁用全量暴露****严禁**在 Serializer 中使用 fields \= '\_\_all\_\_'。必须逐个显式列出对外暴露的字段,防止数据库新增敏感字段后发生意外泄露。
* **严防 N+1 查询**
* 列表接口**严禁**使用包含深层嵌套关系的复杂 Serializer必须为其单独定义轻量级的结构。
* 若 Serializer 输出了外键字段View 层的 QuerySet **必须**配合使用 select\_related 或 prefetch\_related。
* **聚合计算隔离****严禁**在 SerializerMethodField 中执行 SQL 聚合查询(如 .count(), .sum())。必须在 View 层使用 annotate() 提前计算完毕Serializer 仅负责读取内存数据。
## **业务调度层规范 (Views, Services & URLs)**
**核心原则Thin View, Fat Service (轻视图,重服务)。**
View 层仅作为路由调度、参数校验和权限决策的枢纽,绝不可堆砌核心业务逻辑。
### **视图层职能划分**
* **基类选型边界**:标准 CRUD 强制使用 ModelViewSet定制化业务场景强制选用 GenericViewSet 配合 Mixins 按需组合APIView 仅限非标准资源形态(如透明代理)使用。
* **生命周期职责**
* get\_queryset()**必须**在此处完成数据预加载与基于用户身份的数据范围隔离。
* get\_serializer\_class()**必须**实现读写分离(如基于 action 返回不同的 Serializer
* get\_permissions()**必须**基于当前 action 动态分配权限类。
### **服务层下沉模式 (Service)**
* **防腐红线****严禁**重写 create(), update() 等主调度方法来堆砌业务逻辑(这会破坏 DRF 的标准执行流)。
* **标准移交**:复杂的写操作逻辑,应当在 perform\_create() 或 perform\_update() 钩子中,提取并调用独立的 **Service 函数/类** 进行处理。
### **路由与异常处理**
* **命名空间绝对隔离**:全局强制采用 NamespaceVersioning 机制。根路由必须携带命名空间,且内部的 urls.py 必须存在 app\_name。反向解析必须带版本号前缀。
* **异常抛出代替返回**:遇到业务校验错误,**严禁**在代码中手动 return Response({"error": "xxx"})。**必须**直接抛出异常(如 raise ValidationError交由全局的 exception\_handler 统一格式化。
* **统一响应壳**:严禁在 View 中手动构建类似 {"code": 0, "data": ...} 的字典,必须交由自定义的全局 Renderer 统一包装。
## **权限管控与数据隔离 (Permissions)**
系统中的权限管控是防范越权访问、越权篡改的核心防线。必须绝对交由框架层(鉴权基类、过滤器)统一拦截。
### **功能权限 (操作级拦截)**
* **禁用硬编码判断****绝对禁止**在业务 Service 或 View 方法内部使用硬编码的 if 语句拦截权限例如if request.user.role \!= 'admin': raise PermissionDenied
* **规范抽象**:功能权限必须抽象并继承 DRF 的 BasePermission统一在 View 的 permission\_classes 属性中进行声明与挂载。
### **对象级权限 (防越权篡改)**
* **必须重写对象判定**:对于针对单一资源的操作(如修改、删除),如果仅允许资源的拥有者或管理员操作,**必须**在权限类中实现 has\_object\_permission。
* **防跳过红线**DRF 仅在调用 self.get\_object() 时才会触发对象级鉴权。在自定义 Action 中操作单个资源时,**必须**首先显式调用该方法获取对象,严禁直接使用 Model.objects.get(pk=pk) 从而绕过权限检查!
### **数据范围隔离 (防越权查看)**
* **后端绝对阻断**:绝对禁止依靠前端“不显示该列表”或“隐藏入口”来做数据隔离防护。
* **规范落实**:不同租户(组织、用户)的数据隔离,必须通过重写 View 的 get\_queryset() 进行彻底的 QuerySet 过滤来实现。

View File

@@ -0,0 +1,77 @@
# **4.1 自动化测试规范**
自动化测试是保障系统重构信心、防止线上代码回归Regression的唯一有效手段。本规范旨在指导研发团队编写**高优、稳定、可维护**的测试代码,坚决抵制“为了追求覆盖率而写无意义断言”的形式主义。
### **4.1.1 测试分层策略 (Testing Pyramid)**
团队的自动化测试必须遵循经典的“测试金字塔”原则,明确不同测试的边界与职责:
* **单元测试 (Unit Tests \- 占比 70%)**:运行极快,完全隔离。仅测试单一函数/方法的内部逻辑。**绝对禁止**任何真实的网络 I/O 和数据库连接。
* **集成测试 (Integration Tests \- 占比 20%)**:验证多个内部组件能否协同工作。**允许**连接真实的测试数据库或本地 Redis但**禁止**调用外部第三方系统(如真实的支付网关或微信 API
* **接口/端到端自动化测试 (API/E2E Tests \- 占比 10%)**:从用户视角出发,把整个系统当做黑盒,通过 HTTP 协议发起真实请求,验证最终的 Response 和副作用。
### **4.1.2 单元测试编写规范与覆盖率要求**
**核心原则Arrange \- Act \- Assert (3A 模式)**
* **测试结构**:每一个测试用例必须清晰地分为三部分:
1. Arrange (准备):初始化测试数据和 Mock 对象。
2. Act (执行):调用被测函数。
3. Assert (断言):验证返回值或内部方法调用的状态。
* **命名规范**测试函数名必须能清晰表达测试意图。格式推荐test\_\<被测方法\>\_\<测试场景\>\_\<预期结果\>。
* *✅ 正确示例test\_calculate\_discount\_with\_vip\_user\_returns\_half\_price()*
* **覆盖率要求 (不搞一刀切)**
* **核心业务领域层 (Domain/Service)**:核心算法、金额计算、状态流转的单元测试行覆盖率**必须 \>= 80%**。
* **边缘或纯框架粘合层 (Controller/View)**:不做硬性单元测试覆盖率要求,应交由“接口自动化测试”来覆盖。
* *红线:严禁为了凑覆盖率去测试框架自带的 Getter/Setter 或基础的 ORM 查询。*
### **4.1.3 Mock 数据与测试对象构造原则**
脆弱的测试往往来源于糟糕的测试数据构造方式。
* **坚决弃用手动组装大字典**:严禁在测试代码中写几百行的字典或 JSON 来伪造数据库对象。这会导致测试代码极难维护。
* **引入工厂模式 (Factory)**:强制使用 factory\_boy (Python) 或类似工具(如 Java 的 DataFaker来生成测试对象实体。
\# ✅ 正确示范:使用 Factory 快速生成具有合法默认值的测试对象
user \= UserFactory(role='admin', is\_active=True)
order \= OrderFactory(user=user, amount=100)
* **公共数据复用 (Fixtures)**:跨测试用例复用的基础数据(如登录凭证、基础配置),必须统一定义在 conftest.py针对 Pytest 框架)中,通过依赖注入提供给测试用例。
* **Mock 的外部边界红线**
* **必须 Mock**:所有跨出当前服务进程的调用(如请求 AWS、阿里云、第三方大模型、其它微服务在单测和集成测试中**必须被拦截并 Mock**。
* **禁止滥用 Mock**:不要在集成测试中去 Mock 系统内部的私有方法。Mock 应该发生在系统边界处。
### **4.1.4 集成测试规范 (Integration Testing)**
集成测试的核心目的是验证系统组件与外部基础设施(特别是数据库)的交互是否正确。
* **数据库环境清理 (极其重要)**
* 集成测试必须连接到独立的测试数据库(如本地内存 DB或由 CI 动态拉起的 Docker DB
* **红线:严禁测试用例之间产生数据污染。** 每个测试用例执行完毕后,必须**触发事务回滚 (Transaction Rollback)** 或清空相关表。在 Django/pytest 体系中,强制使用 @pytest.mark.django\_db 确保测试在事务中运行。
* **验证副作用**:集成测试不仅要验证函数的 return 值更要验证数据库的真实副作用Side Effects
def test\_cancel\_order\_updates\_db\_status():
order \= OrderFactory(status='PENDING')
\# Act
cancel\_order\_service(order.id)
\# Assert必须重新从真实数据库查出数据验证更新是否落盘
order.refresh\_from\_db()
assert order.status \== 'CANCELLED'
### **4.1.5 接口自动化测试要求 (API Testing)**
接口自动化测试用于替代绝大部分的“手动 Postman 联调”,它是持续交付 (CI/CD) 的最后一道质量门禁。
* **黑盒视角**:测试代码不需要知道内部是怎么实现的。仅通过框架的 APIClient 或 HTTP 客户端(如 httpx, RestAssured发起请求。
* **全链路验证**:不要仅仅测试单一接口的连通性,必须测试**核心业务链路 (Happy Path)**。
* *示例场景:* 1\. 调用登录接口获取 Token \-\> 2\. 携带 Token 创建订单 \-\> 3\. 调用查询接口断言订单存在 \-\> 4\. 调用取消接口 \-\> 5\. 再次查询断言状态变更。
* **契约断言 (Contract Assertion)**
* 必须断言 HTTP 状态码(如 200, 201, 400, 403
* 必须断言外层统一响应结构code, message
* 必须断言核心业务数据字段的存在与类型,确保 API 向前兼容。
### **4.1.6 质量门禁与 CI/CD 强制执行**
* **本地提交前拦截**:推荐使用 Git pre-commit 钩子,在本地 Commit 前执行快速的单元测试。
* **CI 自动化阻断**:任何合并到主干分支(如 main, develop的 Pull Request/Merge Request必须触发 CI 流水线。
* 如果自动化测试失败(红灯),或者核心代码覆盖率跌破基准线,代码审查工具必须**硬性阻断**合并按钮,不允许任何特权绕过。

View File

@@ -0,0 +1,92 @@
# **4.2 代码审查 (Code Review) 规范**
代码审查Code Review, 简称 CR不仅仅是发现 Bug 的防线,更是**团队知识共享、架构共识对齐**的最重要途径。本规范旨在建立一套高效、客观、充满建设性的 CR 流程。
### **4.2.1 审查的触发时机与前置条件 (Prerequisites)**
为了不浪费审查者Reviewer的时间提交者Author在发起合并请求PR/MR**必须满足以下前置条件(即质量门禁)**,否则 Reviewer 有权直接打回:
1. **自动化门禁通过 (绿灯状态)**
* 代码必须通过所有的 Linter 格式化检查(如 Ruff, ESLint
* 必须通过所有的单元测试与核心自动化测试。**不要让人类去 Review 机器能检查出来的缩进和语法错误。**
2. **提交规模限制 (Small PR)**
* 一个 PR 的逻辑代码变更行数建议**控制在 400 行以内**。超过 1000 行的“巨型 PR”极难审查往往会流于形式"LGTM \- Looks Good To Me")。
* 如果是大型需求,必须拆分为多个独立的小 PR 提交。
3. **完成自我审查 (Self-Review)**
* 作者在指派 Reviewer 之前,必须先自己完整看一遍 Diff清理掉调试代码如 print(), console.log、注释掉的废弃代码。
4. **规范的 PR 描述**
* 必须清晰描述“修改了什么”、“为什么修改”、“如何测试”。
### **4.2.2 审查核心 Checklist (Review Dimensions)**
Reviewer 在审查时,应当自顶向下,先看架构,再看逻辑,最后看细节。严禁在没有看懂业务逻辑的情况下,只揪着变量命名不放。
#### **1\. 架构与设计 (Design & Architecture) \-\> *最高优先级***
* **分层边界**:是否出现了越界操作?(例如:在 Controller/View 层直接拼接了复杂的 SQL或者在 Serializer 中写了极重的业务流转)。
* **设计原则**:是否遵循了 DRY不重复造轮子原则是否有过度设计
* **向后兼容性**:修改现有的 API 或数据库字段,是否会引发线上老版本 App 的崩溃?
#### **2\. 业务功能正确性 (Functional Correctness)**
* **需求契合**:代码是否真正解决了 PR 描述中的问题?
* **边界条件**:空值、负数、极大值、并发场景下的数据状态是否被妥善处理?
* **事务一致性**:涉及多个表的写入时,是否正确使用了数据库事务(如 @Transactional 或 transaction.atomic
#### **3\. 安全与性能隐患 (Security & Performance)**
* **安全漏洞**:是否存在 SQL 注入风险(直接拼接 SQL 字符串、XSS/CSRF 风险?越权漏洞(没有校验 owner \== current\_user
* **性能瓶颈**:是否存在潜在的 N+1 查询?是否在大循环中操作了数据库或发起外部网络请求?是否进行了会导致内存溢出的大列表全量加载?
#### **4\. 可测试性与健壮性 (Testability & Robustness)**
* **异常处理**:有没有吞噬异常(空的 except/catch是否抛出了合理的业务错误码还是直接把系统底层报错扔给了前端
* **测试覆盖**:新增的核心逻辑是否包含了对应的单元测试?
### **4.2.3 基于变更类型的动态审查重点**
根据提交的代码类型Reviewer 的关注点应当有所侧重:
* 🆕 **新功能 (Feature)**: 重点关注 **\[功能正确性\]** → **\[设计合理性/扩展性\]** → **\[代码质量\]**。
* 🐛 **缺陷修复 (Bugfix)**: 重点关注 **\[问题根因是否找准\]** → **\[修复是否引入回归风险\]** → **\[是否补充了防回归测试\]**。
* ♻️ **重构 (Refactor)**: 重点关注 **\[系统向后兼容性\]** → **\[设计是否得到改进\]** → **\[性能与测试保持\]**。(重构 PR 原则上不应包含新业务逻辑)。
### **4.2.4 Review 礼仪与沟通规范 (Etiquette)**
代码审查极其容易引发工程师之间的情绪对立。良好的沟通方式是 CR 顺利推行的润滑剂。
* **对事不对人**
* ❌ 错误表达:“*你这里写的完全不对,你为什么不用 Map*”
* ✅ 正确表达:“*这段逻辑如果改用 Map 结构,查找复杂度是不是可以从 O(n) 降到 O(1)?我们试一下如何?*”
* **区分严重程度 (使用标签)**
* 建议在评论前加上标签,明确反馈的性质,避免作者过度恐慌或误解:
* \[Blocker\] / \[Must-Fix\]:致命错误、安全漏洞、严重架构违规。**必须修改才能合并**。
* \[Suggestion\] / \[Should-Fix\]:强烈的优化建议(如代码结构、性能)。建议修改。
* \[Nit\] / \[Optional\]细枝末节的挑刺Nitpick如命名规范、稍微优雅一点的写法。作者可凭主观意愿决定是否修改**不阻塞合并**。
* \[Question\]:纯粹的疑问,希望能解释一下为什么这么写。
* **提出问题,更要给出建议**:如果指出了一段代码很糟糕,请尽量提供一段伪代码或者文档链接作为优化参考。
* **不要吝啬赞美**:如果看到一段非常优雅的实现、极其周全的测试,请直接在评论里留下 👍 或夸奖。正向反馈能极大提升团队技术氛围。
### **4.2.5 标准的 PR 描述与审查总结模板**
提交者发起 PR 或 Reviewer 完成一次重大审查时,应尽量使用以下结构化的 Markdown 模板:
\#\# 📋 变更摘要 (Summary)
\* \*\*变更类型\*\*: \[🆕新功能 | 🐛缺陷修复 | ♻️重构 | ⚡性能优化\]
\* \*\*关联 Ticket\*\*: \#Issue-123
\* \*\*核心目的\*\*: 解决了订单并发退款时的状态不一致问题。
\#\# 🔍 核心变更点 (Key Changes)
1\. 引入了 \`Redisson\` 分布式锁控制并发请求。
2\. 重构了 \`RefundService\`,将第三方退款网关的调用抽离为了防腐层。
3\. 数据库 \`order\` 表新增了 \`refund\_status\` 字段(已包含 Migration 脚本)。
\#\# ⚠️ 影响面与风险评估 (Impact & Risks)
\* \*\*功能影响\*\*: 仅影响退款链路。
\* \*\*兼容性\*\*: \*\*\[注意\]\*\* 接口 \`POST /api/v1/refund\` 新增了必填参数 \`reason\_code\`,需前端同步发版,暂不兼容旧版 App。
\* \*\*性能风险\*\*: 引入了分布式锁,预期单个退款请求耗时增加 10ms在接受范围内。
\#\# 🎯 自我检查 (Self Check)
\- \[x\] 本地单测全部通过。
\- \[x\] 没有遗留的 \`print\` 和注释掉的死代码。
\- \[x\] 已补充对应的 OpenAPI 文档注解。

View File

@@ -0,0 +1,72 @@
# **4.3 安全编码规范 (防御性编程)**
防御性编程的核心思想是:**假设所有的外部输入都是恶意的,假设内部的依赖调用随时会失败**。安全漏洞一旦在生产环境被利用,对业务和公司声誉的打击往往是毁灭性的。
本规范规定了团队在日常编码中必须遵守的安全底线。
### **4.3.1 常见 Web 漏洞防护底线**
#### **1\. SQL 注入 (SQL Injection) 绝对防线**
* **红线****绝对禁止**使用字符串拼接(如 Python 的 f-string 或 %sJava 的 \+)来构造 SQL 语句。
* **规范**
* 默认必须使用框架提供的 ORM 工具(如 Django ORM, SQLAlchemy, MyBatis 动态标签)。
* 如果极其特殊的复杂查询必须执行原生 SQL**必须**使用参数化查询Parameterized Queries将变量作为参数安全传递给数据库驱动。
#### **2\. 跨站脚本攻击 (XSS \- Cross-Site Scripting) 防护**
* **输入校验**:在后端接口层(如 DRF Serializer 或 Pydantic必须严格校验输入数据的格式与长度。
* **输出转义**
* 现代前端框架Vue/React默认防范了 DOM 型 XSS但如果后端需要渲染模板如 Django Template**严禁滥用 |safe 过滤器**。
* **富文本处理**:如果业务确实需要接收和展示用户提交的 HTML 富文本,后端在入库前**必须**使用白名单过滤库(如 Python 的 bleachJava 的 OWASP Java HTML Sanitizer对危险标签如 \<script\>, \<iframe\>, onload进行清洗。
#### **3\. 跨站请求伪造 (CSRF) 防护**
* **无状态 Token 场景(如 JWT**:客户端将 Token 存放在 localStorage 并通过 Header (如 Authorization: Bearer) 发送时,天然免疫 CSRF无需额外配置。
* **Cookie 鉴权场景**:如果项目使用 Cookie 存放 Session ID 或 Token
* 必须为 Cookie 设置 HttpOnly=True防止 XSS 窃取)和 SameSite=Lax 或 Strict防止 CSRF 跨站携带)。
* 涉及状态修改的接口POST/PUT/DELETE必须开启并验证 CSRF Token。
### **4.3.2 敏感数据处理规范 (数据安全红线)**
敏感数据(如用户密码、手机号、身份证号、银行卡号、支付凭证)的生命周期必须受到极其严格的管控。
#### **1\. 传输层加密**
* **规范**:生产环境的所有 API 请求、后台管理系统访问,**强制使用 HTTPS (TLS 1.2 及以上版本)**。绝对禁止敏感数据在公网明文传输。
#### **2\. 密码存储红线**
* **红线****任何情况下,绝对禁止以明文形式存储用户密码。**
* **规范**
* 密码必须使用强单向哈希算法(如 Bcrypt, Argon2或 Django 默认的 PBKDF2进行加密存储。
* **禁止使用 MD5 或 SHA1** 作为密码的哈希算法(极其容易被彩虹表破解)。
* 加密过程必须加盐Salt且每个用户的盐值必须随机且唯一。
#### **3\. PII (个人身份信息) 的存储与加密**
* **需解密还原的数据**(如业务人员需要查看真实手机号、发货地址):必须使用强大的对称加密算法(如 AES-256-GCM进行**落地加密Encryption at Rest**且加密密钥KMS必须与数据库物理隔离。
* **无需解密的数据**(如仅用于用户登录匹配的手机号):建议直接使用带盐哈希存储,业务逻辑只做哈希比对。
#### **4\. 数据展示与脱敏 (Data Masking)**
* **红线****前端展示所需的数据脱敏,必须在后端完成!绝对禁止后端返回完整明文数据,依靠前端代码去隐藏或打星号。**
* **规范**:通过 API 返回给用户终端的敏感信息,必须提前进行掩码截断。
* 手机号138\*\*\*\*1234
* 身份证110105\*\*\*\*\*\*\*\*1234
* 银行卡:\*\*\*\* \*\*\*\* \*\*\*\* 1234
* 姓名:张\*三 或 \*三
#### **5\. 日志安全红线**
* **红线****日志中绝对禁止打印明文密码、鉴权 Token、完整的银行卡号/CVV 码、加密密钥。**
* **规范**在全局中间件或切面AOP记录请求和响应日志时必须配置**敏感字段过滤规则**。如果请求体中包含 "password": "xxx",写入日志时必须替换为 "password": "\*\*\*"。
### **4.3.3 业务安全与防暴破机制**
* **水平越权防护 (IDOR/BOLA)**
* 永远不要相信用户提交的资源 ID。在修改或删除任何记录如 POST /orders/123/cancel除了判断 ID 存在,**必须**在数据库查询层面加上归属校验(如 WHERE order\_id=123 AND user\_id={当前登录用户ID})。*(详见 3.2.7 数据隔离规范)*。
* **接口防刷与限流 (Rate Limiting)**
* 对于发送短信验证码、注册、登录等极易被黑客利用进行暴力破解或“薅羊毛”的接口,必须在网关层或应用层配置**频次限制**(如同一 IP 每分钟最多 5 次,同一手机号每天最多 10 次)。
* **失败提示模糊化**
* 登录失败时,无论是因为“账号不存在”还是“密码错误”,**统一定义返回**:“账号或密码错误”。禁止明确告知攻击者账号是否存在,防止黑客进行“撞库”和账号枚举。

View File

@@ -0,0 +1,106 @@
# **5.1 版本控制与代码提交规范**
优秀的版本控制应当像一本条理清晰的编年史,任何人在任何时候接手代码,都能通过 Git 历史精准还原业务的演进过程。本规范旨在建立清晰、可追溯、自动化的代码流转体系。
### **5.1.1 分支管理模型 (Branching Model)**
为了兼顾敏捷交付与生产环境的极度稳定,团队统一采用 **简化的 GitFlow / 环境变量流 (Environment Flow)**
#### **1\. 核心常驻分支 (Protected Branches)**
这三个核心分支与部署环境严格绑定,**绝对禁止**任何开发人员直接使用 git push 推送代码,必须通过 PR/MR 流程合并:
* **main (或 master) \- 生产环境分支**
* 对应线上生产环境 (Production)。
* 这里的代码必须是随时可发布、经过全面测试的绝对稳定版本。
* **test (或 release) \- 测试/预发环境分支**
* 对应 QA 测试环境或预发布环境 (Staging)。
* 用于产品经理验收和测试工程师进行系统级回归测试。
* **dev (或 develop) \- 开发集成环境分支**
* 对应日常开发联调环境。
* 汇总所有开发人员最新的 Feature 代码,允许存在一定的 Break Change但必须保证编译和基础启动不报错。
#### **2\. 临时工作分支 (Temporary Branches)**
开发人员日常编码都在临时分支上进行,命名必须遵循以下前缀规范,并在开发完成后删除:
* **feat/xxx**:新功能开发分支(从 dev 检出,合并回 dev
* *示例feat/user-login-wechat*
* **fix/xxx**:常规 Bug 修复分支(从 dev 或 test 检出)。
* *示例fix/order-amount-calc-error*
* **hotfix/xxx**:线上紧急漏洞修复分支(**直接从 main 检出**)。
* *红线:紧急修复测试通过后,必须同时双向合并到 main 和 dev 分支,防止代码覆盖丢失!*
### **5.1.2 Commit Message 格式规范 (Conventional Commits)**
**核心理念:让机器能读懂提交历史,以便自动生成 Release Notes。**
团队强制遵循 Angular 提交规范。推荐在项目中引入 commitlint 配合 Git Hooks如 pre-commit进行强制拦截。
#### **1\. 标准格式**
\<type\>(\<scope\>): \<subject\>
\<空行\>
\<body\>
#### **2\. Type (提交类型 \- 必填)**
* feat: ✨ 新增功能 (Feature)
* fix: 🐛 修复缺陷 (Bug)
* docs: 📝 文档更新 (Documentation)
* style: 🎨 代码格式修改(不影响逻辑,如空格、缩进、格式化工具输出)
* refactor: ♻️ 代码重构(既不是新增功能,也不是修复 bug 的代码更改)
* perf: ⚡️ 性能优化 (Performance)
* test: ✅ 新增或修改测试用例
* chore: 🔧 构建过程、CI/CD 脚本、辅助工具库的更改
#### **3\. Scope (影响范围 \- 可选)**
用于说明本次提交影响的模块,如 (user), (order-service), (ci)。
#### **4\. Subject (简短描述 \- 必填)**
* 必须使用祈使句(如:“添加用户登录”,而不是“添加了用户登录”)。
* 结尾**不要**加句号。
* 如果关联了特定的任务卡片或 Issue 编号强烈建议带上feat(auth): 支持微信扫码登录 (\#ISSUE-102))。
#### **4\. 反面教材与正确示范**
* ❌ 错误update 代码
* ❌ 错误fix bug
* ✅ 正确fix(payment): 修复并发退款时状态一致性问题 (\#bug-882)
* ✅ 正确feat(externals): 增加 Dify 代理网关接口
### **5.1.3 Tag 与版本号命名规则 (Semantic Versioning)**
**红线:严禁人肉编造随意字符串作为版本号。** 所有对外发布、打包上线的制品(如 Docker 镜像、NPM 包、Maven 依赖)必须严格遵循 **语义化版本 (SemVer 2.0.0)** 规范。
#### **1\. 版本号格式v\<MAJOR\>.\<MINOR\>.\<PATCH\>**
* **MAJOR (主版本号)**:当你做了**不兼容的 API 修改**或系统进行了史诗级重构时。
* **MINOR (次版本号)**:当你做了**向下兼容的新功能新增**时。
* **PATCH (修订号)**:当你做了**向下兼容的缺陷修复 (Bugfix)** 时。
*示例v1.0.0 \-\> v1.1.0 (加了新功能) \-\> v1.1.1 (修了新功能的 Bug) \-\> v2.0.0 (接口大重构,老版本客户端不可用)。*
#### **2\. 预发布版本后缀**
在正式 Tag 之前,如果是处于测试阶段的里程碑,应当追加连字符与标识:
* Alpha (内测版): v2.0.0-alpha.1
* Beta (公测版): v2.0.0-beta.1
* RC (Release Candidate 候选发布版): v2.0.0-rc.1
### **5.1.4 提交与合并纪律 (Commit & Merge Discipline)**
为配合 4.2 代码审查规范 与 CI/CD 质量门禁,特设立以下代码流转纪律:
1. **防门禁失败兜底 (Pre-commit)**
* 所有代码在 git commit 时,必须触发本地钩子验证。如项目存在特定的门禁脚本(如 GTCO\_AI 项目下的 scripts/ci/quality\_gate.sh必须在本地保证执行通过。
2. **禁止强推 (No Force Push)**
* 绝对禁止对 dev, test, main 等公共分支执行 git push \-f。此行为将直接导致团队其他成员的版本库断裂。
3. **主张 Squash Merge (压缩合并)**
* 开发者在自己的 feat/xxx 分支上为了备份,可能会产生大量零碎的 commit如 fix typo, update again
* 在通过 PR 合并到主干分支(如 dev**强烈建议使用 Squash and Merge**,将无数琐碎的 commit 压缩成一个整洁的业务 Commit 记录进入主干。
4. **及时变基 (Rebase / Sync)**
* 开发周期较长的 Feature 分支,必须每天从目标主干分支拉取最新代码(建议使用 git pull \--rebase origin dev提前解决冲突严禁等到提 PR 那天才去处理几千行的灾难性冲突。

View File

@@ -0,0 +1,85 @@
# **5.2 CI/CD 与环境部署规范**
持续集成与持续部署CI/CD是连接代码与生产环境的高速公路。我们追求的目标是**一次构建随处运行一切即代码Pipeline as Code消除环境差异带来的人为故障。**
团队统一采用 **Jenkins** 作为核心的 CI/CD 引擎。
### **5.2.1 多环境定义与资源流转 (Environments)**
系统从开发到上线,必须经历严格的环境隔离与流转。严禁跨环境调用(如 Dev 环境连接 Prod 数据库)。
* **1\. Local (本地开发环境)**
* **使用者**:开发人员。
* **形态**研发个人的笔记本电脑依赖的数据库、Redis 推荐通过本地 Docker Compose 快速拉起。
* **目的**:日常编码、单步调试、执行本地单元测试。
* **2\. Dev (开发集成环境)**
* **对应分支**dev (或 develop)
* **使用者**:开发人员、前端/客户端联调人员。
* **形态**:自动拉取 dev 分支最新代码部署。允许存在一定的不稳定性,日志级别通常设为 DEBUG。
* **目的**:验证微服务间的连通性、前后端接口联调。
* **3\. Test (系统测试环境)**
* **对应分支**test (或 release)
* **使用者**QA 测试工程师。
* **形态**:由专门的合并操作触发部署。数据库通常会定期从线上脱敏同步部分数据以模拟真实场景。
* **目的**:功能验收测试、自动化接口回归测试、性能压测基准测试。
* **4\. UAT (用户验收测试 / 预发环境)**
* **对应分支**main (打 Tag 前的最终验证)
* **使用者**:产品经理、业务方验收人员。
* **形态****基础架构、配置规格必须与 Prod 生产环境 100% 保持一致**。甚至可以连接生产环境的只读库或独立的预发库。
* **目的**:上线前的最后一次演练,验证部署脚本本身是否正确,业务逻辑是否符合预期。
* **5\. Prod (生产环境)**
* **对应分支**main (基于发布 Tag如 v1.2.0)
* **使用者**:真实的外部用户。
* **形态**:极度稳定、高可用、严控权限。
* **目的**:承载真实业务。
### **5.2.2 配置隔离与凭证安全**
为了实现“同一份代码(或镜像)在不同环境无缝切换”,必须做到代码与配置的彻底分离。
* **配置文件解耦**
* 遵循《3.2 框架实施规范》,代码中必须拆分不同环境的配置文件(如 settings/dev.py, settings/prod.py
* 运行时通过环境变量(如 export APP\_ENV=prod来决定加载哪份配置。
* **密码与密钥红线 (Secret Management)**
* **绝对禁止**将数据库密码、API 秘钥、云服务 AccessKey 写死在代码库(包括 .env 文件也不允许提交到 Git
* Jenkins 注入:在 CI/CD 阶段,通过 Jenkins 的凭据管理Credentials Binding或 HashiCorp Vault、云厂商配置中心如 Nacos/Apollo在容器启动时动态注入环境变量。
### **5.2.3 持续集成流水线规范 (Jenkins Pipeline)**
**核心理念Pipeline as Code (流水线即代码)。**
* **严禁手动配置 Job**:禁止在 Jenkins UI 页面上手工拼凑 Shell 脚本构建步骤。
* **强制使用 Jenkinsfile**
* 每个代码仓库的根目录必须包含一个使用声明式语法Declarative Pipeline编写的 Jenkinsfile。
* 流水线的版本控制与业务代码同源谁修改了部署逻辑Git 历史一目了然。
**标准 Jenkinsfile 阶段 (Stages) 划分:**
1. Checkout拉取代码。
2. Quality Gate (Linter & Test)执行静态代码扫描Ruff/ESLint和单元测试Pytest。**失败则立刻中断流水线**。
3. SonarQube Analysis进行代码异味、漏洞分析。
4. Build & Push将应用打包并构建为 Docker 镜像,打上与 Git Commit ID 绑定的 Tag推送到镜像仓库Harbor/阿里云 ACR
5. Deploy to XXX触发 Kubernetes (K8s) 或目标服务器拉取新镜像并滚动更新。
### **5.2.4 流水线触发规则与门禁策略 (Trigger Rules)**
为了平衡开发效率与质量控制Jenkins 流水线必须配合 Webhook 实现自动化触发并设置严格的卡点Quality Gates
#### **1\. PR/MR 提交阶段 (Merge Request to Dev/Main)**
* **触发方式**:开发人员在 Gitlab/Github 提交 Pull Request。
* **执行流水线**:仅执行 Lint \-\> Unit Test \-\> Sonar。**不进行部署**。
* **门禁规则**:如果 Jenkins 反馈测试失败、覆盖率低于 80% 或存在高危漏洞,代码托管平台必须**锁定合并按钮Block Merge**,强迫开发者修复。
#### **2\. 代码合并阶段 (Push to Dev/Test)**
* **触发方式**PR 合并到 dev 或 test 分支。
* **执行流水线**:完整走完上述五个 Stage最终自动部署到对应的 Dev 或 Test 服务器。
* **验证测试**部署完成后流水线应触发自动化接口测试API E2E Tests一旦测试不通过立即发送飞书/钉钉告警通知团队。
#### **3\. 生产发布阶段 (Deploy to Prod)**
* **触发方式**:在 main 分支打上符合 SemVer 规范的 Tag如 v2.1.0)。
* **门禁规则 (人工卡点)**
* 生产环境的部署**绝对禁止全自动触发**。
* 在 Jenkins 流水线的 Deploy to Prod 阶段前,必须设置一个 input() 审批节点。只有具备 Release 权限的运维工程师或技术 TL 在 Jenkins 界面点击“同意确认”后,才会真正触发生产环境的镜像替换。

51
README.md Normal file
View File

@@ -0,0 +1,51 @@
# **CPS 研发团队规范与文档导航 (Developer Playbook)**
欢迎来到 CPS 研发团队规范文档库!本文档是整个团队在架构设计、编码实施、项目协同以及代码审查等环节的**唯一基准指南**。
## **🗂️ 核心目录导航**
### **📂 01 \- Knowledge & Prompts (知识库与架构沉淀)**
沉淀团队宏观架构决策与 AI 提效资产,强调“为什么这么做”而非单纯的“怎么做”。
* 📝 **Architecture Decision Records (ADR)**:记录重大技术选型对比与架构演进背景。
* 🤖 **AI Prompts**存放标准代码生成、Code Review 及排障的 AI 提示词模板。
### **📂 02 \- Architecture & Design (系统与架构设计规范)**
脱离具体编程语言与框架的通用系统设计、接口契约与数据规约。
* 🏗️ **2.1 系统架构设计原则**:定义单体/微服务边界、分层架构模式DDD/MVC/BFF及依赖解耦底线。
* 🔌 **2.2 API 接口设计规范**:规定 RESTful 协议标准、统一的请求头、响应结构及分页/错误码策略。
* 💾 **2.3 数据库与存储设计规范**:明确表结构与字段命名、慢查询规避红线及 Redis 缓存防雪崩/穿透规范。
### **📂 03 \- Coding & Frameworks (编码基础与框架实施规范)**
针对具体编程语言和 Web 框架的强制性编码约束与最佳实践。
* 💻 **Python 编码与开发规范**:定义 Python 现代工具链 (uv, Ruff)、类型注解标准及核心设计范式。
* ⚙️ **框架开发实施规范 (Django/DRF)**:规定 Model/Serializer 性能红线、Fat Service 分层原则及数据隔离策略。
* 🏢 **GTCO\_AI 项目特有业务实施规范**:针对 GTCO\_AI 业务项目的私有红线、专属鉴权绑定与联调脚本约束。
### **📂 04 \- Quality & Review (质量保证与代码审查)**
保障代码合入主干前的高质量与安全性,防范线上故障回归。
* 🧪 **4.1 自动化测试规范**:明确 3A 原则、Mock 边界及单元/集成/E2E 接口测试的执行策略。
* 🧐 **4.2 代码审查 (Code Review) 规范**:梳理 CR 触发门禁、架构/逻辑审查 Checklist 及团队沟通礼仪。
* 🛡️ **4.3 安全编码规范**:防御 SQL 注入/XSS/CSRF 三大 Web 漏洞,制定敏感数据脱敏与存储红线。
### **📂 05 \- Collaboration & Delivery (协作与交付规范)**
定义代码从本地开发到生产环境的标准化流转轨道与持续集成策略。
* 🌿 **5.1 版本控制与代码提交规范**:确立常驻三分支模型 (main/test/dev)、Angular 提交规范及 SemVer 版本号管理。
* 🚀 **5.2 CI/CD 与环境部署规范**:定义多环境隔离标准及基于 Jenkinsfile 的全自动化流水线与卡点策略。
## **📖 如何使用本指南?**
1. **新员工入职**:请优先阅读 03 \- Coding & Frameworks 目录下的相关语言与框架规范,确保首个提交符合团队红线。
2. **架构设计与选型**:在引入新技术或进行微服务拆分前,请先查阅并编写 01 \- Knowledge & Prompts 目录下的 ADR 文档。
3. **日常疑难杂症**:善用 01 目录中沉淀的 AI Prompts 资产,加速代码生成与排障过程。
**维护说明**:本文档及子目录规范由系统架构组与核心开发团队共同维护。若有规范调整建议,请提交 PR 或在技术会议上发起讨论。