FR-150 需求與決策紀錄

任務卡到期提醒:PM 手動挑任務寄信

白話需求(Phase 0),2026-10-18 決策者口述、首腦整理,同日全部裁定。設計見 design.md。 承接 FR-140 的「任務卡到期提醒」(自動排程版),本篇只談PM 手動挑任務寄提醒。 2026-10-18 決策者已裁:不做一鍵全發、也不做逐卡按鈕,做一個彈窗讓 PM 勾選未完成任務後一次寄出。 同日再裁 Q2~Q4、Q7(見 §5):其他 manager 不收、卡上留系統留言、沒期限也能勾、一卡一封。待裁項已清空。

1. 想解決什麼

現在到期提醒只有兩個時點會自動寄(剩 3 天、到期當天),而且一個時點只寄一次。 PM 遇到很急的卡(例如客戶明天就要、或指派人一直沒動),想不等排程、不受兩個時點限制, 直接在專案管理裡面挑幾張卡,提醒信一次寄出去。逐張開抽屜按會很煩,一鍵全發又會催到不急的人, 所以要的是中間那種:一個彈窗,勾要催的卡,按一次寄。

2. 現況(手動版要搭在這上面)

項目 現況
自動寄的時點 剩 3 天(due_3d)、到期當天(due_today),台北日曆天算
寄給誰 該卡指派人 + 專案 manager
擋重複 task_alert_notifications 唯一索引 (object_type, object_uid, stage, recipient_email),同卡同階段同信箱一次
寄失敗 不補寄,紀錄頁顯示失敗
哪些卡 狀態 TODO/PROCESSING、有設期限的卡
信件內容 固定模板:專案/任務/完成期限/連結,沒有自訂文字
看紀錄 專案總覽 →「通知紀錄」頁,每封一列,點列開回那張卡
程式位置 app/task_alert/service/job_due_reminder_service.py、infra/readmodel/tasks/job_due_reminder_query.py、core/scheduler.py 的 task_recurrence_tick

3. 想要的樣子(2026-10-18 決策者已裁定)

3.1 入口與彈窗(決策者已裁)

入口:專案總覽頁動作列多一顆「寄送任務提醒」,限專案 manager。放總覽頁是因為 PM 催人的時機是「看整個專案進度時」,不是在單張卡裡。

彈窗內容:

  • 列出本專案所有未完成任務(狀態 TODO/PROCESSING),每列:勾選框/任務名/控制項/指派人/期限/期限標示(逾期紅、即將到期黃、未設定)。
  • 預設排序:逾期最前、再來即將到期、再來其他;同級依期限近到遠,沒期限的排最後。急的卡自然浮在上面。
  • 頂部兩個快速篩選:「只看逾期」「只看 3 天內到期」,另有任務名/指派人關鍵字搜尋。
  • 全選只選「目前篩選後看得到的」,不會把隱藏的也勾進去。
  • 沒有指派人的卡顯示但不能勾(灰掉、hover 提示「尚未指派人員」),寄了也沒人收。
  • 底部一個多行留言框(可空、上限 500 字)、一行「將寄給 N 張任務的 M 位指派人」、「寄出」鈕。
  • 按「寄出」後同步寄、同步回結果;關窗前 toast 寫「已寄 M 封,失敗 K 封」。

被否決的方案與原因(留著免得下次又提):

方案 為什麼不做
每張卡抽屜一顆「寄提醒」鈕 PM 要催五張就要開五次抽屜,決策者原話「一個一個點會崩潰」
總覽頁一鍵催全部逾期卡 不急的人也被催,催信變噪音;也無法對特定卡講為什麼急

3.2 誰可以按

限專案 manager,沿用既有 assert_project_manager(改期限那支端點就是這樣守的)。 輪次已結束的專案整顆入口不顯示、端點也擋(跟改期限同一條件)。

3.3 哪些卡可以寄

  • 彈窗只列狀態 TODO/PROCESSING 的卡;已完成/已取消不出現。
  • 沒設期限的卡也列、也能勾。急的卡不一定有期限,手動版的意義就是「PM 說急就急」。信裡沒期限就不印期限那列。
  • 沒有任何指派人的卡列出但不能勾,後端收到也略過並在結果裡回「N 張略過:未指派」。
  • 後端收到的 uid 逐張驗歸屬(必須屬於 URL 上那個專案),不屬於的整批 400 退回,不要部分寄。

3.4 寄給誰

  • 每張卡寄該卡全部指派人。同一人被勾了三張卡,收三封(一封一張卡),不合併。合併成一封要另做模板,而且點連結要開哪張卡會說不清;先不做,§5 Q7 留著。
  • 發信的 PM 本人不寄,其他 manager 也不寄(已裁)。manager 要知道有人催過,看卡上的系統留言(§3.7)。

3.5 信長什麼樣

  • 主旨:[系統名] 專案管理者提醒:<任務名>
  • 內文沿用現有模板結構(專案/任務/完成期限/連結),when 那句改成「專案管理者 <暱稱> 請您儘速處理」。
  • 可選填一段 PM 留言(彈窗底部的多行文字框,上限 500 字,可空白),這一批勾的卡共用同一段留言。信裡多一段「管理者留言:…」。這是手動版跟自動版最大的差別,急的時候 PM 通常要講「為什麼急」。

3.6 擋重複與防手滑

  • 唯一索引鎖的是「同卡同階段同信箱」,手動寄每次都是新階段,stage 用 manual_<這一批的 epoch 秒>(同一批所有卡共用同一個 stage 值,之後查「這一批寄了哪些」才對得起來),所以可以重複寄,這是刻意的(急就是要能催第二次)。
  • 防手滑:彈窗列上顯示「上次手動提醒:X 分鐘前/X 天前」(讀紀錄表最近一筆 manual_*);勾到的卡裡有 10 分鐘內寄過的,按寄出時多一層確認「其中 N 張 10 分鐘內才寄過,確定再寄?」。後端不擋。
  • 不做每日上限。真的濫用是管理問題不是系統問題。

3.7 紀錄要留什麼

  • 一樣寫進 task_alert_notifications,object_type=job_due、stage=manual_<epoch>,每位收件人一列。
  • 通知紀錄頁那一列要看得出「這是 PM 手動寄的、誰寄的」:「新出現」欄改掛「管理者提醒 · 王小明」。
  • 表上沒有「誰觸發」的欄位,要加一欄 triggered_by(login_name,可空;自動寄的留空)。這是一支 migration,主線 active,只套 DEV,出貨基線待重產。
  • 每張被寄的卡留一則系統留言(已裁):「管理者 <暱稱> 已寄出提醒」,PM 有填留言就接在後面。指派人開卡就看到被催過,其他 manager 也看得到有人催過。留言作者用 system,跟內稽退回那則同一套。

3.8 寄出的回饋

  • 同步寄、同步回結果。PM 按下去要立刻知道「寄出去了」還是「郵件伺服器沒開」,不要丟背景。一批最多就幾十封,同步寄撐得住;若實測超過 10 秒再考慮改背景。
  • 回 {jobs: N, sent: M, failed: K, skipped_unassigned: S},前端 toast:「已寄 M 封」/「寄送失敗:郵件伺服器未啟用,請管理員到郵件設定啟用」。
  • 一封寄失敗不影響其他封(跟自動版一樣)。

4. 粗估要動哪裡

層 動作
migration task_alert_notifications 加 triggered_by varchar(64);DEV only,主線 active,出貨基線待重產
BE 查詢 新 readmodel:專案未完成任務清單(任務名/控制項/指派人/期限/最近一次 manual_* 時間),給彈窗用。既有任務清單 API 形狀是規劃頁用的,欄位多且沒有「最近手動提醒」,不硬塞
BE 端點 GET /project/<project_uid>/job-due-reminder/candidates(彈窗清單)、POST /project/<project_uid>/job-due-reminder(body:job_uids[]、message 可空);兩支都 assert_project_manager
BE service 新檔 app/task_alert/service/manual_job_due_reminder_service.py,不塞進自動版那支;寄信與寫紀錄的 helper 從自動版抽出共用;收件人查詢重用 JobDueReminderQuery.recipients 加「排除 manager」與「排除某 login_name」參數
BE i18n 主旨、when 句、管理者留言段三個 key,zh/en 兩份
FE 專案總覽動作列入口(限 manager)+選任務彈窗(清單/篩選/搜尋/全選/留言框/寄出);通知紀錄頁手動列的標籤
通知紀錄 API 回傳多 triggered_by+triggered_by_name(暱稱 enrich 照審計欄位規範)
spec project-overview.md §1.1 動作列、project-alert-notifications.md §11、my-tasks.md §11.5 各補一段

5. 決策紀錄(2026-10-18 全部裁定)

# 問題 裁示 理由
Q1 入口先做哪個 總覽頁入口開彈窗、勾選未完成任務一次寄 逐卡按太煩、一鍵全發太粗
Q2 其他 manager 要不要一起收 不收,只寄指派人 發信的 PM 知道自己寄了;多 manager 互相收催信是噪音;要知道有人催過看卡上系統留言
Q3 卡上要不要留系統留言 要 指派人開卡就看到「被催了」;也補上 Q2 不寄 manager 的資訊缺口
Q4 沒期限的卡能不能勾 能 手動版的本質是「PM 判斷急」,不該被期限綁住
Q5 可不可以重複寄 可以,10 分鐘內寄過的要二次確認 催兩次是正常需求;二次確認擋手滑就夠
Q6 要不要同時進頂欄鈴鐺 這次不做 鈴鐺目前只接流程進站通知,接進來要改查詢形狀,另案
Q7 同一人被勾多張卡,一封還是多封 多封,一卡一封 合併要另做模板、連結開哪張卡說不清;跟自動版、通知紀錄「一列一封」形狀一致
Q8 彈窗要不要也列已完成的卡 不列 催已完成的卡沒意義

6. 不在範圍

  • 逾期後的自動再提醒(每天催一次之類)。那是自動版的規則改動,另談。
  • 補寄自動版寄失敗的那幾封。
  • 全專案一鍵催(不勾選直接全發)。
  • 逐卡抽屜按鈕。
  • 合併同一收件人多張卡成一封信(Q7 若改裁再做)。
  • 站內鈴鐺。
  • Discord/Telegram 管道。到期提醒目前只有 Email,手動版跟著只做 Email。