---
title: "第三期砍掉的通報／弱點／提醒設計——給「週期任務與條件通知」FR 的輸入 (FR-135)"
brand: "Guidant AI · **FR-135** CRA 合規框架"
eyebrow: "FR-135 · 第三期歸檔 · 2026-10-13"
h1: "通報、提醒、支援期到期通知的設計草案，交給週期任務 FR"
subtitle: "CRA 第三期不做的三件事（通報案件頁籤、提醒排程與寄信紀錄、相關決策），其設計草案與 ENISA 欄位對照集中在此"
lede: "CRA 第三期只做三份法定文件匯出（X1）與支援期剩餘天數徽章（S1）。通報案件、通報提醒、支援期提醒都不在 CRA 第三期，併入平台級 FR「週期任務與條件通知」（FR-137）。本檔把已寫好的設計草案、決策者已裁的相關決策、探脈發現的落地問題、ENISA SRP 三階段欄位對照集中保存，給 FR-137 討論時當輸入。**這裡的內容不是定案**：決策者方向一節是 2026-10-13 的裁示，其餘草案要在 FR-137 重新對照該 FR 的架構再定。"
chips: [
  {text: "CRA 第三期不做", kind: warn},
  {text: "給 FR-137 當輸入", kind: accent},
  {text: "弱點處理狀態另轉 FR-134", kind: accent}
]
footer: "FR-135 · 第三期歸檔 · 2026-10-13 · CRA 第三期本體見 [phase3-discussion](phase3-discussion.md) · 弱點處理狀態見 FR-134 STATE §3 第 14 列 · 沿革見 [`handoff/FR-135-LOG.md`](handoff/FR-135-LOG.md) 與 git log"
---

**狀態**：歸檔（新 FR 輸入）　｜　**日期**：2026-10-13　｜　**去向**：FR-137「週期任務與條件通知」（母卡 CM-2714、探脈 CM-2715）

## 決策者方向（2026-10-13） {#direction nav="方向"}

::: {.callout .decided}
**新 FR 的方向（只定方向，不展開設計）**

- **週期設定放任務**，不放 AO（一個 AO 底下會有多筆任務）。資源庫 `module_frames.frequency` 閒置欄日後當建專案時的預設帶入。
- **自動執行只限掃描類任務**。
- **通知預設＝任務執行人員**；掃描類多一個特例：「風險門檻＋額外通知對象」（例如 CRA 專案設 high 以上通知通報聯絡人）。
- **通報在系統裡只剩一件事**：掃描掃到 high 以上時通知通報人員，且要留紀錄（哪次掃描、什麼等級、何時通知誰）；客戶之後怎麼到 ENISA 平台通報，系統不管。
- 通報提醒、支援期提醒都併入這個 FR。
- `CRA.ART.14.RP` 三個 AO 的證據＝客戶自行上傳 ENISA 平台送件截圖，不加證據來源第七型 `reporting`。
:::

本檔其餘各節是為 CRA 專案內「通報案件頁籤」與「提醒排程」寫的草案。方向改成平台級週期任務後，資料模型、收件人、排程精度都要在 FR-137 重新判斷；ENISA 欄位對照與時區語系的現況盤點仍可直接用。

弱點「處理狀態／揭露狀態」不在本檔：那是掃描結果本身要不要多欄的問題，屬 FR-134，已列在 `docs/features/FR-134-2610-source-code-sbom-scan/handoff/FR-134-STATE.md` §3 第 14 列。草案內提到「W1」「衝突處 ①」處，指的就是那一項。

---

## 通報案件頁籤草案 {#incident nav="通報案件"}

### 做什麼

CRA 專案 SSP 多一個「通報案件」頁籤：列出本專案的通報案件，每筆顯示軌道、狀態、三個到期倒數；點進去可填案件內容、回填三階段送件時間與回執編號。一案一筆，三階段在同一筆補填，最終報告送出後唯讀——與 ENISA 平台同形狀。

### 資料模型草案：`oscal.ssp_incident_reports`

照 `oscal.ssp_risks` 的骨架（`tenant_id`／`org_unit_id` 取自專案、RLS ENABLE＋FORCE、一條 FOR ALL policy、GRANT cm_app 含 sequence、FK `ssp_id` ON DELETE CASCADE）。業務欄如下：

| 欄 | 型別 | 說明 |
|---|---|---|
| `track` | varchar | `exploited-vulnerability`／`severe-incident`，程式列舉（決定期限算法） |
| `title` | text | ENISA 必填（255 字） |
| `summary` | text | ENISA 早期警示必填（4000 字）；雛形「摘要」 |
| `severity` | varchar | 嚴重度；值域建議進 `system_menus`（N1 開工時定 group 名） |
| `member_states` | jsonb | 受影響會員國（多選，ISO 國碼陣列）；ENISA 必填 |
| `manufacturer_name` | text | 預設帶 Party「製造商」名，可改 |
| `product_name`／`product_version` | text | 預設帶受評標的 `ext:cra-product-name`／`ext:cra-product-identifier`，可改；ENISA 必填 |
| `aware_at` | timestamptz | 知悉時間，使用者填，UTC 存（D1） |
| `fix_available_at` | timestamptz | 修補可用時間，只漏洞軌（D1） |
| `due_early_warning_at`／`due_notification_at` | timestamptz | 建案時算好存（知悉＋24h／＋72h） |
| `due_final_at` | timestamptz | 依軌道重算，可空（D1） |
| `submitted_early_warning_at`／`submitted_notification_at`／`submitted_final_at` | timestamptz | 三階段送件時間（＝時間軸） |
| `receipt_early_warning`／`receipt_notification`／`receipt_final` | varchar | 三段回執編號（ENISA 案件編號形如 `SRP-GR-I-2026-00001289`，一案一號，三段通常相同） |
| `status` | varchar | 草稿／已早期警示／已通知／已結案，程式列舉（狀態機） |
| `vulnerability_disposition_id` | bigint 可空 | 關聯弱點（W1 上線後才有值），見衝突處 ① |
| `stage_content` | jsonb | 三階段的長文欄（見「ENISA 欄位對照」），一階段一個 key |
| `remarks` | text | 備註 |
| `regulation` | varchar | 固定 `CRA`，唯一預留 |

`stage_content` 用 JSONB 而非逐欄展開：ENISA 三階段的文字欄有十餘個且兩軌不同，逐欄展開會讓表寬翻倍、且平台改版就要改 schema；這些欄只給 X1 套範本與畫面顯示，不做查詢條件。

### 端點（照 R1-a 四端點）

`GET/POST /ssp/<ssp_uid>/incident-reports`、`PUT/DELETE /ssp/<ssp_uid>/incident-report/<uid>`。讀 `require_participant`＋`oscal.ssp.read`、寫 `require_manager`＋`oscal.ssp.update`（同 R1-a）；`uid` 以 `(ssp_id, uid)` 一起查，擋拿自己 SSP 權限動別人的案件。最終報告已送出（`submitted_final_at` 有值）的案件，PUT 回 409。回應補 `created_user_name`／`updated_user_name`。

### 畫面改動

- `SspTabPanel.vue` 加 TabPanel，條件 `formSettings?.sections?.incident_report`，深連結 key `incident_report`。
- 清單欄：案件編號、標題、軌道、狀態、三個到期（倒數徽章）、關聯弱點。倒數顏色照雛形提案：已送出綠、剩超過 24h 灰、24h 內橘、2h 內或逾期紅、未開始算虛線框。
- 案件頁：照雛形「時間軸／回填送件紀錄／案件資料／摘要」四區。
- **雛形要拿掉的**：「適用法規下拉／規則展開」（雛形本身已無此下拉，`phase3-incidents.html` grep「法規」0 處；確認不加回）、「通報對象與聯絡資訊」區塊中「協調 CSIRT：待設定」改顯示「受影響會員國」欄的值；「寄信紀錄」區塊等 N2 上線才有資料，N1 先隱藏。

### 證據來源第七型 `reporting`

`ao_evidence_source.py` 加 `T_REPORTING = "reporting"` 與 `_reporting`：查本 SSP 的案件，`status` 有案件即 `filled`，`count`＝案件數，`summary`＝最近一筆的更新時間，`link`＝`{tab:'ssp', section:'incident_report'}`。沒有案件時顯示 `empty`——**「沒有發生需通報的事件」也是正常狀態**，FE 文案要寫「尚無通報案件」而非「缺漏」。哪幾個 AO 掛這一型由套件 seed 決定（II.8 協調揭露、Art.14 相關控制項），N1 開工時對 seed 006 現有掛點補。


---

## 提醒排程與寄信紀錄草案 {#reminder nav="提醒排程"}

### 做什麼

每天跑一次：找出今天該寄的通報期限提醒與支援期提醒，寄給對的人，並記一筆紀錄；同一件事同一階段只寄一次。

### 排程

`core/scheduler.py` `init_scheduler` 加一支每日 cron（照 `:236-267` 的 `system_context`＋`session_scope` 寫法，跨租戶掃描）。**例外：D2 的「到期前 4 小時」與「逾期」精度是小時級**，每日一次跑不到——見衝突處 ③ 的處理建議（改每小時 tick、寄送仍靠紀錄表去重）。

### 寄信紀錄表：`compliance.notification_logs`

| 欄 | 說明 |
|---|---|
| `tenant_id`／`org_unit_id` | |
| `object_type` | `incident_report`／`information_system_version` |
| `object_uid` | 物件 uid |
| `stage` | 通報：`created`、`ew-before-4h`、`ew-overdue`、`n72-before-4h`、`n72-overdue`、`final-before-4h`、`final-overdue`；支援期：`d90`、`d30`、`d7` |
| `recipient` | 收件信箱（一人一列） |
| `sent_at` | 寄出時間 |

`UNIQUE (object_type, object_uid, stage, recipient)` 即去重鍵；排程先 INSERT 搶到列才寄，搶不到跳過。

### 收件人

- 通報：該案件所屬專案的參與者 manager（D2）。
- 支援期：反查「哪些 CRA 專案的 SSP 盤點掛了這個資訊系統」，寄給那些專案的 manager；沒掛任何專案的版本只顯示徽章不寄（D5）。反查要新寫：`oscal.ssp_inventory_items.props` 內 `ref-id`＝資訊系統 uid → `system_implementation_id` → SSP → `compliance.projects.living_ssp_id`，再濾框架為 CRA。

### 信件文字

排程沒有 request，`flask_babel.gettext` 不能用（`project_service.py:10` 那條只能在 request 內）。定案寫「改讀租戶預設語系」，但系統目前**沒有租戶語系設定**，見衝突處 ③。


---

## 相關決策（決策者 2026-10-13 拍板時的原文） {#decisions nav="決策"}

D3（弱點兩組狀態）隨弱點處理狀態轉 FR-134；D4（只出 docx）留在 CRA 第三期。以下四項是通報與提醒相關的原文。

::: {.callout .decided}
**✅ D1 — 通報期限怎麼算**

**定案**：知悉時間由使用者填（UTC 存、顯示換時區）；到期一（24h）與到期二（72h）建案時算好存欄位；到期三依軌道重算：漏洞軌＝回填「修補可用時間」後加 14 天，空著顯示「待修補」；事件軌＝回填 72 小時通知送件時間後加 1 個月。

**理由**：CRA Art.14 兩軌第三段起算點不同（`docs/reference/CRA/cra-reference.md` Step 7 表）；ENISA SRP 的做法也一致——漏洞最終報告平台不計時（要等修補）、事件最終報告從通知送出起算。

**被排除**：「三個到期都在建案時算死」——事件軌第三段的起算點不是知悉，算死會在使用者還沒送 72 小時通知時就顯示錯的倒數。
:::

::: {.callout .decided}
**✅ D2 — 提醒寄幾封、寄給誰**

**定案**：建案當下一封、每階段到期前 4 小時一封、逾期一封；收件人＝專案參與者 manager；「提前幾小時」進 `system_menus`（group `incident_reminder_offset`），不寫死。

**理由**：24 小時期限太短，按天提醒無意義；4 小時是「還來得及到平台送件」的緩衝。manager 是專案層唯一確定有權處理的角色。

**被排除**：按天多次提醒（24h 期限內沒有意義）；寄給所有參與者（auditor／viewer 無權回填，只是噪音）。
:::


::: {.callout .decided}
**✅ D5 — 支援期提醒**

**定案**：到期前 90／30／7 天各一封；收件人＝有掛該資訊系統的 CRA 專案 manager（SSP 盤點 `ref-type` 資訊系統 → 專案）；沒掛任何專案的版本只顯示徽章不寄信。

**理由**：資訊系統是租戶層主檔，沒有「負責人」欄；能確定有人負責的只有「把它納入 CRA 評估的專案」。

**被排除**：寄給租戶管理員（不一定懂產品）；本期做「通知設定」畫面（雛形提案，延後）。
:::

::: {.callout .decided}
**✅ D6 — 弱點反向連結通報案件**

**定案**：弱點列顯示「已建通報案件」連結（`vulnerability_dispositions.incident_report_id`）。

**理由**：顧問在掃描結果頁看到高風險弱點時，要一眼知道「這個已經通報了沒」。

**被排除**：只做通報 → 弱點單向（掃描結果頁看不到通報狀態）。
:::

---

## 落地問題（探脈發現） {#issues nav="落地問題"}

::: {.callout .warn}
**⚠️ ② D5 收件人要新寫「資訊系統反查專案」，不是現成能力**

- 盤點掛資訊系統存在 `oscal.ssp_inventory_items.props` JSONB（`ref-id`＝資訊系統 uid），要經 `system_implementation_id` → SSP → `compliance.projects.living_ssp_id` 才到專案，再判框架是否 CRA；CM-2707 探脈已記「資訊系統反查專案沒有現成查詢」。
- 這不改定案，但讓 N2 的規模比卡上 S～M 偏向 M；也是 CM-2707 改裁「不做反查專案」與 D5 之間的張力——CM-2707 不做的是「通報頁反查」，D5 需要的是「排程反查」，兩者不同，本稿照 D5 寫。

**建議**：反查寫成 infra 層一支查詢（JSONB 條件），放 N2；不擴大成通用 API。
:::

::: {.callout .warn}
**⚠️ ③ 時區、語系與提醒精度：系統沒有「租戶時區」「租戶預設語系」，每日 tick 也追不到 4 小時**

- **時區**：D1 寫「租戶時區顯示」，但全庫沒有租戶時區欄；後端營運時區寫死 Asia/Taipei（`common/util/common_util.py:36`、`config/config.py:178`），FE 顯示時區寫死（`src/utils/dateTime.js:9`，註解寫明「個人 profile 時區設定接這裡」）。
- **語系**：N2 寫「改讀租戶預設語系」，但沒有租戶語系設定，只有環境變數 `DEFAULT_LOCALE`（`.env.sample:124`，jedi-iam 透過 `common/iam_ports.py:31-50` 讀）與 `BABEL_DEFAULT_LOCALE`（`config/config.py:176`）。
- **精度**：D2「到期前 4 小時」「逾期」是小時級；卡上 N2 寫「每日 tick」，每日一次會晚最多 24 小時，對 24h 期限等於沒提醒。

**建議**：時區照現況走既有顯示時區（`getDisplayTimeZone()`／`BUSINESS_TZ`），不在本期加租戶時區；語系讀 `DEFAULT_LOCALE` 環境變數，信件文字放與 gettext 無關的字典檔；通報提醒的 tick 改每小時（支援期提醒仍可每日，同一支 tick 內判斷）。三點都不改 D1／D2 的內容，只改落地方式，請首腦確認。
:::

---

## ENISA SRP 三階段欄位對照 {#enisa nav="ENISA"}

來源：ENISA《CRA SRP — AR User Manual》v1.1 §4.7（2026-09 版，55 頁；本稿只抄欄位，未轉貼全文）。手冊截圖只示範「嚴重事件」軌，**被利用漏洞軌的欄位未截圖**；手冊寫明「Fields differ depending on whether you select Actively Exploited Vulnerability or Severe Incident」，並說「部分欄位若資訊已有即為必填」。

| 欄位（手冊原文） | 中文 | 早期警示 | 72 小時通知 | 最終報告 | 我們的落點 |
|---|---|---|---|---|---|
| Notification type | 軌道 | 必填 | 帶入 | 帶入 | `track` |
| Title（255） | 標題 | 必填 | 帶入 | 帶入 | `title` |
| Summary（4000） | 摘要 | 必填 | 帶入 | 帶入 | `summary` |
| Manufacturer name | 製造商 | 必填（下拉，可新增） | 帶入 | 帶入 | `manufacturer_name` ← Party |
| Member States where product available | 受影響會員國（決定協調 CSIRT） | 必填（多選） | 帶入 | 帶入 | `member_states` |
| Product Name／Product version（各 255） | 產品名／版本 | 必填（可多個產品） | 帶入 | 帶入 | `product_name`／`product_version` |
| Product type | 預設／重要／關鍵產品 | 選填 | — | — | ← `ext:cra-product-class` |
| End of support indicator | 是否已過支援期 | 選填 | — | — | ← 版本 `support_end_date` |
| Component name | 元件名 | 選填 | — | — | `stage_content`（漏洞軌可帶 W1 套件名） |
| Mitigating measure expected shortly | 近期會有緩解措施 | 選填 | — | — | `stage_content` |
| Incident is suspected by unlawful or malicious acts（255） | 是否疑為惡意行為 | 必填（事件軌） | — | — | `stage_content` |
| User action able to reduce impact（4000） | 使用者可採取的降低影響措施 | 選填 | — | — | `stage_content` |
| Considered sensitivity of information（255） | 資訊敏感度 | 選填 | 選填 | — | `stage_content` |
| General information about the nature of the incident（4000） | 事件性質概述 | 選填 | **必填** | — | `stage_content` |
| Initial assessment of the incident（4000） | 初步評估 | 選填 | **必填** | — | `stage_content` |
| Date and time when the incident was detected | 偵測時間 | 選填 | **必填** | — | `aware_at` 預設帶入，可改 |
| Date and time when the incident occurred | 發生時間 | 選填 | **必填** | — | `stage_content` |
| Corrective or mitigating measures taken（可多筆，4000） | 已採取的矯正措施 | 選填 | 選填 | **必填** | `stage_content` |
| Corrective or mitigating measures that users can take（可多筆） | 使用者可採取的措施 | 選填 | 選填 | **必填** | `stage_content` |
| Applied and ongoing mitigation measures（可多筆） | 已實施與進行中的緩解 | 選填 | 選填 | **必填** | `stage_content` |
| Attack vector（255） | 攻擊向量 | — | 選填 | — | `stage_content` |
| Detailed description of the Severity of the incident（4000） | 嚴重度詳述 | 選填 | 選填 | **必填** | `stage_content`；`severity` 是我們的分級欄 |
| Detailed description of the Impact of the incident（4000） | 影響詳述 | 選填 | 選填 | **必填** | `stage_content` |
| Type of threat or root cause（255） | 威脅類型或根因 | 選填 | 選填 | **必填** | `stage_content` |
| Particular Exceptional Circumstances（PEC）＋理由三選＋補充（800） | 特殊例外情況（延後轉發） | — | 選填（**僅漏洞軌**） | — | `stage_content` |
| Additional Notes | 補充說明 | 任何階段可更新 | 同左 | 同左 | `remarks` |

平台行為（給 N1 狀態機參考）：草稿只存在送件人帳號、不送 CSIRT；早期警示與 72 小時通知送出後仍可更新；**最終報告送出後唯讀**；狀態依序為 `EW Submitted` → `72h Submitted`（或 `72h Submitted under PEC`）→ `FR Submitted`，CSIRT 審後另有 Valid／Invalid／Closed。我們的 `status` 四值（草稿／已早期警示／已通知／已結案）對應前三段，CSIRT 審查結果不追。

::: {.callout .warn}
**被利用漏洞軌的欄位：未取得，X1 開工前補**

手冊只截嚴重事件軌的畫面。漏洞軌至少有 PEC（上表）、元件名；其他差異（例如 CVE 編號、修補可用時間）要在 X1 開工前以 SRP 測試帳號或 ENISA 後續文件補齊，補到後更新本表與 `stage_content` 的 key 清單。
:::

---

## 日後拔成獨立模組的預留 {#future nav="預留"}

本期不做多法規、多對象，但寫法要讓日後拔得出來：

- 通報的四層檔案自成一組（`ssp_incident_report_*`），**不把通報邏輯寫進 SSP 既有 service 或規劃頁 service**。
- `ssp_id` 本期必填。
- 日後獨立＝搬成套件（照 jedi-asset 切法、套件自帶 migration，見 CM-2707 探脈結論）、`ssp_id` 改可空、`regulation` 欄變成規則軸、頁籤改側選單入口。

---

沿革見 [`handoff/FR-135-LOG.md`](handoff/FR-135-LOG.md) 與 git log。
