← 回課程首頁

STORY LAB · 完整示範篇

那台被借走
兩次的投影機

跟著阿哲與 ChatGPT,從一句「做個借用系統」走到能被驗證的交付。

設備借用 × ASP.NET Core × PostgreSQL
圖解加長版 · 約 100–140 分鐘 · 先看完整故事,再獨立解題

圖解加長版

每幕新增圖解或成果快照;讀完後勾選的是「能解釋」,不是「滑到底」。進度僅存在本次頁面,重新整理會重設。

已自我確認 0 / 12 幕

STORY 00

開場|一台投影機,兩張核准單

星期一,早上九點零五分。小晴抱著筆電站在器材室門口:「我十點要提案,昨天核准的投影機呢?」

管理員美玲翻開試算表,臉色變了一下。另一位同事阿凱也有一張核准單,設備編號一模一樣:P-001

主管:「阿哲,你不是會用 AI?幫我們做個借用系統吧。可以申請、核准、歸還就好,很簡單。」

工程師阿哲打開 ChatGPT。他差點輸入「用 ASP.NET Core 和 PostgreSQL 做借用系統」,但停住了:畫面能跑,和公司不再把設備借兩次,是兩回事。

這是一個虛構但貼近工作的完整示範。所有角色對話、AI 回應及業務數據都是教學設計;不是實際執行紀錄。你將讀完一次需求到交付的工作流程,並操作前端模型;本頁不是已完成部署的後端應用。

先看終點:本次到底要交付什麼?

一份能追溯決策的 MVP 規格、一條「核准 → 領用 → 歸還」垂直切片設計、資料庫防線、測試計畫與上線檢查。故事中的成功不是「AI 寫了好多程式」,而是我們知道什麼已確認、什麼仍需驗證

人物登場|你會跟誰一起完成這件事?

小晴 · 使用者

「我不在乎資料表,我只想知道十點有沒有設備。」

提醒我們:成果要回到使用情境。

美玲 · 管理員

「系統說歸還,東西真的回來了嗎?」

提醒我們:系統狀態要對應現實。

阿哲 · 開發者

「先把規則說清楚,再讓 AI 幫忙實作。」

提醒我們:決策不能外包給猜測。

全書地圖|每一站都要帶走一樣東西

01

事件現場|找出真正損失

02

訪談桌|核准的需求

03

設計室|狀態與不變條件

04

施工區|小而可驗證的切片

05

測試台|成功與失敗證據

06

交接處|可重現與可復原

讀法:第一遍跟著劇情走;第二遍只看每幕「成果快照」;第三遍遮住解析,把自己的決策說出來。看懂是起點,能解釋反例才是更有力的吸收證據。

STORY 01

第一幕|先別讓漂亮答案替你決定需求

阿哲先試了一次模糊的問法。

幫我設計一套專業的設備借用系統,要完整一點。
示範 AI 草案

加入預約月曆、主管簽核、電子郵件通知、逾期罰款,並在申請成功後扣除庫存。

看起來很完整。美玲卻問:「我們沒有罰款,而且申請還沒核准,為什麼就不能借給別人?」

第一個錯誤浮出來了:AI 把合理猜測寫得像既定政策。阿哲沒有要求它「更聰明一點」,而是改變工作順序。

先不要寫程式。我們要解決設備重複借出的問題。
請列出會改變資料模型或權限設計的關鍵問題。
區分:已知事實、待確認事項、你的建議。
不要自行把建議當成公司規定。
關鍵問題美玲確認的答案
一筆設備是一種品項,還是一台實體?一台實體,有唯一設備編號。
何時占用設備?核准時保留;申請時不保留。
是否可預約下個月?MVP 不做未來時段預約。
誰能核准、領用、歸還?管理員登記;員工只能申請及查自己的紀錄。
逾期會自動釋出嗎?不會。沒還就是還在外面。
核准後一直沒領?管理員可取消;本版不做自動到期。

帶走的概念:好 Prompt 不是修飾詞多,而是能讓未決事項浮出來。

停一下:主管說「完整一點」,可以直接加通知寄送嗎?

可以列為建議,但不能當成已授權功能。通知涉及收件人、個資、寄送時機與外部動作;先確認範圍。設計通知草稿和真的寄出是不同授權。

加長現場|一場十五分鐘的需求訪談

阿哲:「如果小晴提出申請,阿凱也提出申請,你們希望誰先拿到?」

美玲:「不是先申請先贏,我要看用途。核准之前都只是候選。」

阿哲:「那核准後、還沒領走呢?」

美玲:「就要幫她留著。不然我核准了也沒意義。」

阿哲:「所以『占用』從核准開始,不是領用開始。我把這個寫進規格,你確認一下。」

需求原句

「做個可以借東西的系統。」

不知道誰、何時、什麼算成功。

確認後的需求

「管理員核准申請時,即保留那台設備;其他申請不得同時獲得保留。」

角色、時機與約束已可辨識。

成果快照 · 決策 D-01

決策:Approved 開始占用,Pending 不占用。
理由:管理員需要在多個用途間選擇。
確認者:美玲(故事角色)
受影響:可用性查詢、唯一索引、核准 API、並行測試。
若改變:不能只改按鈕文字,要同步重看以上項目。
進一步想:如果主管說「先申請先贏」呢?

那是另一套分配政策。需確認「先」依伺服器收到、資料提交還是人工優先順序判定。先到先得也不會自動消除並行問題;排序政策與資料庫保證是兩件事。

STORY 02

第二幕|給 AI 一本薄薄的案卷

午餐前,阿哲把確認結果整理成一張「案卷」。他不再把整段聊天丟回去要求 AI 自己猜哪句最新。

【任務】設計設備借用 MVP 的核准流程。
【已確認/規格 v1】
一筆設備代表一台實體。Pending 不占用。
Approved、CheckedOut 占用。逾期不釋出。
不做未來預約、罰款、通知、自動核准。
管理員操作核准、領用、歸還;員工看自己的借用。
【技術】ASP.NET Core + PostgreSQL,版本尚待專案確認。
【本輪成果】狀態轉移表 + 不變條件 + 驗收案例。
【限制】不寫整個專案;新增假設另列,不能默默改規格。
【檢查】找出至少三個容易漏掉的失敗情境。

這就是 Context:讓這一輪判斷所需的資訊到位,而不是字數越多越好。即使留在同一個對話,也要有可引用、可更新的決策摘要。

這一輪要搜尋嗎?

美玲確認的內部政策,不需要上網找答案。若要選實際套件版本、查資料庫語法與安全設定,就查官方文件並記錄版本。本章的規則推導可以先做;不能把「AI 記得某個版本」當成部署依據。

阿哲要求更仔細地比較並行情境,卻沒有要求 AI 保證正確。推理深度能幫助分析,不能取代資料庫測試、權限測試或事實查證

停一下:換新對話會不會一定做不好?

不會。帶入核准的規格、目前程式版本、已知失敗與本輪目標,就能接手。同一對話也不等於永遠記得全部細節。工作連續性靠可交接的案卷,不靠期待 AI 自動記住。

圖解|上下文不是一袋聊天紀錄

① 事實層

已確認政策、既有系統、實際錯誤與程式版本。

② 決策層

本版採用什麼?排除什麼?為什麼?

③ 本輪任務

這次只要狀態表,不要整個專案。

④ 驗收與未知

要查什麼?要測什麼?哪些仍待確認?

第二天阿哲開了新對話。他沒有說「接著昨天做」,而是貼入案卷,附上目前要修改的服務檔及相關測試,要求先確認理解。

請先回覆:
1. 本輪會維持的三個不變條件。
2. 你仍缺少哪些資訊。
3. 你打算修改的範圍。
等範圍確認後,再產出修改。
不要把文件中的範例值當成正式環境設定。
示範回應

我會維持單設備單占用、管理員核准、狀態與稽核一起提交。目前缺少專案版本、資料存取介面及現有授權方式,因此先交付設計,不宣稱能編譯。

阿哲的審查

這個回應比「沒問題,全部完成」更可用:它說出缺口,讓下一輪有方向。若 AI 誤以為申請就占用,先修正案卷理解,別讓錯誤一路長到程式碼裡。

STORY 03

第三幕|把「不能重複借」變成能驗收的句子

「不可以重複借出。」主管點頭。阿哲追問:「兩個人同時按核准,也算嗎?」這句追問把漂亮需求變成工程問題。

ID規則可觀察的驗收結果
R1同一設備最多一筆有效占用兩筆 Pending 同時核准,最多一筆成功;另一筆衝突,不得留下核准稽核。
R2只有管理員能核准已登入員工直接呼叫核准 API 仍被拒絕,資料不變。
R3狀態與稽核一起成立稽核寫入失敗時,狀態修改也回滾。
R4逾期不等於歸還超過期限仍維持 CheckedOut,別人的核准仍失敗。
R5重試不可造成重複副作用重複歸還不新增第二筆歸還稽核。
Given P-001 有兩筆 Pending:A、B
When 兩個管理員同時核准 A 與 B
Then 只有一筆成為 Approved
And 有效占用筆數 = 1
And 只有成功者新增核准稽核
And 失敗者收到可理解的衝突訊息

這裡沒有規定 A 一定贏。先後順序可能不確定,但不變條件不能變。

停一下:畫面已隱藏「核准」按鈕,R2 就通過了嗎?

沒有。隱藏按鈕是介面體驗,後端仍須檢查登入與角色。員工也不能只靠換網址就讀到別人的紀錄;資源層級存取要另外驗證。

畫面故事板|同一個系統,三種視角

設備借用 · 員工小晴/靜態畫面示意

P-001 會議投影機

目前可申請 · 不代表送出就保留

用途:客戶提案
期望歸還:明日下午 17:00

送出申請(示意)

送出後顯示「等待管理員核准」,不能顯示「借用成功」。

設備借用 · 管理員美玲/靜態畫面示意
A · 小晴/客戶提案Pending
B · 阿凱/內部訓練Pending

兩筆都是申請,不等於設備有兩台。核准任一筆後,另一筆應更新為「設備已被占用」,而不是假裝操作沒發生。

設備借用 · 衝突發生/靜態畫面示意

這台設備已被其他申請保留

你的申請尚未核准。請重新整理設備狀態,或與管理員確認其他設備。

重新取得狀態(示意)

畫面應提供下一步,不顯示資料庫例外與其他借用者的非必要個資。

從畫面倒推驗收

小晴點申請後看見 Pending;美玲核准後看見 Approved;網路逾時時顯示「結果尚未確認」,不能直接說失敗。這三句介面文字其實都需要後端契約支撐。

STORY 04

第四幕|逾期不是新的出口

AI 提議增加一個 Overdue 狀態。美玲說:「那今天一逾期,原本那筆 CheckedOut 不就不算占用了?」

阿哲把圖重畫了。這不是所有系統的唯一設計,但符合本案:逾期是由時間推導的標籤,不是釋出設備的生命週期狀態。

Pending
尚未占用
Approved
已保留
CheckedOut
已領用,仍占用
Returned
已歸還,釋出

主路徑由左至右(小螢幕由上至下)。旁支:Pending → Rejected/Cancelled;Approved → Cancelled。CheckedOut 必須歸還,不能直接取消來掩蓋未歸還事實。

isOverdue = status == CheckedOut AND nowUtc > dueAtUtc
isOccupied = status IN (Approved, CheckedOut)

核准時必須設定未來的歸還期限;領用時再確認期限仍在未來。時間以 UTC 儲存,畫面依使用者時區顯示。剛好等於期限尚不算逾期,超過才算:邊界也要測。

停一下:改成「可預約下週一到週三」,只要加兩個日期欄位?

不夠。目前保證的是任何時刻最多一筆有效占用,不是時段不重疊。未來預約會改變衝突模型、取消政策及測試;須重新設計區間重疊約束,不能直接沿用本章索引。

雙軌圖|設備在哪裡,資料就應該說什麼

現實世界還在器材櫃替小晴保留小晴拿走美玲點收
系統紀錄PendingApprovedCheckedOutReturned
占用判定是/逾期也一樣

這張圖最重要的不是箭頭,而是「點收」。本案由管理員確認歸還,避免員工在家按下歸還,設備卻還沒回來。若以後要自助歸還,必須新增證據或待點收政策,不能默默沿用 Returned 的語意。

例外支線 · 核准了卻沒來領

Approved

設備已保留

管理員確認取消

記錄取消原因及操作人

Cancelled

釋出占用,保留歷史

管理員誤按歸還,直接把狀態改回 CheckedOut?

要先確認設備是否已被另一筆申請占用。修正不是任意倒帶;需要授權、衝突檢查與更正稽核。這是本版尚未涵蓋的管理更正流程,應另列需求。

STORY 05

第五幕|兩個請求都說:我剛剛看過,沒人借

下午兩點,阿哲看到 AI 寫出的第一版邏輯:

如果查不到有效占用:
    把這筆申請改成 Approved
    儲存

「看起來對呀?」小晴問。阿哲把兩個請求並排放在白板上。

時刻請求 A請求 B
1查詢:沒有占用
2查詢:也沒有占用
3更新 A 為 Approved
4更新 B 為 Approved

兩邊都沒有說謊,只是都用過時的觀察做決定。阿哲補上最後一道防線:

-- 設計片段:loans 的每列是一筆申請
CREATE UNIQUE INDEX ux_loans_one_active_equipment
ON loans (equipment_id)
WHERE status IN ('Approved', 'CheckedOut');

局部唯一索引只對符合條件的列要求唯一。兩筆申請可同時 Pending;一旦爭取同一設備的有效占用,資料庫不允許兩筆都成功。這是 PostgreSQL 支援的機制;此處不是已套用的 migration。官方:Partial Indexes

資料模型還需要 equipment_id、borrower_id 的非空與外鍵,status 合法值約束,以及占用/歸還階段必要時間欄位的檢查。索引只解決「最多一筆占用」,不會替你檢查管理員權限或合法狀態轉移

停一下:只要包 transaction 就不會雙重核准?

不一定。原子性確保一組修改一起成功或失敗,不代表兩個交易不會都讀到「沒有占用」。本案用唯一索引守住跨申請的不變條件,並用條件更新守住同一申請的狀態轉移。

並行分鏡|唯一索引改變的是哪一瞬間?

管理員 A
資料庫防線
管理員 B
① 將申請 A 改為 Approved
檢查 P-001 的有效占用
② 同時嘗試核准 B
③ A 寫入並提交
只能留下 1 筆有效占用
④ 若 A 已提交,B 的衝突寫入失敗

這是「A 成功提交」的一條示範時序,不是承諾 A 必勝。實際等待與錯誤時機依交易交錯而定。若 A 回滾,B 可能成功;要驗證的是最後不會出現兩筆有效占用。

防線 1 · 條件更新

守同一申請:只能由 Pending 核准,不能把 Returned 重新核准。

防線 2 · 唯一索引

守不同申請:不同 loan_id 也不能同時占用同一 equipment_id。

防線 3 · 交易

守整組操作:狀態更新與稽核不能只完成一半。

防線 4 · 授權

守操作資格:知道網址的人不等於有權核准。

四道防線各有責任,不能互相代替。前端停用按鈕可減少誤點,但不列為資料一致性的最後保證。

STORY 06

第六幕|把成功與失敗都寫進 API 契約

阿哲沒有直接叫 AI「補上錯誤處理」,而是先要求列出使用者會遇到的結果。

請依 R1–R5 設計核准 API 契約。
列出成功、未登入、無權限、找不到、
狀態已改變、設備被占用的回應。
操作人從伺服器驗證的登入身分取得,不接受 body 的角色。
請求成功重要失敗
POST /loans/{id}/approve200,回傳 Approved 與 dueAt401 未登入、403 非管理員、404 不存在、409 狀態/占用衝突、400 不合法期限
POST /loans/{id}/checkout200,回傳 CheckedOut409 非 Approved 或期限已過
POST /loans/{id}/return200,回傳 Returned409 非 CheckedOut;若已 Returned,依本案契約回 200 但不再新增稽核

以上操作都先做管理員授權;錯誤不能包含 SQL、連線資訊或其他人的個資。員工查自己的紀錄另做 borrower_id 篩選,不能信任前端傳來的 userId。

美玲又問:「我按歸還後網路斷了,再按一次呢?」這讓阿哲看見重試不是少見例外,而是正常使用情境。同一結果可重回,不代表副作用可重做。

停一下:收到逾時,可以斷言後端沒成功嗎?

不可以。可能資料已提交,只是回應沒到。先查最新狀態,或按已定義的可重試契約重送;對寄信、扣款等額外副作用還需要獨立去重設計。

請求剖面圖|按一下核准,後面其實有這些關卡

瀏覽器

送出 loanId 與歸還期限;不決定自己是不是管理員。

身分與授權

伺服器確認登入及角色;拒絕不合格操作。

應用服務

檢查輸入、執行合法轉移、組織交易。

PostgreSQL

約束有效占用;提交狀態與稽核。

回應與介面

回傳成功或可理解的衝突;畫面重新反映事實。

資料快照|成功之前與之後

資料核准之前核准提交後
loan A.statusPendingApproved
loan A.due_at尚未核准的期限管理員核准期限
有效占用數01
核准稽核01

表格是示範預期。若稽核寫入失敗,右欄不能只保留前三項;這正是交易必須保護的邊界。

可以把 actorId 放 body,方便測試?

測試可以建立測試身分或注入測試授權情境;正式操作人的來源仍應是已驗證身分。不能為了測試方便,留下使用者可偽造操作人的正式 API。

STORY 07

第七幕|這次,請 AI 寫小一點

阿哲準備請 AI 寫完整專案,想了想改成:「先做核准這一條。」小切片比較容易審查,也容易用測試推翻。

依規格 v1,先產出 ApproveLoan 的服務流程。
保留條件更新、局部唯一索引衝突處理、稽核同交易。
標明示意碼和未實作依賴。不要宣稱測試通過。
另外列出:這段程式仍不能保證什麼。
// C# 風格示意碼;不是可直接編譯的實作。
RequireAuthenticatedAdmin(actor);
ValidateFutureDueAt(dueAtUtc);
await using var tx = await db.BeginTransactionAsync();
try {
    // 參數化 SQL:
    // UPDATE loans SET status='Approved', due_at=@due
    // WHERE id=@id AND status='Pending' RETURNING id;
    var changed = await ConditionalApprove(id, dueAtUtc);
    if (!changed) {
        // 同交易查明不存在或狀態衝突;不建立稽核
        throw await NotFoundOrConflict(id);
    }
    await InsertAudit(id, "Approved", actor.Id);
    await tx.CommitAsync();
    return Approved;
}
catch (PostgresException ex)
    when (ex.SqlState == "23505"
       && ex.ConstraintName == "ux_loans_one_active_equipment") {
    await tx.RollbackAsync();
    return EquipmentOccupiedConflict;
}
// 其他例外不得偽裝成占用衝突;交易 dispose 回滾,
// 由統一錯誤處理記錄安全診斷資訊並回適當錯誤。

同一筆申請被核准兩次時,條件更新只允許從 Pending 轉移;不同申請搶同一設備時,由索引限制。稽核與更新包在同一交易,才不會留下「核准成功,稽核卻失蹤」的半套結果。

EF Core 在支援交易的 provider 上,單次 SaveChanges 通常以交易處理;本例有多個操作,必須明確保證它們使用同一連線/交易。不能因為程式出現 BeginTransaction 就假定所有 helper 都參與了它。官方:Using Transactions

未實作依賴:登入與授權、實體與 migration、資料存取 helper、HTTP mapping、連線設定、時鐘注入、完整例外處理與 integration tests。這段碼展示設計,不代表後端已完成或通過編譯。
停一下:把所有資料庫錯誤都回 409,比較安全?

不對。連線中斷、SQL 錯誤、其他約束失敗都不是「有人先借走」。只精準映射指定衝突,其餘保留可診斷性,對外不洩漏敏感細節。

資料關係圖|不要把所有東西塞進設備表

Equipment · 設備

id(主鍵)
asset_code(唯一編號)
display_name

一台設備
↓ 多筆歷史申請

Loan · 借用申請

id(主鍵)
equipment_id(外鍵)
borrower_id
status · due_at

一筆申請
↓ 多筆操作稽核

LoanAudit · 稽核

id(主鍵)
loan_id(外鍵)
action · actor_id
occurred_at

這是概念模型,不是完整建表腳本。borrower_id 與 actor_id 需對應既有身分系統;設備歷史和刪除策略也要定義。把 borrower_name 直接塞在設備表會讓歷史、身分變更與多次借用難以表達。

完整一輪 AI 協作,而不是一次生成

  1. 先要方案:「依規格產出核准流程,指出競爭條件。」
  2. 再挑反例:「兩筆不同申請同時核准,哪個機制阻止雙成功?」
  3. 縮小修改:「只補占用約束與指定衝突處理,不改未相關模組。」
  4. 要檢查證據:「列出實際執行命令與結果;未執行分開列。」
  5. 回存案卷:「更新決策、未完成清單及測試結果,不把待辦寫成完成。」

阿哲的價值不是比 AI 打字快,而是能判斷什麼問題值得追問,以及哪個答案仍缺證據。

STORY 08

第八幕|你坐到管理員的椅子上

美玲說:「程式我看不懂,但你讓我按一次,我就知道有沒有怪。」下面是只在這個網頁執行的狀態模型:不連資料庫、不登入、不寄信、不證明並行安全。它讓你看清規則造成的結果。

建議照順序按:核准 A → 核准 B → 領用 A → 時間超過期限 → 再核准 B → 歸還 A → 核准 B → 再歸還 A。

    完整走法的結果與解析

    A 核准成功,占用 P-001;B 核准衝突。A 領用後,即使逾期仍占用,B 仍失敗。A 歸還才釋出,B 此時可核准。再次歸還 A 回傳已歸還,不新增稽核,也不能釋出 B 的占用。

    最後應為 A=Returned、B=Approved、稽核 4 筆(A 核准、A 領用、A 歸還、B 核准)。讓時間前進不是使用者狀態操作,不寫入此示範的操作稽核。

    三個連續事故|你應該注意的不是成功按鈕

    事故 A · 美玲連點兩次核准

    前端可暫時停用按鈕,但第二個請求仍可能抵達。後端應只接受一次合法轉移,稽核不能加兩次。

    事故 B · 小晴逾期兩天

    畫面變成「逾期」,實體設備仍在她手上。若系統把它列為可借,這是業務規則錯誤,不是介面顏色問題。

    事故 C · A 歸還後,B 已核准,A 又重送歸還

    系統應認出 A 已 Returned;不能用「把設備設成可用」的粗略更新,誤釋出 B 的占用。

    錯誤思路:
    歸還任何借用 → equipment.available = true
    
    本案思路:
    確認這筆 loan 是否可歸還 → 轉移這筆 loan 狀態
    設備是否占用 → 根據仍有效的 loan 判定

    若實務上要保存額外快取欄位,也必須處理它與借用紀錄的一致性。本章刻意避免第二份可用性真相,先把主要規則做清楚。

    STORY 09

    第九幕|綠色勾勾,也可能只是畫出來的

    AI 交出一張測試表,每列都寫「通過」。阿哲問:「你在哪個環境、用哪個版本、執行了哪個命令?」對方若拿不出紀錄,這些勾勾只能刪掉。

    請產出測試案例,不要填入未執行的實際結果。
    每例包含前置資料、操作、預期 HTTP、資料列與稽核斷言。
    並行案例必須使用真實 PostgreSQL 的兩個獨立連線,
    不能只用前端按鈕或記憶體 fake 宣稱通過。
    測試預期證據本教材後端執行狀態
    一般核准200;Approved;一筆核准稽核未執行
    兩申請並行核准一個成功、一個 409;有效占用=1;核准稽核=1未執行
    同申請並行核准只轉移一次;只一筆核准稽核未執行
    稽核故障注入整筆回滾;仍 Pending;無稽核未執行
    員工偽造 admin 欄位403;狀態、稽核不變未執行
    歸還重試重送仍 200;歸還稽核維持一筆未執行
    期限邊界等於期限不逾期;超過才逾期;兩者都不釋出未執行

    並行測試要安排兩個工作者競爭,記錄回應、交易結果及最終資料;不要只依序呼叫兩次。使用隔離測試資料庫,不能在正式借用資料上試故障。

    停一下:模型幫自己審查三次,可以取代上述測試?

    不行。自我審查有助找遺漏,但可能反覆忽略同一假設。需要可執行的檢查、獨立觀察與失敗證據;檢查次數不是正確率證明。

    測試實驗桌|把「應該」變成能觀察的證據

    準備

    隔離 PostgreSQL
    P-001 一台
    A、B 兩筆 Pending
    兩個獨立連線

    施加動作

    協調兩個工作者競爭核准
    收集各自回應
    等待兩者完成

    觀察

    成功數 = 1
    衝突數 = 1
    有效占用 = 1
    核准稽核 = 1

    故障注入故事

    測試者故意讓稽核儲存失敗。若 API 回錯誤,但資料庫裡 A 已 Approved,表示使用者看到失敗,設備卻被保留:這不是「錯誤處理有做」,而是交易邊界有洞。

    測試紀錄樣板(不是已執行結果)
    程式 commit:
    資料庫/provider 版本:
    測試命令:
    測試資料與隔離方式:
    實際 HTTP:
    最終 loan:
    最終 audit:
    結果:未執行 / 通過 / 失敗
    失敗附件與重現方式:

    除錯 Prompt 也要有證據

    預期:稽核失敗時 loan 維持 Pending。
    實際:API 回 500,但 loan 變成 Approved。
    附上:服務方法、交易建立處、兩個 helper 的連線取得方式。
    請先提出可驗證的原因假說與檢查順序,
    不要直接重寫整個專案,也不要斷言唯一原因。

    好的診斷會檢查是否不同連線、提前提交或例外被吞掉。這些都是假說,需用程式與紀錄確認;不是因為聽起來合理就算找到原因。

    STORY 10

    第十幕|交付不是把程式壓縮寄出去

    星期五,美玲已經能說出「逾期不釋出」。阿哲準備交付,卻在舊資料中找到兩筆同設備的有效核准。若直接建立唯一索引,migration 會失敗。

    他沒有讓 AI 自動刪掉其中一筆,而是產生衝突清單,請管理員確認真實借用狀態,保留修正紀錄。技術上的重複,不代表可以替業務決定哪筆是真的。

    交付物必須讓接手者知道
    規格與決策紀錄R1–R5、角色、狀態圖、不做未來預約、尚未決定事項
    程式與資料庫版本commit、套件鎖定、migration、設定樣板;不含密碼
    測試證據環境、命令、時間、結果;未測明列,不能混入通過欄
    部署與復原備份與還原演練、既有衝突清查、暫停寫入/切換方案、失敗復原步驟
    操作與觀察核准/歸還流程、衝突訊息、錯誤監控、負責人

    正式部署還需依資料量、維護窗口與實際版本確認 migration 策略。回滾不能只是「把索引刪掉」;那會拿掉保護,必須評估舊版程式與資料相容性。

    故事的工作流程示範到此完整走完;真正系統的完成門檻仍是實作、可重現的測試及部署驗證。本教材交付的是教學,不把敘述當成執行證據。

    上線前的最後一扇門

    規格門

    業務已確認
    未知已列出

    實作門

    版本固定
    變更可追溯

    證據門

    權限與並行已測
    失敗可重現

    營運門

    備份能還原
    負責人與復原流程明確

    四扇門不是看完教學就自動變綠。本故事走完的是決策與設計示範,真正專案要拿出各門的證據。

    美玲的使用說明,只有三段也能有用

    1. 核准前:確認設備、用途與歸還期限。核准表示保留,不表示已領用。
    2. 交出時:核對實體編號後登記領用。設備編號比「黑色那台」可靠。
    3. 收回時:確認實體回來才登記歸還;異常設備狀況另記錄,不擅自宣稱可立即再借。

    「故障/維修中的設備是否能申請」是尚需新增的範圍。本版不因為故事提到實體點收,就假裝已實作完整資產維護系統。

    交接 Prompt

    依目前已確認內容產出交接摘要:
    已完成(附證據)、未完成、已知限制、部署前必要檢查。
    每項對應檔案或測試紀錄;沒有證據標註未驗證。
    另外列出明天接手者的前三個動作。
    STORY 11

    終章|你真正學到的,不是設備借用

    美玲關上器材櫃:「下次再做請假系統,是不是把設備換成假單就好?」

    阿哲笑了:「要帶走的是做事方法,不是照抄資料表。」

    故事中的動作可遷移的能力
    先問何時占用找出改變設計的未決需求
    整理案卷 v1控制 Context,區分事實、假設與建議
    要求失敗案例用反例檢驗答案,不只看成功路徑
    分開條件更新、索引與交易知道每道機制保障什麼、沒保障什麼
    要求執行證據區分建議、示意、已實作與已驗證

    這些方法也能用在 Claude;本章是示範如何與 ChatGPT 協作,不是宣稱另一個產品沒有工作流程能力。

    真正的吸收測試:不看上面,換一個規則

    新需求:小晴已領用 P-001,想延長三天。員工可以提出延期,但只有管理員可核准。若設備已逾期,仍可申請;核准前原期限不變。

    請先自行寫出:要問的問題、最小 Context、狀態/資料變更、兩個失敗情境及其可觀察斷言。不要只把「借用」換成「延期」。下方可寫草稿(不會自動儲存,離頁前請自行複製)。

    寫完再開:參考解題與 100 分人工評分規準

    20 分|找未知:問最長可延幾天、可否重複申請、誰能取消、以原期限或核准日為基準。每個真正影響設計的問題 5 分,最多 20;不能自行當成既定政策。

    20 分|Context:說明目前 CheckedOut、現有 dueAt、占用不釋出、管理員核准前期限不變。各 5 分。

    20 分|模型:延期申請與借用生命週期分開(5);保存 proposedDueAt 與原核准期限(5);核准時才更新 dueAt(5);更新與稽核同交易(5)。這是參考設計,不是唯一資料表答案。

    30 分|反例:提出「等待核准時先歸還」與「兩個管理員同時處理延期」。各 15 分:前置條件 5、預期行為 5、資料/稽核斷言 5。核准時須重新確認仍 CheckedOut;並行處理不得重複核准或覆寫較新的期限。

    10 分|證據邊界:列出需要真實後端/DB 測試(5);沒有執行結果不宣稱通過(5)。

    示範 Prompt:「依設備借用規格 v1,新增延期申請。先列未決政策,不直接實作。產出申請與借用狀態的關係、原期限更新時點,以及『先歸還後核准』『並行核准』的驗收案例。不要讓待核准申請改變有效期限。」

    解讀:90–100 表示本次回答涵蓋主要重點,仍不代表已具備實作能力;75–89 補弱項;低於 75 重讀對應場景。若先看過答案再寫,這次分數只算練習。隔天改做「取消核准」,不看答案重做,才能增加對遷移能力的信心。

    六道容易答太快的口頭追問

    設備歸還後,刪掉舊借用紀錄就能釋出?

    不應如此。Returned 已不在占用索引範圍,保留歷史才能追溯;刪資料不是狀態設計。

    兩筆 Pending 算不算資料重複?

    依本案不算。尚未占用,允許多人申請;業務上的不變條件不是『每台只能有一筆紀錄』。

    有官方文件連結,就表示這段程式用法正確?

    不表示。來源支持機制,不證明你使用同一交易、正確參數或完整例外處理;仍須檢查與執行。

    核准衝突直接自動重試,直到成功?

    不適合。設備確實被占用時,重試不會改變業務事實。應呈現衝突並更新狀態,不無限重試。

    使用者要求做系統,就能把真實員工名單放進教材?

    不能推定。教學用虛構或去識別資料;真實資料的存取、用途與分享範圍需要分別確認。

    我能背出唯一索引,就算吸收這章?

    還不夠。要能解釋它不管權限、不管合法轉移、不能直接支援未來時段預約,並能提出可驗證反例。

    加映|另一個變更,完整示範一次思考

    主管追上阿哲:「我想讓員工自己取消申請。」這次阿哲不急著加按鈕。

    阿哲:「只取消自己的 Pending,還是連 Approved 也能取消?」

    主管:「先只讓員工取消自己的 Pending。核准後找管理員。」

    阿哲:「如果你取消的同時,管理員正好核准呢?」

    主管:「只能一個成功。取消若沒成功,要讓員工知道已核准。」

    第一步 · 寫本輪 Context

    沿用規格 v1。新增:員工可取消自己的 Pending。
    Approved 的取消仍由管理員操作。
    本輪只設計員工取消,不變更核准政策。
    請列授權條件、條件更新、並行驗收與錯誤回應。

    第二步 · 得到設計,再自己檢查

    取消操作要同時確認申請所有人及 Pending。示意條件是 id=@id AND borrower_id=@actor AND status='Pending'。actor 來自已驗證登入身分。更新與取消稽核使用同一交易。

    零筆更新不能一律說取消成功;需依契約區分不可見資源與狀態衝突,並避免藉由回應洩漏他人申請。本案可對非本人資源回 404,對自己的非 Pending 回 409。

    第三步 · 用反例驗收

    情境預期
    小晴取消自己的 PendingCancelled;一筆取消稽核。
    阿凱改網址取消小晴的申請拒絕;狀態與稽核不變。
    取消與核准同時發生只有一個 Pending 轉移成功;不得同時留下兩個成功操作。
    小晴取消已領用設備拒絕;不能以取消代替歸還。

    第四步 · 對照你是否會遷移

    你不必照抄任何一句 Prompt,但應能自行找出所有權、狀態前提、並行競爭、稽核一致性。如果只想到「新增取消按鈕」,請回看請求剖面圖;若只想到 transaction,請回看四道防線。

    最終口試:用自己的話回答這三句

    ① 為什麼申請和核准不能混為一談?因為它們承擔不同業務承諾;本案只有核准開始占用。

    ② 為什麼 AI 回覆完整,仍不能直接交付?因為完整敘述不代表政策已確認、程式已執行或風險已驗證。

    ③ 換成會議室預約,哪個設計最先不能照抄?本案「任何時間只能一筆有效占用」的限制;會議室通常要處理時段重疊,需重新確認模型。