# 档案服务 **本文引用的文件** - [profile_service.go](file://internal/service/profile_service.go) - [profile_repository.go](file://internal/repository/profile_repository.go) - [profile.go](file://internal/model/profile.go) - [user.go](file://internal/model/user.go) - [texture.go](file://internal/model/texture.go) - [profile_handler.go](file://internal/handler/profile_handler.go) - [common.go](file://internal/types/common.go) - [profile_service_test.go](file://internal/service/profile_service_test.go) - [profile_handler_test.go](file://internal/handler/profile_handler_test.go) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本档“档案服务”文档聚焦于 ProfileService 的职责、方法与内部逻辑,覆盖档案的创建、更新、删除与活跃状态管理;明确档案名称与用户ID的验证规则(名称非空且长度1-16,用户ID大于0),以及状态有效性判断(仅当状态为1时表示正常可用);阐述新创建档案默认为活跃状态的业务规则,并说明多档案用户的活跃档案切换逻辑;解释档案与用户、材质之间的关联关系;最后提供常见错误场景的排查指南,帮助开发者快速定位问题。 ## 项目结构 档案服务位于 internal/service 层,通过 internal/handler 接收HTTP请求,调用 ProfileService 完成业务逻辑,再由 ProfileService 调用 internal/repository 访问数据库;数据模型定义在 internal/model 中,类型定义在 internal/types 中。 ```mermaid graph TB subgraph "接口层" H["profile_handler.go
HTTP处理器"] end subgraph "服务层" S["profile_service.go
ProfileService"] end subgraph "仓储层" R["profile_repository.go
Profile仓储"] end subgraph "模型层" M1["profile.go
Profile模型"] M2["user.go
User模型"] M3["texture.go
Texture模型"] end subgraph "类型定义" T["common.go
CreateProfileRequest/UpdateProfileRequest/ProfileInfo"] end H --> S S --> R R --> M1 R --> M2 R --> M3 H --> T ``` 图表来源 - [profile_handler.go](file://internal/handler/profile_handler.go#L1-L399) - [profile_service.go](file://internal/service/profile_service.go#L1-L253) - [profile_repository.go](file://internal/repository/profile_repository.go#L1-L200) - [profile.go](file://internal/model/profile.go#L1-L64) - [user.go](file://internal/model/user.go#L1-L71) - [texture.go](file://internal/model/texture.go#L1-L77) - [common.go](file://internal/types/common.go#L81-L207) 章节来源 - [profile_handler.go](file://internal/handler/profile_handler.go#L1-L399) - [profile_service.go](file://internal/service/profile_service.go#L1-L253) - [profile_repository.go](file://internal/repository/profile_repository.go#L1-L200) - [profile.go](file://internal/model/profile.go#L1-L64) - [user.go](file://internal/model/user.go#L1-L71) - [texture.go](file://internal/model/texture.go#L1-L77) - [common.go](file://internal/types/common.go#L81-L207) ## 核心组件 - ProfileService:负责档案的创建、查询、更新、删除、活跃状态设置与数量限制检查等核心业务逻辑。 - ProfileRepository:封装数据库访问,包括创建、查询、更新、删除、统计、设置活跃状态等。 - Profile 模型:定义档案的数据结构及与用户、材质的关联。 - Handler:接收HTTP请求,解析参数,调用服务层并返回统一响应。 - 类型定义:CreateProfileRequest、UpdateProfileRequest、ProfileInfo 等用于API契约与响应结构。 章节来源 - [profile_service.go](file://internal/service/profile_service.go#L1-L253) - [profile_repository.go](file://internal/repository/profile_repository.go#L1-L200) - [profile.go](file://internal/model/profile.go#L1-L64) - [profile_handler.go](file://internal/handler/profile_handler.go#L1-L399) - [common.go](file://internal/types/common.go#L81-L207) ## 架构总览 档案服务采用典型的三层架构:Handler 负责接口与参数校验,Service 负责业务规则与流程编排,Repository 负责数据持久化。ProfileService 在创建档案时会进行用户存在性与状态校验、角色名唯一性校验、生成UUID与RSA密钥、创建档案并将其设置为活跃状态;在设置活跃状态时,通过事务将该用户下的其他档案全部置为非活跃,确保同一时刻仅有一个活跃档案。 ```mermaid sequenceDiagram participant C as "客户端" participant H as "Handler" participant S as "ProfileService" participant R as "ProfileRepository" participant DB as "数据库" C->>H : "POST /api/v1/profile" H->>H : "解析请求体(CreateProfileRequest)" H->>S : "CheckProfileLimit(userID, maxProfiles)" S->>R : "CountProfilesByUserID(userID)" R-->>S : "count" S-->>H : "通过/错误" H->>S : "CreateProfile(userID, name)" S->>R : "FindUserByID(userID)" R-->>S : "User" S->>R : "FindProfileByName(name)" R-->>S : "Profile 或 NotFound" S->>S : "生成UUID与RSA私钥" S->>R : "CreateProfile(Profile)" R->>DB : "INSERT" DB-->>R : "OK" S->>R : "SetActiveProfile(uuid, userID)" R->>DB : "事务 : 先将用户其他档案置为非活跃,再将目标置为活跃" DB-->>R : "OK" R-->>S : "OK" S-->>H : "Profile" H-->>C : "200 成功响应" ``` 图表来源 - [profile_handler.go](file://internal/handler/profile_handler.go#L28-L93) - [profile_service.go](file://internal/service/profile_service.go#L17-L68) - [profile_repository.go](file://internal/repository/profile_repository.go#L13-L109) ## 详细组件分析 ### ProfileService 方法与职责 - 创建档案 - 输入:用户ID、档案名称 - 校验:用户存在且状态为1;档案名称唯一;名称长度1-16 - 生成:UUID、RSA私钥(PEM格式) - 写入:创建档案记录,默认 IsActive=true - 并发安全:通过事务将该用户下其他档案置为非活跃,确保仅一个活跃档案 - 获取档案详情 - 输入:档案UUID - 输出:Profile(预加载Skin与Cape) - 获取用户档案列表 - 输入:用户ID - 输出:Profile 列表(按创建时间倒序) - 更新档案 - 输入:UUID、用户ID、可选名称、可选SkinID、可选CapeID - 校验:权限(档案属于当前用户)、名称唯一性(若更改) - 更新:保存变更并重新加载以返回最新数据 - 删除档案 - 输入:UUID、用户ID - 校验:权限 - 删除:物理删除档案 - 设置活跃档案 - 输入:UUID、用户ID - 校验:权限 - 事务:将该用户下其他档案置为非活跃,再将目标置为活跃 - 同步:更新最后使用时间 - 档案数量限制 - 输入:用户ID、最大数量 - 校验:统计当前档案数是否达到上限 - 校验档案归属 - 输入:用户ID、档案UUID - 校验:UUID存在且属于该用户 - 名称批量查询 - 输入:名称数组 - 输出:Profile 列表 - 密钥对查询 - 输入:档案ID - 输出:KeyPair(私钥、公钥、过期时间等) 章节来源 - [profile_service.go](file://internal/service/profile_service.go#L17-L253) - [profile_repository.go](file://internal/repository/profile_repository.go#L13-L177) - [profile.go](file://internal/model/profile.go#L1-L64) ### 数据模型与关联关系 - Profile - 字段:UUID、UserID、Name、SkinID、CapeID、RSAPrivateKey、IsActive、LastUsedAt、CreatedAt、UpdatedAt - 关联:User(外键 UserID)、Texture(SkinID、CapeID) - User - 字段:ID、Username、Email、Role、Status(1: 正常, 0: 禁用, -1: 删除) - Texture - 字段:ID、UploaderID、Name、Type、URL、Hash、IsPublic、DownloadCount、FavoriteCount、IsSlim、Status(1: 正常, 0: 审核中, -1: 已删除) ```mermaid erDiagram USER { bigint id PK varchar username UK varchar email UK smallint status } PROFILE { varchar uuid PK bigint user_id FK varchar name UK bigint skin_id bigint cape_id boolean is_active timestamp last_used_at timestamp created_at timestamp updated_at } TEXTURE { bigint id PK bigint uploader_id FK varchar name varchar type varchar url varchar hash UK boolean is_public integer download_count integer favorite_count boolean is_slim smallint status } USER ||--o{ PROFILE : "拥有" TEXTURE ||--o{ PROFILE : "被使用(Skin/Cape)" ``` 图表来源 - [profile.go](file://internal/model/profile.go#L1-L64) - [user.go](file://internal/model/user.go#L1-L71) - [texture.go](file://internal/model/texture.go#L1-L77) ### 验证规则与状态判断 - 档案名称 - 非空且长度在1-16之间 - 更新时仅当名称发生变更才检查唯一性 - 用户ID - 必须大于0 - 用户状态 - 仅当用户状态为1(正常)时允许创建档案 - 活跃状态 - 默认 IsActive=true - 仅当状态为1时表示“正常可用” - 设置活跃状态时,通过事务将该用户下其他档案置为非活跃 章节来源 - [profile_service.go](file://internal/service/profile_service.go#L17-L68) - [profile_service_test.go](file://internal/service/profile_service_test.go#L1-L77) - [common.go](file://internal/types/common.go#L81-L207) - [user.go](file://internal/model/user.go#L1-L71) ### 活跃档案切换逻辑 - 设计目标:同一用户在同一时刻仅有一个活跃档案 - 实现方式:在设置活跃档案时,使用数据库事务 - 先将该用户下所有档案的 IsActive=false - 再将目标档案 IsActive=true - 最后更新最后使用时间 ```mermaid flowchart TD Start(["开始"]) --> Load["加载档案(uuid, userID)"] Load --> CheckPerm{"权限校验通过?"} CheckPerm --> |否| ErrPerm["返回无权操作"] CheckPerm --> |是| Txn["开启事务"] Txn --> SetAllFalse["将用户其他档案置为非活跃"] SetAllFalse --> SetTargetTrue["将目标档案置为活跃"] SetTargetTrue --> UpdateTime["更新最后使用时间"] UpdateTime --> Commit["提交事务"] Commit --> Done(["结束"]) ErrPerm --> Done ``` 图表来源 - [profile_service.go](file://internal/service/profile_service.go#L161-L188) - [profile_repository.go](file://internal/repository/profile_repository.go#L89-L109) ### API 与错误处理 - 创建档案 - 请求体:CreateProfileRequest(仅需 name,长度1-16) - 成功:返回 ProfileInfo(含 UUID、UserID、Name、IsActive、时间戳等) - 常见错误:未授权、参数错误、已达上限、服务器错误 - 获取档案列表/详情 - 成功:返回 ProfileInfo 列表/对象 - 常见错误:未授权、服务器错误、档案不存在 - 更新档案 - 请求体:UpdateProfileRequest(可选 name、skin_id、cape_id) - 成功:返回更新后的 ProfileInfo - 常见错误:未授权、参数错误、无权操作、档案不存在、服务器错误 - 删除档案 - 成功:返回“删除成功” - 常见错误:未授权、无权操作、档案不存在、服务器错误 - 设置活跃档案 - 成功:返回“设置成功” - 常见错误:未授权、无权操作、档案不存在、服务器错误 章节来源 - [profile_handler.go](file://internal/handler/profile_handler.go#L28-L399) - [common.go](file://internal/types/common.go#L81-L207) ## 依赖关系分析 - Handler 依赖 Service - Service 依赖 Repository - Repository 依赖 Model 与数据库连接 - Model 间通过外键建立关联 ```mermaid graph LR H["profile_handler.go"] --> S["profile_service.go"] S --> R["profile_repository.go"] R --> M1["profile.go"] R --> M2["user.go"] R --> M3["texture.go"] ``` 图表来源 - [profile_handler.go](file://internal/handler/profile_handler.go#L1-L399) - [profile_service.go](file://internal/service/profile_service.go#L1-L253) - [profile_repository.go](file://internal/repository/profile_repository.go#L1-L200) - [profile.go](file://internal/model/profile.go#L1-L64) - [user.go](file://internal/model/user.go#L1-L71) - [texture.go](file://internal/model/texture.go#L1-L77) ## 性能考量 - 查询预加载:获取档案详情与列表时预加载 Skin 与 Cape,减少 N+1 查询风险 - 事务一致性:设置活跃档案使用事务,保证原子性与一致性 - 唯一索引:Name 与 Hash 等字段具备唯一索引,降低重复写入成本 - 时间戳:LastUsedAt 便于后续统计与清理策略 [本节为通用建议,不涉及具体文件分析] ## 故障排查指南 - 创建失败 - 用户不存在或状态异常:检查用户是否存在且状态为1 - 角色名重复:确认名称唯一性 - 达到档案数量上限:检查当前用户档案数量与上限配置 - 数据库错误:查看事务提交与唯一约束冲突 - 更新失败 - 无权操作:确认请求用户ID与档案所属用户一致 - 名称重复:若修改了名称,需确保唯一性 - 删除失败 - 无权操作:确认请求用户ID与档案所属用户一致 - 设置活跃失败 - 无权操作:确认请求用户ID与档案所属用户一致 - 事务回滚:检查数据库事务日志 - 获取失败 - 档案不存在:确认UUID正确且未被删除 章节来源 - [profile_service.go](file://internal/service/profile_service.go#L17-L253) - [profile_repository.go](file://internal/repository/profile_repository.go#L13-L177) - [profile_handler.go](file://internal/handler/profile_handler.go#L153-L399) ## 结论 ProfileService 提供了完整的档案生命周期管理能力,涵盖创建、查询、更新、删除与活跃状态切换,并通过严格的验证规则与事务保障确保数据一致性。档案与用户、材质的关联清晰,便于扩展更多功能。建议在生产环境中结合日志与监控,持续优化性能与稳定性。 [本节为总结性内容,不涉及具体文件分析] ## 附录 - 关键方法路径参考 - 创建档案:[CreateProfile](file://internal/service/profile_service.go#L17-L68) - 获取档案详情:[GetProfileByUUID](file://internal/service/profile_service.go#L71-L81) - 获取用户档案列表:[GetUserProfiles](file://internal/service/profile_service.go#L83-L90) - 更新档案:[UpdateProfile](file://internal/service/profile_service.go#L92-L135) - 删除档案:[DeleteProfile](file://internal/service/profile_service.go#L137-L159) - 设置活跃档案:[SetActiveProfile](file://internal/service/profile_service.go#L161-L188) - 数量限制检查:[CheckProfileLimit](file://internal/service/profile_service.go#L190-L202) - 校验档案归属:[ValidateProfileByUserID](file://internal/service/profile_service.go#L222-L235) - 名称批量查询:[GetProfilesDataByNames](file://internal/service/profile_service.go#L237-L243) - 密钥对查询:[GetProfileKeyPair](file://internal/service/profile_service.go#L245-L253) - Handler 路由与错误映射 - 创建/获取/更新/删除/设置活跃:[profile_handler.go](file://internal/handler/profile_handler.go#L28-L399)