---
title: "週期任務與條件通知 — 討論稿 (FR-137)"
brand: "Guidant AI · **FR-137** 週期任務與條件通知"
eyebrow: "FR-137 · 討論稿 · 2026-10-12"
h1: "任務到期自己生下一期、掃描自己跑、掃到新的高風險多通知一個人"
subtitle: "13 題已裁（第 5 題作廢），展開成資料模型、端到端流程與五張卡；附三頁假資料雛形"
lede: "這份把首腦與決策者已裁的 12 項決策展開成可以開工的規格：週期設在任務上、到期生一筆新任務、掃描類任務到期自動派掃、SBOM 掃完與上一次比對，新出現 high 以上的弱點時寄信給指定的人並留紀錄。每一項都附現況座標（程式碼行號或 DEV 查詢，細節在 [探脈盤點](explore-findings.md)）。請先開 [雛形索引](prototype/index.html) 點三頁，再回來看規格。"
chips: [
  {text: "17 項已裁、第 5 題作廢", kind: ok},
  {text: "五張卡，畫面先出", kind: accent},
  {text: "門檻通知第一版只做 SBOM", kind: warn},
  {text: "D14～D18 補裁完成", kind: ok}
]
footer: "FR-137 · 討論稿 · 2026-10-12 · Notion CM-2717（母卡 CM-2714）· 輸入：[探脈盤點](explore-findings.md)（CM-2715）、FR-135 [phase3-deferred-to-recurring-tasks-fr](../FR-135-2610-cra-compliance-framework/phase3-deferred-to-recurring-tasks-fr.md)、雛形 [index](prototype/index.html) · 現況依據：程式碼行號與 DEV DB 唯讀查詢（2026-10-12）"
---

> 設計定案見 [design.md](design.md)。

**狀態**：討論稿（決策已裁，等決策者看雛形拍板）　｜　**日期**：2026-10-12　｜　**卡片**：Notion CM-2717（母卡 CM-2714）　｜　**雛形**：[prototype/index.html](prototype/index.html)

路徑慣例同探脈檔：BE 路徑相對 `compliance-manager-be/`；`pkg/` 代表 `~/Projects/Jedicogy/module/jedi-python-package/`；FE 路徑相對 `compliance-manager-fe/`。

## 變更紀錄 {#changelog nav="變更紀錄"}

| 日期 | 變更 | 對應 |
|---|---|---|
| 2026-10-12 | v1：已裁 D1～D13 展開、補裁 D14～D18；資料模型草案、端到端流程、五卡拆卡草案、三頁雛形；畫面放法（週期用 Dialog、通知紀錄放專案內） | CM-2717 |

---

## 分工概述（30 秒版） {#overview nav="概述"}

整案一句話：**專案管理者在規劃頁替任務設週期；到期時系統生一筆新任務（第 N 期）並通知執行人，掃描類任務直接自動開掃；SBOM 掃完若比上一次多出 high 以上的弱點，就寄信給額外指定的人（例如 CRA 的通報聯絡人），每封都留紀錄可查。**

給非工程讀者的背景：稽核裡很多工作不是做一次就好——每月掃一次源碼弱點、每季填一次問卷、每年檢視一次程序書。現在系統的任務做完就結束，下一期要人記得重建。本案讓任務自己「到期長出下一期」；掃描類更進一步不用人按；而 CRA 要求製造商知悉高風險漏洞要及時處理，所以掃到「新出現」的高風險時多通知一個負責對外通報的人。

| 卡 | 做什麼 | 產出 | 決策者檢查法 |
|---|---|---|---|
| **① 週期設定畫面** | 規劃頁任務表單多一行週期摘要＋「設定」開週期 Dialog；任務頁籤有週期的加 ↻；頻率選項進 `system_menus` | migration（任務新欄、頻率 seed）、BE 讀寫、FE 週期 Dialog 子元件、FE 四處寫死頻率改讀 menu | 對照 [雛形頁 1](prototype/period-settings.html)：Dialog 設好存檔、重開還在，表單其餘欄位不變 |
| **② 到期生新任務＋通知執行人** | 每小時排程查到期任務，生第 N+1 期（複製指派、部門、設備、檢測綁定、問卷空白快照），寄信給執行人 | 排程 job、單筆任務複製 service、任務抽屜標題期數＋檢測設定卡三行 | 對照 [雛形頁 2](prototype/task-drawer.html)：把下次到期改成過去時間，一小時內看到第 N+1 期且收到信 |
| **③ 掃描自動執行** | 自動執行開著的掃描類任務，新一期生出來直接開掃（檢測工具派 agent、SBOM 沿用上次源碼包） | 新任務轉執行中並觸發既有派掃掛鉤 | 抽屜執行紀錄出現「第 N 期 自動執行」那筆 |
| **④ 門檻通知＋紀錄** | SBOM 掃完與上一次比，新出現 high 以上就寄給額外通知對象，每封記一筆 | 通知紀錄表、掃完匯合點加判斷、專案內「通知紀錄」頁（入口在專案概覽頁頂端） | 對照 [雛形頁 3](prototype/notify-log.html)：同一份源碼包重掃不寄、換一包多了新 high 會寄 |
| **⑤ 支援期提醒接入** | 資訊系統版本支援期到期前 90／30／7 天提醒，走同一支排程與紀錄表 | 排程內加一段、紀錄表加一種對象 | 建一筆 30 天後到期的版本，隔天收到一封、不會重複 |

依賴：①→②→③ 依序；④ 只依賴 ①（額外通知對象欄位），可與 ②③ 平行；⑤ 依賴 ② 的排程與 ④ 的紀錄表。

```{.mermaid cap="圖 1 — 五張卡的依賴（實線＝必須先做）"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
    C1[① 週期設定畫面] --> C2[② 到期生新任務<br/>＋通知執行人]
    C2 --> C3[③ 掃描自動執行]
    C1 --> C4[④ 門檻通知＋紀錄]
    C2 --> C5[⑤ 支援期提醒]
    C4 --> C5
```

---

## 現況盤點：接入點 × 現況 × 本案動作 {#inventory nav="盤點"}

細節與完整行號在 [探脈盤點](explore-findings.md) 各節，這裡只列本案會碰的接入點。

### ① 任務本體

| 接入點 | 現況 | 本案動作 |
|---|---|---|
| 任務週期欄位 | `job_executions` 沒有到期日、週期、下次執行（`pkg/jedi-flow-engine/.../job_execution.py:15-41`） | 加欄（見資料模型） |
| 任務屬於哪一輪 | 在 `workflow_execution_control_mapping.round_id`（`prep_job_generation_service.py:257-260`） | 新一期掛同一輪（D2） |
| 複製單筆任務 | 沒有；覆核輪是整輪重生＋逐對承襲（`reverify_inheritance_service.py:34`、`reverify_clone_query.py:69-143`） | 新寫單筆複製，承襲子方法的寫法當參考，不綁母輪語意 |
| 建 job | `create_job`（`flow_control_job_repo_impl.py:639`） | 複製時沿用 |

### ② 型別申報

| 接入點 | 現況 | 本案動作 |
|---|---|---|
| `on_tasks_activated` 掛鉤 | 唯一有呼叫的掛鉤（`task_execution_service.py:94`） | ③ 沿用：新一期轉執行中後觸發它 |
| 完成／到期掛鉤 | 沒有 | 不加（D4，BE 排程直查） |
| `system_menus` `TASK_TYPE` | 五個 key 與申報三型別對不上 | 只記錄、本案不處理（D12） |

### ③ 排程

| 接入點 | 現況 | 本案動作 |
|---|---|---|
| APScheduler（api 模式） | 12 支 job、寫法統一（`core/scheduler.py`） | 加一支每小時「到期掃描」 |
| 多副本防重 | 無分散式鎖，靠冪等 | 唯一鍵擋（D11） |
| `background_jobs` | 入列需租戶身分；排程裡包 `tenant_context`（`core/plugins/_source_scan_vulndb_fetch.py:127-143` 先例） | SBOM 自動掃沿用既有入列 |
| 營運時區 | `BUSINESS_TZ` 寫死 Asia/Taipei（`common/util/common_util.py:36`） | 沿用（D10） |

### ④ 通知

| 接入點 | 現況 | 本案動作 |
|---|---|---|
| `send_mail_notification` | 背景可用、不需登入者；SMTP 未啟用回 False（`notification_service.py:75-84`） | 沿用；回 False 記成「寄送失敗」 |
| 新任務通知信 | `notify_user_todo_job` 寄指派人（`workflow_execution_service.py:1240-1300`） | ② 沿用 |
| 寄信紀錄表 | BE 與 jedi-notification 都沒有 | 新建，放 BE（D9） |
| 信件語系 | 排程裡固定 zh_Hant_TW | 沿用（D10） |

### ⑤ 掃描觸發

| 接入點 | 現況 | 本案動作 |
|---|---|---|
| 首次派掃 | `_auto_dispatch_first_scans` 只派「沒有執行紀錄」的任務（`app/detection_tools/task_type_declaration.py:43,79`） | 新一期天生沒有執行紀錄，觸發掛鉤即會派——不用改它 |
| 檢測工具排未來時間 | `agent_tasks.scheduled_at` 拉單過濾（`agent_task_repo_impl.py:18-33`） | 沿用（D6） |
| SBOM 源碼來源 | 不帶新檔即沿用綁定上次那份（`pkg/jedi-detection/.../server_side_dispatch.py:118-137`），背景以 `input_file_id` 重掃（`source_scan_job_steps.py:102`） | 新一期複製綁定時連 `tool_params` 一起帶，沿用即成立 |
| 掃完匯合點 | `_close_group_if_terminal`（`detection_orchestration_service.py:1626-1675`），不看嚴重度、無可外掛事件 | ④ 門檻判斷改由 jedi-source-scan SBOM 完成回呼觸發（D14） |
| 與上一次比對 | SBOM 完成時已算 `summary.delta`，配對鍵 `fingerprint`（`pkg/jedi-source-scan/.../source_scan_diff_service.py:71-83`、`source_scan_job_steps.py:113,123-130`） | ④ 沿用 `diff()` 取「新出現」再濾等級 |
| SBOM 嚴重度 | `source_scan_findings.severity` 六級大寫 | 門檻＝CRITICAL、HIGH |

### ⑥ 資源庫 frequency

| 接入點 | 現況 | 本案動作 |
|---|---|---|
| `module_frames.frequency` | 未刪除列皆小寫標準值＋`none`，無人讀 | 建專案時帶入任務預設（D3） |
| 頻率選項 | FE 四處寫死、`system_menus` 無 group | 進 `system_menus`，四處改讀（D12） |
| `last_execute_date`／`next_execute_date` | 全 NULL、無寫入者 | 棄用不啟用（D12） |

### ⑦ 問卷任務

| 接入點 | 現況 | 本案動作 |
|---|---|---|
| 問卷快照 | 規劃頁路徑深度複製（`survey_snapshot_domain_service.py:36-71`） | 新一期建全新空白快照（D13） |
| 填完自動完成任務 | 沒有 | 本案不處理（D13） |

---

## 資料模型草案 {#model nav="資料模型"}

### `compliance.job_executions` 新欄

| 欄 | 型別 | 用途 |
|---|---|---|
| `recur_unit` | varchar(32) 可空 | 週期單位，值＝頻率 menu 的 key（daily／weekly／monthly／quarterly／semi_annually／annually）；空＝不重複 |
| `recur_interval` | int 預設 1 | 每幾個單位一次（每 2 個月＝monthly＋2） |
| `next_due_at` | timestamptz 可空 | 下一期該生出來的時間；排程只看這欄 |
| `period_no` | int 預設 1 | 第幾期 |
| `source_job_id` | bigint 可空 | 從哪一筆生出來（第 1 期為空） |
| `auto_execute` | boolean 預設 false | 新一期生出來是否直接開掃；只有掃描類可設 |
| `alert_recipients` | jsonb 可空 | 掃到新出現 high 以上時額外通知誰：`[{type: "participant", user_id}]` 或 `[{type: "party_role", role_id: "vulnerability-contact"}]`；只有掃描類可設 |

唯一鍵 `UNIQUE (source_job_id, period_no)`：同一筆源任務的第 N 期只會有一筆（D11）。

`next_due_at` 只寫在「目前最新一期」上：生出第 N+1 期時，把週期設定整組搬到新任務、舊任務的 `next_due_at` 清空。這樣排程永遠只撈到每條週期鏈的最後一筆，不會同一期生兩次。

### 新表 `compliance.task_alert_notifications`（通知紀錄）

| 欄 | 用途 |
|---|---|
| `id`／`uid`／`tenant_id`／`org_unit_id` | 標準欄；RLS 依租戶 |
| `job_execution_id` | 哪一筆任務（第幾期） |
| `scan_uid` | 哪一次掃描（`source_scans.uid`） |
| `vs_scan_uid` | 跟哪一次比（首掃為空） |
| `new_critical_count`／`new_high_count` | 新出現的 critical、high 筆數 |
| `recipient_email` | 收件信箱（一人一列） |
| `recipient_label` | 顯示用：參與者暱稱或 Party 名稱 |
| `sent_at` | 寄出時間 |
| `result` | `sent`／`failed`（SMTP 未啟用或寄送失敗） |

唯一鍵 `UNIQUE (scan_uid, recipient_email)`：同一次掃描同一人只寄一封（D11）。排程先 INSERT 搶到列才寄，搶不到跳過——FR-135 支援期提醒草案的同一招。

### `public.system_menus` 頻率 seed

主線 `phase=seed` migration，`ON CONFLICT DO NOTHING`，先例 `scripts/sql/2026-05-22-seed-oscal-ssp-roles.sql`。group 名 `task_frequency`（D18），六個 key：`daily`／`weekly`／`monthly`／`quarterly`／`semi_annually`／`annually`，i18n 標籤走 `lang.task_frequency.<key>`。資源庫的 `none` 不進 menu：任務上「不重複」用週期開關表示，資源庫 `none` 帶入時就是開關關閉。

FE 四處寫死改讀 menu：`src/stores/menuStore.js:168-174`、`src/components/grc/ModuleFrameBasicInfoPanel.vue:171-176`、`src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue:1133-1138`、`src/components/grc/ssp-excel-import/SheetPreviewBasic.vue:53-58`。

---

## 端到端流程 {#flow nav="流程"}

```{.mermaid cap="圖 2 — 從設週期到門檻通知（虛線＝本案新增）"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart TD
    MF[資源庫 frequency] -.建專案時帶預設.-> P[規劃頁任務週期設定<br/>頻率・間隔・下次到期・自動執行・額外通知]
    P --> S[開始執行任務]
    S --> T{{每小時 tick<br/>撈 next_due_at 已到的任務}}
    T -.-> N[生第 N+1 期新任務<br/>同一輪・複製指派與綁定・問卷空白快照]
    N --> K{掃描類且<br/>自動執行開著？}
    K -- 否 --> M[寄信通知執行人]
    K -- 是 --> A[轉執行中＋觸發既有派掃掛鉤]
    A --> D1[檢測工具：派 agent]
    A --> D2[SBOM：沿用上次源碼包排背景掃]
    D1 --> C[掃完匯合<br/>_close_group_if_terminal]
    D2 --> C
    C -.SBOM.-> F{與上一次比<br/>有新出現 high 以上？}
    F -- 否 --> X[不寄・不記]
    F -- 是 --> R[寄給額外通知對象<br/>＋寫通知紀錄]
```

排程每小時跑一次的步驟：

1. 撈 `next_due_at <= now()` 的任務（跨租戶，`system_context`＋每租戶 `tenant_context`）。
2. 每筆以 `INSERT ... (source_job_id, period_no)` 建新任務，唯一鍵撞到就跳過（另一個副本已建）。
3. 新任務繼承週期設定並算下一個 `next_due_at`；舊任務的 `next_due_at` 清空。
4. 非自動執行 → 沿用 `notify_user_todo_job` 寄執行人；自動執行 → 轉執行中並呼叫 `_run_activation_hooks`，由既有 `_auto_dispatch_first_scans` 派掃。

---

## 畫面放法 {#ui nav="畫面"}

現行規劃頁「控制項實作」頁籤：左邊三層樹（群組 → 控制項 → 檢查項目）；選到檢查項目時，右邊由上往下是檢查項目標頭、參考條文、證據來源、檢查項目現況說明、任務區塊（`ProjectPlanningView.vue`）。任務區塊在 2 筆以上時，上面是頁籤列、下面是單一表單（`AoTaskSection.vue`），表單欄位依序為名稱、描述、指南、任務類型、指派人員、部門、設備、問卷、檢測工具＋Agent 分派、完成模式、刪除／儲存（`AoTaskForm.vue`）。檢測工具任務展開 Agent 分派後，表單已超過一個螢幕。

::: {.callout .decided}
**週期設定用「表單一行摘要＋Dialog」，不攤進表單（提案，等決策者看雛形確認）**

- 表單在「任務類型」下方多一行：`↻ 每月 · 第 2 期 · 下次到期 2026-11-01 · 自動執行 · 高風險額外通知 2 人　[設定]`；沒設週期時顯示「不重複　[＋ 設定週期]」。
- Dialog 內：重複開關、頻率、間隔、下次到期；檢測工具多「自動執行」與「額外通知對象」；下方唯讀列出各期。
- 任務頁籤列上，有週期的任務加一個 ↻ 小標。

**理由**：週期設定一次很少改，各期列表是執行資訊、不是規劃欄位；攤進表單會讓已經很長的表單再長一截，各期列表還會被擠到最底下。Dialog 跟頁首「快速配置」的做法一致。檢查項目內容與任務表單其餘欄位都不動。

**被排除**：表單內整塊展開（太長）；另開一欄任務清單（現行沒有這一欄，要重排整頁）。
:::

通知紀錄放在專案裡：專案概覽頁頂端那排按鈕（開始執行任務、專案規劃、稽核計畫等，`ProjectAuditorOverview.vue` 頁首）多一顆「通知紀錄」，點進去是專案內頁、只列本專案；頁首規格同規劃頁，有返回鍵。

---

## 已裁決策 {#decisions nav="已裁"}

::: {.callout .decided}
**✅ D1 — 重開語意：每期生一筆新任務**

**定案**：週期到了生一筆新任務，每期一筆、歷史各自獨立；不在同一筆退回重做。

**理由**：每期的證據、執行紀錄、問卷答案要分開查；退回路徑會把歷次結果疊在同一列。
:::

::: {.callout .decided}
**✅ D2 — 新任務屬同一輪**

**定案**：新任務掛在源任務的同一輪；任務多「期數」與「源自哪筆」兩欄，不另立「週期輪」概念。

**理由**：輪次是稽核範圍的單位，週期是任務層的節奏；混在一起會跟覆核輪的母輪關係打架。
:::

::: {.callout .decided}
**✅ D3 — 週期設定存在任務層**

**定案**：任務層新欄位（週期單位、間隔、下次到期、自動執行開關）；資源庫 `module_frames.frequency` 只在建專案時帶入預設，不影響既有專案。

**理由**：一個評估目標底下會有多筆任務、各自頻率不同；`config_schema` 只到租戶層且平台不讀。
:::

::: {.callout .decided}
**✅ D4 — BE 排程直查，不動申報表**

**定案**：排程每小時 tick 一支「到期掃描」直接查任務表；不在 jedi-task-platform 加到期／完成掛鉤。

**理由**：週期是產品業務規則，比照檢測派掃從平台搬出的原則（`app/detection_tools/task_type_declaration.py:47-51`）；也免一次套件異動。
:::

::: {.callout .decided}
**⛔ D5 — 作廢**

SBOM 重新執行本來就沿用上次上傳的源碼包（見探脈盤點 ⑤ 節），週期自動掃走同一條路：到期 → 建新任務 → 依型別自動派掃或通知人。不需另外決定源碼來源。
:::

::: {.callout .decided}
**✅ D6 — 兩種掃描同一套排程機制**

**定案**：到期判斷都在同一支每小時 tick；派掃時檢測工具沿用 `agent_tasks.scheduled_at`、SBOM 沿用 `background_jobs` 排單。

**理由**：兩條派掃路都已存在且可靠，排程只負責「何時生新任務」，不重做派工。
:::

::: {.callout .decided}
**✅ D7 — 門檻等級第一版只做 SBOM**

**定案**：門檻用 SBOM 標準六級，high（含）以上＝CRITICAL、HIGH；檢測工具結果沒有統一等級，第一版不做。

**理由**：檢測工具單次結果只有各工具不同鍵的 summary，要先正規化才談得上門檻。
:::

::: {.callout .decided}
**✅ D8 — 只在「新出現」high 以上時發（決策者裁）**

**定案**：與上一次掃描比 fingerprint 差集，差集裡有 high 以上才通知。

**理由**：同一批老弱點每期都寄等於沒寄，收件人很快就會無視；新出現的才是要動作的。SBOM 完成時已算過與上一次的差異（`summary.delta`），配對鍵 fingerprint 不含版本，升版仍受同一弱點影響不算新的。
:::

::: {.callout .decided}
**✅ D9 — 通知紀錄第一版只記門檻通知**

**定案**：紀錄表只記門檻通知（掃描 uid、等級、收件人、寄出時間、結果），放 BE 主專案，不動 jedi-notification。

**理由**：決策者要的是「哪次掃描、什麼等級、何時通知誰」可查；指派／完成信納入要改所有既有寄信點，不在本案。
:::

::: {.callout .decided}
**✅ D10 — 語系時區第一版寫死**

**定案**：信件 zh_Hant_TW、時區 Asia/Taipei，沿用現況。

**理由**：使用者與租戶都沒有語系／時區欄位，補上是獨立工程。
:::

::: {.callout .decided}
**✅ D11 — 冪等靠唯一鍵**

**定案**：新任務唯一鍵「源任務＋期數」；門檻通知唯一鍵「掃描 uid＋收件人」；第一版承諾單副本，多副本靠唯一鍵擋重複。

**理由**：現有 12 支排程 job 都靠冪等，沒有分散式鎖；唯一鍵是最小的保險。
:::

::: {.callout .decided}
**✅ D12 — 頻率進 system_menus，閒置欄棄用**

**定案**：頻率值進 `system_menus`（六個 key），FE 四處寫死改讀 menu；`module_frames.last_execute_date`／`next_execute_date` 棄用不啟用；`TASK_TYPE` 五 key 與申報三型別對不上一事只記錄，本案不處理。

**理由**：下拉選項不寫死是專案鐵則；閒置欄放在資源庫範本上，語意是「範本的」執行日，跟任務層週期是兩回事。
:::

::: {.callout .decided}
**✅ D13 — 問卷週期重開空白重填（決策者裁）**

**定案**：新一期問卷建全新空白快照；「填完問卷不自動完成任務」本案不處理。

**理由**：每期的回覆要反映當期狀況，帶上期答案容易被直接送出。
:::

::: {.callout .decided}
**✅ 通知對象**

**定案**：預設＝任務執行人員；掃描類多一個「掃到新出現 high（含）以上時額外通知誰」，可選專案參與者或 Party 角色（CRA 填通報聯絡人 `vulnerability-contact`，FR-135 已預建於 `cra_2024.py:136-138`）。

**理由**：執行人是做事的人；對外通報的責任人常常不是執行人。
:::

---

## 展開時補裁（決策者 2026-10-12） {#decisions2 nav="補裁"}

::: {.callout .decided}
**✅ D14 — 動兩支套件**

**定案**：jedi-flow-engine 的 `job_executions` 照 D3 直接加欄；SBOM 門檻判斷的觸發點在 jedi-source-scan 的 SBOM 完成轉回處（`DetectionResultForwarder`，`pkg/jedi-source-scan/.../sbom_scan_job.py:74-79`）加一個「掃完」回呼，由 BE 註冊。開發期走 path dependency，發版等決策者明示。

**理由**：週期是任務本身的資料，放套件不另開 sidecar 表；回呼只影響 SBOM，與 D7 一致，範圍比改 jedi-detection 的匯合點 `_close_group_if_terminal` 小。

**被排除**：BE 另開一對一任務週期表（sidecar）；改 jedi-detection 匯合點（會牽動檢測工具全部收口邏輯）。
:::

::: {.callout .decided}
**✅ D15 — 支援期提醒併入通知紀錄表**

**定案**：通知紀錄表第一版欄位照門檻通知設計；卡 ⑤ 開工時加 `object_type`／`stage` 兩欄，把支援期 90／30／7 天提醒記進同一張表，唯一鍵同步擴成含這兩欄。

**理由**：「寄過了沒」與「何時寄給誰」只有一處可查；不在版本列上另掛戳記欄。

**被排除**：版本列單欄戳記（三個階段要三欄，且查不到寄給誰）。
:::

::: {.callout .decided}
**✅ D16 — 通報三階段期限提醒不做**

**定案**：卡 ⑤ 只做支援期提醒；24 小時預警／72 小時通報／最終報告提醒不做。

**理由**：起算點是通報案件的「知悉時間」，通報案件頁籤已裁不做，系統裡沒有這筆資料。日後恢復通報案件時再接同一套排程與紀錄表。
:::

::: {.callout .decided}
**✅ D17 — 首掃的 high 以上全算新出現**

**定案**：沒有上一次可比的掃描（`summary.delta` 為空），high 以上全部當新出現、照寄。

**理由**：第一次掃描就是第一次知道它們存在。
:::

::: {.callout .decided}
**✅ D18 — 頻率 menu group 名 `task_frequency`**

**定案**：`system_menus` group＝`task_frequency`，任務與資源庫共用。

**理由**：與近期新增的小寫 group（`ssp_party_role`、`risk_reference_standard`）一致。
:::

另兩點照常理處理：上一期還沒做完，下一期照樣到期就生（D1 各期獨立）；週期開關關掉時清空 `next_due_at`，已生出的各期不動。

---

## 拆卡草案（依「何時看得到畫面」排序） {#cards nav="拆卡"}

| 順序 | 卡 | 規模 | 主要檔案 | 前置 |
|---|---|---|---|---|
| 1 | **① 週期設定畫面** | M | migration（任務新欄＋頻率 seed）、jedi-flow-engine ORM、規劃頁任務讀寫 service、FE 週期 Dialog 新子元件，`AoTaskForm.vue`（733 行）只加一行摘要＋開 Dialog、`AoTaskSection.vue` 頁籤加 ↻、FE 四處頻率改讀 menu | D14 |
| 2 | **② 到期生新任務＋通知執行人** | M | `core/scheduler.py` 加一支、單筆任務複製 service（新檔）、任務抽屜：`JobDrawerHeader.vue` 加期數，`JobExecutionDrawer.vue` 檢測設定卡加三行（該檔超標，三行抽成新子元件） | ① |
| 3 | **③ 掃描自動執行** | S | 新任務轉執行中＋呼叫 `_run_activation_hooks`；確認檢測綁定複製帶 `tool_params` | ② |
| 4 | **④ 門檻通知＋紀錄** | M | 通知紀錄表 migration、jedi-source-scan SBOM 完成回呼＋BE 註冊門檻判斷（D14）、專案內「通知紀錄」頁＋專案概覽頁頂端入口按鈕（`ProjectAuditorOverview.vue` 頁首那排） | ① |
| 5 | **⑤ 支援期提醒接入** | S | 排程加一段、收件人反查（資訊系統 → SSP 盤點 → CRA 專案 manager，FR-135 草案已列路徑）、紀錄表加 `object_type`／`stage`（D15） | ②、④ |

e2e 屬母卡收口，不在單卡做。

---

## 不做清單 {#out nav="不做"}

- 檢測工具結果的門檻通知（D7：單次結果沒有統一等級）。
- 使用者或租戶層級的語系、時區（D10）。
- `system_menus` `TASK_TYPE` 與申報型別對齊（D12）。
- 填完問卷自動完成任務（D13）。
- 指派、完成、專案啟動信納入通知紀錄（D9）。
- 通知設定頁（「哪些事件通知誰」的全域設定）；專案首頁的提醒卡。
- 通報案件三階段期限提醒（D16）。
- 多副本分散式鎖（D11，靠唯一鍵）。
