# TaskTraceStore public 查詢介面實作前確認

本文件承接 [MySQL TaskTraceStore 查詢邊界設計](mysql-task-trace-store-query-boundary-design.md) 與 [第三階段前置規劃](phase-three-preplanning.md)，用來整理 `TaskTraceStore` public 查詢介面進入程式 repo 前必須先確認的範圍、命名、資料模型與驗證方式。

本文件只做實作前確認，不代表已同意新增 public interface、DTO、WebApi、ServiceHost、正式 DB 查詢、DDL、啟動流程或外部服務設定。

## 目前可用基礎

| 項目 | 狀態 | 說明 |
|---|---|---|
| `task_log_traces` schema class | 已完成 | 欄位、索引與 comment 已可由 C# class 維護。 |
| `MySqlLogWriter` 第一版 | 已完成 | 可將 `LogEntry` 映射到 `task_log_traces`。 |
| payload sanitizer | 已完成 | 可遮罩 password、token、secret、authorization 與 connection string 類資訊。 |
| fake gateway 測試 | 已完成 | 已驗證寫入映射、fallback 與錯誤處理。 |
| manual-only xUnit 入口 | 已完成 | 預設不連 DB、不寫入，需明確 gate 才會執行。 |
| 真實測試 DB 驗證 | 已完成 | 已完成 `task_log_traces` 寫入 / 查詢 / cleanup 驗證。 |
| 查詢邊界設計 | 已完成 | 已先固定 read-side 角色、查詢條件、SQL 安全與停止線。 |

## 是否建議進入 public 查詢介面

建議可以進入「實作前確認」，但不建議直接進入程式實作。

原因是 `TaskTraceStore` 會成為後續 WebApi、ServiceHost、Debug Tool 與資料庫儀表板共用的 read-side contract；如果命名、DTO、分頁、排序、遮罩規則或錯誤格式沒有先固定，後續 API 與 UI 很容易被第一版臨時模型綁住。

## 建議 public contract 邊界

| 項目 | 建議 | 備註 |
|---|---|---|
| 介面名稱 | 優先評估 `ITaskTraceStore` | 延續 `TaskStore` 命名語意；進程式 repo 前仍需檢查既有命名慣例。 |
| 職責 | 只讀 `task_log_traces` | 不改 Workflow 狀態、不寫入任務主檔、不執行 cleanup。 |
| 回傳格式 | 使用專用 `TaskTraceQueryResult` + `ErrorInfo` | 目前 Core `Result` 不是泛型；不建議為 3A 第一版新增 `Result<T>`。 |
| 查詢型態 | 第一版建議採同步 `Query(...)` | 程式 repo 既有 MySQL TaskStore / LogWriter 為同步介面；後續 WebApi / ServiceHost 再另行評估 async。 |
| DB 執行方式 | 參數化 SQL | 不接受使用者輸入直接組 table、column、order by。 |
| 使用範圍 | Infrastructure read-side | WebApi / ServiceHost / UI 只能在後續階段引用，不在本次導入。 |

## 候選 method 形狀

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

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

這個草案依 [TaskTraceStore 介面命名與 DTO 位置盤點](task-trace-store-interface-dto-location-audit.md) 調整而來。

不建議第一版使用 `Result<TaskTraceQueryResult>`，因為目前 Core 只有非泛型 `Result`。若要新增泛型 Result，會變成另一個 public contract 決策，應另案討論。

## Request model 候選欄位

| 欄位 | 必填 | 建議規則 |
|---|---:|---|
| `TaskId` | 否 | 若未提供，必須至少提供時間範圍或其他主要條件，避免全表查詢。 |
| `NodeId` | 否 | 篩選特定節點 trace。 |
| `DeviceId` | 否 | 篩選特定設備 trace。 |
| `CommandName` | 否 | 篩選特定設備命令。 |
| `Level` | 否 | 篩選 info / warning / error 類級別。 |
| `Status` | 否 | 篩選 success / failed / timeout 類狀態。 |
| `ErrorCode` | 否 | 篩選特定錯誤代碼。 |
| `CreatedFrom` | 否 | 時間範圍起點。 |
| `CreatedTo` | 否 | 時間範圍終點，不可早於 `CreatedFrom`。 |
| `Limit` | 否 | 預設 100，第一版最大建議 500。 |
| `Offset` | 否 | 預設 0，不可小於 0。 |
| `SortDescending` | 否 | 預設依 `created_at` 由新到舊。 |

## Result model 候選欄位

| 欄位 | 用途 |
|---|---|
| `Success` | 是否查詢成功。 |
| `Items` | 查回的 trace 清單。 |
| `Limit` | 本次查詢限制筆數。 |
| `Offset` | 本次查詢位移。 |
| `HasMore` | 是否仍有下一頁資料。 |
| `Error` | 失敗時使用 `ErrorInfo`。 |
| `TimeTakenMs` | 查詢耗時。 |
| `TotalCount` | 第一版建議不做，避免大量資料查詢成本過高。 |

`Items` 建議至少包含：

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

## 驗證規則

| 規則 | 建議處理 |
|---|---|
| 沒有任何查詢條件 | 回傳 validation error，不執行全表查詢。 |
| `Limit` 未填 | 使用預設 100。 |
| `Limit` 超過上限 | 回傳 validation error 或壓到最大值；建議第一版回傳錯誤。 |
| `Offset` 小於 0 | 回傳 validation error。 |
| `CreatedTo` 早於 `CreatedFrom` | 回傳 validation error。 |
| 字串條件過長 | 回傳 validation error，避免異常查詢與 log 污染。 |
| 排序欄位 | 第一版只允許 `created_at`，不開放任意欄位。 |

## 遮罩與安全規則

- read-side 不得還原已遮罩資料。
- `RawRequestSummary`、`RawResponseSummary`、`MetadataSummary` 若包含敏感字串，仍需經 sanitizer。
- 測試需覆蓋 password、token、secret、authorization、connection string 類字串。
- 不得將 DB password、Token、連線字串、IP 白名單或外部服務 Secret 寫入 repo。

## SQL 與資料庫查詢規則

- 必須使用參數化 SQL。
- table / column / order by 必須由程式白名單決定。
- 第一版不接受任意 SQL filter。
- 預設排序為 `created_at DESC`。
- 查詢 timeout 應可設定，但不得把敏感連線資訊寫入文件或 Log。
- 查詢失敗需回標準 `ErrorInfo`，保留可判斷原因的錯誤碼與訊息。

## 錯誤碼建議

| 錯誤情境 | 建議錯誤語意 |
|---|---|
| 查詢條件不合法 | `TraceQueryInvalidRequest` |
| 未提供必要篩選條件 | `TraceQueryFilterRequired` |
| DB 查詢失敗 | `TraceQueryDatabaseFailed` |
| DB timeout | `TraceQueryTimeout` |
| schema 不符合預期 | `TraceQuerySchemaMismatch` |
| 連線不可用 | `TraceQueryConnectionUnavailable` |

實際錯誤碼名稱需進程式 repo 後比對既有 `ErrorCode` 命名風格再決定。

## 測試計畫

| 測試類型 | 目的 |
|---|---|
| Request validator unit test | 驗證必要條件、分頁、時間範圍、字串長度。 |
| SQL builder fake test | 驗證 SQL 使用參數化、排序白名單與條件組合。 |
| Row mapper test | 驗證 DB row 可轉為 `TaskTraceItem`。 |
| sanitizer output test | 驗證 read-side 回傳仍不洩漏敏感資訊。 |
| fake gateway query test | 不連 DB 驗證查詢流程與錯誤處理。 |
| manual-only 真實 DB 查詢測試 | 使用者授權後，對測試 DB 執行查詢驗證；預設關閉。 |

## 停止線

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

- 新增 `ITaskTraceStore` public interface。
- 新增或固定 public DTO / model。
- 改動 `ITaskStore`、`ILogWriter` 或既有 public method 簽章。
- 導入 WebApi、ServiceHost、WinForms Debug Tool 或 UI。
- 連真實 DB 執行查詢、寫入、DDL、cleanup。
- 修改設定檔格式、啟動流程、Secret、GitHub / Cloudflare 設定。

## 決策表

| 決策項 | 建議 | 是否已定案 |
|---|---|---|
| 介面名稱 | 建議採 `ITaskTraceStore` | 待使用者確認 |
| DTO 位置 | 建議放在 `HS.DeviceControl.Core.Logging` | 待使用者確認 |
| sync / async | 第一版建議同步 `Query(TaskTraceQueryRequest request)` | 待使用者確認 |
| `TaskTraceQueryResult` | 建議採專用 result，內含 `Success`、`Items`、`Error`、`TimeTakenMs` | 待使用者確認 |
| `TotalCount` | 第一版不做，改用 `HasMore` | 待使用者確認 |
| 查詢上限 | 預設 100，最大 500 | 待使用者確認 |
| 無條件查詢 | 不允許 | 建議定案 |
| 排序欄位 | 第一版只允許 `created_at DESC` | 建議定案 |
| manual-only 真實 DB 查詢 | 只在使用者授權與 gate 開啟後執行 | 建議定案 |

## 建議下一步

程式 repo 命名與 DTO 位置盤點已完成，建議下一步由使用者確認以下 5 點：

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

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