# MySQL DB LogWriter / TraceStore 實作前確認

## 1. 文件目的

本文件承接 [MySQL DB LogWriter / TraceStore 邊界設計](mysql-db-logwriter-tracestore-boundary-design.md)，整理 `MySqlLogWriter`、`task_log_traces` 與 `TaskTraceStore` 第一版 PoC 的實作前確認項目。

本文件只做實作前確認，不新增 table、不執行 DDL、不連真實 DB、不修改 `ILogWriter` public method 簽章、不修改 `TaskExecutionRecord` / `TaskNodeExecutionRecord` public model，也不修改 ConsoleHost 或專案啟動方式。

## 2. 目前程式狀態

| 項目 | 狀態 | 判斷 |
| --- | --- | --- |
| `ILogWriter` | 已存在 | `Write(LogEntry entry)` 可作為 DB log 寫入入口，第一版不需修改介面。 |
| `LogEntry` | 已存在 | 已包含 TaskId、NodeId、NodeName、DeviceId、CommandName、Status、RetryCount、TimeTakenMs、AdapterTimeTakenMs、DataSummary、RawRequestSummary、RawResponseSummary、MetadataSummary、ErrorCode、Message。 |
| `ConsoleLogWriter` / `FileLogWriter` / `MemoryLogWriter` | 已存在 | DB writer 應作為可選 writer，不可取代既有 writer。 |
| `MySqlTaskStore` | 已存在 | 已保存 `task_executions` 與 `node_executions`，不應再承擔詳細 trace sink。 |
| MySQL schema attribute | 已存在 | 可用 C# schema class 維護欄位、索引、描述與 SQL preview。 |
| 真實 DB manual-only 驗證 | 已存在 | 目前僅用於已確認的 TaskStore / node_executions 驗證，不可自動擴大到 trace table。 |

## 3. 本批建議目標

第一版目標是讓 DB trace 能用既有 `LogEntry` 寫入 MySQL，但不影響 Workflow 成功 / 失敗判斷。

建議範圍：

1. 新增 `task_log_traces` schema class，僅產生 SQL preview，不自動 apply。
2. 新增 `MySqlLogWriter` 第一版，承接 `ILogWriter.Write(LogEntry entry)`。
3. 新增 `LogEntry` to trace row mapper。
4. 新增 payload sanitizer，遮蔽敏感資訊並控制欄位長度。
5. 新增 fake gateway 測試，驗證 SQL 與參數，不連真實 DB。
6. 新增 writer failure 測試，確認 DB log 寫入失敗不會改變 Workflow result。
7. `TaskTraceStore` 第一版先做設計或 internal query helper；若要新增 public 查詢介面，需再次確認。

## 4. 建議資料表：task_log_traces

`task_log_traces` 定位為診斷 trace table，用於查詢任務、節點、設備命令與錯誤摘要，不取代 `task_executions` 或 `node_executions`。

### 4.1 欄位草案

| 欄位 | 型別 | 必填 | 來源 | 說明 |
| --- | --- | --- | --- | --- |
| `trace_id` | `varchar(64)` | 是 | writer 產生 | Trace 主鍵。 |
| `task_id` | `varchar(64)` | 否 | `LogEntry.TaskId` | 任務識別碼。 |
| `node_id` | `varchar(64)` | 否 | `LogEntry.NodeId` | 節點識別碼。 |
| `node_name` | `varchar(128)` | 否 | `LogEntry.NodeName` | 節點名稱。 |
| `device_id` | `varchar(64)` | 否 | `LogEntry.DeviceId` | 設備識別碼。 |
| `command_name` | `varchar(128)` | 否 | `LogEntry.CommandName` | 命令名稱。 |
| `level` | `varchar(32)` | 是 | `LogEntry.Level` | Log 等級。 |
| `status` | `varchar(32)` | 否 | `LogEntry.Status` | 節點或事件狀態。 |
| `retry_count` | `int` | 是 | `LogEntry.RetryCount` | 重試次數。 |
| `time_taken_ms` | `int` | 是 | `LogEntry.TimeTakenMs` | 節點或事件耗時。 |
| `adapter_time_taken_ms` | `int` | 是 | `LogEntry.AdapterTimeTakenMs` | Adapter 命令耗時。 |
| `error_code` | `varchar(64)` | 否 | `LogEntry.ErrorCode` | 錯誤代碼。 |
| `message` | `varchar(255)` | 否 | `LogEntry.Message` | 訊息摘要。 |
| `data_summary` | `text` | 否 | `LogEntry.DataSummary` | Adapter Data 摘要。 |
| `raw_request_summary` | `text` | 否 | `LogEntry.RawRequestSummary` | 已遮蔽 request 摘要。 |
| `raw_response_summary` | `text` | 否 | `LogEntry.RawResponseSummary` | 已遮蔽 response 摘要。 |
| `metadata_summary` | `text` | 否 | `LogEntry.MetadataSummary` | Metadata 摘要。 |
| `created_at` | `datetime` | 是 | `LogEntry.Timestamp` | Trace 建立時間。 |

### 4.2 索引草案

| Index | Columns | 用途 |
| --- | --- | --- |
| `idx_task_log_traces_task_id` | `task_id` | 查詢指定任務完整 trace。 |
| `idx_task_log_traces_node_id` | `node_id` | 查詢指定節點 trace。 |
| `idx_task_log_traces_device` | `device_id` | 查詢設備 trace。 |
| `idx_task_log_traces_command` | `command_name` | 查詢命令 trace。 |
| `idx_task_log_traces_level` | `level` | 查詢錯誤或警告等級。 |
| `idx_task_log_traces_error_code` | `error_code` | 查詢特定錯誤代碼。 |
| `idx_task_log_traces_created_at` | `created_at` | 依時間排序、稽核與後續清理。 |

## 5. MySqlLogWriter 實作邊界

| 項目 | 第一版建議 | 原因 |
| --- | --- | --- |
| 寫入入口 | 實作既有 `ILogWriter` | 不修改 Core log contract。 |
| 寫入方式 | 單筆 insert | 避免導入背景服務、queue 或批次 flush。 |
| 失敗處理 | 捕捉 DB 寫入例外並交給 fallback writer | DB log 失敗不應改變 Workflow result。 |
| fallback writer | 可選 `ILogWriter`，但需避免遞迴呼叫自己 | 保留可觀察性，避免無限遞迴。 |
| schema apply | 不自動執行 | DDL 需使用者確認。 |
| 真實 DB | 不自動連線 | 只能透過 manual-only gate 驗證。 |
| ConsoleHost | 不自動接入 | 啟動方式變更需另行確認。 |

## 6. Payload Sanitizer 規則

DB trace 不得保存未遮蔽的敏感資訊。

第一版 sanitizer 建議規則：

| 規則 | 說明 |
| --- | --- |
| 敏感字遮蔽 | key 或內容包含 password、pwd、token、secret、authorization、connectionstring 時需遮蔽。 |
| 長度限制 | `message`、`data_summary`、`raw_request_summary`、`raw_response_summary`、`metadata_summary` 需固定最大長度。 |
| Null 安全 | null 保持 null，不硬轉成空字串。 |
| 二進位摘要 | 若後續遇到 byte array，只保存長度與摘要，不保存完整大 payload。 |
| 可讀性 | 遮蔽後仍需保留 TaskId、NodeId、DeviceId、CommandName、ErrorCode 等判斷線索。 |

## 7. TaskTraceStore 第一版邊界

`TaskTraceStore` 建議不要併入 `ITaskStore`。

若第一版只做 writer，可先不新增 public 查詢介面；若要提供查詢，建議另行確認以下 public contract：

| 查詢能力 | 用途 | 是否本批自動實作 |
| --- | --- | --- |
| `FindByTaskId(taskId)` | 查詢單一任務 trace | 否，需確認 public contract。 |
| `FindByNodeId(taskId, nodeId)` | 查詢單一任務節點 trace | 否，需確認 public contract。 |
| `FindByDeviceId(deviceId, from, to)` | 查詢設備時間區間 trace | 否，需確認 public contract。 |
| `ListRecentErrors(limit)` | 查詢最近錯誤 trace | 否，需確認 public contract。 |

本批建議先完成 writer 與 schema preview，再討論查詢介面。

## 8. 測試策略

| 測試 | 類型 | 目的 |
| --- | --- | --- |
| `MySqlTaskLogTraceSchemaTests` | 自動測試 | 確認欄位、索引與描述可產生 MySQL 5.6.2 SQL preview。 |
| `LogEntryTraceRowMapperTests` | 自動測試 | 確認 `LogEntry` 欄位正確映射到 trace row。 |
| `PayloadSanitizerTests` | 自動測試 | 確認敏感資訊遮蔽與長度截斷。 |
| `MySqlLogWriterTests` | fake gateway 測試 | 確認 insert SQL 與參數正確，不連真實 DB。 |
| `MySqlLogWriterFailureTests` | fake gateway 測試 | 確認 DB 寫入失敗不會丟出影響 Workflow 的例外。 |

## 9. 真實 DB manual-only 驗證條件

完成第一版程式後，真實 DB 驗證仍需使用者明確確認，且需符合：

1. 測試 DB 已建立 `task_log_traces`。
2. 使用者確認允許本次 INSERT / SELECT / cleanup。
3. manual-only gate 已開啟。
4. 測試資料需使用固定前綴，cleanup 僅刪除本次測試資料。
5. 驗證欄位、索引、comment 與敏感資訊遮蔽結果。

## 10. 必須停下確認的項目

以下項目不得自動執行：

1. 修改 `ILogWriter`、`ITaskStore` 或新增 `TaskTraceStore` public 查詢介面。
2. 修改 `TaskExecutionRecord` / `TaskNodeExecutionRecord` public constructor 或 property。
3. 對真實 DB 執行 `CREATE TABLE`、`ALTER TABLE`、`DROP TABLE`。
4. 對真實 DB 執行未確認的 `INSERT`、`UPDATE`、`DELETE`。
5. 將 DB writer 自動接入 ConsoleHost、ServiceHost、WebApi 或正式啟動流程。
6. 導入背景佇列、批次 worker、retention job 或正式排程。
7. 新增或更換 MySQL 套件。
8. 保存未遮蔽的 password、token、secret、authorization 或完整 connection string。

## 11. 建議實作順序

建議下一步分成小批：

1. `task_log_traces` schema class 與 SQL preview 測試。
2. payload sanitizer 與 mapper。
3. `MySqlLogWriter` fake gateway 第一版。
4. writer failure fallback 測試。
5. 文件同步與進度更新。
6. 另行討論是否需要 `TaskTraceStore` public 查詢介面。
7. 使用者確認後再建立 manual-only 真實 DB 驗證節點。

## 12. 本次結論

目前專案已具備進入 `DB LogWriter / TraceStore` 第一版的前置條件，且可以先不修改 Core public contract。

建議下一步實作「`task_log_traces` schema class + payload sanitizer + `MySqlLogWriter` fake gateway 測試」，但仍不得自動建立 MySQL table、不得自動接入 ConsoleHost，也不得對真實 DB 寫入。
