# TaskTraceStore 介面命名與 DTO 位置盤點

本文件承接 [TaskTraceStore public 查詢介面實作前確認](task-trace-store-public-query-interface-preimplementation-checklist.md) 與 [第三階段執行儀表板](phase-three-dashboard.md)，整理程式 repo 目前的命名、Result 風格、MySQL infrastructure 分層與 sync / async 慣例。

本文件只做盤點與建議，不新增 public interface、不新增 DTO、不修改 `ITaskStore` / `ILogWriter`、不修改資料庫欄位、不連真實 DB，也不導入 WebApi / ServiceHost / WinForms Debug Tool。

## 盤點範圍

| 項目 | 盤點結果 |
|---|---|
| 程式 repo | `Hongsen-tw/hs-device-control-template` |
| 主要分支 | `poc/nmodbus-tcp` |
| 盤點日期 | 2026-06-03 |
| 盤點方式 | 讀取 Core、Tasks、Logging、Infrastructure.MySql 與對應測試檔。 |

## Core Result 與 Error 風格

| 檔案 / 類型 | 目前設計 | 對 3A 的影響 |
|---|---|---|
| `HS.DeviceControl.Core.Common.Result` | 非泛型 sealed class，包含 `Success`、`Message`、`Error`，用 `Ok()` / `Fail()` 建立結果。 | 先前草案的 `Result<TaskTraceQueryResult>` 不能直接使用；若要新增泛型 Result，會影響 public contract，需另行確認。 |
| `HS.DeviceControl.Core.Common.ErrorInfo` | 錯誤資訊包含 `Code`、`Message`、`ExceptionType`、`StackTrace`。 | Trace 查詢失敗應維持使用 `ErrorInfo`，避免只回傳 `bool` 或未整理例外。 |
| `HS.DeviceControl.Core.Common.ErrorCodes` | 目前已有 workflow、device、config、schema 類錯誤碼，尚未有 trace query 錯誤碼。 | 若要新增 `TraceQuery...` 錯誤碼，會修改 public constant，需在實作前確認。 |
| Schema 類 result | 既有 `SchemaDryRunResult`、`SchemaInitializerResult`、`SchemaInspectResult` 等專用 result 類型。 | 3A 可以採用專用 `TaskTraceQueryResult`，內含 `Success`、`Items`、`Error`、`TimeTakenMs`，比新增泛型 Result 更保守。 |

## 既有 Store 與 Logging 契約

| 類型 | 目前職責 | 對 3A 的建議 |
|---|---|---|
| `ITaskStore` | 任務執行摘要的 `Save`、`FindById`、`ListRecent`。 | 不應混入 trace 查詢，避免 TaskStore 同時承擔大量診斷資料 read-side。 |
| `InMemoryTaskStore` | 記憶體版任務摘要 store。 | 可作為同步介面與測試替身的風格參考。 |
| `ILogWriter` | 只負責 `Write(LogEntry entry)`。 | 不應增加查詢方法，否則 write-side / read-side 會混在一起。 |
| `LogEntry` | Workflow 節點與 Adapter data 的診斷摘要。 | Trace 查詢 item 應對應 `task_log_traces` 欄位，但不應直接重用 `LogEntry`，因為 `LogEntry` 是寫入模型。 |

## MySQL Infrastructure 命名慣例

| 現有類型 | 命名與分層慣例 |
|---|---|
| `MySqlTaskStore` | public store class，實作 Core 的 `ITaskStore`。 |
| `IMySqlTaskStoreGateway` | internal gateway interface，用於隔離 MySQL 連線與 fake gateway 測試。 |
| `MySqlTaskStoreSqlBuilder` | internal SQL builder，負責參數化 SQL。 |
| `MySqlTaskStoreOptions` | public options，保存 host、port、database、user、password、table、timeout、ssl mode。 |
| `MySqlLogWriter` | public writer class，實作 Core 的 `ILogWriter`。 |
| `IMySqlLogWriterGateway` | internal gateway interface，fake gateway 測試沿用此入口。 |
| `MySqlLogWriterSqlBuilder` | internal SQL builder，寫入 `task_log_traces`。 |
| `MySqlLogTraceRecord` | internal row / command model，不外露給 Core。 |
| `MySqlTaskLogTraceSchema` | internal schema class，已定義 `task_log_traces` 欄位、索引與 comment。 |

3A 建議沿用「public read-side store + internal gateway + SQL builder + row mapper + options validator」的分層，不建議把查詢 SQL 放在 ConsoleHost、測試或文件工具中。

## sync / async 盤點

目前 MySQL infrastructure 的主要 store / writer 都是同步介面：

| 類型 | 方法型態 |
|---|---|
| `ITaskStore` | `void Save(...)`、`TaskExecutionRecord FindById(...)`、`IReadOnlyList<TaskExecutionRecord> ListRecent(...)` |
| `MySqlTaskStore` | 同步呼叫 `ExecuteNonQueryBatch`、`QuerySingle`、`QueryList` |
| `ILogWriter` | `void Write(LogEntry entry)` |
| `MySqlLogWriter` | 同步呼叫 gateway 寫入 |

3A 第一版建議採同步方法，先與現有 MySQL infrastructure 一致；未來若進入 WebApi / ServiceHost，再另外評估 async public contract。

## 建議命名與放置位置

| 項目 | 建議 | 理由 |
|---|---|---|
| Core 查詢介面 | `ITaskTraceStore` | 延續 `ITaskStore` 語意，但職責清楚分成 trace read-side。 |
| Core namespace | `HS.DeviceControl.Core.Logging` | Trace 來源是 `LogEntry` / `task_log_traces`，放在 Logging 比放在 Tasks 更能避免與任務主檔混淆。 |
| Request DTO | `TaskTraceQueryRequest` | 表示查詢條件，不承擔 SQL 或 MySQL 細節。 |
| Result DTO | `TaskTraceQueryResult` | 建議使用專用 result 形狀，避免此階段新增泛型 `Result<T>`。 |
| Item DTO | `TaskTraceItem` | 表示已遮罩、可回傳給 Debug Tool / API 的 trace row。 |
| MySQL 實作 | `MySqlTaskTraceStore` | 放在 `HS.DeviceControl.Infrastructure.MySql.Logging`，查詢 `task_log_traces`。 |
| MySQL options | `MySqlTaskTraceStoreOptions` | 不直接重用 `MySqlLogWriterOptions`，避免查詢能力被寫入器命名綁住。 |
| MySQL internal helper | `IMySqlTaskTraceStoreGateway`、`MySqlTaskTraceStoreSqlBuilder`、`MySqlTaskTraceRowMapper` | 延續現有 fake gateway 與 SQL builder 測試方式。 |

## 建議 public method 草案

以下只是下一步實作前確認的建議，不代表已同意新增 public method：

```csharp
TaskTraceQueryResult Query(TaskTraceQueryRequest request);
```

不建議本階段直接使用：

```csharp
Result<TaskTraceQueryResult> Query(TaskTraceQueryRequest request);
```

原因是目前 Core 沒有泛型 `Result<T>`，若為 3A 新增泛型 Result，會變成另一個 public contract 決策，超出 Trace 查詢第一版的必要範圍。

## 建議 DTO 欄位

### `TaskTraceQueryRequest`

| 欄位 | 建議 |
|---|---|
| `TaskId` | 可選；若空白，需至少提供時間範圍或其他篩選條件。 |
| `NodeId` | 可選。 |
| `DeviceId` | 可選。 |
| `CommandName` | 可選。 |
| `Level` | 可選。 |
| `Status` | 可選。 |
| `ErrorCode` | 可選。 |
| `CreatedFrom` / `CreatedTo` | 可選；`CreatedTo` 不可早於 `CreatedFrom`。 |
| `Limit` | 預設 100，最大 500。 |
| `Offset` | 預設 0，不可小於 0。 |
| `SortDescending` | 預設 true，第一版只允許依 `created_at` 排序。 |

### `TaskTraceQueryResult`

| 欄位 | 建議 |
|---|---|
| `Success` | 是否查詢成功。 |
| `Items` | 查回的 trace 清單。 |
| `Limit` / `Offset` | 回傳本次查詢分頁資訊。 |
| `HasMore` | 建議用 `Limit + 1` 判斷，不在第一版做昂貴 `COUNT(*)`。 |
| `Error` | 失敗時使用 `ErrorInfo`。 |
| `TimeTakenMs` | 查詢耗時。 |

### `TaskTraceItem`

建議對應 `task_log_traces` 已存在欄位：

- `TraceId`
- `TaskId`
- `NodeId`
- `NodeName`
- `DeviceId`
- `CommandName`
- `Level`
- `Status`
- `RetryCount`
- `TimeTakenMs`
- `AdapterTimeTakenMs`
- `ErrorCode`
- `Message`
- `DataSummary`
- `RawRequestSummary`
- `RawResponseSummary`
- `MetadataSummary`
- `CreatedAt`

## 需要確認的 public contract 決策

| 決策 | 建議 | 是否需要使用者確認 |
|---|---|---|
| 新增 `ITaskTraceStore` | 建議新增 | 需要。 |
| DTO 放在 `Core.Logging` | 建議採用 | 需要。 |
| 採同步 `Query(...)` | 建議採用 | 需要，因為會固定 public method 簽章。 |
| `TaskTraceQueryResult` 專用 result | 建議採用 | 需要。 |
| 新增 `ErrorCodes.TraceQuery...` | 建議採用，但可延後 | 需要，因為會修改 public constant。 |
| `TotalCount` | 第一版不做 | 需要確認。 |
| 無條件查詢 | 不允許 | 建議定案。 |

## 下一步建議

建議下一步進入「ITaskTraceStore 第一版 public contract 確認」，先由使用者確認以下 5 點，再開始程式實作：

1. 允許新增 `ITaskTraceStore`。
2. 允許在 `HS.DeviceControl.Core.Logging` 新增 `TaskTraceQueryRequest`、`TaskTraceQueryResult`、`TaskTraceItem`。
3. 第一版採同步 `Query(TaskTraceQueryRequest request)`。
4. 第一版不做 `TotalCount`，改用 `HasMore`。
5. 第一版不允許無條件全表查詢。

確認後再進入 fake gateway 查詢實作；未確認前不新增 public contract。
