From b54877f2400f752f5b9a1c8aef39c4aa9e851ac5 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期三, 11 三月 2026 09:54:19 +0800
Subject: [PATCH] docs: 添加WCS系统DDD重构设计文档

---
 Code/WCS/WIDESEAWCS_Server/docs/superpowers/specs/2026-03-11-wcs-ddd-refactor-design.md |  840 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 840 insertions(+), 0 deletions(-)

diff --git a/Code/WCS/WIDESEAWCS_Server/docs/superpowers/specs/2026-03-11-wcs-ddd-refactor-design.md b/Code/WCS/WIDESEAWCS_Server/docs/superpowers/specs/2026-03-11-wcs-ddd-refactor-design.md
new file mode 100644
index 0000000..2dfea6f
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/docs/superpowers/specs/2026-03-11-wcs-ddd-refactor-design.md
@@ -0,0 +1,840 @@
+# WCS绯荤粺娓愯繘寮廌DD閲嶆瀯璁捐鏂囨。
+
+**鍒涘缓鏃ユ湡**: 2026-03-11
+**鐗堟湰**: 1.0
+**鑼冨洿**: 鍏ㄧ郴缁熼噸鏋勶紙娓愯繘寮廌DD锛�
+
+## 1. 鏋舵瀯鎬昏
+
+鍩轰簬鎮ㄧ殑闇�姹傦紝鎴戝皢鎻愬嚭涓�涓�傚悎2鍛ㄦ椂闂寸獥鍙g殑娓愯繘寮廌DD閲嶆瀯鏂规銆�
+
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹�                        琛ㄧ幇灞� (API)                           鈹�
+鈹�  WIDESEAWCS_Server (ASP.NET Core Controllers)                鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+                          鈹�
+                          鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹�                        搴旂敤灞�                                 鈹�
+鈹�  搴旂敤鏈嶅姟 / DTO / 鍛戒护 / 鏌ヨ                                  鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+                          鈹�
+                          鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹�                        棰嗗煙灞� (鏂板)                          鈹�
+鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
+鈹�  鈹�  璁惧绠$悊棰嗗煙                                          鈹�   鈹�
+鈹�  鈹�  鈥� 鑱氬悎鏍�: 璁惧, 璁惧缁�, 璁惧浠诲姟                     鈹�   鈹�
+鈹�  鈹�  鈥� 瀹炰綋: 璁惧鐘舵��, 璁惧浣嶇疆, 璁惧灞炴��                 鈹�   鈹�
+鈹�  鈹�  鈥� 鍊煎璞�: 璁惧ID, 鍦板潃, 鐘舵�佹灇涓�                    鈹�   鈹�
+鈹�  鈹�  鈥� 棰嗗煙鏈嶅姟: 璁惧璋冨害鍣�, 鐘舵�佹満                      鈹�   鈹�
+鈹�  鈹�  鈥� 浠撳偍鎺ュ彛: IDeviceRepository, IDeviceTaskRepository 鈹�   鈹�
+鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
+鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
+鈹�  鈹�  浠撳偍浣滀笟棰嗗煙                                          鈹�   鈹�
+鈹�  鈹�  鈥� 鑱氬悎鏍�: 浣滀笟, 鎵樼洏, 搴撲綅                            鈹�   鈹�
+鈹�  鈹�  鈥� 棰嗗煙浜嬩欢: 浣滀笟瀹屾垚, 浣滀笟寮傚父                        鈹�   鈹�
+鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
+鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
+鈹�  鈹�  绯荤粺闆嗘垚棰嗗煙                                          鈹�   鈹�
+鈹�  鈹�  鈥� 闆嗘垚鏈嶅姟: WMS闆嗘垚, MES闆嗘垚, ERP闆嗘垚               鈹�   鈹�
+鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+                          鈹�
+                          鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹�                      鍩虹璁炬柦灞�                              鈹�
+鈹�  鈥� 浠撳偍瀹炵幇 (SqlSugar ORM)                                   鈹�
+鈹�  鈥� 閫氫俊椹卞姩 (HslCommunication)                               鈹�
+鈹�  鈥� 缂撳瓨鏈嶅姟 (Redis)                                          鈹�
+鈹�  鈥� 浠诲姟璋冨害 (Quartz.NET)                                     鈹�
+鈹�  鈥� 鏁版嵁搴撹闂� (SqlSugar)                                     鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+---
+
+## 2. 棰嗗煙灞傝璁� - 璁惧绠$悊棰嗗煙锛堟牳蹇冿級
+
+### 2.1 鑱氬悎鏍硅璁�
+
+```csharp
+// 璁惧鑱氬悎鏍�
+public class Device : AggregateRoot<DeviceId>
+{
+    // 鍩烘湰灞炴��
+    private DeviceId _id;
+    private DeviceName _name;
+    private DeviceType _type;
+    private DeviceStatus _status;
+    private DeviceAddress _address;
+    private List<DeviceProperty> _properties;
+
+    // 鐘舵�佺鐞�
+    private DateTime _lastConnectedAt;
+    private DateTime _lastHeartbeatAt;
+    private string _errorMessage;
+
+    // 棰嗗煙浜嬩欢
+    private List<IDomainEvent> _domainEvents = new();
+
+    // 琛屼负鏂规硶
+    public void Connect()
+    {
+        if (_status == DeviceStatus.Connected)
+            throw new DomainException("璁惧宸茶繛鎺�");
+
+        _status = DeviceStatus.Connected;
+        _lastConnectedAt = DateTime.UtcNow;
+        _domainEvents.Add(new DeviceConnectedEvent(_id));
+    }
+
+    public void Disconnect(string reason)
+    {
+        _status = DeviceStatus.Disconnected;
+        _errorMessage = reason;
+        _domainEvents.Add(new DeviceDisconnectedEvent(_id, reason));
+    }
+
+    public void UpdateHeartbeat()
+    {
+        _lastHeartbeatAt = DateTime.UtcNow;
+        _domainEvents.Add(new DeviceHeartbeatEvent(_id));
+    }
+
+    public void SetProperty(string key, string value)
+    {
+        var property = _properties.FirstOrDefault(p => p.Key == key);
+        if (property != null)
+            property.UpdateValue(value);
+        else
+            _properties.Add(DeviceProperty.Create(key, value));
+    }
+
+    public IReadOnlyCollection<IDomainEvent> GetDomainEvents() => _domainEvents.AsReadOnly();
+    public void ClearDomainEvents() => _domainEvents.Clear();
+}
+
+// 璁惧缁勮仛鍚堟牴
+public class DeviceGroup : AggregateRoot<DeviceGroupId>
+{
+    private DeviceGroupId _id;
+    private DeviceGroupName _name;
+    private List<DeviceId> _deviceIds;
+    private GroupStrategy _strategy;
+    private int _currentIndex;
+
+    public void AddDevice(DeviceId deviceId)
+    {
+        if (_deviceIds.Contains(deviceId))
+            throw new DomainException("璁惧宸插湪缁勫唴");
+        _deviceIds.Add(deviceId);
+    }
+
+    public void RemoveDevice(DeviceId deviceId)
+    {
+        _deviceIds.Remove(deviceId);
+    }
+
+    // 杞绛栫暐
+    public DeviceId GetNextDevice()
+    {
+        if (!_deviceIds.Any())
+            throw new DomainException("璁惧缁勪负绌�");
+
+        switch (_strategy)
+        {
+            case GroupStrategy.RoundRobin:
+                return _deviceIds[_currentIndex++ % _deviceIds.Count];
+            case GroupStrategy.Random:
+                return _deviceIds[new Random().Next(_deviceIds.Count)];
+            default:
+                return _deviceIds[0];
+        }
+    }
+}
+
+// 璁惧浠诲姟鑱氬悎鏍�
+public class DeviceTask : AggregateRoot<DeviceTaskId>
+{
+    private DeviceTaskId _id;
+    private DeviceId _deviceId;
+    private TaskType _type;
+    private TaskStatus _status;
+    private TaskPriority _priority;
+    private TaskPayload _payload;
+    private DateTime _createdAt;
+    private DateTime? _startedAt;
+    private DateTime? _completedAt;
+    private string? _errorMessage;
+    private List<IDomainEvent> _domainEvents = new();
+
+    public void Start()
+    {
+        if (_status != TaskStatus.Pending)
+            throw new DomainException("浠诲姟鐘舵�佷笉姝g‘");
+
+        _status = TaskStatus.Running;
+        _startedAt = DateTime.UtcNow;
+        _domainEvents.Add(new TaskStartedEvent(_id, _deviceId));
+    }
+
+    public void Complete()
+    {
+        if (_status != TaskStatus.Running)
+            throw new DomainException("浠诲姟鏈湪杩愯涓�");
+
+        _status = TaskStatus.Completed;
+        _completedAt = DateTime.UtcNow;
+        _domainEvents.Add(new TaskCompletedEvent(_id, _deviceId));
+    }
+
+    public void Fail(string errorMessage)
+    {
+        _status = TaskStatus.Failed;
+        _errorMessage = errorMessage;
+        _completedAt = DateTime.UtcNow;
+        _domainEvents.Add(new TaskFailedEvent(_id, _deviceId, errorMessage));
+    }
+
+    public IReadOnlyCollection<IDomainEvent> GetDomainEvents() => _domainEvents.AsReadOnly();
+    public void ClearDomainEvents() => _domainEvents.Clear();
+}
+```
+
+### 2.2 鍊煎璞¤璁�
+
+```csharp
+// 璁惧ID鍊煎璞�
+public record DeviceId(Guid Value)
+{
+    public static DeviceId New() => new DeviceId(Guid.NewGuid());
+    public static DeviceId From(Guid value) => new DeviceId(value);
+}
+
+// 璁惧鍚嶇О鍊煎璞�
+public record DeviceName(string Value)
+{
+    public DeviceName(string value)
+    {
+        if (string.IsNullOrWhiteSpace(value) || value.Length > 100)
+            throw new ArgumentException("璁惧鍚嶇О鏃犳晥");
+        Value = value;
+    }
+}
+
+// 璁惧绫诲瀷鏋氫妇
+public enum DeviceType
+{
+    StackerCrane,    // 鍫嗗灈鏈�
+    ConveyorLine,    // 杈撻�佺嚎
+    ShuttleCar,      // 绌挎杞�
+    Robot,           // 鏈烘鎵�
+    AGV              // 鑷姩瀵煎紩杞�
+}
+
+// 璁惧鐘舵�佹灇涓�
+public enum DeviceStatus
+{
+    Disconnected,    // 鏈繛鎺�
+    Connecting,      // 杩炴帴涓�
+    Connected,       // 宸茶繛鎺�
+    Busy,            // 蹇欑
+    Error,           // 閿欒
+    Maintenance      // 缁存姢涓�
+}
+
+// 璁惧鍦板潃鍊煎璞�
+public record DeviceAddress(string Ip, int Port)
+{
+    public DeviceAddress(string ip, int port)
+    {
+        if (!IPAddress.TryParse(ip, out _))
+            throw new ArgumentException("IP鍦板潃鏃犳晥");
+        if (port < 1 || port > 65535)
+            throw new ArgumentException("绔彛鏃犳晥");
+        Ip = ip;
+        Port = port;
+    }
+}
+```
+
+### 2.3 棰嗗煙鏈嶅姟璁捐
+
+```csharp
+// 璁惧璋冨害棰嗗煙鏈嶅姟
+public interface IDeviceScheduler
+{
+    Task<DeviceTask> CreateTask(DeviceId deviceId, TaskType type, TaskPayload payload);
+    Task<DeviceTask> AssignTask(DeviceId deviceId);
+    Task CompleteTask(DeviceTaskId taskId);
+    Task FailTask(DeviceTaskId taskId, string errorMessage);
+}
+
+public class DeviceScheduler : IDeviceScheduler
+{
+    private readonly IDeviceTaskRepository _taskRepository;
+    private readonly IDeviceRepository _deviceRepository;
+    private readonly ITaskQueue _taskQueue;
+
+    public async Task<DeviceTask> CreateTask(DeviceId deviceId, TaskType type, TaskPayload payload)
+    {
+        var device = await _deviceRepository.GetById(deviceId);
+        if (device == null)
+            throw new DomainException("璁惧涓嶅瓨鍦�");
+
+        if (device.Status != DeviceStatus.Connected)
+            throw new DomainException("璁惧鏈繛鎺�");
+
+        var task = DeviceTask.Create(deviceId, type, payload);
+        await _taskRepository.Add(task);
+        await _taskQueue.Enqueue(task);
+
+        return task;
+    }
+
+    public async Task<DeviceTask> AssignTask(DeviceId deviceId)
+    {
+        var tasks = await _taskRepository.GetPendingTasksForDevice(deviceId);
+        if (!tasks.Any())
+            return null;
+
+        var task = tasks.OrderBy(t => t.Priority).First();
+        task.Start();
+        await _taskRepository.Update(task);
+
+        return task;
+    }
+}
+
+// 璁惧鐘舵�佹満棰嗗煙鏈嶅姟
+public interface IDeviceStateMachine
+{
+    bool CanTransition(DeviceStatus current, DeviceStatus target);
+    void Transition(Device device, DeviceStatus target);
+}
+
+public class DeviceStateMachine : IDeviceStateMachine
+{
+    private static readonly Dictionary<DeviceStatus, HashSet<DeviceStatus>> _transitions = new()
+    {
+        [DeviceStatus.Disconnected] = new() { DeviceStatus.Connecting, DeviceStatus.Maintenance },
+        [DeviceStatus.Connecting] = new() { DeviceStatus.Connected, DeviceStatus.Error },
+        [DeviceStatus.Connected] = new() { DeviceStatus.Busy, DeviceStatus.Disconnected, DeviceStatus.Error, DeviceStatus.Maintenance },
+        [DeviceStatus.Busy] = new() { DeviceStatus.Connected, DeviceStatus.Error },
+        [DeviceStatus.Error] = new() { DeviceStatus.Disconnected, DeviceStatus.Maintenance },
+        [DeviceStatus.Maintenance] = new() { DeviceStatus.Disconnected }
+    };
+
+    public bool CanTransition(DeviceStatus current, DeviceStatus target)
+    {
+        return _transitions.TryGetValue(current, out var allowed) && allowed.Contains(target);
+    }
+
+    public void Transition(Device device, DeviceStatus target)
+    {
+        if (!CanTransition(device.Status, target))
+            throw new DomainException($"鏃犳晥鐨勭姸鎬佽浆鎹�: {device.Status} -> {target}");
+
+        device.SetStatus(target);
+    }
+}
+```
+
+### 2.4 浠撳偍鎺ュ彛璁捐
+
+```csharp
+// 璁惧浠撳偍鎺ュ彛
+public interface IDeviceRepository : IRepository<Device, DeviceId>
+{
+    Task<Device?> GetByName(DeviceName name);
+    Task<IEnumerable<Device>> GetByType(DeviceType type);
+    Task<IEnumerable<Device>> GetByStatus(DeviceStatus status);
+    Task<IEnumerable<Device>> GetAllConnected();
+}
+
+// 璁惧浠诲姟浠撳偍鎺ュ彛
+public interface IDeviceTaskRepository : IRepository<DeviceTask, DeviceTaskId>
+{
+    Task<IEnumerable<DeviceTask>> GetPendingTasksForDevice(DeviceId deviceId);
+    Task<IEnumerable<DeviceTask>> GetRunningTasksForDevice(DeviceId deviceId);
+    Task<IEnumerable<DeviceTask>> GetTasksByStatus(TaskStatus status);
+}
+```
+
+---
+
+## 3. 搴旂敤灞傝璁�
+
+### 3.1 搴旂敤鏈嶅姟璁捐
+
+```csharp
+// 璁惧搴旂敤鏈嶅姟
+public class DeviceApplicationService
+{
+    private readonly IDeviceRepository _deviceRepository;
+    private readonly IDeviceScheduler _deviceScheduler;
+    private readonly IUnitOfWork _unitOfWork;
+
+    public async Task<DeviceDto> GetDevice(DeviceId id)
+    {
+        var device = await _deviceRepository.GetById(id);
+        return device.ToDto();
+    }
+
+    public async Task<DeviceTaskDto> CreateTask(CreateDeviceTaskCommand command)
+    {
+        await using var transaction = await _unitOfWork.BeginTransaction();
+
+        var deviceId = DeviceId.From(command.DeviceId);
+        var task = await _deviceScheduler.CreateTask(
+            deviceId,
+            command.Type,
+            new TaskPayload(command.Payload)
+        );
+
+        await _unitOfWork.Commit();
+        return task.ToDto();
+    }
+
+    public async Task CompleteTask(CompleteDeviceTaskCommand command)
+    {
+        var taskId = DeviceTaskId.From(command.TaskId);
+        await _deviceScheduler.CompleteTask(taskId);
+    }
+}
+
+// 鍛戒护鍜屾煡璇㈠璞�
+public record CreateDeviceTaskCommand(Guid DeviceId, TaskType Type, string Payload);
+public record CompleteDeviceTaskCommand(Guid TaskId);
+
+// DTO
+public record DeviceDto(Guid Id, string Name, DeviceType Type, DeviceStatus Status);
+public record DeviceTaskDto(Guid Id, Guid DeviceId, TaskType Type, TaskStatus Status);
+```
+
+---
+
+## 4. 鍩虹璁炬柦灞傞噸鏋�
+
+### 4.1 浠撳偍瀹炵幇
+
+```csharp
+// 璁惧浠撳偍瀹炵幇
+public class DeviceRepository : IDeviceRepository
+{
+    private readonly ISqlSugarClient _db;
+    private readonly ICacheService _cache;
+
+    public DeviceRepository(ISqlSugarClient db, ICacheService cache)
+    {
+        _db = db;
+        _cache = cache;
+    }
+
+    public async Task<Device?> GetById(DeviceId id)
+    {
+        // 鍏堟煡缂撳瓨
+        var cached = await _cache.Get<Device>($"device:{id.Value}");
+        if (cached != null)
+            return cached;
+
+        // 鏌ユ暟鎹簱
+        var entity = await _db.Queryable<Dt_DeviceInfo>()
+            .Where(d => d.DeviceId == id.Value)
+            .FirstAsync();
+
+        if (entity == null) return null;
+
+        // 杞崲涓洪鍩熸ā鍨�
+        var device = MapToDomain(entity);
+
+        // 鍐欏叆缂撳瓨
+        await _cache.Set($"device:{id.Value}", device, TimeSpan.FromMinutes(5));
+
+        return device;
+    }
+
+    public async Task Add(Device device)
+    {
+        var entity = MapToEntity(device);
+        await _db.Insertable(entity).ExecuteCommandAsync();
+
+        // 娓呴櫎鐩稿叧缂撳瓨
+        await _cache.RemoveByPrefix("device:");
+    }
+
+    private Device MapToDomain(Dt_DeviceInfo entity) { /* ... */ }
+    private Dt_DeviceInfo MapToEntity(Device domain) { /* ... */ }
+}
+```
+
+### 4.2 閫氫俊椹卞姩灏佽
+
+```csharp
+// 璁惧閫氫俊閫傞厤鍣ㄦ帴鍙�
+public interface IDeviceCommunicatorAdapter
+{
+    Task<bool> Connect(DeviceAddress address);
+    Task<bool> Disconnect();
+    Task<DeviceData> ReadData(string address);
+    Task WriteData(string address, object value);
+    Task<bool> IsConnected();
+}
+
+// Siemens PLC閫傞厤鍣�
+public class SiemensCommunicatorAdapter : IDeviceCommunicatorAdapter
+{
+    private readonly SiemensS7Net _plc;
+
+    public SiemensCommunicatorAdapter(DeviceAddress address)
+    {
+        _plc = new SiemensS7Net(SiemensPLCS.S1200, address.Ip);
+        _plc.ConnectTimeOut = 5000;
+    }
+
+    public async Task<bool> Connect(DeviceAddress address)
+    {
+        var result = await Task.Run(() => _plc.ConnectServer());
+        return result.IsSuccess;
+    }
+
+    public async Task<DeviceData> ReadData(string address)
+    {
+        var result = await Task.Run(() => _plc.Read(address));
+        if (!result.IsSuccess)
+            throw new CommunicationException($"璇诲彇澶辫触: {result.Message}");
+
+        return new DeviceData(result.Content);
+    }
+
+    // ... 鍏朵粬鏂规硶
+}
+```
+
+---
+
+## 5. 鍒嗗眰娓呮櫚鍖�
+
+### 5.1 椤圭洰缁撴瀯閲嶇粍
+
+```
+WIDESEAWCS_Domain/
+鈹溾攢鈹� DeviceManagement/
+鈹�   鈹溾攢鈹� Aggregates/
+鈹�   鈹�   鈹溾攢鈹� Device.cs
+鈹�   鈹�   鈹溾攢鈹� DeviceGroup.cs
+鈹�   鈹�   鈹斺攢鈹� DeviceTask.cs
+鈹�   鈹溾攢鈹� Entities/
+鈹�   鈹�   鈹溾攢鈹� DeviceStatus.cs
+鈹�   鈹�   鈹溾攢鈹� DeviceLocation.cs
+鈹�   鈹�   鈹斺攢鈹� DeviceProperty.cs
+鈹�   鈹溾攢鈹� ValueObjects/
+鈹�   鈹�   鈹溾攢鈹� DeviceId.cs
+鈹�   鈹�   鈹溾攢鈹� DeviceName.cs
+鈹�   鈹�   鈹溾攢鈹� DeviceAddress.cs
+鈹�   鈹�   鈹斺攢鈹� TaskPayload.cs
+鈹�   鈹溾攢鈹� Services/
+鈹�   鈹�   鈹溾攢鈹� IDeviceScheduler.cs
+鈹�   鈹�   鈹溾攢鈹� DeviceScheduler.cs
+鈹�   鈹�   鈹溾攢鈹� IDeviceStateMachine.cs
+鈹�   鈹�   鈹斺攢鈹� DeviceStateMachine.cs
+鈹�   鈹溾攢鈹� Repositories/
+鈹�   鈹�   鈹溾攢鈹� IDeviceRepository.cs
+鈹�   鈹�   鈹斺攢鈹� IDeviceTaskRepository.cs
+鈹�   鈹斺攢鈹� Events/
+鈹�       鈹溾攢鈹� DeviceConnectedEvent.cs
+鈹�       鈹斺攢鈹� TaskCompletedEvent.cs
+鈹斺攢鈹� WarehouseOperations/
+    鈹斺攢鈹� ...
+
+WIDESEAWCS_Application/
+鈹溾攢鈹� Services/
+鈹�   鈹斺攢鈹� DeviceApplicationService.cs
+鈹溾攢鈹� Commands/
+鈹�   鈹斺攢鈹� CreateDeviceTaskCommand.cs
+鈹溾攢鈹� Queries/
+鈹�   鈹斺攢鈹� GetDeviceQuery.cs
+鈹斺攢鈹� DTOs/
+    鈹斺攢鈹� DeviceDto.cs
+
+WIDESEAWCS_Infrastructure/
+鈹溾攢鈹� Persistence/
+鈹�   鈹溾攢鈹� Repositories/
+鈹�   鈹�   鈹溾攢鈹� DeviceRepository.cs
+鈹�   鈹�   鈹斺攢鈹� DeviceTaskRepository.cs
+鈹�   鈹斺攢鈹� SqlSugar/
+鈹�       鈹斺攢鈹� DbContext.cs
+鈹溾攢鈹� Communication/
+鈹�   鈹溾攢鈹� Adapters/
+鈹�   鈹�   鈹溾攢鈹� SiemensCommunicatorAdapter.cs
+鈹�   鈹�   鈹溾攢鈹� OmronCommunicatorAdapter.cs
+鈹�   鈹�   鈹斺攢鈹� ModbusCommunicatorAdapter.cs
+鈹�   鈹斺攢鈹� IDeviceCommunicatorAdapter.cs
+鈹溾攢鈹� Caching/
+鈹�   鈹斺攢鈹� RedisCacheService.cs
+鈹斺攢鈹� Scheduling/
+    鈹斺攢鈹� QuartzJobManager.cs
+
+WIDESEAWCS_Server/
+鈹斺攢鈹� Controllers/
+    鈹斺攢鈹� DeviceController.cs
+```
+
+---
+
+## 6. 鎬ц兘浼樺寲绛栫暐
+
+### 6.1 缂撳瓨浼樺寲
+
+```csharp
+// 澶氱骇缂撳瓨绛栫暐
+public class HybridCacheService : ICacheService
+{
+    private readonly IMemoryCache _l1Cache;
+    private readonly IConnectionMultiplexer _redis;
+    private readonly IDistributedCache _l2Cache;
+
+    public async Task<T?> Get<T>(string key)
+    {
+        // L1缂撳瓨
+        if (_l1Cache.TryGetValue(key, out T l1Value))
+            return l1Value;
+
+        // L2缂撳瓨
+        var l2Value = await _l2Cache.GetStringAsync(key);
+        if (l2Value != null)
+        {
+            var value = JsonSerializer.Deserialize<T>(l2Value);
+            _l1Cache.Set(key, value, TimeSpan.FromMinutes(1));
+            return value;
+        }
+
+        return default;
+    }
+
+    public async Task Set<T>(string key, T value, TimeSpan? expiry = null)
+    {
+        _l1Cache.Set(key, value, TimeSpan.FromMinutes(1));
+
+        var serialized = JsonSerializer.Serialize(value);
+        await _l2Cache.SetStringAsync(key, serialized, expiry);
+    }
+}
+```
+
+### 6.2 鏁版嵁搴撴煡璇紭鍖�
+
+```csharp
+// 鎵归噺鏌ヨ浼樺寲
+public class DeviceRepository : IDeviceRepository
+{
+    public async Task<IDictionary<DeviceId, Device>> GetByIds(IEnumerable<DeviceId> ids)
+    {
+        var idList = ids.Select(id => id.Value).ToList();
+
+        // 鎵归噺鏌ヨ
+        var entities = await _db.Queryable<Dt_DeviceInfo>()
+            .In(idList)
+            .ToListAsync();
+
+        return entities.ToDictionary(
+            e => DeviceId.From(e.DeviceId),
+            e => MapToDomain(e)
+        );
+    }
+
+    // 寤惰繜鏌ヨ
+    public async Task<IEnumerable<Device>> QueryActiveDevices()
+    {
+        return await _db.Queryable<Dt_DeviceInfo>()
+            .Where(d => d.Status != DeviceStatus.Disconnected)
+            .OrderBy(d => d.Name)
+            .Select(d => MapToDomain(d))
+            .ToListAsync();
+    }
+}
+```
+
+---
+
+## 7. 閿欒澶勭悊鍜屾棩蹇楃粺涓�
+
+### 7.1 缁熶竴寮傚父澶勭悊
+
+```csharp
+// 棰嗗煙寮傚父鍩虹被
+public abstract class DomainException : Exception
+{
+    public string ErrorCode { get; }
+
+    protected DomainException(string message, string errorCode = "DOMAIN_ERROR")
+        : base(message)
+    {
+        ErrorCode = errorCode;
+    }
+}
+
+// 搴旂敤寮傚父
+public class ApplicationException : Exception
+{
+    public string ErrorCode { get; }
+
+    public ApplicationException(string message, string errorCode = "APP_ERROR")
+        : base(message)
+    {
+        ErrorCode = errorCode;
+    }
+}
+
+// 鍏ㄥ眬寮傚父澶勭悊涓棿浠�
+public class GlobalExceptionHandlerMiddleware
+{
+    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
+    {
+        try
+        {
+            await next(context);
+        }
+        catch (DomainException ex)
+        {
+            context.Response.StatusCode = 400;
+            await context.Response.WriteAsJsonAsync(new
+            {
+                error = ex.ErrorCode,
+                message = ex.Message
+            });
+        }
+        catch (ApplicationException ex)
+        {
+            context.Response.StatusCode = 500;
+            await context.Response.WriteAsJsonAsync(new
+            {
+                error = ex.ErrorCode,
+                message = ex.Message
+            });
+        }
+    }
+}
+```
+
+### 7.2 缁撴瀯鍖栨棩蹇�
+
+```csharp
+// 棰嗗煙浜嬩欢鏃ュ織
+public class DomainEventLogger : IDomainEventDispatcher
+{
+    private readonly ILogger<DomainEventLogger> _logger;
+
+    public async Task Dispatch(IDomainEvent domainEvent)
+    {
+        _logger.LogInformation("棰嗗煙浜嬩欢: {EventType}, 鏁版嵁: {EventData}",
+            domainEvent.GetType().Name,
+            JsonSerializer.Serialize(domainEvent));
+
+        // 鍙戦�佸埌浜嬩欢鎬荤嚎
+    }
+}
+
+// 璁惧鎿嶄綔鏃ュ織
+public class DeviceOperationLogger : IDeviceOperationLogger
+{
+    public void LogConnect(DeviceId deviceId, bool success, string? error = null)
+    {
+        if (success)
+        {
+            _logger.LogInformation("璁惧杩炴帴鎴愬姛: {DeviceId}", deviceId.Value);
+        }
+        else
+        {
+            _logger.LogError("璁惧杩炴帴澶辫触: {DeviceId}, 閿欒: {Error}",
+                deviceId.Value, error);
+        }
+    }
+}
+```
+
+---
+
+## 8. 瀹炴柦璁″垝锛�2鍛級
+
+### 绗�1鍛細棰嗗煙灞傛惌寤�
+
+| 澶╂暟 | 浠诲姟 |
+|------|------|
+| Day 1-2 | 鍒涘缓棰嗗煙椤圭洰缁撴瀯锛屽畾涔夊�煎璞″拰鑱氬悎鏍� |
+| Day 3-4 | 瀹炵幇棰嗗煙鏈嶅姟鍜岀姸鎬佹満 |
+| Day 5 | 鍒涘缓浠撳偍鎺ュ彛锛屽畾涔夐鍩熶簨浠� |
+
+### 绗�2鍛細搴旂敤灞傚拰鍩虹璁炬柦灞�
+
+| 澶╂暟 | 浠诲姟 |
+|------|------|
+| Day 1-2 | 瀹炵幇搴旂敤鏈嶅姟鍜孌TO |
+| Day 3 | 鍒涘缓浠撳偍瀹炵幇锛岃縼绉绘暟鎹闂�昏緫 |
+| Day 4 | 灏佽閫氫俊椹卞姩锛屼紭鍖栫紦瀛樼瓥鐣� |
+| Day 5 | 缁熶竴閿欒澶勭悊鍜屾棩蹇楋紝闆嗘垚娴嬭瘯 |
+
+---
+
+## 9. 璁捐鍐崇瓥璁板綍
+
+### 9.1 涓轰粈涔堥�夋嫨娓愯繘寮廌DD鑰岄潪瀹屾暣DDD閲嶆瀯锛�
+
+**鍐崇瓥**锛氶�夋嫨娓愯繘寮廌DD閲嶆瀯鑰岄潪瀹屾暣DDD閲嶆瀯
+
+**鐞嗙敱**锛�
+1. 鏃堕棿绾︽潫锛�2鍛ㄥ唴鏃犳硶瀹屾垚瀹屾暣DDD閲嶆瀯
+2. 椋庨櫓鎺у埗锛氭笎杩涘紡闄嶄綆椋庨櫓锛屽彲鍒嗛樁娈甸獙璇�
+3. 绯荤粺绋冲畾鎬э細淇濇寔鐜版湁鍔熻兘鍙敤
+4. 璧勬簮鏁堢巼锛氫紭鍏堥噸鏋勬牳蹇冮鍩�
+
+### 9.2 涓轰粈涔堝皢璁惧绠$悊浣滀负鏍稿績棰嗗煙锛�
+
+**鍐崇瓥**锛氬皢璁惧绠$悊浣滀负绗竴涓噸鏋勭殑鏍稿績棰嗗煙
+
+**鐞嗙敱**锛�
+1. 涓氬姟浼樺厛绾э細璁惧绠$悊鏄疻CS绯荤粺鐨勬牳蹇�
+2. 浠g爜澶嶆潅搴︼細璁惧绠$悊鍖呭惈鐘舵�併�佽皟搴︺�侀�氫俊绛夊鏉傞�昏緫
+3. 浼樺寲绌洪棿澶э細璁惧绠$悊瀛樺湪杈冨鎬ц兘鍜岃�﹀悎闂
+4. 褰卞搷鑼冨洿骞匡細璁惧绠$悊鏄叾浠栦笟鍔$殑鍩虹
+
+### 9.3 涓轰粈涔堥噰鐢–QRS妯″紡锛�
+
+**鍐崇瓥**锛氬湪搴旂敤灞傞噰鐢–QRS妯″紡
+
+**鐞嗙敱**锛�
+1. 鍏虫敞鐐瑰垎绂伙細鍛戒护鍜屾煡璇㈣亴璐f竻鏅�
+2. 鎬ц兘浼樺寲锛氬彲鍒嗗埆浼樺寲璇诲啓鎿嶄綔
+3. 鎵╁睍鎬уソ锛氫究浜庢坊鍔犵紦瀛樸�佷簨浠跺鐞�
+
+---
+
+## 10. 闈炲姛鑳芥�ч渶姹�
+
+### 10.1 鎬ц兘瑕佹眰
+- 璁惧鐘舵�佹煡璇㈠搷搴旀椂闂� < 100ms
+- 浠诲姟鍒涘缓鍝嶅簲鏃堕棿 < 200ms
+- 鏀寔鑷冲皯100涓苟鍙戣澶囪繛鎺�
+
+### 10.2 鍙淮鎶ゆ�ц姹�
+- 浠g爜瑕嗙洊鐜� > 80%
+- 鍦堝鏉傚害 < 10
+- 閬靛惊鍗曚竴鑱岃矗鍘熷垯
+
+### 10.3 鍙墿灞曟�ц姹�
+- 鏀寔鏂板璁惧绫诲瀷鏃犻渶淇敼鏍稿績浠g爜
+- 鏀寔鏂板浠诲姟绫诲瀷
+- 鏀寔澶氱閫氫俊鍗忚鎵╁睍
+
+---
+
+## 11. 椋庨櫓璇勪及
+
+| 椋庨櫓 | 鍙兘鎬� | 褰卞搷 | 缂撹В鎺柦 |
+|------|--------|------|----------|
+| 鏃堕棿涓嶈冻 | 楂� | 楂� | 鍒嗛樁娈靛疄鏂斤紝浼樺厛鏍稿績鍔熻兘 |
+| 鏁版嵁杩佺Щ闂 | 涓� | 楂� | 鍏呭垎娴嬭瘯锛屼繚鐣欏洖婊氭柟妗� |
+| 鎬ц兘涓嬮檷 | 涓� | 涓� | 鎬ц兘鍩哄噯娴嬭瘯锛岀洃鎺т紭鍖� |
+| 鍥㈤槦閫傚簲 | 浣� | 涓� | 鎻愪緵鍩硅锛屾枃妗e畬鍠� |

--
Gitblit v1.9.3