問卷功能群總覽(Survey V2 Overview)
本檔放「本功能群多個頁面共用的知識」:頁面地圖、問卷 v2 資料模型、作者端發布與消費端填答雙生命週期、快照機制、角色基調。
各頁面 spec 引用本檔,只寫自己頁面的差異——改共用邏輯時改這裡一份。
事實基準:2026-07-05 從 FE(
views/survey-v2/、config/router/index.js)/ BE(api/survey、api/task_survey)code 與db_schema.json(surveyschema)掃出。
1. 頁面地圖
問卷群分兩半:作者端(設計可重用問卷範本)與消費端(稽核任務執行者對問卷快照填答)。
| 頁面 | FE route | 用途一句話 | 端|spec |
|---|---|---|---|
| 問卷管理 | /survey/manage |
資料夾樹 + 問卷清單 CRUD、複製、發布、版本、匯入 | 作者|問卷管理 |
| 問卷設計器 | /survey/designer/:id |
單一問卷的頁面樹 + 題目編輯(題型 / 選項 / 權重) | 作者|問卷設計器 |
| 問卷預覽 | /survey/preview/:id |
作者唯讀預覽(不落資料);與填寫頁同一個 view | 作者|併入 問卷預覽 |
| 問卷填寫 | /survey/fill |
稽核任務執行者對問卷快照填答、送審 | 消費|問卷填寫 |
preview 與 fill 兩條 route
共用同一個 SurveyPreview.vue(作者預覽 vs
任務填答由 route / 參數分流,見 fill 頁 spec §10)。
上游 / 下游關係:問卷範本在此群設計、發布;被專案規劃頁的稽核任務(job_type=survey)綁定消費——綁定當下
BE 對問卷取快照,任務執行者填的是凍結快照而非 live
範本(見 §4)。
2. 核心資料模型(本群最重要)
全部表都在 survey schema(不是
compliance / oscal)。兩條線:
- 作者端(範本樹):
survey.survey_folders(資料夾,pid樹)→survey.surveys(問卷主檔)→survey.survey_pages(頁面,pid樹 +no+sort)→survey.survey_questions(題目,pid樹 +type+weights+options/tags/referencesjsonb)。另有survey.survey_discussions(問卷討論串)。四張主表各有_trans翻譯表(見 §6.3)。 - 消費端(任務填答):
survey.task_surveys(任務×問卷×設備的執行期追蹤,status填答狀態機、main_project_id/task_id、approval_required、job_evidence_idsoft-ref)→survey.question_answers(每題答案,answer/feedbackjsonb +score);填答異動快照進survey.question_answer_histories(+_details)供還原。
兩個 BE 模組對應兩端:作者端 =
api.survey(/survey、/survey-folder、/survey-page、/survey-question、/survey-discussion);消費端
=
api.task_survey(/task-survey*、/project-survey/*)。
3. 作者端發布生命週期(surveys.release)
- 草稿 →
已發布:
surveys.release(0草稿 /1已發布)+release_at+release_target(發布對象)。PUT /survey/{uid}/release發布、DELETE /survey/{uid}/release取消發布。 - 版本:
group_id群組同一問卷的多版本、version_no版本號;問卷管理「另存新版」=POST /survey(as_new_version=true+group_id),保留舊版、產生新版列。 - 範本旗標:
is_sample(1為系統範本,可被複製起手)。 - 軟刪除:
is_delete(1已刪,查詢預設is_delete=0)。
4. 快照機制(作者範本 → 消費快照,本群關鍵)
問卷被稽核任務綁定消費時不直接引用 live 範本,而是 clone 一份快照:
- 快照是
survey.surveys內的另一列,is_snapshot=1+source_survey_id指回原範本;快照連同其 pages / questions 一起複製,與原範本脫鉤——之後改範本不影響已綁定任務。 - 綁定發生在專案規劃頁:任務(GRC
job)
job_type=survey設定問卷後,job_service.update_job對問卷取 snapshot、job_execution_surveys記 job→snapshot 關聯,並把 survey × device 笛卡爾積 reconcile 進survey.task_surveys(多問卷 × 多設備 → 列數乘開)。 - 消費端填答頁只認
task_surveys/ 快照,看不到作者端資料夾樹。
(任務綁定的完整欄位語意、full-replace 陷阱見 project-task-edit.md §6.2 / §12。)
5. 角色基調
角色是誰:
問卷作者(capability 控管,非專案角色)——設計問卷頁面與題目、發布版本,供稽核專案挑選使用。「身為問卷作者,我要設計一份問卷範本、加好題目與選項,發布後讓專案可以在任務裡指派。」
任務執行者(受稽方)——對指派給自己的問卷快照作答。「身為受稽方,我要完成被指派的問卷、填完後送出等待審核。」
審核人(
task_assignees.is_approver)——審核送出的問卷答案。「身為審核人,我要檢查受稽方填的問卷答案是否需要退回修改。」作者端(管理 / 設計 / 預覽):問卷範本作者,以選單能力(capability)/ RBAC 控管(
ui_routes+ RBAC 三層,見docs/claude/權限系統 SOP),非專案層 manager/auditor 角色。routemeta.requiresAuth(config/router/index.js:710)——目前beforeEach僅硬性擋requiresAdmin,requiresAuth的 token gate 待 auth/session 重構接上(見各頁 §3)。消費端(填寫):稽核任務執行者(受稽方),對指派給自己的
task_surveys填答;審核由任務指派時標記的審核人(task_assignees.is_approver)處理(approval_required決定是否需送審)。各頁實際 endpoint 守門以該頁 §3 為準。
6. 本群共用的已知坑
- 表都在
surveyschema:survey.surveys/survey_pages/survey_questions/task_surveys/question_answers等——別寫成compliance.*或public.*。 - 作者端 survey ≠ 消費端 task_survey:兩個 BE
模組、兩套 route、兩種角色;
survey.surveys同一張表同時放範本列(is_snapshot=0)與快照列(is_snapshot=1),靠is_snapshot/source_survey_id區分。 - 可翻譯欄位:
surveys(name/description/release_target)、survey_pages(name/description)、survey_questions(question/description/tags/references/options)、survey_folders(name/description)各有_trans表;寫入含翻譯欄位要傳locale,否則只更新主表(見docs/claude/translatable-fields.md)。 - 快照脫鉤:改已發布範本不回溯已綁定任務的快照;要讓既有任務吃到新版得重綁。
- 樹狀結構:資料夾 / 頁面 / 題目都用
pid自參照成樹;刪父層多為ON DELETE CASCADE(見各表 FK)。 - 已發布仍可被填答的是快照:作者端
release只影響「可否被規劃頁選用」;填答走的是綁定當下的快照狀態,與範本後續發布狀態無關。