母案:FR-049(來源側 goto 跳題,四段已完成 commit 未部署)。本案是 user 2026-07-18 手測後拍板的資料模型翻轉:跳題規則從「來源選項宣告目的地」改為「目標題目/題組自己宣告顯示條件」——業界主流(Qualtrics/SurveyMonkey)形態。 狀態:design 拍板(六決策見 §2),implementation plan 待寫。 前提:FR-049 未部署 STG、無生產資料用 goto_* 新鍵、E2E 未 commit——現在翻轉零遷移成本,晚一版成本翻倍。
user 手測 Designer 時三連問(「這兩個是不是擇一」「為什麼可複選」「BC 都要打幹嘛設跳轉」)暴露的不是文案問題,是模型錯位:
| 來源側瑕疵 | 說明 |
|---|---|
| 隱式副作用 | 題組 B 變條件題組,是「被別題的選項提到」的副作用,B 自己身上無跡可循 |
| 漏網坑 | 來源題新增選項忘設規則 → 答該選項者整章看不到,Designer 零警告(靜默漏答) |
| 零全局視圖 | 規則散在各題 dialog 深處,無法一眼看出誰是條件題組、被誰控制 |
| 心智模型錯位 | 「跳轉至題組(可複選)」——「混合跳去兩個地方」語意荒謬;真語意是「此答案適用哪些章節」 |
目標側一次解決:條件寫在目標身上(自描述)、條件不成立即不顯示(無覆蓋問題)、列表卡片可掛條件 badge(全局視圖免費)、「我何時出現」是使用者真正在想的問題。
需求形狀確認:user 拍板本產品問卷是「通用為主、例外分流」(多數章節人人答,少數依情況出現)——目標側模型直接命中,不需要「完全分支」的批次隱藏工具(列 backlog)。
| # | 決策 | 結論 |
|---|---|---|
| 1 | 跳題模型 | A 案:目標側顯示條件,來源側 goto UI 整個拿掉 |
| 2 | 子題語意 | 純排版附屬(編號/縮排/一起出現一起答);「答了才展開」= 對子題設顯示條件的機制在 BE/引擎層保留,但 v1 不給 UI 入口(決策 9 二修:僅 FE 隱藏) |
| 3 | 子題建立入口 | 母題卡片直接「+ 新增延伸題」,dialog 的「父題目」下拉拿掉 |
| 4 | 同組跳題操作殼 | |
| 5 | FR-049 已 commit 四段 | 不 revert,FR-049.1 以 delta 疊上(保留/重做清單見 §5) |
| 6 | E2E | 舊模型場景止損,FR-049.1 定案後重派 |
| 7 | 跳題精靈(段② 手測追加) | user 實際手測體感「要跑到目標題身上設定、還要回頭找來源題選項」摩擦過大——來源題編輯 dialog 加「依此題答案控制顯示」區:選目標(題目/題組,可多目標) + 圈答案 → 存檔時自動翻譯成目標側 display_condition 寫到各目標身上。資料模型不動(仍只有目標側 display_condition,精靈是純 UI 翻譯層);目標側「顯示條件」區與 badge 照舊保留,兩入口殊途同歸、互相同步顯示 |
| 8 | 來源題型擴充(段② 手測追加) | dropdown(下拉選擇)納入合法來源題型——語意同為單選。BE 驗證(SOURCE_NOT_RADIO 五擋之一)與 FE 來源題過濾同步放寬為 type ∈ {radio, dropdown};error code 文案改「來源題必須是單選類型(單選題/下拉選擇)」 |
| 9 | 子題跳題「僅 FE 隱藏」(段② 手測追加,2026-07-18 二修) | 延伸題(子題)的顯示條件 UI 前端不顯示——編輯子題的 dialog 隱藏「顯示條件」區與跳題精靈區、精靈目標下拉排除子題。BE 能力保留不加擋(display_condition 落子題仍合法、引擎照算)——日後要開放「答了才展開」只需把 FE 顯示打開,零 BE 改動。決策 2 的「對子題設條件=答了才展開」語意在 BE/引擎層仍成立,只是 v1 不給 UI 入口。子題不作 source 維持不變(既有排除) |
| 10 | 子題題號自動衍生(段② 手測追加) | 「+新增延伸題」建立時題號自動帶「母題號-序」:母 AC-1 → 子依序 AC-1-1、AC-1-2(取母題現有子題數+1);欄位仍可手改。刪中間子題不回填重排(避免題號漂移) |
| 11 | Badge 全文化 + 來源側反向提示(段② 填答手測追加) | (A) 目標側 badge 改完整條件語句「當 AC-2=『已全面實施』或『部分實施』時顯示」,答案多時截斷+tooltip 全文;(B) Designer 編輯來源題時,每個選項列尾端顯示反向提示「→ 顯示:AC-2-1、B 題組」/「(無影響)」(資料=精靈反向索引,純渲染) |
| 12 | 填答端選項提示(段② 填答手測追加) | 會展開追加題的選項尾端加輕量提示「+將增加 N 題」——只顯示題數不顯示內容(避免答題誘導偏誤,對齊 Qualtrics 受測端預設) |
| 13 | 雙入口統一語言(段② 填答手測追加,選項 a) | 維持目標側+來源側精靈雙入口,以視覺語言表明同一份資料:①兩區標題同詞根(目標側「顯示條件——此題何時顯示」/來源側「顯示條件——此題答案控制誰顯示」)②精靈區頂部說明「在此設定的規則會寫入各目標題的顯示條件,兩處是同一份設定」③配合決策 11 的全局視圖。不砍任一入口(使用者兩種心智模型並存) |
| 14 | 條件答案欄反面提示(snapshot 手測追加) | user 設條件後填答才發現「未圈中的答案作答=隱藏」——三處條件答案 MultiSelect(目標側/精靈/題組)下方加即時反面提示「未勾選的答案({names})作答時,本題/本題組將隱藏」,把「未命中=隱藏」的後果攤在設定當下。answers 空/未選來源/全圈不顯示 |
| 15 | 決策 12 修訂:題數提示改靜態計數(snapshot 手測追加) | what-if 動態 diff 在「未作答=顯示」語意下恆 0(受控題本來就顯示)——改靜態反向索引:N=引用「本題+本選項」的目標題數(page 目標計其下全部題目含子題),與顯示狀態無關、空白問卷即顯示 |
SurveyQuestion.options 之外,題目與題組本體各加一個 JSONB 鍵 display_condition:
// SurveyQuestion(題目)與 SurveyPage(題組)同形狀
"display_condition": {
"source_question_uid": "<單選題 uid>", // 條件來源(v1 範圍:單一來源、單選題)
"answers": ["<option key>", ...] // 來源題答這些值時本題/題組顯示
} | null // null / 缺省 = 無條件恆顯示
display_condition 存在 → 僅當來源題已作答且答案 ∈ answers 時顯示;來源題未作答時顯示(維持 FR-049「答了才略過」語意,保證空白問卷全可見)——注意這與「答案 ∈ answers」判斷相互獨立:未作答=顯示,已作答才比對集合。key || name(FE mapOptionFromApi 同款取值)。goto_question_uid/goto_page_uids 不讀不寫;FR-049 從未部署,無資料要遷移。jedi-survey 段① 寫的 goto 驗證邏輯同步退役。SurveyQuestion.options 同表另一 JSONB 欄?否——display_condition 是題目級屬性非選項級,落 SurveyQuestion 本體(實作時查 jedi-survey model 有無現成 JSONB 雜項欄可掛,無則 options 平級新增欄位——落點在 implementation plan 前提查證定案,含可翻譯欄位家族檢查:若落在 translatable_fields 內的欄位,必須複查 jedi-common 翻譯 bug 耦合,見 docs/issues/pending/2026-07-18-jedi-common-translation-exclude-never-works.md)。SurveyPage 本體同款。survey.question_answer_histories.flow_rules_snapshot(DEV 已套的欄位照用,不回滾)——內容從 goto 鍵集合改為「當下全部 display_condition 的快照」:
[{ "target_type": "question|page", "target_uid": "...",
"source_question_uid": "...", "answers": [...] }, ...]
checkpoint 落快照、revert 繼承目標快照、null 容忍——三個行為與 FR-049 裁決完全一致,只換抽取來源。
display_condition 的題目/題組顯示「條件顯示:依 <來源題編號>」badge——全局視圖。computeVisibility 純函數保留,輸入從「掃 options goto 鍵」改為「掃全部 display_condition」;渲染/進度/必填三消費點同源架構原封不動。已填後被隱藏的答案保留不刪(稽核軌跡)——全部沿 FR-049。
「不適用 vs 漏答」判定沿 FR-049 段④:讀快照重算,灰標「不適用(依 XX 作答略過)」/紅標必填。computeVisibilityFromSnapshot 換輸入形狀。
| 資產 | 處置 |
|---|---|
| 可見性引擎骨架(useSurveyVisibility.js 雙函數) | 保留,換輸入解析 |
| 快照機制(migration/model→serializer 全鏈/checkpoint/revert 繼承) | 保留,換抽取內容 |
| 三消費點同源架構(SurveyPreview 重構) | 保留 |
| 子題 pid 接線(mapper/useSurveyApi/BE) | 保留 |
| 檔案上傳 dropzone 等樣式修 | 保留(與模型無關) |
| jedi-survey 段① goto 驗證(_validate_flow_rules)+ 14 測試 | 重做:改驗 display_condition(單選來源/禁自指/目標存在/同問卷——邏輯同款換對象);goto 驗證與測試退役 |
| jedi-survey 段① 清理 hook | 改造:清理對象從「選項 goto 鍵」改為「引用該題的 display_condition」 |
| Designer 流程規則 UI(AddQuestionDialog 三行卡片) | 退役,換目標側「顯示條件」區 |
| survey-mapper goto 鍵映射 | 重做:改映 display_condition |
| E2E 舊模型場景 | 已止損;子題/既有回歸類經新設計比對後沿用,跳題類重寫 |