Repository navigation
Conversation
PDF、Excel、人員 Excel 三個匯出過去都用固定檔名(班表.pdf、班表.xlsx、 人員班表.xlsx),每次匯出瀏覽器只能自動加 (1)(2)... 分辨,看檔名完全 不知道是哪次、哪份班表匯出的。 新增 exportFilename.js 的 buildExportFilename(),統一組出 「已儲存班表名稱(沒有就用預設)_ 週次日期範圍 _ 匯出時間戳記」的檔名, 三個匯出函式共用同一份邏輯,避免各自重複實作。 已用真實瀏覽器操作驗證三種情況:未儲存班表時的 Excel 匯出(班表_ 0907~0918_時間戳.xlsx)、已儲存班表「中午」時的 PDF 匯出(中午_ 0907~0918_時間戳.pdf)、人員 Excel 匯出(中午_人員_0907~0918_時間戳. xlsx),檔名皆正確。backend 229 個、frontend 68 個測試(新增 6 個) 與 production build 皆正常。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
除錯 PDF 匯出問題時親自撞到:PDF/Excel/人員 Excel 三個匯出按鈕點擊後
沒有任何 disable 或 loading 提示,匯出過程(尤其 PDF 要跑好幾秒
html2canvas)使用者容易誤以為沒反應而多點幾下,導致兩個匯出流程同時
執行、共用同一份注入的 <style> class 名稱與 DOM 操作互相干擾,其中一個
常常靜默失敗或產生錯誤的結果。
三個匯出函式開頭都加上「按鈕已 disabled 就直接 return」的防呆,並在
匯出開始時 disable、結束後(含錯誤路徑)恢復。全域已有
`button:disabled { opacity: 0.45; cursor: not-allowed; }` 樣式,
不用額外做 loading UI 就能讓使用者看出匯出正在進行中。
已用真實瀏覽器操作驗證:連續快速點兩下 PDF 匯出,確認按鈕點擊後立即
變成 disabled、只跑了一組 html2canvas 擷取(不再像修正前那樣出現交錯
的兩組擷取紀錄)、Downloads 也只多一個檔案。backend 229 個、frontend
68 個測試與 production build 皆正常。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
這兩個自動抓資料機制過去失敗時完全沒有地方看得出來:全部只寫 debug log,正式環境預設不會顯示 DEBUG 環境變數,CDN 掛掉或學校網站 改版導致 regex 抓不到東西,都會靜默發生、無從察覺。 holidayService.js 的 refreshHolidaysFromCDN() 現在記錄每個年份的 success/count/error 到 lastRefreshStatus;成功與否用「有沒有實際抓到 資料」判斷,而不是「有沒有拋例外」,因為 getHolidaysForYear() 在 CDN 失敗時本來就是回傳空 Map、不拋例外——先前的作法即使兩年都抓到 0 筆也會被視為「更新成功」。 schoolCalendar.js 的 getSchoolEvents() 現在記錄「最近一次即時抓取」 (不含快取命中)到 getLastFetchStatus()。這是整套機制最脆弱的一環: 靠 regex 解析學校網站的 HTML,網站改版時 fetch 仍會 200 成功、但完全 解析不到任何考試資料,程式本身不會拋出任何錯誤。新增「回傳 0 筆」視為 可疑並發出 console.warn(不受 DEBUG 環境變數影響一定看得到)。 GET /api/status 新增 holidaysLastRefresh/schoolCalendarLastFetch 兩個 欄位回報上述狀態,向下兼容(純新增欄位)。 已用真實 CDN/學校網站驗證兩個資料源目前都正常:直接打 cdn.jsdelivr.net 的台灣行事曆 JSON 確認格式正常;解碼明道中學的 Big5 頁面確認程式依賴的 HTML class 都還在。並清空測試資料庫的假日/行事曆 快取後實際觸發一次即時抓取,確認 /api/status 正確回報 success:true 與抓到的筆數。backend 236 個測試(新增 7 個)皆正常。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題:⚙️ 進階設定 Modal 開啟時,標題「每週上限 X 班」與班次上限輸入框 皆為空白,且儲存後不會更新 person.maxShifts,只有側邊欄清單能正常編輯。 原因:main.js 的 elements 物件從未取得 #pm-max、#pm-maxshifts 這兩個 DOM 節點,openPersonnelModal 也從未寫入其值;儲存邏輯同樣漏讀該欄位。 修改: - elements 補上 pmMax、pmMaxshifts - openPersonnelModal 開啟時同步帶入 person.maxShifts(預設 5) - 儲存邏輯讀取輸入框數值並寫回 person.maxShifts(NaN 或 <1 時 fallback 為 1) - index.html 的 #pm-maxshifts min/max 由 0–5 改為 1–7,對齊後端實際驗證範圍與側邊欄輸入框 已用隔離測試資料庫(scheduleApp_test)實際操作驗證:開啟 Modal 正確顯示 現有上限、修改並儲存後側邊欄與後端資料皆正確更新為新值。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題一:編輯模式下修改儲存格後,若用「復原」把內容退回與已儲存版本 完全相同的狀態,右上角「有未儲存的修改」文字與「儲存修改」按鈕仍 維持已修改狀態,且 localStorage 草稿也不會被清除。 原因:undoEdit/redoEdit 只還原 editingData,從未重新比對是否與 generatedData 一致,未儲存旗標永遠只能被 markAsModified() 單向設為 true。 修改:editableSchedule.js 新增 syncModifiedState(),於復原/重做後 以 JSON 深層比對 editingData 與 generatedData,重新推導旗標、按鈕 disabled 狀態、狀態文字,並依結果呼叫 autoSaveDraft()/clearDraft()。 問題二:編輯模式下使用瀏覽器原生列印(Ctrl+P),編輯工具列 (復原/重做/儲存修改等按鈕)、每個人員格子的「×」刪除鈕、 空格「+ 待補」佔位標籤都會一併印出。 修改:@media print 區塊補上 #edit-toolbar、.remove-person、 .person-tag.unfilled 的 display: none。 已用隔離測試資料庫(scheduleApp_test)實際操作驗證:編輯後復原, 按鈕與文字正確清空、草稿正確移除;重做後正確恢復未儲存狀態; 並讀取瀏覽器解析後的 @media print CSSOM 規則確認新增的隱藏規則 語法正確、無誤植。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題一(使用者回報):編輯模式下把人員拖到已滿的格子時,永遠是跟格內
「第一個可對調的人」交換,不是使用者實際拖放上去的那個人。
修改:evaluateCellDrop() 新增 preferredBumpTarget 參數,優先嘗試跟
使用者實際放開滑鼠時所在的那個 .person-tag 對調;若那個人不可對調
(排休/當天衝突)才 fallback 掃描格內其他人選,行為與過去一致。
handleCellDrop() 用 e.target.closest('.person-tag') 取得該對象傳入。
問題二(第二輪實機 QA 發現):編輯模式下刪除或重新命名目前作用中的
設定檔,畫面雖然因為 #output-container 被隱藏而不會露出殘影,但
「有未儲存的修改」旗標、undo/redo 歷史、可用人員側邊欄等狀態並未
清除。若使用者接著針對另一個設定檔重新產生班表並進入編輯模式,
工具列會沿用上一段(已被刪除的設定檔的)編輯狀態,錯誤顯示「有未
儲存的修改」與可儲存按鈕,且已用瀏覽器實測重現。
根因:main.js 的刪除/改名設定檔按鈕只呼叫 initApp() 重新載入
profiles/settings,從未重設 generatedData/editingData/
currentScheduleName/hasUnsavedChanges,也未清除 undo 歷史;而
editableSchedule.js 的 enableEditMode() 進入編輯模式時只是把
hasUnsavedChanges 直接設為 false,並未同步工具列 DOM(按鈕
disabled、狀態文字),一旦有殘留的舊 DOM 狀態就不會被校正。
修改:
- main.js 抽出 resetScheduleEditingState()(原本切換設定檔時的重設
邏輯),改名/刪除設定檔成功後與切換設定檔一樣呼叫它。
- editableSchedule.js 的 enableEditMode() 改用 syncModifiedState()
取代直接 setHasUnsavedChanges(false),確保每次進入編輯模式都會
依實際 editingData vs generatedData 差異重新校正工具列視覺狀態,
不受之前殘留的 DOM 影響(這是能徹底解決問題二的關鍵修正)。
已用隔離測試資料庫(scheduleApp_test)建立多個設定檔,實際操作
「編輯中刪除作用中設定檔→切到另一設定檔→重新產生班表→進入編輯
模式」的完整流程,確認工具列正確歸零(按鈕停用、文字清空、可用
人員清單顯示新設定檔自己的人員),並確認拖曳對調時交換對象改為
實際拖放上去的人員。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
需求:想要 PDF 檔案本身能「藏」一份可還原的班表資料——一般人開啟 PDF
完全看不出來,但同一套系統可以讀回原始班表;且藏的資料要真的加密,
金鑰不能放在前端(避免被讀原始碼反解)。
作法:
- 後端新增 AES-256-GCM 加解密服務 pdfPayloadCrypto.js,金鑰來自新環境
變數 PDF_PAYLOAD_SECRET(64 字元 hex,選填,未設定則功能自動停用,
不影響任何既有功能)。GCM 內建的 authTag 驗證同時提供竄改偵測:
被動過手腳或並非本系統加密的內容,解密會直接拋出例外。
- 新增兩個端點 POST /api/pdf-payload/encrypt、/decrypt,金鑰全程留在
後端,前端只經手加密後的 base64 字串。
- 前端匯出 PDF 時(pdfExport.js),把當次匯出的班表資料送到後端加密,
結果用 jsPDF 內建的 setProperties({ keywords }) 寫進 PDF 的中繼資料
欄位——一般 PDF 檢視器的內容畫面完全看不到,只有「文件內容」對話
框才看得到一段亂碼,且此步驟為錦上添花:後端未設定金鑰或任何失敗
都靜默略過,不影響 PDF 正常匯出。
- 新增「從 PDF 匯入」按鈕(pdfImport.js + pdf-lib 讀取 metadata),選擇
先前匯出的 PDF 檔案即可送後端解密、還原班表並直接顯示,效果等同
重新產生一份班表。找不到嵌入資料或解密失敗都會用 toast 清楚告知
原因(此為使用者主動操作,不能靜默略過)。
已用隔離測試資料庫(scheduleApp_test)+ 實際設定 PDF_PAYLOAD_SECRET
驗證完整流程:直接呼叫後端 encrypt/decrypt 端點確認往返正確、竄改內容
會被拒絕;在瀏覽器內用真正的 jsPDF + pdf-lib + 後端 API 組出真實 PDF
位元組,透過實際的「從 PDF 匯入」檔案輸入框觸發匯入,確認還原的班表
資料與畫面跟原始匯出前逐格一致;另外驗證了兩種失敗情境(PDF 沒有
嵌入資料、檔案本身不是有效 PDF)都能正確擋下並清楚回報,不會誤把
既有畫面上的班表覆蓋掉。
新增前端依賴 pdf-lib(MIT、零依賴,僅用於讀取 PDF metadata)。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
一、設定檔快速複製 問題:新增設定檔永遠是空白的,要重新輸入一次所有勤務與人員。 修改: - POST /api/profiles 新增選填的 settings 欄位(向下相容:不帶時沿用 原本建立空白設定檔的行為),帶了就用該內容建立新設定檔(validateSettings 驗證後才寫入)。 - profileRepository.createProfile(name, settings) 支援帶入初始設定。 - 設定檔管理新增「複製」按鈕:複製目前作用中設定檔的勤務/人員設定 (不含已儲存班表,避免帶入跟新設定檔無關的舊班表)建立同名+「-複製」 的新設定檔。 二、假日/學校行事曆自動更新健康狀態顯示在 UI 問題:/api/status 早已回傳 holidaysLastRefresh、schoolCalendarLastFetch, 但前端從未讀取顯示,異常時完全沒人看得到。 修改:connectionStatus.js 新增 buildAutoFetchWarnings(),checkConnectionStatus() 每次輪詢時一併判斷;異常時在頂部連線狀態旁顯示警示圖示(平常隱藏), 點擊以 toast 顯示具體原因(哪一年假日更新失敗、學校行事曆抓取警告)。 三、離開頁面前的未儲存修改警告 問題:編輯模式下有未儲存修改時,只有 localStorage 草稿自動存檔這道 安全網,使用者手滑重新整理或關分頁完全不會被攔下來。 修改:main.js 新增 beforeunload 監聽,getHasUnsavedChanges() 為 true 時呼叫 preventDefault() 觸發瀏覽器原生的離開確認對話框。 已用隔離測試資料庫(scheduleApp_test)實際操作驗證:複製設定檔後 用 API 直接確認新設定檔的 tasks/personnel 與來源完全一致、schedules 為空;用模擬的 /api/status 回應驗證警示圖示正常顯示/隱藏、點擊後 toast 內容正確;直接對 window 派發 beforeunload 事件確認有未儲存 修改時會 preventDefault、沒有修改時不會。後端 257/257、前端 83/83 測試全過。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題:.profile-actions 原本寫死 grid-template-columns: repeat(5, 1fr), 上一版新增「複製」按鈕後變成 6 個子元素,第 6 個(刪除的垃圾桶圖示) 自動換到第二行,第二行只有它自己、右邊留一大片空白,視覺上很突兀。 修改:改成 repeat(6, 1fr),六個按鈕排回同一行。 已用瀏覽器截圖確認深色/淺色模式下皆恢復正常排列。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題:先前修過列印時隱藏編輯工具列/刪除鈕/待補標籤,但 @media print 只處理了 #output-container 內部,沒注意到 <main> 底下還有兩個平行的 區塊完全沒被隱藏:「已儲存的班表」卡片(含載入/刪除連結、這次新增 的「從 PDF 匯入」「比較班表」按鈕)、頁尾(版權/快捷鍵提示)。使用者 列印班表時這兩塊會原封不動印在後面,對紙本毫無意義。 修改:@media print 補上 .card.saved、.app-footer 的 display: none。 已讀取瀏覽器解析後的 CSSOM 確認新規則語法正確、選擇器與實際 DOM 元素相符。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題:選檔案的原生對話框本身會擋掉重複點擊,但選好檔案後到匯入處理 完成(讀檔 + 呼叫後端解密的非同步空檔)這段期間按鈕仍可再次點擊, 快速連續匯入兩個檔案會讓兩次 importScheduleFromPdfFile() 同時執行、 互相干擾最終顯示結果。跟本工作階段稍早修過的匯出按鈕連點問題是同一類。 修改:仿照匯出按鈕的做法,選到檔案後立即 disable「從 PDF 匯入」按鈕, 處理完成(不論成功或失敗)才重新啟用。 已用人工延遲後端解密回應的方式重現非同步空檔,確認按鈕在處理期間 正確顯示 disabled、完成後正確恢復。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題:檢查發現 index.html 裡 7 個 Modal 的關閉鈕 title 全部都是「關閉 (Esc)」,但實際上只有 input-modal 自己在 field 上做了 Escape 監聽, 其餘 6 個(含最常用的 confirm-modal 通用確認框)按 Esc 完全沒反應—— 等於 tooltip 開了從未兌現的空頭支票。 修改:main.js 新增一個全域 keydown 監聽,Escape 時找出目前開啟的 .modal-backdrop.open 並觸發跟點擊 × 鈕相同的關閉邏輯(沿用既有邏輯, confirm/input modal 會正確走取消流程讓 Promise resolve,其餘直接關閉)。 input-modal 本身既有的 Escape 處理不受影響、不會重複觸發(它自己的 監聽器在 field 上,冒泡到 document 的全域監聽器執行時該 modal 已經 被關掉,查不到開啟中的 backdrop)。 已用瀏覽器實測全部 7 個 Modal(含 confirm-modal 驗證 Promise 正確 resolve 為取消、input-modal 驗證原本行為不受影響)按 Esc 都能正確關閉。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題:追查上一個 Esc 的問題時,發現頁尾同時廣告了 ⌘K、⌘↵、⌘Z 三個 快捷鍵,但翻遍前端程式碼只有 ⌘Z / ⌘⇧Z(復原/重做)是真的有實作, ⌘↵ 完全沒有對應的監聽器——「產生智慧班表」按鈕上明明就印著這個 按鍵提示,實際按下去卻沒有任何反應。 修改:全域鍵盤快捷鍵監聽新增 ⌘/Ctrl+Enter 觸發「產生智慧班表」按鈕的 click。刻意放在「游標在輸入框內就略過」的判斷之前,讓在設定欄位打完 字後直接按也能觸發,不用特地把游標移開。 已用瀏覽器實測:確認頁面上尚未有班表時,直接對 document 派發 ctrlKey+Enter 的按鍵事件,output-container 正確從隱藏變成顯示班表結果。 註:⌘K 目前查不出原本預期要做什麼(沒有任何按鈕或功能有相關提示), 沒有一併實作,留給使用者決定。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題:使用者回報畫面上的快捷鍵提示「長得很奇怪」——復原/重做按鈕的 title、「產生智慧班表」按鈕與頁尾的按鍵提示,全部寫死顯示 ⌘(Mac Command 鍵符號)。keydown 監聽器裡判斷「這次按的是不是修飾鍵」早就 有依平台分流(Mac 用 metaKey、其餘用 ctrlKey),但顯示給使用者看的 提示文字完全沒有跟著分流,在 Windows/Linux 鍵盤上顯示一個根本不存在 的按鍵符號。 修改:新增 applyPlatformKeyboardHints(),非 Mac 平台時把 ⌘ 相關提示 文字換成 Ctrl(含 Shift 组合),複用既有的平台判斷邏輯(抽成 isMacPlatform 常數,keydown 監聽器裡的判斷也改用同一個常數,不重複 判斷兩次)。 已用瀏覽器實測(navigator.platform 為 Win32)確認復原/重做按鈕的 title、「產生智慧班表」按鈕上的提示、頁尾三個提示全部正確顯示 Ctrl 而非 ⌘。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
一、showConfirm() 補上 Enter 確認 問題:showInput() 本來就支援 Enter 送出、Escape 取消,但 showConfirm() (「確定要刪除嗎?」這種最常見的通用確認框)完全沒有鍵盤支援,連 最基本的 Enter 確認都要用滑鼠點。Escape 已經在稍早的全域 Modal 監聽器修好,這裡補上 Enter。 二、移除 ⌘K 上一個 commit 發現頁尾廣告的 ⌘K 快捷鍵從頭到尾沒有任何實作、也在整個 程式碼庫裡找不到任何線索它原本要做什麼。討論後決定不要憑空猜測實作, 直接從頁尾與對應的平台快捷鍵提示邏輯中移除,避免繼續誤導使用者。 已用瀏覽器實測:showConfirm() 開啟時按 Enter 正確 resolve 為 true (確認)並關閉 Modal;確認頁尾文字只剩下 Ctrl ↵、Ctrl Z 兩個提示。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
需求:讓每個人可以拿到一個免登入的網址查看自己的班次,比訂閱 .ics
行事曆更輕量、不需要對方開啟行事曆 App,適合直接傳連結給人看;同時
也要能分享整份班表給所有人看。連結必須是隨機、猜不到的權杖,別人拿
到你的連結不能推導出其他人的連結。
作法:
- 新增 MongoDB collection `scheduleShares`,一筆一個分享連結:
{_id: 隨機 128-bit token, profile, scheduleName, personFilter}。
分享連結對應到「某一份已儲存班表」的即時查詢,不是存快照——若該
班表被刪除,連結會 404;若被覆蓋重新儲存,連結會顯示新內容。
- 新增 POST /api/schedule-shares(建立分享連結)、
GET /api/schedule-shares/:token(全站唯一刻意設計成免登入的公開
端點)。personFilter 有指定時,過濾邏輯在**後端**執行(保留完整
週次/任務結構,只清空不是該人員的格子,直接沿用既有的
generateScheduleHtml 渲染),不是前端隱藏——避免瀏覽器開發者工具
的網路分頁還是看得到完整班表資料,等於沒做過濾。
- 前端「已儲存的班表」列表每筆多一個「分享」按鈕,開啟 Modal 選擇
分享對象(全部人或指定單一人員,清單直接從這份班表實際出現過的
人名產生,而非目前設定檔的人員名單,兩者可能已經不同步)後產生
連結。
- 新增 sharedView.js:偵測到網址帶 ?share=<token> 時,整個接管
document.body,完全不初始化後台功能(側邊欄、編輯、設定管理等),
只顯示唯讀的班表內容。
已用隔離測試資料庫實機驗證完整流程:產生「全部人」與「指定人員」
兩種連結,分別用新分頁開啟,確認畫面正確(指定人員版本其他人的格
子清空、標題正確顯示「OOO 的班表」);直接 fetch 該分享端點的原始
回應內容,確認被過濾掉的人員姓名完全不存在於回應中(不是只在畫面
隱藏);確認無效 token 會顯示清楚的錯誤訊息、不會顯示任何後台介面。
後端 275/275、前端 83/83 測試全過。
已知限制(已寫進 CLAUDE.md 已知地雷):目前沒有連結過期機制,也沒有
前端介面可以撤銷已產生的連結。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
需求:延續上一版的班表分享連結,要能選擇「無限時間」或「限時」。
修改:
- shareRepository.createShare() 新增選填的 expiresInDays,未提供時
不寫入 expiresAt 欄位(永久有效),提供時換算成 expiresAt。
- db/connect.js 為 scheduleShares 建立 TTL index
({expiresAt:1}, {expireAfterSeconds:0}):只會清除「有 expiresAt
且已過期」的文件,永久連結沒有這個欄位完全不受影響。
- POST /api/schedule-shares 新增 expiresInDays 驗證(1-365 之間的
整數,或不帶)。
- GET /api/schedule-shares/:token 讀取當下額外檢查 expiresAt 是否已
過期——MongoDB TTL 背景清除任務約每 60 秒才跑一次,不能只依賴它,
否則過期瞬間到文件真的被刪除之間會有一段視窗仍可存取。
- 前端分享 Modal 新增「有效期限」下拉選單(永久有效/1/7/30/90
天後失效),每次開啟都重設為預設值。
已用隔離測試資料庫實機驗證:分別建立永久與 1 天期限的分享連結,直接
連線 MongoDB 確認永久連結完全沒有 expiresAt 欄位、限時連結的 expiresAt
精確等於 createdAt + 天數;確認 TTL index 已正確建立;透過瀏覽器 UI
選「7 天後失效」產生連結,同樣直接查 DB 確認 expiresAt 正確為 7 天後。
後端 282/282、前端 83/83 測試全過。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
需求:延續前兩版的班表分享連結,補上撤銷能力。 修改: - shareRepository 新增 listShares(profile, scheduleName)(依 createdAt 新到舊排序)、deleteShare(token)。 - 新增 GET /api/schedule-shares?profile=&scheduleName=,回傳精簡欄位 (token/personFilter/createdAt/expiresAt,不含 profile/scheduleName 避免回傳多餘資訊)。 - 新增 DELETE /api/schedule-shares/:token,刪除成功回 200、找不到回 404。 - 分享 Modal 開啟時(以及每次成功產生新連結後)自動讀取並顯示這份班表 已產生的所有連結,每筆附「撤銷」按鈕,點擊後立即呼叫 DELETE 並從 清單移除。 已用隔離測試資料庫實機驗證:對同一份班表建立「全部人」與「張三、 30 天後失效」兩個連結,重新整理頁面後開啟分享 Modal,確認清單依新到 舊正確列出兩筆、期限文字正確;點擊其中一筆「撤銷」,確認畫面上該筆 立即消失,且直接對該 token 打 GET 確認伺服器端已回傳 404(token 真的 從資料庫刪除,不是只有前端隱藏)。後端 292/292、前端 83/83 測試全過。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
問題:CI 的 E2E 測試在這個 PR 上失敗——「匯出 Excel/PDF 觸發下載」
兩個測試還斷言固定檔名 班表.xlsx / 班表.pdf,但本工作階段稍早已經把
匯出檔名改成「班表名稱_日期範圍_時間戳記」的動態格式(避免每次匯出
覆蓋同一個檔名),測試沒有跟著更新。
修改:改用正則比對格式(^班表_\d{4}~\d{4}_\d{8}-\d{6}\.xlsx$ 等),
不用固定字串比對,避免日期範圍/時間戳記隨每次執行變動導致測試又要
手動更新期望值。
已在本機用隔離測試環境跑過完整 E2E 測試(backend 無 DB 模式 + Vite
dev server,由 Playwright webServer 設定自動啟動),35/35 全數通過。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
累積多個功能與修復,準備從 develop 合併進 release。
新功能
PDF_PAYLOAD_SECRET),未設定時功能自動停用、不影響既有匯出。/api/status回報最近一次自動更新結果,前端異常時顯示警示圖示並可查看原因。Bug 修復(多輪實機 QA 找出)
⌘↵產生班表快捷鍵從未真正實作;移除查無用途的⌘KTest plan
npm --prefix backend test:292/292 通過npm --prefix frontend test -- --run:83/83 通過npm --prefix frontend run build成功scheduleApp_test)搭配瀏覽器實機操作驗證,非僅單元測試🤖 Generated with Claude Code
https://claude.ai/code/session_0117v1Qxx7foQEH4cd6pfnLS