# 开发规范 AI 工具必须严格遵守以下全部约束。 ## 专题文档 | 文档 | 内容 | | ---------------------------------- | ---------------------------------- | | [architecture.md](architecture.md) | 项目结构、启动流程、前后端边界 | | [backend.md](backend.md) | 模块 API、数据访问函数、AI 层说明 | | [frontend.md](frontend.md) | 组件索引、页面组成、hooks/工具清单 | | [release.md](release.md) | 开发服务、构建、脚本、环境变量 | --- ## 一、全局规则 ### 语言与环境 - 使用中文编写注释、文档和交流内容。 - 仅使用 bun 作为包管理器和 bunx 作为工具运行器;禁止 npm、pnpm、yarn、npx、pnpx。 - 无需考虑向前兼容。 ### 依赖引入 **后端**优先级(上层已有方案则不得引入新依赖): 1. Bun 内置 API(Bun.serve、bun:sqlite 等) 2. es-toolkit 3. 标准 Web API(fetch、Headers 等) 4. 已批准三方库:pino、@sinclair/typebox、ajv、drizzle-orm、ai、@ai-sdk/\* 5. 自行实现(仅以上都不满足时) **前端**:优先复用已有组件/hooks/依赖库;确需新增依赖时先说明原因。 **Zod**:AI 工具层(`src/server/ai/tools/`)使用 Zod 定义 `tool()` 的 `inputSchema`,以满足 AI SDK 对 `ZodSchema` 的类型推断要求,属于框架级约束而非项目选型冲突。配置校验层使用 TypeBox + Ajv,两层级各司其职,不混用。 ### 目录边界 | 目录 | 约束 | | ------------------------ | -------------------------------------------- | | `src/server/` | 后端,禁止 import src/web/ | | `src/server/db/` | 数据库层:schema、connection、migration、DAO | | `src/server/ai/` | AI Provider Registry + Agent + 工具 | | `src/server/helpers/` | 跨路由工具:响应格式化、URL 拼接 | | `src/server/middleware/` | 参数校验 + 错误处理中间件 | | `src/web/` | 前端,禁止 import src/server/ 运行时实现 | | `src/web/consoles/` | 控制台外壳(Admin / Workbench) | | `src/shared/` | 前后端共享类型(api.ts)和常量(app.ts) | | `scripts/` | 独立脚本,可 import 项目源码 | | `drizzle/` | SQL migration 文件(开发期产出) | | `tests/` | 测试目录,镜像 src/ 结构 | ### 类型与配置 - 共享类型唯一源头:`src/shared/api.ts`;应用常量唯一源头:`src/shared/app.ts`;版本号唯一源头:`package.json`。 - 配置加载流程:unknown → AuthoringConfig → NormalizedConfig → ValidatedConfig → ServerConfig。 - Ajv 严格拒绝模式:不类型转换、不注入默认值、不删除未知字段。 - 新增/修改配置字段必须同步更新 TypeBox schema、`config.schema.json`、测试和用户文档。 ### 后端日志 - 运行时代码通过 Logger 接口输出,禁止 `console.*`(仅 `logger.ts` 实现类内部可用)。 - 敏感字段(authorization、cookie、password 等)自动 redact。 ### API 路由 - 每个端点一个文件:`src/server/routes/{资源}/{操作}.ts`。 - 路由在 `server.ts` 的 `Bun.serve({ routes })` 中声明式注册。 - 新增路由:创建 handler → 在 `server.ts` 注册 → 在 `tests/server/` 添加测试。 ### 前端数据层 - 统一使用 `fetch`,不引入 axios。 - 错误抛异常,TanStack Query error 状态承接。 - 返回类型必须匹配后端 JSON 形状;包装对象(如 `{ project }`)须在 hook 内提取业务对象。 - 服务端状态用 TanStack Query,组件内状态用 `useState`,不引入额外状态管理库。 ### 禁止事项 - 禁止前端 import `src/server/` - 禁止后端使用 `console.*` - 禁止组件内联 `style` 属性 - 禁止 CSS 覆盖 `.ant-*` 内部类名 - 禁止 `!important` - 禁止硬编码色值(使用 `var(--ant-*)` CSS 变量) - 禁止路由 handler 直接操作 `bun:sqlite` / Drizzle ORM(须通过 DAO 层) - 禁止跳过或忽略测试 - 禁止在 `Modal onOk` 中直接执行异步提交(用 `Form onFinish`) --- ## 二、后端红线 ### 路由 handler - 签名:`(req: Request, db: Database, mode: RuntimeMode, logger?: Logger): Promise`。 - 业务错误:`jsonResponse(createApiError(msg, status), { mode, status })`;未知异常直接 throw,`withErrorHandler` 兜底。 - body 解析后立即校验必填字段和类型,失败返回 400。 - ID 参数走 `validateIdParam`,分页参数走 `validatePagination`。 - 路由注册:`withErrorHandler` 包裹 + 动态 `await import()` 加载 handler。 ### 数据访问层 - handler 通过 `src/server/db/*.ts` 函数操作数据库,禁止直接使用 `bun:sqlite` 或 Drizzle。 - DAO 函数第一个参数接收原始 `Database`,内部 `wrap(db)` 转 Drizzle。 - 返回联合类型:成功 `{ resource: T }`,失败 `{ error: string; status: number }`。 - 输入输出类型来自 `src/shared/api.ts`。 - 列表查询使用 `paginateQuery()`,不重复实现分页。 - 列名 snake_case,TS 类型 camelCase,Drizzle schema 映射。 ### AI 调用层 - Provider 实例:`buildProviderRegistry(db)`,每次从 DB 重建,不缓存。 - Agent 实例:`createAlfredAgent(model)` 工厂。 - SSE 响应:`createAgentUIStreamResponse`,`onFinish` 持久化完整 parts。 - 工具定义:`src/server/ai/tools/`。 ### 错误处理 - 业务异常用 `AppError(statusCode)` 或 `jsonResponse(createApiError(...))`。 - handler 外层 `withErrorHandler` 兜底,不手动 try-catch 整个 handler。 - 生产模式错误响应不暴露内部细节。 --- ## 三、前端红线 ### 组件规范 - 优先 antd 默认能力 + props,不额外改写视觉。 - `ConfigProvider(zhCN)` 配置中文 locale 和主题,不在 CSS 硬编码亮/暗分支。 - 应用级能力(message、modal、notification)通过 `AntApp` + `App.useApp()` 获取。 - 页面保持编排职责,组合 hooks + 展示组件;复杂页面按功能边界拆分。 ### 能力优先级(上层满足则不用下层) 1. antd 组件/props 2. antd 布局组件(Layout、Space、Flex) 3. antd theme token + CSS 变量 4. TanStack Query + useState 5. 已有 hooks(`use-*.ts`)和工具函数(`utils/`) 6. CSS Modules(就近放置) 7. 引入新依赖(需说明原因) ### 样式红线 - 严禁内联 `style`、覆盖 `.ant-*`、`!important`、硬编码色值。 - 颜色使用 `var(--ant-*)` CSS 变量。 - 不引入 Tailwind/Sass/Less/CSS-in-JS 等额外样式方案。 - 全局 CSS 类名用 `app-*` 前缀,禁止泛名。样式增长后用 CSS Modules 就近维护。 ### 表单与交互 - Modal + Form:`Form onFinish` 处理提交,`Modal onOk` 只调 `form.submit()`。 - 必填文本字段同时配 `required` + `whitespace`。 - 操作确认用 `Popconfirm`,反馈用 antd message。 ### 错误边界 - 生产入口必须启用 `ErrorBoundary`。`ReactQueryDevtools` 仅 `DEV` 模式渲染。 --- ## 四、测试规范 ### 后端 - 路由测试通过真实 `startServer` 覆盖路由注册、HTTP method、fallback、header 和核心错误路径。 - SQLite 测试复用 `tests/helpers.ts`,不分散实现临时目录清理。 - DAO/路由测试优先用真实 migration 初始化。 - logger/bootstrap fallback 输出须捕获断言,正常测试不污染 stdout/stderr。 ### 前端 - 目录 `tests/web/`,结构对应 `src/web/`。 - 用 jsdom + `@testing-library/react` 测试用户行为,断言基于可见文本/role/按钮。 - 系统边界复用 `tests/web/test-utils.tsx`。 - 数据页面覆盖:请求参数、成功可见结果、关键错误路径。 - ErrorBoundary/hooks/fetch helper 用单元测试覆盖异常,页面测试只保留用户路径。 --- ## 常用命令 | 命令 | 说明 | | -------------------------------- | -------------------------------------- | | `bun run dev config.yaml` | 启动双进程开发环境 | | `bun run dev:server config.yaml` | 仅后端 API server | | `bun run dev:web` | 仅 Vite dev server | | `bun run check` | schema:check + typecheck + lint + test | | `bun run verify` | check + build 完整验证 | | `bun run build` | 构建生产可执行文件 | | `bun run schema` | 生成 config.schema.json | | `bun run schema:check` | 检查 schema 同步 | | `bun run typecheck` | TypeScript 类型检查 | | `bun run lint` | ESLint + Prettier 检查 | | `bun run format` | Prettier 格式化 | | `bun test` | 运行全部测试 | | `bun run clean` | 清理构建缓存 | | `bun run version:patch` | 升迁 patch 版本 | | `bun run version:minor` | 升迁 minor 版本 | | `bun run version:major` | 升迁 major 版本 | | `bun run version:set` | 显式设置版本号 | ## 质量门禁 | 变更类型 | 必跑命令 | | ----------------------- | --------------------------------------------------------- | | 常规代码变更 | `bun run check` | | 构建、部署、集成变更 | `bun run verify` | | 配置 schema 变化 | `bun run schema`、`bun run schema:check`、`bun run check` | | SQLite 测试基础设施变化 | 相关测试 + SQLite 聚焦 `--rerun-each` + `bun run check` | | 仅文档变更 | 检查链接、索引和文档归属一致性 | 正式提交优先运行 `bun run verify`。无法执行时须在收尾说明中记录。 ## 已知设计决策 | 决策 | 原因 | | -------------------------- | ----------------------------------------------------------------------------------------- | | Provider.apiKey 返回给前端 | 个人项目,apiKey 非严格密码,前端需要展示和编辑。如需保护,应改为返回脱敏值或仅后端存储。 | ## 文档影响分析 | 变更影响 | 更新 | | -------------------------------------- | ------------------------------------------ | | 用户可见行为、配置、部署、运行行为 | `docs/user/` 对应文档 | | 开发流程、架构、测试、构建发布流程 | `docs/development/` 对应文档 | | 项目定位、快速开始、核心能力、文档导航 | `README.md` | | 文档同步规则或归属矩阵 | `docs/README.md` 和 `openspec/config.yaml` | | 开发规范变化 | 本文档对应章节 | 无需更新文档时,须在收尾说明中说明原因。 ## 更新触发条件 修改常用命令、质量门禁、开发规范(任何章节)、目录边界或开发文档索引时,必须更新本文档。 ### 文档编撰规范 本节开发文档面向 AI 工具阅读,编撰时遵循以下原则: **精简原则** - 删除引导语、适用场景、过渡句等装饰性文字。AI 无需"应首先阅读"或"本文档说明…"类引导。 - 不重复项目结构树,AI 可通过 glob 获取目录结构。 - 不重复已在 README.md 声明的规范细节,专题文档只记录实现层面的函数签名、API 端点、模块职责等索引信息。 - 表格标题自明时不再加说明段落。 **信息完整性** - 所有函数签名、API 端点(方法+路径+说明)、数据访问函数清单必须完整列举,不可用"等"省略。 - 页面行为描述须包含关键交互逻辑(如 Tab 切换、默认值、条件跳转、测试不阻止保存等),不可只写组件名。 - 配置文件列表必须完整,不可遗漏已有文件。 **结构规范** - 每个专题文档末尾保留 `## 更新触发条件` 章节,明确列出哪些变更必须更新该文档。 - 用表格和编号列表替代散文段落,减少 token 消耗。 - 同一信息只在一处维护,避免多处重复导致不一致。