d2618758e2
- 位置統一:舊 docs/3-specs/ 五份 SDD git mv 到 system-dev/docs/3-specs/,舊位置留 README 指針 - 狀態判定:0 份 active(無現行開發,合法);paused×3(ingest-contract/kbdb-graph-extraction/plugin-install,等跨 repo 接通);closed×2 入 archive/(arcrun-key-auth/blocks-edit-api 死件,附封存原因) - 鋪檔(自 system-dev-template v1.15.0):SDD-LIFECYCLE.md、pending-changes.md、sdd-guard.sh 新版、sdd-check.md、sdd-active-check.sh - hook 掛載:settings.json PreToolUse Write|Edit 加 sdd-guard.sh - CLAUDE.md:SDD 鐵律段(濃縮五條+0-active 註明重啟先升 active)+修正遷移後舊路徑 - 驗證:sdd-active-check exit 0;guard pipe-test 0-active 擋 code 寫入(exit 2)/md 放行(exit 0) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
235 lines
7.9 KiB
Markdown
235 lines
7.9 KiB
Markdown
---
|
||
status: closed # active | draft | paused | closed(生命週期鐵律見 ../../SDD-LIFECYCLE.md)
|
||
superseded_by: ""
|
||
---
|
||
|
||
> **封存(2026-07-17)**:基於舊「萬物皆 Block/blocks 表」架構,該架構已判定為違規殘留並刪除(2026-06-14 改寫);base `PATCH /records/:id` 已由 Arcrun #6 實作取代本需求。
|
||
|
||
# KBDB — Blocks Edit API
|
||
|
||
> **建立**:2026-05-06
|
||
> **狀態**:草稿,待 richblack review
|
||
> **依賴**:`matrix/kbdb/CLAUDE.md`(萬物皆 Block 架構,2026-02-28 鎖定)
|
||
> **驅動需求**:`polaris/mira/.agents/specs/mira-app/design.md`(前端 inline edit 直寫 KBDB 的需求)
|
||
|
||
---
|
||
|
||
## 0. 背景
|
||
|
||
KBDB v3「萬物皆 Block」架構鎖定後,現役 routes 涵蓋 Block CRUD 多數操作,但**缺少編輯既有 block 的 PATCH endpoints**。具體缺口:
|
||
|
||
| 操作 | 現役狀態 |
|
||
|---|---|
|
||
| `POST /blocks/ingest`(建立) | ✅ 已有 |
|
||
| `GET /blocks/{id}`(讀取單筆) | ✅ 已有 |
|
||
| `GET /blocks/`(列表 / 查詢) | ✅ 已有 |
|
||
| `DELETE /blocks/{id}`(刪除) | ✅ 已有 |
|
||
| **`PATCH /blocks/{id}`(部分更新)** | ❌ **缺** |
|
||
| `POST /triplets/`(建立) | ✅ 已有 |
|
||
| **`PATCH /triplets/{id}` / `DELETE /triplets/{id}`** | ❌ **缺** |
|
||
| `PUT /templates/{name}` | ✅ 已有 |
|
||
| `PATCH /tasks/{id}/status` | ✅ 已有 |
|
||
|
||
→ 沒有 PATCH/UPDATE block 內容的 API,前端「inline edit 寫回 KBDB」做不了。
|
||
|
||
> **註**:`src/routes/blocks.ts.bak` 有 PUT /:id 的舊實作可參考,但已被 v3 取代並停用。**不直接複用 .bak 檔案**,按 v3 規範重寫。
|
||
|
||
---
|
||
|
||
## 1. 範圍
|
||
|
||
本 SDD 涵蓋兩件事:
|
||
|
||
1. **補三組 endpoint**:`PATCH /blocks/{id}`, `PATCH /triplets/{id}`, `DELETE /triplets/{id}`
|
||
2. **建三個 templates**:`data-source-config`, `source-skill`, `wiki-page`(為 mira-app 準備)
|
||
|
||
**不在範圍內**:
|
||
- 改 schema(v3 鎖定,禁止 ALTER TABLE)
|
||
- 改既有 endpoint 行為(純加新 endpoint)
|
||
- 多用戶權限細分(partner key 已能做 org 隔離,沿用即可)
|
||
- 編輯歷史 / undo(未來 SDD)
|
||
|
||
---
|
||
|
||
## 2. PATCH /blocks/{id}
|
||
|
||
### 2.1 用途
|
||
|
||
部分更新一個既有 block。前端 inline edit 場景:使用者點 edit icon,改 content / refs / tags,按儲存 → 送 PATCH。
|
||
|
||
### 2.2 規格
|
||
|
||
```
|
||
PATCH /blocks/{id}
|
||
Authorization: Bearer <api_key>
|
||
Content-Type: application/json
|
||
|
||
Body (所有欄位皆 optional,至少要有一個):
|
||
{
|
||
"content": "新的內容",
|
||
"tags": ["tag1", "tag2"], // 完整覆寫 tags 陣列
|
||
"refs": ["block-id-1", "block-id-2"], // 完整覆寫 refs 陣列
|
||
"slots": { "key": "value" }, // 完整覆寫 slots 物件
|
||
"source": "...", // 通常不改,但允許
|
||
"metadata_json": { ... } // 完整覆寫
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"id": "...",
|
||
"content": "...",
|
||
"updated_at": "2026-05-06T...",
|
||
...完整 block 欄位
|
||
}
|
||
|
||
Response 400:
|
||
{ "error": "no fields to update" }
|
||
|
||
Response 403:
|
||
{ "error": "block belongs to different org" }
|
||
|
||
Response 404:
|
||
{ "error": "block not found" }
|
||
```
|
||
|
||
### 2.3 行為
|
||
|
||
- 只更新 body 內提供的欄位
|
||
- 自動更新 `updated_at`
|
||
- 自動重新計算 `content_hash`(如 content 變動)
|
||
- 自動觸發 embedding 重算(如 content 變動,async)
|
||
- **權限**:partner key 只能改自己 org 內的 block(透過 user_id 對應),internal token 可改任何 block
|
||
- **content_hash 衝突**:partner key 不可修改 v3「`source` 為 `system` 的 admin 標記資料」(沿用既有 admin-preservation 規則)
|
||
|
||
### 2.4 實作位置
|
||
|
||
- Action: `src/actions/update-block.ts`(< 100 行,按 KBDB CLAUDE.md 樂高法)
|
||
- Route: `src/routes/blocks.ts` 加新 OpenAPI route
|
||
- Test: `tests/blocks-update.test.ts`
|
||
|
||
---
|
||
|
||
## 3. Triplet 編輯:使用既有 `PUT /records/:id` + `DELETE /records/:id`
|
||
|
||
**設計修正(2026-05-06 實作時發現)**:
|
||
|
||
v3 萬物皆 Block 架構下,triplet 是 `tpl-triplet` template 的 record(用 entry_values 存 subject/predicate/object slots)。**既有 `PUT /records/:id` 跟 `DELETE /records/:id` 已涵蓋編輯/刪除需求**,無需新增 `PATCH /triplets/:id`。
|
||
|
||
→ 前端編輯異見牆上的 triplet:
|
||
- 編輯:`PUT /records/{triplet_record_id}` body `{ values: { subject, predicate, object } }`
|
||
- 刪除:`DELETE /records/{triplet_record_id}`
|
||
|
||
→ **本 SDD 不再規劃新 triplet endpoint**。
|
||
|
||
---
|
||
|
||
## 5. 三個新 Templates
|
||
|
||
按 KBDB v3 規範,新資料類型透過 template 定義,**不動 schema**。
|
||
|
||
### 5.1 template: `data-source-config`
|
||
|
||
每個資料源實例對應一個此 template 的 block。Mira 的「來源篩選」、cron workflow 的「每天去抓什麼」都讀這個。
|
||
|
||
```yaml
|
||
template_name: data-source-config
|
||
slots:
|
||
- name: string # "電子時報"、"我的 Logseq"
|
||
- channel: string # rss / telegram / km-writer / voice-stt / ai-comment / ai-canon
|
||
- config: object # channel-specific (e.g., rss: {url, schedule})
|
||
- skill_id: string? # 連到 source-skill block 的 id
|
||
- enabled: bool
|
||
- ai_comment: bool # 是否需要 AI 加註解
|
||
- ai_comment_style: string? # 提示給 claude_api 的風格
|
||
```
|
||
|
||
### 5.2 template: `source-skill`
|
||
|
||
每個 source 累積的「分析配方」(prompt + few-shot)。可在前端編輯、版本化。
|
||
|
||
```yaml
|
||
template_name: source-skill
|
||
slots:
|
||
- name: string # 例 "電子時報科技類分析"
|
||
- prompt: text # system_prompt 內容
|
||
- examples: text? # few-shot examples(markdown)
|
||
- version: int
|
||
- based_on: string? # 上一版的 block id
|
||
```
|
||
|
||
### 5.3 template: `wiki-page`
|
||
|
||
AI 從河道對話合成的定稿。
|
||
|
||
```yaml
|
||
template_name: wiki-page
|
||
slots:
|
||
- entity_name: string
|
||
- summary: text # markdown
|
||
- key_blocks: array<string> # 引用的 source block ids
|
||
- conflicts: array<string>? # 標記為矛盾的 block ids
|
||
- generated_at: timestamp
|
||
- version: int
|
||
- based_on: string?
|
||
```
|
||
|
||
### 5.4 建立方式
|
||
|
||
不寫 SQL migration(v3 規範禁止)。改用 KBDB 既有的 `POST /templates`:
|
||
|
||
```bash
|
||
curl -X POST https://kbdb.finally.click/templates \
|
||
-H "Authorization: Bearer <internal_token>" \
|
||
-d '{"name": "data-source-config", "slots": [...]}'
|
||
```
|
||
|
||
→ tasks.md 列為 P0 任務(用 internal token 一次性建好)。
|
||
|
||
---
|
||
|
||
## 6. 實作步驟
|
||
|
||
### Phase 1:補 endpoints
|
||
|
||
1. 寫 `src/actions/update-block.ts`(純函數,< 100 行,含權限檢查)
|
||
2. 寫 `tests/blocks-update.test.ts`(含 happy path、403、404、no-fields 三案)
|
||
3. 寫 `src/routes/blocks.ts` 的 PATCH route(OpenAPI 定義 + 呼叫 action)
|
||
4. 補 `src/routes/triplets.ts` PATCH(wrapper)+ DELETE(alias)
|
||
5. 部署 + smoke test
|
||
|
||
### Phase 2:建 templates
|
||
|
||
6. 用 internal token 呼叫 `POST /templates` 建三個 template
|
||
7. 驗證:用 partner key (mira 用的) 創建一個 `data-source-config` block 看能否寫成功
|
||
|
||
### Phase 3:補 OpenAPI spec
|
||
|
||
8. 確認新 routes 自動進 swagger.json(OpenAPIHono 應該自動,需驗證)
|
||
|
||
---
|
||
|
||
## 7. 風險
|
||
|
||
- **embedding 重算成本**:PATCH content 會觸發 vectorize 重算,頻繁 inline edit 可能拖慢。**對策**:embedding 改為 async(行為已是 async,需確認)。
|
||
- **content_hash 計算遺漏**:忘記重算會讓查重失效。**對策**:在 action 內統一處理,不讓 route 層管。
|
||
- **partner key 越權**:必須驗 user_id 對應,不能讓 partner A 改 partner B 的 block。**對策**:write tests 涵蓋此案。
|
||
- **三個 templates 命名衝突**:若 KBDB 已有同名 template 會 fail。**對策**:建立前先 GET /templates/{name} 檢查。
|
||
|
||
---
|
||
|
||
## 8. 不在範圍內
|
||
|
||
- 編輯歷史 / undo / version diff(未來 SDD)
|
||
- Block soft delete(v3 已有 hard delete,softdelete 是 enhancement)
|
||
- Bulk PATCH(一次改多個 block,未來看需求)
|
||
- Field-level permissions(特定欄位只能某些 user 改)
|
||
- WebSocket 通知 block 改了(即時協作)
|
||
|
||
---
|
||
|
||
## 9. 變更紀錄
|
||
|
||
| 版本 | 日期 | 內容 |
|
||
|---|---|---|
|
||
| v0 | 2026-05-06 | 初稿。對應 mira-app 的 inline edit 需求。 |
|