8.3 KiB
后端开发
本文档说明 alfred 后端的模块实现细节、API 索引和开发方式。开发规范(库优先级、类型规范、配置契约、API 路由规范、测试约定等)见 开发规范文档。
适用场景:修改 src/server/、了解现有模块 API、查找可供复用的工具函数和数据访问接口。
共享工具
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
src/server/middleware/ 提供 API 参数校验和错误处理中间件:
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 和未知异常
数据库
项目使用 SQLite 作为存储后端,通过 bun:sqlite + Drizzle ORM 实现类型安全的数据访问。
schema 定义
src/server/db/schema.ts 使用 Drizzle ORM 定义表结构,列名使用 snake_case,TypeScript 类型使用 camelCase,Drizzle schema 负责映射。
数据库连接
src/server/db/connection.ts 的 createDatabase(dataDir, logger) 打开 <dataDir>/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 到
<dataDir>/backups/alfred-<timestamp>.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。
AI 服务层
src/server/ai/ 提供 AI Provider Registry 构建与连接测试能力。
类型定义
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 RegistrytestProviderConnection(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 |
|---|---|
openai |
createOpenAI({ apiKey, baseURL }) |
anthropic |
createAnthropic({ apiKey, baseURL }) |
openai-compatible |
createOpenAICompatible({ name, apiKey, baseURL }) |
聊天 API
聊天 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。
日志模块
后端运行时代码统一通过 Logger 接口输出日志。
| 实现 | 用途 |
|---|---|
| PinoLoggerWrapper | 生产运行时 |
| ConsoleFallbackLogger | 配置加载失败前的降级日志 |
| NoopLogger | 静默丢弃日志 |
| MemoryLogger | 测试替身 |
版本管理
版本号以 package.json.version 为唯一来源。
版本获取方式:
- 开发模式:
src/server/version.ts运行时从 package.json 读取 - 生产模式:
scripts/build.ts在构建时将版本号烘焙为字面量注入
版本升迁命令:
bun run version:patch # 升迁 patch 版本
bun run version:minor # 升迁 minor 版本
bun run version:major # 升迁 major 版本
bun run version:set # 显式设置版本号
更新触发条件
修改后端模块 API、共享工具、数据库 schema、AI 服务层或聊天 API 时,必须更新本文档。