visionA/visionA-backend/migrations/0006_model_sharing.up.sql
jim800121chen 47a1d4d0ef feat(backend): 設備註冊 + 模型共享 backend(B 設備管理 + C 模型共享)
B 設備管理(feature-device-mgmt-tdd):
- POST /api/devices/:id/register + /unregister(owner 檢查 + representative 擋
  + 已註冊擋 + SetRegistered 單欄翻轉,不碰 unpair 軟刪)
- error codes ALREADY_REGISTERED / REPRESENTATIVE_DEVICE(409)
- 不需 migration(registered_at 欄/index/讀寫已在 0005)

C 模型共享(feature-model-sharing-tdd,security 深審 APPROVE):
- migration 0006:models.visibility enum DEFAULT 'private'(零行為改變)+ model_shares 表
- canAccessModel single source(owner ∪ share ∪ public ∪ tenant):profile + download 共用
- GET /library(cursor keyset)/ GET /:id/profile(404 防列舉、GetWithOwner join name 不洩 email)
  / PATCH /:id/visibility(owner-only)/ shares CRUD / download 放寬
- tenant 因 OIDC 無 org claim 留 stub(恆空、安全預設;補 org claim 需重送 security 深審)

reviewer 通過(B 三條紅線 / C security APPROVE 無 C/M)。130 dbtest 全綠、gosec 新檔 0。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-02 16:29:50 +08:00

50 lines
3.4 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 0006_model_sharing.up.sql
--
-- 模型共享Model SharingL 級新功能。在既有 owner-only 模型庫上,疊加兩個正交維度:
-- (1) visibility 廣播欄private / tenant / public— models 表加 enum 欄。
-- (2) model_shares 點對點分享表ADR-017 決策 3 B1— 分享給特定 user。
--
-- 對齊docs/autoflow/04-architecture/feature-model-sharing-tdd.md §3、
-- docs/autoflow/04-architecture/api/api-model-sharing.md、
-- docs/autoflow/04-architecture/adr/adr-017-model-library-access.md 決策 3。
--
-- 環境事實(與 00010005 相同已驗證PostgreSQL 14.23gen_random_uuid() 內建可直接用。
--
-- ★關鍵相容性models.visibility DEFAULT 'private' → 既有所有 model 遷移後維持 owner-only
-- 語意,零行為改變。使用者要主動 PATCH visibility 才會公開。
-- ── (1) models 加 visibility 欄(廣播式公開對象)─────────────────────────────
-- 'private'(僅擁有者,= 現況預設)| 'tenant'(同租戶可見)| 'public'(全平台可見)
-- 全部既有 row 加欄後為 'private'DEFAULT語意完全等同遷移前的 owner-only。
ALTER TABLE models ADD COLUMN visibility TEXT NOT NULL DEFAULT 'private';
ALTER TABLE models ADD CONSTRAINT chk_models_visibility
CHECK (visibility IN ('private', 'tenant', 'public'));
-- ── (2) model_shares 表點對點分享ADR-017 決策 3 B1本功能沿用不重造──────
-- role'viewer'(可 list/get/download| 'editor'(可改 metadata本期讀取端用寫入權後續
-- PK (model_id, grantee_user_id):同一 model 對同一 grantee 只有一筆分享(重複分享 = upsert
-- FK ON DELETE CASCADEmodel 硬刪時連帶清 share雖然本系統 model 為軟刪CASCADE 為防禦性
-- 一致——若未來真硬刪不留孤兒列;軟刪時 share 保留,由查詢端 join models.deleted_at 過濾)。
CREATE TABLE model_shares (
model_id UUID NOT NULL REFERENCES models(id) ON DELETE CASCADE,
grantee_user_id UUID NOT NULL REFERENCES users(id),
role TEXT NOT NULL DEFAULT 'viewer',
granted_by UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (model_id, grantee_user_id),
CONSTRAINT chk_model_shares_role CHECK (role IN ('viewer', 'editor'))
);
-- grantee 反查共享庫「分享給我」predicate 的 EXISTS 子查走此 index
CREATE INDEX idx_model_shares_grantee ON model_shares (grantee_user_id);
-- ── (3) 共享庫查詢用 index ───────────────────────────────────────────────────
-- public 全平台可見列表high-selectivity partial index沿用既有 models index 的
-- `WHERE deleted_at IS NULL` 慣例)。只索引 public 且未刪除且已上傳ready的 model
-- 共享庫預設按 created_at DESC 排序、此 index 直接覆蓋該掃描。
CREATE INDEX idx_models_public_active ON models (created_at DESC)
WHERE deleted_at IS NULL AND visibility = 'public' AND uploaded_at IS NOT NULL;
-- tenant 可見需 join users 取 owner.org_idusers 主鍵 join 成本低,
-- owner 維度沿用既有 idx_models_owner_active不另建。