# ManualApplyPreview 實作前確認

本文件承接 [MySQL Schema Apply / DDL Executor 安全策略](mysql-schema-apply-ddl-executor-safety-strategy.md)、[第三階段前置規劃](phase-three-preplanning.md) 與 [第三階段執行儀表板](phase-three-dashboard.md)，用來整理第三階段 3B `ManualApplyPreview` 進入程式 repo 前必須先確認的範圍、資料模型、風險分類、輸出格式與驗證方式。

本文件只做實作前確認與後續回填，不代表已同意實作正式 DDL Executor、執行 `CREATE TABLE` / `ALTER TABLE` / `DROP`、修改 ConsoleHost 啟動流程、導入 ServiceHost / WebApi、保存 DB 密碼或連線字串。

## 1. 目前可用基礎

| 項目 | 狀態 | 說明 |
|---|---|---|
| Schema Attribute | 已完成 | `task_executions`、`node_executions`、`task_log_traces` 已可由 C# class 維護欄位、索引與 comment。 |
| SQL Generator | 已完成 | 可產生 MySQL 5.6.2 相容 SQL preview。 |
| Schema Inspector | 已完成 | 可讀取 expected / current schema；真實 MySQL metadata inspect 採 manual-only。 |
| Dry Run Planner | 已完成 | 可產生 schema 差異與 SQL preview，不執行 DDL。 |
| ConsoleHost DryRun 顯示 | 已完成 | 目前只顯示 preview 與警告，不具備 apply 能力。 |
| Apply 安全策略 | 已完成 | 已整理 gate、權限、備份、rollback、plan hash、高風險分類與停止線。 |
| 3A Trace 查詢 | 已完成 | 已完成 `ITaskTraceStore`、MySQL read-side、manual-only 查詢與 write/read/cleanup 補驗。 |

## 2. 本次 3B 目標

`ManualApplyPreview` 的目標是把「可以檢查 schema 差異」推進到「可以產生可審核的 apply plan」，但仍不執行任何 DDL。

| 目標 | 說明 |
|---|---|
| 固定 preview model | 先定義 apply plan、operation、risk、warning、plan hash 等資料邊界。 |
| 固定高風險分類 | 明確標記 DROP、MODIFY、CHANGE、縮短欄位、NOT NULL 無 default、大表 index 等風險。 |
| 固定輸出格式 | 讓 ConsoleHost / 未來 ServiceHost 能顯示可人工審核的摘要。 |
| 固定停止線 | 確認 preview 階段不得執行 DDL、不得保存敏感資訊、不得改啟動流程。 |
| 固定驗證方式 | 先以 fake schema / dry-run result 測試 preview，不連正式 DB。 |

## 3. 建議實作範圍

| 範圍 | 建議 | 備註 |
|---|---|---|
| 功能名稱 | `ManualApplyPreview` | 表示「人工審核前的 apply preview」，不是 apply executor。 |
| 主要職責 | 接收 dry-run 差異，產生 apply plan 與風險摘要 | 不直接碰 DB connection。 |
| DB 行為 | 不執行 DDL | 即使有 SQL preview，也只輸出文字與風險。 |
| 輸出對象 | ConsoleHost / 後續 ServiceHost 顯示用 | 本次不新增 ServiceHost。 |
| 儲存行為 | 第一版不寫入 `schema_apply_history` | 是否建立 history table 需另行確認。 |
| 專案位置 | 需進程式 repo 後比對現有 Schema namespace | 不在文件階段直接決定 class 位置。 |

## 4. 建議不納入本次

- 不實作正式 DDL Executor。
- 不執行 `CREATE TABLE`、`ALTER TABLE`、`DROP TABLE` 或 `DROP COLUMN`。
- 不修改正式 DB 或測試 DB。
- 不將 Apply 接入 ConsoleHost 預設啟動流程。
- 不新增 WebApi、ServiceHost、WinForms Debug Tool。
- 不建立 `schema_migrations` 或 `schema_apply_history` table。
- 不保存 DB 密碼、Token、完整 connection string 或正式環境資訊。
- 不修改既有 public method 簽章。

## 5. Input model 候選欄位

以下只作為討論草案，不是最終 public contract：

| 欄位 | 必填 | 用途 |
|---|---:|---|
| `TargetDatabaseName` | 是 | 目標 DB 名稱，輸出時只顯示 database，不顯示 host / password。 |
| `ExpectedSchema` | 是 | 由 schema class 產生的預期 schema。 |
| `CurrentSchema` | 否 | 由 inspector 讀取的目前 schema；若沒有 current schema，只能產生 limited preview。 |
| `DryRunPlan` | 是 | 既有 Dry Run Planner 產出的差異與 SQL preview。 |
| `GeneratedBy` | 否 | 產生 preview 的 operator 或 host 名稱，不得放密碼或 token。 |
| `Reason` | 否 | 人工審核原因，例如初始化測試 DB、檢查 schema 差異。 |
| `SourceCommit` | 否 | 程式 repo commit，方便追蹤 schema class 版本。 |
| `AppVersion` | 否 | Host 或工具版本。 |
| `GeneratedAt` | 否 | 產生時間，若未提供由系統填入。 |

## 6. Apply plan 候選欄位

| 欄位 | 用途 |
|---|---|
| `PlanId` | 本次 preview 識別碼，可用 deterministic 或 GUID。 |
| `Mode` | 固定為 `ManualApplyPreview`。 |
| `TargetDatabaseName` | 目標 DB 名稱，避免包含 host / password。 |
| `GeneratedAt` | 產生時間。 |
| `GeneratedBy` | 操作者或 host 名稱。 |
| `SourceCommit` | schema class 對應 commit。 |
| `Operations` | 每一個 table / column / index / comment 差異。 |
| `Warnings` | 需要人工注意但不一定阻擋 preview 的警告。 |
| `BlockedReasons` | 會阻止進一步 apply 的原因。 |
| `HighestRiskLevel` | 本次 plan 最高風險等級。 |
| `RequiresBackup` | 是否需備份。 |
| `RequiresMaintenanceWindow` | 是否建議維運窗口。 |
| `SqlPreview` | 已遮蔽且可人工審核的 SQL preview。 |
| `PlanHash` | 用於後續人工確認 token，不得寫死。 |
| `CanApply` | 第一版建議固定為 `false`，表示此功能只做 preview。 |

## 7. Operation model 候選欄位

| 欄位 | 用途 |
|---|---|
| `OperationType` | 例如 `CreateTable`、`AddColumn`、`AddIndex`、`UpdateComment`、`DropColumn`。 |
| `TableName` | 目標 table。 |
| `ObjectName` | 欄位、index 或 comment 目標名稱。 |
| `Before` | 目前 schema 摘要。 |
| `After` | 預期 schema 摘要。 |
| `SqlPreview` | 單一 operation 對應 SQL。 |
| `RiskLevel` | `Low`、`Medium`、`High`、`Critical`。 |
| `RiskReasons` | 為何判定此風險。 |
| `RequiresBackup` | 此 operation 是否需要備份。 |
| `IsDestructive` | 是否可能破壞或刪除資料。 |
| `IsBlocked` | 是否應阻止後續 apply。 |

## 8. 風險分類建議

| 操作 | 建議風險 | Preview 處理 |
|---|---|---|
| `CREATE TABLE` | Medium | 可列入 preview，標示需確認目標 DB。 |
| `ADD COLUMN nullable` | Medium | 可列入 preview。 |
| `ADD COLUMN not null with default` | High | 需提醒可能鎖表或回填成本。 |
| `ADD COLUMN not null without default` | Critical | 應列為 blocked。 |
| `ADD INDEX` | Medium / High | 小表可 Medium，大表或未知資料量應 High。 |
| `UPDATE COMMENT` | Low | 可列入 preview，但需注意 MySQL 5.6.2 comment 限制。 |
| `MODIFY COLUMN` | Critical | 應列為 blocked，需另案確認。 |
| `CHANGE COLUMN` | Critical | 應列為 blocked，需另案確認。 |
| `DROP INDEX` | High | 第一版建議 blocked。 |
| `DROP COLUMN` | Critical | 必須 blocked。 |
| `DROP TABLE` | Critical | 必須 blocked。 |
| 縮短欄位長度 | Critical | 必須 blocked。 |
| 改 nullable from true to false | High / Critical | 若無 backfill 策略，應 blocked。 |

## 9. Preview 驗證規則

| 規則 | 建議處理 |
|---|---|
| 沒有 dry-run plan | 回傳 validation error，不產生 apply preview。 |
| SQL preview 為空但有差異 | 回傳 validation error，避免 plan 不完整。 |
| 目標 DB 名稱缺少 | 回傳 validation error。 |
| operation 無 table name | 回傳 validation error。 |
| operation 包含 DROP | preview 可列出，但 `IsBlocked=true`。 |
| operation 包含 destructive keyword | `HighestRiskLevel` 至少為 `Critical`。 |
| SQL preview 含 password / token / secret / connection string | 回傳 validation error 或遮罩後加 warning；建議第一版直接擋下。 |
| plan hash 無法產生 | 回傳 error，不允許進一步人工確認。 |

## 10. Plan hash 規則

`PlanHash` 是後續人工確認 token 的基礎，需能反映本次 preview 的實際內容。

建議 hash 納入：

- `TargetDatabaseName`
- `SourceCommit`
- operation type / table / object / SQL preview
- `HighestRiskLevel`
- `BlockedReasons`
- `GeneratedAt` 是否納入需另行決定；若納入，每次 preview 都會產生不同 hash。

第一版建議先不把 DB password、host、port 或 operator 私密資訊納入 hash。

## 11. ConsoleHost 顯示草案

ConsoleHost 若後續接入 preview，建議只顯示：

| 區塊 | 內容 |
|---|---|
| Summary | mode、target database、operation count、highest risk、can apply。 |
| Blocked reasons | 為何本次不能 apply。 |
| Operations | table、object、operation type、risk、blocked。 |
| SQL preview | 可人工審核的 SQL，需遮罩敏感資訊。 |
| Warnings | 備份、維運窗口、MySQL 5.6.2 限制。 |
| Plan hash | 後續人工確認用，不代表本次會 apply。 |

ConsoleHost 顯示不得包含：

- DB password
- token / secret
- 完整 connection string
- 正式環境敏感 host 設定
- 未遮罩 exception stack trace 中的敏感資訊

## 12. 測試計畫

| 測試類型 | 目的 |
|---|---|
| Preview request validator test | 驗證缺少 dry-run plan、缺 target、operation 不完整會失敗。 |
| Risk classifier test | 驗證 DROP、MODIFY、CHANGE、縮短欄位等會被標成 Critical。 |
| Plan hash test | 驗證相同 plan 產生相同 hash，plan 改變時 hash 改變。 |
| Sensitive output test | 驗證 SQL preview / warning / error 不含 password、token、connection string。 |
| Formatter test | 驗證 ConsoleHost 顯示摘要、風險、blocked reasons 與 plan hash。 |
| No DDL execution test | 驗證 preview path 不呼叫任何 DDL executor 或 DB apply gateway。 |

## 13. 停止線

以下項目不得在未確認前執行：

- 不得實作或啟用真正 DDL executor。
- 不得對測試 DB 或正式 DB 執行 `CREATE TABLE`、`ALTER TABLE`、`DROP`。
- 不得把 `ManualApplyPreview` 接入 ConsoleHost 預設啟動流程。
- 不得新增 `schema_migrations` 或 `schema_apply_history` table。
- 不得新增 WebApi / ServiceHost / WinForms Debug Tool。
- 不得保存 DB 密碼、Token、完整 connection string 或正式環境資訊。
- 不得修改既有 public method 簽章。
- 不得把 preview 結果當成已允許 apply。

## 14. 進程式 repo 前需確認

| 決策項 | 建議 | 是否已定案 |
|---|---|---|
| 第一版是否只做 preview | 只做 `ManualApplyPreview`，不做 DDL executor | 已確認 |
| `CanApply` 第一版行為 | 固定 `false` | 已確認 |
| 風險等級 | 使用 `Low`、`Medium`、`High`、`Critical` | 已確認 |
| Critical operation | 允許列出但一律 blocked | 已確認 |
| Plan hash | 由 preview 內容產生，不含密碼與連線資訊 | 已確認 |
| ConsoleHost 接入 | 第一版只新增 formatter / demo，不改預設啟動流程 | 已確認 |
| History table | 第一版不建立、不寫入 | 已確認 |

## 15. 建議下一步

使用者已依 [3B ManualApplyPreview 決策確認表](manual-apply-preview-decision-confirmation.md) 確認以下 7 點：

1. 3B 第一版只做 `ManualApplyPreview`，不做 DDL executor。
2. 第一版 `CanApply` 固定為 `false`。
3. 風險等級採 `Low`、`Medium`、`High`、`Critical`。
4. `DROP`、`MODIFY`、`CHANGE`、縮短欄位、NOT NULL 無 default 一律列為 blocked。
5. `PlanHash` 由 preview 內容產生，不包含密碼、host、port 或完整連線資訊。
6. 若接入 ConsoleHost，第一版只顯示 preview，不改預設啟動流程。
7. 第一版不建立 `schema_apply_history` 或 `schema_migrations` table。

程式 repo 已依上述決策完成第一版 `ManualApplyPreview` 安全預覽，對應 commit `13c14ca`。後續下一步不再是結構檢查，而是整理 3B 完成稽核，或另行確認後執行真實 DB read-only preview 驗證。

## 16. 實作完成回填（2026-06-04）

| 項目 | 結果 |
|---|---|
| 程式 repo commit | `13c14ca`，`新增 ManualApplyPreview 安全預覽` |
| Preview model | 已完成 request、result、item、risk level model |
| Preview builder | 已完成 `SchemaManualApplyPreviewBuilder` |
| `CanApply` | 第一版固定 `false` |
| 風險等級 | 已使用 `Low`、`Medium`、`High`、`Critical` |
| Critical blocked | 已將危險或未知操作標為 blocked |
| `PlanHash` | 已由 preview 內容產生，不含密碼與完整連線資訊 |
| ConsoleHost | 已顯示 preview 摘要、風險、blocked、plan hash 與 SQL preview |
| History table | 未建立、未寫入 |

## 17. 驗證回填

| 驗證項目 | 結果 |
|---|---|
| Core `SchemaManualApplyPreviewBuilderTests` | 9 passed |
| ConsoleHost formatter 測試 | 15 passed |
| MySQL manual-only gate 測試 | 1 passed |
| ConsoleHost 實際輸出 | `dotnet run` 成功輸出 `PlanHash`、`CanApply=False`、`Risk=Low`、`Blocked=False` |
| 污染字串掃描 | repo 內未找到污染字串 |
| 舊命名掃描 | 未找到 `SafeCreate`、`SafeAddColumn`、`MediumAddIndex`、`ManualReviewRequired`、`CanExecuteAutomatically`、`AutoExecute` |

## 18. 後續仍需停止

- 未另行確認前，不得執行真實 DB DDL。
- 未另行確認前，不得將 `CanApply` 改成 `true`。
- 未另行確認前，不得建立 `schema_apply_history` 或 `schema_migrations` table。
- 未另行確認前，不得導入自動 Apply、rollback、WebApi、ServiceHost 或 WinForms Debug Tool。

## 19. 建議下一步

建議整理「3B 完成稽核表」，把第一版實作、驗證結果、停止線與剩餘風險一次收斂；若要進一步碰真實 DB，應另行建立 read-only preview 驗證節點。
