Files

开发规范

AI 工具必须严格遵守以下全部约束。

专题文档

文档 内容
architecture.md 项目结构、启动流程、前后端边界
backend.md 模块 API、数据访问函数、AI 层说明
frontend.md 组件索引、页面组成、hooks/工具清单
release.md 开发服务、构建、脚本、环境变量

一、全局规则

语言与环境

  • 使用中文编写注释、文档和交流内容。
  • 仅使用 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/依赖库;确需新增依赖时先说明原因。

ZodAI 工具层(src/server/ai/tools/)使用 Zod 定义 tool()inputSchema,以满足 AI SDK 对 ZodSchema 的类型推断要求,属于框架级约束而非项目选型冲突。配置校验层使用 TypeBox + Ajv两层级各司其职不混用。

目录边界

目录 约束
src/server/ 后端,禁止 import src/web/
src/server/db/ 数据库层schema、connection、migration、DAO
src/server/ai/ AI Provider Registry + Agent + 工具
src/server/config/ 配置子系统types、variables、issues、schema
src/server/helpers/ 跨路由工具响应格式化、URL 拼接
src/server/middleware/ 参数校验 + 错误处理中间件
src/web/ 前端,禁止 import src/server/ 运行时实现
src/web/layouts/ 布局组件AdminLayout / WorkbenchLayout
src/web/features/ 功能模块dashboard / projects / models / chat 等)
src/web/shared/ 前端共享代码components / hooks / utils / types
src/shared/ 前后端共享类型api.ts和常量app.ts
scripts/ 独立脚本,可 import 项目源码
drizzle/ SQL migration 文件(开发期产出)
tests/ 测试目录,镜像 src/ 结构

前端目录使用规范

目录职责定义

src/web/
├── main.tsx              ← 入口Provider 装配、全局初始化)
├── app.tsx               ← App 组件(路由挂载)
├── routes.tsx            ← 全局路由表(集中声明)
├── styles.css            ← 全局样式
├── menu.tsx              ← 菜单配置类型定义
├── layouts/              ← 布局组件
│   ├── admin-layout/     ←   Admin 布局 + 侧边栏 + 菜单配置
│   └── workbench-layout/ ←   Workbench 布局 + 项目上下文 + 入口守卫
├── features/             ← 功能模块(核心目录)
│   ├── dashboard/        ←   仪表盘页面 + 私有组件/hooks
│   ├── projects/         ←   项目管理页面 + 私有组件/hooks
│   ├── models/           ←   模型管理页面 + 私有组件/hooks
│   ├── chat/             ←   聊天页面 + 私有组件/hooks
│   └── <新增功能>/       ←   新功能直接新增目录
├── shared/               ← 跨 feature 共享代码
│   ├── components/       ←   通用 UI 组件ErrorBoundary, Sidebar, ConsoleShell 等)
│   ├── hooks/            ←   通用 hooksuse-logger, use-theme-preference, use-sidebar-collapsed 等)
│   ├── utils/            ←   通用工具函数api, logger, time
│   └── types.ts          ←   前端内部共享类型
└── css.d.ts              ← CSS 模块类型声明

依赖规则

layouts/   →  shared/      ✅ 布局可使用共享代码
features/* →  shared/      ✅ 功能模块可使用共享代码
features/* →  layouts/     ❌ 功能模块不依赖布局(路由表负责组合)
features/A →  features/B   ❌ 功能模块间禁止直接依赖
shared/    →  features/*   ❌ 共享代码不依赖功能模块

feature 内部组织

每个 feature 目录自治,不强制统一内部结构,按需组织以下子目录:

features/<name>/
├── index.tsx             ← 页面组件(必须,路由入口)
├── components/           ← 私有 UI 组件
├── hooks/                ← 私有 hooks如 use-conversations 仅 chat 使用)
├── utils/                ← 私有工具函数
└── types.ts              ← 私有类型定义
  • 只有 index.tsx(页面组件)是必需的,其他按实际复杂度按需创建。
  • feature 内部文件只在本 feature 内导入。被外部使用的必须提升到 shared/

组件归属判定规则

判定维度 放在 feature/ 放在 shared/
使用范围 仅一个功能模块使用 两个及以上功能模块使用
业务耦合 包含特定业务逻辑(如项目 CRUD 表单、聊天消息渲染) 纯展示或通用交互(如 ErrorBoundary、侧边栏
数据依赖 依赖特定 API 或业务数据 无业务数据依赖或通过 props 注入
可替换性 替换需理解业务上下文 可直接复用于任何页面

组件升降级流程

升级feature → shared 当一个 feature 内的组件/hook/tool 同时满足以下条件时,应提升到 shared/

  1. 至少被 2 个不同的 feature 或 layout 使用
  2. 已消除对原 feature 业务逻辑的直接依赖(数据通过 props/callback 注入)
  3. 有清晰的 props 接口定义

升级步骤:

  1. 将文件从 features/<name>/ 移动到 shared/ 对应子目录
  2. 更新所有 import 路径
  3. 如原 feature 有对应的测试文件,一并迁移(tests/web/shared/
  4. 运行 bun run check 确认无遗漏

降级shared → feature 当一个 shared 组件/hook/tool 仅被一个 feature 使用时,应降级到该 feature 内部:

  1. 确认仅一个消费方(全局搜索 import
  2. 移动到消费方 feature 的对应子目录
  3. 更新 import 路径
  4. 迁移对应测试文件
  5. 运行 bun run check 确认无遗漏

新增功能开发检查清单

新增功能模块时按以下顺序操作:

  1. features/ 下创建以功能名命名的目录kebab-case
  2. 创建 index.tsx 作为页面组件入口
  3. routes.tsx 中注册路由,选择对应 layout 包裹
  4. 如需布局内菜单项,更新对应 layout 的菜单配置
  5. 组件/hooks/utils 先写在 feature 内部
  6. 当确认需要跨 feature 复用时,按升级流程提升到 shared/
  7. 测试文件创建在 tests/web/features/<name>/

禁止事项

  • 禁止在 feature 目录外直接创建页面组件(pages/ 目录不再使用)
  • 禁止 feature 间通过 ../features/other-feature/ 直接导入
  • 禁止在 shared/ 中放置仅单个 feature 使用的代码
  • 禁止跳过升降级流程直接在 shared/ 中新建"预判通用"的代码(先写 feature确认复用后再提升

类型与配置

  • 共享类型唯一源头:src/shared/api.ts;应用常量唯一源头:src/shared/app.ts;版本号唯一源头:package.json
  • 配置加载流程unknown → AuthoringConfig → NormalizedConfig → ValidatedConfig → ResolvedConfig。
  • 配置系统入口:src/server/config.ts(统一配置加载、运行时校验、默认值解析)。
  • Ajv 严格拒绝模式:不类型转换、不注入默认值、不删除未知字段。
  • 新增/修改配置字段必须同步更新 TypeBox schema、config.schema.json、测试和用户文档。

后端日志

  • 运行时代码通过 Logger 接口输出,禁止 console.*(仅 logger.ts 实现类内部可用)。
  • 敏感字段authorization、cookie、password 等)自动 redact。

API 路由

  • 每个端点一个文件:src/server/routes/{资源}/{操作}.ts
  • 路由在 server.tsBun.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 });未知异常直接 throwwithErrorHandler 兜底。
  • 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 映射。
  • 软删除:所有业务表使用 deleted_at 列,通过 notDeleted(table)paginateQuery({ softDelete }) 过滤。deleted_at 不暴露到 API 层。
  • 唯一性:无数据库级 UNIQUE 约束DAO 层应用校验(同字段 + deleted_at IS NULL)。
  • 表定义:通过 helpers.tsbaseColumns 展开 id/created_at/updated_at/deleted_at禁止直接 sqliteTable()oxlint 强制)。

AI 调用层

  • Provider 实例:buildProviderRegistry(db),每次从 DB 重建,不缓存。
  • Agent 实例:createAlfredAgent(model) 工厂。
  • SSE 响应:createAgentUIStreamResponseonFinish 持久化完整 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. 已有 hooksshared/hooks/use-*.ts)和工具函数(shared/utils/
  6. CSS Modules就近放置在 feature 内部)
  7. 引入新依赖(需说明原因)

前端代码组织

  • 新增页面在 features/ 下创建功能目录,不使用 pages/
  • 新增组件/hook/tool 默认放在所属 feature 内部;跨 feature 复用时提升到 shared/
  • 布局组件放 layouts/,布局与页面通过 routes.tsx 组合,不互相导入。
  • 详细规则见上方「前端目录使用规范」章节。

样式红线

  • 严禁内联 style、覆盖 .ant-*!important、硬编码色值。
  • 颜色使用 var(--ant-*) CSS 变量。
  • 不引入 Tailwind/Sass/Less/CSS-in-JS 等额外样式方案。
  • 全局 CSS 类名用 app-* 前缀,禁止泛名。样式增长后用 CSS Modules 就近维护。

表单与交互

  • Modal + FormForm onFinish 处理提交,Modal onOk 只调 form.submit()
  • 必填文本字段同时配 required + whitespace
  • 操作确认用 Popconfirm,反馈用 antd message。

错误边界

  • 生产入口必须启用 ErrorBoundaryReactQueryDevtoolsDEV 模式渲染。

四、测试规范

后端

  • 路由测试通过真实 startServer 覆盖路由注册、HTTP method、fallback、header 和核心错误路径。
  • SQLite 测试复用 tests/helpers.ts,不分散实现临时目录清理。
  • DAO/路由测试优先用真实 migration 初始化。
  • logger/bootstrap fallback 输出须捕获断言,正常测试不污染 stdout/stderr。

前端

  • 目录 tests/web/,结构对应 src/web/
  • 用 happy-dom + @testing-library/react 测试用户行为,断言基于可见文本/role/按钮。
  • 系统边界复用 tests/web/test-utils.tsx
  • 数据页面覆盖:请求参数、成功可见结果、关键错误路径。
  • ErrorBoundary/hooks/fetch helper 用单元测试覆盖异常,页面测试只保留用户路径。

常用命令

命令 说明
bun run dev config.yaml 启动双进程开发环境
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 verify check + build 完整验证
bun run build 构建生产可执行文件
bun run schema 生成 config.schema.json
bun run schema:check 检查 schema 同步
bun run typecheck TypeScript 类型检查
bun run lint oxlint 检查(--deny-warnings
bun run format oxfmt 格式化
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 schemabun run schema:checkbun run check
SQLite 测试基础设施变化 相关测试 + SQLite 聚焦 --rerun-each + bun run check
仅文档变更 检查链接、索引和文档归属一致性

正式提交优先运行 bun run verify。无法执行时须在收尾说明中记录。

已知设计决策

决策 原因
Provider.apiKey 返回给前端 个人项目apiKey 非严格密码,前端需要展示和编辑。如需保护,应改为返回脱敏值或仅后端存储。

文档影响分析

变更影响 更新
用户可见行为、配置、部署、运行行为 docs/user/ 对应文档
开发流程、架构、测试、构建发布流程 docs/development/ 对应文档
项目定位、快速开始、核心能力、文档导航 README.md
文档同步规则或归属矩阵 docs/README.mdopenspec/config.yaml
开发规范变化 本文档对应章节

无需更新文档时,须在收尾说明中说明原因。

更新触发条件

修改常用命令、质量门禁、开发规范(任何章节)、目录边界或开发文档索引时,必须更新本文档。

文档编撰规范

本节开发文档面向 AI 工具阅读,编撰时遵循以下原则:

精简原则

  • 删除引导语、适用场景、过渡句等装饰性文字。AI 无需"应首先阅读"或"本文档说明…"类引导。
  • 不重复项目结构树AI 可通过 glob 获取目录结构。
  • 不重复已在 README.md 声明的规范细节专题文档只记录实现层面的函数签名、API 端点、模块职责等索引信息。
  • 表格标题自明时不再加说明段落。

信息完整性

  • 所有函数签名、API 端点(方法+路径+说明)、数据访问函数清单必须完整列举,不可用"等"省略。
  • 页面行为描述须包含关键交互逻辑(如 Tab 切换、默认值、条件跳转、测试不阻止保存等),不可只写组件名。
  • 配置文件列表必须完整,不可遗漏已有文件。

结构规范

  • 每个专题文档末尾保留 ## 更新触发条件 章节,明确列出哪些变更必须更新该文档。
  • 用表格和编号列表替代散文段落,减少 token 消耗。
  • 同一信息只在一处维护,避免多处重复导致不一致。