Files
Alfred/docs/development/backend.md

9.3 KiB
Raw Permalink Blame History

后端开发

开发规范见 开发规范文档

共享工具

src/server/helpers/:

  • response.tscreateApiError(error, status)createHeaders(mode, init)createMetaResponse(version)formatDuration(ms)jsonResponse(body, options)
  • url.tsparseIdFromUrl(url)
  • list-params.tsparseListParams(url, mode, options?) — 统一校验分页/排序参数,替代 validatePagination
  • pagination.tspaginateQuery() — Drizzle 分页查询封装

src/server/middleware/:

  • validate.tsvalidateIdParam(idStr, mode) — 校验 ID 格式(字母数字 + _-validatePagination(pageParam, pageSizeParam, mode) — page≥1, pageSize≤200validateTimeRange(from, to, mode)
  • error-handler.tsAppError — 业务异常类(含 statusCodewithErrorHandler(fn, mode, logger?) — 包裹 handler 捕获异常

数据库

SQLite + bun:sqlite + Drizzle ORM。

  • src/server/db/schema.tsDrizzle 表结构,列名 snake_caseTS 类型 camelCase。所有业务表通过 helpers.tsbaseColumns 获取 id/created_at/updated_at/deleted_at。
  • src/server/db/helpers.tsbaseColumns 常量id、createdAt、updatedAt、deletedAt+ Drizzle 构建器再导出。src/server/db/ 内禁止直接从 drizzle-orm/sqlite-core 导入 sqliteTableESLint 强制)。
  • src/server/db/connection.tscreateDatabase(dataDir, logger) 打开 alfred.dbPRAGMAforeign_keys=ON、journal_mode=WAL、busy_timeout=5000。wrap(db) 转 Drizzle 实例(DrizzleDB 类型)。工具函数:timestamp()notDeleted(table)softDeleteRecord(db, table, id)paginateQuery()(支持 softDelete 参数自动过滤已删除行)。
  • Migration开发期 drizzle-kit generate 产出到 drizzle/;生产期嵌入可执行文件,启动时自动应用。备份到 <dataDir>/backups/,事务中执行(迁移期间临时关闭外键检查),失败回滚。

软删除

所有业务表projects、providers、models、conversations、materials、messages使用 deleted_at 列实现软删除,不暴露给 API 层。DAO 查询通过 notDeleted(table)paginateQuery({ softDelete }) 自动过滤已删除行。唯一性校验在应用层完成(同名 + deleted_at IS NULL),无数据库级 UNIQUE 约束。级联软删除:删除项目 → 级联软删除会话(→ 消息)+ 素材;删除会话 → 级联软删除消息;删除供应商 → 需无未删除模型。

数据访问函数

文件 函数
projects.ts createProject、getProject、listProjects、updateProject、deleteProject、archiveProject、restoreProject
providers.ts createProvider、getProvider、listProviders、listProviderOptions、updateProvider、deleteProvider
models.ts createModel、getModel、listModels、getModelWithProvider、getModelsByProviderId、updateModel、deleteModel
conversations.ts createConversation、getConversation、listConversations、updateConversation、updateConversationTimestamp、deleteConversation、createMessage、createMessages、listMessages
materials.ts createMaterial、getMaterial、listMaterials、deleteMaterial、approveMaterial、discardMaterial、retryMaterial

输入输出类型来自 src/shared/api.ts

AI 服务层

  • src/server/ai/types.tsAIProviderConfigname、type、baseUrl、apiKeyAIModelConfigproviderId、modelId、capabilities。注AI 层 modelId 对应 DB 层 Model.externalId
  • src/server/ai/registry.ts
    • buildProviderRegistry(db) — 从 DB 查询供应商构建 AI SDK Provider Registry每次调用重建不缓存。通过 registry.languageModel('providerId:modelId') 获取模型实例。
    • testProviderConnection(config, logger) — 测试 Base URL 可达性 + /models 接口
    • testModelConnection(config, logger) — 测试模型连通性(需传入含 modelId 的合并配置)
  • src/server/ai/agents/alfred-agent.tscreateAlfredAgent(model) — ToolLoopAgent + stepCountIs(20) + getCurrentTime 工具。
  • src/server/ai/tools/AI 工具定义。

供应商类型

type AI SDK factory
openai createOpenAI({ apiKey, baseURL })
anthropic createAnthropic({ apiKey, baseURL })
openai-compatible createOpenAICompatible({ name, apiKey, baseURL })

连通性测试

  • POST /api/providers/test — 用未保存配置测试,不写入 DB不阻止保存。Base URL 不可达或 API Key 无效返回 ok: false/models 不支持返回 ok: true + 提示。
  • POST /api/models/test — 用模型关联供应商 + externalId 测试。

素材 API

方法 路径 说明
GET /api/projects/:id/materials 列出项目下素材(分页+状态筛选)
POST /api/projects/:id/materials 创建素材
GET /api/projects/:id/materials/:mid 获取素材详情
DELETE /api/projects/:id/materials/:mid 删除素材(软删除)
POST /api/projects/:id/materials/:mid/approve 审核通过(需 review 状态)
POST /api/projects/:id/materials/:mid/discard 审核放弃(需 review 状态)
POST /api/projects/:id/materials/:mid/retry 重试处理(需 failed 状态)

素材状态流转:pending → processing → review → approved/discarded,失败分支 processing → failed,用户重试 failed → pending。共 6 种状态:pendingprocessingreviewapproveddiscardedfailed

素材类型:general(通用)和 meeting(会议),创建时可选,默认 general

校验description 必填非空associatedDate 必填 YYYY-MM-DD项目须存在且 active 且未删除,素材归属校验不匹配返回 403。processing 状态禁止删除409。approve/discard 仅限 review 状态409retry 仅限 failed 状态409

素材处理引擎

src/server/processing/

  • processor.tsMaterialProcessor 类 — 后台定时扫描 pending 素材,按 FIFO 顺序处理(每 5 秒扫描一次),每次处理最多重试 3 次,成功后 status=review 并设置 processedContent全部失败后 status=failed。启动时自动恢复所有 processing 状态的素材为 pendingrecoverStuckMaterials)。
  • templates/:处理模板目录 — general.ts(通用模板)和 meeting.ts(会议模板),当前为占位实现(原样回显 descriptionindex.ts 导出 ProcessingTemplate 类型和 getTemplate(type) 映射函数。
  • index.tsstartMaterialProcessor(db, logger) — 工厂函数,创建并启动处理器实例。

处理器在 bootstrap.ts 中启动shutdown 时先停止处理器再关闭数据库。

聊天 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 发送消息SSE 回复

send.ts:验证会话归属 → 保存用户消息 → createAlfredAgentcreateAgentUIStreamResponseonFinish 持久化 AI 回复。

日志

实现 用途
PinoLoggerWrapper 生产运行时
ConsoleFallbackLogger 配置加载前降级
NoopLogger 静默丢弃
MemoryLogger 测试替身

版本管理

唯一来源:package.json。开发模式从 package.json 运行时读取;生产模式构建时烘焙为字面量。

更新触发条件

修改后端模块 API、共享工具、数据库 schema、AI 服务层、聊天 API 或列表查询参数解析时,必须更新本文档。管理页面 CRUD 通用模式的详细约定见 crud.md