本卡屬 FR-137(母卡 CM-2714),實作卡 ①/5:週期設定畫面+任務週期欄位+頻率選單。前置:無(D14 已裁可動 jedi-flow-engine)。設計:
docs/features/FR-137-2610-recurring-tasks-and-conditional-notify/design.md§6.1 ①③、§6.7 規劃頁;雛形頁 1docs/features/FR-137-2610-recurring-tasks-and-conditional-notify/prototype/period-settings.html。
讓專案管理者在規劃頁替任務設「多久做一次」。任務表單裡多一行週期摘要,按「設定」跳出一個小視窗(Dialog)填頻率、間隔、下次到期;如果是檢測工具任務,還可以開「自動執行」、指定「掃到新的高風險時額外通知誰」。這張卡只負責設得進去、存得起來、看得到;到期真的生出下一期是卡 ②。同時把頻率選項(每日~每年)從前端寫死改成系統選單。
compliance.job_executions 加欄,ORM 在套件 jedi-flow-engine:jedi_flow_engine/infra/models/job_execution.py、domain/entity/job_execution_entity.py、infra/mapper/job_execution_mapper.py 三處都要帶欄。
recur_unit varchar(32) 可空 週期單位=task_frequency 的 key;空=不重複
recur_interval int NOT NULL DEFAULT 1 每幾個單位一次
next_due_at timestamptz 可空 下一期該生出來的時間(排程只看這欄)
period_no int NOT NULL DEFAULT 1 第幾期
source_job_id bigint 可空 從哪一筆生出來(第 1 期為空)
auto_execute boolean NOT NULL DEFAULT false 只有 detection_tool 可設
alert_recipients jsonb 可空 [{"type":"participant","user_id":12},{"type":"party_role","role_id":"vulnerability-contact"}],只有 detection_tool 可設
ALTER TABLE compliance.job_executions ADD CONSTRAINT uq_job_executions_source_period
UNIQUE (source_job_id, period_no);
CREATE INDEX IF NOT EXISTS ix_job_executions_next_due_at
ON compliance.job_executions (next_due_at) WHERE next_due_at IS NOT NULL;
migration scripts/sql/2026-10-xx-fr137-job-recurrence.sql,manifest.tsv 登記 active *。source_job_id 為 NULL 的既有 6 萬筆不受唯一鍵影響(PostgreSQL NULL 不相等)。
另一支 phase=seed migration,ON CONFLICT ("group", key) DO NOTHING,先例 scripts/sql/2026-05-22-seed-oscal-ssp-roles.sql、2026-10-12-fr135-risk-reference-standards.sql,尾端 DO 區塊驗列數。group=task_frequency(D18),key/sort:daily 10、weekly 20、monthly 30、quarterly 40、semi_annually 50、annually 60。FE i18n lang.task_frequency.<key> zh-tw/en 各補六條。資源庫的 none 不進 menu。
recurrence 物件;app/flow_control/service/job_service.py 只加一行呼叫,驗證本體放新檔 app/flow_control/service/job_recurrence_validator.py。recur_unit 必為 task_frequency 的 enable key;recur_interval ≥ 1;開重複時 next_due_at 必填;auto_execute/alert_recipients 只接受 job_type == detection_tool,其他型別送來回 400;alert_recipients 每筆 type 限 participant(user_id 必為本專案參與者)或 party_role(role_id 必在 ssp_party_role menu)。common/code/flow_control_error_code.py,序號接現有最大號(2026-10-12 為 GRC_400140)往下;FE i18n error-code.json 同步補。next_due_at 存 UTC、畫面以 Asia/Taipei 顯示,只填日期時 FE 送當天 00:00 Asia/Taipei。GET /project/<project_uid>/job/<job_uid>/periods(守門:專案參與者),回傳同一條週期鏈各期:期數、生出日、狀態、一句摘要。週期鏈=沿 source_job_id 往前、往後找。app/flow_control/service/prep_job_generation_service.py 生任務時,資源庫 module_frames.frequency 不是 none 就寫 recur_unit,但 next_due_at 留空(開關視為關閉、只預選頻率)。src/components/grc/planning/AoTaskForm.vue「任務類型」下方只加一行新子元件 <TaskRecurrenceSummary>:有週期時 ↻ 每月 · 第 2 期 · 下次到期 2026-11-01 · 自動執行 · 高風險額外通知 2 人 [設定];沒設時「不重複 [+ 設定週期]」。src/components/grc/planning/TaskRecurrenceDialog.vue:重複開關、頻率(讀 task_frequency)、間隔、下次到期;檢測工具任務多「自動執行」與「額外通知對象」(參與者下拉+Party 角色下拉,可多筆);下方唯讀列各期;一般與問卷任務底部提示「到期時生出下一期並通知指派人員」;檢測工具任務還沒上傳過源碼包時提示「需先手動執行一次」。