# 3D contract 草案 / 實作前確認表

## 1. 文件定位

本文件承接 [3D Plugin / 多設備單元邊界分析](plugin-multi-device-boundary-analysis.md) 與 [3D Plugin / 多設備單元決策確認表](plugin-multi-device-decision-confirmation.md)，把 3D 進入程式實作前可能需要的 Application 層 contract、DTO、測試策略與停止線整理成可逐項確認的草案。

本文件只做 contract 草案與實作前確認，不代表已同意新增程式碼、載入外部 DLL、新增 Plugin Loader、修改 `IDeviceAdapter` public contract、導入 plugin / queue 套件、修改 config schema、新增 ServiceHost / WebApi、執行 DB DDL 或接真實硬體。

## 2. 確認狀態

| 項目 | 內容 |
|---|---|
| 文件狀態 | 已確認 |
| 整理日期 | 2026-06-05 |
| 確認日期 | 2026-06-05 |
| 對應階段 | 第三階段 3D Plugin / 多設備單元 |
| 前置文件 | [3D Plugin / 多設備單元邊界分析](plugin-multi-device-boundary-analysis.md)、[3D Plugin / 多設備單元決策確認表](plugin-multi-device-decision-confirmation.md) |
| 本次目標 | 確認 3D contract 第一版候選範圍，作為進程式 repo 前的停止點 |
| 本次不做 | 不改程式、不新增專案、不載入 DLL、不新增 Plugin Loader、不改 Adapter contract、不改 config schema、不新增 ServiceHost / WebApi |
| 使用者確認 | 使用者已回覆第 10 節七項決策全部同意 |

## 3. 第一版定位

3D contract 第一版的目標，是先讓多設備單元、Resource Lock、Command Queue 與 Plugin metadata 有可討論的 Application 層 contract 候選，避免後續把資源鎖、排隊、plugin 載入與設備 adapter 邏輯直接混入 Core、Workflow node、Host 或 Controller。

第一版不應直接建立完整平台能力。更安全的順序是：

1. 先確認 contract / DTO / 測試邊界。
2. 再唯讀盤點程式 repo 可承接位置。
3. 再決定是否實作最小 in-memory / fake contract。
4. 最後才討論 Plugin Loader、DLL 載入、config schema 或正式 queue / DB 保存。

| 原則 | 說明 |
|---|---|
| Core 保持乾淨 | Core 不知道 DLL、Plugin manifest、Queue implementation 或 Resource Lock storage。 |
| Adapter contract 先不改 | 第一版不新增 `IDeviceAdapter` public method，避免破壞既有 Mock / Modbus Adapter。 |
| Application 層只做協調 contract | 可放候選 request / result / service interface，但不接真實背景服務。 |
| Infrastructure 延後 | Plugin Loader、DLL 掃描、manifest reader、DB 保存與分散式鎖都不是本次預設範圍。 |
| 測試先用 fake / in-memory | 不連 DB、不載入 DLL、不接硬體、不修改啟動方式。 |

## 4. 建議命名與 namespace

以下為程式實作前的候選命名，不代表已授權新增檔案。

| 類型 | 候選 namespace / 路徑 | 用途 |
|---|---|---|
| 多設備單元 | `HS.DeviceControl.Application.ControlUnits` | 定義 `ControlUnitId`、`StationId`、`DeviceId`、`ResourceKey` 的關係。 |
| Resource Lock | `HS.DeviceControl.Application.Resources` | 定義 lock request、result、mode、owner、release reason。 |
| Command Queue | `HS.DeviceControl.Application.Commands` | 定義 queue request、status、cancel、priority 與錯誤摘要。 |
| Plugin metadata | `HS.DeviceControl.Application.Plugins` | 定義 plugin id、version、capability、checksum 與 adapter mapping metadata。 |
| 測試 | `HS.DeviceControl.Application.Tests` | 使用 fake / in-memory 測試 contract 邊界。 |

## 5. 第一版候選檔案

| 類型 | 候選檔案 | 用途 | 是否本次立即新增 |
|---|---|---|---|
| Control Unit DTO | `src/HS.DeviceControl.Application/ControlUnits/ControlUnitDescriptor.cs` | 描述一組設備單元與底下 station / device 關係。 | 否 |
| Control Unit DTO | `src/HS.DeviceControl.Application/ControlUnits/StationDescriptor.cs` | 描述 Control Unit 內的一個操作位置。 | 否 |
| Control Unit DTO | `src/HS.DeviceControl.Application/ControlUnits/DeviceBindingDescriptor.cs` | 描述 `DeviceId` 與 `ResourceKey`、Station 的關係。 | 否 |
| Resource contract | `src/HS.DeviceControl.Application/Resources/IResourceLockService.cs` | 定義取得、釋放與查詢鎖的 contract。 | 否 |
| Resource DTO | `src/HS.DeviceControl.Application/Resources/ResourceLockRequest.cs` | 取得鎖請求。 | 否 |
| Resource DTO | `src/HS.DeviceControl.Application/Resources/ResourceLockResult.cs` | 取得鎖結果與錯誤摘要。 | 否 |
| Resource DTO | `src/HS.DeviceControl.Application/Resources/ResourceReleaseRequest.cs` | 釋放鎖請求。 | 否 |
| Resource DTO | `src/HS.DeviceControl.Application/Resources/ResourceReleaseResult.cs` | 釋放鎖結果。 | 否 |
| Resource enum | `src/HS.DeviceControl.Application/Resources/ResourceLockMode.cs` | `Exclusive` / `SharedRead` 等候選模式。 | 否 |
| Command contract | `src/HS.DeviceControl.Application/Commands/ICommandQueueService.cs` | 定義 enqueue、status、cancel contract。 | 否 |
| Command DTO | `src/HS.DeviceControl.Application/Commands/CommandQueueRequest.cs` | 排入命令請求。 | 否 |
| Command DTO | `src/HS.DeviceControl.Application/Commands/CommandQueueResult.cs` | 排入結果，包含 `QueueItemId` 與錯誤摘要。 | 否 |
| Command DTO | `src/HS.DeviceControl.Application/Commands/CommandQueueStatusQuery.cs` | 查詢 queue item 狀態。 | 否 |
| Command DTO | `src/HS.DeviceControl.Application/Commands/CommandQueueStatusResult.cs` | queue item 狀態、時間與錯誤摘要。 | 否 |
| Command DTO | `src/HS.DeviceControl.Application/Commands/CommandQueueCancelRequest.cs` | 取消排隊或執行中命令的請求。 | 否 |
| Plugin DTO | `src/HS.DeviceControl.Application/Plugins/PluginMetadata.cs` | Plugin manifest 的 read-only metadata 候選。 | 否 |
| Plugin DTO | `src/HS.DeviceControl.Application/Plugins/PluginCapabilityDescriptor.cs` | 描述支援 device type、command 或 capability。 | 否 |
| Plugin DTO | `src/HS.DeviceControl.Application/Plugins/PluginCompatibilityInfo.cs` | 描述 contract version、最低 app version 與相容性。 | 否 |
| 測試 | `tests/HS.DeviceControl.Application.Tests/*` | DTO 驗證、in-memory lock / queue fake、metadata 驗證。 | 否 |

## 6. 多設備單元 contract 草案

多設備單元第一版只描述識別與關係，不直接修改 `devices.json`、`workflows.json` 或 `appsettings.json` schema。

| DTO | 欄位草案 |
|---|---|
| `ControlUnitDescriptor` | `ControlUnitId`、`DisplayName`、`Description`、`Stations`、`Devices`、`Metadata` |
| `StationDescriptor` | `StationId`、`ControlUnitId`、`DisplayName`、`DeviceIds`、`ResourceKeys` |
| `DeviceBindingDescriptor` | `DeviceId`、`ControlUnitId`、`StationId`、`ResourceKeys`、`AdapterType`、`Metadata` |

邊界限制：

- `ControlUnitId` 不等於單一 adapter，也不等於機器 IP 或 Port。
- `StationId` 不取代 `DeviceId`，只描述位置或工作區。
- `ResourceKey` 用於後續 lock / queue，不應保存敏感連線資訊。
- 不把藥局案場專用流程或設備規則寫入 Core。

## 7. Resource Lock contract 草案

Resource Lock 第一版候選放在 Application 層，用來描述「誰要占用哪個 resource、占用多久、如何釋放」。本階段不新增 DB table，不導入分散式鎖。

| 方法 | 目的 | 第一版邊界 |
|---|---|---|
| `Acquire(ResourceLockRequest request)` | 嘗試取得 resource lock。 | 可用 in-memory fake 驗證，不寫 DB。 |
| `Release(ResourceReleaseRequest request)` | 釋放已取得的 lock。 | 需記錄 release reason，不吞錯。 |
| `GetStatus(ResourceLockStatusQuery query)` | 查詢指定 resource 是否被占用。 | read-only，不改任務狀態。 |

| DTO / enum | 欄位草案 |
|---|---|
| `ResourceLockRequest` | `ResourceKey`、`Mode`、`OwnerTaskId`、`OwnerNodeId`、`DeviceId`、`CommandName`、`RequestedAtUtc`、`TimeoutMs`、`Operator` |
| `ResourceLockResult` | `Success`、`LockId`、`ResourceKey`、`Mode`、`Acquired`、`AcquiredAtUtc`、`ExpiresAtUtc`、`Code`、`Message`、`Error` |
| `ResourceReleaseRequest` | `LockId`、`ResourceKey`、`OwnerTaskId`、`ReleaseReason`、`ReleasedAtUtc`、`Operator` |
| `ResourceReleaseResult` | `Success`、`LockId`、`ResourceKey`、`Released`、`Code`、`Message`、`Error` |
| `ResourceLockMode` | `Exclusive`、`SharedRead` |

## 8. Command Queue contract 草案

Command Queue 第一版只做可觀察、可取消、可追蹤的候選 contract，不導入外部 queue framework，也不讓 WebApi request 長時間阻塞。

| 方法 | 目的 | 第一版邊界 |
|---|---|---|
| `Enqueue(CommandQueueRequest request)` | 將設備命令排入 queue。 | 不直接操作硬體，可用 fake 驗證。 |
| `GetStatus(CommandQueueStatusQuery query)` | 查詢 queue item 狀態。 | read-only，不查 DB。 |
| `Cancel(CommandQueueCancelRequest request)` | 提出取消 queue item 請求。 | 不保證已 running 的命令一定能中止。 |

| DTO / enum | 欄位草案 |
|---|---|
| `CommandQueueRequest` | `TaskId`、`NodeId`、`DeviceId`、`CommandName`、`ResourceKey`、`Priority`、`RequestedAtUtc`、`Operator`、`CorrelationId` |
| `CommandQueueResult` | `Success`、`QueueItemId`、`Status`、`Accepted`、`Code`、`Message`、`Error` |
| `CommandQueueStatusQuery` | `QueueItemId`、`TaskId`、`DeviceId`、`IncludeError` |
| `CommandQueueStatusResult` | `Success`、`QueueItemId`、`TaskId`、`DeviceId`、`CommandName`、`Status`、`QueuedAtUtc`、`StartedAtUtc`、`EndedAtUtc`、`Error` |
| `CommandQueueCancelRequest` | `QueueItemId`、`Reason`、`Operator`、`RequestedAtUtc` |
| `CommandQueueItemStatus` | `Queued`、`Running`、`Completed`、`Failed`、`Cancelled`、`Timeout` |

## 9. Plugin metadata contract 草案

Plugin 第一版只整理 metadata / manifest 邊界，不建立 Loader、不掃描資料夾、不載入 DLL、不保存正式 DLL 路徑。

| DTO | 欄位草案 |
|---|---|
| `PluginMetadata` | `PluginId`、`DisplayName`、`Version`、`Vendor`、`Capabilities`、`Compatibility`、`Checksum`、`Metadata` |
| `PluginCapabilityDescriptor` | `CapabilityName`、`DeviceType`、`SupportedCommands`、`AdapterContractVersion` |
| `PluginCompatibilityInfo` | `MinApplicationVersion`、`TargetFramework`、`AdapterContractVersion`、`RequiresExternalDependencies` |

Plugin metadata 不應包含：

- 密碼、Token、IP、Port、完整 connection string。
- 正式 DLL 絕對路徑。
- 可被未確認 Loader 直接執行的任意程式入口。
- 案場客製流程、藥局專用規則或 UI 操作邏輯。

## 10. 七項確認表

使用者已於 2026-06-05 以以下格式確認：

```text
3D contract 確認：
1. 同意
2. 同意
3. 同意
4. 同意
5. 同意
6. 同意
7. 同意
```

| 編號 | 決策項 | 建議定案 | 同意後可進入 | 停止線 |
|---:|---|---|---|---|
| 1 | 多設備單元 contract | 同意以 `ControlUnitId` / `StationId` / `DeviceId` / `ResourceKey` 作為第一版 DTO 命名基礎。 | 可進程式 repo 結構檢查，盤點 Application 專案可承接位置。 | 不立即修改 config schema。 |
| 2 | Resource Lock contract | 同意第一版候選放在 Application 層，先做 request / result / fake 邊界。 | 可整理 lock service / DTO 的程式候選範圍。 | 不新增 DB table、不導入分散式鎖。 |
| 3 | Command Queue contract | 同意第一版候選放在 Application 層，先做 in-memory / fake contract。 | 可整理 enqueue / status / cancel contract 與測試策略。 | 不導入 queue 套件、不改啟動方式。 |
| 4 | Plugin metadata contract | 同意第一版只做 metadata / manifest DTO 候選。 | 可整理 plugin id、version、capability、checksum 與相容性欄位。 | 不建立 Loader、不載入 DLL、不保存正式 DLL 路徑。 |
| 5 | Adapter contract 穩定性 | 同意維持 `IDeviceAdapter` public contract 不變。 | 後續若需要 plugin adapter，可先用 wrapper / factory 映射。 | 未確認前不新增或改動 Adapter public method。 |
| 6 | 測試策略 | 同意第一版只做 Application.Tests 的 DTO / fake / in-memory 測試。 | 可建立不連 DB、不載入 DLL、不接硬體的測試範圍。 | 不跑真實硬體、不連正式 DB。 |
| 7 | 3D 停止線 | 同意未再次確認前不改 config schema、不新增 ServiceHost / WebApi、不改 route、不保存敏感資訊。 | 可保留 3D contract 為安全、可回退的前置節點。 | 不保存密碼、Token、IP、Port、完整 connection string。 |

## 11. 測試策略

| 測試 | 目的 | 邊界 |
|---|---|---|
| DTO 必填欄位驗證 | 確認 `ControlUnitId`、`ResourceKey`、`DeviceId`、`CommandName` 等必要欄位不可空白。 | 不載入設定檔。 |
| Resource Lock fake | 確認同一 `ResourceKey` 在 `Exclusive` 模式下不能被第二個 owner 取得。 | in-memory，不寫 DB。 |
| Resource release | 確認 release reason 可追蹤，錯誤釋放會回標準錯誤。 | 不改 Task state。 |
| Command Queue fake | 確認 enqueue 後可查 status，cancel 可標示 `Cancelled`。 | 不呼叫 Adapter `Execute()`。 |
| Plugin metadata validation | 確認 plugin id、version、capability、checksum 欄位可驗證。 | 不讀 DLL、不掃描資料夾。 |
| Sensitive data guard | 確認 metadata / resource key 不含密碼、Token、完整 connection string。 | 不保存 secret。 |

## 12. 仍需停止的項目

即使本文件七項全部同意，除非使用者另行明確授權，仍不得自動執行：

- 不載入外部 DLL。
- 不掃描 plugin 目錄。
- 不新增 Plugin Loader 程式。
- 不新增或更換 plugin framework、queue framework、DI / Host framework。
- 不修改 `IDeviceAdapter`、Core、Adapters、Infrastructure public method 簽章。
- 不修改既有 config schema 或啟動方式。
- 不新增 ServiceHost / WebApi 專案。
- 不新增 API route、controller、endpoint 或 middleware。
- 不執行 DB 寫入、DDL、ALTER TABLE 或正式 Apply。
- 不保存密碼、Token、IP、Port、完整 connection string、正式 DLL 路徑或正式環境資訊。
- 不把案場客製流程、藥局專用規則或特定設備邏輯寫入 Core。

## 13. 建議下一步

第 10 節七項決策已由使用者確認同意。建議先完成 3D 完成稽核、必要文件同步、文件 repo stage / commit / push 與部署查驗；後續若要進入「3D 程式 repo 結構檢查與實作前確認」，仍只可唯讀盤點 `HS.DeviceControl.Application` 是否適合承接 ControlUnits、Resources、Commands 與 Plugins contract，不直接修改程式。
