diff --git a/03 - Coding & Frameworks/01 - Language Coding Specification/Python 编码与开发规范.md b/03 - Coding & Frameworks/01 - Language Coding Specification/Python 编码与开发规范.md index 745d78a..71c7dad 100644 --- a/03 - Coding & Frameworks/01 - Language Coding Specification/Python 编码与开发规范.md +++ b/03 - Coding & Frameworks/01 - Language Coding Specification/Python 编码与开发规范.md @@ -21,6 +21,8 @@ Python 是一门极其灵活的动态语言,但“灵活”在大型团队协 ... * **常量(Constants):** 强制使用 SCREAMING\_SNAKE\_CASE(全大写加下划线),定义在模块顶部。 +* **布尔语义命名:** 布尔变量与布尔返回值应使用 `is_`、`has_`、`can_`、`allow_` 前缀,避免语义歧义。 +* **集合语义命名:** 列表、集合、查询结果变量应使用复数命名(如 `users`, `orders`, `permission_codes`)。 * **私有与受保护属性:** \* 单下划线 \_private\_var:表示内部使用(软性约束,仅作提示)。 * 双下划线 \_\_strict\_private:触发名称改写(Name Mangling),除非极特殊情况(如防止子类重写),**日常业务开发中不推荐使用**,以免增加调试难度。 @@ -90,6 +92,7 @@ class UserCreateRequest(BaseModel): * **禁止吞噬异常:** 绝不允许出现 except Exception: pass 这种掩耳盗铃的代码。 * **自定义异常层次:** 模块应当抛出特定业务领域的异常(如继承自 ValueError 的 OrderNotFoundError),而不是直接抛出裸露的 Exception。 +* **边界层错误策略:** 在 API、CLI、任务入口等边界层,应优先“抛异常并交由统一处理”,避免在底层函数中拼接错误响应字符串。 ### **4\. 资源释放与安全** diff --git a/03 - Coding & Frameworks/02 - Framework Development Specification/Django_DRF开发规范.md b/03 - Coding & Frameworks/02 - Framework Development Specification/Django_DRF开发规范.md index d526873..ab13857 100644 --- a/03 - Coding & Frameworks/02 - Framework Development Specification/Django_DRF开发规范.md +++ b/03 - Coding & Frameworks/02 - Framework Development Specification/Django_DRF开发规范.md @@ -18,6 +18,7 @@ * **严禁重复造轮子**:Django 和 DRF 拥有极其成熟的第三方开源生态。对于标准化的通用需求,**必须**优先集成成熟的第三方库。例如使用 djangorestframework-simplejwt 处理 Token,使用 django-filter 处理复杂查询过滤。 * **代理层无状态**:若系统作为中间层代理外部 API(如大模型网关),代理视图禁止落库复杂的业务状态。 * **认证逻辑收口**:对接外部系统的身份认证逻辑(如 LDAP、API Key)必须严格收拢在 DRF 的 Authentication 类或 Django 的中间件中,**绝对禁止**在业务 View 中直接读取 Request Headers 做条件分流。 +* **认证冲突拒绝**:当请求同时携带多种互斥认证凭证时,必须直接拒绝并返回统一错误,禁止按优先级做隐式降级兼容。 ## **数据层规范 (Models & Serializers)** @@ -28,11 +29,15 @@ * **显式定义主键与审计**:不推荐使用庞大的公共抽象基类隐式继承。业务 Model 应当显式定义主键和必备的审计字段(如 created\_at, updated\_at),避免基类变更带来全局副作用。 * **字段防空红线**:字符型字段(CharField, TextField)禁止设置 null=True,必须设为 default=''。 * **外键明确声明**:使用 ForeignKey 关联时必须显式指定清晰的 related\_name。 +* **枚举字段规范**:枚举值优先使用 TextChoices 或 IntegerChoices,禁止散落硬编码字符串。 +* **字段文档化**:核心业务字段应补充 help_text,以保障文档可读性与维护一致性。 +* **索引基线**:高频过滤、排序与关联字段必须显式建索引,避免接口上线后暴露慢查询。 * **物理删除优先**:默认优先使用物理删除。仅当业务明确要求审计追溯时引入逻辑删除(is\_deleted)。若启用逻辑删除,必须配合使用带条件的唯一约束以防止重复插入冲突。 ### **序列化层红线 (Serializers)** * **禁用全量暴露**:**严禁**在 Serializer 中使用 fields \= '\_\_all\_\_'。必须逐个显式列出对外暴露的字段,防止数据库新增敏感字段后发生意外泄露。 +* **参数集中声明**:字段级约束(如 read_only、required、write_only)优先通过 Meta.extra_kwargs 集中配置。 * **严防 N+1 查询**: * 列表接口**严禁**使用包含深层嵌套关系的复杂 Serializer,必须为其单独定义轻量级的结构。 * 若 Serializer 输出了外键字段,View 层的 QuerySet **必须**配合使用 select\_related 或 prefetch\_related。 @@ -60,8 +65,24 @@ View 层仅作为路由调度、参数校验和权限决策的枢纽,绝不可 ### **路由与异常处理** * **命名空间绝对隔离**:全局强制采用 NamespaceVersioning 机制。根路由必须携带命名空间,且内部的 urls.py 必须存在 app\_name。反向解析必须带版本号前缀。 +* **URL 风格统一**:内部 REST 接口默认使用 kebab-case 与复数资源命名;第三方透传代理接口可按上游路径 1:1 保持。 * **异常抛出代替返回**:遇到业务校验错误,**严禁**在代码中手动 return Response({"error": "xxx"})。**必须**直接抛出异常(如 raise ValidationError),交由全局的 exception\_handler 统一格式化。 * **统一响应壳**:严禁在 View 中手动构建类似 {"code": 0, "data": ...} 的字典,必须交由自定义的全局 Renderer 统一包装。 +* **状态码语义化**:HTTP 状态码必须通过 `rest_framework.status` 常量引用,禁止直接写数字魔法值。 + +## **分页与文档规范** + +* **默认分页策略**:常规列表接口默认使用 LimitOffsetPagination;仅在瀑布流、时间游标等场景使用 CursorPagination。 +* **文档注解强制化**:所有自定义 Action 与非标准接口必须显式补充 `@extend_schema`(至少包含 summary、description、request、responses)。 +* **透传接口说明**:代理第三方接口时,文档必须标注哪些字段为“上游原样透传”,避免接口语义歧义。 + +## **查询性能与异步基线** + +* **N+1 防线**:开发阶段必须启用 N+1 监测手段(插件或测试守卫),出现问题即阻断合并。 +* **批量操作优先**:批量写入与批量更新优先使用 `bulk_create` / `bulk_update`,禁止循环逐条写库。 +* **大结果集迭代**:处理大表时优先使用 `iterator()` 或分批读取,避免一次性加载导致内存峰值过高。 +* **异步边界清晰**:异步视图仅用于高并发 I/O 场景,CPU 密集计算必须下沉到任务队列或独立计算服务。 +* **耗时任务剥离**:邮件、报表、第三方调用等明显耗时逻辑应通过异步任务框架执行,避免阻塞同步请求。 ## **权限管控与数据隔离 (Permissions)** diff --git a/ref/drfstd.md b/ref/drfstd.md new file mode 100644 index 0000000..3f33b74 --- /dev/null +++ b/ref/drfstd.md @@ -0,0 +1,550 @@ +# **GTCO\_AI Django REST Framework(DRF) 后端开发规范指南** + +**版本**: 2.16 + +**适用对象**: Python 后端开发团队 + +**目标**: 明确技术选型,统一代码风格,降低维护成本,保障系统高可扩展性。 + +**执行策略**: 本规范采用“限制优先”原则。默认不提供多实现方案,优先固定实现路径;未在本文明确允许的做法,一律视为不允许。 + +**文档定位**: 本文件是开发规范的唯一基准文档。若与其它开发文档冲突,以本文件为准。 + +**配套文档入口**: `docs/development/index.md` + +**专项规范**: +1. 文档管理:`docs/development/documentation_standards.md` +2. Dify 代理:`docs/development/dify_proxy_standards.md` +3. 代码审查:`docs/development/code_review_guidelines.md` + +## **0.0 项目红线 (不可变约束)** + +以下为当前仓库的强制架构约束,默认长期有效: + +1. **版本唯一**:仅允许 `v1` 命名空间,必须通过 `NamespaceVersioning` 解析版本;禁止新增未命名空间路由。 +2. **认证唯一入口**:仅允许 `SmartHeaderAuthentication + GTCOAIJWTAuthentication` 组合;禁止在 View 层读取 `Authorization` / `X-API-Key` 做分流。 +3. **认证冲突硬拒绝**:同一请求同时携带 Bearer 与 `X-API-Key` 时必须拒绝,禁止降级兼容。 +4. **响应统一封装**:仅允许 `StandardResponseRenderer` 统一包装 `code/message/data`;禁止在业务 View 手动拼装统一响应壳。 +5. **异常统一出口**:仅允许 `gtcoai_exception_handler` 输出错误结构;禁止各模块自定义返回格式。 +6. **组织作用域强隔离**:凡组织级数据(user/externals)查询必须绑定 `request.user.current_organization`;禁止跨组织默认可见。 +7. **权限链路固定**:涉及外部资源访问时,必须遵循“系统动作策略 -> 组织角色/成员 -> 用户组授权”顺序,禁止跳步放行。 +8. **写操作服务化**:复杂写操作必须下沉到 Service 层;View 层仅做编排、参数校验、权限决策。 +9. **代理链路无状态**:Dify 透明代理禁止落库业务状态,禁止在代理层引入账号同步、审批等副作用逻辑。 +10. **变更必须可验证**:涉及权限、认证、代理路径改动时,必须补齐自动化测试并执行真实路由脚本验证。 +11. **门禁入口唯一**:合并前质量检查仅允许通过 `scripts/ci/quality_gate.sh` 执行,禁止自定义临时命令替代。 + +## **0\. 技术栈清单 (Tech Stack)** + +本规范强制使用以下库与工具: + +| 分类 | 选定库 | 用途 | +| :---- | :---- | :---- | +| **包管理** | uv | Rust 编写的 Python 包管理器,用于替代 pip/poetry | +| **配置管理** | django-split-settings | 多环境配置拆分 | +| **代码质量** | Ruff | 格式化、排序、检查三合一工具 | +| **类型检查** | VS Code (Pylance) | 编辑器实时检查 (CI 不强制 Mypy) | +| **异步视图** | adrf | DRF 的异步扩展 (Async Django REST Framework) | +| **异步任务** | Celery | 后台任务队列 | +| **消息/缓存** | Redis | Celery Broker / Backend 及 Django Cache | +| **性能调试** | django-debug-toolbar | SQL 查询分析 (开发环境) | +| **性能监测** | nplusone | N+1 问题自动检测 | +| **日志系统** | Loguru | JSON 结构化日志 | +| **认证授权** | drf-simplejwt | JWT 认证 | +| **目录认证** | django-auth-ldap | LDAP 认证(生产环境) | +| **API 文档** | drf-spectacular | OpenAPI 3.0 Schema 生成 | +| **测试框架** | pytest-django | 测试运行器 | +| **测试数据** | factory\_boy | 测试数据生成 | +| **并行测试** | pytest-xdist | 多进程测试加速 | + +## **1\. 工程化规范 (Engineering)** + +### **1.1 依赖管理** + +* **工具**: 统一使用 uv。 + * 常用命令: uv pip compile (锁定), uv sync (同步)。 +* **版本锁定**: 生产环境必须存在 uv.lock 文件。 +* **Python 版本**: 强制版本为 **Python 3.11 及以上**(与 `pyproject.toml` 保持一致)。 + +### **1.2 配置管理 (Settings)** + +**禁止**将所有配置写在单个 settings.py 中。**必须**使用 django-split-settings。 + +**目录结构要求**: + + + settings/ + \_\_init\_\_.py \# 入口逻辑 + base.py \# 通用配置 + components/ \# 模块化配置 (logging.py, drf.py, celery.py) + environments/\# 环境差异化配置 (local.py, prod.py) + +* **安全要求**: 密钥 (SECRET\_KEY, DB\_PASSWORD) **必须**从环境变量 (.env) 读取,**严禁**硬编码。 + +### **1.3 代码规范 (Linting)** + +**工具**: 统一使用 **Ruff**。 + +* **配置要求**: + * **格式化**: ruff format + * **检查**: ruff check \--fix + * **行长**: **120** (严禁使用默认的 88\) +* **类型检查**: + * 开发人员需确保 VS Code (Pylance) 无红色报错。 + * CI 流水线不运行 Mypy。 + +## **2\. 命名与风格 (Naming & Style)** + +### **2.1 命名表** + +| 对象 | 规范 | 示例 | +| :---- | :---- | :---- | +| **App** | 全小写,复数 | users, orders | +| **Model** | PascalCase,单数 | User, ProductCategory | +| **Field** | snake\_case | created\_at | +| **Serializer** | Model \+ Serializer | UserSerializer | +| **View** | Resource \+ Action | UserViewSet | +| **URL** | kebab-case | /api/v1/user-profiles/ | + +### **2.2 编码习惯** + +* **布尔值**: 必须使用 is\_, has\_, allow\_ 前缀。 +* **集合变量**: 必须使用复数形式 (users, items)。 + +## **3\. 模型层规范 (Models)** + +### **3.1 基础模型** + +**严禁**使用公共抽象基类(如 BaseModel)进行隐式继承。所有业务 Model **必须**直接继承 django.db.models.Model,并**显式定义**所有需要的字段,包括主键和审计字段。 + +这种“各写各的”策略是为了保证每个 Model 的定义清晰、独立,便于后续的迁移和重构,避免基类变更带来的全局副作用。 + +class MyModel(models.Model): + \# 1\. 主键:根据实际需求显式定义,强制使用 UUID 或 BigAutoField + id \= models.BigAutoField(primary\_key=True) + + \# 2\. 业务字段 + name \= models.CharField(max\_length=100, help\_text="名称") + + \# 3\. 审计字段:必须显式书写,严禁省略 + created\_at \= models.DateTimeField(auto\_now\_add=True, help\_text="创建时间") + updated\_at \= models.DateTimeField(auto\_now=True, help\_text="更新时间") + + class Meta: + verbose\_name \= "我的模型" + verbose\_name\_plural \= verbose\_name + +### **3.2 字段定义** + +* **Choices**: 强制使用 TextChoices / IntegerChoices 枚举。 +* **Null/Blank**: 字符型字段禁止 null=True,必须设为 default=''。 +* **Help Text**: 所有字段必须填写 help\_text (用于生成文档)。 +* **Related Name**: 外键必须指定 related\_name。 + +### **3.3 数据库约束** + +* **Code First**: 严禁手动直连数据库修改结构,一切变更必须通过 Migrations。 +* **索引要求**: 凡是涉及 filter, order\_by, ForeignKey 的字段,**必须**加索引。 +* **删除策略**: 默认优先使用物理删除;仅当业务明确要求“可恢复”或“审计追溯”时才引入软删除字段。 +* **唯一约束**: 若启用软删除,必须使用带条件的唯一约束 (Conditional Unique Constraint)。 + +class Meta: + constraints \= \[ + models.UniqueConstraint( + fields=\['username'\], + name='unique\_active\_username', + condition=models.Q(is\_deleted=False) + ) + \] + +### **3.4 外部服务凭证与账号模型规范 (Externals Credentials & Accounts)** + +适用于第三方代理场景(如 Dify、OpenAI、内部网关等)。 + +* **用户-凭证关系**: 必须为一对多(一个用户可维护多个外部凭证)。 +* **凭证核心字段**: 至少包含 `service`、`credential_type`、`name`、`secret`、`is_active`。 +* **凭证命名**: `name` 必须用于业务可读标识(如“生产Dify主Key”)。 +* **唯一约束**: 同一用户下,`(service, credential_type, name)` 必须唯一。 +* **密钥存储**: 明文密钥字段必须加密存储(字段级加密或等效方案),禁止日志打印完整密钥。 +* **账号绑定**: 若用户直接绑定外部账号,必须与凭证分表管理。账号表用于身份与连接状态,凭证表用于请求鉴权材料。 +* **转发读取原则**: 代理请求阶段只按需求读取目标凭证,不在转发层混入账号同步、授权刷新等重逻辑。 + +## **4\. 序列化层规范 (Serializers)** + +### **4.1 编写规范** + +* **选型**: 统一使用 ModelSerializer。 +* **字段**: 禁止使用 fields \= '\_\_all\_\_',必须显式列出。 +* **参数**: 使用 Meta.extra\_kwargs 定义字段参数,保持代码简洁。 + +### **4.2 职责边界** + +* **定位**: 仅负责数据结构转换和基础格式验证。 +* **禁止**: save/create/update 方法中**严禁**包含发送邮件、复杂计算、外部调用等业务逻辑。 + +### **4.3 性能规范** + +* **列表接口**: 严禁在列表页使用深层嵌套的 Serializer,强制定义 SimpleSerializer。 +* **预加载**: 包含外键的 Serializer,View 层必须配合 select\_related / prefetch\_related。 +* **聚合计算**: **严禁**在 SerializerMethodField 中执行 SQL 聚合 (count/sum)。必须在 View 层使用 annotate 计算完成后传入。 + +## **5\. 视图与业务层规范 (Views & Logic)** + +### **5.1 ViewSet 选型与分层** + +**核心原则**: **精准控制与逻辑分层**。 + +* **选型**: + * 标准 CRUD 强制使用 ModelViewSet。 + * 定制化业务场景强制选用 GenericViewSet 配合 Mixins 按需组合。 + * 严禁直接使用裸的 ViewSet。 + * APIView 仅允许用于“非标准资源形态接口”(如 Dify 透明代理、缓存刷新、健康检查);必须补充 `@extend_schema` 且在类注释中说明无法使用 ViewSet 的原因。 + * 权限控制边界:只读接口绝不暴露 CreateModelMixin 或 DestroyModelMixin。 +* **方法职责表**: + +| 方法 | 核心职责 | 规范要求 | +| :---- | :---- | :---- | +| **get\_queryset** | 查数据 \+ 优化 | **必须**实现权限隔离 (如 filter(user=request.user)) 与预加载 (select\_related),杜绝 N+1。 | +| **get\_serializer\_class** | 定格式 (读写分离) | **必须**区分场景:list 用极简版,create 用校验版,retrieve 用全量版。 | +| **get\_permissions** | 定权限 (动作分离) | **必须**区分动作:如 create 允许匿名,destroy 必须管理员。 | +| **perform\_create/update** | 写业务 (逻辑下沉) | 仅处理关联逻辑 (如绑定 request.user) 或调用 Service 层。 | + +### **5.2 Service 层模式** + +View 层仅作为路由与调度的纯粹枢纽,写操作及复杂查询必须封装到 Service 层。 + +**严禁**重写 create, update, destroy 等主方法来堆砌业务逻辑。 + +\# views.py +def create(self, request, \*args, \*\*kwargs): + \# ❌ 错误:不要重写 create 方法,破坏了 DRF 标准流 + ... + +def perform\_create(self, serializer): + \# ✅ 正确:使用钩子调用 Service + create\_order\_service( + user=self.request.user, + data=serializer.validated\_data + ) + +### **5.3 返回与响应规范 (Return & Response)** + +**规则 1: 标准 CRUD 不重写 Return** + +对于标准的 create, list, retrieve 等方法,**严禁**重写其 return 逻辑。DRF 父类已处理好序列化和状态码。 + +**规则 2: 自定义 Action 规范** + +对于 @action 装饰的方法: + +* **状态码**: 必须导入 rest\_framework.status 使用常量,**严禁**使用魔术数字 (200, 404)。 +* **返回**: 必须显式返回 Response 对象。 + +from rest\_framework import status +from rest\_framework.decorators import action + +@action(detail=True, methods=\['post'\]) +def approve(self, request, pk=None): + order \= self.get\_object() + \# 业务逻辑... + return Response(serializer.data, status=status.HTTP\_200\_OK) + +**规则 3: 错误处理 (Raise, Don't Return)** + +遇到业务错误,**严禁**手动 return Response(error)。 + +**必须**直接 raise Exception (如 ValidationError, PermissionDenied)。全局异常处理器会将异常统一格式化。 + +**规则 4: 统一响应包装** + +**严禁**在每个 View 中手动构建 { "code": 0, "data": ... } 结构。 + +**必须**编写自定义 Renderer 对全局响应进行统一包装。View 层只返回纯粹的业务数据。 + +相关实现文件位置:apps/common/renderers.py。 + +### **5.4 认证分流规范 (Authentication Routing)** + +* **单一职责**: 鉴权头分流必须在认证层处理,固定入口为 `apps.common.authentication.SmartHeaderAuthentication`,禁止在 View 层手动判断 Header。 +* **Header 约定**: + * JWT: `Authorization: Bearer ` + * API Key: `X-API-Key: ` +* **冲突请求**: 同时携带 JWT 与 API Key 的请求必须拒绝,固定抛出 `ValidationError`,禁止“优先 JWT”或“优先 API Key”兼容策略。 +* **错误一致性**: 认证失败响应必须统一由全局异常处理器格式化,禁止各认证类返回不同结构。 +* **日志可观测性**: 中间件应可区分 `jwt/api_key/anonymous` 三类请求,并记录认证失败(401/403)上下文。 + +### **5.5 LDAP 接入规范 (LDAP Integration)** + +* **接入方式**: 通过 Django Authentication Backend 接入 LDAP,禁止在 View/Serializer 直接发 LDAP 请求。 +* **配置来源**: LDAP 地址、绑定 DN、密码、搜索过滤器必须来源于环境变量。 +* **登录模式**: 登录接口应支持 `local/ldap/auto` 模式切换,默认由配置控制优先级。 +* **身份落库**: LDAP 登录成功后,需将本地用户标记为 `auth_type=ldap`,并按配置同步基础属性。 +* **平台差异**: Windows 开发环境可不强制安装 `python-ldap`,但 Linux 生产环境必须验证 LDAP 依赖可用。 + +## **6\. 接口设计规范 (API Design)** + +### **6.1 URL 路由** + +#### **📌 命名空间与版本控制 (Namespace & Versioning)** + +全局强制采用 DRF 的 NamespaceVersioning 机制。**DRF 仅通过读取路由的 namespace 属性来判断当前 API 版本**,若配置缺失,会导致 request.version 为空,进而被权限控制层直接拦截返回 **404 Not Found**。 + +**强制执行标准**: + +1. **根路由 (urls.py)**: + 挂载业务路由时,include() 必须包含版本号命名空间(`namespace="v1"`)。当前项目固定结构如下: + \# gtco_ai/urls.py + + api\_v1\_patterns \= \[ + path("user/", include("apps.user.urls")), + path("external/", include("apps.externals.urls")), + \] + + urlpatterns \= \[ + path("api/v1/", include((api\_v1\_patterns, "api"), namespace="v1")), + \] + +2. **子路由 (apps/xxx/urls.py)**: + 每个 APP 的路由文件必须定义 app\_name 变量,否则 Django 无法正确注册命名空间。 + \# apps/user/urls.py + app\_name \= "user" \# ✅ 必须存在且在项目中唯一 + + urlpatterns \= \[ + \# ... + \] + +3. **反向解析 (Reverse)**: + 在代码中生成 URL 时,必须带上版本前缀。 + \# ✅ 正确 + reverse("v1:user:user-detail", args=\[user.id\]) + \# ❌ 错误 + reverse("user:user-detail", args=\[user.id\]) + +#### **📌 路径设计规范** + +* **路由前缀**:所有 API 路由必须以 /api/{version}/ 开头(例如 /api/v1/)。 +* **末尾斜杠**:统一保留 URL 末尾斜杠 /,与 DRF DefaultRouter 默认行为保持一致。 +* **内部自研接口规范**: + * **资源命名**:URL 路径**必须**使用 kebab-case(短横线连接)风格,例如 /api/v1/user-profiles/。资源集合统一使用名词复数形式。 + * **层级结构**:URL 层级不超过 3 层,禁止过深嵌套。标准结构:/api/v1/{resource}/{id}/{sub-resource}/。 +* **【特批豁免】第三方代理接口 (Proxy API) 规范**: + * **背景**:当代理外部系统(如 Dify 知识库等)接口,且前端需复用官方 SDK 或完全对照第三方官方文档时适用。 + * **1:1 映射优先**:允许豁免单复数、命名风格和层级深度的限制,**必须保证字面路径的 1:1 映射**(例如:允许使用 snake\_case 的 child\_chunks,允许单数 document,允许嵌套深度超过 4 层的 /datasets/{id}/documents/{id}/segments/{id}/child\_chunks/)。 + * **架构底线约束**:即便进行字面映射,底层代码实现仍**必须**严格依赖 Django / DRF 的标准路由调度体系(利用 DefaultRouter 处理扁平结构,利用 path \+ as\_view() 显式分发深层嵌套)。 + +### **6.2 响应格式与状态码 (Response & Status Codes)** + +**统一响应结构**: + +{ + "code": 20000, // 业务状态码 (5位) + "message": "success", // 提示信息 + "data": { ... } // 业务数据 +} + +#### **📌 业务状态码设计原则 (A-BB-CC 5位高可扩展标准)** + +随着业务的演进与微服务化,状态码需要具备极高的**可扩展性**与清晰的**域划分**。本系统严格执行 **A-BB-CC 5位数标准**: + +* **A (1位)**: 错误级别 / HTTP 语义映射。 + * 2 \= 成功 (Success) + * 4 \= 客户端错误 / 业务校验阻断 (Client Error) + * 5 \= 服务端异常 / 第三方依赖崩溃 (Server Error) +* **BB (2位)**: 业务模块 / 子域划分 (00\~99),最高支持 100 个核心模块。 + * 00 \= Common (全局基础) + * 01 \= User / Auth (用户与认证) + * 02 \= Dify (Dify 代理相关的各个模块集合,含知识库、工作流等) + * **【扩展策略】**:如果未来某个超大型模块的错误类型极其复杂、超出了 99 种,**允许为该大模块分配相邻的多个 BB 号段**。 +* **CC (2位)**: 具体错误分类序号 (00\~99)。 + * 00 \= 该模块的“默认通用错误”或“成功”。 + * 01\~99 \= 具体的精细化业务异常。 + +#### **📌 状态码扩展与开发强制规约** + +1. **禁止过度分配 (泛化 vs 特化)**: + * **禁止**为每一个表单字段的“必填项校验”单独分配 Code。普通的输入参数异常统一使用 40000 (全局 Bad Request),并在 message 或 data 节点中动态告知前端具体的字段校验失败原因。 + * **分配底线**:只有当**前端代码需要利用此 Code 进行特殊的交互逻辑跳转时**,才予以分配。例如:40102 (账号被冻结) 前端检测到后需要弹出特殊申诉弹窗;40201 (Dify API Key未配置) 前端检测到后需要引导至设置页面。 +2. **代码物理隔离 (分治策略)**: + * **禁止单文件膨胀**:禁止把所有业务 Code 全部堆在 apps/common/status\_code.py 中。 + * **规范要求**:apps/common/status\_code.py **仅存放 00 模块**的基础状态码。各个业务线独有的状态码,**必须存放于各自 App 的文件内**(例如 apps/dify/knowledge/status\_code.py)。 + +### **6.3 分页** + +* **默认分页**: 统一采用 LimitOffsetPagination。 +* **大数据分页**: 当前仓库未批准引入 Cursor/Keyset 替代方案作为默认行为;所有常规列表接口必须先落地 LimitOffsetPagination。 +* **流式分页**: 对于瀑布流场景,统一使用 CursorPagination。 + +### **6.4 API 文档注解规范 (drf-spectacular / extend_schema)** + +* **强制要求**: 所有对外接口(尤其是 `@action` 自定义动作和代理接口)必须显式使用 `@extend_schema`。 +* **最低字段**: `summary`、`description`、`request`、`responses` 必须完整声明。 +* **响应说明**: 对透传接口应使用 `OpenApiResponse` 明确说明“上游原样透传”,避免文档误导前端。 +* **禁止事项**: 禁止仅依赖自动推断导致关键请求字段(如 `method`、`route`、`path_params`)在文档中缺失。 + +## **7\. 性能与异步规范 (Performance & Async)** + +### **7.1 数据库查询** + +* **N+1 问题**: 开发环境必须安装 nplusone 插件,CI 检测到 N+1 报错即为不合格。 +* **批量操作**: 循环插入/更新必须使用 bulk\_create / bulk\_update。 +* **迭代**: 遍历大表必须使用 .iterator()。 + +### **7.2 异步视图** + +* **场景限制**: 仅在 **高并发 I/O 密集型** (如聚合多个第三方 API) 场景下使用。 +* **实现方案**: 统一使用 adrf 库。 +* **禁止事项**: 严禁在 async def 中运行 CPU 密集型任务 (Pandas/图片处理)。严禁混用同步 ORM 方法。 + +### **7.3 异步任务** + +* **选型**: 统一使用 Celery \+ Redis。 +* **剥离标准**: 耗时 \> 200ms 的逻辑 (邮件、报表、AI推理) 必须剥离到后台任务。 +* **事务安全**: 必须使用 transaction.on\_commit 触发任务。 + +### **7.4 缓存** + +* **组件**: 统一使用 django-redis。 +* **策略**: 强制使用 Cache-Aside (旁路缓存) 策略。 + +## **8\. 日志与异常规范 (Logs)** + +### **8.1 异常处理** + +**配置**: + +1. 必须在 settings.py 中配置 EXCEPTION\_HANDLER 指向 `apps.common.exceptions.gtcoai_exception_handler`。 +2. 异常处理器需将所有 DRF 异常 (APIException) 和 未知异常 (Exception) 统一转化为标准 JSON 响应结构。 + +### **8.2 日志配置** + +**工具**: 统一使用 Loguru。 + +**配置要求**: + +1. **拦截**: 必须通过 InterceptHandler 接管 Django 原生日志。 +2. **输出**: + * 控制台: 彩色文本。 + * 文件: JSON 格式 (serialize=True),便于采集。 + +## **9\. 认证与权限规范 (Auth)** + +### **9.1 认证架构 (Authentication Strategy)** + +**核心方案**:采用 JWT (JSON Web Token) 作为无状态认证标准,库选型锁定 djangorestframework-simplejwt。 + +**单点登录 (SSO) 集成**: + +**架构选型**:强制使用 django-allauth 处理 OAuth 协议握手,配合 dj-rest-auth 暴露 REST 接口。严禁手写 OAuth2 流程。 + +**交互流程**:采用 "Authorization Code" 模式。前端仅负责获取第三方(如 Google/GitHub)的 code,后端负责用 code 换取用户信息并颁发本系统的 JWT。严禁后端直接信任前端传来的第三方用户信息。 + +**账号融合**:强制实施“基于邮箱的自动关联”策略。无论用户是通过账号密码注册,还是通过 SSO 登录,只要邮箱一致,必须关联到同一个 User 实体,确保用户身份唯一性。 + +### **9.2 Token安全与管理 (Token Engineering)** + +**载荷 (Payload) 规范**: + +**最小化原则**:Token 内仅允许携带非敏感的身份标识(如 user\_id, role, username)。 + +**扩展方式**:必须通过继承 TokenObtainPairSerializer 并重写 get\_token 方法注入自定义声明。严禁修改库源码或在 View 层手动拼凑 Token。 + +**生命周期管理**: + +双 Token 机制:强制启用 Access Token 与 Refresh Token 分离。 + +* Access Token 有效期:**固定 24 小时**(与 `settings/components/drf.py` 保持一致)。 +* Refresh Token 有效期:**固定 7 天**。 + +**黑名单机制**:生产环境必须启用 Blacklist 应用,确保用户注销或修改密码后,旧的 Refresh Token 立即失效。 + +### **9.3 权限分层治理 (Permission Governance)** + +**默认策略**:实施 "Default Deny" (默认拒绝) 策略。全局配置 (DEFAULT\_PERMISSION\_CLASSES) 必须设为 IsAuthenticated,仅对特定公开接口(如注册、登录、健康检查)显式配置 AllowAny。 + +在 ViewSet 中,严禁使用静态的 permission\_classes 列表覆盖所有方法。 + +**动作级权限 (Action-Based)**: + +**实现规范**:必须重写 get\_permissions() 方法,根据 self.action(如 create, list, destroy)动态分配权限(例如:所有人可注册,登录用户可查看,仅管理员可删除)。 + +**系统动作策略优先 (System Policy First)**:当接口涉及“资源 + 动作”权限时,必须先校验系统级资源动作策略(资源支持动作 + 系统禁用动作),再进入组织角色与成员授权判断。严禁仅依赖成员授权直接放行不受系统支持的动作。 + +**对象级权限 (Object-Level)**: + +涉及“只能操作自己的数据”或“组内可见”的场景,严禁在 View 的业务逻辑中写 if user \== owner。 + +**实现规范**:必须自定义继承自 BasePermission 的权限类,并重写 has\_object\_permission 方法,将鉴权逻辑与业务逻辑物理隔离。 + +### **9.4 安全加固 (Security Hardening)** + +**CSRF 防护**:所有 POST/PUT/PATCH/DELETE 请求必须包含 CSRF Token,全局配置 (CSRF\_COOKIE\_HTTPONLY) 设为 True。 + +**防爆破 (Throttling)**:所有认证相关接口(登录、注册、刷新 Token、SSO 回调)必须配置高强度的限流策略(如 AnonRateThrottle),防止暴力破解。 + +**错误模糊化**:认证失败时,统一返回“用户名或密码错误”或“认证失败”,严禁明确提示“用户不存在”或“密码错误”,防止用户信息泄露。 + +## **10\. 测试规范 (Testing)** + +### **10.1 工具链** + +* **Runner**: 统一使用 pytest \+ pytest-django。 +* **Data**: 统一使用 factory\_boy。 +* **Client**: 统一使用 APIClient (DRF)。 +* **Coverage**: 统一使用 pytest-cov。 + +### **10.2 编写规范** + +* **Fixture**: 通用对象定义在 conftest.py。 +* **Mock**: 外部 API 调用**必须** Mock,禁止在测试中发起真实网络请求。 +* **真实链路验证例外**: 对 `apps/externals` 的代理/权限链路改动,允许并要求使用 `scripts/external/` 下脚本做“联调验证”,但该验证不替代 pytest。 +* **提交门禁**: 上述改动在合并前必须同时满足“脚本联调通过 + 相关 pytest 用例通过”。 +* **执行**: CI 环境需开启 pytest-xdist 并行执行。 + +### **10.3 当前项目固定测试命令 (提交前最低要求)** + +1. 外部资源治理与代理相关改动:必须运行 `pytest apps/externals/tests.py`。 +2. 用户/组织/认证相关改动:必须运行 `pytest apps/user/tests.py`。 +3. 同时改动 `user + externals`:必须同时运行以上两组用例,禁止只跑局部单测后直接提交。 + +### **10.4 CI 固定执行链路 (禁止绕过)** + +1. 本仓库唯一质量门禁脚本:`scripts/ci/quality_gate.sh`。 +2. 脚本执行顺序固定为:`ruff format --check` -> `ruff check` -> `pytest apps/user/tests.py` -> `pytest apps/externals/tests.py`。 +3. 当前阶段(Docker 开发流程)提交前必须本地执行该脚本;任一步失败不得提交。 +4. CI 启用后,流水线必须在构建前执行该脚本;任一步失败即阻断后续阶段。 +5. 禁止在本地或 CI 中通过 `|| true`、跳过测试参数、或删改步骤顺序绕过门禁。 + +### **10.5 提交审查规范** + +代码审查流程与输出模板统一见: + +`docs/development/code_review_guidelines.md` + +## **11\. 文档管理规范 (Documentation)** + +本章节拆分为独立文档,减少主规范长度并便于专项维护。 + +详见:`docs/development/documentation_standards.md` + +最低强制要求: + +1. 核心业务改动必须同步更新测试与文档。 +2. OpenAPI 注解必须完整(`@extend_schema`)。 +3. 文档冲突时以 `docs/development/standards.md` 为准。 + +## **12\. Dify 代理模块规范 (Dify Proxy Module)** + +本章节拆分为独立文档,避免主规范过长。 + +详见:`docs/development/dify_proxy_standards.md` + +最低强制要求: + +1. 代理层无状态、无业务存储。 +2. 路由常量统一由 `interfaces.py` 维护,禁止硬编码 URL。 +3. 保持全异步链路并统一错误处理。 + +## **13\. 全局权限治理落地文档** + +权限治理的可执行实施方案(角色矩阵、Scope 规范、分阶段改造、验收清单)见: + +`docs/plans/permission_governance_plan.md` \ No newline at end of file