對應 design:design-C1.md 級別:中型 預估工時:BE 0.5 天 + FE 0.5 天
# 1. 確認 system_menus 表存在且 schema 是 (group, key, value, sort, enable, public)
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c "\d system_menus"
# 2. 確認 system_menus 是否已有 UNIQUE(group, key) constraint
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c \
"SELECT conname FROM pg_constraint WHERE conrelid = 'system_menus'::regclass AND contype = 'u';"
# 3. 確認 oscal.oscal_roles 表 schema (C3-D5 同步 seed 需要)
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c "\d oscal.oscal_roles"
# 4. 確認 oscal.oscal_roles 是否已有 UNIQUE(role_id) constraint
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c \
"SELECT conname FROM pg_constraint WHERE conrelid = 'oscal.oscal_roles'::regclass AND contype = 'u';"
# 5. 確認 oscal.oscal_roles 現有資料(避免衝突)
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c \
"SELECT role_id, title FROM oscal.oscal_roles ORDER BY role_id;"
# 6. 確認 GET /system/menu/<group> endpoint 路徑 + 回傳格式
grep -n "SystemGroupMenuRoute" api/system_menu/__init__.py
# 預期:/system/menu/<string:group>
# 7. 確認 jedi-system-menu 在 BE pyproject.toml 已 pin
grep "jedi-system-menu" pyproject.tomlVerification 結果填回 design-C1.md 對應段落(特別是兩個 UNIQUE 是否已存在)。
檔案:
scripts/sql/2026-MM-DD-seed-oscal-ssp-roles.sql行為:
ON CONFLICT DO NOTHING idempotentSELECT COUNT(*) 確認各 9 筆前置處理:
system_menus 無 UNIQUE(group, key):
SELECT "group", key, COUNT(*) FROM system_menus GROUP BY "group", key HAVING COUNT(*) > 1; 確認無重複ALTER TABLE system_menus ADD CONSTRAINT uq_system_menus_group_key UNIQUE ("group", key);oscal.oscal_roles 無 UNIQUE(role_id):
SELECT role_id, COUNT(*) FROM oscal.oscal_roles GROUP BY role_id HAVING COUNT(*) > 1;ALTER TABLE oscal.oscal_roles ADD CONSTRAINT uq_oscal_roles_role_id UNIQUE (role_id);驗證:
SELECT * FROM system_menus WHERE "group" = 'ssp_party_role' ORDER BY sort;
-- 應看到 9 筆,sort 為 10, 20, ..., 90
SELECT role_id, title FROM oscal.oscal_roles WHERE role_id IN (
'responsible-organization','system-owner','system-security-officer',
'authorizing-official','information-owner','information-provider',
'information-receiver','prepared-by','prepared-for'
) ORDER BY role_id;
-- 應看到 9 筆Commit message:chore(sql): C1 seed OSCAL SSP 9 個角色到 system_menus + oscal_roles
驗證:
# 取 JWT token 後
curl -H "Authorization: Bearer <token>" \
http://localhost:8000/api/1.0/system/menu/ssp_party_role | jq '.data.menus | length'
# 預期:9不需新增 BE 程式碼(沿用 jedi-system-menu 既有 endpoint)。
檔案:
src/config/locales/i18n/zh-tw/oscal-role.jsonsrc/config/locales/i18n/en/oscal-role.json接入 i18n loader:
src/config/locales/i18n/zh-tw/index.js(或對應 loader)有自動引入新檔驗證:
// FE console
$t('lang.oscal_role.ssp_party_role.system-owner.label')
// 預期:'系統所有者'Commit message:feat(i18n): C1 新增 oscal-role i18n 9 個 OSCAL SSP 角色
BE 檔案:docs/changelog/YYYY-MM-DD-feat-oscal-ssp-roles-master-data.md
---
type: feat
breaking: false
modules: [system_menu]
---
## 需求說明
C1:OSCAL SSP 角色 master data 化 — 9 個標準 OSCAL role 種子進 system_menus,
供 C2 SSP party endpoint dropdown 使用。
## 變更範圍
### BE
- `scripts/sql/2026-MM-DD-seed-oscal-ssp-roles.sql`:9 個 INSERT + (optional) UNIQUE constraint
## 部署備註
- SQL migration 須在 dev DB 跑一次
- 不影響既有功能FE 檔案:同步建立 changelog(FE repo 對應位置)
| 測試 | 工具 | 內容 |
|---|---|---|
| BE smoke | curl | GET /system/menu/ssp_party_role 回 9 筆 |
| FE i18n | console | $t(...) 解析正確 |
| Idempotent | psql | seed SQL 重跑兩次不會重複 |
不需新 unit test(純資料 seed)。
| 風險 | 緩解 |
|---|---|
| seed 跑失敗 | ON CONFLICT DO NOTHING idempotent,可重跑 |
| 既有 system_menus 同 group 已有同 key | UNIQUE check 阻擋 / ON CONFLICT 跳過 |
| 不小心 seed 到 prod | migration SQL 不會自動跑,須手動執行 |
Rollback:
DELETE FROM system_menus WHERE "group" = 'ssp_party_role';