chore: merge dev-document into master

# Conflicts:
#	docs/development/frontend.md
This commit is contained in:
2026-06-01 20:59:48 +08:00
9 changed files with 438 additions and 615 deletions

View File

@@ -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`

View File

@@ -1,120 +1,261 @@
# 开发文档
# 开发规范
本文档是 alfred 的开发入口。AI 工具和开发者应先阅读 [`../README.md`](../README.md) 判断文档归属,再阅读本文和最小必要专题
AI 工具必须严格遵守以下全部约束
适用场景:修改源码、测试、构建脚本、开发流程、架构边界或项目工程规则。
## 专题文档
## 专题索引
| 文档 | 内容 |
| ---------------------------------- | ---------------------------------- |
| [architecture.md](architecture.md) | 项目结构、启动流程、前后端边界 |
| [backend.md](backend.md) | 模块 API、数据访问函数、AI 层说明 |
| [frontend.md](frontend.md) | 组件索引、页面组成、hooks/工具清单 |
| [release.md](release.md) | 开发服务、构建、脚本、环境变量 |
| 文档 | 内容 |
| ---------------------------------- | ---------------------------------------------------------------- |
| [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 文档更新规则 |
---
## 一、全局规则
### 语言与环境
- 使用中文编写注释、文档和交流内容。
- 仅使用 bun 作为包管理器和 bunx 作为工具运行器;禁止 npm、pnpm、yarn、npx、pnpx。
- 无需考虑向前兼容。
### 依赖引入
**后端**优先级(上层已有方案则不得引入新依赖):
1. Bun 内置 APIBun.serve、bun:sqlite 等)
2. es-toolkit
3. 标准 Web APIfetch、Headers 等)
4. 已批准三方库pino、@sinclair/typebox、ajv、drizzle-orm、ai、@ai-sdk/\*
5. 自行实现(仅以上都不满足时)
**前端**:优先复用已有组件/hooks/依赖库;确需新增依赖时先说明原因。
**Zod**:已引入但未使用(预留),配置校验用 TypeBox + Ajv不得混用 Zod。
### 目录边界
| 目录 | 约束 |
| ------------------------ | -------------------------------------------- |
| `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<Response>`
- 业务错误:`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_caseTS 类型 camelCaseDrizzle 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 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`。无法执行时须在收尾说明中记录。
## 已知设计决策
本节记录项目中有意保留的设计决策,避免后续审查重复报错。
| 决策 | 原因 |
| -------------------------- | ----------------------------------------------------------------------------------------- |
| 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 变更管理与规格文档 |
## 文档影响分析
每次代码变更都必须执行文档影响分析。
| 变更影响 | 更新 |
| -------------------------------------- | ------------------------------------------ |
| 用户可见行为、配置、部署、运行行为 | `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)。
## 事实来源
| 主题 | 事实来源 |
| -------------- | -------------------------------------------------- |
| 代码结构和实现 | `src/``scripts/``tests/` |
| 配置 schema | TypeBox fragments、config.schema.json、schema 测试 |
| 项目全局规则 | `openspec/config.yaml`、本文档、本目录专题文档 |
无需更新文档时,须在收尾说明中说明原因。
## 更新触发条件
修改常用命令、质量门禁、全局工程规则、目录边界或开发文档索引时,必须更新本文档。
修改常用命令、质量门禁、开发规范(任何章节)、目录边界或开发文档索引时,必须更新本文档。
### 文档编撰规范
本节开发文档面向 AI 工具阅读,编撰时遵循以下原则:
**精简原则**
- 删除引导语、适用场景、过渡句等装饰性文字。AI 无需"应首先阅读"或"本文档说明…"类引导。
- 不重复项目结构树AI 可通过 glob 获取目录结构。
- 不重复已在 README.md 声明的规范细节专题文档只记录实现层面的函数签名、API 端点、模块职责等索引信息。
- 表格标题自明时不再加说明段落。
**信息完整性**
- 所有函数签名、API 端点(方法+路径+说明)、数据访问函数清单必须完整列举,不可用"等"省略。
- 页面行为描述须包含关键交互逻辑(如 Tab 切换、默认值、条件跳转、测试不阻止保存等),不可只写组件名。
- 配置文件列表必须完整,不可遗漏已有文件。
**结构规范**
- 每个专题文档末尾保留 `## 更新触发条件` 章节,明确列出哪些变更必须更新该文档。
- 用表格和编号列表替代散文段落,减少 token 消耗。
- 同一信息只在一处维护,避免多处重复导致不一致。

View File

@@ -1,118 +1,60 @@
# 架构与边界
本文档说明 alfred 的项目结构、启动链路、运行时流程、HTTP 请求流程和前后端边界。
适用场景修改目录边界、启动流程、运行时调度、HTTP server、前后端集成方式或主要模块职责。
## 项目结构
```text
src/
server/
bootstrap.ts 统一启动引导loadServerConfig -> DB 初始化 -> startServer
config.ts CLI 参数解析与配置文件加载 facade
config/ 配置解析模块types、issues、variables、normalizer、schema
db/ SQLite 数据库模块
schema.ts Drizzle ORM schema 定义
connection.ts 数据库连接与 PRAGMA 设置
load-migrations.ts 从文件系统加载 migration SQL
migrate.ts migration 执行器(备份 + 事务应用)
projects.ts 项目数据访问函数
providers.ts 供应商数据访问函数
models.ts 模型数据访问函数
conversations.ts 会话数据访问函数
index.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.ts 共享响应格式化工具
middleware.ts API 参数校验中间件
logger.ts 结构化日志(基于 pino + pino-roll
version.ts 运行时版本号读取
routes/ API 路由处理器
providers/ 供应商 CRUD 路由
models/ 模型 CRUD 路由
chat/ 聊天会话与消息路由
shared/
api.ts 前后端共享 TypeScript 类型定义
app.ts 应用全局常量name、title、subtitle、description
web/ React 前端(通过 Vite 构建)
index.html HTML 入口
main.tsx React 入口
app.tsx 根组件
routes.tsx 路由配置
styles.css 全局样式
pages/ 页面组件
models/ 模型管理页面
components/ UI 组件
hooks/ React Hooks
utils/ 前端工具函数
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.ts 响应格式化
-> 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按端点拆分 |
| `src/server/db/` | SQLite 连接、schema、migrationdata 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资源端点拆分 |
| `src/server/db/` | SQLite 连接、schema、migrationdata 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/` |
| models | `/api/models` | `routes/models/` |
| projects | `/api/projects` | `routes/projects/` |
| chat | `/api/projects/:id/conversations``:id/chat` | `routes/chat/` |
## 更新触发条件

View File

@@ -1,104 +1,50 @@
# 后端开发
本文档说明 alfred 后端的 API、配置加载、日志、版本管理和后端测试开发约定
适用场景:修改 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/ 下创建 <name>.ts
2. 实现 handler 函数并 export
3. 在 server.ts 的 routes 对象中注册路径和 method handler
4. 在 tests/server/ 中添加对应测试
开发规范见 [开发规范文档](README.md)
## 共享工具
helpers.ts 提供跨路由共用的响应工具:
`src/server/helpers/`:
- createApiError(error, status) — 构造 API 错误体
- createHeaders(mode, init) — 创建响应 Headers
- jsonResponse(body, options) — JSON 响应构造
- `response.ts``createApiError(error, status)``createHeaders(mode, init)``createMetaResponse(version)``formatDuration(ms)``jsonResponse(body, options)`
- `url.ts``parseIdFromUrl(url)`
middleware.ts 提供 API 参数校验函数:
`src/server/middleware/`:
- 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 捕获异常
## 数据库
项目使用 SQLite 作为存储后端,通过 bun:sqlite + Drizzle ORM 实现类型安全的数据访问
SQLite + bun:sqlite + Drizzle ORM。
### schema 定义
- `src/server/db/schema.ts`Drizzle 表结构,列名 snake_caseTS 类型 camelCase。
- `src/server/db/connection.ts``createDatabase(dataDir, logger)` 打开 `alfred.db`PRAGMAforeign_keys=ON、journal_mode=WAL、busy_timeout=5000。`wrap(db)` 转为 Drizzle 实例。`paginateQuery()` 分页工具。
- Migration开发期 `drizzle-kit generate` 产出到 `drizzle/`;生产期嵌入可执行文件,启动时自动应用。备份到 `<dataDir>/backups/`,事务中执行,失败回滚。
`src/server/db/schema.ts` 使用 Drizzle ORM 定义表结构,列名使用 snake_caseTypeScript 类型使用 camelCaseDrizzle 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)` 打开 `<dataDir>/alfred.db`,设置 PRAGMAforeign_keys=ON、journal_mode=WAL、busy_timeout=5000
### migration 机制
- 开发期:使用 `drizzle-kit generate` 从 TS schema 生成 SQL migration 文件到 `drizzle/` 目录
- 生产期:构建时将 `drizzle/*.sql` 嵌入可执行文件,启动时自动应用 pending migrations
- 每次 migration 前自动备份现有 DB 到 `<dataDir>/backups/alfred-<timestamp>.db`
- migration 在事务中执行,失败则回滚并停止启动
### 数据访问
`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/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 和模型列表接口
每次 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 |
| ------------------- | --------------------------------------------------- |
@@ -106,83 +52,38 @@ middleware.ts 提供 API 参数校验函数:
| `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` | 获取会话详情 |
| 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 回复。
## 类型规范
## 日志
- 共享类型以 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.\*。
| 实现 | 用途 |
| --------------------- | ------------------------ |
| PinoLoggerWrapper | 生产运行时 |
| ConsoleFallbackLogger | 配置加载失败前的降级日志 |
| NoopLogger | 静默丢弃日志 |
| MemoryLogger | 测试替身 |
敏感信息会自动 redact authorization、cookie、password 等字段。
| 实现 | 用途 |
| --------------------- | -------------- |
| 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 # 显式设置版本号
```
## 后端测试
| 变更类型 | 测试重点 |
| ------------------ | --------------------------------- |
| 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。
唯一来源:`package.json`。开发模式从 package.json 运行时读取;生产模式构建时烘焙为字面量
## 更新触发条件
修改后端 API、共享类型、配置契约、日志模块、版本管理或后端测试规范时,必须更新本文档。
修改后端模块 API、共享工具、数据库 schema、AI 服务层或聊天 API 时,必须更新本文档。

View File

@@ -1,184 +1,58 @@
# 前端开发
本文档说明 alfred 前端的 React、Ant Design、TanStack Query、组件、样式和前端测试约定
开发规范见 [开发规范文档](README.md)
适用场景:修改 src/web/、前端共享类型使用方式、组件结构、样式规则或前端测试。
## 控制台架构
## 技术栈
两个控制台入口共享 ConsoleShell`src/web/components/ConsoleShell/`
| 层面 | 技术 | 用途 |
| ------ | --------------------------------------------------- | ------------------------ |
| 框架 | 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 路由与页面导航 |
- **Admin**`src/web/consoles/admin/`):路由 `/`(总览)、`/projects``/models`
- **Workbench**`src/web/consoles/workbench/`):路由 `/workbench/:projectId``/workbench/:projectId/chat``WorkbenchProjectGate` 从 URL 读 projectId通过 `ProjectContext` 提供项目上下文,仅 active 项目渲染。
不引入额外状态管理库。TanStack Query 承担服务端状态,组件内状态使用 useState
ConsoleShell 包含:`ConfigProvider(zhCN)` + `AntApp` + `Layout`(Header/Sider/Content) + 主题切换(明亮/黑暗/系统)+ 侧边栏折叠。Header 显示品牌名、版本号和控制台标题
## 组件开发规范
`Sidebar``src/web/components/Sidebar/`)纯展示组件,通过 `menuItems` props 接收配置。
- 每个 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` 作为主页面。
通用 Console Shell`src/web/components/ConsoleShell/ConsoleShell.tsx`)包含 Layout、Header、Sider、Content、主题切换、版本展示和侧边栏折叠状态由 Admin 和 Workbench 复用。Header 显示品牌名、版本号和控制台标题Admin 显示"管理台"Workbench 显示"工作台 · 项目名")。
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 项目显示"项目不存在或不可访问"。
模型管理页面(`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` 不支持或响应格式不兼容属于可忽略提醒,不得阻止保存。
| 页面 | 路径 | 入口 |
| -------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 总览 | `/` | `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**使用 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**TanStack Query 管理会话列表,创建/删除操作。
- **ChatPanel**`useChat`@ai-sdk/react+ `DefaultChatTransport`ai 包)与后端 SSE 通信。`part.type` 分派渲染TextPartstreamdown Markdown、ReasoningPart、ToolPart四态。支持编辑重发、重新生成、复制
- **ChatInputArea**`Input.TextArea` + `Button` + `Select`(模型切换)
- 生产入口必须启用 `ErrorBoundary`,运行时渲染异常使用 antd `Result status="500"` 或等价组件展示。
- `ReactQueryDevtools` 仅在 `import.meta.env.DEV` 条件下渲染,不进入生产渲染路径。
- 主题切换统一通过 `ConfigProvider` 的 antd theme algorithm 控制,不使用硬编码主题色。
## Hooks
## TanStack Query 规范
| 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 持久化 |
- Query key 使用 structured array使用 as const 保持字面量类型
- 全局面板级查询可持续刷新,详情级查询必须按状态条件启用
- 多处页面使用同一后端资源时,应提取共享 hook避免重复定义 fetch 函数。
## 工具函数
## 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(response, extract)``handleVoidResponse(response)` |
| `utils/time.ts` | `formatCountdown``formatDurationUnit``formatRelativeTime``isOlderThan``subtractHours` |
## 更新触发条件
修改前端技术栈、组件边界、数据流、样式规则、测试环境前端验证方式时,必须更新本文档。
修改前端技术栈、组件边界、数据流、样式规则、测试环境前端验证方式、运行时代码结构、页面组成、组件索引或 hooks/工具清单时,必须更新本文档。
## 日志模块

View File

@@ -1,97 +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 | 显式设置版本号 |
## 配置文件
## 项目配置文件
| 文件 | 用途 |
| -------------------- | --------------------------- |
| 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 配置 |
## 验证期望
| 变更类型 | 验证方式 |
| ---------------- | -------------------- |
| 构建脚本 | 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 配置 |
## 更新触发条件

View File

@@ -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 splittingvendor-react、vendor-antd、vendor-chart

View File

@@ -38,8 +38,6 @@ bun run dev config.yaml
| 项目管理 | `/projects` | 创建、编辑、归档、恢复和永久删除项目 |
| 模型管理 | `/models` | 配置 AI 供应商和模型,供后续 AI 功能使用 |
| 聊天室 | `/workbench/:projectId` | Workbench 工作台聊天室,与 AI 对话 |
| 用户管理 | `/users` | 页面建设中 |
| 系统设置 | `/settings` | 页面建设中 |
平台提供两个入口: