知识以前只能"填个标题就完成",正文、标签、归类都要点进去再补。现在新建 就是一张完整的备忘录:标题、类型、分类、标签、正文一次写完,存完直接打开 详情继续编辑;知识页左侧多了工作区三级分类树,可按分类子树 / 未分类 / 标签 筛选。凡是填信息的抽屉都加宽了,还能一键展开整屏。 后端 - 新增 `knowledge_category`(迁移 0007):`workspace_id NOT NULL` + 自引用 `parent_id`、`depth` 1..3 检查约束、同层重名唯一索引(lower(name))、 RLS 策略与 `dadao_app` 授权;`knowledge_doc.category_id` 外键 ON DELETE SET NULL。 - 新增 `/knowledge/categories` 增删改查:超三级 `7007`、同层重名 `7008`、 跨租户或不存在 `7006`;`move=true` 才改父级,成环与移动后超过三级的子树 一律拒绝,删除有知识的分类要 `force=true`(知识变未分类)。 - 知识列表支持 `category_id`(含子树)、`uncategorized`、`tag`;输出带 `category`(含 `path` / `full_path`)。 - PATCH 只改分类或标签也会推进 `version`,避免"只动标签"之后下次保存撞 乐观锁 `4009`。 Web - `Sheet` 增 `size="md/lg/xl"` 与展开整屏按钮;任务、工单、知识抽屉统一 加宽(`TaskDetail` / `Tickets` / `Knowledge`)。 - 知识页:左侧三级分类树(新建、按子树筛选、未分类)、`KnowledgeComposer` 一次写全新的备忘录、列表卡片露出分类路径与标签、详情抽屉里可直接改分类 与标签。 - 抽屉详情只拉一次:重复的 effect 或迟到的响应不再覆盖用户正在敲的内容。 安卓 - `Api.kt`:分类模型与接口、新建/更新带 `tag_names`/`category_id`、 列表带分类与标签筛选。 - 知识页重做:新建改为近全屏大对话框(标题/类型/分类/标签/正文),列表 顶部按分类筛选,详情里能改分类与标签后单独保存。 文档与测试 - `2.Design/API.md`:5.1/5.3/5.4 补分类与筛选参数,新增 5.5 分类接口章节, 错误码补 `7006`/`7007`/`7008`。 - `2.Design/ROADMAP-M0-M1.md`:新增 3.11(三级分类)、3.12(备忘录形态)。 - 新增 `backend/tests/test_knowledge_categories.py`(8 例):备忘形态落库、 三级到底、移动越界与成环、重名、按子树/未分类/标签/关键词筛选、删分类需 `force`、跨租户隔离。 - 新增 `web/e2e/knowledge-notebook.mjs`(10 项,全绿):建两级分类 → 一次 写全 → 卡片与筛选 → 抽屉改标签/分类 → 正文落库 → 重名 7008。 验证:`pytest` 93 passed、`ruff check` / `ruff format --check` 全过、 `tsc --noEmit` 通过、`vite build` 通过、`knowledge-notebook.mjs` 10 项全绿。 安卓端本机只有 JDK 25,Gradle 8.7 / AGP 8.7.3 不支持,本次未做编译验证。
This commit is contained in:
+43
-8
@@ -342,22 +342,30 @@ Web 端未读数由 `AppShell` 每 30 秒轮询一次;在通知页标已读后
|
||||
| `status` | 可重复;`draft`/`in_review`/`published`/`archived`,不传为全部 |
|
||||
| `doc_type` | `note`/`howto`/`faq`/`postmortem`/`decision` |
|
||||
| `source_item_id` | 按来源事项筛 |
|
||||
| `category_id` | 按分类筛,**包含子分类** |
|
||||
| `uncategorized` | `true` 只看未分类 |
|
||||
| `tag` | 按标签名筛(不区分大小写) |
|
||||
| `q` | 标题 / 正文 / 摘要子串 |
|
||||
| `limit` | 1–100,默认 30 |
|
||||
| `cursor` | 上一页的 `next_cursor` |
|
||||
|
||||
返回 `{items, next_cursor, has_more}`。每条是 `item` 字段 + `knowledge` + `source`:
|
||||
返回 `{items, next_cursor, has_more}`。每条是 `item` 字段 + `knowledge` + `category` + `source`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "…", "kind": "knowledge", "title": "发票原件必须一起寄",
|
||||
"body_md": "…", "status": "published", "tags": [],
|
||||
"body_md": "…", "status": "published", "tags": [{"id": "…", "name": "财务"}],
|
||||
"knowledge": {
|
||||
"doc_type": "howto", "summary": "…", "status_hint": "published",
|
||||
"source_kind": "task", "source_item_id": "…", "generated_by": "human",
|
||||
"published_at": "2026-10-28T05:54:44Z", "archived_at": null,
|
||||
"chunk_count": 0, "author_id": "…"
|
||||
},
|
||||
"category": {
|
||||
"id": "…", "parent_id": "…", "name": "回滚", "depth": 3,
|
||||
"sort_order": 0, "version": 1,
|
||||
"path": ["研发", "部署", "回滚"], "full_path": "研发 / 部署 / 回滚"
|
||||
},
|
||||
"source": {"id": "…", "kind": "task", "title": "发票原件必须一起寄", "status": "done"}
|
||||
}
|
||||
```
|
||||
@@ -374,19 +382,43 @@ Web 端未读数由 `AppShell` 每 30 秒轮询一次;在通知页标已读后
|
||||
|
||||
```json
|
||||
{"title": "报销单要贴发票原件", "body_md": "…", "doc_type": "note",
|
||||
"tag_names": ["财务", "报销"], "category_id": "可选的分类 id",
|
||||
"source_item_id": "可选的来源事项 id"}
|
||||
```
|
||||
|
||||
- 不带 `source_item_id` → `source_kind=manual`(手记),允许没有来源。
|
||||
- 带 → 来源必须是同工作区的 `task`/`ticket`,否则 `7005`。
|
||||
- `category_id` 可省(未分类);跨工作区的分类一律按不存在处理(`7006`)。
|
||||
- `tag_names` 按名字去重创建,空格/逗号分隔由前端拆好再传。
|
||||
- 新知识一律 `draft`,不会直接对外可见。
|
||||
|
||||
### 5.4 `PATCH /knowledge/{item_id}` — 修改内容
|
||||
|
||||
必须带 `version`(乐观锁,冲突 `4009`)。可改 `title`/`body_md`/`summary`/`doc_type`。
|
||||
必须带 `version`(乐观锁,冲突 `4009`)。可改 `title`/`body_md`/`summary`/`doc_type`/`tag_names`/`category_id`;
|
||||
传 `clear_category: true` 表示移到未分类。
|
||||
**已发布的不许直接改**(`7003`,先撤回审议或归档),避免"发布后被悄悄改写"。
|
||||
|
||||
### 5.5 `POST /knowledge/{item_id}/status` — 状态动作
|
||||
### 5.5 知识分类 `/knowledge/categories`
|
||||
|
||||
分类是工作区级的三级小树,用来给知识安一个位置;它**不是权限边界**,只是归类。
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| GET | `/knowledge/categories` | 扁平列表(按 depth/sort_order 排好),每条带 `doc_count`、`path`、`full_path`;另有 `max_depth=3` |
|
||||
| POST | `/knowledge/categories` | `{name, parent_id?, sort_order?}` |
|
||||
| PATCH | `/knowledge/categories/{id}` | `{name?, parent_id?, move?, sort_order?, version}` |
|
||||
| DELETE | `/knowledge/categories/{id}?force=false` | 有子分类不让删;有知识要 `force=true`,删后知识变未分类 |
|
||||
|
||||
三条规则:
|
||||
|
||||
1. **最多三级**。第四级不是"更细",是"找不到",创建/移动越界一律 `7007`。
|
||||
2. **同一层不能重名**(不区分大小写),否则 `7008`;不同层可以同名。
|
||||
3. **移动带着子树走**:把一棵三层树挪到第二层下面会让最深节点到第五层,这种移动直接拒绝(`7007`),
|
||||
不静默改层级。
|
||||
|
||||
`PATCH` 里 `move=true` 才处理 `parent_id`,避免"只改名字"被误当成移动。改名的 `version` 冲突是 `4009`。
|
||||
|
||||
### 5.6 `POST /knowledge/{item_id}/status` — 状态动作
|
||||
|
||||
| action | 允许的前置状态 | 结果 | 谁能做 |
|
||||
|---|---|---|---|
|
||||
@@ -401,7 +433,7 @@ Web 端未读数由 `AppShell` 每 30 秒轮询一次;在通知页标已读后
|
||||
|
||||
**发布要 owner/admin 的理由**:发布等于团队为这条结论背书,不能谁都能推。
|
||||
|
||||
### 5.6 `POST /items/{item_id}/knowledge` — 把一件事沉淀成知识
|
||||
### 5.7 `POST /items/{item_id}/knowledge` — 把一件事沉淀成知识
|
||||
|
||||
Query:`doc_type`(默认 `postmortem`)。来源可以是任务或工单;工单会带出验收结论。
|
||||
返回与 5.2 相同的知识对象;同一来源重复沉淀 → `7002`。
|
||||
@@ -409,7 +441,7 @@ Query:`doc_type`(默认 `postmortem`)。来源可以是任务或工单;
|
||||
**工单验收通过时,后端会自动调用这条逻辑**(`generated_by=rule`,`doc_type=postmortem`,
|
||||
正文开头固定一句"这份草稿由系统根据来源自动整理,请先核对再发布"),所以用户不需要记得点。
|
||||
|
||||
### 5.7 检索 `GET /knowledge/search`
|
||||
### 5.8 检索 `GET /knowledge/search`
|
||||
|
||||
Query:
|
||||
| 参数 | 说明 |
|
||||
@@ -434,7 +466,7 @@ Query:
|
||||
2. **结果必须带来源**,能点回原文。这是 D3(知识必须有来源)的延伸:不给"出处不存在"的答案。
|
||||
3. **宁可返回空,也不凑数**。检索失败比误导便宜。
|
||||
|
||||
发布(`5.5` 的 `publish`)时会自动重建索引,用户发布完立刻能搜到;
|
||||
发布(`5.6` 的 `publish`)时会自动重建索引,用户发布完立刻能搜到;
|
||||
但改完正文不会自动重建,需要调用下面这条。
|
||||
|
||||
### `POST /knowledge/{item_id}/reindex` — 重建切片
|
||||
@@ -447,7 +479,7 @@ Query:
|
||||
将来换 pgvector 只改列类型与索引,接口不变。换 embedding 模型(`EMBEDDING_PROVIDER`)后
|
||||
**必须整体重建**,否则新旧向量混在一张表里,分数没法比较。
|
||||
|
||||
### 5.8 知识的错误码
|
||||
### 5.9 知识的错误码
|
||||
|
||||
| 码 | HTTP | 含义 |
|
||||
|---|---|---|
|
||||
@@ -456,6 +488,9 @@ Query:
|
||||
| 7003 | 409 | 当前状态不允许这个动作 |
|
||||
| 7004 | 403 | 权限不足(如非管理员发布) |
|
||||
| 7005 | 409 | 来源事项无效或缺失 |
|
||||
| 7006 | 404 | 分类不存在,或不是本工作区的 |
|
||||
| 7007 | 422 | 分类层级超过三级,或移动后会让子树超过三级 |
|
||||
| 7008 | 409 | 分类重名 / 还有子分类 / 分类下还有知识(需 `force`) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user