| 欄位 | 內容 |
|---|---|
| Feature | 側邊欄選單分組(menu-group) |
| Phase | Phase 1 — Brainstorm Design |
| 版本 | v1.0 |
| 日期 | 2026-05-26 |
| 撰寫者 | Claude(協作對象:raymond) |
| 上游文件 | docs/features/FR-029-2605-menu-group/requirement-detail.md |
| 狀態 | 待 user review,review 通過後進 Phase 3 implementation-plan |
public.ui_routes 共 39 筆,全部 pid=0(一層扁平結構),側邊欄太冗長。
按業務領域分成 7 個分組,每個分組是可展開父節點,下面掛對應功能入口。具體 7 個分組與包含項目見 requirement-detail.md §2。
ui_routes)+ 既有 /user/web-menu API 即可呈現,FE 不寫死任何項目。三層改動:
┌─────────────────────────────────────────────────────────────┐
│ DB (compliance-manager-be) │
│ ─────────────────────────── │
│ • 新增 9 筆 ui_routes (7 群組 + 2 個寫死搬遷項) │
│ • Update 27 筆既有 ui_routes 的 pid / sort │
│ • schema 完全不動,只動資料 │
└─────────────────────────────────────────────────────────────┘
↓ /user/web-menu API
┌─────────────────────────────────────────────────────────────┐
│ BE Package (jedi-auth) │
│ ───────────────────── │
│ • user_service.get_user_web_ui_routes() 末段 │
│ 加 prune_empty_groups() 剪枝邏輯 │
│ • 移除「無 url 且 items 為空」的分組節點 │
└─────────────────────────────────────────────────────────────┘
↓ JSON tree
┌─────────────────────────────────────────────────────────────┐
│ FE (compliance-manager-fe) │
│ ────────────────────────── │
│ • AppMenu.vue: 移除寫死 grcItems 陣列 │
│ • i18n/zh-tw/menu.json + zh-cn: 補 7 個 group-* key │
│ • AppMenuItem.vue 不動(既有 t() 邏輯自然 work) │
└─────────────────────────────────────────────────────────────┘
主專案 BE 程式碼零改動。
無。public.ui_routes 表結構完全不動,不加欄位、不加 constraint。
檔案位置:scripts/sql/2026-XX-XX-menu-group-restructure.sql(日期由實作時補上)
-- 7 個分組節點(pid=NULL,無 url,僅作為展開父節點)
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), NULL, 'group-project-task', NULL, 'pi pi-briefcase', 1, '專案與任務分組', 10
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'group-project-task');
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), NULL, 'group-compliance-audit', NULL, 'pi pi-shield', 1, '合規與稽核分組', 20
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'group-compliance-audit');
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), NULL, 'group-communication', NULL, 'pi pi-comments', 1, '溝通與互動分組', 30
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'group-communication');
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), NULL, 'group-tenant-org', NULL, 'pi pi-building', 1, '租戶與組織分組', 40
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'group-tenant-org');
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), NULL, 'group-system-admin', NULL, 'pi pi-cog', 1, '系統管理分組', 50
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'group-system-admin');
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), NULL, 'group-system-config', NULL, 'pi pi-sliders-h', 1, '系統設定分組', 60
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'group-system-config');
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), NULL, 'group-ai-analytics', NULL, 'pi pi-chart-line', 1, 'AI 與分析分組', 70
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'group-ai-analytics');
-- 2 個寫死搬遷項(pid 指向 group-project-task)
WITH g AS (SELECT id FROM public.ui_routes WHERE name = 'group-project-task')
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), g.id, 'project-dashboard', '/project/dashboard', 'pi pi-home', 1, '專案儀表板', 10 FROM g
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'project-dashboard');
WITH g AS (SELECT id FROM public.ui_routes WHERE name = 'group-project-task')
INSERT INTO public.ui_routes (uid, pid, name, url, icon, enable, description, sort)
SELECT gen_random_uuid(), g.id, 'my-tasks', '/project/task-manage','pi pi-check-square', 1, '待辦任務', 20 FROM g
WHERE NOT EXISTS (SELECT 1 FROM public.ui_routes WHERE name = 'my-tasks');-- Group 1 (project-task):sort 30/40/50(前面 10/20 給 project-dashboard / my-tasks 用了)
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-project-task'), sort = 30 WHERE name = 'project-list';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-project-task'), sort = 40 WHERE name = 'audit-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-project-task'), sort = 50 WHERE name = 'report-manage';
-- Group 2 (compliance-audit):sort 10/20/30/40
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-compliance-audit'), sort = 10 WHERE name = 'module-frame';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-compliance-audit'), sort = 20 WHERE name = 'compliance-framework-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-compliance-audit'), sort = 30 WHERE name = 'tool-plugin-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-compliance-audit'), sort = 40 WHERE name = 'flow-template-manage';
-- Group 3 (communication):sort 10/20/30/40/50/60
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-communication'), sort = 10 WHERE name = 'bulletin-list';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-communication'), sort = 20 WHERE name = 'bulletin-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-communication'), sort = 30 WHERE name = 'survey-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-communication'), sort = 40 WHERE name = 'system-feedback-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-communication'), sort = 50 WHERE name = 'system-feedback-view';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-communication'), sort = 60 WHERE name = 'issue-integrate-config';
-- Group 4 (tenant-org):sort 10/20/30/40
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-tenant-org'), sort = 10 WHERE name = 'tenant-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-tenant-org'), sort = 20 WHERE name = 'department-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-tenant-org'), sort = 30 WHERE name = 'user-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-tenant-org'), sort = 40 WHERE name = 'role-manage';
-- Group 5 (system-admin):sort 10/20/30/40/50
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-admin'), sort = 10 WHERE name = 'system-menu-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-admin'), sort = 20 WHERE name = 'information-system-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-admin'), sort = 30 WHERE name = 'device-manage';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-admin'), sort = 40 WHERE name = 'storage-config';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-admin'), sort = 50 WHERE name = 'cloud-integrations';
-- Group 6 (system-config):sort 10/20/30/40
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-config'), sort = 10 WHERE name = 'smtp-config';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-config'), sort = 20 WHERE name = 'ldap-config';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-config'), sort = 30 WHERE name = 'notify-config';
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-system-config'), sort = 40 WHERE name = 'user-log';
-- Group 7 (ai-analytics):sort 10
UPDATE public.ui_routes SET pid = (SELECT id FROM public.ui_routes WHERE name = 'group-ai-analytics'), sort = 10 WHERE name = 'ai-dashboard';BEGIN; ... COMMIT; 包,全成或全敗。cmmgr 跑(避開 RLS 擋寫;cm_app 寫不進系統層級資料)。-- N. 說明 (2026-XX-XX) 註解(依 CLAUDE.md 規範)。WHERE NOT EXISTS 保護;Step 2 的 UPDATE 重複跑無害(目標 pid / sort 固定)。| ui_routes.name | enable | 處置 |
|---|---|---|
workflow-setup |
0 | 不動 pid(保持 0/NULL)、不動 sort、不動 enable |
workflow-view |
0 | 同上 |
textbook-execution |
0 | 同上 |
textbook-tested |
0 | 同上 |
textbook-general |
0 | 同上 |
resource-version-manage |
0 | 同上 |
resource-manage |
0 | 同上 |
cruise-project-manage |
0 | 同上 |
cruise-feedback-view |
0 | 同上 |
report-view |
0 | 同上 |
customer-dashboard-editor |
0 | 同上 |
user-guide |
0 | 同上 |
→ BE 過濾 enable=1,這 12 個項目根本不出現在 /user/web-menu 回傳結果。不會變成「pid=0 的孤兒葉節點」與分組節點並列。
檔案:~/Projects/Jedicogy/module/jedi-python-package/jedi-auth/jedi_auth/app/service/user_service.py
Method:get_user_web_ui_routes()(line 438~528)
在現有 sort_nodes(roots) 之後新增剪枝 step:
@transaction
def get_user_web_ui_routes(self, user_uid: str, tenant_id: int | None) -> list[dict]:
"""
取得使用者可檢視的前端路由選單(RBAC,多租戶版)
... (既有 docstring 保留)
"""
# ... (既有邏輯不動:取使用者 capability、build node_map、組樹、sort) ...
sort_nodes(roots)
# 新增:剪枝空分組節點(無 url 且 items 為空的純分組節點)
return self._prune_empty_groups(roots)
def _prune_empty_groups(self, nodes: list[dict]) -> list[dict]:
"""
遞迴剪枝:移除「無 url 且 items 為空」的分組節點。
葉節點(有 url)永遠保留;分組節點若還有可見子項也保留。
使用情境:
- 某 user 對「租戶與組織」分組下所有功能都無 capability → 該分組整個從選單消失
- 葉節點 url 為 None(理論上不應發生)也會被當分組處理:實務上葉節點都應有 url
"""
pruned = []
for n in nodes:
if n.get("items"):
n["items"] = self._prune_empty_groups(n["items"])
is_group = not n.get("url")
if is_group and not n.get("items"):
continue
pruned.append(n)
return pruned檔案:~/Projects/Jedicogy/module/jedi-python-package/jedi-auth/tests/unittest/test_user_service.py
新增 3 個 case(接在現有 test_get_user_web_ui_routes_* 系列後):
test_get_user_web_ui_routes_prune_empty_group
get_viewable_routes_by_user_uid 回 1 個分組節點(無 url)+ 0 個子節點test_get_user_web_ui_routes_keep_group_with_visible_children
test_get_user_web_ui_routes_keep_group_with_partial_visible_children
整 feature 完成 + smoke 通過 + user 明確指示後才做:
jedi-auth/pyproject.toml:version = "0.0.X" → "0.0.X+1"(patch bump,剪枝邏輯屬 bug-fix-style 增量改進)pyproject.toml 還原 path → pin 新版本 + poetry update jedi-authcompliance-manager-fe/src/layout/AppMenu.vue onMounted(()=> {
- // GRC / Project module (static — no permission gate needed for demo)
- const grcItems = [
- { label: 'project-dashboard', icon: 'pi pi-home', to: '/project/dashboard' },
- // { label: 'project-manage', icon: 'pi pi-folder-open', to: '/project/projects' },
- { label: 'my-tasks', icon: 'pi pi-check-square', to: '/project/task-manage' },
- ]
-
- menu.value = [...grcItems, ...genMenuNode(permissions.value)]
+ menu.value = genMenuNode(permissions.value)
})compliance-manager-fe/src/config/locales/i18n/zh-tw/menu.json"menu" 物件內新增 7 個 key(建議排在現有同類 key 附近,或集中放在檔案末尾並加註解區隔):
{
"menu": {
...
"group-project-task": "專案與任務",
"group-compliance-audit": "合規與稽核",
"group-communication": "溝通與互動",
"group-tenant-org": "租戶與組織",
"group-system-admin": "系統管理",
"group-system-config": "系統設定",
"group-ai-analytics": "AI 與分析"
}
}compliance-manager-fe/src/config/locales/i18n/zh-cn/menu.json對應補簡體版(用語由 FE 側決定,例:「项目与任务 / 合规与稽核 / 沟通与互动 / ...」)。若該 repo 有 sync-translations.js 工具,跑該工具自動產生候選翻譯後再 review。
若有 en/menu.json 且該 locale 啟用中,補英文翻譯(如 "Projects & Tasks" 等);若 en locale 未啟用或未維護,本期不要求補。Phase 3 implementation-plan 階段確認。
AppMenuItem.vue — 不動既有 t(\lang.menu.${item.label}`)邏輯天然支援新增的group-*key。<strong>邊界 case</strong>:分組節點to` 為 null 時的 render 行為,需在實作前 manual verify(Phase 5 開工前)— 預期既有 PrimeVue Menu 行為會自動 render 成可展開父節點而非可點擊連結。
| Case | 預期行為 | 風險評估 |
|---|---|---|
| 既有 user(有 role + capabilities) | 看到完整 7 分組 + 對應可見葉節點,與舊版內容一致 | 無 — 葉節點 capability 沒動 |
| 新進 user(無 role) | 看到「專案儀表板 / 待辦任務」2 項(不掛 capability)+ 沒有任何分組標題(都被 prune) | 無 — 符合「2 項 always visible」設計 |
| Admin(super-admin role) | 看到完整 7 分組 + 全部葉節點 | 無 |
| FE i18n key 漏譯 | AppMenuItem 顯示 lang.menu.group-xxx 字串 |
低 — PR 前 verify zh-tw + zh-cn 都補齊即可 |
| AppMenuItem 對「無 url 父節點」處理 | 預期 render 為可展開父節點 | 中 — Phase 5 manual verify 後若不 work 需 wrap 條件判斷 |
| Migration 中斷 | DB 處於部分 update 狀態 | 低 — BEGIN; ... COMMIT; 全成或全敗 |
| 既有外部資料引用 sort 數值 | sort 改動影響該外部資料 | 已確認無 — scripts/sql/ grep 過、BE 只用 sort 做排序、不依賴具體數值 |
| FE 早於 BE/DB 部署 | /user/web-menu 仍回扁平 tree,FE 拿掉寫死 → user 暫時看不到「專案儀表板 / 待辦任務」 |
中 — 部署順序強制 BE/DB 先、FE 後 |
| BE 部署但 DB migration 未跑 | jedi-auth 剪枝邏輯 wrong tree(扁平 tree 無分組)→ 不影響 | 無 — 剪枝對扁平 tree 是 no-op |
| Rollback 需求 | 移除 9 筆新節點 + 還原 27 筆原 sort 值 | 中 — 需事先 dump 既有 sort 備份;Rollback SQL 見附錄 C |
feature/menu-group(user 自行切換,Claude 不切 branch)。pyproject.toml:把 jedi-auth 改成 path dependency(此改動不 commit)。cmmgr 帳號)+ BE 重啟 + smoke test:
pyproject.toml bump version + commit + push origin。pyproject.toml 還原 path 為 pin 新版本。poetry update jedi-auth。順序強制:BE → DB migration → FE
| 步驟 | 動作 | 為何這個順序 |
|---|---|---|
| 1 | 部署 BE(含新 jedi-auth) | 剪枝邏輯先就緒。即使 DB 還沒跑,扁平 tree 對剪枝是 no-op,不影響舊行為 |
| 2 | DB migration | 既有 user 立刻看到分組結構(BE 已備好剪枝邏輯) |
| 3 | 部署 FE | AppMenu.vue 拿掉寫死 + i18n 翻譯生效 |
為何 FE 不能先部署:若 FE 先拿掉 grcItems 但 BE/DB 仍回扁平 tree → user 暫時看不到「專案儀表板 / 待辦任務」。
依 §4.3 新增 3 個 case。
-- 跑完 migration 後驗證
SELECT name, pid, sort FROM public.ui_routes WHERE name LIKE 'group-%' ORDER BY sort;
-- 預期 7 row
SELECT name, pid, sort FROM public.ui_routes WHERE pid IS NOT NULL ORDER BY pid, sort;
-- 預期 29 row(27 既有 + 2 新增搬遷項)| Scenario | 預期 |
|---|---|
| admin user 登入 | 看到 7 個分組標題 + 全部葉節點 |
| 一般 user 登入 | 看到對應 role 的可見分組 + 葉節點 |
| 新進無 role user 登入 | 只看到「專案儀表板 / 待辦任務」2 項、沒有任何分組標題 |
| zh-tw 切換到 zh-cn | 分組標題顯示簡體 |
| 點開可展開分組 | 顯示底下葉節點清單 |
| 點葉節點 | 正常跳轉到對應路由 |
| 點分組節點本身(無 url) | 不跳轉,僅 toggle 展開/收合 |
本期屬 UI 重組,BE 邏輯改動範圍小(單個套件函式末段 prune),不需要在 compliance-manager-test repo 加 Cucumber/Playwright scenarios。
設計預測(§5.5):「AppMenuItem.vue 不動,既有 PrimeVue Menu 行為自然 work」
實際情況:AppMenuItem.vue template 只有單一 <router-link>,沒有遞迴 render sub-items 的區塊。分組結構上線後葉節點完全看不到、分組節點因 router-link :to=undefined 導向首頁。
修正內容(commit 0d1ca8b):
<a @click.prevent> 取代 <router-link><ul v-show="isActiveMenu"><app-menu-item> 遞迴區塊教訓:設計文件標注「需 Phase 5 manual verify」的邊界 case,實作前必須先手動確認,不能交由 subagent 假設。
供後續 Phase 3 plan 參考(不在本 design.md 詳列實作步驟):
| Group | id(runtime) | name | url | sort | source |
|---|---|---|---|---|---|
| — | new | group-project-task |
NULL | 10 | 本期新增 |
| — | new | group-compliance-audit |
NULL | 20 | 本期新增 |
| — | new | group-communication |
NULL | 30 | 本期新增 |
| — | new | group-tenant-org |
NULL | 40 | 本期新增 |
| — | new | group-system-admin |
NULL | 50 | 本期新增 |
| — | new | group-system-config |
NULL | 60 | 本期新增 |
| — | new | group-ai-analytics |
NULL | 70 | 本期新增 |
| 1 | new | project-dashboard |
/project/dashboard |
10 | 本期搬遷 |
| 1 | new | my-tasks |
/project/task-manage |
20 | 本期搬遷 |
| 1 | 8 | project-list |
/project/projects |
30 | 既有 update pid/sort |
| 1 | 37 | audit-manage |
/project/audit-manage |
40 | 既有 update pid/sort |
| 1 | 15 | report-manage |
/project-summary-report |
50 | 既有 update pid/sort |
| 2 | 24 | module-frame |
/module-frame/module-frame |
10 | 既有 update pid/sort |
| 2 | 33 | compliance-framework-manage |
/compliance-framework/compliance-framework-manage |
20 | 既有 update pid/sort |
| 2 | 25 | tool-plugin-manage |
/plugin/tool-plugin-manage |
30 | 既有 update pid/sort |
| 2 | 40 | flow-template-manage |
/flow/template-manage |
40 | 既有 update pid/sort |
| 3 | 6 | bulletin-list |
/bulletin/bulletin-list |
10 | 既有 update pid/sort |
| 3 | 7 | bulletin-manage |
/bulletin/bulletin-manage |
20 | 既有 update pid/sort |
| 3 | 11 | survey-manage |
/survey/manage |
30 | 既有 update pid/sort |
| 3 | 12 | system-feedback-manage |
/feedback/system-feedback-manage |
40 | 既有 update pid/sort |
| 3 | 13 | system-feedback-view |
/feedback/system-feedback-view |
50 | 既有 update pid/sort |
| 3 | 32 | issue-integrate-config |
/system/issue-integrate-config |
60 | 既有 update pid/sort |
| 4 | 31 | tenant-manage |
/tenant/tenant-manage |
10 | 既有 update pid/sort |
| 4 | 29 | department-manage |
/department/department-manage |
20 | 既有 update pid/sort |
| 4 | 2 | user-manage |
/auth/user-manage |
30 | 既有 update pid/sort |
| 4 | 3 | role-manage |
/auth/role-manage |
40 | 既有 update pid/sort |
| 5 | 21 | system-menu-manage |
/system/system-menu-manage |
10 | 既有 update pid/sort |
| 5 | 36 | information-system-manage |
/information-system/manage |
20 | 既有 update pid/sort |
| 5 | 30 | device-manage |
/device/device-manage |
30 | 既有 update pid/sort |
| 5 | 34 | storage-config |
/system/storage-config |
40 | 既有 update pid/sort |
| 5 | 38 | cloud-integrations |
/settings/cloud-integrations |
50 | 既有 update pid/sort |
| 6 | 27 | smtp-config |
/system/smtp-config-manage |
10 | 既有 update pid/sort |
| 6 | 28 | ldap-config |
/system/ldap-config |
20 | 既有 update pid/sort |
| 6 | 39 | notify-config |
/system/notify-config |
30 | 既有 update pid/sort |
| 6 | 4 | user-log |
/log/user-log |
40 | 既有 update pid/sort |
| 7 | 35 | ai-dashboard |
/dashboard/ai-dashboard |
10 | 既有 update pid/sort |
未列項目 12 筆(enable=0、不動):見 §3.3。
PGPASSWORD='<password>' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev \
-At -F',' \
-c "SELECT id, name, pid, sort FROM public.ui_routes ORDER BY id;" \
> scripts/sql/backup/2026-XX-XX-ui_routes-pre-menu-group.csv備份 CSV 用於 rollback 還原。
BEGIN;
-- 1. 還原既有 27 筆的 pid / sort(依附錄 B CSV 還原;以下為示意)
-- 實作時用 psql \copy 或寫 generator 從 CSV 產 UPDATE 語句
-- 2. 移除本期新增 9 筆
DELETE FROM public.ui_routes WHERE name IN (
'group-project-task', 'group-compliance-audit', 'group-communication',
'group-tenant-org', 'group-system-admin', 'group-system-config', 'group-ai-analytics',
'project-dashboard', 'my-tasks'
);
COMMIT;Rollback 限制:jedi-auth 套件的剪枝邏輯若已透過 Nexus 進版部署,rollback DB 後對線上行為無影響(扁平 tree 對剪枝是 no-op,舊行為自然恢復)。FE 若已部署則 rollback FE commit 即可。
| 文件 | 路徑 |
|---|---|
| 上游草稿 | docs/draft_requirement_spec/menu-group/requirement.md(user 原稿) |
| 上游白話需求 | docs/features/FR-029-2605-menu-group/requirement-detail.md |
| jedi-auth source | ~/Projects/Jedicogy/module/jedi-python-package/jedi-auth/jedi_auth/app/service/user_service.py |
| FE AppMenu.vue | ~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/layout/AppMenu.vue |
| FE i18n menu.json | ~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/config/locales/i18n/zh-tw/menu.json |
| 權限系統設計 | docs/system-design/permission/Permission-System-權限與選單系統設計說明書.md |
| Feature workflow SOP | docs/claude/feature-development-workflow.md |