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 配置 | ## 更新触发条件