# FR-049 問卷流程規則（跳題）補回 + 子題 Designer 接線 — Phase 0/1 設計

> **建立**：2026-07-18（site-regression D-3 查證後開案）
> **狀態**：設計拍板（A 案），待 spec review → implementation plan
> **背景查證**：D-3 調查定案（2026-07-18）——子題 pid BE 完整實作有真實資料；flowRules v2 零持久化；v1 曾有 goto 跳題機制上線（options JSONB `goto_question`/`goto_page_1`/`goto_page_2`，2025-05~09 真實資料）。v2 重寫斷鏈非「從未做過」。

## 1. 白話需求（Phase 0）

問卷設計者要能設定「依答案決定後續要答什麼」：

1. **同題組內跳題**：A-1 答選項 2 → 直接跳到第 5 題（中間題目不用答）。
2. **跳到其他題組**：A-1「系統部署環境？」答 1 地端 → 答 B 題組（地端規格）；答 2 雲端 → 答 C 題組；**答 3 混合 → B、C 都要答**（一個選項可指多個題組）。
3. 只有**單選題**可設定流程規則（與 v1 規格一致）。
4. 受稽方填答時，被略過的題目不需作答、不算進度；稽核方檢視時能分辨「不適用（依作答略過）」與「漏答」。
5. **順手收 D-3a**：Designer 建子題存不進去（parentId 沒送出、清單不顯示子題）——BE 現成，補兩處 FE 接線。

現況問題：v2 Designer 有 flowRules 編輯 UI 殼，但設定存檔即蒸發（BE 零持久化、填答端零引擎）——使用者以為設好了，實際問卷完全不跳，比沒有功能更傷信任。

## 2. 方案取捨（Phase 1 已拍板）

| 案 | 內容 | 判定 |
|----|------|------|
| **A（採用）** | 復刻 v1 跳題語意、v2 資料形狀重做；填答端用「可見性計算」實作 | ✅ 符合原規格與使用者心智模型；v1 雙 page 槽位一般化為陣列後混合情境原生支援 |
| B 純條件顯示（Qualtrics 式） | 條件掛在題/題組上 | ❌ 偏離原規格與現有 UI 殼，設計者要換心智模型 |
| C 只做題組級跳轉 | 同組內跳題後期補 | ❌ 「A-1 跳第 5 題」是真實需求，切掉半套 |

**關鍵設計決策：跳題語意、可見性實作。** 對外語意是「跳題」（設計者設「答 X 跳第 N 題」），內部引擎是**純函數**：`可見集合 = f(全部規則, 全部當前答案)`，答案任何變動即全量重算。語意細則（已定案）：
- **初始/未作答**：規則來源題未作答時，其規則不生效 → **預設全可見**（含被規則指到的題組）。跳題語意是「答了才略過」，不是「答了才出現」——與 v1 行為一致，也保證無規則問卷 = 全可見零變化。
- **同題組內跳**：「Q1 答 2 跳 Q5」＝ Q2-Q4 不可見；**Q5 之後照常**（跳題只略過起訖之間，不影響其後）。
- **goto_page**：選項設了 goto_page_uids 時，該題組集合以外、同層級的其他「被任一規則提及的題組」不可見；未被任何規則提及的題組不受影響（照常顯示）。
- **重新進入部分作答的問卷**：載入後以既有答案跑一次同一個純函數還原可見狀態（無需額外持久化「跳題進度」）。
- **已填而後被隱藏的答案**：保留資料不刪除（稽核軌跡）；「不適用」是**運算結果非持久化 flag**——檢視端用「提交當下快照的規則+答案」重算（規則隨問卷版本走，v2 問卷發布後結構鎖定不可改，無「事後改規則」的漂移問題；此前提 implementation plan 時驗證，若發布後仍可改結構則改為提交時落 snapshot flag）。
- **必填檢核只作用於可見題**（與進度計算同源）：現行填答端的 `totalRequired`（進度分母）與提交檢核（`isRequired && !isAnswered` 擋 submit/close）都是全量掃描——FR-049 後兩者一律改以**可見集合**為母集：被規則略過的必填題不擋提交、不算分母。同一個可見性純函數餵三個消費點（渲染/進度/必填檢核），禁止各算各的（否則會出現「畫面上看不到的必填題擋住提交」的死結）。

## 3. 資料模型（已定案）

**沿 v1 內嵌模式：規則直接掛在 options JSONB 的每個選項物件上**，換新鍵名。v1 真實資料形狀（DEV 實查）是 `{key, name, content, goto_page_1: {uid,name}, goto_page_2: {uid,name}}`——選項本身無 uid，內嵌設計天然迴避「option 識別」問題（獨立欄位需 option index/uid 對應，index 重排即壞）。

```
options JSONB 每個選項物件（v2 新鍵，僅單選題）:
{
  "name": "雲端",
  ...既有鍵...,
  "goto_question_uid": "<同題組內目標題 uid>" | 缺省,
  "goto_page_uids": ["<題組 uid>", ...] | 缺省      # v1 goto_page_1/2 一般化為陣列
}
```

- **無 schema migration**：options 本就是 JSONB，新鍵向後相容；既有問卷無新鍵＝無規則。
- **v1 遺留鍵（goto_question/goto_page_1/goto_page_2）不讀不寫不遷移**——v1 問卷已退役，資料留檔即可；v2 引擎只認新鍵。
- 屬套件 domain 資料 → 改 jedi-survey 套件本體（CLAUDE.md 套件異動規範，dev 走 path dependency）。serializer 對 options 內新鍵做白名單驗證（目標存在性、禁止自指、僅單選題允許）。

## 4. 四段鏈範圍

| 段 | 內容 |
|----|------|
| ① BE（jedi-survey） | flow_rules 持久化 + serializer + 驗證（單選限定、目標存在性、禁止自指）；v1 goto 遺留資料**不遷移**（v1 問卷已退役，資料留檔即可） |
| ② Designer | 既有 flowRules UI 殼接 BE（存讀）；目標選擇補「題組（多選）」；子題接線（D-3a：AddQuestionDialog parentId→parentDbId 送出、清單 render subQuestions） |
| ③ 填答端 | 可見性計算引擎（監聽單選答案 → 重算可見題/題組集合）；進度計算只算可見題；被隱藏題答案保留標不適用 |
| ④ 稽核檢視端 | 略過題呈現「不適用（依 X-N 作答略過）」，與漏答視覺區分 |

## 5. 邊界與風險

- **規則循環**：A 跳 B、B 的答案又影響 A 所在題組——BE 驗證擋自指；跨題組循環由「可見性計算是純函數（從全部答案一次算出可見集合）」天然免疫遞迴爆炸，但設計 Designer 時提示使用者避免矛盾規則。
- **多選/其他題型**：不允許設規則（BE 擋 + UI 只在單選題顯示設定區）。
- **匯入路徑**：Excel 匯入問卷（import_survey）本期**不支援** flow_rules 欄位（範圍控制），匯入的問卷無規則、可後續在 Designer 補設。
- **既有 495+ 份 v2 問卷**：無 flow_rules → 行為完全不變（可見性引擎對無規則問卷=全可見）。
- **task-survey（任務問卷）路徑：已盤點確認共用**——FE router 實查：`/survey/preview/:id`（預覽）與 `/survey/fill`（任務抽屜開的填答頁）**都掛同一個 `SurveyPreview.vue`**。可見性引擎做在 SurveyPreview（或其 composable）一處即三入口（預覽/獨立填答/任務填答）全生效，無第二處要改。

## 6. 驗收標準

1. 部署環境三情境可完整跑通：「A-1 系統部署環境？」單選【地端/雲端/混合】，規則設 地端→goto_page_uids=[B 題組]、雲端→[C 題組]、混合→[B,C 兩題組]。填答驗證：答地端只出 B、答雲端只出 C、答混合 B+C 都出。（此即 v1 goto_page_1/2 雙槽位的一般化情境，DEV 遺留資料有同款真實案例可對照）
2. 同題組內「答 2 跳第 5 題」可跑通，Q2-4 不算進度。
3. 回頭改 A-1 答案，可見集合即時重算，已填答案保留。
4. Designer 建子題後重整不消失（D-3a）。
5. 無規則的既有問卷行為零變化（site-regression survey 三頁回歸全綠）。
6. 稽核檢視能區分「不適用」與「漏答」。

## 7. 測試

- jedi-survey pytest：持久化/驗證/serializer
- E2E（test repo `site-regression/features/modules/survey/`，另派）：Designer 設規則→填答跳題→混合情境→改答案重算；survey-v2 既有 47 條（`survey-v2-manage/designer/fill.feature`）回歸不紅
- 移除 site-regression `survey-v2-designer.feature` 子題 @known-bug（D-3a 修復後）；flowRules 新 scenario 補進 `survey-v2-designer` + `survey-v2-fill` 兩 feature
