白話需求(Phase 0),2026-10-18 決策者口述、首腦整理,同日全部裁定。設計見 design.md。 承接 FR-140 的「任務卡到期提醒」(自動排程版),本篇只談PM 手動挑任務寄提醒。 2026-10-18 決策者已裁:不做一鍵全發、也不做逐卡按鈕,做一個彈窗讓 PM 勾選未完成任務後一次寄出。 同日再裁 Q2~Q4、Q7(見 §5):其他 manager 不收、卡上留系統留言、沒期限也能勾、一卡一封。待裁項已清空。
現在到期提醒只有兩個時點會自動寄(剩 3 天、到期當天),而且一個時點只寄一次。 PM 遇到很急的卡(例如客戶明天就要、或指派人一直沒動),想不等排程、不受兩個時點限制, 直接在專案管理裡面挑幾張卡,提醒信一次寄出去。逐張開抽屜按會很煩,一鍵全發又會催到不急的人, 所以要的是中間那種:一個彈窗,勾要催的卡,按一次寄。
| 項目 | 現況 |
|---|---|
| 自動寄的時點 | 剩 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 |
入口:專案總覽頁動作列多一顆「寄送任務提醒」,限專案 manager。放總覽頁是因為 PM 催人的時機是「看整個專案進度時」,不是在單張卡裡。
彈窗內容:
被否決的方案與原因(留著免得下次又提):
| 方案 | 為什麼不做 |
|---|---|
| 每張卡抽屜一顆「寄提醒」鈕 | PM 要催五張就要開五次抽屜,決策者原話「一個一個點會崩潰」 |
| 總覽頁一鍵催全部逾期卡 | 不急的人也被催,催信變噪音;也無法對特定卡講為什麼急 |
限專案 manager,沿用既有 assert_project_manager(改期限那支端點就是這樣守的)。 輪次已結束的專案整顆入口不顯示、端點也擋(跟改期限同一條件)。
[系統名] 專案管理者提醒:<任務名>when 那句改成「專案管理者 <暱稱> 請您儘速處理」。stage 用 manual_<這一批的 epoch 秒>(同一批所有卡共用同一個 stage 值,之後查「這一批寄了哪些」才對得起來),所以可以重複寄,這是刻意的(急就是要能催第二次)。manual_*);勾到的卡裡有 10 分鐘內寄過的,按寄出時多一層確認「其中 N 張 10 分鐘內才寄過,確定再寄?」。後端不擋。task_alert_notifications,object_type=job_due、stage=manual_<epoch>,每位收件人一列。triggered_by(login_name,可空;自動寄的留空)。這是一支 migration,主線 active,只套 DEV,出貨基線待重產。system,跟內稽退回那則同一套。{jobs: N, sent: M, failed: K, skipped_unassigned: S},前端 toast:「已寄 M 封」/「寄送失敗:郵件伺服器未啟用,請管理員到郵件設定啟用」。| 層 | 動作 |
|---|---|
| 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 各補一段 |
| # | 問題 | 裁示 | 理由 |
|---|---|---|---|
| Q1 | 入口先做哪個 | 總覽頁入口開彈窗、勾選未完成任務一次寄 | 逐卡按太煩、一鍵全發太粗 |
| Q2 | 其他 manager 要不要一起收 | 不收,只寄指派人 | 發信的 PM 知道自己寄了;多 manager 互相收催信是噪音;要知道有人催過看卡上系統留言 |
| Q3 | 卡上要不要留系統留言 | 要 | 指派人開卡就看到「被催了」;也補上 Q2 不寄 manager 的資訊缺口 |
| Q4 | 沒期限的卡能不能勾 | 能 | 手動版的本質是「PM 判斷急」,不該被期限綁住 |
| Q5 | 可不可以重複寄 | 可以,10 分鐘內寄過的要二次確認 | 催兩次是正常需求;二次確認擋手滑就夠 |
| Q6 | 要不要同時進頂欄鈴鐺 | 這次不做 | 鈴鐺目前只接流程進站通知,接進來要改查詢形狀,另案 |
| Q7 | 同一人被勾多張卡,一封還是多封 | 多封,一卡一封 | 合併要另做模板、連結開哪張卡說不清;跟自動版、通知紀錄「一列一封」形狀一致 |
| Q8 | 彈窗要不要也列已完成的卡 | 不列 | 催已完成的卡沒意義 |