手冊首頁 / 專案與任務 / 專案建立

專案建立(Project Create)

功能群:專案管理|狀態機與共用概念先讀 功能群總覽

事實基準:2026-07-05 從 FE / BE code 掃出(FR-038 Wave 2B「選 published 資源庫 → clone 三件組」模型);API schema 逐條對照 marshmallow serializer 與 project_start_app_service.start_project;表結構取自 db_schema.json

1. 功能描述

專案建立頁是成立一個稽核專案的三步精靈。使用者選一個已發布的合規資源庫(module_frame 三件組)與稽核流程範本、填基本資料與參與人員,送出後 BE 於單一交易內把資源庫的 catalog / profile / SSP 各 clone 一份脫鉤公版,建立專案主檔、project_extensions(記 living_ssp_id 錨點)、參與人員,並以 best-effort 生成準備期收證據任務與第一輪稽核(round_type='initial')。成功後導向該專案的總覽頁(輪次變體)。

主要使用者:任一登入者(BE 僅要求登入,無角色守門);建立者自動成為專案 manager。

角色速覽(完整定義見 _overview §3):

角色 一句話
任一登入者 可建立專案(BE 無角色守門)
建立者 送出後自動成為該專案 manager(_add_participants fallback)

受評範圍不在此頁(C6, 2026-05-23 決策):audit_systems / devices 已從建立流程移除,改在建立後的 SSP 編輯頁維護;本頁 Step 2 有提示導引。

1.1 功能總覽(本頁全部功能)

# 功能 說明 位置 詳述
1 步驟指示器 三步:基本資訊 / 參與人員 / 確認送出,可回改 頁首下方 §5
2 專案名稱 / 描述 名稱必填(BE 檢查唯一);描述選填 Step 0 UC-PC-01
3 開始 / 結束日期 皆必填;結束須晚於開始(FE 驗證) Step 0 UC-PC-01
4 選合規資源庫 下拉選 published module_frame;選後自動帶入已連結帳號的人員 Step 0 UC-PC-01
5 選稽核流程範本 下拉選 flow_template(第一輪稽核流程)+預覽 dialog(BPMN) Step 0 UC-PC-01
6 參與人員挑選 搜尋加入使用者、設角色、移除;自動帶入者預設 viewer Step 1 UC-PC-01
7 確認摘要卡 基本資訊 / 參與人員兩張唯讀卡,各有「回改」鈕 Step 2 §5
8 受評範圍提示 提示建立後至 SSP 頁籤填系統安全計畫 Step 2 §12
9 建立專案送出 POST /oscal-project/start → clone + bootstrap(交易) Step 2 按鈕 UC-PC-01
10 導航分流 第一輪成功 → 總覽頁(round 變體);失敗 → 輪次清單頁 送出後 §10

UC(§2)只展開一條核心路徑 UC-PC-01(完整三步 + 送出 + BE bootstrap),因為本頁的價值幾乎全在這條建立鏈;其餘為表單互動細節。

2. Use Case

角色速覽(完整定義見 _overview §3):

角色 一句話
任一登入者 可建立專案(BE 無角色守門)
建立者 送出後自動成為該專案 manager(_add_participants fallback)

流程圖視覺慣例:菱形 = 判斷、橘底 = 例外 / 擋下、紅框 = 錯誤(標 error code)、綠框 = 成功終點、虛線 = 可選路徑。

UC-PC-01 建立稽核專案

項目 內容
角色 任一登入者
前置條件 已登入;系統有 ≥1 個 published 合規資源庫與 flow_template
產出 / 後置條件 clone 三件組 + compliance.projects / project_extensions / project_participants;best-effort 生成準備 job 與第一輪;導向總覽頁
uc_pc_01 start s0 Step 0:填名稱/日期 選合規資源庫+流程範本 (選資源庫→自動帶入人員) start->s0 v0 FE 驗證:必填齊全? 結束日期>開始日期? s0->v0 block0 標紅錯誤,停在 Step 0 v0->block0 s1 Step 1:調整參與人員與角色 v0->s1 s2 Step 2:確認兩張摘要卡 s1->s2 submit POST /oscal-project/start (resource_library_uid, name, dates, participants, flow_template_uid) s2->submit dup BE 檢查:名稱重複? 資源庫已發布? submit->dup be BE 交易:clone 三件組→建專案→ SSP 初始化→準備 job→第一輪 (見 §10 寫入時序) r 第一輪建立成功? (best-effort) be->r dup->be 皆過 err 409 GRC_409005(名稱重複) 412 GRC_412031(資源庫未發布) dup->err 命中 nav1 導向總覽頁(round 變體) project-auditor-overview-round r->nav1 nav2 導向輪次清單 project-ap-list (第一輪失敗的降級路徑) r->nav2
UC-PC-01 流程:三步填寫→FE 驗證→送出→BE 名稱/發布檢查→clone+bootstrap→依第一輪成敗分流導航

3. 權限矩陣

操作 FE 判定 BE 強制 BE 檢查位置
進入建立頁 route 無 requiresAdmin;由 project-list 的 CREATE 頁權限導入 src/config/router/index.js:761-765
送出建立 表單驗證通過 @jwt_required()無角色守門(任一登入者可建) api/project/routes/project_route.py::OscalProjectStartRoute.post
成為 manager 建立者若未在 participants 名單,自動補一筆 role='manager' app/project/service/project_start_app_service.py::_add_participants

⚠️ 無角色守門是刻意的現況:建立專案不限角色,靠 FE 的 CREATE 頁權限控制入口。若日後要收緊(例如限特定角色才能開專案),需在 route / app service 補檢查——不要假設 BE 已擋。

4. 狀態機與前置條件

本頁不涉輪次狀態機(輪次在建立之後才有)。建立當下的前置條件(BE 強制):

條件 效果 出處
專案名稱唯一(排除 archived) 重複 → ConflictError(GRC_409005) project_start_app_service.start_project(名稱檢查段)
資源庫已發布(module_frames.enable/published) 未發布 → PreconditionFailedError(GRC_412031) _resolve_source_triple:152-154
資源庫存在且有 catalog / SSP 缺 → NotFoundGRC_404021 / GRC_404037 / GRC_404012 _resolve_source_triple:152-167
建立成功 → 專案 status='pending' 尚未啟動稽核;第一輪為 initial(best-effort) start_project 回傳 + _create_first_round

5. UI 設計

版面骨架與步驟區塊(三步 wizard:基本資訊 → 參與人員 → 確認送出;彩色區塊可點跳本頁小節錨點,API 僅標代表性):

Header + 步驟指示器(圓點:已完成打勾/當前外框/未達灰底,可回改) ① 基本資訊 ——— ② 參與人員 ——— ③ 確認送出 跳至 §2 Use Case(UC-PC-01 建立稽核專案 — Step 0) Step 0 基本資訊 名稱(必填/唯一)/描述 起訖日期(結束>開始) 合規資源庫下拉 稽核流程範本下拉+預覽 GET /module-frame (filter published) GET /module-frame/{uid}/parties (選庫後自動帶入人員) → 點我跳 §2 UC-PC-01 跳至 §2 Use Case(UC-PC-01 — Step 1 參與人員) Step 1 參與人員 搜尋加入使用者、設角色 移除;自動帶入者預設 viewer GET /users/menu (挑選人員來源) → 點我跳 §2 UC-PC-01 跳至 §6 API 規格(POST /oscal-project/start 建立送出) Step 2 確認送出 基本資訊/參與人員兩張 唯讀摘要卡(各有「回改」) 受評範圍提示(建立後填 SSP) POST /oscal-project/start (clone 三件組 + bootstrap) → 點我跳 §6 API 規格 底部導航:上一步/下一步(Step 0~1)|建立專案(Step 2,帶 createLoading)→ 成敗分流導航 彩色=可點跳本頁小節錨點(框內標錨點+代表性 API)|灰=本頁描述 API 僅列代表性 2~3 條,完整規格見 §6;建立無角色守門(任一登入者可建,靠 FE CREATE 頁權限控入口)
專案建立頁版面 wireframe:Header+三步指示器、Step 0 基本資訊、Step 1 參與人員、Step 2 確認送出、底部導航(下一步 / 建立)

實機截圖(STG,亮色模式,2026-07-05,帳號 blsadmin;填完 Step 2 後中止未送出,STG 未產生測試專案):

Step 0 基本資訊:專案名稱/描述/起訖日期/合規資源庫下拉/稽核流程範本下拉

Step 1 參與人員:選定合規資源庫後自動帶入 3 位觀察者提示 + 可調整角色

Step 2 確認與送出:基本資訊 + 參與人員兩張摘要卡

狀態呈現:步驟圓點(已完成打勾 / 當前外框 / 未達灰底);選資源庫時 Step 1 顯示自動帶入 spinner 與「已帶入 N 位」訊息;流程範本預覽走 dialog;建立按鈕帶 createLoading。日期以 %Y-%m-%d 送出(FE formatDate)。

6. API 規格

Envelope:成功 {"status": true, "data": …}、失敗 {"error_code": "…", "msg": "…"}(HTTP 4xx/5xx)。

6.1 總清單(本頁呼叫的全部 endpoint)

分類 Method + Path 說明 完整規格
載入 GET /module-frame(filter published) 合規資源庫下拉來源 GAI-SD-02
載入 GET /users/menu 參與人員挑選來源 GAI-SD-02
載入 GET /module-frame/{uid}/parties 選資源庫後自動帶入已連結帳號人員 GAI-SD-02
載入 GET /flow-engine/...(flow template 清單 / 明細) 流程範本下拉 + 預覽 GAI-SD-02
送出 POST /oscal-project/start 建立專案(clone 三件組 + bootstrap) §6.2

6.2 核心 endpoint

[POST] /oscal-project/start

建立專案。Request(OscalProjectStartRequest):

欄位 型別 必填 說明
resource_library_uid string published 合規資源庫 UID(→ clone catalog / profile / SSP 三件組脫鉤公版)
name string 專案名稱(BE 檢查唯一,排除 archived)
description string|null 專案描述
start_date / end_date date(%Y-%m-%d)|null 專案期程(FE 驗證結束>開始)
owner_uid string|null 專案負責人 user uid;不傳預設建立者
participants array|null [{user_uid(必填), role(manager/reviewer/auditor/viewer,預設 viewer)}];建立者自動補 manager
flow_template_uid string|null 第一輪稽核流程範本 UID(= compliance.flow_templates.uid);不傳則回退資源庫的 audit_flow_template_uid

Response data

欄位 型別 說明
project_uid string 新專案 uid(導航用)
catalog_uid / profile_uid / ssp_uid string|null clone 出的三件組 uid(ssp_uid = living SSP)
control_count int 初始化的控制項數
job_count int 準備期 per-AO 收證據 job 數(best-effort,可能 0)
ap_created / ar_created bool false(AP / AR 延到輪次啟動 B3+,見 _overview §2
first_round_uid / first_round_created string|null / bool 第一輪 uid(best-effort,失敗為 null)
participants array 實際寫入的參與者 {user_uid, user_id, role}
created_user string 建立者 login_name

出處:serializer api/project/serializers/project.py:44-66;組裝與回傳 app/project/service/project_start_app_service.py::start_project(return dict);route api/project/routes/project_route.py::OscalProjectStartRoute

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/project/ProjectCreateView.vue 主檢視(三步精靈、驗證、送出、導航分流)
src/components/grc/ProjectBasicInfoForm.vue Step 0 基本資訊表單(名稱 / 描述 / 日期 + slot 放資源庫 / 流程範本下拉)
src/components/grc/ParticipantPicker.vue Step 1 參與人員挑選(搜尋 / 角色 / 移除)
src/views/flow-template/components/FlowTemplatePreviewDialog.vue 流程範本 BPMN 預覽 dialog
src/service/FlowTemplateService.js 流程範本清單 / 明細 API
src/stores/menuStore.js 資源庫(module_frame)/ 使用者下拉資料
src/config/router/index.js:761-765 route project-create/project/projects/new
src/config/api/api.js endpoint 常數(OSCAL_PROJECT_START 等)
src/config/locales/i18n/zh-tw/project-create.json 頁面 i18n(標籤 / 驗證訊息 / toast)

8. 後端檔案地圖(本頁核心鏈路)

鏈路 Route App Service 底層
建立專案 api/project/routes/project_route.py::OscalProjectStartRoute.post app/project/service/project_start_app_service.py::start_project@transaction;名稱檢查 → clone → 建檔 → 參與人員 → SSP 初始化 → best-effort 準備 job / 第一輪) OscalSnapshotService.clone_resource_library(三件組 clone)、project_service.create_projectproject_extension_domain_serviceproject_participant_domain_serviceaudit_round_app_service.create_round(第一輪)
Drive 初始化 同 route(交易外) drive_sync_orchestration_service.try_enqueue_init_project_folders best-effort 佇列,失敗只 log

DDD 提醒start_project 是唯一 @transaction 開啟點,內部 helper(_resolve_source_triple / _add_participants / _generate_prep_jobs / _create_first_round)都在同一 scope 內、不各自加 @transaction_create_first_round 呼叫的 create_round 是 nested @transaction 重用同一 session)。

9. DB

9.1 資料表總清單(本頁寫入的全部表)

讀/寫 說明 欄位詳述
compliance.module_frames clone 來源(published 資源庫) §9.3
compliance.projects 專案主檔(status=pending) §9.3
compliance.project_extensions module_frame_id / owner_id / living_ssp_id 錨點 §9.3
compliance.project_participants 參與者(建立者補 manager) §9.3
oscal.catalogs / catalog_controls / catalog_control_parts clone 控制母體三層 GAI-SD-03
oscal.profiles / profile_imports clone 基準線 + catalog 導航 GAI-SD-03
oscal.system_security_plans clone 出的 living SSP GAI-SD-03
oscal.ssp_implemented_requirements / ssp_statements 控制項 / AO 現況(空白初始化) GAI-SD-03
oscal.ssp_reference_documents (best-effort) 程序書池 + 對應 clone GAI-SD-03
compliance.workflow_templates / workflow_executions / job_executions (best-effort) 準備期 per-AO 收證據 job GAI-SD-03
compliance.project_audit_rounds (best-effort) 第一輪 round_type='initial' _overview §2

9.2 ER 圖(本頁寫入範圍)

pc_er proj compliance.projects 建立主檔 status=pending ext compliance.project_extensions module_frame_id / owner_id living_ssp_id 錨點 proj->ext 1:1 part compliance.project_participants 建立者+額外成員 role proj->part 1:N wf compliance.workflow_templates job_executions 準備期 per-AO 收證據 job (best-effort) proj->wf per-AO round compliance.project_audit_rounds 第一輪 round_type=initial (best-effort) proj->round 第一輪 ssp oscal.system_security_plans clone 三件組之一 = living SSP ext->ssp living_ssp_id prof oscal.profiles / profile_imports clone 基準線 ssp->prof import_profile_id ir oscal.ssp_implemented_requirements ssp_statements 控制項 / AO 現況(空白初始) ssp->ir 1:N cat oscal.catalogs / catalog_controls clone 控制母體 prof->cat source_catalog_id mf compliance.module_frames published 資源庫(clone 來源) mf->ssp clone 來源
專案建立寫入範圍:綠 = 交易內必成、黃 = clone 的 OSCAL 三件組、藍 = best-effort 尾段(準備 job / 第一輪)

9.3 核心表欄位(取自 DEV DB dump,含 DB comment)

compliance.projects — 專案主檔

欄位 型別 說明
uid uuid 內部唯一識別碼(回傳 project_uid 導航用)
name / description varchar(255) / text 標題 / 描述
status varchar(50)|null 建立後為 pending
start_date / end_date timestamp|null 專案期程
tenant_id / org_unit_id int|null 租戶 / 組織單位(RLS)

compliance.project_extensions — 專案延伸(1:1)

欄位 型別 說明
project_id int → compliance.projects.id(1:1)
module_frame_id int|null 啟動專案用的 module_frame 參考(clone 後即獨立,無 FK)
owner_id int|null 專案負責人(users.id);不傳預設建立者
living_ssp_id bigint|null clone 出的 SSP(soft ref)— 唯一錨點;profile 由 ssp.import_profile_id、catalog 由 profile_imports.source_catalog_id 導航

compliance.project_participants — 參與者

project_id / user_id / rolemanager / reviewer / auditor / viewer);建立者若未在名單自動補 manager_add_participants fallback,in-memory dedup)。

compliance.module_frames — 合規資源庫(clone 來源)

published 的 module_frame 是 clone 的來源;解析出其 catalog / profile / SSP / audit_flow_template_uid(flow_template 未指定時的回退值)。

10. 頁面邏輯與資料對應

BE 寫入時序(本頁最關鍵的邏輯):

pc_bootstrap cluster_atomic start_project(@transaction,任一步失敗全 rollback) cluster_best best-effort 尾段(try/except,失敗只 log,不 rollback 專案) start n1 ① 名稱唯一性檢查 (排除 archived) start->n1 n2 ② 解析資源庫來源 catalog/profile/ssp/template_uid n1->n2 n3 ③ clone 三件組(邊界②) catalog + profile + SSP → 脫鉤公版 n2->n3 n4 ④ 建 compliance.projects(status=pending) n3->n4 n5 ⑤ 建 project_extensions (module_frame_id/owner/living_ssp_id 錨點) n4->n5 n6 ⑥ 加 participants (建立者補 manager fallback) n5->n6 n7 ⑦ SSP 控制項初始化 (補 clone 沒帶到的控制空白 IR) n6->n7 b1 ⑦ᵃ clone 程序書池 + 對應 n7->b1 b2 ⑦ᵇ 生成準備期 per-AO 收證據 job (clone 專屬流程範本) b1->b2 b3 ⑦ᶜ 建第一輪(round_type=initial) 綁 flow_template_uid b2->b3 ret 回傳 {project_uid, ssp_uid, control_count, job_count, first_round_uid, participants…} b3->ret drive best-effort 佇列 INIT_PROJECT_FOLDERS (route 層,交易外) ret->drive
start_project 寫入時序:atomic 核心(名稱檢查→clone→建檔→SSP 初始化)+ best-effort 尾段(程序書 / 準備 job / 第一輪)+交易外 Drive 佇列

關鍵欄位對應(畫面 ↔︎ payload):

畫面元素 FE state API 欄位
合規資源庫下拉 step0.moduleFrameId(取所選 module_frame 的 uid) resource_library_uid
稽核流程範本下拉 step0.flowTemplateUid flow_template_uid
名稱 / 描述 step0.name / step0.description name / description
開始 / 結束日期 step0.startDate / endDateformatDateYYYY-MM-DD start_date / end_date
參與人員清單 selectedParticipants[{uid, role}] participants[{user_uid, role}]

送出後導航分流first_round_uid 有值 → router.push('project-auditor-overview-round', {id: project_uid, roundUid: first_round_uid});為 null(第一輪 best-effort 失敗)→ 降級到 project-ap-list

錯誤對應:BE error envelope → toast;常見碼 GRC_409005(名稱重複)、GRC_412031(資源庫未發布)、GRC_404021(資源庫不存在)。FE 端另有必填 / 日期順序驗證(Vuelidate)在送出前擋。

11. 背景行為與外部依賴

類型 內容
Drive 同步 建立成功後 route 層 best-effort 佇列 INIT_PROJECT_FOLDERS(tenant 未連 Drive 則靜默跳過;失敗只 log,不 rollback 專案),由 worker 非同步建 5 層資料夾
準備 job _generate_prep_jobs 為每 in-scope 控制的每個 AO part clone 專屬流程範本並建 job_execution(指派由 PM 之後手動),best-effort
BPMN 第一輪綁 flow_template_uid(未指定回退資源庫預設);輪次狀態後續由 BPMN 驅動
Socket 本頁 socket;建立為一次 request/response
jedi-* 套件 jedi-oscal-v2(clone 三件組 / SSP repo)、jedi-flow-engine(準備 job / 範本 clone)、jedi-project(專案 domain)、jedi-auth(JWT)
系統參數 無 feature flag;資源庫 / 流程範本清單由 published 狀態決定

12. 邊界情況與已知坑

  1. 交易邊界:atomic 核心 vs best-effort 尾段:名稱檢查 / clone 三件組 / 建專案 / extension / participants / SSP 初始化屬 @transaction 內,任一失敗全 rollback;但程序書 clone、準備 job、第一輪是 try/except 尾段,失敗只 log 不擋專案成立——所以會出現「專案建好但沒第一輪 / 沒準備 job」的合法狀態(FE 導航已針對第一輪缺席降級到輪次清單頁)
  2. 建立無角色守門:任一登入者都能打 oscal-project/start;限制只在 FE 的 CREATE 頁權限。安全評估勿假設 BE 已擋
  3. 受評範圍已移出建立流程(C6):audit_systems / devices 不在 payload;建立後必須到 SSP 編輯頁補系統特性 / 元件 / 盤點,否則控制母體雖有、受評標的空
  4. 自動帶入的人員是 viewer 不是 OSCAL role:選資源庫時從 module_frame parties 帶入「已連結帳號」的人員,一律給 viewer(SSP 角色 ≠ 專案角色);使用者可再調整
  5. owner_uid 預設建立者:不傳 owner_uid 時 owner = 建立者;且建立者一定被加為 manager participant(即使 owner 是別人)
  6. 名稱唯一性排除 archived:軟刪除(archived)的同名專案不算衝突,可重用名稱
  7. living SSP 是唯一錨點:不另存 catalog_id / profile_uid,全靠 living_ssp_id → import_profile_id → source_catalog_id 導航(避免 desync);改動這條鏈要整條一起看
  8. flow_template_uid 回退:不指定則用資源庫 audit_flow_template_uid;兩者皆無時第一輪可能無流程綁定(best-effort 失敗,降級導航)
  9. date-only 陷阱:日期以 %Y-%m-%d 傳輸,顯示時留意時區(見專案共用坑)

13. 開發與驗證

  • 跑起來:BE python main_socketio.py(port 8000,log 在 log/app.log);FE 在 compliance-manager-fe/ 起 Vite dev server。BE 改 service code 後必須重啟(無 hot reload)
  • 測試帳號:dev 環境 blsadmin(manual 測試用;密碼見 .env / 部署文件)
  • 導航路徑:專案列表 → 「建立專案」(/project/projects/new
  • 前置資料:系統需至少一個 published 合規資源庫(module_frame 三件組)與一個 flow_template;否則兩個下拉為空無法送出
  • E2Ecompliance-manager-test/ repo(Cucumber + Playwright);以 專案建立 / project-create 搜尋 feature 檔
  • 相關文件:建立後入口見 專案總覽頁、清單見 專案列表頁;FR-038 Wave 2B 設計 docs/features/FR-038-2606-oscal-redesign/prompt/oscal_project_start_flow.md(啟動寫入順序);DB / API 全量見 GAI-SD-02/03