e788c52dd2
- /entries 與 /entries/search 加 library 多值參數(逗號分隔);不帶=行為一字不變(向後相容) - D1:COALESCE(json_extract(metadata_json,'$.library'),'general') IN (…)(≡ design §3.3 OR 形狀; 未標記舊資料歸 general) - semantic:Vectorize upsert metadata 加 library(寫入端正規化 general);查詢 filter $in 主路徑 (官方文件+workers-types 4.20260702.1 核實支援,fan-out fallback 不需) - 測試:library-filter.test.ts 11 項+既有 6 項全綠;tsc exit 0;本機 miniflare local D1 十案例實跑全過 - semantic 線上路徑(metadata index+reindex backfill)=部署清單,待雲端排練驗(本機無 Vectorize) - cypher kbdb-proxy 透傳順延(P1 派工紅線只動 kbdb,tasks.md 已註) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
81 lines
6.4 KiB
Markdown
81 lines
6.4 KiB
Markdown
# portal-auth — Tasks(實作切分,每階段可獨立 PR)
|
||
|
||
> 狀態:**全部未動工——本 SDD 待總管/leo 審後才開工**(B 類流程:SDD 審 → 實作 PR → component-pr-review-standard → 總管 review → gated 部署 leo21c)
|
||
> 對應:Gitea #24/#25;design.md 各 §
|
||
|
||
依賴鏈:P1 → P2 → P3 → P4(P2 不依賴 P1 可並行起,但 P3 要兩者都齊)。
|
||
|
||
---
|
||
|
||
## P1 — KBDB「庫」filter 地基(design §3.2/§3.3)|觸碰:`kbdb/`
|
||
|
||
- [x] 開工第一件事:實測 Vectorize metadata filter `$in` 支援與否(決定主路徑 vs fan-out fallback)
|
||
- **核實結論(2026-07-14)**:**支援,走主路徑 `$in`,不需 fan-out fallback**。證據:① 官方文件
|
||
developers.cloudflare.com/vectorize/reference/metadata-filtering/ 明列 8 運算子
|
||
`$eq/$ne/$in/$nin/$lt/$lte/$gt/$gte`,「For $in and $nin, filter object values can be arrays of
|
||
string, number, boolean, or null values」;② 本 repo `@cloudflare/workers-types@4.20260702.1`
|
||
原生 typing `VectorizeVectorMetadataFilterCollectionOp = "$in" | "$nin"`(index.d.ts:15782),
|
||
wrangler 4.98.0。限制:metadata filtering 只對 2023-12-06 之後建的 index 有效(本專案 index 皆是)。
|
||
本機無 Vectorize runtime,`$in` 的**線上實跑**併入部署排練驗(見部署清單)。
|
||
- [x] `/entries/search`+`/entries` 加 `library` 多值參數(D1 json_extract IN+NULL→general fallback)
|
||
- 實作註:SQL 用 `COALESCE(json_extract(metadata_json,'$.library'),'general') IN (…)`——與 design §3.3
|
||
的 OR 形狀語意完全等價(單組佔位符較簡)。本機 miniflare+local D1 十案例實跑全過(PR 附證據)。
|
||
- [x] embed upsert metadata 加 `library` 欄;semanticSearch filter 支援 library(**$in 主路徑**,fan-out 不需)
|
||
- 實作註:Vectorize 端在**寫入時正規化**(未標記→`'general'`)——Vectorize filter 做不了 COALESCE,
|
||
寫入端蓋章後查詢端單純 `$in`;與 D1 查詢端 fallback 語意對齊。
|
||
- [x] Vectorize `library` metadata index 建立步驟+reindex backfill 寫進部署清單
|
||
- **部署清單(待雲端排練驗——本機無 Vectorize runtime,semantic 路徑 code 完成、線上實跑未驗)**:
|
||
1. `wrangler vectorize create-metadata-index arcrun-kbdb-embed --property-name library --type string`
|
||
2. `POST /embed/backfill {"reindex":true}` 分批到 remaining=0(index 只收建立後 upsert 的向量)
|
||
3. 驗收抽查:semantic 帶 `library=` 過濾命中/不帶行為不變
|
||
4. 掛號:`cli/src/lib/deploy.ts` `ensureVectorizeMetadataIndexes()` 待補 `library`(cli/ 屬 P1
|
||
派工範圍外「只動 kbdb」,隨 P3 或部署 PR 補——kbdb/wrangler.toml 註解已標)
|
||
- [ ] cypher `kbdb-proxy` 透傳 `library` 參數(供 owner/admin 面用;portal 面走 P3 的注入,不經這)
|
||
- ⚠️ 範圍註(2026-07-14):P1 派工紅線「只動 kbdb、不碰 cypher-executor」與本項矛盾——照窄範圍
|
||
執行,本項順延(一行 query 透傳,隨 P3 動 cypher 時一併)。
|
||
- [x] 測試:D1 filter 單元測、NULL fallback、多值、semantic filter(mock VECTORIZE)
|
||
- `kbdb/tests/library-filter.test.ts` 11 項(SQL 形狀/route 解析/向後相容/降級仍 enforce/$in 構造/
|
||
寫入端正規化)+既有 6 項全綠(17/17);tsc exit 0。
|
||
- **驗收**:curl `/entries/search?q=&library=finance` 只回 finance+未標記條目歸 general 可驗;semantic 同
|
||
- **工程量**:小-中(0.5–1 個 CC 工作天)
|
||
|
||
## P2 — portal_user 模型+認證 API(design §2/§4)|觸碰:`cypher-executor/`(新 route 檔)
|
||
|
||
- [ ] seed template `portal_user`+`portal_library`(init-seed 慣例)
|
||
- [ ] PBKDF2-SHA256 雜湊模組(600k iters、常數時間比對、`pbkdf2-sha256$…` 格式)
|
||
- [ ] `POST /portal/admin/bootstrap`(console owner session 閘)
|
||
- [ ] login/logout/session/改密碼(KV `portal_sess:`、TTL var、每請求回讀 record 驗 status)
|
||
- [ ] admin 用戶 CRUD+libraries 授權+庫目錄 CRUD(role=admin 閘)
|
||
- [ ] 登入失敗節流(5 次/15 分鐘,KV TTL)
|
||
- [ ] 順手修 `record-crud.ts` updateRecord grow 路徑漏 owner_id(design §2.2 附帶)
|
||
- [ ] 測試:bootstrap 閘、登入對錯、停用即拒(session 立即失效)、role 閘、雜湊格式、`{tenant}::portal` 子 namespace 隔離(**搜 email 搜不到**)
|
||
- **驗收**(=#25 驗收):新增用戶能登入;停用登入被拒+既有 session 失效;KBDB 無新表;密碼抽查非明碼
|
||
- **工程量**:中(約 1 個 CC 工作天)
|
||
|
||
## P3 — `/portal` UI:登入殼+搜尋頁+設定頁+scope enforce(design §1/§3.3/§5/§6)|觸碰:`cypher-executor/`
|
||
|
||
- [ ] `/portal` HTML 殼(重用 console 樣式/搜尋 view 抽共用 helper;`CONSOLE_BRAND` 品牌;零 Mira 字樣)
|
||
- [ ] 未登入只見登入殼;登入後兩頁:搜尋(keyword/semantic/graph 三模式+source 溯源+卡片詳頁)+設定(改密碼/看自己權限/主題)
|
||
- [ ] `/portal/data/*` server-side enforce:session→record→注入 `owner_id`+`library`;**前端絕不下發租戶字串**
|
||
- [ ] 卡片詳頁逐筆驗 library(越庫 id 直讀 → 404)
|
||
- [ ] graph 粗閘(D-4:無 graph 來源庫權限 → 模式不顯示+API 403)
|
||
- [ ] 測試:curl 帶 user session 直打 data API 驗 filter 繞不過(=#24 驗收 3 的 server-side 證明)
|
||
- **驗收**(=#24 驗收):leo21c `/portal` 可開;未登入只見登入殼;三模式+溯源可用;A 用戶(僅 general)搜不到 finance 內容——UI 與 curl 雙驗
|
||
- **工程量**:大(1–1.5 個 CC 工作天,UI 是最大件)
|
||
|
||
## P4 — admin 頁+工作流顯示(design §6)|觸碰:`cypher-executor/`
|
||
|
||
- [ ] 帳號管理頁(admin-only nav):列表/新增/停用/重設密碼+每帳號庫權限勾選
|
||
- [ ] 庫目錄管理(登記/停用庫)
|
||
- [ ] 工作流頁(唯讀 list+最近執行;`PORTAL_SHOW_WORKFLOWS` 預設 admin;不開 trigger)
|
||
- **驗收**:admin 全流程「發帳號→授庫→同仁登入查詢→停用」在 UI 走通;一般用戶看不到 admin 頁與(預設下)工作流頁
|
||
- **工程量**:中(約 1 個 CC 工作天)
|
||
|
||
---
|
||
|
||
## 第二波(不在本 SDD 動工範圍,掛號)
|
||
|
||
- MCP token 綁庫集合(design §9;PR#15 擴充,只動 `mcp/`)
|
||
- graph 逐節點/逐邊細粒度過濾
|
||
- Google OAuth2 fast-follow、審計 log、忘記密碼 email 自助、舊資料 library 回填清潔工
|