Files
Hua.Todo/docs/project/研发工单-v1.2.0/09-CloudSync-同步策略改进方案.md
T
ShaoHua 65cee20006 docs: 重组 docs/manual/ 指南结构,区分普通用户与开发者双入口
- 新增 00-目录与导读.md 双入口导航

- 用户面(01-04):项目介绍、安装指南、版本记录、其他信息

- 开发者面(05-10):技术栈、构建、架构、云同步、代码规范、MCP

- 拆分旧01为 01(用户)+05(开发者);旧02为 02(用户)+06(开发者)

- 合并旧08+09 MCP文档为 10-MCP服务集成

- 同步更新 README.md 与 .trae/rules/项目/ 交叉引用
2026-06-16 01:46:46 +08:00

734 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CloudSync 同步策略改进方案
> 研发工单序号:09
> 依赖:04-CloudSync-服务端基础能力、05-CloudSync-客户端配置与工作流
> 状态:待实现
---
## 一、背景与问题
当前同步规则([02-任务同步规则.md](../../manual/02-任务同步规则.md) 6.2 节)存在以下问题:
1. **TaskEntity 缺少 ABP 审计字段**:未继承 ABP 基类,缺少 `ExtraProperties``ConcurrencyStamp``CreationTime``CreatorId``LastModificationTime``LastModifierId` 等标准字段
2. **主键类型不符合 ABP 规范**ABP 要求主键为 `Guid`,当前为 `int`
3. **软删除字段缺失**:没有 `IsDeleted``DeletionTime` 字段,无法实现 Tombstone 逻辑删除
---
## 二、ABP 审计字段规范(必须遵守)
根据 [表设计与字段命名规范.md](file:///d:/Codes/CodeSmith/CodeSmith/ShaoHua.CodeSmith.Abp/docs/2.表设计与字段命名规范.md)`FullAuditedEntityWithUser<Guid, IdentityUser>` 基类提供以下字段:
| ABP 标准字段 | 含义 | 类型 |
|---|---|---|
| `Id` | 主键 | `Guid`ABP 强制要求) |
| `ExtraProperties` | 扩展属性字典 | `ExtraPropertyDictionary` |
| `ConcurrencyStamp` | 并发戳,用于乐观并发控制 | `string?` |
| `CreationTime` | 创建时间 | `DateTime` |
| `CreatorId` | 创建人Id | `Guid?` |
| `LastModificationTime` | 最后修改时间 | `DateTime?` |
| `LastModifierId` | 最后修改人Id | `Guid?` |
| `IsDeleted` | 软删除标记 | `bool` |
| `DeletionTime` | 删除时间 | `DateTime?` |
| `DeleterId` | 删除人Id | `Guid?` |
### 字段忽略规则(ShouldIgnoreList
以下字段在实体中**不生成任何属性**:
| 字段名 | 理由 |
|---|---|
| `ExtraProperties` | ABP 框架扩展属性,基类已处理 |
### 不可编辑字段(NotEnableEditList
以下字段在更新 DTO 中**不可编辑**:`IsDeleted``CreationTime``CreatorId``LastModificationTime``LastModifierId``DeletionTime``DeleterId`
---
## 三、TaskEntity 重构方案
### 3.1 数据库表名(ABP 规范)
> ABP 框架约定表名格式为 `T_{实体名}s`,例如实体 `TaskEntity` 对应表名 `T_Tasks`。
> EF Core 迁移脚本中的 `table: "Tasks"` 为 DbContext 配置的表名,两者须保持一致。
### 3.2 继承关系变更
```csharp
// 原
public class TaskEntity
{
public int Id { get; set; }
// ...
}
// 改后
public class TaskEntity : FullAuditedEntityWithUser<Guid, IdentityUser>
{
// Id、ExtraProperties、ConcurrencyStamp、CreationTime、CreatorId、
// LastModificationTime、LastModifierId、IsDeleted、DeletionTime、DeleterId
// 均由基类提供
}
```
### 3.2 业务字段保留
| 业务字段 | 类型 | 说明 |
|---|---|---|
| `UserId` | `Guid` | 任务所属用户(云端隔离),本地为 `"local"` |
| `Title` | `string` | 任务标题 |
| `Priority` | `TaskPriority` | 优先级枚举 |
| `IsCompleted` | `bool` | 是否完成 |
| `ParentTaskId` | `Guid?` | 父任务ID(外键) |
> **ParentTaskId 类型变更**:从 `int?` 改为 `Guid?`,与主键类型一致。
### 3.3 导航属性
```csharp
public class TaskEntity : FullAuditedEntityWithUser<Guid, IdentityUser>
{
public UserEntity? User { get; set; }
public TaskEntity? ParentTask { get; set; }
public List<TaskEntity> SubTasks { get; set; } = new();
}
```
---
## 四、DTO 重构方案(与数据库保持一致)
### 4.1 CloudTaskItemC# → JSON 响应)
```csharp
// src/Hua.Todo.Application/CloudSync/Models/TaskSyncDtos.cs
/// <summary>
/// 云同步任务条目(ABP 标准)。
/// </summary>
public class CloudTaskItem
{
/// <summary>
/// 任务 ID(服务端分配,Guid)。
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// 标题。
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 优先级。
/// </summary>
public TaskPriority Priority { get; set; }
/// <summary>
/// 是否完成。
/// </summary>
public bool IsCompleted { get; set; }
/// <summary>
/// 父任务 IDGuid)。
/// </summary>
public Guid? ParentTaskId { get; set; }
// === ABP 审计字段 ===
/// <summary>
/// 创建时间。
/// </summary>
public DateTime CreationTime { get; set; }
/// <summary>
/// 创建人 ID。
/// </summary>
public Guid? CreatorId { get; set; }
/// <summary>
/// 最后修改时间(用于 LWW 冲突判断)。
/// </summary>
public DateTime? LastModificationTime { get; set; }
/// <summary>
/// 最后修改人 ID。
/// </summary>
public Guid? LastModifierId { get; set; }
/// <summary>
/// 软删除标记。
/// </summary>
public bool IsDeleted { get; set; }
/// <summary>
/// 删除时间。
/// </summary>
public DateTime? DeletionTime { get; set; }
/// <summary>
/// 删除人 ID。
/// </summary>
public Guid? DeleterId { get; set; }
}
```
### 4.2 CloudTaskUpsertC# → JSON 请求)
```csharp
/// <summary>
/// 任务 Upsert DTO(客户端提交)。
/// </summary>
public class CloudTaskUpsert
{
/// <summary>
/// 任务 ID;为 null 表示新建。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 标题。
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 优先级。
/// </summary>
public TaskPriority Priority { get; set; } = TaskPriority.Medium;
/// <summary>
/// 是否完成。
/// </summary>
public bool IsCompleted { get; set; }
/// <summary>
/// 父任务 ID(可选)。
/// </summary>
public Guid? ParentTaskId { get; set; }
/// <summary>
/// 客户端发起变更时写入的时间戳(UTC),用于 LWW 冲突判断。
/// </summary>
public DateTime? LastModificationTime { get; set; }
}
```
### 4.3 SyncRequest / SyncResponse
```csharp
/// <summary>
/// 同步请求(增改删)。
/// </summary>
public class SyncRequest
{
/// <summary>
/// 新增或更新的任务列表。
/// </summary>
public List<CloudTaskUpsert> Upserts { get; set; } = new();
/// <summary>
/// 需要逻辑删除的任务 ID 列表。
/// </summary>
public List<Guid> Deletes { get; set; } = new();
}
/// <summary>
/// 同步响应。
/// </summary>
public class SyncResponse
{
/// <summary>
/// 服务端时间(UTC)。
/// </summary>
public DateTime ServerTimeUtc { get; set; }
/// <summary>
/// 当前用户的任务全量(含 Tombstone)。
/// </summary>
public List<CloudTaskItem> Tasks { get; set; } = new();
}
```
### 4.4 JSON 序列化配置
DTO 默认使用 PascalCaseABP 标准),通过 `[JsonPropertyName]` 特性控制 JSON 输出:
```csharp
public class CloudTaskItem
{
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("title")]
public string Title { get; set; }
// ... 其他字段
}
```
或通过全局配置启用 camelCase:
```csharp
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
```
---
## 五、前端类型定义(与 DTO 保持一致)
### 5.1 当前状态 vs 目标状态对比
| 字段 | 当前类型 | 目标类型 | 变更说明 |
|---|---|---|---|
| `id` | `number` | `string` | 主键从 int 改为 GuidJSON 序列化为字符串 |
| `parentTaskId` | `number \| undefined` | `string \| null` | 外键类型同步变更 |
| `createdAt` | `string` | **移除** | 替换为 `creationTime` |
| `updatedAt` | `string` | **移除** | 替换为 `lastModificationTime` |
| `subTasks` | `Task[]` | `Task[]` | 类型不变,递归结构 |
| — | — | `creationTime: string` | 新增:ABP 创建时间 |
| — | — | `creatorId: string \| null` | 新增:创建人 ID |
| — | — | `lastModificationTime: string \| null` | 新增:最后修改时间(LWW 冲突判断) |
| — | — | `lastModifierId: string \| null` | 新增:最后修改人 ID |
| — | — | `isDeleted: boolean` | 新增:软删除标记 |
| — | — | `deletionTime: string \| null` | 新增:删除时间 |
| — | — | `deleterId: string \| null` | 新增:删除人 ID |
### 5.2 task.ts 目标定义
```typescript
// src/Hua.Todo.Web/src/types/task.ts
export type TaskPriority = 0 | 1 | 2;
/**
* Todo 待办项(与 CloudTaskItem DTO 一一对应)。
* - 主键 id 为 Guid 序列化后的字符串
* - 包含 ABP 审计字段,用于云同步冲突判断
*/
export interface Task {
// === 业务字段 ===
id: string; // Guid 序列化
title: string;
priority: TaskPriority;
isCompleted: boolean;
parentTaskId: string | null; // Guid 类型,null 表示顶级任务
// === ABP 审计字段 ===
/** 创建时间(服务端分配) */
creationTime: string;
/** 创建人 ID */
creatorId: string | null;
/** 最后修改时间(用于 LWW 冲突判断) */
lastModificationTime: string | null;
/** 最后修改人 ID */
lastModifierId: string | null;
/** 软删除标记(前端本地过滤不展示) */
isDeleted: boolean;
/** 删除时间(不为 null 时表示已逻辑删除) */
deletionTime: string | null;
/** 删除人 ID */
deleterId: string | null;
// === 导航属性 ===
subTasks: Task[];
}
/**
* 创建 Todo 待办项请求(客户端 → 服务端,新建时不带 id)
*/
export interface CreateTaskDto {
title: string;
priority: TaskPriority;
parentTaskId?: string; // Guid 字符串
}
/**
* 更新 Todo 待办项请求(客户端 → 服务端,必须带 id)
*/
export interface UpdateTaskDto {
id: string; // Guid 字符串
title?: string;
priority?: TaskPriority;
isCompleted?: boolean;
}
```
### 5.3 前端变更检测逻辑
```typescript
// src/Hua.Todo.Web/src/types/task.ts 或业务层
/**
* 标记任务为脏(本地修改待同步)。
* - 每次用户操作(创建/修改/删除)时调用
* - 更新 lastModificationTime 为当前 UTC 时间
*/
export function markTaskDirty(task: Task): void {
task.lastModificationTime = new Date().toISOString();
task.lastModifierId = getCurrentUserId(); // 若已登录
pendingUpserts.set(task.id, task);
}
/**
* 标记任务为待删除(本地删除待同步)。
* - 设置 deletionTime 而非真正从数组移除
*/
export function markTaskDeleted(task: Task): void {
task.isDeleted = true;
task.deletionTime = new Date().toISOString();
task.deleterId = getCurrentUserId();
pendingDeletes.add(task.id);
}
```
### 5.4 API 响应处理
```typescript
// src/Hua.Todo.Web/src/api/cloudSync.ts
import type { Task } from '@/types/task';
/**
* 获取云端全量任务(含 Tombstone)。
* 返回数据直接赋值给本地 store,无需字段转换。
*/
export async function fetchCloudTasks(): Promise<Task[]> {
const response = await cloudSyncApi.getTasks();
// response.data 类型已是 Task[],服务端返回的 Guid 已序列化为 string
return response.data;
}
/**
* 拉取全量后,本地过滤不展示已删除任务。
*/
export function filterVisibleTasks(tasks: Task[]): Task[] {
return tasks.filter(task => task.deletionTime === null);
}
```
### 5.5 pendingUpserts / pendingDeletes 类型修正
```typescript
// src/Hua.Todo.Web/src/stores/taskStore.ts(示例)
import type { Task } from '@/types/task';
// 待上传的脏任务(key: task.id,即 Guid string
const pendingUpserts = reactive(new Map<string, Task>());
// 待上传的删除任务 IDGuid string
const pendingDeletes = reactive(new Set<string>());
```
### 5.6 Guid 字符串处理工具
```typescript
// src/Hua.Todo.Web/src/utils/guid.ts
/**
* 生成新的 Guid 字符串(客户端创建临时任务时使用)。
* 格式:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx(小写)
*/
export function generateGuid(): string {
return crypto.randomUUID();
}
/**
* 判断字符串是否为有效 Guid 格式。
*/
export function isValidGuid(value: string): boolean {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
}
```
---
## 六、迁移脚本
### 6.1 EF Core 迁移命令
```powershell
cd src/Hua.Todo.Application
dotnet ef migrations add MakeTaskEntityAbpCompatible --startup-project ../Hua.Todo.Host
```
### 6.2 迁移内容预期
此迁移涉及大量字段变更,建议分阶段执行或使用"双写/兼容期"策略:
```csharp
// MakeTaskEntityAbpCompatible.cs
// 表名:T_TasksABP 规范),DbContext 配置为 "Tasks"
protected override void Up(MigrationBuilder migrationBuilder)
{
// 1. 新增 Guid Id 列(临时名)
migrationBuilder.AddColumn<Guid>(
name: "NewId",
table: "T_Tasks",
type: "TEXT",
nullable: false,
defaultValue: Guid.NewGuid());
// 2. 将旧 int Id 数据迁移到 NewId
// (需要手动 SQL 脚本或数据迁移)
// 3. 删除旧 Id 列,重命名 NewId 为 Id
migrationBuilder.DropColumn("Id", "T_Tasks");
migrationBuilder.RenameColumn("NewId", "T_Tasks", "Id");
// 4. 新增 ABP 审计字段
migrationBuilder.AddColumn<string>(
name: "ExtraProperties",
table: "T_Tasks",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "ConcurrencyStamp",
table: "T_Tasks",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "CreationTime",
table: "T_Tasks",
type: "TEXT",
nullable: false,
defaultValue: DateTime.UtcNow);
migrationBuilder.AddColumn<Guid?>(
name: "CreatorId",
table: "T_Tasks",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<DateTime?>(
name: "LastModificationTime",
table: "T_Tasks",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<Guid?>(
name: "LastModifierId",
table: "T_Tasks",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsDeleted",
table: "T_Tasks",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<DateTime?>(
name: "DeletionTime",
table: "T_Tasks",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<Guid?>(
name: "DeleterId",
table: "T_Tasks",
type: "TEXT",
nullable: true);
// 5. ParentTaskId 从 int 改为 Guid
migrationBuilder.DropColumn("ParentTaskId", "T_Tasks");
migrationBuilder.AddColumn<Guid?>(
name: "ParentTaskId",
table: "T_Tasks",
type: "TEXT",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
// 回滚逻辑...
}
```
> **注意**:此迁移为破坏性变更,建议在离线环境充分测试后再部署到生产环境。
---
## 七、同步策略(与 02-任务同步规则.md 保持一致)
> 本章节同步策略逻辑完全遵循 [02-任务同步规则.md](../../manual/02-任务同步规则.md) 6.2 节,字段名使用 ABP 标准。
### 7.1 核心原则
- **任务唯一标识是 `id`**`id` 是任务实体的唯一稳定标识,不可依赖时间戳做身份判断
- **`lastModificationTime` 是冲突判断字段**:用于解决"同一任务被多端修改时哪个变更更新"的问题
- **服务端存储唯一真实源(Source of Truth)**:所有设备最终都收敛到服务端数据
- **字段级 Last-Write-WinsLWW)合并**:同一字段的多设备并发修改,以 `lastModificationTime` 较新者为准
- **逻辑删除(Tombstone**:删除操作标记为"已删除",而非物理删除,保证多端删除语义一致
- **增量同步**:每次同步只上传本端变更(pendingUpserts + pendingDeletes),不上传全量
### 7.2 变更追踪机制
每个 `CloudTaskItem` 包含以下时间戳字段:
| ABP 字段 | 说明 |
|---|---|
| `creationTime` | 创建时间(服务端分配,永不改变) |
| `lastModificationTime` | 最后一次修改时间(每次字段变更时更新) |
| `isDeleted` | 软删除标记 |
| `deletionTime` | 逻辑删除时间(为 `null` 表示未删除) |
| `creatorId` | 创建人 ID |
| `lastModifierId` | 最后修改人 ID |
> `lastModificationTime` 由**请求发起方**(客户端或服务端)在发起变更时写入,存储到服务端后不再覆盖(除非有更新的变更)。
### 7.3 冲突解决规则
当客户端提交的任务与服务端现有任务发生 `id` 冲突时,按以下规则处理:
| 场景 | 解决规则 |
|---|---|
| 同一 `id`,客户端 `lastModificationTime` **更新** | 服务端接受客户端版本,覆盖对应字段 |
| 同一 `id`,服务端 `lastModificationTime` **更新** | 服务端拒绝客户端版本,保留服务端版本 |
| 同一 `id`,两者 `lastModificationTime` **相同** | 服务端优先(保守策略) |
**字段级合并示例**
- 设备 A 修改标题,设备 B 修改优先级
- 服务端对两个字段分别取 `lastModificationTime` 较新者,合并出最终结果
- 两个设备的修改都被保留,不会互相覆盖
### 7.4 父子任务处理
- **删除**:删除父任务时,其子任务一并标记为已删除(递归)
- **创建**:子任务的 `parentTaskId` 在上传时若为 `null`(新创建任务),服务端分配 ID 后,第一遍返回临时 ID 映射;第二遍利用映射完成父子关系重映射
- **重建父子关系**:若原父任务被删除后重建,子任务的 `parentTaskId` 引用仍指向原父 ID,不会自动指向新父
### 7.5 Tombstone 保留策略
- `deletionTime``null` 的任务在服务端保留至少 **30 天**
- 超过 30 天后由服务端垃圾收集(物理删除)
- 客户端同步时拉取全量(含 Tombstone),本地过滤不展示 `deletionTime != null` 的任务
### 7.6 服务端处理流程
`POST /sync` 服务端执行顺序:
```
1. 解析 upserts 和 deletes
2. 对 deletes 中的每个 id
- 递归标记该任务及所有子任务 deletionTime = now, isDeleted = true
3. 对 upserts 按 lastModificationTime 降序排列(较新的先处理)
4. 对每个 upsert 任务:
a. 若 id 在服务端不存在 → 创建新记录(分配 Guid)
b. 若 id 存在但服务端 lastModificationTime 更新 → 跳过(保留服务端)
c. 若 id 存在且客户端 lastModificationTime >= 服务端 lastModificationTime → 字段级合并更新
5. 返回当前用户全量任务(含 Tombstone)
```
> 排序处理的目的:确保最新的变更优先被采纳。
### 7.7 关于"服务端为准"的正确理解
"服务端为准"并不意味着客户端会丢失数据。完整的同步流程是:
1. **客户端上传阶段**:将 `pendingUpserts` + `pendingDeletes` 提交到服务器
2. **服务器合并阶段**:按 LWW 规则合并客户端提交与服务器现有数据
3. **客户端覆盖阶段**:用服务器返回的全量数据覆盖本地
由于客户端在第 1 步已经把本地所有变更提交,服务器在第 2 步已经把客户端的变更合并进权威状态,第 3 步用权威状态覆盖本地是安全的——**不会丢失任何已提交的变更**。
真正会丢失的场景是:客户端在离线状态下修改了任务 A,但没有在联网后发起同步就直接断开连接。这种情况下,离线修改会保留在本地 `pendingUpserts` 中,下次联网同步时会正常提交。
---
## 九、服务端代码改动
### 9.1 TaskRepository 查询过滤
```csharp
// 基类已自动过滤 IsDeleted = true 的记录
// 但若需要显式查询(含已删除),使用 _context.Tasks.IgnoreQueryFilters()
```
### 9.2 CloudTaskSyncService 逻辑删除处理
```csharp
// POST /sync 处理 deletes
foreach (var id in request.Deletes)
{
var task = await _context.Tasks.FindAsync(id);
if (task != null && !task.IsDeleted)
{
await _taskRepository.DeleteAsync(task); // 调用基类软删除
}
}
```
---
## 十、验收标准
1. [ ] TaskEntity 继承 `FullAuditedEntityWithUser<Guid, IdentityUser>`
2. [ ] 主键类型从 `int` 迁移到 `Guid`
3. [ ] EF Core 迁移成功执行,新增 ABP 审计字段
4. [ ] 服务端 `/tasks` 端点返回 ABP 标准字段
5. [ ] 服务端 `/sync` 端点正确处理软删除
6. [ ] 前端正确适配 Guid 类型和 ABP 字段
7. [ ] 同步规则文档(02-任务同步规则.md)字段命名已修正
8. [ ] 数据模型约束文档(03-数据模型与迁移约束.md)已更新
---
## 十一、风险与缓解
| 风险 | 缓解措施 |
|---|---|
| 主键从 int 变 Guid 为破坏性迁移 | 使用双写/兼容期策略;提供数据迁移脚本 |
| 迁移破坏嵌入式宿主启动 | 在 MAUI/Avalonia 上验证 `Database.Migrate()` 不报错 |
| 前端类型变更导致编译错误 | 同步更新 TypeScript 类型定义 |
| 旧客户端不兼容新 API | API 版本化;新字段为可选/默认值 |
**回滚方案**
- 迁移回滚:`dotnet ef migrations remove`(可能丢失数据)
- 代码回滚:恢复 TaskEntity 原定义
---
## 十二、Touch List
| 文件路径 | 改动类型 | 共享文件 |
|---|---|---|
| `src/Hua.Todo.Core/Entities/TaskEntity.cs` | 重构(继承 ABP 基类) | 否 |
| `src/Hua.Todo.Application/CloudSync/Models/TaskSyncDtos.cs` | DTO 字段更新(新增 ABP 审计字段) | 否 |
| `src/Hua.Todo.Application/Data/TodoDbContext.cs` | 查询过滤器配置 | 否 |
| `src/Hua.Todo.Application/CloudSync/CloudTaskSyncService.cs` | 软删除处理逻辑 | 否 |
| `src/Hua.Todo.Application/Migrations/` | 新增迁移文件 | 否 |
| `src/Hua.Todo.Web/src/types/task.ts` | **重构(Guid 主键 + ABP 审计字段 + 类型修正)** | **前端共享** |
| `src/Hua.Todo.Web/src/api/cloudSync.ts` | API 响应类型对齐 | 否 |
| `src/Hua.Todo.Web/src/stores/taskStore.ts` | pendingUpserts/pendingDeletes 类型修正 | 否 |
| `src/Hua.Todo.Web/src/utils/guid.ts` | **新增 Guid 工具函数** | 否 |
| `docs/manual/04-云同步规则.md` | 文档修正(字段命名) | 是(文档) |
| `.trae/rules/项目/03-数据模型与迁移约束.md` | 实体清单更新 | 是(规则) |
---
## 十三、与其他工单的边界
| 工单 | 边界 |
|---|---|
| 04-CloudSync-服务端基础能力 | 依赖本工单的 ABP 审计字段 |
| 05-CloudSync-客户端配置与工作流 | 依赖本工单的 DTO 字段更新 |
| 08-同源 Host 重构 | 无依赖,可并行 |
> **建议**:本工单与 04/05 存在依赖关系,建议在 04/05 之前完成,或合并为一个工单实现。
---
> **相关文档**
> - ABP 表设计规范:[2.表设计与字段命名规范.md](file:///d:/Codes/CodeSmith/CodeSmith/ShaoHua.CodeSmith.Abp/docs/2.表设计与字段命名规范.md)
> - 同步规则:[02-任务同步规则.md](../../manual/02-任务同步规则.md)
> - 数据模型约束:[03-数据模型与迁移约束.md](../../../.trae/rules/项目/03-数据模型与迁移约束.md)