From d765f86b6597b5a6c280b59e5440c6a866172ed5 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Mon, 1 Jun 2026 13:13:52 +0800 Subject: [PATCH 1/4] =?UTF-8?q?docs:=20=E6=96=87=E6=A1=A3=E5=85=A8?= =?UTF-8?q?=E9=9D=A2=E5=AE=A1=E6=9F=A5=E6=9B=B4=E6=96=B0=E4=B8=8E=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E9=9B=86=E4=B8=AD=E5=8C=96=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 42 ++++--- docs/development/README.md | 202 +++++++++++++++++++++++-------- docs/development/architecture.md | 95 ++++++++++----- docs/development/backend.md | 100 +++++---------- docs/development/frontend.md | 201 +++++++----------------------- docs/development/release.md | 9 ++ docs/user/deploy.md | 4 +- docs/user/usage.md | 2 - 8 files changed, 324 insertions(+), 331 deletions(-) diff --git a/docs/README.md b/docs/README.md index 12f20b1..8b0c565 100644 --- a/docs/README.md +++ b/docs/README.md @@ -31,11 +31,11 @@ docs/ ## 入口文档 -| 入口 | 定位 | -| --------------------------------- | -------------------------------------- | -| [项目 README](../README.md) | 项目整体介绍、快速开始、文档引导 | -| [开发文档](development/README.md) | 开发入口、全局规则、常用命令、质量门禁 | -| [用户文档](user/README.md) | 使用、配置、部署、排障入口 | +| 入口 | 定位 | +| --------------------------------- | -------------------------------------------------------- | +| [项目 README](../README.md) | 项目整体介绍、快速开始、文档引导 | +| [开发文档](development/README.md) | 开发入口、**全部开发规范**、常用命令、质量门禁、专题索引 | +| [用户文档](user/README.md) | 使用、配置、部署、排障入口 | ## 按任务阅读路径 @@ -54,28 +54,30 @@ docs/ ## 文档归属矩阵 -| 变更类型 | 默认更新位置 | -| --------------------------------------------------------- | ---------------------------------------- | -| 项目定位、核心能力、快速开始、顶层文档导航 | `README.md` | -| 文档路由、文档更新规则、文档归属矩阵 | `docs/README.md`、`openspec/config.yaml` | -| 开发入口、常用命令、质量门禁、全局工程规则、OpenSpec 约定 | `docs/development/README.md` | -| 架构边界、启动流程、运行时流程、前后端边界 | `docs/development/architecture.md` | -| 后端 API、配置加载、logger、helpers、类型规范、后端测试 | `docs/development/backend.md` | -| 前端技术栈、组件、样式、数据层、前端测试 | `docs/development/frontend.md` | -| 构建、发布、脚本、前后端静态资源集成 | `docs/development/release.md` | -| 快速开始、安装配置 | `docs/user/usage.md` | -| YAML 配置、变量语法、server/storage/logging、JSON Schema | `docs/user/config.md` | -| 生产构建、可执行文件运行、运行时配置 | `docs/user/deploy.md` | -| 常见运行问题、配置校验、变量解析、构建失败 | `docs/user/troubleshoot.md` | +| 变更类型 | 默认更新位置 | +| -------------------------------------------------------- | ---------------------------------------- | +| 项目定位、核心能力、快速开始、顶层文档导航 | `README.md` | +| 文档路由、文档更新规则、文档归属矩阵 | `docs/README.md`、`openspec/config.yaml` | +| 开发规范(全局规则、库优先级、类型规范、样式、测试等) | `docs/development/README.md` | +| 开发入口、常用命令、质量门禁、目录边界、OpenSpec 约定 | `docs/development/README.md` | +| 架构边界、启动流程、运行时流程、前后端边界 | `docs/development/architecture.md` | +| 后端模块 API、工具函数索引、数据库 schema、AI 层实现 | `docs/development/backend.md` | +| 前端运行时代码结构、组件索引、页面组成、hooks/工具清单 | `docs/development/frontend.md` | +| 构建、发布、脚本、前后端静态资源集成 | `docs/development/release.md` | +| 快速开始、安装配置 | `docs/user/usage.md` | +| YAML 配置、变量语法、server/storage/logging、JSON Schema | `docs/user/config.md` | +| 生产构建、可执行文件运行、运行时配置 | `docs/user/deploy.md` | +| 常见运行问题、配置校验、变量解析、构建失败 | `docs/user/troubleshoot.md` | ## development 文档如何更新 开发文档解释"如何实现和维护"。代码变更影响开发者理解、开发流程、测试方式或架构边界时,必须更新 `docs/development/` 对应文档。 - 全局规则、常用命令、质量门禁、目录边界、OpenSpec 约定更新到 `docs/development/README.md`。 +- **全部开发规范**(全局规则、后端规范、前端通用规范、样式规范、测试规范)统一维护在 `docs/development/README.md`。 - 架构图、启动链路、运行时流程、前后端边界更新到 `docs/development/architecture.md`。 -- 后端 API、配置加载、logger、helpers、类型规范和后端测试规范更新到 `docs/development/backend.md`。 -- 前端技术栈、组件边界、数据流、样式规则和前端测试规范更新到 `docs/development/frontend.md`。 +- 后端模块 API、工具函数索引、数据库 schema、AI 层实现、日志模块更新到 `docs/development/backend.md`。 +- 前端运行时代码结构、组件索引、页面组成、hooks/工具清单更新到 `docs/development/frontend.md`。 - 构建、脚本和发布验证更新到 `docs/development/release.md`。 - 不新增"杂项"开发文档;优先把内容放入上述最贴近的专题,确需新增专题时先更新本文档和 `openspec/config.yaml`。 diff --git a/docs/development/README.md b/docs/development/README.md index 3a3d4ff..1430188 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -1,18 +1,157 @@ # 开发文档 -本文档是 alfred 的开发入口。AI 工具和开发者应先阅读 [`../README.md`](../README.md) 判断文档归属,再阅读本文和最小必要专题。 +本文档是 alfred 的开发入口,包含**全部开发规范**和专题索引。AI 工具和开发者应首先阅读本文档掌握所有约束,再按需查阅专题文档获取实现细节。 适用场景:修改源码、测试、构建脚本、开发流程、架构边界或项目工程规则。 ## 专题索引 -| 文档 | 内容 | -| ---------------------------------- | ---------------------------------------------------------------- | -| [architecture.md](architecture.md) | 项目结构、启动流程、运行时流程、HTTP 请求流程、前后端边界 | -| [backend.md](backend.md) | 后端库优先级、API 路由、共享工具、类型规范、配置契约、日志、测试 | -| [frontend.md](frontend.md) | React、Ant Design、TanStack Query、组件、样式和前端测试规范 | -| [release.md](release.md) | 开发服务、前后端集成、构建、脚本、环境变量 | -| [../README.md](../README.md) | 文档路由、文档归属矩阵、development/user 文档更新规则 | +| 文档 | 内容 | +| ---------------------------------- | ----------------------------------------------------------------- | +| [architecture.md](architecture.md) | 项目结构、启动流程、运行时流程、HTTP 请求流程、前后端边界 | +| [backend.md](backend.md) | 后端实现细节:模块 API、工具函数索引、数据访问函数清单、AI 层说明 | +| [frontend.md](frontend.md) | 前端实现细节:运行时代码结构、组件索引、页面组成、hooks/工具清单 | +| [release.md](release.md) | 开发服务、前后端集成、构建、脚本、环境变量 | +| [../README.md](../README.md) | 文档路由、文档归属矩阵、文档更新规则 | + +--- + +# 开发规范 + +以下规范是所有代码变更必须遵守的约束。AI 工具必须严格遵守,开发者 review 时以此为准。 + +## 一、全局规则 + +### 语言与环境 + +- 使用中文编写注释、文档和项目内交流内容。 +- 仅使用 bun 作为包管理器,禁止使用 npm、pnpm、yarn。 +- 运行工具使用 bunx,禁止使用 npx、pnpx。 +- 当前项目无需考虑向前兼容。 + +### 依赖引入 + +**后端**:新增依赖前必须按以下优先级检查,上层已有方案则不得引入新依赖: + +| 优先级 | 来源 | 典型用途 | +| ------ | ------------ | ---------------------------------------------------- | +| 1 | Bun 内置 API | Bun.serve、Bun.file、Bun.YAML、Bun.spawn、bun:sqlite | +| 2 | es-toolkit | 类型判断、深度比较、并发控制 | +| 3 | 标准 Web API | Headers、fetch、AbortController | +| 4 | 主流三方库 | pino、@sinclair/typebox、ajv、drizzle-orm | +| 5 | 自行实现 | 仅在以上都无法满足时 | + +**前端**:新增代码优先复用已有组件、工具和依赖库,不引入新依赖。确需新增依赖时先说明原因。 + +### Git 提交 + +- 提交信息使用中文,格式为 `类型: 简短描述`。 +- 提交类型限定为:`feat`、`fix`、`refactor`、`docs`、`style`、`test`、`chore`。 +- 多行提交描述时,标题和正文之间空一行。 + +### 目录边界 + +| 目录 | 约定 | +| ------------------- | -------------------------------------------------------------------- | +| `src/server/` | Bun 后端代码,不能 import src/web/,HTML import 集成除外 | +| `src/server/db/` | SQLite 数据库模块,包含 schema、connection、migration 和 data access | +| `src/server/ai/` | AI Provider Registry 构建与连接测试 | +| `src/web/` | React 前端,不能 import src/server/ 运行时实现 | +| `src/shared/` | 前后端共享 TypeScript 类型 | +| `scripts/` | 独立运行脚本,可 import 项目源码 | +| `drizzle/` | Drizzle Kit 生成的 SQL migration 文件(开发期产出) | +| `tests/` | 测试目录,结构镜像 src/ | +| `docs/user/` | 用户使用、配置、部署和排障文档 | +| `docs/development/` | 架构、后端、前端、发布开发文档 | +| `openspec/` | OpenSpec 变更管理与规格文档 | + +### 类型与配置 + +- 共享类型以 `src/shared/api.ts` 为唯一源头。 +- 应用常量以 `src/shared/app.ts` 为唯一源头。 +- 版本号以 `package.json.version` 为唯一源头。 +- 前端不得 import `src/server/` 下的任何文件。 +- 配置加载流程固定为:unknown → AuthoringConfig → NormalizedConfig → ValidatedConfig → ServerConfig。 +- Ajv 保持严格拒绝模式:不开类型强制转换、不注入默认值、不自动删除未知字段。 +- 新增或修改配置字段时必须同步更新 TypeBox schema fragments、`config.schema.json`、测试和对应用户文档。 + +### 后端日志 + +- 后端运行时代码统一通过 Logger 接口输出日志,禁止直接使用 `console.*`(仅 `src/server/logger.ts` 的实现类内部可用)。 +- 敏感信息自动 redact `authorization`、`cookie`、`password` 等字段。 + +### API 路由 + +- 路由文件位于 `src/server/routes/`,每个端点一个文件。 +- 路由通过 `server.ts` 的 `Bun.serve({ routes })` 声明式注册。 +- 新增路由步骤:创建 handler 文件 → 在 `server.ts` 注册 → 在 `tests/server/` 添加测试。 + +### 前端数据层 + +- 统一使用 `fetch`,不引入 axios。 +- 错误抛异常,由 TanStack Query 的 error 状态承接。 +- 前端 fetch 返回类型必须匹配后端真实 JSON 形状;后端返回包装对象(如 `{ project: Project }`)时,应声明对应响应类型并在 hook 内提取业务对象。 +- 不引入额外状态管理库。TanStack Query 承担服务端状态,组件内状态使用 `useState`。 + +--- + +## 二、前端红线 + +### 组件红线 + +- 优先使用 antd 组件默认能力和 props 配置行为,不额外改写组件视觉。 +- 全局使用 `ConfigProvider` 配置中文 locale 和主题切换,不在 CSS 中硬编码亮色或暗色分支。 +- 需要 message、modal、notification 等应用级能力时,在 `ConfigProvider` 内包裹 `App`(代码中别名为 `AntApp`),组件内通过 `App.useApp()` 获取。 +- 页面组件保持编排职责,组合 hooks 和展示组件;当页面同时承担查询、筛选、分页、表格列、弹窗表单和 mutation 时,应按功能边界拆分。 + +### 样式红线 + +- **严禁**在组件中使用 `style` 属性内联样式。 +- **严禁**通过 CSS 覆盖 antd 组件内部类名(`.ant-*`)。 +- **严禁**使用 `!important`。 +- **严禁**使用硬编码色值,颜色统一使用 antd CSS 变量(`var(--ant-*)`)。 +- 默认不引入 Tailwind、Sass、Less、CSS-in-JS 等额外样式方案;确需引入时必须先说明原因和影响范围。 + +### 样式指导原则 + +- antd 承担主视觉系统,项目 CSS 只补足页面外壳和局部布局,不另起一套样式体系。 +- 样式选择优先级:antd 默认能力 → antd props → antd 布局组件 → theme token → antd CSS 变量 → 全局 CSS。 +- 全局 CSS 仅承载应用外壳和基础样式,类名使用 `app-*` 前缀,禁止泛名类(如 `.container`、`.title`)。 +- 当样式需求增长到需要就近维护时,使用 CSS Modules 与页面/组件同级放置。 + +### 表单与交互 + +- Modal + Form 提交使用 `Form onFinish` 处理业务提交,`Modal onOk` 只触发 `form.submit()`。 +- 不在 `Modal onOk` 中直接执行异步 `validateFields` 和提交逻辑。 +- 文本必填字段同时配置 `required: true` 和 `whitespace: true`,保持前后端校验一致。 +- 操作确认优先使用 `Popconfirm`,成功/失败反馈优先使用 antd message。 + +### 错误边界 + +- 生产入口必须启用 `ErrorBoundary`。 +- `ReactQueryDevtools` 仅在 `import.meta.env.DEV` 条件下渲染。 + +--- + +## 三、测试规范 + +### 后端测试 + +- API 路由集成测试必须通过真实 `startServer` 覆盖路由注册、HTTP method、fallback、响应 header 和核心错误路径。 +- SQLite 相关测试必须复用 `tests/helpers.ts` 中的测试数据库 helper,不要在测试文件内分散实现临时目录清理。 +- DAO 和路由边界测试应优先使用真实 migration 初始化测试库。 +- logger/bootstrap 中预期的 fallback 输出必须在测试中捕获并断言,正常通过的测试不应污染 stdout/stderr。 + +### 前端测试 + +- 测试目录为 `tests/web/`,结构对应 `src/web/`。 +- 组件测试使用 jsdom 和 `@testing-library/react`,测试用户行为而非实现细节。 +- 断言优先基于用户可见文本、role、按钮和交互结果,不依赖 `.ant-*` 内部类名。 +- 系统边界(fetch mock、路由、QueryClientProvider)优先复用 `tests/web/test-utils.tsx`。 +- 数据驱动页面至少覆盖请求 URL/query、method/body、成功后的用户可见结果,以及关键错误路径。 +- ErrorBoundary、hooks 纯逻辑和 fetch helper 应使用单元测试覆盖异常回退,页面测试只保留真实用户路径。 + +--- ## 常用命令 @@ -54,46 +193,10 @@ ## 已知设计决策 -本节记录项目中有意保留的设计决策,避免后续审查重复报错。 - | 决策 | 原因 | | -------------------------- | ----------------------------------------------------------------------------------------- | | Provider.apiKey 返回给前端 | 个人项目,apiKey 非严格密码,前端需要展示和编辑。如需保护,应改为返回脱敏值或仅后端存储。 | -## 全局工程规则 - -- 使用中文编写注释、文档和项目内交流内容。 -- 仅使用 bun 作为包管理器,禁止使用 npm、pnpm、yarn。 -- 运行工具使用 bunx,禁止使用 npx、pnpx。 -- 新增代码优先复用已有组件、工具和依赖库,不引入新依赖;确需新增依赖时先说明原因。 -- 后端优先使用 Bun 内置 API,其次是 es-toolkit、标准 Web API、主流三方库,最后才自行实现。 -- 前端优先使用 Ant Design 组件默认能力和组件 props 组合界面,具体组件、样式、数据流和测试细节见 [frontend.md](frontend.md)。 -- 当前项目无需考虑向前兼容。 - -## 包管理、依赖与提交 - -- 仅使用 bun 安装依赖和运行项目脚本,锁文件为 bun.lock。 -- 新增依赖前先确认 Bun 内置 API、es-toolkit、标准 Web API、现有三方库和项目公共工具是否已满足需求。 -- Git 提交信息使用中文,格式为"类型: 简短描述"。 -- 提交类型限定为 feat、fix、refactor、docs、style、test、chore。 -- 多行提交描述时,标题和正文之间空一行。 - -## 目录边界 - -| 目录 | 约定 | -| ------------------- | -------------------------------------------------------------------- | -| `src/server/` | Bun 后端代码,不能 import src/web/,HTML import 集成除外 | -| `src/server/db/` | SQLite 数据库模块,包含 schema、connection、migration 和 data access | -| `src/server/ai/` | AI Provider Registry 构建与连接测试 | -| `src/web/` | React 前端,不能 import src/server/ 运行时实现 | -| `src/shared/` | 前后端共享 TypeScript 类型 | -| `scripts/` | 独立运行脚本,可 import 项目源码 | -| `drizzle/` | Drizzle Kit 生成的 SQL migration 文件(开发期产出) | -| `tests/` | 测试目录,结构镜像 src/ | -| `docs/user/` | 用户使用、配置、部署和排障文档 | -| `docs/development/` | 架构、后端、前端、发布开发文档 | -| `openspec/` | OpenSpec 变更管理与规格文档 | - ## 文档影响分析 每次代码变更都必须执行文档影响分析。 @@ -104,17 +207,10 @@ | 开发流程、架构、测试、构建发布流程 | `docs/development/` 对应文档 | | 项目定位、快速开始、核心能力列表、文档导航 | `README.md` | | 文档同步规则或文档归属矩阵 | `docs/README.md` 和 `openspec/config.yaml` | +| 开发规范变化 | 本文档对应章节 | 如果无需更新文档,必须在收尾说明中说明原因。详细规则见 [文档总览](../README.md)。 -## 事实来源 - -| 主题 | 事实来源 | -| -------------- | -------------------------------------------------- | -| 代码结构和实现 | `src/`、`scripts/`、`tests/` | -| 配置 schema | TypeBox fragments、config.schema.json、schema 测试 | -| 项目全局规则 | `openspec/config.yaml`、本文档、本目录专题文档 | - ## 更新触发条件 -修改常用命令、质量门禁、全局工程规则、目录边界或开发文档索引时,必须更新本文档。 +修改常用命令、质量门禁、开发规范(任何章节)、目录边界或开发文档索引时,必须更新本文档。 diff --git a/docs/development/architecture.md b/docs/development/architecture.md index 10080e3..f609f44 100644 --- a/docs/development/architecture.md +++ b/docs/development/architecture.md @@ -11,8 +11,19 @@ src/ server/ bootstrap.ts 统一启动引导(loadServerConfig -> DB 初始化 -> startServer) config.ts CLI 参数解析与配置文件加载 facade - config/ 配置解析模块(types、issues、variables、normalizer、schema) + config/ 配置解析模块 + index.ts 配置模块导出 + types.ts 配置类型定义 + issues.ts 配置问题收集 + variables.ts 变量解析 + normalizer.ts 配置标准化 + schema/ JSON Schema 生成与校验 + builder.ts + export.ts + fragments.ts + validate.ts db/ SQLite 数据库模块 + index.ts 数据库模块导出 schema.ts Drizzle ORM schema 定义 connection.ts 数据库连接与 PRAGMA 设置 load-migrations.ts 从文件系统加载 migration SQL @@ -20,8 +31,7 @@ src/ projects.ts 项目数据访问函数 providers.ts 供应商数据访问函数 models.ts 模型数据访问函数 - conversations.ts 会话数据访问函数 - index.ts 数据库模块导出 + conversations.ts 会话与消息数据访问函数 ai/ AI 服务层 types.ts AI 配置类型定义 registry.ts AI Provider Registry 构建与连接测试 @@ -33,28 +43,47 @@ src/ main.ts 生产模式启动入口 server.ts HTTP server 启动工厂(Bun.serve routes 声明式路由) static.ts 生产模式静态资源服务 - helpers.ts 共享响应格式化工具 - middleware.ts API 参数校验中间件 + helpers/ 共享工具模块 + index.ts 模块导出 + response.ts 响应格式化工具 + url.ts URL 拼接工具 + middleware/ API 中间件模块 + index.ts 模块导出 + validate.ts 参数校验中间件 + error-handler.ts 错误处理中间件 logger.ts 结构化日志(基于 pino + pino-roll) version.ts 运行时版本号读取 routes/ API 路由处理器 - providers/ 供应商 CRUD 路由 - models/ 模型 CRUD 路由 - chat/ 聊天会话与消息路由 + meta.ts 应用元信息路由 + providers/ 供应商 CRUD 与测试路由 + models/ 模型 CRUD 与测试路由 + projects/ 项目 CRUD、归档与恢复路由 + chat/ 聊天会话与消息路由(含 SSE 流式发送) shared/ api.ts 前后端共享 TypeScript 类型定义 app.ts 应用全局常量(name、title、subtitle、description) web/ React 前端(通过 Vite 构建) index.html HTML 入口 - main.tsx React 入口 - app.tsx 根组件 - routes.tsx 路由配置 + main.tsx React 入口(StrictMode + ErrorBoundary + QueryClientProvider + BrowserRouter) + app.tsx 根组件(设置 document 标题和 meta) + routes.tsx 路由配置(Admin + Workbench 两大控制台) + menu.tsx 共享菜单项类型定义 styles.css 全局样式 + css.d.ts CSS Modules 类型声明 pages/ 页面组件 - models/ 模型管理页面 - components/ UI 组件 - hooks/ React Hooks - utils/ 前端工具函数 + dashboard/ 总览页面 + projects/ 项目管理页面及其子组件 + models/ 模型管理页面及其子组件 + 404/ 404 页面 + components/ 共享 UI 组件 + ErrorBoundary.tsx 错误边界 + ConsoleShell/ 通用控制台外壳(ConsoleShell、ConsoleOutlet、types) + Sidebar/ 侧边栏导航组件 + consoles/ 控制台入口 + admin/ Admin 管理台(AdminConsoleLayout、菜单配置) + workbench/ Workbench 工作台(ProjectGate、ConsoleLayout、菜单配置、ChatPage 等) + hooks/ React Hooks(use-meta、use-projects、use-providers、use-models、use-conversations、主题/侧边栏偏好) + utils/ 前端工具函数(fetch 封装、时间格式化) scripts/ 独立运行脚本 tests/ 测试文件(镜像 src 目录结构) docs/ 项目文档 @@ -85,7 +114,7 @@ dev.ts / main.ts Request -> Bun.serve routes 声明式匹配 -> routes/*.ts handler - -> helpers.ts 响应格式化 + -> helpers/ 响应格式化 -> Response ``` @@ -102,17 +131,29 @@ Request ## 主要模块职责 -| 模块 | 职责 | -| ------------------------- | --------------------------------------------- | -| `src/server/bootstrap.ts` | 统一启动引导、DB 初始化和 shutdown 编排 | -| `src/server/server.ts` | Bun HTTP server 和 routes 注册 | -| `src/server/routes/` | API handler,按端点拆分 | -| `src/server/db/` | SQLite 连接、schema、migration 和 data access | -| `src/server/ai/` | AI Provider Registry 构建与 Agent 流式调用 | -| `src/server/config/` | 配置解析模块(types、variables、schema) | -| `src/web/` | React 前端 | -| `src/shared/api.ts` | 前后端共享 API 类型 | -| `src/shared/app.ts` | 应用全局常量 | +| 模块 | 职责 | +| ------------------------- | ---------------------------------------------------------------------- | +| `src/server/bootstrap.ts` | 统一启动引导、DB 初始化和 shutdown 编排 | +| `src/server/server.ts` | Bun HTTP server 和 routes 注册 | +| `src/server/routes/` | API handler,按资源端点拆分(meta、providers、models、projects、chat) | +| `src/server/db/` | SQLite 连接、schema、migration 和 data access | +| `src/server/ai/` | AI Provider Registry 构建与 Agent 流式调用 | +| `src/server/config/` | 配置解析模块(types、variables、normalizer、schema) | +| `src/server/helpers/` | 共享响应格式化和 URL 工具 | +| `src/server/middleware/` | API 参数校验和错误处理中间件 | +| `src/web/` | React 前端(Admin + Workbench 双控制台架构) | +| `src/shared/api.ts` | 前后端共享 API 类型 | +| `src/shared/app.ts` | 应用全局常量 | + +### 路由按资源分组 + +| 资源分组 | 路径前缀 | 路由文件 | +| --------- | ------------------------------------------------------------- | ---------------------------- | +| meta | `/api/meta` | `routes/meta.ts` | +| providers | `/api/providers` | `routes/providers/` (7 文件) | +| models | `/api/models` | `routes/models/` (6 文件) | +| projects | `/api/projects` | `routes/projects/` (7 文件) | +| chat | `/api/projects/:id/conversations` 和 `/api/projects/:id/chat` | `routes/chat/` (7 文件) | ## 更新触发条件 diff --git a/docs/development/backend.md b/docs/development/backend.md index a39c5eb..7075b1e 100644 --- a/docs/development/backend.md +++ b/docs/development/backend.md @@ -1,45 +1,31 @@ # 后端开发 -本文档说明 alfred 后端的 API、配置加载、日志、版本管理和后端测试开发约定。 +本文档说明 alfred 后端的模块实现细节、API 索引和开发方式。开发规范(库优先级、类型规范、配置契约、API 路由规范、测试约定等)见 [开发规范文档](README.md#开发规范)。 -适用场景:修改 src/server/、src/shared/api.ts、后端测试、配置契约、API 响应或日志模块。 - -## 库使用优先级 - -| 优先级 | 来源 | 典型用途 | -| ------ | ------------ | ---------------------------------------------------- | -| 1 | Bun 内置 API | Bun.serve、Bun.file、Bun.YAML、Bun.spawn、bun:sqlite | -| 2 | es-toolkit | 类型判断、深度比较、并发控制 | -| 3 | 标准 Web API | Headers、fetch、AbortController | -| 4 | 主流三方库 | pino、@sinclair/typebox、ajv、drizzle-orm | -| 5 | 自行实现 | 仅在以上都无法满足时 | - -新增依赖前必须先检查上述每一层是否已有可用方案。 - -## API 路由开发 - -路由文件位于 src/server/routes/,每个端点一个文件。路由通过 server.ts 的 Bun.serve({ routes }) 声明式注册。 - -新增路由步骤: - -1. 在 src/server/routes/ 下创建 .ts -2. 实现 handler 函数并 export -3. 在 server.ts 的 routes 对象中注册路径和 method handler -4. 在 tests/server/ 中添加对应测试 +适用场景:修改 `src/server/`、了解现有模块 API、查找可供复用的工具函数和数据访问接口。 ## 共享工具 -helpers.ts 提供跨路由共用的响应工具: +`src/server/helpers/` 提供跨路由共用的工具模块: -- createApiError(error, status) — 构造 API 错误体 -- createHeaders(mode, init) — 创建响应 Headers -- jsonResponse(body, options) — JSON 响应构造 +- `response.ts` — 响应格式化工具: + - `createApiError(error, status)` — 构造 API 错误体 + - `createHeaders(mode, init)` — 创建响应 Headers(生产模式附加安全 header) + - `createMetaResponse(version)` — 构造应用元信息响应 + - `formatDuration(ms)` — 格式化毫秒时长为可读字符串 + - `jsonResponse(body, options)` — JSON 响应构造 +- `url.ts` — URL 工具: + - `parseIdFromUrl(url)` — 从 URL 解析路径中的 ID -middleware.ts 提供 API 参数校验函数: +`src/server/middleware/` 提供 API 参数校验和错误处理中间件: -- validateIdParam(idStr, mode) — 校验 ID 参数格式 -- validatePagination(pageParam, pageSizeParam, mode) — 校验分页参数 -- validateTimeRange(from, to, mode) — 校验时间范围参数 +- `validate.ts` — 参数校验函数: + - `validateIdParam(idStr, mode)` — 校验 ID 参数格式(字母数字 + `_` `-`) + - `validatePagination(pageParam, pageSizeParam, mode)` — 校验分页参数(page 最小 1,pageSize 最大 200) + - `validateTimeRange(from, to, mode)` — 校验时间范围参数 +- `error-handler.ts` — 错误处理中间件: + - `AppError` — 业务异常类(含 statusCode) + - `withErrorHandler(fn, mode, logger?)` — 包裹路由 handler,捕获 AppError 和未知异常 ## 数据库 @@ -62,7 +48,7 @@ middleware.ts 提供 API 参数校验函数: ### 数据访问 -`src/server/db/projects.ts` 提供项目数据访问函数,`src/server/db/providers.ts` 提供供应商数据访问函数,`src/server/db/models.ts` 提供模型数据访问函数,`src/server/db/conversations.ts` 提供会话和消息数据访问函数。输入输出使用 `src/shared/api.ts` 的类型。函数内部使用 Drizzle query builder 包装 `bun:sqlite` Database。 +`src/server/db/projects.ts` 提供项目数据访问函数(`createProject`、`getProject`、`listProjects`、`updateProject`、`deleteProject`、`archiveProject`、`restoreProject`)。`src/server/db/providers.ts` 提供供应商数据访问函数(`createProvider`、`getProvider`、`listProviders`、`listProviderOptions`、`updateProvider`、`deleteProvider`)。`src/server/db/models.ts` 提供模型数据访问函数(`createModel`、`getModel`、`listModels`、`getModelsByProviderId`、`updateModel`、`deleteModel`)。`src/server/db/conversations.ts` 提供会话和消息数据访问函数(`createConversation`、`getConversation`、`listConversations`、`updateConversation`、`updateConversationTimestamp`、`deleteConversation`、`createMessage`、`createMessages`、`listMessages`)。`src/server/db/connection.ts` 还提供 `paginateQuery` 和 `wrap` 工具函数。输入输出使用 `src/shared/api.ts` 的类型。函数内部使用 Drizzle query builder 包装 `bun:sqlite` Database。 ## AI 服务层 @@ -82,6 +68,8 @@ middleware.ts 提供 API 参数校验函数: - `buildProviderRegistry(db)` — 从 DB 查询所有供应商,构建 Vercel AI SDK Provider Registry - `testProviderConnection(config)` — 先测试 Base URL 可达性,再请求 `/models` 验证 API Key 和模型列表接口 +- `testModelConnection(config)` — 先通过 providerId 查询供应商(含 apiKey),再以 modelId 请求对应模型的 API 连通性 +- `countModels(db)` — 统计 DB 中已配置的模型总数,用于 Agent 调用前的可用性检查 每次 AI 调用时从 DB 查询 providers,构建 registry 后通过 `registry.languageModel('providerId:modelId')` 获取模型实例。不使用缓存层。模型是否存在以及业务能力标签由调用方基于 models 表先行校验,registry 只负责将 providerId/modelId 映射到 AI SDK 模型实例。 @@ -115,31 +103,16 @@ middleware.ts 提供 API 参数校验函数: | GET | `/api/projects/:id/conversations` | 列出项目下所有会话 | | POST | `/api/projects/:id/conversations` | 创建新会话 | | GET | `/api/projects/:id/conversations/:cid` | 获取会话详情 | +| PATCH | `/api/projects/:id/conversations/:cid` | 更新会话标题或模型 | | DELETE | `/api/projects/:id/conversations/:cid` | 删除会话及其消息 | | GET | `/api/projects/:id/conversations/:cid/messages` | 获取会话消息列表 | | POST | `/api/projects/:id/chat` | 发送消息并流式回复 | 聊天路由处理器位于 `src/server/routes/chat/`,遵循统一的 handler 模式。`send.ts` 处理发送消息:验证会话归属后只保存最后一条用户消息到 DB,通过 `createAlfredAgent` 创建 agent,调用 `createAgentUIStreamResponse` 返回 SSE UI 消息流,流结束通过 `onFinish` 回调保存 AI 回复到 DB。 -## 类型规范 - -- 共享类型以 src/shared/api.ts 为唯一源头 -- 应用常量以 src/shared/app.ts 为唯一源头 -- 版本号以 package.json.version 为唯一源头 -- 前端不得 import src/server/ 下的任何文件 -- 严格联合类型优先于宽类型 - -## 配置契约 - -配置加载流程固定为:unknown -> AuthoringConfig -> NormalizedConfig -> ValidatedConfig -> ServerConfig。 - -Ajv 保持严格拒绝模式:allErrors: true、不启用类型强制转换、不注入默认值、不自动删除未知字段。 - -新增或修改配置字段时必须同步更新 TypeBox schema fragments、config.schema.json、测试和对应用户文档。 - ## 日志模块 -后端运行时代码统一通过 Logger 接口输出日志,禁止直接使用 console.\*。 +后端运行时代码统一通过 Logger 接口输出日志。 | 实现 | 用途 | | --------------------- | ------------------------ | @@ -148,16 +121,14 @@ Ajv 保持严格拒绝模式:allErrors: true、不启用类型强制转换、 | NoopLogger | 静默丢弃日志 | | MemoryLogger | 测试替身 | -敏感信息会自动 redact authorization、cookie、password 等字段。 - ## 版本管理 -项目使用 package.json.version 作为版本号唯一来源。 +版本号以 `package.json.version` 为唯一来源。 版本获取方式: -- 开发模式:src/server/version.ts 运行时从 package.json 读取 -- 生产模式:scripts/build.ts 在构建时将版本号烘焙为字面量注入 +- 开发模式:`src/server/version.ts` 运行时从 package.json 读取 +- 生产模式:`scripts/build.ts` 在构建时将版本号烘焙为字面量注入 版本升迁命令: @@ -168,21 +139,6 @@ bun run version:major # 升迁 major 版本 bun run version:set # 显式设置版本号 ``` -## 后端测试 - -| 变更类型 | 测试重点 | -| ------------------ | --------------------------------- | -| API 路由 | tests/server/app.test.ts 集成行为 | -| 配置 schema | schema 导出、合法/非法配置 | -| helpers/middleware | 单元测试 | - -后端测试约定: - -- API 路由集成测试必须通过真实 `startServer` 覆盖路由注册、HTTP method、fallback、响应 header 和核心错误路径。 -- SQLite 相关测试必须复用 `tests/helpers.ts` 中的测试数据库 helper,不要在测试文件内分散实现临时目录清理或直接裸用 `rmSync(dir, { recursive: true })`。 -- DAO 和路由边界测试应优先使用真实 migration 初始化测试库,只有 migration 执行器单测可以使用最小 fake migration。 -- logger/bootstrap 中预期的 fallback 输出必须在测试中捕获并断言,正常通过的测试不应污染 stdout/stderr。 - ## 更新触发条件 -修改后端 API、共享类型、配置契约、日志模块、版本管理或后端测试规范时,必须更新本文档。 +修改后端模块 API、共享工具、数据库 schema、AI 服务层或聊天 API 时,必须更新本文档。 diff --git a/docs/development/frontend.md b/docs/development/frontend.md index cfb6fdb..f741db1 100644 --- a/docs/development/frontend.md +++ b/docs/development/frontend.md @@ -1,181 +1,72 @@ # 前端开发 -本文档说明 alfred 前端的 React、Ant Design、TanStack Query、组件、样式和前端测试约定。 +本文档说明 alfred 前端的运行时代码结构、组件索引和页面组成。开发规范(组件规范、Ant Design 用法、样式规则、表单交互、TanStack Query、测试约定等)见 [开发规范文档](README.md#开发规范)。 -适用场景:修改 src/web/、前端共享类型使用方式、组件结构、样式规则或前端测试。 +适用场景:修改 `src/web/`、了解现有组件和页面结构、查找 hooks 和工具函数。 -## 技术栈 - -| 层面 | 技术 | 用途 | -| ------ | --------------------------------------------------- | ------------------------ | -| 框架 | React 19 | UI 组件开发 | -| 构建 | Vite(开发)+ Bun compile(生产) | 开发服务 HMR 与生产构建 | -| 语言 | TypeScript | 类型安全 | -| UI 库 | Ant Design (antd) + @ant-design/icons | UI 组件与图标 | -| 数据层 | TanStack Query (React Query) + React Query Devtools | 服务端状态管理与自动刷新 | -| AI 层 | Vercel AI SDK (`@ai-sdk/react`) | 聊天状态管理与流式通信 | -| 路由 | React Router v7 (Declarative mode) | SPA 路由与页面导航 | - -不引入额外状态管理库。TanStack Query 承担服务端状态,组件内状态使用 useState。 - -## 组件开发规范 - -- 每个 React 组件一个 .tsx 文件,文件名使用 PascalCase -- 组件 props 定义为 interface XxxProps,紧邻组件函数声明 -- 类型从 src/shared/api.ts 导入,使用 import type -- 展示组件放在 components/,通过 props 接收数据,通过回调返回事件;页面专属展示组件可就近放在 pages/\*/components/ -- 容器逻辑放在 hooks 中,组件只做数据消费;全局共享查询可提取为独立 hook(如 use-meta) -- 工具函数放在 utils/,保持纯函数无副作用 - -页面组件保持编排职责,组合 hooks 和展示组件;当页面同时承担查询、筛选、分页、表格列、弹窗表单和 mutation 时,应按工具栏、表格、表单弹窗等功能边界拆分。拆分以降低职责复杂度为目标,避免为了拆分而拆分。 - -## Ant Design 使用规范 - -- 优先使用 antd 组件默认状态和官方交互模式;没有明确产品定制需求时,不额外改写组件视觉。 -- 优先通过组件 props 配置行为和外观,例如 `collapsible`、`theme`、`scroll`、`locale`、`status`、`variant`、`color`。 -- 全局使用 `ConfigProvider` 配置 antd 中文 locale;从 `antd/locale/zh_CN` 导入 `zhCN`。 -- 需要 message、modal、notification 等 antd 应用级能力时,在 `ConfigProvider` 内包裹 `App`(代码中可别名为 `AntApp`),组件内通过 `App.useApp()` 获取。 -- 状态页、异常页、空结果优先使用 `Result`、`Empty`、`Alert`、`Spin` 等 antd 组件。 -- 信息展示优先使用 `Typography`、`Card`、`Descriptions`、`Table` 等 antd 组件,避免用原生标签加自定义 CSS 复刻。 -- 搜索输入优先使用 `Input.Search`,保持回车搜索、按钮搜索和清空行为一致。 -- 表格在窄屏有挤压风险时必须提供明确的 `scroll` 或响应式列策略。 - -## 样式开发规范 - -前端基于 Ant Design 构建 UI。样式管理目标是让 antd 继续承担主视觉系统,项目 CSS 只补足页面外壳、局部布局和自有组件视觉,不另起一套与 antd 竞争的样式体系。 - -样式开发优先级: - -1. antd 组件默认能力,例如 `Button`、`Card`、`Table`、`Form`、`Result`、`Empty`。 -2. antd 组件 props,例如 `size`、`type`、`variant`、`color`、`status`、`layout`、`scroll`、`gutter`。 -3. antd 布局组件,例如 `Layout`、`Flex`、`Space`、`Row`、`Col`,避免为普通排列关系新增 CSS。 -4. `ConfigProvider` theme token 和 antd 组件 token,处理主题级或组件级统一调整。 -5. antd CSS 变量(`--ant-*`),用于项目自有 CSS 中引用颜色、间距、字体、圆角和阴影等设计值。 -6. 全局 CSS,仅承载应用外壳、全局基础样式和少量明确复用的工具类。 -7. CSS Modules,用于页面专属布局或项目自有组件视觉;仅在局部样式增长到需要就近维护时使用。 -8. 自行开发视觉组件,仅在 antd 组件和组合方式无法表达明确产品需求时使用。 - -红线: - -- 严禁在组件中使用 `style` 属性内联调整样式。 -- 严禁通过 CSS 覆盖 antd 组件内部类名,例如 `.ant-*`。 -- 严禁使用 `!important`。 -- 颜色统一使用 antd Design Token / CSS 变量,不使用硬编码色值。 -- 默认不引入 Tailwind、UnoCSS、Sass、Less、CSS-in-JS 或额外 PostCSS 插件;确需引入时必须先说明现有 antd + CSS Modules 无法满足的具体问题、影响范围和迁移成本。 - -默认状态原则:如果 antd 组件默认样式已经满足当前需求,不为其增加额外 CSS 类;不要通过外层 CSS 修改 Sider、Menu、Table、Modal 等组件内部结构样式。 - -全局 CSS 归属: - -- 当前入口保留 `src/web/styles.css`;当文件继续增长时,优先拆分为 `src/web/styles/global.css`、`src/web/styles/app-shell.css`、`src/web/styles/utilities.css` 等按职责命名的文件,再由入口样式文件集中导入。 -- `global.css` 仅放 `html`、`body`、`:root`、字体渲染、全局背景等应用级基础样式。 -- `app-shell.css` 仅放应用外壳样式,例如 `app-layout`、`app-header`、`app-content`、Header 内容分布和主内容间距。 -- `utilities.css` 只放至少两处复用、语义稳定、不会与 antd props 重叠的工具类;只有一处使用时优先改为 antd 布局组件或局部 CSS Modules。 -- 全局类名必须带有明确前缀,应用外壳使用 `app-*`,工具类使用 `u-*`;禁止新增 `.container`、`.title`、`.content` 等容易跨页面冲突的泛名类。 - -CSS Modules 归属: - -- 页面专属样式与页面就近放置,例如 `src/web/pages/projects/projects.module.css`。 -- 自有组件样式与组件就近放置,例如 `src/web/components/FooCard/foo-card.module.css`。 -- CSS Modules 中类名使用职责语义,例如 `.root`、`.toolbar`、`.summaryCard`、`.emptyState`;通过导入对象绑定到组件,避免字符串拼写散落。 -- 同一类样式只服务当前页面或组件;一旦被多处复用,应先判断能否用 antd 组件或 props 表达,再考虑提取共享组件,而不是直接提升为全局 CSS。 -- 首次实际使用 `*.module.css` 时,同步补全 TypeScript 声明和必要测试,确保类型检查与构建链路稳定。 - -antd 定制边界: - -- 优先使用官方 props、theme token 和组件 token;不要因为视觉微调直接写 CSS。 -- antd v6 组件暴露 `classNames` 语义插槽时,可以把项目自有类绑定到官方稳定插槽;仍然不得选择 `.ant-*` 内部 DOM 类名。 -- 避免使用 antd `styles` 语义插槽写内联样式;如果必须使用,应先评估是否可以通过 token、CSS 变量或 CSS Modules 表达。 -- 弹窗、下拉、表格、菜单等复杂组件不依赖内部 DOM 结构做布局修补;发现必须修补时,优先调整组件组合或交互设计。 - -token 和 CSS 变量规则: - -- 颜色使用 `var(--ant-color-*)`,例如文本、边框、背景和状态色。 -- 间距、字号、圆角和阴影优先使用 `var(--ant-padding-*)`、`var(--ant-margin-*)`、`var(--ant-font-size-*)`、`var(--ant-border-radius*)`、`var(--ant-box-shadow*)` 等 antd 变量。 -- 项目自定义 CSS 变量只能定义在 `:root` 或清晰的主题容器上,并且必须基于 antd token 派生;不要创建与 antd 平行的颜色、间距、字号体系。 -- 主题切换统一通过 `ConfigProvider` theme algorithm 和 token 控制,不在 CSS 中硬编码亮色或暗色分支。 - -响应式规则: - -- 页面必须在桌面和移动端正常加载和可读。 -- 优先使用 antd `Flex`、`Grid`、`Table scroll`、响应式列配置处理布局收缩。 -- 媒体查询只处理页面或自有组件的布局断点;不要用媒体查询覆盖 antd 内部结构。 -- 移动端适配优先保证内容可访问、操作可点击和横向溢出可控,不追求与桌面完全一致的排版。 - -新增样式前检查: - -1. 这个需求是否可以由 antd 组件或 props 完成? -2. 这个样式是否属于主题级统一调整,应该放到 `ConfigProvider` theme token? -3. 这个样式是否只服务页面外壳,应该留在全局 CSS? -4. 这个样式是否只服务单个页面或自有组件,应该使用 CSS Modules? -5. 这个样式是否在覆盖 antd 内部结构?如果是,应重新设计组件组合。 -6. 这个样式是否引入了硬编码色值、`style`、`.ant-*` 或 `!important`?如果是,不应合入。 - -## 表单与交互规范 - -- Modal + Form 提交使用 `Form onFinish` 处理业务提交,`Modal onOk` 只触发 `form.submit()`。 -- 不在 `Modal onOk` 中直接执行异步 `validateFields` 和提交逻辑,也不通过 lint disable 绕过该问题。 -- 文本必填字段同时配置 `required: true` 和 `whitespace: true`,保持前端校验与后端 trim 后校验一致。 -- 提交中状态传给 antd 组件的 loading/confirmLoading 等 props,避免自行实现重复状态样式。 -- 操作确认优先使用 `Popconfirm`,成功/失败反馈优先使用 antd message。 - -## 运行时外壳规范 +## 运行时外壳 前端提供两个入口外壳,共享通用 Console Shell 组件: -- **Admin(管理台)**:`src/web/consoles/admin/AdminConsoleLayout.tsx`,菜单配置在 `menu.tsx`,路由 `/`、`/projects`、`/models`。 -- **Workbench(工作台)**:`src/web/consoles/workbench/WorkbenchProjectGate.tsx` → `WorkbenchConsoleLayout.tsx`,菜单配置和路由构造在 `routes.ts`,路由 `/workbench/:projectId`。默认菜单为"聊天室",使用 `ChatPage` 作为主页面。 +- **Admin(管理台)**:`src/web/consoles/admin/AdminConsoleLayout.tsx`,菜单配置在 `src/web/consoles/admin/menu.tsx`,路由 `/`(总览)、`/projects`(项目管理)、`/models`(模型管理)。 +- **Workbench(工作台)**:`src/web/consoles/workbench/WorkbenchProjectGate.tsx` → `WorkbenchConsoleLayout.tsx`,菜单配置和路由构造在 `src/web/consoles/workbench/routes.ts`,路由 `/workbench/:projectId` 和 `/workbench/:projectId/chat`。默认菜单为"聊天室"。 -通用 Console Shell(`src/web/components/ConsoleShell/ConsoleShell.tsx`)包含 Layout、Header、Sider、Content、主题切换、版本展示和侧边栏折叠状态,由 Admin 和 Workbench 复用。Header 显示品牌名、版本号和控制台标题(Admin 显示"管理台",Workbench 显示"工作台 · 项目名")。 +通用 Console Shell(`src/web/components/ConsoleShell/ConsoleShell.tsx`)包含 `ConfigProvider`(zhCN locale)、`AntApp`、`Layout`、`Header`、`Sider`、`Content`、主题切换(明亮/黑暗/系统)和侧边栏折叠状态,由 Admin 和 Workbench 复用。Header 显示品牌名、版本号和控制台标题(Admin 显示"管理台",Workbench 显示"工作台 · 项目名")。 + +Menu 类型定义在 `src/web/menu.tsx` 中的 `MenuItemConfig` 接口(icon、label、path、value)。 Sidebar(`src/web/components/Sidebar/index.tsx`)是纯展示/导航组件,通过 `menuItems` props 接收菜单配置,由调用方决定菜单内容和路径。Admin 传入静态路径 `/`、`/projects`、`/models`;Workbench 通过 route builder(`buildWorkbenchPath`)将相对菜单路径拼成 `/workbench/:projectId` 的子路径。 -Workbench 项目上下文通过 `ProjectContext` 提供,在 `WorkbenchProjectGate` 中从 URL path param 读取 `projectId`,通过 `useProject(projectId)` 加载项目,仅 active 项目渲染工作台布局,不存在或 archived 项目显示"项目不存在或不可访问"。 +Workbench 项目上下文通过 `ProjectContext`(`src/web/consoles/workbench/ProjectContext.tsx` 和 `ProjectContextValue.ts`)提供,在 `WorkbenchProjectGate` 中从 URL path param 读取 `projectId`,通过 `useProject(projectId)` 加载项目,仅 active 项目渲染工作台布局,不存在或 archived 项目显示"项目不存在或不可访问"。 -模型管理页面(`src/web/pages/models/index.tsx`)属于 Admin 路由 `/models`,通过 antd `Tabs` 在同页组织供应商和模型两个视图。页面使用 `ModelsToolbar`、`ProviderTable`、`ProviderFormModal`、`ModelTable`、`ModelFormModal` 拆分筛选、表格和表单职责;模型表单和模型表格必须使用 `GET /api/providers/options` 获取最小供应商选项,不能复用供应商标签页当前分页或搜索结果作为全量选项。 +### 页面概览 -供应商表单必须支持未保存配置的连通性测试,新建供应商时 type 默认 `openai-compatible`,baseURL 不设默认值。连通性测试返回 `ok: false` 时应展示失败反馈,不得使用成功提示样式;`/models` 不支持或响应格式不兼容属于可忽略提醒,不得阻止保存。 +| 页面 | 路径 | 入口文件 | +| -------- | ---------------- | ----------------------------------------------- | +| 总览 | `/` | `src/web/pages/dashboard/index.tsx` | +| 项目管理 | `/projects` | `src/web/pages/projects/index.tsx` | +| 模型管理 | `/models` | `src/web/pages/models/index.tsx` | +| 聊天室 | `/workbench/:id` | `src/web/consoles/workbench/pages/ChatPage.tsx` | +| 404 | `*` | `src/web/pages/404/index.tsx` | + +### 项目管理页面 + +项目管理页面(`src/web/pages/projects/index.tsx`)使用 `ProjectToolbar`(Tab 切换 active/archived + 搜索 + 新建按钮)、`ProjectTable`(列表展示、内联操作)和 `ProjectFormModal` 拆分职责。支持创建、编辑、归档、恢复和永久删除项目,仅 active 项目可点击跳转工作台。 + +### 模型管理页面 + +模型管理页面(`src/web/pages/models/index.tsx`)通过 antd `Tabs` 在同页组织供应商和模型两个视图。页面使用 `ModelsToolbar`、`ProviderTable`、`ProviderFormModal`、`ModelTable`、`ModelFormModal` 拆分职责;模型表单和模型表格必须使用 `GET /api/providers/options` 获取最小供应商选项。供应商表单支持未保存配置的连通性测试(`POST /api/providers/test`),新建供应商时 type 默认 `openai-compatible`,baseURL 不设默认值。连通性测试返回 `ok: false` 时展示失败反馈;`/models` 不支持属于可忽略提醒,不阻止保存。 ### 聊天页面 Workbench 聊天页面位于 `src/web/consoles/workbench/pages/ChatPage.tsx`,组合 `ChatSidebar` 和 `ChatPanel` 两个子组件。 -- **ChatSidebar**:使用 TanStack Query 管理会话列表,提供创建和删除会话操作。 -- **ChatPanel**:使用 Vercel AI SDK `useChat` hook(来自 `@ai-sdk/react`)管理聊天状态,通过 `DefaultChatTransport`(来自 `ai` 包)与后端 SSE 端点通信。采用论坛式单列垂直布局,使用 antd `Card` 组件承载每条消息,通过 `PartRenderer` 按 `part.type` 分派渲染(文本/工具调用/推理/步骤分隔)。AI 文本使用 `streamdown` 流式 Markdown 渲染,工具调用使用 `ToolCallCard` 展示参数和执行结果。输入区使用 antd `Input.TextArea` + `Button`。 -- **ToolCallCard**:工具调用状态组件,支持 input-streaming/input-available/output-available/output-error 四态。 -- **MessageBubble**:已删除,由 PartRenderer + Card 容器替代。 -- **use-conversations hook**:位于 `src/web/hooks/use-conversations.ts`,封装会话 CRUD 的 fetch 调用。 +- **ChatSidebar**(`src/web/consoles/workbench/components/chat/ChatSidebar.tsx`):使用 TanStack Query 管理会话列表,提供创建和删除会话操作。 +- **ChatPanel**(`src/web/consoles/workbench/components/chat/ChatPanel.tsx`):使用 Vercel AI SDK `useChat` hook(来自 `@ai-sdk/react`)管理聊天状态,通过 `DefaultChatTransport`(来自 `ai` 包)与后端 SSE 端点通信。采用论坛式单列垂直布局,使用 antd `Card` 组件承载每条消息,通过按 `part.type` 分派渲染(文本/推理/工具调用)。AI 文本使用 `streamdown` 流式 Markdown 渲染。支持编辑上一条用户消息后重新发送、重新生成最后一条 AI 回复、复制消息内容。 +- **ChatInputArea**(`src/web/consoles/workbench/components/chat/ChatInputArea.tsx`):使用 antd `Input.TextArea` + `Button` + `Select` 组合,支持模型切换和发送/停止操作。 +- **Part renderers**(`src/web/consoles/workbench/components/chat/parts/`):`TextPart.tsx`(Markdown 文本渲染)、`ReasoningPart.tsx`(推理过程)、`ToolPart.tsx`(工具调用展示,支持 input-streaming/input-available/output-available/output-error 四态)。 -- 生产入口必须启用 `ErrorBoundary`,运行时渲染异常使用 antd `Result status="500"` 或等价组件展示。 -- `ReactQueryDevtools` 仅在 `import.meta.env.DEV` 条件下渲染,不进入生产渲染路径。 -- 主题切换统一通过 `ConfigProvider` 的 antd theme algorithm 控制,不使用硬编码主题色。 +`use-conversations` hook 位于 `src/web/hooks/use-conversations.ts`,封装会话 CRUD 和消息获取的 fetch 调用。 -## TanStack Query 规范 +## Hooks 索引 -- Query key 使用 structured array,使用 as const 保持字面量类型 -- 全局面板级查询可持续刷新,详情级查询必须按状态条件启用 -- 多处页面使用同一后端资源时,应提取共享 hook,避免重复定义 fetch 函数。 +| Hook 文件 | 说明 | +| -------------------------- | ------------------------------------------------- | +| `use-meta.ts` | 获取 `/api/meta`(30s 轮询,5s staleTime) | +| `use-projects.ts` | 项目 CRUD + archive/restore API | +| `use-providers.ts` | 供应商 CRUD + test connection API | +| `use-models.ts` | 模型 CRUD + test connection API | +| `use-conversations.ts` | 会话和消息 fetch 函数(不含 Query hooks) | +| `use-theme-preference.ts` | 主题偏好(明亮/黑暗/跟随系统)localStorage 持久化 | +| `use-sidebar-collapsed.ts` | 侧边栏折叠状态 localStorage 持久化 | -## fetch 封装 +## 工具函数索引 -统一使用 fetch,不引入 axios。错误抛异常,由 TanStack Query 的 error 状态承接。 - -前后端共享的请求和响应类型定义在 src/shared/api.ts。前端 fetch 函数的返回类型必须匹配后端真实 JSON 形状;如果后端返回包装对象,例如 `{ project: Project }`,应声明对应响应类型并在 hook 内提取业务对象。 - -## 前端测试 - -- 测试目录为 tests/web/,结构对应 src/web/ -- 单元测试重点覆盖 utils/ 和 hooks 中的纯逻辑 -- 组件测试使用 jsdom 和 @testing-library/react -- 测试用户行为而非实现细节 -- 只 mock 系统边界,使用真实的 QueryClientProvider 包裹组件 -- 组件测试环境由 tests/setup.ts 和 bunfig.toml preload 提供 -- 断言优先基于用户可见文本、role、按钮和交互结果,不依赖 `.ant-*` 内部类名。 -- 对 antd 组件只断言本项目传入的可观察行为或配置结果,避免把 antd 内部 DOM 结构当作稳定契约。 -- fetch mock、路由、QueryClientProvider 等系统边界优先复用 tests/web/test-utils.tsx,避免在每个测试文件重复安装 `window.fetch`。 -- 项目页这类数据驱动页面至少覆盖请求 URL/query、method/body、成功后的用户可见结果,以及关键错误路径或失败后状态。 -- ErrorBoundary、hooks 纯逻辑和 fetch request helper 应使用单元测试覆盖异常回退,页面测试只保留真实用户路径。 +| 文件 | 说明 | +| --------------- | --------------------------------------------------------------------------------------------- | +| `utils/api.ts` | `handleResponse()`、`handleVoidResponse()` — 通用 fetch 响应处理 | +| `utils/time.ts` | `formatCountdown`、`formatDurationUnit`、`formatRelativeTime`、`isOlderThan`、`subtractHours` | ## 更新触发条件 -修改前端技术栈、组件边界、数据流、样式规则、测试环境或前端验证方式时,必须更新本文档。 +修改前端运行时代码结构、页面组成、组件索引或 hooks/工具清单时,必须更新本文档。 diff --git a/docs/development/release.md b/docs/development/release.md index 74f4557..23a757d 100644 --- a/docs/development/release.md +++ b/docs/development/release.md @@ -68,6 +68,14 @@ bun run build | bun run version:minor | scripts/bump-version.ts | 升迁 minor 版本 | | bun run version:major | scripts/bump-version.ts | 升迁 major 版本 | | bun run version:set | scripts/bump-version.ts | 显式设置版本号 | +| bun test | (Bun 内置) | 运行全部测试 | + +内部辅助脚本(不直接对外开放): + +| 文件 | 说明 | +| ----------------------------------- | ---------------------------------------------- | +| scripts/bump-version-logic.ts | 版本号升迁/设置的逻辑实现 | +| scripts/generate-migrations-data.ts | 构建时将 drizzle/\*.sql 嵌入为 TypeScript 模块 | ## 项目配置文件 @@ -83,6 +91,7 @@ bun run build | config.schema.json | 配置文件 JSON Schema | | vite.config.ts | Vite 构建配置 | | bunfig.toml | Bun 配置 | +| drizzle.config.ts | Drizzle ORM 配置 | ## 验证期望 diff --git a/docs/user/deploy.md b/docs/user/deploy.md index a2a321d..fecd112 100644 --- a/docs/user/deploy.md +++ b/docs/user/deploy.md @@ -15,7 +15,6 @@ bun run build | ------------------------------ | ------------------- | | http://127.0.0.1:3000/ | 返回前端 SPA | | http://127.0.0.1:3000/api/meta | 返回应用元信息 JSON | -| http://127.0.0.1:3000/health | 返回健康检查 | ## 构建流程 @@ -23,8 +22,9 @@ scripts/build.ts 执行三步流水线: ```text 1. Vite build -> dist/web/(前端静态资源,含 code splitting) -2. Code generation -> .build/static-assets.ts + .build/server-entry.ts(含版本号字面量注入) +2. Code generation -> .build/static-assets.ts + .build/migrations-data.ts + .build/server-entry.ts(含版本号字面量注入) 3. Bun compile -> dist/alfred(单可执行文件) +4. Cleanup -> 清理 .build/ 临时目录 ``` - Vite 构建前端资源到 dist/web/,自动 code splitting(vendor-react、vendor-antd、vendor-chart) diff --git a/docs/user/usage.md b/docs/user/usage.md index 9d24764..986ecb9 100644 --- a/docs/user/usage.md +++ b/docs/user/usage.md @@ -38,8 +38,6 @@ bun run dev config.yaml | 项目管理 | `/projects` | 创建、编辑、归档、恢复和永久删除项目 | | 模型管理 | `/models` | 配置 AI 供应商和模型,供后续 AI 功能使用 | | 聊天室 | `/workbench/:projectId` | Workbench 工作台聊天室,与 AI 对话 | -| 用户管理 | `/users` | 页面建设中 | -| 系统设置 | `/settings` | 页面建设中 | 平台提供两个入口: From de51a817fbdc0f89e381eb234d0c75bf177c07d3 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Mon, 1 Jun 2026 16:12:21 +0800 Subject: [PATCH 2/4] =?UTF-8?q?docs:=20=E5=BC=80=E5=8F=91=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E9=87=8D=E6=9E=84=20=E2=80=94=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E7=BA=A2=E7=BA=BF=E3=80=81=E7=A6=81=E6=AD=A2?= =?UTF-8?q?=E4=BA=8B=E9=A1=B9=E6=B1=87=E6=80=BB=E3=80=81=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=E4=BC=98=E5=85=88=E7=BA=A7=EF=BC=8C=E7=B2=BE?= =?UTF-8?q?=E7=AE=80=20config.yaml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/development/README.md | 298 ++++++++++++++++++++----------------- openspec/config.yaml | 45 +++--- 2 files changed, 181 insertions(+), 162 deletions(-) diff --git a/docs/development/README.md b/docs/development/README.md index 1430188..2a35822 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -1,155 +1,181 @@ -# 开发文档 - -本文档是 alfred 的开发入口,包含**全部开发规范**和专题索引。AI 工具和开发者应首先阅读本文档掌握所有约束,再按需查阅专题文档获取实现细节。 - -适用场景:修改源码、测试、构建脚本、开发流程、架构边界或项目工程规则。 - -## 专题索引 - -| 文档 | 内容 | -| ---------------------------------- | ----------------------------------------------------------------- | -| [architecture.md](architecture.md) | 项目结构、启动流程、运行时流程、HTTP 请求流程、前后端边界 | -| [backend.md](backend.md) | 后端实现细节:模块 API、工具函数索引、数据访问函数清单、AI 层说明 | -| [frontend.md](frontend.md) | 前端实现细节:运行时代码结构、组件索引、页面组成、hooks/工具清单 | -| [release.md](release.md) | 开发服务、前后端集成、构建、脚本、环境变量 | -| [../README.md](../README.md) | 文档路由、文档归属矩阵、文档更新规则 | - ---- - # 开发规范 -以下规范是所有代码变更必须遵守的约束。AI 工具必须严格遵守,开发者 review 时以此为准。 +AI 工具必须严格遵守以下全部约束。 + +## 专题文档 + +| 文档 | 内容 | +| ---------------------------------- | ---------------------------------- | +| [architecture.md](architecture.md) | 项目结构、启动流程、前后端边界 | +| [backend.md](backend.md) | 模块 API、数据访问函数、AI 层说明 | +| [frontend.md](frontend.md) | 组件索引、页面组成、hooks/工具清单 | +| [release.md](release.md) | 开发服务、构建、脚本、环境变量 | + +--- ## 一、全局规则 ### 语言与环境 -- 使用中文编写注释、文档和项目内交流内容。 -- 仅使用 bun 作为包管理器,禁止使用 npm、pnpm、yarn。 -- 运行工具使用 bunx,禁止使用 npx、pnpx。 -- 当前项目无需考虑向前兼容。 +- 使用中文编写注释、文档和交流内容。 +- 仅使用 bun 作为包管理器和 bunx 作为工具运行器;禁止 npm、pnpm、yarn、npx、pnpx。 +- 无需考虑向前兼容。 ### 依赖引入 -**后端**:新增依赖前必须按以下优先级检查,上层已有方案则不得引入新依赖: +**后端**优先级(上层已有方案则不得引入新依赖): -| 优先级 | 来源 | 典型用途 | -| ------ | ------------ | ---------------------------------------------------- | -| 1 | Bun 内置 API | Bun.serve、Bun.file、Bun.YAML、Bun.spawn、bun:sqlite | -| 2 | es-toolkit | 类型判断、深度比较、并发控制 | -| 3 | 标准 Web API | Headers、fetch、AbortController | -| 4 | 主流三方库 | pino、@sinclair/typebox、ajv、drizzle-orm | -| 5 | 自行实现 | 仅在以上都无法满足时 | +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/依赖库;确需新增依赖时先说明原因。 -### Git 提交 - -- 提交信息使用中文,格式为 `类型: 简短描述`。 -- 提交类型限定为:`feat`、`fix`、`refactor`、`docs`、`style`、`test`、`chore`。 -- 多行提交描述时,标题和正文之间空一行。 +**Zod**:已引入但未使用(预留),配置校验用 TypeBox + Ajv,不得混用 Zod。 ### 目录边界 -| 目录 | 约定 | -| ------------------- | -------------------------------------------------------------------- | -| `src/server/` | Bun 后端代码,不能 import src/web/,HTML import 集成除外 | -| `src/server/db/` | SQLite 数据库模块,包含 schema、connection、migration 和 data access | -| `src/server/ai/` | AI Provider Registry 构建与连接测试 | -| `src/web/` | React 前端,不能 import src/server/ 运行时实现 | -| `src/shared/` | 前后端共享 TypeScript 类型 | -| `scripts/` | 独立运行脚本,可 import 项目源码 | -| `drizzle/` | Drizzle Kit 生成的 SQL migration 文件(开发期产出) | -| `tests/` | 测试目录,结构镜像 src/ | -| `docs/user/` | 用户使用、配置、部署和排障文档 | -| `docs/development/` | 架构、后端、前端、发布开发文档 | -| `openspec/` | OpenSpec 变更管理与规格文档 | +| 目录 | 约束 | +| ------------------------ | -------------------------------------------- | +| `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.version` 为唯一源头。 -- 前端不得 import `src/server/` 下的任何文件。 -- 配置加载流程固定为:unknown → AuthoringConfig → NormalizedConfig → ValidatedConfig → ServerConfig。 -- Ajv 保持严格拒绝模式:不开类型强制转换、不注入默认值、不自动删除未知字段。 -- 新增或修改配置字段时必须同步更新 TypeBox schema fragments、`config.schema.json`、测试和对应用户文档。 +- 共享类型唯一源头:`src/shared/api.ts`;应用常量唯一源头:`src/shared/app.ts`;版本号唯一源头:`package.json`。 +- 配置加载流程:unknown → AuthoringConfig → NormalizedConfig → ValidatedConfig → ServerConfig。 +- Ajv 严格拒绝模式:不类型转换、不注入默认值、不删除未知字段。 +- 新增/修改配置字段必须同步更新 TypeBox schema、`config.schema.json`、测试和用户文档。 ### 后端日志 -- 后端运行时代码统一通过 Logger 接口输出日志,禁止直接使用 `console.*`(仅 `src/server/logger.ts` 的实现类内部可用)。 -- 敏感信息自动 redact `authorization`、`cookie`、`password` 等字段。 +- 运行时代码通过 Logger 接口输出,禁止 `console.*`(仅 `logger.ts` 实现类内部可用)。 +- 敏感字段(authorization、cookie、password 等)自动 redact。 ### API 路由 -- 路由文件位于 `src/server/routes/`,每个端点一个文件。 -- 路由通过 `server.ts` 的 `Bun.serve({ routes })` 声明式注册。 -- 新增路由步骤:创建 handler 文件 → 在 `server.ts` 注册 → 在 `tests/server/` 添加测试。 +- 每个端点一个文件:`src/server/routes/{资源}/{操作}.ts`。 +- 路由在 `server.ts` 的 `Bun.serve({ routes })` 中声明式注册。 +- 新增路由:创建 handler → 在 `server.ts` 注册 → 在 `tests/server/` 添加测试。 ### 前端数据层 - 统一使用 `fetch`,不引入 axios。 -- 错误抛异常,由 TanStack Query 的 error 状态承接。 -- 前端 fetch 返回类型必须匹配后端真实 JSON 形状;后端返回包装对象(如 `{ project: Project }`)时,应声明对应响应类型并在 hook 内提取业务对象。 -- 不引入额外状态管理库。TanStack Query 承担服务端状态,组件内状态使用 `useState`。 +- 错误抛异常,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 -- 优先使用 antd 组件默认能力和 props 配置行为,不额外改写组件视觉。 -- 全局使用 `ConfigProvider` 配置中文 locale 和主题切换,不在 CSS 中硬编码亮色或暗色分支。 -- 需要 message、modal、notification 等应用级能力时,在 `ConfigProvider` 内包裹 `App`(代码中别名为 `AntApp`),组件内通过 `App.useApp()` 获取。 -- 页面组件保持编排职责,组合 hooks 和展示组件;当页面同时承担查询、筛选、分页、表格列、弹窗表单和 mutation 时,应按功能边界拆分。 +- 签名:`(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` 属性内联样式。 -- **严禁**通过 CSS 覆盖 antd 组件内部类名(`.ant-*`)。 -- **严禁**使用 `!important`。 -- **严禁**使用硬编码色值,颜色统一使用 antd CSS 变量(`var(--ant-*)`)。 -- 默认不引入 Tailwind、Sass、Less、CSS-in-JS 等额外样式方案;确需引入时必须先说明原因和影响范围。 - -### 样式指导原则 - -- antd 承担主视觉系统,项目 CSS 只补足页面外壳和局部布局,不另起一套样式体系。 -- 样式选择优先级:antd 默认能力 → antd props → antd 布局组件 → theme token → antd CSS 变量 → 全局 CSS。 -- 全局 CSS 仅承载应用外壳和基础样式,类名使用 `app-*` 前缀,禁止泛名类(如 `.container`、`.title`)。 -- 当样式需求增长到需要就近维护时,使用 CSS Modules 与页面/组件同级放置。 +- 严禁内联 `style`、覆盖 `.ant-*`、`!important`、硬编码色值。 +- 颜色使用 `var(--ant-*)` CSS 变量。 +- 不引入 Tailwind/Sass/Less/CSS-in-JS 等额外样式方案。 +- 全局 CSS 类名用 `app-*` 前缀,禁止泛名。样式增长后用 CSS Modules 就近维护。 ### 表单与交互 -- Modal + Form 提交使用 `Form onFinish` 处理业务提交,`Modal onOk` 只触发 `form.submit()`。 -- 不在 `Modal onOk` 中直接执行异步 `validateFields` 和提交逻辑。 -- 文本必填字段同时配置 `required: true` 和 `whitespace: true`,保持前后端校验一致。 -- 操作确认优先使用 `Popconfirm`,成功/失败反馈优先使用 antd message。 +- Modal + Form:`Form onFinish` 处理提交,`Modal onOk` 只调 `form.submit()`。 +- 必填文本字段同时配 `required` + `whitespace`。 +- 操作确认用 `Popconfirm`,反馈用 antd message。 -### 错误边界 - -- 生产入口必须启用 `ErrorBoundary`。 -- `ReactQueryDevtools` 仅在 `import.meta.env.DEV` 条件下渲染。 +- 生产入口必须启用 `ErrorBoundary`。`ReactQueryDevtools` 仅 `DEV` 模式渲染。 --- -## 三、测试规范 +## 四、测试规范 -### 后端测试 +### 后端 -- API 路由集成测试必须通过真实 `startServer` 覆盖路由注册、HTTP method、fallback、响应 header 和核心错误路径。 -- SQLite 相关测试必须复用 `tests/helpers.ts` 中的测试数据库 helper,不要在测试文件内分散实现临时目录清理。 -- DAO 和路由边界测试应优先使用真实 migration 初始化测试库。 -- logger/bootstrap 中预期的 fallback 输出必须在测试中捕获并断言,正常通过的测试不应污染 stdout/stderr。 +- 路由测试通过真实 `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、按钮和交互结果,不依赖 `.ant-*` 内部类名。 -- 系统边界(fetch mock、路由、QueryClientProvider)优先复用 `tests/web/test-utils.tsx`。 -- 数据驱动页面至少覆盖请求 URL/query、method/body、成功后的用户可见结果,以及关键错误路径。 -- ErrorBoundary、hooks 纯逻辑和 fetch helper 应使用单元测试覆盖异常回退,页面测试只保留真实用户路径。 +- 目录 `tests/web/`,结构对应 `src/web/`。 +- 用 jsdom + `@testing-library/react` 测试用户行为,断言基于可见文本/role/按钮。 +- 系统边界复用 `tests/web/test-utils.tsx`。 +- 数据页面覆盖:请求参数、成功可见结果、关键错误路径。 +- ErrorBoundary/hooks/fetch helper 用单元测试覆盖异常,页面测试只保留用户路径。 --- @@ -157,39 +183,35 @@ | 命令 | 说明 | | -------------------------------- | -------------------------------------- | -| `bun install` | 安装依赖 | | `bun run dev config.yaml` | 启动双进程开发环境 | -| `bun run dev:server config.yaml` | 仅启动后端 API server | -| `bun run dev:web` | 仅启动 Vite dev server | -| `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 run format:check` | Prettier 格式检查 | -| `bun test` | 运行全部测试 | +| `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 build` | 构建生产可执行文件 | | `bun run verify` | check + build 完整验证 | -| `bun run clean` | 清理构建缓存与临时文件 | -| `bun run version:patch` | 升迁 patch 版本(x.y.Z) | -| `bun run version:minor` | 升迁 minor 版本(x.Y.0) | -| `bun run version:major` | 升迁 major 版本(X.0.0) | +| `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 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`。如果因环境限制无法执行完整验证,必须在收尾说明中记录未执行项和原因。 +正式提交优先运行 `bun run verify`。无法执行时须在收尾说明中记录。 ## 已知设计决策 @@ -199,17 +221,15 @@ ## 文档影响分析 -每次代码变更都必须执行文档影响分析。 +| 变更影响 | 更新 | +| -------------------------------------- | ------------------------------------------ | +| 用户可见行为、配置、部署、运行行为 | `docs/user/` 对应文档 | +| 开发流程、架构、测试、构建发布流程 | `docs/development/` 对应文档 | +| 项目定位、快速开始、核心能力、文档导航 | `README.md` | +| 文档同步规则或归属矩阵 | `docs/README.md` 和 `openspec/config.yaml` | +| 开发规范变化 | 本文档对应章节 | -| 如果变更影响 | 更新 | -| ------------------------------------------ | ------------------------------------------ | -| 用户可见行为、配置、部署、运行行为 | `docs/user/` 对应文档 | -| 开发流程、架构、测试、构建发布流程 | `docs/development/` 对应文档 | -| 项目定位、快速开始、核心能力列表、文档导航 | `README.md` | -| 文档同步规则或文档归属矩阵 | `docs/README.md` 和 `openspec/config.yaml` | -| 开发规范变化 | 本文档对应章节 | - -如果无需更新文档,必须在收尾说明中说明原因。详细规则见 [文档总览](../README.md)。 +无需更新文档时,须在收尾说明中说明原因。 ## 更新触发条件 diff --git a/openspec/config.yaml b/openspec/config.yaml index 9a3d00e..99b18fb 100644 --- a/openspec/config.yaml +++ b/openspec/config.yaml @@ -1,32 +1,31 @@ schema: fast-drive context: | + ## 项目概览 + - 本项目为 Bun 全栈应用(Alfred·阿福),Bun 是唯一包管理器和运行时,严禁使用 npm、pnpm、yarn、npx、pnpx + - docs/user/ 记录用户使用方法,docs/development/ 记录开发技术细节 - 使用中文(注释、文档、交流),面向中文开发者 - - **优先阅读 docs/README.md** 获取文档路由、归属矩阵和影响分析规则 - - **其次阅读 docs/development/README.md** 获取开发规范、常用命令、质量门禁和全局规则 - - 文档文件名优先使用单个英文单词(usage.md、config.md、deploy.md、troubleshoot.md),目录上下文足以消歧时不在文件名重复限定词 - - 每次代码变更必须执行文档影响分析: - - 用户可见行为、配置、部署、运行行为变更 → 更新 docs/user/ 对应文档 - - 开发流程、架构、测试、构建发布流程变更 → 更新 docs/development/ 对应文档 - - 项目定位、快速开始、核心能力列表、文档导航变更 → 更新 README.md - - 文档同步规则或文档归属矩阵变更 → 更新 docs/README.md 和本文件 - - 无需更新文档时必须在收尾说明中说明原因 - - 新增代码优先复用已有组件、工具、依赖库,不引入新依赖 - - 新增的逻辑必须编写完善的测试,并保证测试的正确性,不允许跳过任何测试 - - 这是基于bun实现的前端后一体化项目,使用bun作为唯一包管理器,严禁使用pnpm、npm,使用bunx运行工具,严禁使用npx、pnpx - - src/server目录下是基于bun实现的后端代码 - - 后端库使用优先级:Bun 内置 API > es-toolkit > 主流三方库 > 项目公共工具 > 自行实现 - - src/web目录下是基于Bun HTML import、React、Ant Design实现的前端代码 - - 前端最高规约:优先使用 antd 组件默认能力和组件 props 组合界面,具体组件、样式、数据流和测试细节遵循 docs/development/frontend.md - - 前端样式管理:antd 组件/props/token 优先,AppShell 使用最小全局 CSS,页面和自有组件样式增长后使用就近 CSS Modules,默认不引入 Tailwind、UnoCSS、Sass、Less、CSS-in-JS 等额外样式体系 - - 前端样式红线:禁止组件内联 style、覆盖 antd 内部类名、使用 !important、硬编码色值 - - Git提交: 仅中文; 格式"类型: 简短描述", 类型: feat/fix/refactor/docs/style/test/chore; 多行描述空行后写详细说明 - - 禁止创建git操作task - - 积极使用subagents精心设计并行任务,节省上下文空间,加速任务执行 - - 优先使用提问工具对用户进行提问 - - 本项目为 Bun 全栈应用(Alfred·阿福),docs/user/ 记录用户使用方法,docs/development/ 记录开发技术细节 - 本项目无需考虑向前兼容性 + ## 文档入口(按顺序阅读) + - **优先阅读 docs/README.md** 获取文档路由、归属矩阵和影响分析规则 + - **其次阅读 docs/development/README.md** 获取完整开发规范、常用命令和质量门禁 + + ## 全局红线 + - 前端禁止导入 src/server/ 的后端运行时实现 + - 后端运行时代码禁止直接使用 console.*,通过 Logger 实例输出 + - 新增逻辑必须编写完善的测试,不允许跳过任何测试 + - 每次代码变更必须执行文档影响分析(详见 docs/README.md) + - 新增代码优先复用已有组件、工具、依赖库,不轻易引入新依赖 + + ## Git 规范 + - 提交信息中文,格式"类型: 简短描述",类型:feat/fix/refactor/docs/style/test/chore + - 禁止创建 git 操作 task + + ## 工作方式 + - 积极使用 subagents 并行任务,节省上下文空间 + - 优先使用提问工具对用户确认 + rules: design: - fast-drive的design.md章节标题和正文使用中文;仅OpenSpec术语、文件名、schema字段名、命令和代码符号保留英文 From b225b0a0c7dce5d9e87b8a846c09feb1c64cd955 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Mon, 1 Jun 2026 16:43:17 +0800 Subject: [PATCH 3/4] =?UTF-8?q?docs:=20=E5=BC=80=E5=8F=91=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E9=9D=A2=E5=90=91AI=E7=B2=BE=E7=AE=80=E9=87=8D?= =?UTF-8?q?=E6=9E=84=EF=BC=8C=E8=A1=A5=E5=85=85=E6=96=87=E6=A1=A3=E7=BC=96?= =?UTF-8?q?=E6=92=B0=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/development/README.md | 25 +++++ docs/development/architecture.md | 169 +++++++------------------------ docs/development/backend.md | 147 +++++++++------------------ docs/development/frontend.md | 81 ++++++--------- docs/development/release.md | 124 +++++++---------------- 5 files changed, 177 insertions(+), 369 deletions(-) diff --git a/docs/development/README.md b/docs/development/README.md index 2a35822..b565506 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -156,6 +156,8 @@ AI 工具必须严格遵守以下全部约束。 - 必填文本字段同时配 `required` + `whitespace`。 - 操作确认用 `Popconfirm`,反馈用 antd message。 +### 错误边界 + - 生产入口必须启用 `ErrorBoundary`。`ReactQueryDevtools` 仅 `DEV` 模式渲染。 --- @@ -234,3 +236,26 @@ AI 工具必须严格遵守以下全部约束。 ## 更新触发条件 修改常用命令、质量门禁、开发规范(任何章节)、目录边界或开发文档索引时,必须更新本文档。 + +### 文档编撰规范 + +本节开发文档面向 AI 工具阅读,编撰时遵循以下原则: + +**精简原则** + +- 删除引导语、适用场景、过渡句等装饰性文字。AI 无需"应首先阅读"或"本文档说明…"类引导。 +- 不重复项目结构树,AI 可通过 glob 获取目录结构。 +- 不重复已在 README.md 声明的规范细节,专题文档只记录实现层面的函数签名、API 端点、模块职责等索引信息。 +- 表格标题自明时不再加说明段落。 + +**信息完整性** + +- 所有函数签名、API 端点(方法+路径+说明)、数据访问函数清单必须完整列举,不可用"等"省略。 +- 页面行为描述须包含关键交互逻辑(如 Tab 切换、默认值、条件跳转、测试不阻止保存等),不可只写组件名。 +- 配置文件列表必须完整,不可遗漏已有文件。 + +**结构规范** + +- 每个专题文档末尾保留 `## 更新触发条件` 章节,明确列出哪些变更必须更新该文档。 +- 用表格和编号列表替代散文段落,减少 token 消耗。 +- 同一信息只在一处维护,避免多处重复导致不一致。 diff --git a/docs/development/architecture.md b/docs/development/architecture.md index f609f44..f341198 100644 --- a/docs/development/architecture.md +++ b/docs/development/architecture.md @@ -1,159 +1,60 @@ # 架构与边界 -本文档说明 alfred 的项目结构、启动链路、运行时流程、HTTP 请求流程和前后端边界。 - -适用场景:修改目录边界、启动流程、运行时调度、HTTP server、前后端集成方式或主要模块职责。 - -## 项目结构 - -```text -src/ - server/ - bootstrap.ts 统一启动引导(loadServerConfig -> DB 初始化 -> startServer) - config.ts CLI 参数解析与配置文件加载 facade - config/ 配置解析模块 - index.ts 配置模块导出 - types.ts 配置类型定义 - issues.ts 配置问题收集 - variables.ts 变量解析 - normalizer.ts 配置标准化 - schema/ JSON Schema 生成与校验 - builder.ts - export.ts - fragments.ts - validate.ts - db/ SQLite 数据库模块 - index.ts 数据库模块导出 - schema.ts Drizzle ORM schema 定义 - connection.ts 数据库连接与 PRAGMA 设置 - load-migrations.ts 从文件系统加载 migration SQL - migrate.ts migration 执行器(备份 + 事务应用) - projects.ts 项目数据访问函数 - providers.ts 供应商数据访问函数 - models.ts 模型数据访问函数 - conversations.ts 会话与消息数据访问函数 - ai/ AI 服务层 - types.ts AI 配置类型定义 - registry.ts AI Provider Registry 构建与连接测试 - agents/ Agent 工厂 - alfred-agent.ts Agent 工厂(ToolLoopAgent + 工具) - tools/ 工具定义 - get-current-time.ts 获取当前时间工具 - dev.ts 开发模式启动入口 - main.ts 生产模式启动入口 - server.ts HTTP server 启动工厂(Bun.serve routes 声明式路由) - static.ts 生产模式静态资源服务 - helpers/ 共享工具模块 - index.ts 模块导出 - response.ts 响应格式化工具 - url.ts URL 拼接工具 - middleware/ API 中间件模块 - index.ts 模块导出 - validate.ts 参数校验中间件 - error-handler.ts 错误处理中间件 - logger.ts 结构化日志(基于 pino + pino-roll) - version.ts 运行时版本号读取 - routes/ API 路由处理器 - meta.ts 应用元信息路由 - providers/ 供应商 CRUD 与测试路由 - models/ 模型 CRUD 与测试路由 - projects/ 项目 CRUD、归档与恢复路由 - chat/ 聊天会话与消息路由(含 SSE 流式发送) - shared/ - api.ts 前后端共享 TypeScript 类型定义 - app.ts 应用全局常量(name、title、subtitle、description) - web/ React 前端(通过 Vite 构建) - index.html HTML 入口 - main.tsx React 入口(StrictMode + ErrorBoundary + QueryClientProvider + BrowserRouter) - app.tsx 根组件(设置 document 标题和 meta) - routes.tsx 路由配置(Admin + Workbench 两大控制台) - menu.tsx 共享菜单项类型定义 - styles.css 全局样式 - css.d.ts CSS Modules 类型声明 - pages/ 页面组件 - dashboard/ 总览页面 - projects/ 项目管理页面及其子组件 - models/ 模型管理页面及其子组件 - 404/ 404 页面 - components/ 共享 UI 组件 - ErrorBoundary.tsx 错误边界 - ConsoleShell/ 通用控制台外壳(ConsoleShell、ConsoleOutlet、types) - Sidebar/ 侧边栏导航组件 - consoles/ 控制台入口 - admin/ Admin 管理台(AdminConsoleLayout、菜单配置) - workbench/ Workbench 工作台(ProjectGate、ConsoleLayout、菜单配置、ChatPage 等) - hooks/ React Hooks(use-meta、use-projects、use-providers、use-models、use-conversations、主题/侧边栏偏好) - utils/ 前端工具函数(fetch 封装、时间格式化) -scripts/ 独立运行脚本 -tests/ 测试文件(镜像 src 目录结构) -docs/ 项目文档 -openspec/ OpenSpec 规格、变更与 fast-drive workflow schema -``` - ## 启动流程 ```text dev.ts / main.ts - -> parseRuntimeArgs(cli args) - -> 必须指定 config.yaml + -> parseRuntimeArgs(cli args) — 必须指定 config.yaml -> bootstrap({ configPath, mode }) - -> loadServerConfig(configPath) - -> createRuntimeLogger(config.logging) - -> 确保 dataDir 就绪(mkdirSync) - -> 加载 migrations(生产:嵌入的 bytes;开发:磁盘 drizzle/ 目录) - -> createDatabase(dataDir) - -> runMigrations(db, migrations)(pending migration 存在时先备份 DB) - -> startServer({ config, logger, db }) - -> logger 记录启动成功 + -> loadServerConfig(configPath) + -> createRuntimeLogger(config.logging) + -> mkdirSync(dataDir) + -> 加载 migrations(生产:嵌入 bytes;开发:磁盘 drizzle/) + -> createDatabase(dataDir) + -> runMigrations(db, migrations) — pending 时先备份 DB + -> startServer({ config, logger, db }) -> SIGINT/SIGTERM -> db.close() -> logger.flush() -> exit ``` ## HTTP 请求流程 ```text -Request - -> Bun.serve routes 声明式匹配 - -> routes/*.ts handler - -> helpers/ 响应格式化 - -> Response +Request -> Bun.serve routes 声明式匹配 -> routes/*.ts handler -> helpers/ 响应格式化 -> Response ``` -生产模式下,非 API 路径由 fetch fallback 处理:有文件扩展名的返回静态资源或 404,无扩展名的返回 SPA index.html。 - -开发模式下,Vite proxy 将 /api 请求转发到 Bun API server。 +- 生产模式:非 API 路径由 fetch fallback 处理,有扩展名返回静态资源或 404,无扩展名返回 SPA index.html。 +- 开发模式:Vite proxy 将 /api 转发到 Bun。 ## 前后端边界 -- 前端只通过 HTTP 调用后端,API 路径为 /api/\*。 -- 共享类型放在 src/shared/。 -- 前端不得 import src/server/ 的运行时实现。 -- 后端不得依赖 src/web/ 运行时代码,HTML import 集成除外。 +- 前端只通过 HTTP /api/\* 调用后端。 +- 共享类型在 `src/shared/`。 +- 前端禁止 import `src/server/` 运行时实现;后端禁止依赖 `src/web/` 运行时代码(HTML import 集成除外)。 -## 主要模块职责 +## 主要模块 -| 模块 | 职责 | -| ------------------------- | ---------------------------------------------------------------------- | -| `src/server/bootstrap.ts` | 统一启动引导、DB 初始化和 shutdown 编排 | -| `src/server/server.ts` | Bun HTTP server 和 routes 注册 | -| `src/server/routes/` | API handler,按资源端点拆分(meta、providers、models、projects、chat) | -| `src/server/db/` | SQLite 连接、schema、migration 和 data access | -| `src/server/ai/` | AI Provider Registry 构建与 Agent 流式调用 | -| `src/server/config/` | 配置解析模块(types、variables、normalizer、schema) | -| `src/server/helpers/` | 共享响应格式化和 URL 工具 | -| `src/server/middleware/` | API 参数校验和错误处理中间件 | -| `src/web/` | React 前端(Admin + Workbench 双控制台架构) | -| `src/shared/api.ts` | 前后端共享 API 类型 | -| `src/shared/app.ts` | 应用全局常量 | +| 模块 | 职责 | +| ------------------------- | ------------------------------------------------ | +| `src/server/bootstrap.ts` | 统一启动引导、DB 初始化、shutdown 编排 | +| `src/server/server.ts` | Bun HTTP server + routes 注册 | +| `src/server/routes/` | API handler,按资源端点拆分 | +| `src/server/db/` | SQLite 连接、schema、migration、data access | +| `src/server/ai/` | AI Provider Registry + Agent 流式调用 | +| `src/server/config/` | 配置解析(types、variables、normalizer、schema) | +| `src/server/helpers/` | 响应格式化、URL 工具 | +| `src/server/middleware/` | 参数校验 + 错误处理 | +| `src/shared/api.ts` | 前后端共享 API 类型 | +| `src/shared/app.ts` | 应用全局常量 | -### 路由按资源分组 +## 路由分组 -| 资源分组 | 路径前缀 | 路由文件 | -| --------- | ------------------------------------------------------------- | ---------------------------- | -| meta | `/api/meta` | `routes/meta.ts` | -| providers | `/api/providers` | `routes/providers/` (7 文件) | -| models | `/api/models` | `routes/models/` (6 文件) | -| projects | `/api/projects` | `routes/projects/` (7 文件) | -| chat | `/api/projects/:id/conversations` 和 `/api/projects/:id/chat` | `routes/chat/` (7 文件) | +| 资源 | 路径前缀 | 文件目录 | +| --------- | ----------------------------------------------- | ------------------- | +| meta | `/api/meta` | `routes/meta.ts` | +| providers | `/api/providers` | `routes/providers/` | +| models | `/api/models` | `routes/models/` | +| projects | `/api/projects` | `routes/projects/` | +| chat | `/api/projects/:id/conversations` 和 `:id/chat` | `routes/chat/` | ## 更新触发条件 diff --git a/docs/development/backend.md b/docs/development/backend.md index 7075b1e..3319bc8 100644 --- a/docs/development/backend.md +++ b/docs/development/backend.md @@ -1,92 +1,50 @@ # 后端开发 -本文档说明 alfred 后端的模块实现细节、API 索引和开发方式。开发规范(库优先级、类型规范、配置契约、API 路由规范、测试约定等)见 [开发规范文档](README.md#开发规范)。 - -适用场景:修改 `src/server/`、了解现有模块 API、查找可供复用的工具函数和数据访问接口。 +开发规范见 [开发规范文档](README.md)。 ## 共享工具 -`src/server/helpers/` 提供跨路由共用的工具模块: +`src/server/helpers/`: -- `response.ts` — 响应格式化工具: - - `createApiError(error, status)` — 构造 API 错误体 - - `createHeaders(mode, init)` — 创建响应 Headers(生产模式附加安全 header) - - `createMetaResponse(version)` — 构造应用元信息响应 - - `formatDuration(ms)` — 格式化毫秒时长为可读字符串 - - `jsonResponse(body, options)` — JSON 响应构造 -- `url.ts` — URL 工具: - - `parseIdFromUrl(url)` — 从 URL 解析路径中的 ID +- `response.ts`:`createApiError(error, status)`、`createHeaders(mode, init)`、`createMetaResponse(version)`、`formatDuration(ms)`、`jsonResponse(body, options)` +- `url.ts`:`parseIdFromUrl(url)` -`src/server/middleware/` 提供 API 参数校验和错误处理中间件: +`src/server/middleware/`: -- `validate.ts` — 参数校验函数: - - `validateIdParam(idStr, mode)` — 校验 ID 参数格式(字母数字 + `_` `-`) - - `validatePagination(pageParam, pageSizeParam, mode)` — 校验分页参数(page 最小 1,pageSize 最大 200) - - `validateTimeRange(from, to, mode)` — 校验时间范围参数 -- `error-handler.ts` — 错误处理中间件: - - `AppError` — 业务异常类(含 statusCode) - - `withErrorHandler(fn, mode, logger?)` — 包裹路由 handler,捕获 AppError 和未知异常 +- `validate.ts`:`validateIdParam(idStr, mode)` — 校验 ID 格式(字母数字 + `_-`);`validatePagination(pageParam, pageSizeParam, mode)` — page≥1, pageSize≤200;`validateTimeRange(from, to, mode)` +- `error-handler.ts`:`AppError` — 业务异常类(含 statusCode);`withErrorHandler(fn, mode, logger?)` — 包裹 handler 捕获异常 ## 数据库 -项目使用 SQLite 作为存储后端,通过 bun:sqlite + Drizzle ORM 实现类型安全的数据访问。 +SQLite + bun:sqlite + Drizzle ORM。 -### schema 定义 +- `src/server/db/schema.ts`:Drizzle 表结构,列名 snake_case,TS 类型 camelCase。 +- `src/server/db/connection.ts`:`createDatabase(dataDir, logger)` 打开 `alfred.db`,PRAGMA:foreign_keys=ON、journal_mode=WAL、busy_timeout=5000。`wrap(db)` 转为 Drizzle 实例。`paginateQuery()` 分页工具。 +- Migration:开发期 `drizzle-kit generate` 产出到 `drizzle/`;生产期嵌入可执行文件,启动时自动应用。备份到 `/backups/`,事务中执行,失败回滚。 -`src/server/db/schema.ts` 使用 Drizzle ORM 定义表结构,列名使用 snake_case,TypeScript 类型使用 camelCase,Drizzle schema 负责映射。 +### 数据访问函数 -### 数据库连接 +| 文件 | 函数 | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `projects.ts` | createProject、getProject、listProjects、updateProject、deleteProject、archiveProject、restoreProject | +| `providers.ts` | createProvider、getProvider、listProviders、listProviderOptions、updateProvider、deleteProvider | +| `models.ts` | createModel、getModel、listModels、getModelsByProviderId、updateModel、deleteModel | +| `conversations.ts` | createConversation、getConversation、listConversations、updateConversation、updateConversationTimestamp、deleteConversation、createMessage、createMessages、listMessages | -`src/server/db/connection.ts` 的 `createDatabase(dataDir, logger)` 打开 `/alfred.db`,设置 PRAGMA(foreign_keys=ON、journal_mode=WAL、busy_timeout=5000)。 - -### migration 机制 - -- 开发期:使用 `drizzle-kit generate` 从 TS schema 生成 SQL migration 文件到 `drizzle/` 目录 -- 生产期:构建时将 `drizzle/*.sql` 嵌入可执行文件,启动时自动应用 pending migrations -- 每次 migration 前自动备份现有 DB 到 `/backups/alfred-.db` -- migration 在事务中执行,失败则回滚并停止启动 - -### 数据访问 - -`src/server/db/projects.ts` 提供项目数据访问函数(`createProject`、`getProject`、`listProjects`、`updateProject`、`deleteProject`、`archiveProject`、`restoreProject`)。`src/server/db/providers.ts` 提供供应商数据访问函数(`createProvider`、`getProvider`、`listProviders`、`listProviderOptions`、`updateProvider`、`deleteProvider`)。`src/server/db/models.ts` 提供模型数据访问函数(`createModel`、`getModel`、`listModels`、`getModelsByProviderId`、`updateModel`、`deleteModel`)。`src/server/db/conversations.ts` 提供会话和消息数据访问函数(`createConversation`、`getConversation`、`listConversations`、`updateConversation`、`updateConversationTimestamp`、`deleteConversation`、`createMessage`、`createMessages`、`listMessages`)。`src/server/db/connection.ts` 还提供 `paginateQuery` 和 `wrap` 工具函数。输入输出使用 `src/shared/api.ts` 的类型。函数内部使用 Drizzle query builder 包装 `bun:sqlite` Database。 +输入输出类型来自 `src/shared/api.ts`。 ## AI 服务层 -`src/server/ai/` 提供 AI Provider Registry 构建与连接测试能力。 +- `src/server/ai/types.ts`:`AIProviderConfig`(name、type、baseUrl、apiKey)、`AIModelConfig`(providerId、modelId、capabilities)。 +- `src/server/ai/registry.ts`: + - `buildProviderRegistry(db)` — 从 DB 查询供应商构建 AI SDK Provider Registry,每次调用重建,不缓存。通过 `registry.languageModel('providerId:modelId')` 获取模型实例。 + - `testProviderConnection(config)` — 测试 Base URL 可达性 + `/models` 接口 + - `testModelConnection(config)` — 测试模型连通性 + - `countModels(db)` — 统计已配置模型数 +- `src/server/ai/agents/alfred-agent.ts`:`createAlfredAgent(model)` — ToolLoopAgent + `stepCountIs(20)` + `getCurrentTime` 工具。 +- `src/server/ai/tools/`:AI 工具定义。 -### 类型定义 - -`src/server/ai/types.ts` 定义 AI 配置类型: - -- `AIProviderConfig` — 供应商配置(name、type、baseUrl、apiKey) -- `AIModelConfig` — 模型配置(providerId、modelId、capabilities) -- `AIRegistryConfig` — Registry 构建配置(providers、models),供后续 AI 调用层组合使用 - -### Registry 构建 - -`src/server/ai/registry.ts` 提供: - -- `buildProviderRegistry(db)` — 从 DB 查询所有供应商,构建 Vercel AI SDK Provider Registry -- `testProviderConnection(config)` — 先测试 Base URL 可达性,再请求 `/models` 验证 API Key 和模型列表接口 -- `testModelConnection(config)` — 先通过 providerId 查询供应商(含 apiKey),再以 modelId 请求对应模型的 API 连通性 -- `countModels(db)` — 统计 DB 中已配置的模型总数,用于 Agent 调用前的可用性检查 - -每次 AI 调用时从 DB 查询 providers,构建 registry 后通过 `registry.languageModel('providerId:modelId')` 获取模型实例。不使用缓存层。模型是否存在以及业务能力标签由调用方基于 models 表先行校验,registry 只负责将 providerId/modelId 映射到 AI SDK 模型实例。 - -### Agent 流式调用 - -`src/server/ai/agents/alfred-agent.ts` 提供 `createAlfredAgent(model)` 工厂函数,返回 AI SDK `ToolLoopAgent` 实例。默认使用 `stepCountIs(20)` 限制最大迭代次数,配置 `getCurrentTime` 工具供 AI 调用。路由层通过 `createAgentUIStreamResponse()` 转为 SSE 响应,流结束通过 `onFinish` 回调可靠持久化 AI 回复(含完整 `parts`)。 - -### 供应商连通性测试 - -供应商连通性测试返回 `{ providerTestResponse: { ok, message } }`,前端根据 `ok` 展示成功或失败提示。 - -- `POST /api/providers/test` — 使用表单中尚未保存的供应商配置测试连接 -- `POST /api/models/test` — 使用模型关联供应商配置和 modelId 测试模型连接 - -测试连接不会写入数据库,也不会阻止保存。Base URL 不可达或 API Key 无效返回 `ok: false`;Base URL 可达但 `/models` 不支持、非标准或返回非鉴权错误时返回 `ok: true` 并在 `message` 中提示用户可检查 URL 或忽略提醒。 - -### 支持的供应商类型 +### 供应商类型 | type | AI SDK factory | | ------------------- | --------------------------------------------------- | @@ -94,50 +52,37 @@ | `anthropic` | `createAnthropic({ apiKey, baseURL })` | | `openai-compatible` | `createOpenAICompatible({ name, apiKey, baseURL })` | -## 聊天 API +### 连通性测试 -聊天 API 按项目维度组织会话和消息: +- `POST /api/providers/test` — 用未保存配置测试,不写入 DB,不阻止保存。Base URL 不可达或 API Key 无效返回 `ok: false`;`/models` 不支持返回 `ok: true` + 提示。 +- `POST /api/models/test` — 用模型关联供应商 + modelId 测试。 + +## 聊天 API | 方法 | 路径 | 说明 | | ------ | ----------------------------------------------- | ------------------ | | GET | `/api/projects/:id/conversations` | 列出项目下所有会话 | | POST | `/api/projects/:id/conversations` | 创建新会话 | | GET | `/api/projects/:id/conversations/:cid` | 获取会话详情 | -| PATCH | `/api/projects/:id/conversations/:cid` | 更新会话标题或模型 | -| DELETE | `/api/projects/:id/conversations/:cid` | 删除会话及其消息 | -| GET | `/api/projects/:id/conversations/:cid/messages` | 获取会话消息列表 | -| POST | `/api/projects/:id/chat` | 发送消息并流式回复 | +| PATCH | `/api/projects/:id/conversations/:cid` | 更新会话 | +| DELETE | `/api/projects/:id/conversations/:cid` | 删除会话及消息 | +| GET | `/api/projects/:id/conversations/:cid/messages` | 获取消息列表 | +| POST | `/api/projects/:id/chat` | 发送消息,SSE 回复 | -聊天路由处理器位于 `src/server/routes/chat/`,遵循统一的 handler 模式。`send.ts` 处理发送消息:验证会话归属后只保存最后一条用户消息到 DB,通过 `createAlfredAgent` 创建 agent,调用 `createAgentUIStreamResponse` 返回 SSE UI 消息流,流结束通过 `onFinish` 回调保存 AI 回复到 DB。 +`send.ts`:验证会话归属 → 保存用户消息 → `createAlfredAgent` → `createAgentUIStreamResponse` → `onFinish` 持久化 AI 回复。 -## 日志模块 +## 日志 -后端运行时代码统一通过 Logger 接口输出日志。 - -| 实现 | 用途 | -| --------------------- | ------------------------ | -| PinoLoggerWrapper | 生产运行时 | -| ConsoleFallbackLogger | 配置加载失败前的降级日志 | -| NoopLogger | 静默丢弃日志 | -| MemoryLogger | 测试替身 | +| 实现 | 用途 | +| --------------------- | -------------- | +| PinoLoggerWrapper | 生产运行时 | +| ConsoleFallbackLogger | 配置加载前降级 | +| NoopLogger | 静默丢弃 | +| MemoryLogger | 测试替身 | ## 版本管理 -版本号以 `package.json.version` 为唯一来源。 - -版本获取方式: - -- 开发模式:`src/server/version.ts` 运行时从 package.json 读取 -- 生产模式:`scripts/build.ts` 在构建时将版本号烘焙为字面量注入 - -版本升迁命令: - -```bash -bun run version:patch # 升迁 patch 版本 -bun run version:minor # 升迁 minor 版本 -bun run version:major # 升迁 major 版本 -bun run version:set # 显式设置版本号 -``` +唯一来源:`package.json`。开发模式从 package.json 运行时读取;生产模式构建时烘焙为字面量。 ## 更新触发条件 diff --git a/docs/development/frontend.md b/docs/development/frontend.md index f741db1..dfe62c8 100644 --- a/docs/development/frontend.md +++ b/docs/development/frontend.md @@ -1,70 +1,53 @@ # 前端开发 -本文档说明 alfred 前端的运行时代码结构、组件索引和页面组成。开发规范(组件规范、Ant Design 用法、样式规则、表单交互、TanStack Query、测试约定等)见 [开发规范文档](README.md#开发规范)。 +开发规范见 [开发规范文档](README.md)。 -适用场景:修改 `src/web/`、了解现有组件和页面结构、查找 hooks 和工具函数。 +## 控制台架构 -## 运行时外壳 +两个控制台入口共享 ConsoleShell(`src/web/components/ConsoleShell/`): -前端提供两个入口外壳,共享通用 Console Shell 组件: +- **Admin**(`src/web/consoles/admin/`):路由 `/`(总览)、`/projects`、`/models`。 +- **Workbench**(`src/web/consoles/workbench/`):路由 `/workbench/:projectId`、`/workbench/:projectId/chat`。`WorkbenchProjectGate` 从 URL 读 projectId,通过 `ProjectContext` 提供项目上下文,仅 active 项目渲染。 -- **Admin(管理台)**:`src/web/consoles/admin/AdminConsoleLayout.tsx`,菜单配置在 `src/web/consoles/admin/menu.tsx`,路由 `/`(总览)、`/projects`(项目管理)、`/models`(模型管理)。 -- **Workbench(工作台)**:`src/web/consoles/workbench/WorkbenchProjectGate.tsx` → `WorkbenchConsoleLayout.tsx`,菜单配置和路由构造在 `src/web/consoles/workbench/routes.ts`,路由 `/workbench/:projectId` 和 `/workbench/:projectId/chat`。默认菜单为"聊天室"。 +ConsoleShell 包含:`ConfigProvider(zhCN)` + `AntApp` + `Layout`(Header/Sider/Content) + 主题切换(明亮/黑暗/系统)+ 侧边栏折叠。Header 显示品牌名、版本号和控制台标题。 -通用 Console Shell(`src/web/components/ConsoleShell/ConsoleShell.tsx`)包含 `ConfigProvider`(zhCN locale)、`AntApp`、`Layout`、`Header`、`Sider`、`Content`、主题切换(明亮/黑暗/系统)和侧边栏折叠状态,由 Admin 和 Workbench 复用。Header 显示品牌名、版本号和控制台标题(Admin 显示"管理台",Workbench 显示"工作台 · 项目名")。 +`Sidebar`(`src/web/components/Sidebar/`)纯展示组件,通过 `menuItems` props 接收配置。 -Menu 类型定义在 `src/web/menu.tsx` 中的 `MenuItemConfig` 接口(icon、label、path、value)。 +## 页面 -Sidebar(`src/web/components/Sidebar/index.tsx`)是纯展示/导航组件,通过 `menuItems` props 接收菜单配置,由调用方决定菜单内容和路径。Admin 传入静态路径 `/`、`/projects`、`/models`;Workbench 通过 route builder(`buildWorkbenchPath`)将相对菜单路径拼成 `/workbench/:projectId` 的子路径。 - -Workbench 项目上下文通过 `ProjectContext`(`src/web/consoles/workbench/ProjectContext.tsx` 和 `ProjectContextValue.ts`)提供,在 `WorkbenchProjectGate` 中从 URL path param 读取 `projectId`,通过 `useProject(projectId)` 加载项目,仅 active 项目渲染工作台布局,不存在或 archived 项目显示"项目不存在或不可访问"。 - -### 页面概览 - -| 页面 | 路径 | 入口文件 | -| -------- | ---------------- | ----------------------------------------------- | -| 总览 | `/` | `src/web/pages/dashboard/index.tsx` | -| 项目管理 | `/projects` | `src/web/pages/projects/index.tsx` | -| 模型管理 | `/models` | `src/web/pages/models/index.tsx` | -| 聊天室 | `/workbench/:id` | `src/web/consoles/workbench/pages/ChatPage.tsx` | -| 404 | `*` | `src/web/pages/404/index.tsx` | - -### 项目管理页面 - -项目管理页面(`src/web/pages/projects/index.tsx`)使用 `ProjectToolbar`(Tab 切换 active/archived + 搜索 + 新建按钮)、`ProjectTable`(列表展示、内联操作)和 `ProjectFormModal` 拆分职责。支持创建、编辑、归档、恢复和永久删除项目,仅 active 项目可点击跳转工作台。 - -### 模型管理页面 - -模型管理页面(`src/web/pages/models/index.tsx`)通过 antd `Tabs` 在同页组织供应商和模型两个视图。页面使用 `ModelsToolbar`、`ProviderTable`、`ProviderFormModal`、`ModelTable`、`ModelFormModal` 拆分职责;模型表单和模型表格必须使用 `GET /api/providers/options` 获取最小供应商选项。供应商表单支持未保存配置的连通性测试(`POST /api/providers/test`),新建供应商时 type 默认 `openai-compatible`,baseURL 不设默认值。连通性测试返回 `ok: false` 时展示失败反馈;`/models` 不支持属于可忽略提醒,不阻止保存。 +| 页面 | 路径 | 入口 | +| -------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 总览 | `/` | `pages/dashboard/index.tsx` | +| 项目管理 | `/projects` | `pages/projects/index.tsx` — ProjectToolbar(Tab 切换 active/archived + 搜索 + 新建) + ProjectTable + ProjectFormModal。支持创建/编辑/归档/恢复/删除,仅 active 项目可跳转工作台。 | +| 模型管理 | `/models` | `pages/models/index.tsx` — antd Tabs 切换供应商/模型视图。模型表单和表格使用 `GET /api/providers/options`。供应商表单支持预保存连通性测试(`POST /api/providers/test`),新建时 type 默认 `openai-compatible`,测试 `ok: false` 展示失败但不阻止保存。 | +| 聊天室 | `/workbench/:id` | `consoles/workbench/pages/ChatPage.tsx` | +| 404 | `*` | `pages/404/index.tsx` | ### 聊天页面 -Workbench 聊天页面位于 `src/web/consoles/workbench/pages/ChatPage.tsx`,组合 `ChatSidebar` 和 `ChatPanel` 两个子组件。 +`ChatPage` = `ChatSidebar` + `ChatPanel`。 -- **ChatSidebar**(`src/web/consoles/workbench/components/chat/ChatSidebar.tsx`):使用 TanStack Query 管理会话列表,提供创建和删除会话操作。 -- **ChatPanel**(`src/web/consoles/workbench/components/chat/ChatPanel.tsx`):使用 Vercel AI SDK `useChat` hook(来自 `@ai-sdk/react`)管理聊天状态,通过 `DefaultChatTransport`(来自 `ai` 包)与后端 SSE 端点通信。采用论坛式单列垂直布局,使用 antd `Card` 组件承载每条消息,通过按 `part.type` 分派渲染(文本/推理/工具调用)。AI 文本使用 `streamdown` 流式 Markdown 渲染。支持编辑上一条用户消息后重新发送、重新生成最后一条 AI 回复、复制消息内容。 -- **ChatInputArea**(`src/web/consoles/workbench/components/chat/ChatInputArea.tsx`):使用 antd `Input.TextArea` + `Button` + `Select` 组合,支持模型切换和发送/停止操作。 -- **Part renderers**(`src/web/consoles/workbench/components/chat/parts/`):`TextPart.tsx`(Markdown 文本渲染)、`ReasoningPart.tsx`(推理过程)、`ToolPart.tsx`(工具调用展示,支持 input-streaming/input-available/output-available/output-error 四态)。 +- **ChatSidebar**:TanStack Query 管理会话列表,创建/删除操作。 +- **ChatPanel**:`useChat`(@ai-sdk/react)+ `DefaultChatTransport`(ai 包)与后端 SSE 通信。按 `part.type` 分派渲染:TextPart(streamdown Markdown)、ReasoningPart、ToolPart(四态)。支持编辑重发、重新生成、复制。 +- **ChatInputArea**:`Input.TextArea` + `Button` + `Select`(模型切换)。 -`use-conversations` hook 位于 `src/web/hooks/use-conversations.ts`,封装会话 CRUD 和消息获取的 fetch 调用。 +## Hooks -## Hooks 索引 +| Hook | 说明 | +| ----------------------- | ----------------------------------------- | +| `use-meta.ts` | `/api/meta`(30s 轮询,5s staleTime) | +| `use-projects.ts` | 项目 CRUD + archive/restore | +| `use-providers.ts` | 供应商 CRUD + test connection | +| `use-models.ts` | 模型 CRUD + test connection | +| `use-conversations.ts` | 会话和消息 fetch 函数(不含 Query hooks) | +| `use-theme-preference` | 主题偏好 localStorage 持久化 | +| `use-sidebar-collapsed` | 侧边栏折叠 localStorage 持久化 | -| Hook 文件 | 说明 | -| -------------------------- | ------------------------------------------------- | -| `use-meta.ts` | 获取 `/api/meta`(30s 轮询,5s staleTime) | -| `use-projects.ts` | 项目 CRUD + archive/restore API | -| `use-providers.ts` | 供应商 CRUD + test connection API | -| `use-models.ts` | 模型 CRUD + test connection API | -| `use-conversations.ts` | 会话和消息 fetch 函数(不含 Query hooks) | -| `use-theme-preference.ts` | 主题偏好(明亮/黑暗/跟随系统)localStorage 持久化 | -| `use-sidebar-collapsed.ts` | 侧边栏折叠状态 localStorage 持久化 | +## 工具函数 -## 工具函数索引 - -| 文件 | 说明 | +| 文件 | 导出 | | --------------- | --------------------------------------------------------------------------------------------- | -| `utils/api.ts` | `handleResponse()`、`handleVoidResponse()` — 通用 fetch 响应处理 | +| `utils/api.ts` | `handleResponse(response, extract)`、`handleVoidResponse(response)` | | `utils/time.ts` | `formatCountdown`、`formatDurationUnit`、`formatRelativeTime`、`isOlderThan`、`subtractHours` | ## 更新触发条件 diff --git a/docs/development/release.md b/docs/development/release.md index 23a757d..badda52 100644 --- a/docs/development/release.md +++ b/docs/development/release.md @@ -1,106 +1,60 @@ # 构建与发布 -本文档说明开发服务、前后端集成、生产构建、脚本维护和环境变量。 +## 开发运行 -适用场景:修改 scripts/、构建流程、静态资源集成或环境变量。 +- `bun run dev config.yaml` — 双进程(Bun API server --watch + Vite dev server HMR) +- `bun run dev:server config.yaml` — 仅后端 +- `bun run dev:web` — 仅前端 -## 开发期运行 - -```bash -bun run dev config.yaml -``` - -scripts/dev.ts 同时启动两个进程: - -| 进程 | 用途 | -| --------------- | --------------------------------------- | -| Bun API server | 后端 API 服务,--watch 监听变更自动重启 | -| Vite dev server | 前端 SPA、HMR 热更新 | - -也可以单独启动: - -```bash -bun run dev:server config.yaml # 仅启动后端 API server -bun run dev:web # 仅启动 Vite dev server -``` +开发模式 Vite proxy 将 /api/\* 转发到 Bun。 ## 前后端集成 -开发模式下,Vite 通过 proxy 将 /api/\* 转发到 Bun。 +生产模式:Vite 构建为静态资源 → `import with { type: "file" }` 嵌入 Bun 可执行文件 → 非 API 路径 fetch fallback 处理。 -生产模式下,前端通过 Vite 构建为静态资源,通过 import with { type: "file" } 嵌入 Bun 可执行文件。非 API 路径由 fetch fallback 处理。 - -路由优先级:Bun routes 具体路径 > 通配符。/api/meta 优先于 /api/\*。 +路由优先级:Bun routes 具体路径 > 通配符。`/api/meta` 优先于 `/api/*`。 ## 构建 -```bash -bun run build -``` +`bun run build` 流程: -构建流程: +1. `Vite build` → `dist/web/` +2. `Code generation` → `.build/static-assets.ts` + `.build/migrations-data.ts` + `.build/server-entry.ts` +3. `Bun compile` → `dist/alfred` +4. `Cleanup` → 清理 `.build/` -```text -1. Vite build -> dist/web/ -2. Code generation -> .build/static-assets.ts + .build/migrations-data.ts + .build/server-entry.ts -3. Bun compile -> dist/alfred -4. Cleanup -> 清理 .build/ 临时目录 -``` +构建参数:`BUN_TARGET` / `BUILD_TARGET` — 交叉编译目标平台。 -构建参数: +## 脚本 -| 环境变量 | 说明 | -| ------------------------- | ---------------- | -| BUN_TARGET / BUILD_TARGET | 交叉编译目标平台 | +| 脚本 | 文件 | 说明 | +| ----------------------------- | --------------------------------- | ------------------------ | +| dev | scripts/dev.ts | 双进程开发服务 | +| dev:server | src/server/dev.ts | 仅后端 | +| dev:web | Vite CLI | 仅前端 | +| build | scripts/build.ts | Vite → codegen → compile | +| schema | scripts/generate-config-schema.ts | 生成 JSON Schema | +| schema:check | (同上) | 检查 Schema 同步 | +| clean | scripts/clean.ts | 清理构建缓存 | +| version:patch/minor/major/set | scripts/bump-version.ts | 版本升迁 | -## 脚本说明 +内部辅助:`scripts/bump-version-logic.ts`(版本逻辑)、`scripts/generate-migrations-data.ts`(构建时嵌入 SQL)。 -| 脚本 | 文件 | 说明 | -| --------------------- | --------------------------------- | ------------------------------ | -| bun run dev | scripts/dev.ts | 双进程开发服务 | -| bun run dev:server | src/server/dev.ts | 仅启动后端 API server | -| bun run dev:web | Vite CLI | 仅启动 Vite dev server | -| bun run build | scripts/build.ts | Vite -> codegen -> Bun compile | -| bun run schema | scripts/generate-config-schema.ts | 生成配置 JSON Schema | -| bun run schema:check | scripts/generate-config-schema.ts | 检查配置 JSON Schema 同步 | -| bun run clean | scripts/clean.ts | 清理构建缓存与临时文件 | -| bun run version:patch | scripts/bump-version.ts | 升迁 patch 版本 | -| bun run version:minor | scripts/bump-version.ts | 升迁 minor 版本 | -| bun run version:major | scripts/bump-version.ts | 升迁 major 版本 | -| bun run version:set | scripts/bump-version.ts | 显式设置版本号 | -| bun test | (Bun 内置) | 运行全部测试 | +## 配置文件 -内部辅助脚本(不直接对外开放): - -| 文件 | 说明 | -| ----------------------------------- | ---------------------------------------------- | -| scripts/bump-version-logic.ts | 版本号升迁/设置的逻辑实现 | -| scripts/generate-migrations-data.ts | 构建时将 drizzle/\*.sql 嵌入为 TypeScript 模块 | - -## 项目配置文件 - -| 文件 | 用途 | -| -------------------- | --------------------------- | -| package.json | 项目信息、脚本、依赖声明 | -| tsconfig.json | TypeScript 配置 | -| eslint.config.js | ESLint 规则 | -| commitlint.config.js | commitlint 提交信息格式校验 | -| .prettierrc.json | Prettier 格式化规则 | -| .lintstagedrc.json | lint-staged 配置 | -| config.example.yaml | 配置文件示例 | -| config.schema.json | 配置文件 JSON Schema | -| vite.config.ts | Vite 构建配置 | -| bunfig.toml | Bun 配置 | -| drizzle.config.ts | Drizzle ORM 配置 | - -## 验证期望 - -| 变更类型 | 验证方式 | -| ---------------- | -------------------- | -| 构建脚本 | bun run verify | -| 静态资源集成 | bun run build | -| 配置 schema 同步 | bun run schema:check | -| 发布前完整验证 | bun run verify | +| 文件 | 用途 | +| -------------------- | -------------------- | +| package.json | 项目信息、脚本、依赖 | +| tsconfig.json | TypeScript 配置 | +| eslint.config.js | ESLint 规则 | +| commitlint.config.js | 提交信息格式校验 | +| .prettierrc.json | Prettier 规则 | +| .lintstagedrc.json | lint-staged 配置 | +| config.example.yaml | 配置示例 | +| config.schema.json | 配置 JSON Schema | +| vite.config.ts | Vite 构建配置 | +| bunfig.toml | Bun 配置 | +| drizzle.config.ts | Drizzle ORM 配置 | ## 更新触发条件 From b3f77e8ac6b0ea6a1c94b0b687c3aa03e554a5c1 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Mon, 1 Jun 2026 16:51:29 +0800 Subject: [PATCH 4/4] =?UTF-8?q?docs:=20=E7=BB=86=E5=8C=96=20config.yaml=20?= =?UTF-8?q?subagent=20=E4=BD=BF=E7=94=A8=E6=8C=87=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openspec/config.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openspec/config.yaml b/openspec/config.yaml index 99b18fb..98b107d 100644 --- a/openspec/config.yaml +++ b/openspec/config.yaml @@ -23,7 +23,10 @@ context: | - 禁止创建 git 操作 task ## 工作方式 - - 积极使用 subagents 并行任务,节省上下文空间 + - 积极使用 subagent 并行独立子任务,节省上下文空间;能并行的步骤明确并行 + - subagent 仅用于只读收集和分析,禁止用于文件修改、代码生成、git 操作或依赖安装 + - 单个文件或目录只分配给一个 subagent,不重复分配;subagent 输出文件路径、行号和问题摘要,不输出大段源码 + - 主 agent 负责最终结论:去重、交叉验证、合并同根因问题 - 优先使用提问工具对用户确认 rules: