
這章要學會什麼
- 畫出服務版本的五種狀態與六種合法的狀態轉換,並說出每一種轉換由誰觸發。
- 送審時就把內容拍一張「不可修改的快照」,核准時確認目前內容跟快照一致。
- 做出「不能審核自己送出的案件」「退回一定要寫理由」「已處理過的案件不能再審一次」三條規則。
- 讓兩位管理員同時按下核准時,只有一位會成功,另一位得到清楚的衝突訊息。
- 讓提供者跟管理員都看得到同一條完整的審核歷程:送審、退回(含理由)、再送審、核准、下架。
先備知識
要先完成第 5 章:送審前檢查全部通過的草稿。要知道第 3 章提到的「版本號欄位」跟「條件約束」這兩個資料庫機制,本章會實際派上用場。
觀念白話講
為什麼需要審核
會員登記的服務一旦公開,就會被包裝成 AI 看得懂的工具,讓其他會員的 AI 助理呼叫。如果不經審核就上架,可能發生:網址其實指向內部網路、規格寫得太寬鬆讓 AI 可以亂傳任何內容、說明文字跟實際行為不符。審核讓一位不是提供者本人的管理員,看著一份「已經不會再變動」的規格做決定,並且留下紀錄。
版本的狀態與轉換
| 轉換 | 誰觸發 | 前提條件 |
|---|---|---|
| 建立 → 草稿 | 提供者 | 同一支服務沒有其他草稿或審核中的版本 |
| 草稿/被退回 → 已送審 | 提供者本人 | 送審前檢查全部通過;沒有其他待審案件 |
| 已送審 → 已發布 | 管理員 | 案件待審;審核者不是送審者也不是擁有者;內容與快照一致;版本號未變 |
| 已送審 → 已退回 | 管理員 | 同上,另外必須填理由 |
| 已發布 → 已下架 | 管理員 | 必須填原因;版本號未變 |
不可變的快照:審核者看到的是「那一刻」,不是「現在」
送審那一刻,系統會把整份規格(名稱、分類、版本號、方法、網址、認證方式、兩個規格、請求範例)序列化成一段固定內容存起來,之後永遠不會再修改這一份快照。第 5 章已經讓已送審的版本無法從網頁上修改,為什麼還要多存一份快照?三個理由:
- 事後能證明審核者當初看到什麼:半年後有人問「當初核准的內容是什麼」,答案是這份快照,不是「現在資料表裡的值」。
- 防止繞過網頁直接改資料庫:有人直接用資料庫工具改掉網址,核准時系統會比對目前內容跟快照是否一致,發現不一致就拒絕核准。
- 每次送審各自留一份:被退回、修改、再送審會產生第二份快照,兩次的差異一眼就看得出來。
送審者跟審核者一定要是不同人
管理員也是會員,也可以在會員中心登記自己的服務——如果他能審核自己送出的案件,審核就只剩形式。所以系統同時檢查「審核者不是送審者」而且「審核者不是這支服務的擁有者」。
兩位管理員同時按下核准,會發生什麼事
核准表單裡藏著一個「我做決定當下看到的版本號」;兩人都是看著同一個版本號按下核准,但資料庫在真正執行更新時會用「版本號一致」當作條件——第一位管理員更新成功後,這個版本號就變了;第二位管理員送出的更新條件因此對不上任何一列,得到「這件案子剛剛已經被別人處理過,請重新整理再確認」的訊息,不會因此多產生一筆審核紀錄。這是第一道防線;第二道防線是資料庫本身的唯一性限制:一件送審案就算真的僥倖繞過版本號檢查,也不可能寫出第二筆審核紀錄。
一次核准,其實同時改了四個地方
核准一件案件要同時改:送審案件的狀態、版本的狀態與發布時間、新增一筆審核紀錄、新增一筆稽核紀錄。這四件事被包在同一次存檔裡,等於是同一個資料庫交易——任何一步失敗(例如版本號衝突),四件事全部一起回復,不會出現「案件寫了核准,但版本卻沒有真的變成已發布」這種半套狀態。
老師示範做了什麼
示範情境:一位會員送審一支服務,管理員先退回、會員修改後再送審、管理員核准;接著用兩個瀏覽器同時核准同一件案件,觀察誰會成功;最後分別從提供者與管理員兩邊看同一條審核歷程。
兩個瀏覽器同時核准同一件案件的實測結果:一個瀏覽器成功轉向待審清單、提示「已核准並發布」;另一個瀏覽器被導回案件詳細頁,提示「這件案子剛剛已被其他人處理,請重新整理後再確認」。資料庫查詢確認這件案子最終只有 1 筆審核紀錄,版本狀態正確變成已發布。
自己動手的步驟
步驟一:快照欄位與唯一性限制
幫送審案件的資料表加一個存放快照內容的欄位;另外建立兩個「有篩選條件」的唯一性限制:一是「同一個版本同時只能有一件待審案件」,二是「一件送審案件只能有一筆審核紀錄」。這種帶篩選條件的限制只對符合條件的資料生效,不影響已經結案、可以重新送審的案件。
步驟二:送審
提供者送審時:先確認這個版本是自己的、狀態必須是草稿或被退回、再重新完整跑一次送審前檢查(不能只信任頁面上「送審按鈕看起來能不能按」,因為表單可能被直接繞過送出)。都通過才把版本狀態改成已送審,並存下這一刻的完整內容快照。
步驟三:併發衝突的實作
核准或退回時,要把表單裡帶回來的「使用者當初看到的版本號」設成資料庫更新條件的比對依據(而不是用「剛剛從資料庫讀到」的版本號)——這樣「使用者看到的版本」才是真正被拿去比對的版本。存檔時如果比對失敗,要把底層丟出的技術性例外,轉換成一句使用者看得懂的提示訊息。
步驟四:審核頁、下架與歷程
核准的動作裡,「審核者是誰」一律從登入資訊取得,不會相信表單裡任何指定審核者的欄位。下架功能設計成:先顯示一個確認頁(含目前狀態、歷程、下架原因欄位),送出後只改版本狀態、寫一筆稽核紀錄——歷史資料完全不受影響。審核歷程頁面會把「送審」「核准或退回」「下架」三種不同來源的紀錄合併、依時間排序顯示,會員中心跟後臺共用同一份邏輯。
常見錯誤
| 症狀 | 原因 | 怎麼處理 |
|---|---|---|
| 按核准得到看不懂的技術性錯誤畫面 | 表單裡的版本號欄位被改壞,或編碼格式不對 | 先驗證格式是否合法,格式不對就回傳明確的「請求格式錯誤」而不是讓程式崩潰 |
| 審核頁的快照內容顯示出一堆奇怪的跳脫符號 | 顯示快照時用了過度激進的字元跳脫設定 | 改用適合顯示中文內容的跳脫設定;頁面渲染本身仍會做安全編碼,不會有安全疑慮 |
| 直接用資料庫工具替已審核的案件再寫一筆審核紀錄,被拒絕 | 唯一性限制在正常運作 | 這是預期中的保護;審核一律要透過網站流程進行 |
怎麼驗收+反向驗證
- 未核准的版本無法使用:送審後、核准前,公開詳細頁回「找不到」;核准後同一個網址變成能正常打開。
- 同一案件重複核准不會產生重複發布:兩個工作階段並行核准同一件案件,一個成功、一個得到衝突訊息;事後再核准一次會得到「已經審過,不能重複審核」。資料庫查詢這件案子的審核紀錄應該只有 1 筆。
- 退回修訂要有完整歷程:依序是送審→退回(附理由)→再送審→核准發布,對應兩筆送審案件紀錄與兩筆審核紀錄。
- 反向驗證:讓管理員自己登記並送審一支服務,再嘗試自己核准,必須得到「不能審核本人送出或擁有的服務」,版本狀態維持審核中不變。