docs(specs): add AGENTS.md and engineering guidelines
项目尚无统一工程规范,AI 助手与研发各自发挥导致返工风险。建立 总纲 + 细则两层结构:AGENTS.md 只写硬约束与索引(14 条红线、技术栈 基线、仓库结构、命令契约),细则拆为 10 份文档覆盖 Git、代码风格、 格式化、API 与路由、数据库、测试与 CI、Review、日志、密钥、资产命名。 影响面:仅文档。约束力从本轮起对新建代码生效;与现状冲突处以文档为准。 回滚方式:git revert 本提交。
This commit is contained in:
1 parent
d062d79465
commit
00ae12435e
12 files changed
+1562
No files matched your search
@@ -0,0 +1,131 @@
|
||||
# 02 · 代码风格
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 文档版本 | V1.0(2026-11-02) |
|
||||
| 依据 | 技术架构 §2.2 / §2.3 / §10.1 |
|
||||
| 适用范围 | `apps/` `packages/` `prisma/` `infra/` 全部 TypeScript / JavaScript |
|
||||
| 强制级别 | 强制(标注「建议」的除外) |
|
||||
|
||||
> 格式问题交给 Prettier(见 [03](03-格式化与Lint.md)),本文只约定**格式化管不到**的部分。
|
||||
|
||||
---
|
||||
|
||||
## 1 命名
|
||||
|
||||
| 对象 | 规则 | 示例 |
|
||||
| --- | --- | --- |
|
||||
| 目录 / 文件 | kebab-case | `ai-routes/`、`script-task.service.ts` |
|
||||
| React 组件文件 | PascalCase.tsx | `ScriptCard.tsx` |
|
||||
| 变量 / 函数 | camelCase | `nextCursor`、`resolveScope()` |
|
||||
| 类型 / 接口 / 类 | PascalCase | `MediaTask`、`StorageProvider` |
|
||||
| 常量(模块级不可变) | UPPER_SNAKE | `MAX_UPLOAD_MB` |
|
||||
| 布尔 | `is/has/can/should` 前缀 | `isArchived`、`hasPermission` |
|
||||
| 事件回调 | 属性 `onXxx`,处理器 `handleXxx` | `onSelect` / `handleSelect` |
|
||||
| 异步动作 | 动词开头,返回 Promise | `createBatch()` |
|
||||
| 数据库表 / 列 | snake_case(Prisma `@@map` / `@map`) | `media_tasks`、`customer_id` |
|
||||
| 权限点常量 | `UPPER_SNAKE`,与库内 code 一致 | `SCRIPT_APPROVE` |
|
||||
|
||||
- `CS-01` 禁止拼音命名(`shangpin`);业务术语用 PRD 术语表英文(`briefCard`、`videoDirection`、`shot`)。
|
||||
- `CS-02` 单字母变量只允许循环下标 `i/j` 与泛型 `T/K/V`。
|
||||
- `CS-03` 缩写词按单词大小写:`s3Key`、`httpClient`、`ulid`,不写 `S3Key` / `HttpClient` 混排。
|
||||
|
||||
---
|
||||
|
||||
## 2 类型
|
||||
|
||||
- `CS-04` `strict: true`,禁止 `any`、隐式 `any`、`@ts-ignore`;确需忽略用 `@ts-expect-error` 并写原因。
|
||||
- `CS-05` 禁止用 `as` 做类型断言绕过检查;只允许「收窄断言」(`as const`、`as unknown as X` 需注释理由)。
|
||||
- `CS-06` 对外导出的函数 / 方法**必须显式标注返回类型**,内部函数可推断。
|
||||
- `CS-07` 对象契约用 `interface`,联合 / 工具 / 映射类型用 `type`;二者不混用于同一实体。
|
||||
- `CS-08` 业务枚举用 `as const` 对象 + 派生联合类型,**禁止 TS `enum`**;库内枚举由字典表提供(Prisma enum 仅用于永不扩展的封闭集合,需迁移评审说明)。
|
||||
- `CS-09` 泛型参数 ≥ 2 个或含义不清时必须命名(`<TInput, TOutput>`),禁止全用 `T`。
|
||||
- `CS-10` 禁止在业务代码中出现 `object`、`Function`、`{}` 作为类型;用具体形状或 `Record<string, unknown>`。
|
||||
|
||||
---
|
||||
|
||||
## 3 函数与结构
|
||||
|
||||
- `CS-11` 函数单一职责,建议 ≤ 50 行;超过则拆分。
|
||||
- `CS-12` 参数 > 3 个必须用对象参数;可选参数不用位置占位。
|
||||
- `CS-13` 嵌套 ≤ 3 层,用**早返回**替代 `else` 链。
|
||||
- `CS-14` 禁止魔法值:数字 / 字符串常量抽到 `constants` 或读取系统配置(PRD R-26)。
|
||||
- `CS-15` 单文件 ≤ 400 行;超出按职责拆分(Controller / Service / Repository 各自成文件)。
|
||||
- `CS-16` 禁止循环依赖;跨包引用只从包 `index.ts` 出口导入。
|
||||
|
||||
---
|
||||
|
||||
## 4 错误处理
|
||||
|
||||
- `CS-17` 统一抛 `AppError(code, message, details?)`,`code` 取错误码表(见 [04](04-API与路由规范.md) §4);**禁止 `throw new Error('...')` 直接面向用户**。
|
||||
- `CS-18` 禁止 `catch` 后空吞;要么处理、要么包装后重抛,并保留 `cause`。
|
||||
- `CS-19` `async` 函数必须有 `await` 或显式 `void`;禁止 floating promise。
|
||||
- `CS-20` 外部调用(AI / 存储 / ffmpeg)必须设置超时 + 分类重试;**内容违规类错误不重试**。
|
||||
- `CS-21` 任务(BullMQ)处理器必须**幂等**:以 `taskItemId` 为幂等键,重复执行结果一致。
|
||||
- `CS-22` 前端错误:路由级 ErrorBoundary + 请求层统一 toast,禁止页面内零散 `alert`。
|
||||
|
||||
---
|
||||
|
||||
## 5 注释与文档
|
||||
|
||||
- `CS-23` 注释解释**为什么**,不复述代码;业务规则必须引用 PRD 编号:`// R-04 查询必须带 customer_id`。
|
||||
- `CS-24` 导出 API 写 JSDoc(用途、参数、错误码、副作用);内部实现按需。
|
||||
- `CS-25` TODO 格式:`// TODO(@owner, 2026-12-01): 原因与后续`;禁止无主 TODO。
|
||||
- `CS-26` 禁止提交注释掉的整段代码;历史查 git。
|
||||
- `CS-27` 不写「本次改动」「新增」这类时间性注释,注释描述当下状态。
|
||||
|
||||
---
|
||||
|
||||
## 6 导入顺序
|
||||
|
||||
按组排序,组间空行,组内按字母序(由 ESLint `simple-import-sort` 自动修复):
|
||||
|
||||
```
|
||||
1. Node 内置(node:fs)
|
||||
2. 第三方(@nestjs/*、zod)
|
||||
3. workspace 包(@lingxi/shared、@lingxi/ui)
|
||||
4. 应用内绝对路径(~/ 或 @/)
|
||||
5. 相对路径(./、../)
|
||||
6. 样式 / 资源(*.css、*.svg?raw)
|
||||
```
|
||||
|
||||
- `CS-28` 禁止 `import * as X` 整包导入(图标包、UI 包尤甚,会破坏 tree-shaking)。
|
||||
- `CS-29` 图标只从 `packages/ui/icons.ts` 导入语义名(`import { IconScript } from '@lingxi/ui/icons'`),禁直接引 `remixicon` 具体路径。
|
||||
- `CS-30` 禁 `export *` 聚合无审阅的公共 API;`index.ts` 显式列出导出。
|
||||
|
||||
---
|
||||
|
||||
## 7 React / 前端
|
||||
|
||||
- `CS-31` 只用函数组件 + Hooks;禁 class 组件、禁 `React.FC`(返回类型写 `ReactNode` / `JSX.Element`)。
|
||||
- `CS-32` 服务端数据只用 TanStack Query(`useQuery` / `useMutation`);**禁止**在 `useEffect` 里手写 fetch + 自建缓存。
|
||||
- `CS-33` 全局状态只放跨页共享且非服务端数据(Zustand);页面内状态用 `useState` / `useReducer`,禁止为省 props 上全局。
|
||||
- `CS-34` 列表 `key` 用业务 ID,禁止 `index`。
|
||||
- `CS-35` 组件文件导出一个主组件;子组件同文件时用内部函数,跨文件复用必须提为独立组件。
|
||||
- `CS-36` 样式只用 Semi design token(`cssVar`)/ CSS Modules;**禁止散落十六进制色值**、禁止行内 style 做主题。
|
||||
- `CS-37` 文案集中在 `packages/ui/locale`(zh-CN),组件内不写死中文用户可见文案(日志与注释除外)。
|
||||
- `CS-38` 表单走 `packages/form-engine` 的 schema 渲染;**禁止**在业务页面手写动态字段映射(会绕过白名单校验)。
|
||||
|
||||
---
|
||||
|
||||
## 8 后端
|
||||
|
||||
- `CS-39` 分层职责:Controller 只解析入参 / 组装响应;Service 承载业务规则与状态机;Repository 是唯一访问 Prisma 的层。
|
||||
- `CS-40` Repository 方法**必须接收 `ScopeContext`** 作为首个参数,禁止在 Repository 内部从全局取当前用户。
|
||||
- `CS-41` 模块间只通过 Service 接口或领域事件通信;禁止跨模块注入 `PrismaService` 直接查表。
|
||||
- `CS-42` 状态迁移集中在 Service 的状态机函数内,禁止 Controller 直接改 `status` 字段。
|
||||
- `CS-43` 事务边界在 Service;事务内**禁止**外部 IO(AI 调用、HTTP、对象存储)。
|
||||
- `CS-44` 队列任务只做「可重试的纯执行」,业务校验与成本预占在 API 层完成。
|
||||
|
||||
---
|
||||
|
||||
## 9 检查清单
|
||||
|
||||
- [ ] 命名符合 §1,无拼音、无缩写混排
|
||||
- [ ] 无 `any` / `@ts-ignore` / 滥用 `as`
|
||||
- [ ] 函数 ≤ 50 行、文件 ≤ 400 行、嵌套 ≤ 3 层
|
||||
- [ ] 错误统一 `AppError`,无空 catch
|
||||
- [ ] 队列任务幂等,外部调用有超时
|
||||
- [ ] 图标 / UI 从统一出口导入
|
||||
- [ ] 业务规则注释带 R-xx
|
||||
- [ ] 无魔数、无硬编码阈值
|
||||
Reference in new issue
Block a user