# 在流程內開啟自訂 UI API

先在「流程管理 → 報名流程」設計及發佈流程，再進入該流程的「網站接入」。報名連結、嵌入代碼及自訂 UI API 都在這裡管理。新接入由 OpenDashboard 驗證、保存正式答案及推進流程；網站只負責外觀與自己的使用者身份。

## 1. 選擇填表方式

| 方式 | 設定 | 網站需要開發甚麼 |
| --- | --- | --- |
| 報名連結 | 建立入口，開放新報名，複製網址 | 放一個報名按鈕即可 |
| iframe | 複製「嵌入網站」的代碼 | 在 HTML 放入 iframe，按版面調整高度 |
| 自訂 UI | 在「自訂填表 → 開發者設定」啟用 API，保存一次顯示的金鑰 | 後端保存金鑰及每宗申請的私人憑證；前端按問題和允許操作顯示 |

三種方式可以同時使用，資料都進入此流程的「申請進度」。公開入口每次開始建立新申請；跨介面繼續同一宗申請，必須沿用原私人憑證，不能再呼叫一次新的開始請求。

iframe 使用完整填表頁，框內捲動，沒有自動高度協議。它不需要管理員登入或 API 金鑰。原有獨立活動表單、電郵、QR、簽到及網址維持原來用法。

## 表單、流程及版本的關係

進入流程的「流程設計」，新增「填寫表單」步驟後，直接在「表單欄位」建立問題，或選「使用已有表單」。

- **流程內表單**：題目在流程編輯，和流程一起儲存及發佈。
- **引用既有表單**：需要有來源表單管理權限。題目用同一套編輯器，在「編輯來源題目」開啟原表單；回到流程「檢查更新」並明確更新草稿。來源改動後未更新草稿，伺服器會阻止發佈。
- **固定版本**：發佈後的問題與規則固定。新版本不會改寫舊申請或自動更換既有報名入口的版本。新版本要建立相應入口，再按需要關閉舊入口的新報名。
- **表單列表**：預設顯示獨立及既有表單。切換「全部（含流程版本）」可找到內部版本，點擊名稱返回所屬流程。

引用只共用題目；每宗流程申請有自己的答案。它不會把答案另存進來源活動，也不觸發来源活動的確認電郵、QR 或簽到。來源活動仍按原有方式獨立運作。若要獨立修改流程題目，可「解除引用」，保留目前題目後在流程內編輯。

題型相容性會在選取時顯示，不能默默丟掉不支援的設定。測驗評分、圖片展示與圖片專用上傳設定不直接轉為流程欄位；流程可另外使用私人附件。檔案在流程使用私人上傳識別碼，不能沿用獨立表單的公開檔案 URL。包含個人資料的問題需要工作區應用已允許收集個人資料。

來源表單的引用及發佈由有權限的管理員操作；應用管理金鑰不能用引用繞過來源表單權限。外站自訂 UI 只讀取已發佈的問題，毋須解析 `form_source` 或建立第二份表單。

## 2. 金鑰與私人憑證

流程金鑰以 `odb_flow_live_` 或 `odb_flow_test_` 開頭，只能在 `/api/workflow-ui` 使用，綁定一個入口及其固定版本。它不能編輯流程、列出全部申請、讀其他流程、分配角色或執行管理員審批。不要把它當作既有的應用管理金鑰。

金鑰只放在網站後端的環境變數 `OPENDASHBOARD_WORKFLOW_KEY`，不能放在 HTML、iframe、前端程式或網址。網站後端必須核對登入使用者與申請的關係；免登入網站則需要安全的私人連結或伺服器工作階段，不能按姓名、電郵或任意申請編號認領資料。

開始前，網站後端以加密安全隨機數產生 **32 bytes 的 base64url 私人憑證（43 字元）**，持久保存後才送請求。每宗申請一個，後續全部請求使用同一憑證。不要把別人的憑證送給目前訪客。

| Header | 用途 |
| --- | --- |
| `Authorization: Bearer <workflow-key>` | 此流程入口的伺服器金鑰 |
| `X-ODB-Participant-Token: <participant-token>` | 開始及操作同一宗申請；取得問題時不需要 |
| `Content-Type: application/json` | POST JSON |

## 3. 取得問題、開始及讀取申請

下載[流程後端範例](workflow-client.mjs)，使用 Node.js 22.13 或更新版本。它只提供呼叫及驗證函式，沒有自動建立申請、開放報名或保存金鑰。與它一起部署到你的網站後端，不能直接放進前端 bundle。

先在 UI 建立一個獨立驗收流程：「須知 → 報名表 → 作品表 → 完成」。表單問題 key 以下僅為示例，實際提交必須使用 definition 回傳的 key。勾選允許「使用自己網站的填表介面」，發佈、建立入口、啟用 API；驗收入口可暫時開放，正式入口保持關閉。`open:false` 時仍能讀問題，但不能建立新申請。

```js
import { randomUUID } from 'node:crypto';
import { createWorkflowClient, newParticipantToken, startBody } from './workflow-client.mjs';
const client = createWorkflowClient(); // 從伺服器環境讀 OPENDASHBOARD_WORKFLOW_KEY
const definition = await client.definition();
// 展示 definition.introduction 的頁面；consent 必須由本人明確確認。
// checkedByUser 來自本人操作，不可自動全部勾選。
const requestBody = startBody(definition, checkedByUser);
```

**接到你的網站儲存層後才執行以下操作。** `binding` 代表網站自己的持久資料，不是 OpenDashboard 函式或可直接從瀏覽器傳入的物件：

1. 後端驗證登入或私人工作階段。
2. 在資料庫以「該使用者＋入口」建立唯一綁定，產生 `newParticipantToken()` 並加密保存；併發請求必須取得同一綁定。若產品允許多宗申請，再加入你自己的穩定申請代碼。
3. 保存入口、金鑰設定的參照、私人憑證、原始 requestBody。重試或換裝置讀回原值；不要每次產生新憑證。
4. 然後呼叫 start，成功後保存 id；結果未知時用原憑證及原正文重試。

```js
// binding.token、binding.startBody 必須已按上面步驟持久保存。
const started = await client.start(binding.token, binding.startBody);
// started.id 是申請編號；private_url 是相對路徑，例如 /w/<private-token>。
// 僅向該申請的授權使用者提供：new URL(started.private_url, trustedOrigin).href。
let current = await client.application(binding.token);
```

`GET ?action=definition` 直接回傳物件，沒有 data 包裝：`entry`、`workflow_id`、`title`、`version`、`test`、`open`（布林）、`link_days`、`attachments`、`forms`、`information_pages`、`introduction`、`resources`。每份 forms 包含 `id`（步驟 id）、`form_id`、`title`、`questions`、`submission`。

`GET ?action=application` 直接回傳 `id`、`version`、`revision`、`state`、`definition`、`current_actions`。目前步驟是 `state.current`；以它找 `definition.nodes` 中的節點。`state.forms[stepId].items` 才是該步已保存的項目，尚未開始的步驟可能不存在，請使用 `?.items || []`。每項的 `id` 用於修改時傳入 `item`，答案在 `answers`，`status` 分草稿及已提交。

開始後以 application 的固定版本及 current_actions 為準，不能以最新草稿或固定第幾頁判斷下一步。題型大致沿用[表單 UI 參考](custom-ui.md)，但流程私人附件型別是 **file**，答案是 **apu_ 上傳編號**；普通表單的 file_upload URL 格式不能搬到流程。不要把管理欄位、整份未篩選定義或其他人的資料直接交給瀏覽器。

## 4. 兩份表單串成一宗申請

例如流程設計為「隊伍資料 → 作品資料 → 資料確認」。參加者先提交隊伍資料，然後讀取新狀態，再填作品資料。管理員在同一宗申請查看兩步答案。

```js
const command = {
  operation_id: randomUUID(),
  revision: current.revision,
  action: 'submit',
  node: current.state.current,
  answers: { team_name: '示範隊伍' }
};
// command 要持久保存；逾時時原樣重試，包括 operation_id 及 revision。
const result = await client.action(binding.token, command);
// 保存 result.item；草稿後提交／編輯同一項目必須傳 item。
current = await client.application(binding.token);
if (current.current_actions.includes('continue')) {
  const nextCommand = {
    operation_id: randomUUID(), revision: current.revision,
    action: 'continue', node: current.state.current
  };
  // 呼叫前持久保存 nextCommand，結果未知時原樣重試。
  await client.action(binding.token, nextCommand);
  current = await client.application(binding.token);
}
```

欄位 key 以你在流程建立的 questions 為準。`save` 保存草稿，`submit` 正式提交。修改已有項目需帶該項目的 `item`，不可當成新項目。單次及多次提交步驟都一樣，只有 `current_actions` 包含 `continue` 時才顯示繼續；提交與繼續是兩個動作。使用同一私人憑證讀回下一步，無須再建立 run。

每個動作都要帶新的 `operation_id`、最新 `revision`、`action` 及 `node`；精確重試除外。流程角色、期限、必填、數量及分支都由伺服器檢查。參加者不能提交 `actor` 或冒充管理員。

## 5. 附件

附件沿用私人流程頁的檔案驗證與歸屬規則：

| 呼叫 | 方法及內容 |
| --- | --- |
| `?action=upload` | POST `{external_id, field, name, content_type, size, sha256}`；取得上傳位置 |
| 上傳檔案 | PUT 回傳的 upload_url；Content-Type 為實際類型，x-upsert: false；只送原始 bytes，不帶流程金鑰 |
| `?action=complete-upload&file=<upload-id>` | POST `{}`；確認完成 |
| 提交答案 | 在該步的附件欄位填 upload id |
| `?action=file&file=<upload-id>` | GET；取得目前申請可查看的附件 |

只有 OpenDashboard API 步驟帶流程金鑰和私人憑證；儲存空間 PUT 不帶兩者。`external_id` 用 4–64 字元的英數、底線或連字號；同一檔案重試使用相同 id。不可提交別隊附件。題目使用私人附件時，應用須已開啟 identified mode；配置詳見[檔案 API 參考](reference.md)。

`field` 為目前步驟的附件路徑，例如 `document` 或 `members.photo`（不帶陣列索引）。建議一律傳入；有欄位限制時不可省略。完成上傳還未保存答案，必須把回傳 id 放入 save／submit 的答案。

```js
// bytes 為後端接收及檢查過的 Buffer；externalId 在第一次上傳前持久保存。
const uploaded = await client.upload(binding.token, {
  externalId: storedUploadId, field: 'document', name: 'proposal.pdf',
  contentType: 'application/pdf', bytes
});
// current 是此步最新狀態；answers 包含本步其他完整答案，已有項目另帶 item。
const fileCommand = {
  operation_id: randomUUID(), revision: current.revision,
  node: current.state.current, action: 'save',
  answers: { ...answers, document: uploaded.id }
};
// 先持久保存 fileCommand，再呼叫；修改已有草稿時須加入原 item。
await client.action(binding.token, fileCommand);
// 保存成功且附件已在本申請可見答案中引用後，才可取得下載網址：
const download = await client.file(binding.token, uploaded.id);
// download.url 有效 60 秒。只保存 upload id，不保存短效網址。
```

上傳結果未知時，先用相同 external_id 和 metadata 取得原預約，再嘗試完成驗證；檔案可能已存在，PUT 失敗不一定代表原上傳失敗。範例會呼叫 complete-upload 核對 bytes 的大小及 SHA-256，驗證失敗才回錯誤；更換檔案則用新的 external_id。name、size、sha256 的規則見[私人附件合約](reference.md#section-9)。流程有附件規則時，保存答案還會驗證檔頭類型與總量；這不是病毒掃描或完整 PDF 安全檢查。

## 6. 停止、版本及錯誤處理 {#retry}

| 操作／情況 | 實際影響 |
| --- | --- |
| 停止新報名 | link、iframe、API 不接受新申請；已建立的私人申請仍可繼續 |
| 停用 API | 此金鑰不能讀取或提交；公開連結、iframe 和已發出的私人連結保持原狀 |
| 重新產生金鑰 | 舊金鑰立即失效；申請和私人憑證保留。需更新網站後端 |
| 發佈新版本 | 舊入口和申請保留原版本。建立新版本入口後，替換網站的連結或金鑰 |
| 網路逾時 | 結果未知。開始請求使用同一私人憑證，動作使用原 operation_id 及原內容重試 |
| `run_changed` | 先讀最新申請，保留本地輸入讓使用者核對，不能盲目覆寫 |
| `invalid_workflow_key` | 金鑰不正確、已停用、更換，或應用已停用 |
| `link_not_found` | 私人憑證不屬此入口、過期或已撤銷 |
| `entry_closed` | 尚未開放、已截止或停止新報名 |
| `invalid_answers` | 依 fields 路徑顯示錯誤，保留輸入；修正後用新 operation_id 提交 |
| `operation_id_reused` | 同一操作編號被用於不同內容；查核原操作，新動作使用新編號 |
| `invalid_upload_field` / `invalid_upload` / `upload_content_mismatch` | 核對欄位路徑、類型、大小及檔案 bytes |
| `window_closed` | 該步驟已截止或尚未開放；與入口是否接受新申請是兩項設定 |
| `custom_ui_not_allowed` | 此入口的已發佈版本不允許自訂 UI；在流程重新設定並發佈新版本 |
| `action_not_allowed` | 目前步驟或角色不允許此操作 |
| `rate_limited` | 按 Retry-After 等待後，原樣重試 |

API 回傳 `{ok:false,error,message,fields}` 錯誤格式，fields 只在有欄位錯誤時提供。只有成功回覆才顯示「已保存／已提交」。金鑰設定遇到未知結果，重新載入狀態；若未取得一次顯示的金鑰，重新產生後再接入。

## 7. 範圍

這是參加者填表 API，管理員在 OpenDashboard「申請進度」查看及確認資料。此參加者金鑰沒有全部申請匯出權限。外站副本可另用[流程資料同步](workflow-sync.md)的應用金鑰讀取與變更通知；不提供自動雙向同步、評分或排名。舊式[應用流程 API](workflows.md)保留原合約，權限較廣；新網站填表優先使用本頁的流程金鑰。

## 服務狀態與操作紀錄

流程發佈後會開啟「網站接入」。日常管理不需要選擇資料環境；既有測試流程仍保持隔離，並標示「測試流程」。頁面分成「報名連結」、「自訂填表」及「資料通知」三區。報名連結區可預覽、複製及展開嵌入代碼；金鑰及程式範例收在「自訂填表 → 開發者設定」。各區的 ⓘ 可點擊展開普通文字說明，手機及鍵盤也可使用。

- **服務中 / In Service**：此入口的自訂填表 API 已啟用，不代表已驗證外站健康或最近請求成功。新報名是否開放另行顯示。
- **成功／失敗**：最近 24 小時已通過流程金鑰驗證的 API 操作，HTTP 小於 400 算成功，其餘算失敗。讀取、保存、上傳各算一次，並非報名人數。
- **自訂填表 → 使用紀錄**：查看最近 7 天、每頁 20 筆，可只看失敗、手動重新整理及展開詳細紀錄。公開報名連結與 iframe 的申請在「申請進度」查看，不計入此 API 紀錄。
- 無效或已停用的金鑰無法安全歸屬流程，不納入紀錄。紀錄在回應完成後盡力保存，可能短暫延遲；服務中斷時可能缺漏，不是計費或完整稽核依據。
- 只保存操作類型、時間、狀態、錯誤碼及耗時，不保存金鑰、填表答案、請求內容或檔案名稱。介面只讀取最近 7 天；背景工作分批清除較早紀錄。
- **資料通知 → 傳送紀錄**：另一組紀錄，表示資料保存後通知外站是否送達，不代表填表是否成功。

查看操作紀錄需要工作區的「查看個人資料」權限。接入設定只供具備相應管理權限的使用者操作。

## 資訊頁、參考資料與同意確認 {#information}

在「流程設計 → 新增步驟 → 資訊頁」建立內容。中央編輯文字、標題、清單、連結、圖片及 PDF，右側設定「流程步驟」或「只供查閱的參考資料」。流程步驟可同時列於參考資料；兩個位置使用同一份內容。資訊頁不建立表單或回覆，也不列在表單管理。

資訊頁與流程一起儲存及發佈。已開始的申請固定原版本；既有報名入口也不會自行切換版本。上傳的資訊頁圖片／PDF 是**公開材料**，不是參加者的私人附件；請勿放入個人資料。接受 JPG、PNG、WebP 及 PDF，每檔最多 3 MB，圖片會縮圖及移除 metadata。PDF 提供獨立預覽和下載，手機不嵌入狹小文件框。移除區塊不會刪除舊版本仍引用的附件。

`GET ?action=definition` 新增以下欄位（既有 `forms` 不變）：

| 欄位 | 內容 |
| --- | --- |
| `information_pages` | `{id,title,blocks,placement,show_in_resources,button_label,consent,next?}` |
| `introduction` | 開始填表前依次顯示的資訊頁 id 陣列；從流程起點連續的資訊頁取得 |
| `resources` | 可隨時查閱的資訊頁 id 陣列；打開不改變進度 |

`blocks` 為有序陣列：`{id,type,text}`；type 包含 `paragraph`、`heading`、`subheading`、`bullets`、`numbered`、`link`、`image`、`pdf`。清單的 `text` 每行一項。連結另有 `url`；圖片／PDF 另有 `url,name,size`。請當純文字渲染，不把 text 當 HTML；連結只接受 http/https。圖片的 text 作圖片說明／替代文字。

**開始前的瀏覽不建立申請。** 網站先展示 `introduction`，最後由參加者明確點擊開始。`consent` 非空時，必須展示未預先勾選的確認欄位；單純開啟頁面、PDF 或「繼續」不代表同意。

```js
// checkedByUser 必須來自本人實際勾選；不可直接將所有項目設成 true。
const information = definition.introduction.map(id => ({
  id,
  accepted: checkedByUser[id] === true
}));
// 先持久保存這份正文和 binding.token，再呼叫：
await client.start(binding.token, { version: definition.version, information });
```

伺服器核對完整次序、入口固定版本及必要確認，才建立同一宗申請，並跳到首個非資訊頁步驟。`version` 是確認你顯示的內容版本，不允許選用另一版本。無前置資訊頁的舊流程仍可送 `{}`。逾時時保存同一私人憑證及原請求重試。`information_changed` 表示應重新讀取並展示內容；`information_confirmation_required` 表示缺少確認。

填表期間遇到 `type: "information"` 的步驟，按 `current_actions` 執行正常流程操作：

```js
await client.action(binding.token, {
  node: current.state.current,
  action: 'continue',
  accepted: checkedByUser[current.state.current] === true,
  revision: current.revision,
  operation_id: randomUUID()
});
```

只有所屬申請的參加者／聯絡人或有權限的主辦方可繼續。`state.information` 記錄 `{node,at,version,accepted}`；`accepted:false` 表示只是按繼續，不能宣稱使用者同意。實際內容由該申請不可變的 definition 取得。主辦方可在申請進度查看確認紀錄；外站的申請 export 也包含 `information`。OpenDashboard 連結、iframe 及自訂 UI 使用同一份已發佈內容與驗證規則。

## 在管理介面設定附件規則

管理員在「流程設計 → 填寫表單 → 表單欄位」選擇附件題目，使用「附件限制」設定接受的 JPG／PNG／PDF 及每檔大小（平台上限 50 MiB）。重複群組內的附件使用相同設定。在「流程設定」可選填整宗申請的附件總大小。空白表示沒有另加流程總額限制；平台既有上傳限制仍適用。

規則隨草稿儲存、隨版本發佈，不能直接改寫既有申請。正式啟用前，須與接收網站支援的格式和容量核對；OpenDashboard 的設定不會自動擴充外站儲存能力。

平台容量提升不會重寫既有流程：未設定 `upload` 的舊欄位仍採 20 MiB；要使用 50 MiB，管理員需在欄位設定限制、儲存及發佈新版本，再讓新入口使用該版本。既有申請保持原版本。外站接收端也必須能處理相同大小。

已發佈附件欄位可含 `upload: {content_types: ["application/pdf"], max_bytes: 20971520}`；流程 definition 可含 `attachments: {max_total_bytes: 52428800}`。總大小涵蓋同一宗申請所有表單項目的附件；同一檔案在兩個欄位使用也計兩次。

自訂 UI 應直接用這些規則顯示提示、限制選檔，不能另藏一套規則。`upload` 請求增加 `field`，是目前步驟的欄位路徑，如 `members.photo`，不包含行號。當目前步驟有設定附件限制時，必須提供此路徑。OpenDashboard 後端在上傳預約檢查格式與大小，在保存／提交檢查附件歸屬、檔案內容格式及全申請總大小；只改副檔名或 HTML 的 `accept` 不能繞過驗證。未設定規則的舊流程保持相容。

登入綁定仍由網站後端實作：以已驗證帳號為索引，持久保存一份加密私人憑證，建立唯一關聯後才開始申請。網絡結果未知時沿用原憑證重試；瀏覽器傳入的帳號、申請編號或電郵不能作為認領證明。這是外站接駁責任，不是 OpenDashboard 勾選一下便會完成的登入功能。


## 發佈前確認與權限 {#publication}

在「流程管理 → 流程 → 發佈版本」先確認填表入口及資料副本，再按「確認並發佈版本」。
新流程預設使用 OpenDashboard 報名頁，不啟用自訂網站填表或資料同步。既有流程沒有這份設定時保留原行為。

| 選擇 | 新版本允許的行為 | 發佈後還要完成 |
| --- | --- | --- |
| 使用 OpenDashboard 報名頁 | 從公開連結或 iframe 建立申請 | 建立此版本入口，預覽後開放報名 |
| 使用自己網站的填表介面 | 以流程金鑰及私人憑證填表 | 啟用 API，網站後端保存金鑰、綁定帳號並接入 |
| 通知我的網站，讓兩邊都有資料 | 變更通知、同步匯出及同步附件讀取 | 設定通知接收網址、簽章及後端讀取副本，回報處理結果 |

可同時勾選兩種填表方式；答案、驗證及進度仍由 OpenDashboard 主導。勾選不是接駁成功，也不會自動開放報名或發出金鑰。
在「網站接入」查看所選入口的版本與允許範圍，以及服務啟用、通知送達、外站處理結果。

管理用流程定義的可選 `publication` 為 `{hosted: true, custom_ui: false, data_sync: false}`。
三項都必須是布林值，至少一種填表方式須開啟。發佈時保存於不可變版本；修改需發佈新版本及建立新入口，舊申請及入口不受影響。
`hosted: false` 禁止該入口的公開開始申請，已發出的私人連結仍可用。
`custom_ui: false` 禁止啟用或使用該版本的流程 UI API，回傳 `custom_ui_not_allowed`。
`data_sync: false` 不排入該版本的變更通知，外站同步 export/files 端點回傳 `data_sync_not_allowed`。

這些是流程接入範圍，不會撤銷既有工作區管理員或連接應用管理金鑰的其他管理能力。
管理員 API 啟用、金鑰及資料通知設定仍須同時持有 `edit_boards` 與 `read_personal`。

## 使用連結或 iframe {#hosted}

選「使用 OpenDashboard 報名頁」並發佈，於「網站接入」建立新版本入口。
先預覽報名頁，確認問題、資訊頁及附件規則，再開放新報名。使用「複製報名連結」或展開「嵌入自己的網站」取得 iframe。
這兩種方法使用同一套 OpenDashboard 畫面，不需要啟用自訂填表 API。

## 自己的填表介面 {#custom-ui}

選「使用自己網站的填表介面」並發佈，建立新版本入口後，在「自訂填表 → 開發者設定」啟用 API。
流程金鑰只保存在網站後端；使用本頁的 definition → start → application（需要檔案時先 upload）範例接入。
網站後端驗證登入帳號，保存帳號與私人憑證的對應；不要接受瀏覽器提交的申請編號來認領資料。

同時開放 OpenDashboard 入口時，兩邊續填同一宗申請須使用同一個私人憑證及帳號對應。
若兩邊使用不同私人憑證呼叫 start，會建立不同申請；同一憑證的精確重試仍是同一宗；OpenDashboard 不會根據姓名或電郵自動合併。
只需要外站填表及該使用者查看自己的申請，不需要勾選資料副本；需要外站資料庫保存時，再看[同步教學](workflow-sync.md#copy)。


## 接入完成怎樣驗收

| 檢查 | 預期結果 |
| --- | --- |
| 只查看須知，未按開始 | 申請數不增加；缺少必要同意不建立申請 |
| 同一開始請求重試 | 相同 id，只有一宗申請 |
| 保存草稿後提交 | 帶原 item；仍只有一個項目 |
| 兩份表單依次 submit／continue | 同一申請 id，各步有自己的答案；申請可完成 |
| 必填缺漏、錯誤選項、附件超限／錯誤類型 | 失敗並顯示欄位錯誤，不宣稱成功 |
| 原操作精確重試、過期 revision | 前者不重複；後者拒絕覆寫並要求核對 |
| 另一帳戶或另一入口的私人憑證 | 網站後端拒絕帳戶越權；平台拒絕跨入口憑證 |
| 停收後繼續原申請 | 不新增申請，原申請仍依其有效期及步驟期限操作 |
| 外站副本 | 額外核對通知驗證、處理回報、去重及附件落地 |

範例及契約測試使用合成資料；你的登入、儲存層、檔案服務和接收網站仍須按此表在隔離流程驗收。服務中或 HTTP 200 不等於整個網站已驗收完成。
