docs: update forest AI setup and verification

This commit is contained in:
2026-07-21 21:23:21 +08:00
parent 7f71c971eb
commit fff6cdcba7
2 changed files with 336 additions and 104 deletions

214
README.md
View File

@@ -1,76 +1,143 @@
# SenlinAI Agent Workbench
# 森林AI
SenlinAI Agent Workbench 是一个以项目为中心的私有化工作台 MVP。
## 产品定位
## 本地开发
森林AI 是一个以项目为中心、面向私有化部署的工作台 MVP服务于个人知识工作者、团队负责人和可信的内部用户。它把项目、任务、Inbox 收集、Markdown 笔记、文件资料、AI 会话、项目内标签和轻量任务分发组织在同一工作区中。
启动本地 PostgreSQL
Web 客户端桌面优先,同时保留移动浏览器可用性;登录页允许输入私有部署服务器的 IP 地址或域名。
## MVP 范围
当前版本包含:
- 项目创建、设置和聚合工作区。
- 项目内任务、标签、文件资料和计划任务元数据。
- Inbox 收集、分析建议和用户确认创建对象的流程。
- 项目、任务和笔记的关键词搜索。
- 项目内 AI 会话入口、密钥选择、限流与调用审计。
- React Web 客户端和 Tauri 桌面壳。
当前版本不包含实时即时通讯、项目级成员角色体系、匿名公开分享、自主 Agent 执行、语义或向量搜索、第三方数据源集成、原生移动 App、浏览器扩展、离线编辑或本地优先同步。
## 技术栈
- 后端Go 1.26.1、Gin、Gorm、PostgreSQL 16。
- WebReact 18、TypeScript、Vite 8、Arco Design。
- 桌面端Tauri 2、Rust stable共用 Web 构建产物。
- 本地基础设施Docker Compose。
本仓库当前验证环境使用 Node.js 24.11.0、npm 11.12.1、Rust 1.97.1;其他版本应满足各锁文件与工具链要求。
## 目录结构
```text
.
├── backend/ # Go API、数据库模型、业务逻辑和演示数据
│ ├── cmd/api/ # API 入口
│ ├── cmd/seed/ # 开发演示数据入口
│ ├── etc/ # 按模式加载的 YAML 配置
│ └── internal/ # httpx、models 与各业务包
├── apps/web_v1/ # React + TypeScript 主 Web 客户端
├── apps/desktop/ # Tauri 桌面壳
├── infra/docker-compose.yml # 本地 PostgreSQL 16
└── docs/ # 规格、计划与 MVP 验证说明
```
## 快速开始
### 1. 准备环境
安装 Go、Node.js/npm 和 Docker Desktop并确保 Docker Desktop 已启动。桌面端构建还需要 Rust stable 与平台编译工具链。
### 2. 启动 PostgreSQL
在仓库根目录运行:
```powershell
docker compose -f infra/docker-compose.yml up -d
```
启动后端 API
Compose 只用于本地开发,创建 PostgreSQL 16 服务并监听 `localhost:5432`。其中的默认数据库凭据不得用于生产环境。
### 3. 初始化演示数据
```powershell
Set-Location backend
go run ./cmd/seed
```
默认演示账号为 `demo@senlin.ai`,默认密码为 `password123`。它们只用于本地开发;生产部署必须创建正式用户并替换所有默认凭据与密钥。
### 4. 启动 API
在新的终端中运行:
```powershell
Set-Location backend
go run ./cmd/api
```
启动 Web 客户端:
开发配置默认监听 `http://localhost:9150`。可用 `GET /healthz` 检查进程健康状态Web 登录页使用 `GET /api/v1/status` 检查服务器连接。
### 5. 启动 Web 客户端
在新的终端中运行:
```powershell
Set-Location apps/web_v1
npm ci
npm run dev
```
## 后端配置
Vite 默认地址为 `http://localhost:5173`。登录时服务器地址填写 `http://localhost:9150`;也可以通过 `VITE_API_BASE_URL` 指定 Web 的初始 API 地址。
后端配置不再从多个环境变量直接读取,而是从 `backend/etc/agent.<mode>.yaml` 读取。
## 配置
配置模式由环境变量 `SENLIN_APP_MODE` 决定:
后端从 `backend/etc/agent.<mode>.yaml` 读取配置。`SENLIN_APP_MODE` 未设置时使用 `backend/etc/agent.dev.yaml`;例如设置 `$env:SENLIN_APP_MODE='prod'` 时读取 `backend/etc/agent.prod.yaml`,该生产文件需由部署方安全提供。
- 未设置 `SENLIN_APP_MODE` 时,默认读取 `backend/etc/agent.dev.yaml`
- 设置 `SENLIN_APP_MODE=prod` 时,读取 `backend/etc/agent.prod.yaml`
- 设置其他值时,按同样规则读取 `backend/etc/agent.<value>.yaml`
| 字段 | 用途 |
| --- | --- |
| `env` | 运行环境标识。 |
| `port` | API 监听端口;开发值为 `9150`。 |
| `dsn` | PostgreSQL 连接串。 |
| `storage_dir` | 服务端文件存储根目录。 |
| `max_upload_bytes` | multipart 请求体大小上限;开发值为 32 MiB。 |
| `auth_secret` | 邀请和登录会话签名密钥。 |
| `system_ai_key` | 可选的系统级 AI provider fallback key。 |
| `ai_key_encryption_secret` | 用户 AI key 的静态加密密钥。 |
| `allowed_origins` | 允许访问 API 的 Web/Tauri 来源列表。 |
默认开发配置文件:
不要提交生产数据库连接串、AI key、会话凭据或真实密钥。开发配置中的固定值和 Compose 数据库账号仅供本地使用,生产环境必须全部替换。修改 Web 来源或端口时,应同步更新 `allowed_origins`,否则浏览器会拦截跨域请求。
```text
backend/etc/agent.dev.yaml
```
`go run ./cmd/seed` 还支持 `DATABASE_DSN``DATABASE_URL` 临时覆盖数据库地址,以及 `SENLIN_SEED_EMAIL``SENLIN_SEED_NAME``SENLIN_SEED_PASSWORD` 覆盖演示用户信息。
配置字段:
## API v1 概览
- `env`: 运行环境,例如 `development`
- `port`: API 监听端口,默认开发值为 `8080`
- `dsn`: PostgreSQL 连接串。不要提交真实生产或测试凭据。
- `storage_dir`: 服务端本地文件存储目录。
- `auth_secret`: 邀请 token 和 session token 的 HMAC 密钥。
- `system_ai_key`: 可选的系统级 AI provider fallback key。
- `ai_key_encryption_secret`: 用户 AI key 静态加密密钥。
业务接口前缀为 `/api/v1`JSON 字段使用 camelCase对外 ID 使用 UUIDv7 字符串,时间使用 UTC RFC 3339。除连接状态和登录外接口都要求有效的 `Authorization: Bearer` 会话凭据
## 前端
| 方法 | 路径 | 成功响应 |
| --- | --- | --- |
| `GET` | `/api/v1/status` | `200`,包含 `timestamp` 的对象;无需登录。 |
| `POST` | `/api/v1/auth/login` | `200`,包含签名且会过期的 `token` 字段;请求体为 `email``password`。 |
| `GET` | `/api/v1/projects` | `200`,项目 DTO 数组。 |
| `POST` | `/api/v1/projects` | `201`,项目 DTO。 |
| `GET` | `/api/v1/projects/:projectId` | `200`,项目 DTO。 |
| `PATCH` | `/api/v1/projects/:projectId` | `200`,更新后的项目 DTO。 |
| `GET` | `/api/v1/projects/:projectId/workspace` | `200`聚合项目、频道、标签、Inbox、任务、AI 会话、笔记资料和计划任务的工作区 DTO。 |
| `POST` | `/api/v1/projects/:projectId/tasks` | `201`,任务 DTO。 |
| `PATCH` | `/api/v1/projects/:projectId/tasks/:taskId` | `200`,更新后的任务 DTO。 |
| `GET` | `/api/v1/projects/:projectId/tags` | `200`,该项目的标签 DTO 数组。 |
| `POST` | `/api/v1/projects/:projectId/tags` | `201`,标签 DTO。 |
| `POST` | `/api/v1/projects/:projectId/sources` | `201`,文件资料 DTO请求为含 `file` 和可选 `title` 的 multipart 表单。 |
| `POST` | `/api/v1/projects/:projectId/cron-plans` | `201`,计划任务 DTO只管理元数据不执行自主 Agent。 |
| `POST` | `/api/v1/projects/:projectId/inbox` | `201`Inbox 条目 DTO。 |
| `POST` | `/api/v1/inbox/:inboxId/analyze` | `200``suggestions` 草稿数组,不创建正式对象。 |
| `POST` | `/api/v1/inbox/:inboxId/confirm` | `200`,含 `createdCount`;只确认服务端已保存且由用户选中的建议。 |
| `GET` | `/api/v1/search?q=...` | `200``items` 数组,当前检索项目、任务和笔记。 |
| `GET` | `/api/v1/projects/:projectId/ai-sessions` | `200`AI 会话 DTO 数组。 |
| `POST` | `/api/v1/projects/:projectId/ai-sessions` | `201`AI 会话 DTO请求体只接收 `title``context`。 |
Web 客户端使用 React、TypeScript、Vite 和 Arco Design。登录界面允许用户输入服务器 IP 地址或域名,并将其保存为 API base URL
## 桌面端
桌面端使用 Tauri 包装 Web 客户端。
构建桌面可执行文件:
```powershell
Set-Location apps/desktop
npm run build
```
生成安装包:
```powershell
Set-Location apps/desktop
npm run bundle
```
错误统一返回 `{"error":{"code":"...","message":"..."}}`。路径中的项目、任务和 Inbox ID 必须是 UUIDv7数据库自增 ID 不对外暴露
## 验证
@@ -78,7 +145,7 @@ npm run bundle
```powershell
Set-Location backend
go test ./... -v
go test ./...
```
Web
@@ -90,11 +157,64 @@ npm run build
npm run lint
```
桌面端
如果设置了指向隔离测试库的 `DATABASE_URL`,再运行 PostgreSQL 集成检查
```powershell
Set-Location backend
go test -tags integration ./internal/models -run TestPostgresPing -v
```
不得把真实测试数据库凭据写入仓库。当前机器的逐项执行结果与产物路径见 [MVP 验证说明](docs/mvp-verification.md)。
## 桌面端
先完成 Web 依赖安装,再构建 Tauri 可执行文件:
```powershell
Set-Location apps/desktop
npm ci
npm run build
```
更多验证说明见 `docs/mvp-verification.md`
`npm run build` 会先执行 Web 生产构建,再运行 `tauri build --no-bundle`。Windows 产物位于 `apps/desktop/src-tauri/target/release/senlinai_workbench.exe`
需要安装包时运行:
```powershell
Set-Location apps/desktop
npm run bundle
```
打包需要 Rust stable、平台编译工具链和对应安装器依赖它与无安装包的可执行文件构建是两个独立验证项。
## 常见问题
### 数据库连接或认证失败
确认 Docker Desktop 和 Compose 服务正在运行,并用 `docker compose -f infra/docker-compose.yml ps` 查看状态。若本机已有 PostgreSQL 占用 `5432`,请停止冲突服务或同步修改 Compose 映射与 `backend/etc/agent.dev.yaml` 中的 `dsn`。演示数据和 API 必须连接到同一个数据库。
### 浏览器提示无法连接或 CORS 错误
先访问 `http://localhost:9150/api/v1/status`。如果 API 可达但浏览器仍失败,检查登录页的服务器地址、协议和端口,并把实际 Web 来源加入 `allowed_origins` 后重启 API。
### Vite 端口被占用
默认端口是 `5173`。可以停止占用进程,或让 Vite 选择可用端口;使用其他端口时必须同步配置后端 `allowed_origins`
### 演示账号无法登录
先成功运行 `go run ./cmd/seed`,再使用 seed 命令输出所对应的开发账号。若通过环境变量覆盖过演示用户信息,应使用覆盖后的值。生产环境不得使用默认演示密码。
### AI 会话返回缺少密钥或限流错误
创建 AI 会话前会执行每用户、每动作限流并选择加密存储的用户 key 或系统 fallback key。缺少可用 key 时返回服务不可用,超过配额时返回 `429`;不要在前端或提交记录中粘贴 key。
## 安全说明
- 登录会话使用签名且会过期的 bearer token服务端从认证中间件读取当前用户不接受可伪造的用户 ID 字符串。
- 用户 AI key 加密存储。AI 操作先限流,再选择 provider/key并记录 provider、key 类型、action、status 和 error日志不得记录 key 明文。
- AI 分析和会话不会自动创建正式任务、笔记或资料。Inbox 只有在用户确认服务端保存的建议后才创建对象,并保留来源 Inbox ID。
- 项目标签只在项目内有效。任务移动、标签写入和文件上传都校验项目所有权。
- 任务分享遵循最小可见范围:被指派人只能看到任务以及被显式分享的关联对象;分享的 note/source 必须与任务属于同一项目。
- 文件存储路径只由文件服务构造,上传在写磁盘前校验所有权和请求体大小。
- 生产部署必须替换所有开发凭据和密钥、限制 CORS 来源、使用独立数据库与受控存储目录,并通过 HTTPS 暴露服务。

View File

@@ -1,101 +1,213 @@
# MVP Verification
# 森林AI MVP 验证
## Backend
本文记录 2026-07-21 在 Windows、PowerShell 环境中对当前仓库实际执行的验证。只有获得成功退出码或明确 HTTP 响应的命令列为通过;未满足环境条件的项目单独列出,不视为通过。
Run:
## 环境基线
- Go `1.26.1 windows/amd64`
- Node.js `24.11.0`
- npm `11.12.1`
- Rust `1.97.1`
- Cargo `1.97.1`
- Docker CLI当前机器不可用
- `DATABASE_URL`:当前 shell 未设置
本地 Compose 与 `backend/etc/agent.dev.yaml` 约定 PostgreSQL 监听 `localhost:5432`API 监听 `localhost:9150`Vite 默认监听 `localhost:5173`。Compose 和开发配置中的固定数据库凭据只供本地开发,生产环境必须替换。
## 本次结果摘要
| 验证项 | 结果 | 说明 |
| --- | --- | --- |
| `go test ./...` | 通过 | 全部 Go 包通过;另以 `-count=1` 无缓存复核通过。 |
| `go run ./cmd/api` | 未通过 | 本机现有 PostgreSQL 的账号配置与开发配置不匹配,初始化时认证失败。 |
| `go run ./cmd/seed` | 未通过 | 与 API 相同,因本机 PostgreSQL 认证失败。 |
| Compose 启动 | 未验证 | 当前机器没有可用的 Docker CLI未声称启动成功。 |
| Web 依赖安装 | 通过 | `npm ci` 成功,审计未发现漏洞。 |
| Web 短时启动 | 通过 | `npm run dev` 启动因默认端口已有用户进程占用时自动选择可用端口HTTP 根路径返回 `200`。本次进程随后已停止。 |
| Web 视觉检查 | 通过 | `node scripts/visual-check.mjs` 退出 `0`,无未预期 console error。 |
| Web 生产构建 | 通过 | `npm run build` 退出 `0`;存在 bundle 大小警告,不影响构建结果。 |
| Web lint | 通过 | `npm run lint` 退出 `0`。 |
| Web 结构检查 | 通过 | `node scripts/structure-check.mjs` 输出 `structure ok`。 |
| 桌面端依赖安装 | 通过 | `apps/desktop``npm ci` 成功。 |
| Tauri 可执行文件构建 | 通过 | 冷构建超过单次 240 秒工具等待上限,但已完成 release 编译;同一命令增量重跑 58.3 秒退出 `0`。 |
| Tauri 安装包 | 未验证 | 本次未运行 `npm run bundle`。 |
| PostgreSQL 集成测试 | 未运行 | 当前 shell 未提供 `DATABASE_URL`。 |
## 本地启动检查
### PostgreSQL
需要 Docker Desktop。仓库根目录的预期命令是
```powershell
docker compose -f infra/docker-compose.yml up -d
docker compose -f infra/docker-compose.yml ps
```
当前机器无法识别 `docker` 命令,因此这两条命令未验证。不要根据本记录推断 Compose 已成功启动。
### 演示数据与 API
数据库可用后,在两个独立终端中运行:
```powershell
Set-Location backend
go test ./... -v
go run ./cmd/seed
```
Expected: all backend tests pass.
```powershell
Set-Location backend
go run ./cmd/api
```
## PostgreSQL Integration
Set `DATABASE_URL` to the live PostgreSQL test database before running integration checks. Do not commit real credentials.
Run:
本次两条命令都真实执行过,但均在连接本机 PostgreSQL 时因开发账号认证失败而退出。排除本机数据库冲突并成功启动后,应检查:
```powershell
Invoke-RestMethod http://localhost:9150/healthz
Invoke-RestMethod http://localhost:9150/api/v1/status
```
预期分别返回 `status: ok` 和 UTC RFC 3339 `timestamp``/api/v1/status` 是登录页使用的公开连接检查;其他业务接口除登录外均要求有效 bearer 会话。
### Web 开发服务器
```powershell
Set-Location apps/web_v1
npm ci
npm run dev
```
本次 `npm ci` 通过。短时启动时默认端口已被用户原有 Vite 进程占用,本次实例自动选择另一个可用端口;对该实例根路径请求得到 HTTP `200`。验证结束后仅停止了本次新建的进程树,用户原有进程未被修改。
## 自动化验证
### 后端
```powershell
Set-Location backend
go test ./...
```
本次退出 `0`。为排除 Go 测试缓存影响,还执行了:
```powershell
go test -count=1 ./...
```
无缓存复核同样退出 `0`覆盖配置、HTTP 路由、认证、项目/工作区、任务、标签、资料、Inbox、关键词搜索、AI key 加密、限流与审计等包。
### PostgreSQL 集成测试
仅在准备了隔离的实时测试数据库时运行:
```powershell
$env:DATABASE_URL='<隔离测试库连接串>'
Set-Location backend
go test -tags integration ./internal/models -run TestPostgresPing -v
```
Expected: `TestPostgresPing` passes.
连接串必须通过安全的本地或 CI secret 注入,不能提交到仓库。本次 `DATABASE_URL` 未设置,因此没有运行,也不列为通过。
## Web
The primary frontend is the React + Arco Design client under `apps/web_v1`.
Run:
### Web
```powershell
Set-Location apps/web_v1
node scripts/visual-check.mjs
npm run build
npm run lint
node scripts/structure-check.mjs
```
Expected: visual smoke checks, production build, and lint pass.
四条命令本次均退出 `0`。视觉检查覆盖桌面和移动登录页、工作台、项目导航、Inbox 确认、AI 会话受控创建、深色模式、无横向溢出和无未预期 console error。
## Desktop
`npm run build` 生成:
Run:
- `apps/web_v1/dist/index.html`
- `apps/web_v1/dist/assets/`
- `apps/web_v1/dist/senlinai-icon.svg`
`node scripts/visual-check.mjs` 生成的本地证据位于 `apps/web_v1/test-results/`,包括:
- `login-react-acro.png`
- `login-react-acro-mobile.png`
- `workbench-react-acro-light.png`
- `project-react-acro-light.png`
- `project-react-acro-dark.png`
- `project-navigation-mobile.png`
- `channel-navigation-mobile.png`
- `project-inbox-confirmed.png`
- `project-inbox-confirmed-mobile.png`
- `project-ai-controlled.png`
`dist/``test-results/` 都是本地产物,已被 `.gitignore` 排除,不应提交。
### 桌面端
```powershell
Set-Location apps/web_v1
npm run build
Set-Location ../desktop
Set-Location apps/desktop
npm ci
npm run build
```
Expected: the Tauri desktop executable builds when Rust/Cargo is installed and the stable Rust toolchain is complete.
本次最终重跑退出 `0``npm run build` 使用 `tauri build --no-bundle`,并先执行 Web 生产构建。Windows 可执行文件为:
Installer packaging is a separate step:
```text
apps/desktop/src-tauri/target/release/senlinai_workbench.exe
```
本次产物大小为 `8,783,360` 字节。冷构建需要下载或编译 Rust 依赖,可能耗时数分钟;本次第一次调用因外部等待工具达到 240 秒上限而返回超时,但编译日志已显示 release 完成和产物生成,随后相同命令增量重跑获得退出码 `0`
安装包是独立验证项:
```powershell
Set-Location apps/desktop
npm run bundle
```
Current machine status:
- Cargo and rustc are installed under `%USERPROFILE%\.cargo\bin`.
- If the current shell does not see Cargo yet, prepend `%USERPROFILE%\.cargo\bin` to `PATH` or open a new terminal.
- `npx tauri build --no-bundle --verbose` passes and produces `apps/desktop/src-tauri/target/release/senlinai_workbench.exe`.
- Full installer bundling through `npm run bundle` currently times out in the Tauri CLI bundling stage on this machine before producing `target/release/bundle` artifacts.
本次没有运行该命令,不记录安装包结果。
## Latest Audit Verification
## API 契约抽查
Last audited: 2026-07-18.
当前路由注册与 Web API client 均使用 `/api/v1`
- `backend`: `go test ./... -v` passed.
- `apps/web_v1`: `node scripts/visual-check.mjs` passed.
- `apps/web_v1`: `npm run build` passed.
- `apps/web_v1`: `npm run lint` passed.
- `apps/desktop`: `npx tauri build --no-bundle --verbose` passed and produced the desktop executable.
- `apps/desktop`: installer packaging is still blocked by Tauri CLI bundling timeout on the current machine.
- 公共:`GET /api/v1/status``POST /api/v1/auth/login`
- 项目与工作区:项目列表/创建/读取/更新,以及项目工作区读取。
- 任务与标签:任务创建/更新、项目标签列表/创建。
- 资料与计划任务multipart 文件资料创建、计划任务元数据创建。
- Inbox收集、生成建议、按服务端建议 ID 确认。
- 搜索:带 `q` 参数的关键词搜索,响应为 `items` 数组。
- AI 会话:项目会话列表与受控创建,响应为会话 DTO。
Audit fixes included:
抽查结论:创建接口返回 `201`,读取和当前更新接口返回 `200`JSON DTO 使用 camelCase对外路径参数使用 UUIDv7错误为 `error.code``error.message` 包装结构。API 不直接返回 Gorm 模型或内部自增 ID。
- Signed expiring auth session tokens replaced forgeable `user:<id>` tokens.
- Project and inbox HTTP handlers now read the authenticated user from bearer middleware instead of hard-coding user `1`.
- Project dashboard loading now checks project ownership before returning counters.
- Inbox confirmation preserves provenance with `source_inbox_item_id` on generated tasks, notes, and sources.
- Task sharing now rejects note/source links from another project.
- AI user keys are encrypted before storage, decrypted on selection, and can be checked with a per-user action rate limit.
- Web API calls use the backend `/api` prefix, and the active client is now the React + Arco Design workbench.
## 人工 MVP 流程
## Manual MVP Flow
在 Compose、seed、API 和 Web 均成功启动后,按以下顺序人工验收:
1. Open the client and enter the server IP or domain on the login screen.
2. Create or log in as a private-deployment user.
3. Create a project.
4. Add text to project inbox.
5. Click Analyze/Organize.
6. Confirm one task and one note from the suggestion list.
7. Assign the task to another system user.
8. Explicitly share one note with the task.
9. Search for text from the note body in global search.
10. Open an AI session under the project and reference the note.
11. Use Tauri quick capture to send text into the active project inbox.
1. 打开 Web 客户端,在登录页输入服务器 IP 地址或域名。
2. 使用仅供开发的演示账号登录,并确认生产部署未使用默认凭据。
3. 创建项目,修改项目设置,再刷新确认数据保留。
4. 创建项目内标签和任务,验证任务卡显示真实标签与状态。
5. 上传文件资料,确认返回路径是相对存储路径,且越权项目不能留下文件。
6. 创建计划任务元数据,确认界面没有暗示自主 Agent 已执行。
7. 收集一条 Inbox 内容,先分析建议;此时不应出现正式对象。
8. 选择一条或多条服务端建议并确认,验证生成对象保留来源 Inbox ID。
9. 用关键词搜索项目、任务和笔记,确认用户只能看到有权访问的结果。
10. 创建项目 AI 会话,确认缺 key、限流和服务错误有明确提示且不会自动生成正式对象。
11. 在桌面与移动视口检查项目/频道导航、焦点状态和横向溢出。
12. 启动桌面可执行文件,逐项检查登录持久化、拖拽上传、通知和全局快捷收集等 MVP 目标;未实际走通的能力不得记为通过。
## 安全复核清单
- 生产环境已替换数据库凭据、`auth_secret`、AI key 加密密钥和所有开发默认值。
- 未提交数据库连接串、用户 AI key、会话凭据、日志、数据库文件、上传文件或构建产物。
- 登录凭据由签名且会过期的 bearer session 校验handler 从认证上下文获取用户。
- 用户 AI key 加密存储AI 操作在 key/provider 选择前占用限流配额,并写 provider、key 类型、action、status 和 error 审计。
- AI 输出只形成待确认草稿;用户确认前不创建任务、笔记或资料。
- 项目标签保持项目内范围;任务分享的 note/source 与任务属于同一项目。
- 被指派人只看到任务和明确分享的关联对象。
- PostgreSQL 集成测试只使用显式 `DATABASE_URL` 指向的隔离测试库。
## 文档一致性检查
已对两份文档执行旧品牌、旧 API 前缀、旧前端目录和旧技术栈关键词扫描,结果无匹配。还应抽查 Markdown 相对链接存在,所有命令的工作目录与仓库实际脚本一致。