# MySQL TaskStore 節點 / 命令 / 詳細 log table 邊界分析

## 1. 文件目的

本文件整理 MySQL TaskStore 第一版 PoC 完成後，是否要把節點歷程、設備命令與詳細 log table 納入第二階段下一批。

本文件只做邊界分析與實作順序建議，不直接修改資料表、C# model、public method 簽章、ConsoleHost 啟動方式，也不執行真實 DB 寫入或 DDL。

## 2. 目前已完成狀態

| 項目 | 狀態 | 說明 |
| --- | --- | --- |
| `task_executions` | 已完成第一版 PoC | 已完成 Save upsert、FindById、ListRecent 與真實 DB manual-only 驗證。 |
| `TaskExecutionRecord.NodeRecords` | 已存在 | 可記錄節點摘要，包含 NodeId、NodeName、DeviceId、CommandName、Status、RetryCount、TimeTakenMs、DataSummary、MetadataSummary、NextNodeId、TransitionSummary。 |
| `WorkflowNodeExecutionSnapshot` | 已存在 | 比 `TaskNodeExecutionRecord` 更接近 Workflow 完成瞬間，包含 AdapterTimeTakenMs、RawRequestSummary、RawResponseSummary。 |
| `LogEntry` | 已存在 | 已承接 TaskId、NodeId、DeviceId、CommandName、Status、RetryCount、TimeTakenMs、AdapterTimeTakenMs、DataSummary、RawRequestSummary、RawResponseSummary、MetadataSummary、ErrorCode、Message。 |
| MySQL Schema Automation | 已完成第一輪 | 可用 C# schema class 維護欄位、索引、描述，並以 dry run 產生 SQL preview。 |

## 3. 邊界結論

建議第二階段下一批不要一次把節點、命令與詳細 log 全部實作，而是拆成三個層級：

| 層級 | 建議狀態 | 原因 |
| --- | --- | --- |
| `node_executions` | 建議優先納入下一批 | 目前 `TaskExecutionRecord.NodeRecords` 已有足夠資料，可不改 public contract 先保存節點摘要。 |
| `command_executions` | 建議先做實作前確認 | 目前最完整的 RawRequest / RawResponse 來源在 `WorkflowNodeExecutionSnapshot` 與 `LogEntry`，不是 `TaskNodeExecutionRecord`；需先決定資料來源，避免改錯模型。 |
| 詳細 log table | 建議獨立於 TaskStore 設計 | 詳細 log 屬於 Log Writer / Trace 職責，不宜塞進 TaskStore；建議後續以 DB LogWriter 或 TaskTraceStore 方式處理。 |

## 4. 為什麼不一次做完

一次完成多表持久化會同時碰到：

- 新增資料表與 schema class。
- 是否修改 `TaskNodeExecutionRecord` public constructor / property。
- 是否讓 TaskStore 直接保存 RawRequest / RawResponse。
- 是否建立交易邊界。
- 是否把詳細 log 變成任務資料的一部分。
- 是否讓 ConsoleHost / ServiceHost 啟動時自動 apply schema。

以上任一項都可能改變資料模型、public contract 或正式 DB 邊界，依 AGENTS.md 規則必須先停下確認。

## 5. 建議 table 分工

| Table | 職責 | 是否屬 TaskStore | 建議批次 |
| --- | --- | --- | --- |
| `task_executions` | 任務主檔與任務狀態摘要 | 是 | 已完成第一版 |
| `node_executions` | Workflow 節點歷程摘要 | 是 | 下一批優先 |
| `command_executions` | Adapter / Device command 執行明細 | 視資料來源決定 | 下一批後段或獨立批次 |
| `task_log_traces` | 任務相關詳細 log / trace | 否，建議屬 Log Writer | 後續批次 |
| `task_errors` | 錯誤快照與例外資訊 | 可選 | 等錯誤查詢需求明確後再做 |

## 6. `node_executions` 建議邊界

`node_executions` 可直接由 `TaskExecutionRecord.NodeRecords` 產生，因此最適合作為下一個小步。

### 6.1 建議保存欄位

| 欄位 | 來源 | 第一版建議 |
| --- | --- | --- |
| `node_execution_id` | 程式產生 | 建議用 `task_id + sequence_no` 或 Guid，需實作前確認。 |
| `task_id` | `TaskExecutionRecord.TaskId` | 必填。 |
| `sequence_no` | NodeRecords 順序 | 必填，利於重建節點順序。 |
| `node_id` | `TaskNodeExecutionRecord.NodeId` | 必填。 |
| `node_name` | `TaskNodeExecutionRecord.NodeName` | 可空。 |
| `device_id` | `TaskNodeExecutionRecord.DeviceId` | 可空。 |
| `command_name` | `TaskNodeExecutionRecord.CommandName` | 可空。 |
| `status` | `TaskNodeExecutionRecord.Status` | 必填。 |
| `retry_count` | `TaskNodeExecutionRecord.RetryCount` | 必填或預設 0。 |
| `started_at` | `TaskNodeExecutionRecord.StartedAt` | 必填。 |
| `ended_at` | `TaskNodeExecutionRecord.EndedAt` | 可空。 |
| `time_taken_ms` | `TaskNodeExecutionRecord.TimeTakenMs` | 必填或預設 0。 |
| `error_code` | `TaskNodeExecutionRecord.ErrorCode` | 可空。 |
| `error_message` | `TaskNodeExecutionRecord.ErrorMessage` | 可空。 |
| `data_summary` | `TaskNodeExecutionRecord.DataSummary` | 可空，建議 `text`。 |
| `metadata_summary` | `TaskNodeExecutionRecord.MetadataSummary` | 可空，建議 `text`。 |
| `next_node_id` | `TaskNodeExecutionRecord.NextNodeId` | 可空。 |
| `transition_summary` | `TaskNodeExecutionRecord.TransitionSummary` | 可空，建議 `text`。 |
| `created_at` | 寫入當下 | 必填。 |

### 6.2 建議索引

| Index | Columns | 用途 |
| --- | --- | --- |
| `idx_node_executions_task_id` | `task_id` | 查詢指定任務節點歷程。 |
| `idx_node_executions_task_sequence` | `task_id`, `sequence_no` | 依任務還原節點順序。 |
| `idx_node_executions_status` | `status` | 查詢失敗或執行中節點。 |
| `idx_node_executions_device` | `device_id` | 查詢某設備參與的節點。 |

### 6.3 實作注意

第一版建議只追加保存節點摘要，不要求 `FindById` / `ListRecent` 立即完整回填 `NodeRecords`。

原因是查詢還原多表資料會牽涉：

- `ITaskStore` 是否應提供「含明細」查詢模式。
- `ListRecent` 是否應載入明細，避免大量資料。
- `TaskExecutionRecord.Restore` 是否應由 Infrastructure.MySql 使用多表資料。

這些都可能影響 public contract 或效能，應另行實作前確認。

## 7. `command_executions` 邊界

`command_executions` 要保存設備命令明細，但目前資料來源需先定義。

| 候選來源 | 優點 | 風險 |
| --- | --- | --- |
| `TaskNodeExecutionRecord` | 已被 TaskStore 持有，可隨 Save 一起處理 | 目前沒有 RawRequestSummary、RawResponseSummary、AdapterTimeTakenMs。若補欄位會改 public constructor / model。 |
| `WorkflowNodeExecutionSnapshot` | 資料最完整，包含 RawRequestSummary / RawResponseSummary / AdapterTimeTakenMs | Snapshot 只在 Workflow callback 當下存在，TaskStore 目前拿不到。 |
| `LogEntry` | 已包含命令與 raw summary，可由 Log Writer 承接 | 屬 Log 流，不是 TaskStore 流；需另建 DB LogWriter 或 TraceStore。 |

建議結論：

- 若命令明細只要「每個節點一筆命令摘要」，可先從 `TaskNodeExecutionRecord` 做簡版，但不保存 RawRequest / RawResponse。
- 若命令明細要包含 RawRequest / RawResponse，建議先設計資料流，不要直接改 `TaskNodeExecutionRecord`。
- 若未來一個節點可能執行多個 Adapter command，`command_executions` 不能假設一個 node 只有一個 command。

## 8. 詳細 log table 邊界

詳細 log table 建議不要由 `MySqlTaskStore.Save` 負責。

原因：

- TaskStore 的職責是任務狀態與查詢，不是完整 log sink。
- Log 量可能遠大於 Task / Node / Command，會影響 TaskStore 查詢效能。
- 詳細 log 可能需要 level、category、message、raw payload、exception、host、operator、app version，欄位比 TaskStore 更接近 `ILogWriter`。

建議後續另立：

| 元件 | 職責 |
| --- | --- |
| `MySqlLogWriter` | 將 `LogEntry` 寫入 DB。 |
| `TaskTraceStore` | 提供依 TaskId 查詢 log trace 的讀取介面。 |
| `task_log_traces` | 保存任務相關 log / trace，不替代 file log。 |

第一版 detailed log table 建議只保存摘要與診斷欄位，不保存過大的完整 raw payload；若要保存完整 RawRequest / RawResponse，需先定義大小限制與遮蔽規則。

## 9. 交易策略建議

| 策略 | 適用情境 | 建議 |
| --- | --- | --- |
| 單表 upsert | 目前 `task_executions` 第一版 | 已完成。 |
| `task_executions` + `node_executions` 同一 transaction | 保存任務摘要與節點摘要 | 下一批建議。 |
| `task_executions` + `node_executions` + `command_executions` 同一 transaction | 命令資料來源明確後 | 後續再做。 |
| log table 獨立寫入 | 詳細 log / trace | 建議獨立，不阻塞 TaskStore Save。 |

`node_executions` 若與 `task_executions` 同批保存，建議採「先刪除同 task_id 舊節點，再插入目前 NodeRecords」或「以 task_id + sequence_no upsert」二選一。兩者都會影響 DB 寫入語意，需要實作前確認。

## 10. Schema / DDL 停止線

以下項目在使用者再次確認前不得執行：

- 建立 `node_executions`、`command_executions`、`task_log_traces` 或 `task_errors` table。
- 修改 `task_executions` 欄位、索引、comment。
- 對真實 DB 執行 `CREATE TABLE`、`ALTER TABLE`、`DROP TABLE`。
- 修改 `ITaskStore` public method 簽章。
- 修改 `TaskExecutionRecord` / `TaskNodeExecutionRecord` public constructor 或 property。
- 將 `MySqlTaskStore` 接入 ConsoleHost、ServiceHost 或 WebApi 正式啟動流程。

## 11. 建議下一批實作順序

建議下一批先做「`node_executions` 實作前確認」，範圍如下：

1. 確認 `node_executions` 欄位、索引、comment 與 C# schema class。
2. 決定 `node_execution_id` 產生規則。
3. 決定 `task_id + sequence_no` 寫入語意：delete-and-insert 或 upsert。
4. 先實作 SQL Builder / fake gateway 測試，不連真實 DB。
5. 不修改 `ITaskStore` public method 簽章。
6. 不要求 `FindById` / `ListRecent` 立即載入節點明細。
7. 完成後再討論 `command_executions` 的資料來源。

## 12. 本次建議結論

建議採用「先節點、再命令、最後詳細 log」：

1. `node_executions` 是 TaskStore 下一批最合理的小步，因為目前資料來源已在 `TaskExecutionRecord.NodeRecords`。
2. `command_executions` 需要先確認 RawRequest / RawResponse 資料來源，不宜直接改 public model。
3. 詳細 log table 應獨立走 DB LogWriter / TraceStore，不應放進 `MySqlTaskStore.Save`。

建議下一步做「MySQL TaskStore node_executions 實作前確認」，先固定欄位、索引、交易策略與測試範圍。
