第6章封面圖:Section 06 API上架送審與管理者審核

這章要學會什麼

  • 畫出服務版本的五種狀態與六種合法的狀態轉換,並說出每一種轉換由誰觸發。
  • 送審時就把內容拍一張「不可修改的快照」,核准時確認目前內容跟快照一致。
  • 做出「不能審核自己送出的案件」「退回一定要寫理由」「已處理過的案件不能再審一次」三條規則。
  • 讓兩位管理員同時按下核准時,只有一位會成功,另一位得到清楚的衝突訊息。
  • 讓提供者跟管理員都看得到同一條完整的審核歷程:送審、退回(含理由)、再送審、核准、下架。

先備知識

要先完成第 5 章:送審前檢查全部通過的草稿。要知道第 3 章提到的「版本號欄位」跟「條件約束」這兩個資料庫機制,本章會實際派上用場。

觀念白話講

為什麼需要審核

會員登記的服務一旦公開,就會被包裝成 AI 看得懂的工具,讓其他會員的 AI 助理呼叫。如果不經審核就上架,可能發生:網址其實指向內部網路、規格寫得太寬鬆讓 AI 可以亂傳任何內容、說明文字跟實際行為不符。審核讓一位不是提供者本人的管理員,看著一份「已經不會再變動」的規格做決定,並且留下紀錄。

版本的狀態與轉換

服務版本一生可能經過的狀態:建立成草稿→送審→(核准變成已發布,或退回打回草稿、修改後可以重新送審)→已發布的版本之後可以下架。每一條箭頭都只能透過程式裡固定的方法發生,沒有任何頁面可以直接把狀態改成別的值。
圖 6-1 服務版本一生可能經過的狀態:建立成草稿→送審→(核准變成已發布,或退回打回草稿、修改後可以重新送審)→已發布的版本之後可以下架。每一條箭頭都只能透過程式裡固定的方法發生,沒有任何頁面可以直接把狀態改成別的值。
轉換誰觸發前提條件
建立 → 草稿提供者同一支服務沒有其他草稿或審核中的版本
草稿/被退回 → 已送審提供者本人送審前檢查全部通過;沒有其他待審案件
已送審 → 已發布管理員案件待審;審核者不是送審者也不是擁有者;內容與快照一致;版本號未變
已送審 → 已退回管理員同上,另外必須填理由
已發布 → 已下架管理員必須填原因;版本號未變

不可變的快照:審核者看到的是「那一刻」,不是「現在」

送審那一刻,系統會把整份規格(名稱、分類、版本號、方法、網址、認證方式、兩個規格、請求範例)序列化成一段固定內容存起來,之後永遠不會再修改這一份快照。第 5 章已經讓已送審的版本無法從網頁上修改,為什麼還要多存一份快照?三個理由:

  • 事後能證明審核者當初看到什麼:半年後有人問「當初核准的內容是什麼」,答案是這份快照,不是「現在資料表裡的值」。
  • 防止繞過網頁直接改資料庫:有人直接用資料庫工具改掉網址,核准時系統會比對目前內容跟快照是否一致,發現不一致就拒絕核准。
  • 每次送審各自留一份:被退回、修改、再送審會產生第二份快照,兩次的差異一眼就看得出來。

送審者跟審核者一定要是不同人

管理員也是會員,也可以在會員中心登記自己的服務——如果他能審核自己送出的案件,審核就只剩形式。所以系統同時檢查「審核者不是送審者」而且「審核者不是這支服務的擁有者」。

兩位管理員同時按下核准,會發生什麼事

兩位管理員幾乎同時打開同一件案件、同時按下核准:兩人看到的「版本號」相同,但真正送到資料庫更新時,第一個人的更新成功並讓版本號往前跳;第二個人再送出更新時,資料庫發現「版本號對不上」,判定為 0 筆被更新,於是回報衝突。
圖 6-2 兩位管理員幾乎同時打開同一件案件、同時按下核准:兩人看到的「版本號」相同,但真正送到資料庫更新時,第一個人的更新成功並讓版本號往前跳;第二個人再送出更新時,資料庫發現「版本號對不上」,判定為 0 筆被更新,於是回報衝突。

核准表單裡藏著一個「我做決定當下看到的版本號」;兩人都是看著同一個版本號按下核准,但資料庫在真正執行更新時會用「版本號一致」當作條件——第一位管理員更新成功後,這個版本號就變了;第二位管理員送出的更新條件因此對不上任何一列,得到「這件案子剛剛已經被別人處理過,請重新整理再確認」的訊息,不會因此多產生一筆審核紀錄。這是第一道防線;第二道防線是資料庫本身的唯一性限制:一件送審案就算真的僥倖繞過版本號檢查,也不可能寫出第二筆審核紀錄。

一次核准,其實同時改了四個地方

核准一件案件要同時改:送審案件的狀態、版本的狀態與發布時間、新增一筆審核紀錄、新增一筆稽核紀錄。這四件事被包在同一次存檔裡,等於是同一個資料庫交易——任何一步失敗(例如版本號衝突),四件事全部一起回復,不會出現「案件寫了核准,但版本卻沒有真的變成已發布」這種半套狀態。

老師示範做了什麼

示範情境:一位會員送審一支服務,管理員先退回、會員修改後再送審、管理員核准;接著用兩個瀏覽器同時核准同一件案件,觀察誰會成功;最後分別從提供者與管理員兩邊看同一條審核歷程。

後臺待審清單:依送審時間先後排列,每一列顯示案件編號、服務與版本、送審者、送審時間,右側有進入審核頁的按鈕。
圖 6-3 後臺待審清單:依送審時間先後排列,每一列顯示案件編號、服務與版本、送審者、送審時間,右側有進入審核頁的按鈕。
審核頁:左欄直接顯示送審那一刻的快照內容(不是目前資料表裡的值);右上是「核准備註(選填)」與核准按鈕;右下是「退回理由(必填)」,理由空白送出會被擋下;最下方是這件案子目前的審核歷程。
圖 6-4 審核頁:左欄直接顯示送審那一刻的快照內容(不是目前資料表裡的值);右上是「核准備註(選填)」與核准按鈕;右下是「退回理由(必填)」,理由空白送出會被擋下;最下方是這件案子目前的審核歷程。
在提供者自己的頁面看到的審核歷程:已發布狀態下不再出現修改或送審按鈕;歷程依序是送審→退回(附理由原文)→再送審→核准發布,提供者能看到退回理由,才知道該往哪個方向修改。
圖 6-5 在提供者自己的頁面看到的審核歷程:已發布狀態下不再出現修改或送審按鈕;歷程依序是送審→退回(附理由原文)→再送審→核准發布,提供者能看到退回理由,才知道該往哪個方向修改。

兩個瀏覽器同時核准同一件案件的實測結果:一個瀏覽器成功轉向待審清單、提示「已核准並發布」;另一個瀏覽器被導回案件詳細頁,提示「這件案子剛剛已被其他人處理,請重新整理後再確認」。資料庫查詢確認這件案子最終只有 1 筆審核紀錄,版本狀態正確變成已發布。

自己動手的步驟

步驟一:快照欄位與唯一性限制

幫送審案件的資料表加一個存放快照內容的欄位;另外建立兩個「有篩選條件」的唯一性限制:一是「同一個版本同時只能有一件待審案件」,二是「一件送審案件只能有一筆審核紀錄」。這種帶篩選條件的限制只對符合條件的資料生效,不影響已經結案、可以重新送審的案件。

步驟二:送審

提供者送審時:先確認這個版本是自己的、狀態必須是草稿或被退回、再重新完整跑一次送審前檢查(不能只信任頁面上「送審按鈕看起來能不能按」,因為表單可能被直接繞過送出)。都通過才把版本狀態改成已送審,並存下這一刻的完整內容快照。

步驟三:併發衝突的實作

核准或退回時,要把表單裡帶回來的「使用者當初看到的版本號」設成資料庫更新條件的比對依據(而不是用「剛剛從資料庫讀到」的版本號)——這樣「使用者看到的版本」才是真正被拿去比對的版本。存檔時如果比對失敗,要把底層丟出的技術性例外,轉換成一句使用者看得懂的提示訊息。

常見誤區:如果表單裡的版本號欄位被竄改成不是合法格式的內容,用最直接的方式去解碼會直接讓程式崩潰、回傳難看的技術性錯誤——要先驗證格式,格式不對就回傳一個明確的「請求格式錯誤」。

步驟四:審核頁、下架與歷程

核准的動作裡,「審核者是誰」一律從登入資訊取得,不會相信表單裡任何指定審核者的欄位。下架功能設計成:先顯示一個確認頁(含目前狀態、歷程、下架原因欄位),送出後只改版本狀態、寫一筆稽核紀錄——歷史資料完全不受影響。審核歷程頁面會把「送審」「核准或退回」「下架」三種不同來源的紀錄合併、依時間排序顯示,會員中心跟後臺共用同一份邏輯。

常見錯誤

症狀原因怎麼處理
按核准得到看不懂的技術性錯誤畫面表單裡的版本號欄位被改壞,或編碼格式不對先驗證格式是否合法,格式不對就回傳明確的「請求格式錯誤」而不是讓程式崩潰
審核頁的快照內容顯示出一堆奇怪的跳脫符號顯示快照時用了過度激進的字元跳脫設定改用適合顯示中文內容的跳脫設定;頁面渲染本身仍會做安全編碼,不會有安全疑慮
直接用資料庫工具替已審核的案件再寫一筆審核紀錄,被拒絕唯一性限制在正常運作這是預期中的保護;審核一律要透過網站流程進行

怎麼驗收+反向驗證

  1. 未核准的版本無法使用:送審後、核准前,公開詳細頁回「找不到」;核准後同一個網址變成能正常打開。
  2. 同一案件重複核准不會產生重複發布:兩個工作階段並行核准同一件案件,一個成功、一個得到衝突訊息;事後再核准一次會得到「已經審過,不能重複審核」。資料庫查詢這件案子的審核紀錄應該只有 1 筆。
  3. 退回修訂要有完整歷程:依序是送審→退回(附理由)→再送審→核准發布,對應兩筆送審案件紀錄與兩筆審核紀錄。
  4. 反向驗證:讓管理員自己登記並送審一支服務,再嘗試自己核准,必須得到「不能審核本人送出或擁有的服務」,版本狀態維持審核中不變。
← 上一章 回課程地圖 下一章 →