專案儀表板(Project Dashboard)
事實基準:2026-07-05 從 FE / BE code 掃出(FR-038 v2);endpoint 對照
routes.json,response 對照 marshmallow serializer,表結構取自db_schema.json變更紀錄:2026-07-09 FR-047 —— ① 專案狀態機 B 案:專案建立即
in_progress(「未開始 pending」語意取消),落地頁「進行中專案」卡改只判in_progress(DashboardView篩選對齊輪次驅動真相);② 進行中專案卡進度條接上真值(list_projects補completion_rate,原恆 0%)
1. 功能描述
專案儀表板是登入後的全域落地頁(route
/project/dashboard)——聚合「我有份的」跨專案資訊:四張指標卡、我的待辦任務、我的稽核、進行中專案卡片、兩張圖表(各專案完成度
/ 狀態分佈)。
與專案總覽頁的區別:本頁是跨專案的個人落地頁(無專案
id);專案總覽頁(/project/projects/:id/round/:roundUid)是單一專案單一輪次的儀表板。兩者不同頁、不同資料源,勿混淆。
主要使用者:所有登入者(各區塊以
hasCap() 能力個別 gate;本頁無 route
層權限,缺能力則該區塊隱藏而非整頁擋)。
角色速覽:本頁無專案層角色概念,改以全域能力(capability)gate 個別區塊。
| 能力 | 開放區塊 |
|---|---|
project.read |
指標卡 2~4、進行中專案卡、兩張圖表 |
audit.read |
我的稽核表 |
| (無需能力) | 歡迎列、我的待辦任務(指標卡 5 + 表格 6) |
1.1 功能總覽(本頁全部功能)
| # | 功能 | 說明 | 位置 | 詳述 |
|---|---|---|---|---|
| 1 | 歡迎列 | 「歡迎回來,{nickname}」+ 今日日期(本地格式,非 API) | 頁首 | §10 |
| 2 | 指標卡:進行中專案數 | metrics.active_project_count(project.read) |
指標區 | §6.2 |
| 3 | 指標卡:控制項總數 | metrics.total_controls(project.read) |
指標區 | §6.2 |
| 4 | 指標卡:平均完成度 | metrics.avg_completion_rate %(project.read) |
指標區 | §6.2 |
| 5 | 指標卡:我的待辦任務數 | metrics.my_pending_task_count(永遠顯示) |
指標區 | §6.2 |
| 6 | 我的待辦任務表 | 前 5 筆;tab 全部/未開始/進行中(client filter);列 → project-my-tasks | 表格 | UC-PD-01 |
| 7 | 我的稽核表 | audit.read;僅 status=auditing;前 5
筆;列 → project-audit-review-round |
表格 | UC-PD-01 |
| 8 | 進行中專案卡 | project.read;6
張;名稱/框架/最新輪次徽章/描述/進度條/群組控制數/期程;卡 →
project-ap-list |
卡片區 | UC-PD-01 |
| 9 | 圖表:各專案完成度 | 橫條(Chart.js),project.read,project_completion
真值 |
圖表區 | §6.2 |
| 10 | 圖表:專案狀態分佈 | 甜甜圈,7 態 status_distribution,零值桶濾除 |
圖表區 | §6.2 |
| 11 | 載入狀態 | 全頁 spinner 於並行 fetch 期間 | 頁面 | §10 |
UC(§2)展開一條核心路徑 UC-PD-01(載入聚合資料並導航到各明細頁)。§12 記錄兩處已確認失效的 UI 元素(專案卡進度條恆 0%、SSP 迷你件不顯示),本頁如實描述現況、不當作正常功能寫。
2. Use Case
角色速覽:本頁無專案層角色概念,改以全域能力(capability)gate 個別區塊。
| 能力 | 開放區塊 |
|---|---|
project.read |
指標卡 2~4、進行中專案卡、兩張圖表 |
audit.read |
我的稽核表 |
| (無需能力) | 歡迎列、我的待辦任務(指標卡 5 + 表格 6) |
流程圖視覺慣例:菱形 = 判斷、橘底 = 例外 / 擋下、綠框 = 成功終點、虛線 = 可選路徑。
UC-PD-01 檢視儀表板並導航到明細
| 項目 | 內容 |
|---|---|
| 角色 | 任一登入者(區塊依 hasCap 顯示) |
| 前置條件 | 已登入 |
| 產出 / 後置條件 | 並行載入 2~4 個 endpoint(依能力);點任務 / 稽核 / 專案卡導向對應明細頁 |
3. 權限矩陣
本頁無 route 層權限(無 pagePermission
meta),控制在 UI 組成層以 hasCap() 個別 gate;BE 各
endpoint 另有可見性強制:
| 操作 | FE 判定 | BE 強制 | BE 檢查位置 |
|---|---|---|---|
| 指標 / 專案清單 / 圖表 | hasCap('project.read') |
只回自己有份的專案(is_admin=False,admin 繞 RLS
但不繞成員資格) |
infra/grc/repository/grc_dashboard_repo_impl.py /
grc_project_repo_impl.py(可見性聯集) |
| 我的稽核 | hasCap('audit.read') |
SQL join
project_participants.role IN ('auditor','manager') +
可見輪次狀態白名單(auditing/remediation/closed) |
infra/grc/repository/auditor_dashboard_query.py:43-46,15 |
| 我的待辦任務 | 無 gate | vw_user_job_queue.user_id == user_id(任務指派身分) |
infra/participant/repository/task_assignee_repo_impl.py |
⚠️ 本頁權限是「區塊級隱藏」而非整頁擋——缺
project.read只是專案相關區塊消失,「我的待辦任務」仍顯示(對落地頁合理)。各 endpoint 的 BE 可見性各自獨立,三種身分判定不同(專案成員資格 / 稽核角色 / 任務指派),勿假設一致。
4. 狀態機與前置條件
本頁不推進任何狀態,僅呈現跨專案彙總。狀態分佈甜甜圈的
7 態桶對應輪次狀態機(見 _overview
§2);completion_trend 欄位恆 [](v2
無歷史快照表,見 §12)。
5. UI 設計
版面骨架與區塊職責(本頁為落地儀表板,區塊以全域 capability gate;彩色區塊可點跳本頁小節錨點,API 僅標代表性):
實機截圖(STG,亮色模式,2026-07-05,帳號 blsadmin):



狀態呈現:全頁 spinner 於並行 fetch;MetricCard /
StatusBadge / FrameworkBadge /
GrcProgressBar 共用元件;兩圖為 PrimeVue
Chart(Chart.js v4)橫條 +
甜甜圈,甜甜圈附自訂圖例。注意:進行中專案卡的進度條已接上真值(2026-07-07
修,§12 坑 2);SSP 完成度迷你件仍不顯示(§12 坑 1,未接
follow-up)。
6. API 規格
Envelope:成功 {"status": true, "data": …}(清單類帶
meta)、失敗
{"error_code": "…", "msg": "…"}。
6.1 總清單(本頁呼叫的全部 endpoint)
| 分類 | Method + Path | 說明 | 完整規格 |
|---|---|---|---|
| 聚合 | GET /grc/dashboard/summary |
四指標 + 狀態分佈 + 各專案完成度 | §6.2 |
| 我的任務 | POST /grc/jobs/my/list |
我的待辦(exclude COMPLETED,page_size 8) | §6.2 |
| 專案 | POST /grc/projects/list |
進行中專案卡(status in_progress/pending,6 筆) | project-list.md §6.2 |
| 我的稽核 | POST /grc/audits/my/list |
我的 auditing 稽核 | §6.2 |
| (死路) | GET /ssp/{ssp_uid}/control-implementations |
SSP 迷你件——本頁永不觸發(§12 錨點1) | — |
6.2 核心 endpoint
[GET] /grc/dashboard/summary
無參數。Response
data(DashboardSummaryResponseSchema):
| 欄位 | 型別 | 說明 |
|---|---|---|
| metrics | object | {active_project_count:int, total_controls:int, avg_completion_rate:int, my_pending_task_count:int} |
| status_distribution | object | {<7 態>: int}(狀態分佈甜甜圈;零值桶前端濾除) |
| project_completion | array | [{project_uid, project_name, completion_rate:int}](各專案完成度橫條,真值) |
| completion_trend | array | 恆 [](v2 無歷史快照表,schema back-compat 保留;FE
不消費) |
存取控制:route 強制 is_admin=False(admin
不繞專案成員資格)。出處:api/grc/serializers/dashboard.py、infra/grc/repository/grc_dashboard_repo_impl.py
[POST] /grc/jobs/my/list
Request:
{
"pager": { "page": 1, "page_size": 8, "with_total": false },
"sort": [],
"filters": { "exclude_status": "COMPLETED" }
}Response
data(MyJobResponseSchema[],每項一筆待辦任務):
| 欄位 | 型別 | 說明 |
|---|---|---|
| id | string | = uid(字串非數字) |
| name | string | 任務名稱 |
| job_type | string | 任務類型 |
| status | string | 任務狀態 |
| project_uid / project_name | string | 所屬專案識別 / 名稱 |
| control_group_* / control_* / ao_* | string | 控制群組 / 控制項 / AO 的識別與名稱(多欄,*
為前綴群) |
| workflow_execution_uid | string | BPMN 執行實體 |
| attachment_count | int | 附件數 |
| survey_completed | bool | 問卷是否完成 |
來源 = ORM view
public.vw_user_job_queue。出處:api/grc/serializers/job.py:235、infra/participant/repository/task_assignee_repo_impl.py
[POST] /grc/audits/my/list
Request(無分頁,回 flat items):
{ "filters": { "status": "auditing" } }Response
data.items(AuditorDashboardItemSchema[]):
| 欄位 | 型別 | 說明 |
|---|---|---|
| project_uid / project_name | string | 所屬專案識別 / 名稱 |
| round_uid | string | 稽核輪次 |
| ap_uid | string | = round_uid 別名 |
| ap_title | string | = project_name |
| run_no | int | 輪次序號 |
| ap_status | string | 輪次狀態 |
| total_controls | int | 控制項總數 |
| verdict_completed / verdict_pending | int | 已判定 / 未判定數 |
| verdict_summary | object | {passed, fail, partial, na} 判定分佈 |
| finding_count | int | finding 數 |
| evidence_ready_count / evidence_total_count | int | 證據就緒 / 總數(恆 0,v2 follow-up 未實作) |
| started_at / deadline | datetime | 起始 / 期限 |
SQL 內建 role IN ('auditor','manager') +
輪次狀態白名單守門。出處:api/grc/serializers/auditor_dashboard.py、infra/grc/repository/auditor_dashboard_query.py
7. 前端檔案地圖(compliance-manager-fe/)
| 檔案 | 角色 |
|---|---|
src/views/project/DashboardView.vue |
主檢視(約 503 行;4 fetch、指標卡、兩表、專案卡、兩圖) |
src/config/router/index.js:748-753 |
route
project-dashboard(/project/dashboard) |
src/components/grc/{MetricCard,StatusBadge,FrameworkBadge,GrcProgressBar}.vue |
指標卡 / 狀態徽章 / 框架徽章 / 進度條 |
src/service/SspService.js |
getControlImplementations()(本頁死路,§12) |
src/config/api/api.js |
endpoint 常數(GRC_DASHBOARD_SUMMARY 等) |
src/config/locales/i18n/zh-tw/project-dashboard.json |
頁面 i18n |
src/utils/userUtil.js |
hasCap() 能力判定(區塊 gate) |
8. 後端檔案地圖(本頁核心鏈路)
| 鏈路 | Route | App Service | 底層 |
|---|---|---|---|
| 儀表板聚合 | api/grc/routes/dashboard_route.py::DashboardSummaryResource.get |
app/grc/service/dashboard_service.py::get_dashboard_summary |
domain/grc/service/grc_dashboard_domain_service.py →
infra/grc/repository/grc_dashboard_repo_impl.py(可見性聯集
+ 控制母體 resolution + 完成度統計) |
| 我的任務 | api/grc/routes/job_route.py::MyJobListResource.post |
app/participant/service/task_assignee_service.py::list_my_grc_jobs(+
證據 / 問卷 enrich) |
infra/participant/repository/task_assignee_repo_impl.py(查
view vw_user_job_queue) |
| 進行中專案 | api/grc/routes/project_route.py::ProjectListResource.post |
project_service.list_projects |
grc_project_repo_impl.list_projects(見 專案列表頁) |
| 我的稽核 | api/grc/routes/auditor_dashboard_route.py::AuditorDashboardRoute.post |
app/grc/service/auditor_dashboard_service.py::get_my_audit_list |
infra/grc/repository/auditor_dashboard_query.py(raw
SQL query-object,非完整 DDD 鏈) |
DDD 提醒:auditor_dashboard_query 是
query-object pattern(raw SQL),非標準 entity 鏈——讀取聚合場景刻意繞
entity 提效,別當一般 CRUD 樣板。
9. DB
9.1 資料表總清單(本頁讀取的全部表 / 視圖)
| 表 / 視圖 | 讀/寫 | 說明 | 欄位詳述 |
|---|---|---|---|
| compliance.projects | 讀 | 可見性主檔(is_admin=False) | 規劃頁 §9.3 |
| compliance.project_extensions | 讀 | owner / living_ssp 導航 | 規劃頁 §9.3 |
| compliance.project_audit_rounds | 讀 | status(狀態分佈)/ round_no(最新輪) | 規劃頁 §9.3 |
| compliance.project_participants | 讀 | 成員資格 + 稽核角色守門 | GAI-SD-03 |
| compliance.control_group_participants / project_control_participants / project_group_participants / task_assignees | 讀 | 可見性聯集子查詢 | GAI-SD-03 |
| oscal.system_security_plans / profile_imports / catalog_controls / catalog_control_parts | 讀 | 控制母體(total_controls) | GAI-SD-03 |
| compliance.workflow_templates / workflow_executions / job_executions | 讀 | 完成度(type=USER 完成數) | 規劃頁 §9.3 |
| oscal.assessment_findings | 讀 | 我的稽核 verdict 統計 | GAI-SD-03 |
| public.vw_user_job_queue(VIEW) | 讀 | 我的待辦任務清單(by user_id) | §9.3 |
9.2 ER 圖(本頁讀取範圍)
9.3 核心表 / 視圖
大多數表欄位見規劃頁 §9.3 與 GAI-SD-03。本頁特有:
public.vw_user_job_queue — 使用者任務佇列(VIEW)
非基底表,是 view(定義
scripts/sql/view/vw_user_job_queue.sql),由
compliance.task_assignees / job_executions /
projects / workflow_executions /
public.users /
workflow_execution_control_mapping /
project_extensions + catalog 表組成;供「我的待辦任務」按
user_id 撈。欄位:job_id /
user_id / job_status / job_name /
project_uid / project_name /
group_name / control_no /
ap_task_* / workflow_execution_uid。
10. 頁面邏輯與資料對應
載入時序:見 §2 UC-PD-01(2~4 支並行,依能力)。歡迎列 nickname / 日期來自 user store 與本地時間,非 API。
關鍵欄位對應:
| 畫面元素 | FE state | API 欄位 |
|---|---|---|
| 四指標卡 | metrics.* |
summary
metrics.{active_project_count,total_controls,avg_completion_rate,my_pending_task_count} |
| 各專案完成度橫條 | projectCompletion |
summary project_completion[] |
| 狀態分佈甜甜圈 | statusDistributionData |
summary status_distribution |
| 我的待辦表 | myPendingTasks(slice 5) |
jobs/my/list data[] |
| 我的稽核表 | myAudits(slice 5) |
audits/my/list data.items[] |
| 進行中專案卡 | projects(6) |
projects/list data[] |
導航:待辦列 →
project-my-tasks?job=;稽核列 →
project-audit-review-round;專案卡 →
project-ap-list;「檢視全部」→ 對應列表頁。
錯誤對應:各 fetch 失敗個別 catch,不整頁 fail;能力不足的區塊直接不渲染。
11. 背景行為與外部依賴
| 類型 | 內容 |
|---|---|
| Socket | 本頁無 socket / 輪詢;進頁一次載入 |
| 圖表 | PrimeVue Chart(Chart.js v4)本地渲染,無外部請求 |
| jedi-* 套件 | jedi-oscal-v2(控制母體
resolution)、jedi-flow-engine(任務)、jedi-auth(JWT
/ RLS) |
| RLS | tenant 隔離由 PostgreSQL RLS session 變數處理,非 app 層 filter |
| 系統參數 | 無 feature flag;能力來自 /user/web-menu 權限樹 |
12. 邊界情況與已知坑
- ⚠️ 進行中專案卡的「SSP
完成度迷你件」永不顯示(已驗證死碼):卡片
v-if="sspStatsMap[project.id]",但填充它的fetchSspStats依賴p.ssp?.id,而POST /grc/projects/list的list_projects不 wiressp(mapper 預設ssp_uid=None,只有 detail endpoint 才帶)→ SSP 迷你件在本頁任何情況都不會 render - 進行中專案卡進度條已接上真值(2026-07-07 修,FR-047
R1):原本
list_projects不傳completion_rate、mapper 預設 0 → 進度條恆 0%,與同頁「各專案完成度」圖表(summary 真值)矛盾。已在list_projects加_completion_rates()批次 helper(公式與 summaryproject_completion同源)餵 mapper,進度條與圖表同源。註:SSP 完成度迷你件(坑 1)仍未接(ssp仍不 wire),屬另一 follow-up evidence_ready_count/evidence_total_count恆 0:auditor_dashboard_query硬寫 0(v2 證據統計 follow-up);本頁我的稽核表不消費這兩欄,暫無害,但未來若有 UI 讀它是不完整值completion_trend恆 []:v2 無歷史快照表,刻意棄用;FE 改用project_completion,此欄僅 schema back-compat 保留(非 bug)id欄位是 uid 字串非數字:ProjectResponseSchema/MyJobResponseSchema的id是 Method 回uid,別誤當數字主鍵- 我的稽核無分頁:POST 帶
filters但回 flatitems全量;FE 只.slice(0,5)。稽核輪次爆量時整包傳輸 - 待辦數兩處來源可能分歧:待辦表抓
page_size:8顯示 5 筆;「檢視全部」條件用metrics.my_pending_task_count > 5(summary 的 distinct count)而非myPendingTasks.length——兩者不同查詢,理論上可能不一致 - 無 route 層權限:本頁無
pagePermissionmeta;缺能力是「區塊消失」而非整頁擋。這對落地頁合理(待辦任務對所有人有用),但與其他頁的 route-guard 模式不同 - 與專案總覽頁易混:本頁是全域跨專案落地頁;專案總覽頁 是單專案單輪。名稱都含「儀表板 / dashboard」但完全不同
13. 開發與驗證
- 跑起來:BE
python main_socketio.py(port 8000,log 在log/app.log);FE 在compliance-manager-fe/起 Vite dev server。BE 改 service code 後必須重啟 - 測試帳號:dev 環境
blsadmin(密碼見.env/ 部署文件) - 導航路徑:登入 →
側邊選單「專案儀表板」(
/project/dashboard) - 前置資料:需自己有份的專案 + 指派給自己的任務 /
稽核,各區塊才有資料;驗能力 gate 需有 / 無
project.read/audit.read兩種帳號 - E2E:
compliance-manager-test/repo;以儀表板/dashboard搜尋(注意與 AI 儀表板ai-dashboard區分) - 相關文件:單專案儀表板見 專案總覽頁、專案清單見 專案列表頁、我的任務見稽核執行群
project-my-tasks;FR-038
docs/features/FR-038-2606-oscal-redesign/