# 资产服务(Asset Service)设计文档 ## 📊 文档状态总结 ### ✅ 已完成 - ✅ 数据库模型设计(`pkg/models/asset.go` 已实现) - ✅ 核心功能设计确认(Q1-Q17, Q23-Q25 已确认) - ✅ 数据库表结构设计(assets、mint_orders、asset_likes 表结构已确定) - ✅ 服务职责边界定义 - ✅ 配置设计(参考 socialService 的配置模式) ### ⚠️ 需要补充和确认 #### 🔴 高优先级(阻塞开发) 1. **User Service 接口补充** - ❌ `UpdateCrystalBalance` RPC 接口(需要在 `proto/user.proto` 中添加) - ⚠️ `UpdateAssetsCount` RPC 接口(Repository 层已实现,需要添加 RPC 接口) 2. **Asset Service Proto 定义** - ❌ 需要创建 `proto/asset.proto` 文件 - ❌ 定义资产服务的所有 RPC 接口 3. **Social Service 接口补充** - ❌ 资产点赞相关的 RPC 接口(需要在 `proto/social.proto` 中添加) #### 🟡 中优先级(建议确认) 4. **事件驱动机制** ✅ **已确认:不使用消息队列** - ✅ 不使用消息队列(RocketMQ/Kafka/RabbitMQ),直接通过 RPC 调用或数据库记录 - ⚠️ 事件格式规范(如需事件记录,可在数据库中记录) - ⚠️ 事件重试机制(如需重试,可在应用层实现) 5. **缓存策略** ✅ **已确认:不使用 Redis 缓存** - ✅ 不使用 Redis 缓存,直接查询数据库 - ✅ 所有数据查询都直接访问数据库 #### 🟢 低优先级(可后续优化) 6. **错误处理国际化** - ⚠️ 是否需要多语言支持 ### 📝 待实现内容 #### 1. 服务实现(未开始) - [ ] 创建 `services/assetService/` 目录结构 - [ ] 实现 Repository 层(asset_repository.go、mint_order_repository.go、asset_like_repository.go) - [ ] 实现 Service 层(asset_service.go、mint_service.go) - [ ] 实现 Provider 层(asset_provider.go) - [ ] 实现 RPC Client(user_rpc_client.go) #### 2. Gateway 集成(未开始) - [ ] 创建 `gateway/controller/asset_controller.go` - [ ] 创建 `gateway/dto/asset_converter.go` - [ ] 在 `gateway/router/router.go` 中添加路由 #### 3. 数据库迁移(未开始) - [ ] 创建表结构迁移脚本 - [ ] 创建索引 #### 4. 测试(未开始) - [ ] 单元测试 - [ ] 集成测试 - [ ] HTTP 完整测试流程 --- ## 📋 快速参考 ### 数据库表设计(基于提供设计 + 服务交互字段) #### assets 表 - **基础字段**(来自提供设计):`id`, `owner_uid`, `star_id`, `name`, `cover_url`, `status`, `tx_hash`, `block_number`, `like_count` - **新增字段**(需求确认):`material_url`(用户上传素材),`description`, `rarity`, `tags`, `visibility`(预留) - **新增字段**(服务交互):`created_at`, `updated_at`, `minted_at`, `deleted_at`, `is_active` #### mint_orders 表 - **基础字段**(来自提供设计):`order_id`(UUID), `user_id`, `asset_id`, `star_id`, `status`, `created_at` - **新增字段**(服务交互):`updated_at`, `minted_at`, `cost_crystal`, `error_message`, `retry_count` ### 服务间交互字段映射 | 交互服务 | 使用的字段 | 用途 | |---------|----------|------| | **User Service** | `mint_orders.cost_crystal` | 扣除/退款水晶 | | **User Service** | `assets.owner_uid`, `assets.star_id` | 更新资产数量 | | **Social Service** | `assets.like_count` | 更新点赞数 | | **Gallery Service** | - | 暂不考虑,后续再实现 | | **Task Service** | `assets.created_at`, `assets.minted_at` | 事件发布 | ### 需要确认的关键问题 **🔴 高优先级(必须确认):** 1. 铸造费用和支付方式(Q1) 2. 区块链集成方式(Q11, Q23) 3. User Service 接口可用性(Q18) **🟡 中优先级(建议确认):** 4. 资产属性字段(Q13) 5. 订单表设计细节(Q14) **🟢 低优先级(可后续优化):** 6. 其他功能细节(Q5-Q10, Q15-Q17, Q19-Q30) --- ## 一、服务概述 ### 1.1 服务定位 **Asset Service(资产服务)** 是负责数字藏品(NFT)全生命周期管理的核心微服务,包括: - 数字藏品的铸造(链下记录 + 链上确权) - 资产查询与列表管理 - 资产详情展示 - 素材管理(平台素材库) - 图片上传与审核 ### 1.2 服务职责边界 **Asset Service 负责:** - ✅ 资产的创建、查询、更新 - ✅ 铸造订单的管理 - ✅ 素材库管理 - ✅ 图片上传处理 - ✅ 资产上链状态跟踪 **Asset Service 不负责:** - ❌ 用户余额管理(CoinBalance, CrystalBalance)- 由 User Service 管理 - ❌ 资产数量统计(AssetsCount)- 由 User Service 管理(通过 RPC 调用更新) - ❌ 资产展示(展馆)- 由 Gallery Service 管理 - ❌ 资产点赞 - 由 Social Service 管理 --- ## 二、核心功能设计 ### 2.1 资产铸造流程 #### 2.1.1 铸造流程概述 ``` 用户发起铸造请求 ↓ 1. 验证用户权限和余额 ↓ 2. 创建资产记录(链下) ↓ 3. 创建铸造订单(异步) ↓ 4. 调用区块链服务上链 ↓ 5. 更新资产状态和链上信息 ↓ 6. 更新用户资产数量(调用 User Service) ↓ 7. 发布事件(asset.mint_complete) ``` #### 2.1.2 ✅ 已确认 **Q1: 铸造费用和支付方式** ✅ - ✅ 铸造需要消耗水晶(CrystalBalance) - ✅ 费用后续同样会引入规则表进行定义,现在直接和 socialService 一致,统一定义在 `config/asset_config.go` 文件中(`CostCrystal`) - ✅ 支付是在创建订单的时候扣除 - ✅ 上链失败会进行退款 **Q2: 铸造材料来源** ✅ - ✅ 目前可以暂不考虑,随机生成一个图片的 URL 即可 - ✅ 后续再进行拓展 **Q3: 铸造限制** ✅ - ✅ 次数限制同样和 Q1 一致,后续同样会引入规则表进行定义 - ✅ 现在直接和 socialService 一致,统一定义在 `config/asset_config.go` 文件中(`MaxMintCountPerDay`, `MaxMintCountPerUser`) **Q4: 异步处理机制** ✅ - ✅ 上链为异步机制 - ✅ 但是目前不引入上链功能,所以只需要做简单的模拟 - ✅ 后续引入后再进行优化 --- ### 2.2 资产查询功能 #### 2.2.1 我的藏品列表 **接口设计:** ``` GET /api/v1/assets/me Query Parameters: - page: 页码(默认1) - page_size: 每页数量(默认20,最大100) - status: 状态筛选(all, pending, minted, failed) - keyword: 关键词搜索(资产名称) - sort: 排序方式(created_at_desc, created_at_asc, name_asc) ``` **响应结构:** ```json { "code": 200, "message": "ok", "data": { "items": [ { "asset_id": 123, "name": "藏品名称", "cover_url": "https://...", "status": "minted", // pending, minting, minted, failed "token_id": "0x123...", "tx_hash": "0xabc...", "created_at": 1704067200000, "minted_at": 1704067300000 } ], "total": 100, "page": 1, "page_size": 20, "has_more": true } } ``` #### 2.2.2 资产详情 **接口设计:** ``` GET /api/v1/assets/{asset_id} ``` **响应结构:** ```json { "code": 200, "message": "ok", "data": { "asset_id": 123, "name": "藏品名称", "description": "藏品描述", "cover_url": "https://...", "owner": { "user_id": 1, "nickname": "张三" }, "star_id": 1, "status": "minted", "token_id": "0x123...", "tx_hash": "0xabc...", "materials": [ { "material_id": 1, "type": "platform", "url": "https://..." } ], "created_at": 1704067200000, "minted_at": 1704067300000, "like_count": 10, "is_liked": false // 当前用户是否点赞 } } ``` #### 2.2.3 ✅ 已确认 **Q5: 资产可见性** ✅ - ✅ 用户不能看到别人的资产 - ✅ 目前不需要考虑分享等功能 - ✅ 但是在表格设计的时候可以留一个权限控制的字段接口出来(`visibility` 字段) **Q6: 资产属性** ✅ - ✅ 名称(name)和封面图(cover_url)是目前设计的必须字段 - ✅ 同样可以预留描述(description)、稀有度(rarity)、标签(tags)的字段接口以便后续功能添加 --- ### 2.3 素材管理功能 #### 2.3.1 平台素材列表 **接口设计:** ``` GET /api/v1/materials/platform Query Parameters: - page: 页码 - page_size: 每页数量 - category: 分类筛选(可选) ``` **响应结构:** ```json { "code": 200, "message": "ok", "data": { "items": [ { "material_id": 1, "name": "素材名称", "url": "https://...", "category": "背景", "star_id": 1 } ], "total": 50, "page": 1, "page_size": 20 } } ``` #### 2.3.2 ✅ 已确认 **Q7: 素材分类和管理** ✅ - ✅ 素材需要根据 `star_id` 进行隔离 **Q8: 用户上传素材** ✅ - ✅ 用户可以上传自己的素材 - ✅ 目前暂不需要审核功能 - ✅ 不需要 `materials` 表,直接在 `assets` 表里面加入一个 `material_url` 字段代表素材的 URL 即可 - ✅ 后续会定期清理这个字段 --- ### 2.4 图片上传功能 #### 2.4.1 上传接口设计 **接口设计:** ``` POST /api/v1/assets/upload Content-Type: multipart/form-data Form Data: - file: 图片文件 - type: 上传类型(cover, material) ``` **响应结构:** ```json { "code": 200, "message": "ok", "data": { "url": "https://minio.example.com/bucket/path/to/image.jpg", "upload_id": "upload_123" } } ``` #### 2.4.2 ✅ 已确认 **Q9: 图片存储和审核** ✅ - ✅ 暂不考虑图片存储的细节问题,存一个 URL 即可 **Q10: 上传任务管理** ✅ - ✅ 不需要上传任务表 - ✅ 直接阻塞上传,上传成功返回后才会允许前端用户进行下一步操作 --- ### 2.5 上链状态查询 #### 2.5.1 状态查询接口 **接口设计:** ``` GET /api/v1/assets/{asset_id}/status ``` **响应结构:** ```json { "code": 200, "message": "ok", "data": { "asset_id": 123, "status": "minting", // pending, minting, minted, failed "tx_hash": "0xabc...", "token_id": "0x123...", "block_number": 12345, "minted_at": 1704067300000, "error_message": "" // 如果失败,错误信息 } } ``` #### 2.5.2 ✅ 已确认 **Q11: 区块链集成** ✅ - ✅ 区块链暂不考虑,后续才会引入相应的函数功能 - ✅ 目前只需要模拟已经上链成功结束即可 **Q12: 上链信息存储** ✅ - ✅ 只需要存储 `tx_hash` 和 `block_number` 即可 - ✅ 不需要 `token_id` --- ## 三、数据库设计 ### 3.1 核心表结构 #### 3.1.1 assets 表(资产表) **基于提供的数据库设计,完善后的表结构:** ```sql CREATE TABLE assets ( -- 主键和基础字段 id BIGSERIAL PRIMARY KEY, -- asset_id (Asset ID) owner_uid BIGINT NOT NULL, -- 当前持有者 (Current Owner) star_id BIGINT NOT NULL, -- 所属星球 (Belonging Planet) name VARCHAR(100) NOT NULL, -- 藏品名称 (Collection Name) cover_url VARCHAR(500) NOT NULL, -- 封面图URL (Cover Image URL) -- 用户上传的素材URL(后续会定期清理) material_url VARCHAR(500), -- 用户上传的素材URL(可选) -- 预留字段(后续功能扩展) description TEXT, -- 藏品描述(预留) rarity INT, -- 稀有度(预留) tags JSONB, -- 标签(预留,JSON数组) -- 权限控制字段(预留) visibility VARCHAR(20) DEFAULT 'private', -- 可见性:private, friends, public(预留) -- 状态字段 status INT NOT NULL DEFAULT 0, -- 0:Pending, 1:Active (状态枚举) -- 链上信息(目前模拟,后续引入区块链功能) tx_hash VARCHAR(100), -- Web3:交易哈希 block_number BIGINT, -- 区块号 -- 社交相关(与 Social Service 交互) like_count INT NOT NULL DEFAULT 0, -- 点赞数 (Like Count) -- 时间戳字段(用于排序、查询、事件追踪) created_at BIGINT NOT NULL, -- 创建时间(毫秒时间戳) updated_at BIGINT NOT NULL, -- 更新时间(毫秒时间戳) minted_at BIGINT, -- 上链成功时间(毫秒时间戳,用于 Task Service 事件) -- 软删除(与现有服务保持一致) deleted_at BIGINT, -- 软删除时间戳(NULL 表示未删除) is_active BOOLEAN NOT NULL DEFAULT true, -- 是否激活(用于快速查询过滤) -- 索引 INDEX idx_assets_owner_star (owner_uid, star_id), INDEX idx_assets_status (status), INDEX idx_assets_created_at (created_at DESC), INDEX idx_assets_tx_hash (tx_hash), INDEX idx_assets_star_active (star_id, is_active), INDEX idx_assets_deleted_at (deleted_at) ); ``` **完整字段列表(基于提供的设计 + 服务交互所需字段):** | 字段名 | 类型 | 约束 | 默认值 | 说明 | 来源 | |--------|------|------|--------|------|------| | `id` | BIGINT | PK, AUTO_INCREMENT | - | 资产ID | 提供设计 | | `owner_uid` | BIGINT | NOT NULL, FK | - | 当前持有者 | 提供设计 | | `star_id` | BIGINT | NOT NULL, FK | - | 所属星球 | 提供设计 | | `name` | VARCHAR(100) | NOT NULL | - | 藏品名称 | 提供设计 | | `cover_url` | VARCHAR(500) | NOT NULL | - | MinIO地址 | 提供设计 | | `status` | INT | NOT NULL | 0 | 状态(0:Pending, 1:Active) | 提供设计 | | `tx_hash` | VARCHAR(100) | NULL | NULL | Web3交易哈希 | 提供设计 | | `token_id` | VARCHAR(100) | NULL | NULL | Web3链上ID | 提供设计 | | `like_count` | INT | NOT NULL | 0 | 点赞数 | 提供设计 | | `created_at` | BIGINT | NOT NULL | - | 创建时间(毫秒时间戳) | **新增** | | `updated_at` | BIGINT | NOT NULL | - | 更新时间(毫秒时间戳) | **新增** | | `minted_at` | BIGINT | NULL | NULL | 上链成功时间(毫秒时间戳) | **新增** | | `deleted_at` | BIGINT | NULL | NULL | 软删除时间戳 | **新增** | | `is_active` | BOOLEAN | NOT NULL | true | 是否激活 | **新增** | **字段说明:** | 字段 | 类型 | 说明 | 用途 | |------|------|------|------| | `id` | bigint | 资产ID(主键) | 唯一标识 | | `owner_uid` | bigint | 当前持有者 | 资产归属,与 User Service 交互 | | `star_id` | bigint | 所属星球 | 数据隔离,与现有服务保持一致 | | `name` | varchar | 藏品名称 | 显示和搜索 | | `cover_url` | varchar | 封面图URL | 图片展示 | | `material_url` | varchar | 用户上传的素材URL | 用户自定义素材(后续会清理) | | `status` | int | 状态(0:Pending, 1:Active) | 状态管理 | | `tx_hash` | varchar | 交易哈希 | 链上查询(目前模拟) | | `block_number` | bigint | 区块号 | 链上查询(目前模拟) | | `like_count` | int | 点赞数 | 与 Social Service 交互 | | `created_at` | bigint | 创建时间 | 排序、查询、Task Service 事件 | | `updated_at` | bigint | 更新时间 | 追踪变更 | | `minted_at` | bigint | 上链成功时间 | 事件发布、统计 | | `deleted_at` | bigint | 软删除时间 | 数据恢复、审计 | | `is_active` | boolean | 是否激活 | 快速查询过滤 | | `description` | text | 藏品描述 | 🔵 预留字段 | | `rarity` | int | 稀有度 | 🔵 预留字段 | | `tags` | jsonb | 标签(JSON数组) | 🔵 预留字段 | | `visibility` | varchar | 可见性(private/friends/public) | 🔵 预留字段 | **状态枚举值:** ```go const ( AssetStatusPending = 0 // 待处理(创建中) AssetStatusActive = 1 // 已激活(上链成功) // 预留:AssetStatusMinting = 2 // 上链中 // 预留:AssetStatusFailed = 3 // 上链失败 ) ``` **索引设计说明:** | 索引名 | 字段 | 用途 | |--------|------|------| | `idx_assets_owner_star` | `(owner_uid, star_id)` | 查询用户的资产列表 | | `idx_assets_status` | `(status)` | 按状态筛选资产 | | `idx_assets_created_at` | `(created_at DESC)` | 按创建时间排序 | | `idx_assets_tx_hash` | `(tx_hash)` | 通过交易哈希查询 | | `idx_assets_star_active` | `(star_id, is_active)` | 按明星和激活状态查询 | | `idx_assets_deleted_at` | `(deleted_at)` | 软删除查询过滤 | **Q13: 资产表字段补充** ✅ - ✅ `description`(描述)字段:已添加为预留字段 - ✅ `block_number`(区块号)字段:已添加 - ✅ `token_id`(链上ID)字段:不需要,已移除 - ✅ `contract_address`(合约地址)字段:不需要 - ✅ `chain_id`(链ID)字段:不需要 - ✅ `material_url`(用户上传素材URL)字段:已添加,后续会定期清理 - ✅ 不需要合约地址和链ID,其他都需要(description, block_number等) #### 3.1.2 mint_orders 表(铸造订单表) **基于提供的数据库设计,完善后的表结构:** ```sql CREATE TABLE mint_orders ( -- 主键 order_id VARCHAR(100) PRIMARY KEY, -- 铸造订单号 (Mint Order Number) -- 关联字段 user_id BIGINT NOT NULL, -- 用户ID asset_id BIGINT, -- 关联资产(生成后回填) (Associated Asset) star_id BIGINT NOT NULL, -- 明星ID(用于数据隔离) -- 状态字段 status VARCHAR(20) NOT NULL DEFAULT 'PENDING', -- PENDING/PROCESSING/SUCCESS/FAILED -- 费用相关(与 User Service 交互) cost_crystal BIGINT DEFAULT 0, -- 消耗的水晶数量(用于记录和审计) -- 错误处理 error_message TEXT, -- 错误信息(如果失败) retry_count INT DEFAULT 0, -- 重试次数(用于上链失败重试) -- 时间戳字段 created_at BIGINT NOT NULL, -- 创建时间(毫秒时间戳) updated_at BIGINT NOT NULL, -- 更新时间(毫秒时间戳) minted_at BIGINT, -- 上链成功时间(用于 Task Service 事件) -- 外键约束 FOREIGN KEY (asset_id) REFERENCES assets(id) ON DELETE SET NULL, -- 索引 INDEX idx_mint_orders_user_star (user_id, star_id), INDEX idx_mint_orders_asset (asset_id), INDEX idx_mint_orders_status (status), INDEX idx_mint_orders_created_at (created_at DESC) ); ``` **字段说明:** | 字段 | 类型 | 说明 | 用途 | |------|------|------|------| | `order_id` | varchar | 铸造订单号(主键) | 唯一标识,使用 UUID 生成 | | `user_id` | bigint | 用户ID | 与 User Service 交互 | | `asset_id` | bigint | 关联资产ID | 关联 assets 表(创建资产后回填) | | `star_id` | bigint | 明星ID | 数据隔离 | | `status` | varchar | 订单状态 | PENDING/PROCESSING/SUCCESS/FAILED | | `cost_crystal` | bigint | 消耗的水晶数量 | 记录费用,用于审计和退款 | | `error_message` | text | 错误信息 | 失败原因记录 | | `retry_count` | int | 重试次数 | 上链失败重试机制 | | `created_at` | bigint | 创建时间 | 排序、查询 | | `updated_at` | bigint | 更新时间 | 追踪变更 | | `minted_at` | bigint | 上链成功时间 | Task Service 事件发布 | **状态枚举值:** ```go const ( MintOrderStatusPending = "PENDING" // 待处理 MintOrderStatusProcessing = "PROCESSING" // 处理中(上链中,目前模拟) MintOrderStatusSuccess = "SUCCESS" // 成功 MintOrderStatusFailed = "FAILED" // 失败 // 注意:不需要 CANCELLED 状态,不支持订单取消功能 ) ``` **字段说明:** | 字段 | 类型 | 说明 | 状态 | |------|------|------|------| | `order_id` | varchar | 铸造订单号(UUID) | ✅ 必需 | | `user_id` | bigint | 用户ID | ✅ 必需 | | `asset_id` | bigint | 关联资产ID | ✅ 必需 | | `star_id` | bigint | 明星ID | ✅ 必需 | | `status` | varchar | 订单状态 | ✅ 必需 | | `cost_crystal` | bigint | 消耗的水晶数量 | ✅ 必需 | | `error_message` | text | 错误信息 | ✅ 必需 | | `retry_count` | int | 重试次数 | ✅ 必需 | | `created_at` | bigint | 创建时间 | ✅ 必需 | | `updated_at` | bigint | 更新时间 | ✅ 必需 | | `minted_at` | bigint | 上链成功时间 | ✅ 必需 | ### 3.2 与现有服务交互所需的额外字段 #### 3.2.1 与 User Service 交互 **需要添加的字段:** 1. **`assets.created_at` / `mint_orders.created_at`** - **用途**:记录创建时间,用于: - 资产列表排序(按创建时间) - Task Service 事件发布(`asset.mint` 事件需要时间戳) - 统计和报表(每日/每月新增资产数) 2. **`assets.minted_at` / `mint_orders.minted_at`** - **用途**:记录上链成功时间,用于: - Task Service 事件发布(`asset.mint_complete` 事件) - 统计上链成功率 - 计算上链耗时 3. **`mint_orders.cost_crystal`** - **用途**:记录消耗的水晶数量,用于: - 调用 User Service 扣除余额时的参数 - 上链失败时的退款计算 - 费用审计和统计 4. **`assets.updated_at` / `mint_orders.updated_at`** - **用途**:追踪数据变更,用于: - 数据同步和缓存更新 - 审计日志 #### 3.2.2 与 Social Service 交互 **已包含的字段:** 1. **`assets.like_count`** - **用途**:存储点赞数,避免每次查询都 JOIN `asset_likes` 表 - **更新方式**:Social Service 点赞/取消点赞时,通过 RPC 调用更新 **✅ 已确认:** - ✅ 暂不考虑 Gallery Service,不需要 `is_exhibited` 字段 #### 3.2.3 与 Gallery Service 交互(暂不考虑) **✅ 已确认:** - ✅ 目前不考虑 Gallery Service 的实现 - ✅ 后续引入 Gallery Service 时,再添加相应的字段和接口 - ✅ 可能的字段:`assets.is_exhibited` 或通过关联表实现 #### 3.2.4 与 Task Service 交互 **需要添加的字段:** 1. **`assets.created_at`** - **用途**:发布 `asset.mint` 事件时的时间戳 2. **`assets.minted_at`** - **用途**:发布 `asset.mint_complete` 事件时的时间戳 **事件发布格式:** ```json { "event_type": "asset.mint_complete", "user_id": 1, "star_id": 1, "asset_id": 123, "minted_at": 1704067300000, "timestamp": 1704067300000 } ``` #### 3.2.5 数据隔离和软删除 **需要添加的字段:** 1. **`assets.deleted_at` / `mint_orders.deleted_at`** - **类型**:BIGINT NULL - **用途**:软删除,与现有服务(User Service)保持一致 - **查询过滤**:`WHERE deleted_at IS NULL` 2. **`assets.is_active`** - **类型**:BOOLEAN DEFAULT true - **用途**:快速查询过滤,避免每次都检查 `deleted_at` - **索引**:`(star_id, is_active)` 复合索引 #### 3.2.6 字段添加总结 **assets 表需要添加的字段:** | 字段名 | 类型 | 默认值 | 说明 | 交互服务 | |--------|------|--------|------|----------| | `created_at` | BIGINT | NOT NULL | 创建时间(毫秒时间戳) | Task Service | | `updated_at` | BIGINT | NOT NULL | 更新时间(毫秒时间戳) | 通用 | | `minted_at` | BIGINT | NULL | 上链成功时间(毫秒时间戳) | Task Service | | `deleted_at` | BIGINT | NULL | 软删除时间戳 | 通用 | | `is_active` | BOOLEAN | true | 是否激活 | 通用 | **mint_orders 表需要添加的字段:** | 字段名 | 类型 | 默认值 | 说明 | 交互服务 | |--------|------|--------|------|----------| | `updated_at` | BIGINT | NOT NULL | 更新时间(毫秒时间戳) | 通用 | | `minted_at` | BIGINT | NULL | 上链成功时间(毫秒时间戳) | Task Service | | `cost_crystal` | BIGINT | 0 | 消耗的水晶数量 | User Service | | `error_message` | TEXT | NULL | 错误信息 | 错误处理 | | `retry_count` | INT | 0 | 重试次数 | 错误处理 | --- **✅ 已确认:** - ✅ 不需要 `materials` 表:用户上传的素材直接存储在 `assets.material_url` 字段中 - ✅ 不需要 `asset_materials` 表:资产和素材的关联关系不需要单独维护 - ✅ 不需要 `upload_tasks` 表:上传采用阻塞式,上传成功返回后才会允许前端用户进行下一步操作 - ✅ 素材隔离:根据 `star_id` 进行隔离(在 `assets` 表中已有 `star_id` 字段) #### 3.1.3 asset_likes 表(点赞记录表) **用于存储用户对资产的点赞记录,支持高并发场景:** ```sql CREATE TABLE asset_likes ( id BIGSERIAL PRIMARY KEY, asset_id BIGINT NOT NULL, user_id BIGINT NOT NULL, star_id BIGINT NOT NULL, -- 用于数据隔离和查询优化 created_at BIGINT NOT NULL, -- 唯一索引:防止重复点赞(数据库层面保护) UNIQUE KEY uk_asset_likes_user_asset (asset_id, user_id), -- 索引:用于查询用户点赞列表 INDEX idx_asset_likes_user_star (user_id, star_id, created_at DESC), -- 索引:用于查询资产点赞用户列表(可选功能) INDEX idx_asset_likes_asset (asset_id, created_at DESC), -- 外键约束 FOREIGN KEY (asset_id) REFERENCES assets(id) ON DELETE CASCADE ); ``` **字段说明:** | 字段 | 类型 | 说明 | 用途 | |------|------|------|------| | `id` | bigint | 主键 | 唯一标识 | | `asset_id` | bigint | 资产ID | 关联 assets 表 | | `user_id` | bigint | 用户ID | 点赞用户 | | `star_id` | bigint | 明星ID | 数据隔离,查询优化 | | `created_at` | bigint | 创建时间 | 排序、统计 | **设计要点:** - ✅ **唯一索引**:`uk_asset_likes_user_asset` 防止重复点赞 - ✅ **复合索引**:`idx_asset_likes_user_star` 支持查询用户点赞列表 - ✅ **外键约束**:资产删除时自动删除点赞记录 - ✅ **第一阶段设计**:直接数据库查询,不使用 Redis 缓存(后续可根据性能需求再引入) **详细设计文档:** [资产点赞功能高性能设计.md](./资产点赞功能高性能设计.md) --- ## 四、服务间交互设计 ### 4.1 与 User Service 的交互 #### 4.1.1 需要调用的接口 **验证用户和粉丝档案:** ``` RPC: ValidateUser(user_id) -> bool RPC: ValidateFanProfile(user_id, star_id) -> bool ``` - **使用场景**:创建铸造订单前验证用户有效性 - **使用字段**:`mint_orders.user_id`, `mint_orders.star_id` **扣除/增加余额:** ``` RPC: UpdateCrystalBalance(user_id, star_id, delta) -> new_balance RPC: UpdateCoinBalance(user_id, star_id, delta) -> new_balance ``` - **使用场景**: - 创建铸造订单时扣除水晶(`mint_orders.cost_crystal`) - 上链失败时退款 - **使用字段**:`mint_orders.cost_crystal`, `mint_orders.user_id`, `mint_orders.star_id` **更新资产数量:** ``` RPC: UpdateAssetsCount(user_id, star_id, delta) -> new_count ``` - **使用场景**:资产上链成功后,更新用户的资产数量 - **使用字段**:`assets.owner_uid`, `assets.star_id` - **触发时机**:`assets.status` 从 `0` (Pending) 变为 `1` (Active) 时 #### 4.1.2 需要提供的接口 **查询用户信息(用于资产详情展示):** ``` RPC: GetUserInfo(user_id) -> UserInfo ``` - **使用场景**:资产详情中显示持有者信息 - **使用字段**:`assets.owner_uid` **需要确认的问题 ⚠️** **Q18: User Service 接口** - ✅ `ValidateUser(user_id) -> bool` - **已实现**(通过 `GetUser` RPC 接口实现,Social Service 中已有使用) - ✅ `ValidateFanProfile(user_id, star_id) -> bool` - **已实现**(通过 `GetFanProfile` RPC 接口实现,Social Service 中已有使用) - ❌ `UpdateCrystalBalance(user_id, star_id, delta) -> new_balance` - **未实现**,需要在 User Service 中添加 RPC 接口 - ⚠️ `UpdateAssetsCount(user_id, star_id, delta) -> new_count` - **Repository 层已实现**(`IncrementAssetsCount`/`DecrementAssetsCount`),但**缺少 RPC 接口**,需要在 User Service 中添加 **补充说明:** - `ValidateUser` 和 `ValidateFanProfile` 可以通过现有的 `GetUser` 和 `GetFanProfile` 接口实现,返回错误即表示不存在 - `UpdateCrystalBalance` 需要新增 RPC 接口,用于扣除/增加水晶余额 - `UpdateAssetsCount` 需要在 User Service 的 Proto 中新增 RPC 接口,调用现有的 Repository 方法 **Q19: 接口提供** - ✅ Asset Service 需要提供 RPC 接口给其他服务 - ✅ 需要调用的服务: - **Social Service**:需要 `GetAsset(asset_id)` 接口用于验证资产是否存在(点赞功能) - **Gallery Service**(后续):需要 `ValidateAsset` 和 `GetAsset` 接口 - **Task Service**(后续):可能需要查询资产信息用于事件处理 --- ### 4.2 与 Social Service 的交互 #### 4.2.1 点赞功能交互 **Social Service 需要提供的接口:** **更新点赞数:** ``` RPC: UpdateAssetLikeCount(asset_id, delta) -> new_count ``` - **使用场景**:用户点赞/取消点赞时,更新 `assets.like_count` - **使用字段**:`assets.like_count` - **delta 值**:+1(点赞)或 -1(取消点赞) **查询用户是否点赞:** ``` RPC: CheckAssetLike(user_id, star_id, asset_id) -> bool ``` - **使用场景**:资产详情中显示 `is_liked` 状态 - **使用字段**:`assets.id` **Asset Service 需要提供的接口:** **获取资产信息:** ``` RPC: GetAsset(asset_id) -> AssetInfo ``` - **使用场景**:Social Service 点赞时验证资产是否存在 - **使用字段**:`assets.id`, `assets.status`, `assets.is_active` **✅ 简化设计方案(第一阶段,直接数据库交互):** **核心设计要点:** 1. **数据库直接交互** - 点赞操作直接写入数据库 - 使用数据库原子更新保证一致性 - 使用唯一索引防止重复点赞 2. **原子操作** - 使用 `UPDATE assets SET like_count = like_count + 1` 原子更新 - 使用数据库唯一索引 `uk_asset_likes_user_asset` 防止重复 3. **防重复点赞** - 数据库唯一索引 `uk_asset_likes_user_asset` 保护 - 应用层先查询再插入(双重保护) 4. **性能优化** - 数据库索引优化(`uk_asset_likes_user_asset`, `idx_asset_likes_user_star`) - 原子更新减少锁竞争 - 不使用 Redis 缓存,直接查询数据库(后续可根据性能需求再引入) **实现方式:** ```go // 点赞操作(直接数据库) 1. 检查是否已点赞:SELECT COUNT(*) FROM asset_likes WHERE asset_id = ? AND user_id = ? 2. 如果未点赞: - INSERT INTO asset_likes (asset_id, user_id, star_id, created_at) - UPDATE assets SET like_count = like_count + 1 WHERE id = ? 3. 返回成功 ``` **后续优化(第二阶段,暂不实现):** - 如需提升性能,可后续引入 Redis 缓存 - 可考虑异步写入数据库 - 详细设计参考:[资产点赞功能高性能设计.md](./资产点赞功能高性能设计.md) **需要确认的问题 ⚠️** **Q20: 点赞功能实现** - ✅ 资产点赞功能在 Social Service 中实现(参考:[资产点赞功能高性能设计.md](./资产点赞功能高性能设计.md)) - ✅ Asset Service 不需要提供资产列表,Social Service 直接查询 assets 表 - ✅ 资产详情中的 like_count 和 is_liked 获取方式: - **当前实现**:直接查询数据库(`assets.like_count` 和 `asset_likes` 表) - **后续优化**:如需提升性能,可后续引入 Redis 缓存(暂不实现) - ⚠️ **需要补充**:Social Service 的 Proto 中需要添加资产点赞相关的 RPC 接口定义(`LikeAsset`, `UnlikeAsset`, `CheckAssetLike` 等) --- ### 4.3 与 Gallery Service 的交互 #### 4.3.1 资产验证 **Asset Service 需要提供的接口:** **验证资产是否存在:** ``` RPC: ValidateAsset(asset_id, user_id, star_id) -> bool ``` - **使用场景**:Gallery Service 放置资产前验证资产是否存在且属于当前用户 - **使用字段**:`assets.id`, `assets.owner_uid`, `assets.star_id`, `assets.status`, `assets.is_active` **获取资产信息:** ``` RPC: GetAsset(asset_id) -> AssetInfo ``` - **使用场景**:Gallery Service 获取资产信息用于展示 - **使用字段**:`assets.*` #### 4.3.2 展馆状态同步 **Gallery Service 需要提供的接口:** **更新资产展馆状态:** ``` RPC: UpdateAssetExhibitionStatus(asset_id, is_exhibited) -> void ``` - **使用场景**:资产放置/下架时,更新 `assets.is_exhibited` - **使用字段**:`assets.is_exhibited` - **触发时机**: - 放置资产:`is_exhibited = true` - 下架资产:`is_exhibited = false` **需要确认的问题 ⚠️** **Q21: 展馆集成** - [ ] Gallery Service 是否需要验证资产是否存在? - [ ] Asset Service 是否需要提供资产列表接口给 Gallery Service? - [ ] 资产下架时,是否需要通知 Gallery Service? - [ ] 是否需要 `assets.is_exhibited` 字段,还是通过关联表查询? --- ### 4.4 与 Task Service 的交互 #### 4.4.1 事件发布 ✅ **已确认:不使用消息队列** **实现方式:** - ✅ 不使用消息队列(RocketMQ/Kafka/RabbitMQ) - ✅ 如需事件通知,直接通过 RPC 调用 Task Service - ✅ 如需事件记录,可在数据库中创建事件表进行记录 **事件类型(如需实现):** 1. **`asset.mint`** - 资产创建事件 - **触发时机**:创建资产记录时(`assets.status = 0`) - **使用字段**:`assets.created_at`, `assets.owner_uid`, `assets.star_id`, `assets.id` - **实现方式**:直接 RPC 调用 Task Service 或数据库记录 2. **`asset.mint_complete`** - 资产上链成功事件 - **触发时机**:资产上链成功,`assets.status` 从 `0` 变为 `1` 时 - **使用字段**:`assets.minted_at`, `assets.owner_uid`, `assets.star_id`, `assets.id` - **实现方式**:直接 RPC 调用 Task Service 或数据库记录 3. **`asset.mint_failed`** - 资产上链失败事件(可选) - **触发时机**:资产上链失败时 - **实现方式**:直接 RPC 调用 Task Service 或数据库记录 **✅ 已确认:** - ✅ 不使用消息队列,直接通过 RPC 调用或数据库记录 - ⚠️ 事件格式是否需要统一规范?**待确认**(如需事件记录,可在数据库中创建事件表) - ⚠️ 是否需要事件重试机制?**待确认**(如需重试,可在应用层实现) - ⚠️ 是否需要 `asset.mint_failed` 事件(上链失败时)?**待确认**(如需记录,可在数据库中记录) --- ## 五、配置设计 ### 5.1 配置结构 参考 `socialService` 的配置设计,在 `assetService/config/asset_config.go` 中定义配置: ```go package config // AssetConfig 资产服务配置 type AssetConfig struct { // MintConfig 铸造相关配置 MintConfig MintConfig // RetryConfig 重试相关配置 RetryConfig RetryConfig } // MintConfig 铸造配置 type MintConfig struct { // CostCrystal 铸造费用(水晶数量) // 后续会引入规则表进行定义,现在统一定义在config文件中 CostCrystal int64 // MaxMintCountPerDay 每日最大铸造次数 // 后续会引入规则表进行定义,现在统一定义在config文件中 MaxMintCountPerDay int // MaxMintCountPerUser 用户最大铸造次数(总次数) // 后续会引入规则表进行定义,现在统一定义在config文件中 MaxMintCountPerUser int } // RetryConfig 重试配置 type RetryConfig struct { // MaxRetryCount 上链失败最大重试次数 MaxRetryCount int // RetryIntervalSeconds 重试间隔(秒) RetryIntervalSeconds int } // GlobalAssetConfig 全局资产配置实例 var GlobalAssetConfig = &AssetConfig{ MintConfig: MintConfig{ CostCrystal: 100, // 默认100水晶 MaxMintCountPerDay: 10, // 默认每日10次 MaxMintCountPerUser: 100, // 默认总次数100次 }, RetryConfig: RetryConfig{ MaxRetryCount: 3, // 默认重试3次 RetryIntervalSeconds: 5, // 默认间隔5秒 }, } ``` ### 5.2 配置使用场景 #### 5.2.1 铸造费用(CostCrystal) **使用场景:** - 创建铸造订单时,从用户账户扣除 `CostCrystal` 数量的水晶 - 上链失败时,退还 `CostCrystal` 数量的水晶 **实现位置:** - `service/mint_service.go` - `CreateMintOrder` 方法 #### 5.2.2 次数限制(MaxMintCountPerDay / MaxMintCountPerUser) **使用场景:** - 创建铸造订单前,检查用户是否超过每日/总次数限制 **实现位置:** - `service/mint_service.go` - `CreateMintOrder` 方法 - 需要查询 `mint_orders` 表统计用户今日/总铸造次数 #### 5.2.3 重试配置(MaxRetryCount / RetryIntervalSeconds) **使用场景:** - 上链失败时,根据 `MaxRetryCount` 决定是否重试 - 重试间隔由 `RetryIntervalSeconds` 控制 **实现位置:** - `service/mint_service.go` - 上链失败处理逻辑(目前模拟) ### 5.3 配置更新方法(预留) ```go // UpdateMintConfig 更新铸造配置 // 注意:后续可以从规则表或配置中心读取配置并调用此方法更新 func (c *AssetConfig) UpdateMintConfig(costCrystal int64, maxPerDay, maxPerUser int) { c.MintConfig.CostCrystal = costCrystal c.MintConfig.MaxMintCountPerDay = maxPerDay c.MintConfig.MaxMintCountPerUser = maxPerUser } // UpdateRetryConfig 更新重试配置 func (c *AssetConfig) UpdateRetryConfig(maxRetryCount, retryIntervalSeconds int) { c.RetryConfig.MaxRetryCount = maxRetryCount c.RetryConfig.RetryIntervalSeconds = retryIntervalSeconds } ``` **✅ 已确认:** - ✅ 铸造费用:配置在 `config/asset_config.go` 中,创建订单时扣除,上链失败退款 - ✅ 次数限制:配置在 `config/asset_config.go` 中,后续会引入规则表 - ✅ 重试次数:配置在 `config/asset_config.go` 中,默认3次 --- ## 六、技术架构设计 ### 5.1 服务结构 ``` assetService/ ├── main.go # 服务入口 ├── config/ # 配置管理 │ └── asset_config.go ├── repository/ # 数据访问层 │ ├── asset_repository.go │ ├── mint_order_repository.go │ └── asset_like_repository.go # 点赞记录(第一阶段:直接数据库) ├── service/ # 业务逻辑层 │ ├── asset_service.go │ └── mint_service.go ├── provider/ # RPC 提供者 │ └── asset_provider.go ├── client/ # RPC 客户端(调用其他服务) │ └── user_rpc_client.go ├── proto/ # Proto 定义(可选,如果单独定义) └── start.sh # 启动脚本 ``` ### 5.2 外部依赖 #### 6.2.1 区块链服务 **✅ 已确认:** - ✅ 区块链暂不考虑,后续才会引入相应的功能 - ✅ 目前只需要模拟已经上链成功结束即可 - ✅ 上链为异步机制,但目前不引入上链功能,只做简单模拟 **实现方式:** - 创建资产时,随机生成 `tx_hash` 和 `block_number` - 模拟异步上链:延迟几秒后更新 `assets.status = 1`(Active) - 后续引入区块链功能后再进行优化 #### 6.2.2 对象存储服务 **✅ 已确认:** - ✅ 暂不考虑图片存储的细节问题,存一个URL即可 - ✅ 封面图URL直接存储在 `assets.cover_url` 字段中 - ✅ 用户上传的素材URL存储在 `assets.material_url` 字段中(后续会定期清理) **实现方式:** - 前端上传图片后,返回图片URL - 后端直接存储URL,不进行图片处理 --- ## 七、API 接口设计 ### 7.1 接口列表 | 功能 | 方法 | 路径 | 说明 | |------|------|------|------| | 创建铸造订单 | POST | `/api/v1/assets/mints` | 创建资产并发起铸造(包含上传封面图) | | 获取我的藏品列表 | GET | `/api/v1/assets/me` | 获取当前用户的藏品列表 | | 获取资产详情 | GET | `/api/v1/assets/{asset_id}` | 获取资产详细信息(仅限自己的资产) | | 查询上链状态 | GET | `/api/v1/assets/{asset_id}/status` | 查询资产上链状态(仅限自己的资产) | **✅ 已确认:** - ✅ 不需要单独的上传接口:上传采用阻塞式,在创建铸造订单时一起处理 - ✅ 不需要素材管理接口:用户上传的素材直接存储在 `assets.material_url` 字段中 - ✅ 不需要订单取消接口:不支持订单取消功能 - ✅ 用户不能看到别人的资产:所有查询接口都只返回当前用户的资产 ### 6.2 需要确认的问题 ⚠️ **Q26: API 路径规范** - ✅ API 路径前缀使用 `/api/v1/assets`(与其他服务保持一致) - ✅ 需要版本控制(v1) **Q27: 权限控制** - ✅ 所有接口都需要登录(通过 Gateway 的 auth middleware) - ✅ 资产查询接口需要验证资产所有权(只能查询自己的资产) - ✅ 创建铸造订单接口需要验证用户权限和余额 --- ## 七、数据隔离设计 ### 7.1 隔离方案 **所有表都包含 `star_id` 字段,实现数据隔离:** ```sql -- 所有查询都基于 user_id + star_id SELECT * FROM assets WHERE user_id = ? AND star_id = ?; ``` ### 7.2 需要确认的问题 ⚠️ **Q28: 跨明星资产** - ✅ 资产不能跨明星使用(通过 `star_id` 字段隔离) - ✅ 用户切换明星身份后,只能看到当前明星下的资产(通过 `star_id` 过滤) --- ## 八、性能优化设计 ### 8.1 缓存策略 **需要确认的问题 ⚠️** **Q29: 缓存需求** ✅ **已确认:不使用 Redis 缓存** - ✅ 不使用 Redis 缓存,所有数据查询都直接访问数据库 - ✅ 所有接口都直接查询数据库,保证数据实时性 - ⚠️ **后续优化**:如需提升性能,可后续引入 Redis 缓存(暂不实现) ### 8.2 分页和索引 - ✅ 所有列表接口都支持分页(默认 page=1, page_size=20,最大 page_size=100) - ✅ 关键字段建立索引(user_id, star_id, status, created_at) --- ## 九、错误处理设计 ### 9.1 错误码定义 **需要确认的问题 ⚠️** **Q30: 错误处理** - ✅ 使用统一的错误码体系(参考 `pkg/errors/errors.go`) - ⚠️ **待确认**:错误信息是否需要国际化?(建议第一阶段仅支持中文,后续再扩展) --- ## 十、数据库设计总结 ### 10.1 完整表结构(基于提供设计 + 服务交互字段) #### assets 表(最终设计) ```sql CREATE TABLE assets ( -- 主键和基础字段(来自提供设计) id BIGSERIAL PRIMARY KEY, owner_uid BIGINT NOT NULL, star_id BIGINT NOT NULL, name VARCHAR(100) NOT NULL, cover_url VARCHAR(500) NOT NULL, material_url VARCHAR(500), -- 用户上传的素材URL(后续会定期清理) description TEXT, -- 藏品描述(预留) rarity INT, -- 稀有度(预留) tags JSONB, -- 标签(预留,JSON数组) visibility VARCHAR(20) DEFAULT 'private', -- 可见性(预留) status INT NOT NULL DEFAULT 0, -- 0:Pending, 1:Active tx_hash VARCHAR(100), -- 交易哈希(目前模拟) block_number BIGINT, -- 区块号(目前模拟) like_count INT NOT NULL DEFAULT 0, -- 服务交互所需字段(新增) created_at BIGINT NOT NULL, -- Task Service 事件 updated_at BIGINT NOT NULL, -- 通用 minted_at BIGINT, -- Task Service 事件 deleted_at BIGINT, -- 软删除 is_active BOOLEAN NOT NULL DEFAULT true, -- 快速查询 -- 索引 INDEX idx_assets_owner_star (owner_uid, star_id), INDEX idx_assets_status (status), INDEX idx_assets_created_at (created_at DESC), INDEX idx_assets_tx_hash (tx_hash), INDEX idx_assets_star_active (star_id, is_active), INDEX idx_assets_deleted_at (deleted_at) ); ``` #### mint_orders 表(最终设计) ```sql CREATE TABLE mint_orders ( -- 主键和基础字段(来自提供设计) order_id VARCHAR(100) PRIMARY KEY, user_id BIGINT NOT NULL, asset_id BIGINT, star_id BIGINT NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'PENDING', created_at BIGINT NOT NULL, -- 服务交互所需字段(新增) updated_at BIGINT NOT NULL, -- 通用 minted_at BIGINT, -- Task Service 事件 cost_crystal BIGINT DEFAULT 0, -- User Service 交互 error_message TEXT, -- 错误处理 retry_count INT DEFAULT 0, -- 重试机制 -- 外键和索引 FOREIGN KEY (asset_id) REFERENCES assets(id) ON DELETE SET NULL, INDEX idx_mint_orders_user_star (user_id, star_id), INDEX idx_mint_orders_asset (asset_id), INDEX idx_mint_orders_status (status), INDEX idx_mint_orders_created_at (created_at DESC) ); ``` ### 10.2 字段分类总结 **来自提供设计的字段:** - ✅ `assets.id`, `assets.owner_uid`, `assets.star_id`, `assets.name`, `assets.cover_url` - ✅ `assets.status`, `assets.tx_hash`, `assets.like_count` - ✅ `mint_orders.order_id`, `mint_orders.user_id`, `mint_orders.asset_id`, `mint_orders.status`, `mint_orders.created_at` **根据需求新增的字段:** - ✅ `assets.material_url` - 用户上传的素材URL(后续会定期清理) - ✅ `assets.description`, `assets.rarity`, `assets.tags`, `assets.visibility` - 预留字段 - ✅ `assets.block_number` - 区块号(目前模拟) - ✅ `assets.created_at`, `assets.updated_at`, `assets.minted_at` - 时间戳(Task Service 事件) - ✅ `assets.deleted_at`, `assets.is_active` - 软删除(与现有服务一致) - ✅ `mint_orders.updated_at`, `mint_orders.minted_at` - 时间戳 - ✅ `mint_orders.cost_crystal` - 费用记录(User Service 交互) - ✅ `mint_orders.error_message`, `mint_orders.retry_count` - 错误处理 **已移除的字段:** - ❌ `assets.token_id` - 不需要(根据Q12确认) - ❌ `assets.is_exhibited` - 暂不需要(Gallery Service集成后续再考虑) --- ## 十一、待确认问题汇总 ### ✅ 已确认的问题 **Q1-Q4: 铸造流程相关** ✅ - ✅ Q1: 铸造费用在config文件中定义,创建订单时扣除,上链失败退款 - ✅ Q2: 暂不考虑,随机生成图片URL即可 - ✅ Q3: 次数限制在config文件中定义 - ✅ Q4: 上链为异步机制,但目前只做简单模拟 **Q5-Q6: 资产可见性和属性** ✅ - ✅ Q5: 用户不能看到别人的资产,预留权限控制字段 - ✅ Q6: 名称和封面图必须,预留描述、稀有度、标签字段 **Q7-Q10: 素材和上传** ✅ - ✅ Q7: 素材需要根据star_id隔离 - ✅ Q8: 用户可以上传素材,不需要审核,不需要materials表,在assets表加material_url字段 - ✅ Q9: 暂不考虑图片存储细节,存URL即可 - ✅ Q10: 不需要上传任务表,直接阻塞上传 **Q11-Q12: 区块链集成** ✅ - ✅ Q11: 区块链暂不考虑,模拟上链成功 - ✅ Q12: 只需要tx_hash和block_number,不需要token_id **Q13-Q14: 数据库表字段** ✅ - ✅ Q13: 不需要合约地址和链ID,其他都需要(description, block_number等) - ✅ Q14: UUID生成,不需要支付状态,不需要取消功能,重试次数在config中 **Q15-Q17: 其他表设计** ✅ - ✅ Q15-Q17: 不需要materials表、asset_materials表、upload_tasks表 **Q23-Q25: 技术选型** ✅ - ✅ Q23: 区块链暂不考虑,后续引入 - ✅ Q24: 暂不考虑图片存储细节 - ✅ Q25: 暂不考虑AI生成功能 ### ⚠️ 仍需确认的问题 **Q18: User Service 接口可用性** ⚠️ **部分已实现,部分待补充** - ✅ `ValidateUser` - 已实现(通过 `GetUser` 接口) - ✅ `ValidateFanProfile` - 已实现(通过 `GetFanProfile` 接口) - ❌ `UpdateCrystalBalance` - **需要在 User Service 中新增 RPC 接口** - ⚠️ `UpdateAssetsCount` - Repository 层已实现,**需要在 User Service 中新增 RPC 接口** **Q19-Q22: 服务间交互细节** - ✅ Q19: Asset Service 需要提供 RPC 接口给 Social Service 和 Gallery Service - ✅ Q20: 资产点赞功能在 Social Service 中实现,直接查询数据库(不使用 Redis) - ✅ Q21: Gallery Service 集成暂不考虑,后续再实现 - ✅ Q22: 事件驱动已确认不使用消息队列,直接通过 RPC 调用或数据库记录 **Q26-Q30: 其他技术细节** - ✅ Q26-Q27: API 路径规范和权限控制已确认 - ✅ Q28: 跨明星资产隔离已确认 - ✅ Q29: 缓存需求已确认(不使用 Redis 缓存,直接查询数据库) - ⚠️ Q30: 错误处理国际化待确认 ### 📝 需要补充的内容 #### 1. Proto 接口定义 - [ ] **Asset Service Proto**:需要创建 `proto/asset.proto` 文件,定义资产服务的 RPC 接口 - [ ] **User Service Proto 补充**:需要在 `proto/user.proto` 中添加: - `UpdateCrystalBalance` RPC 接口 - `UpdateAssetsCount` RPC 接口 - [ ] **Social Service Proto 补充**:需要在 `proto/social.proto` 中添加资产点赞相关的 RPC 接口 #### 2. 服务实现状态 - [ ] **Asset Service 服务目录**:需要创建 `services/assetService/` 目录结构 - [ ] **配置管理**:需要创建 `services/assetService/config/asset_config.go`(参考 `socialService/config/social_config.go`) - [ ] **Repository 层**:需要实现 `asset_repository.go`、`mint_order_repository.go`、`asset_like_repository.go` - [ ] **Service 层**:需要实现 `asset_service.go`、`mint_service.go` - [ ] **Provider 层**:需要实现 `asset_provider.go` - [ ] **RPC Client**:需要实现 `user_rpc_client.go`(调用 User Service) #### 3. Gateway 集成 - [ ] **路由配置**:需要在 `gateway/router/router.go` 中添加资产服务的路由 - [ ] **Controller**:需要创建 `gateway/controller/asset_controller.go` - [ ] **DTO 转换**:需要创建 `gateway/dto/asset_converter.go` #### 4. 数据库迁移 - [ ] **表结构创建**:需要创建 `assets`、`mint_orders`、`asset_likes` 表的迁移脚本 - [ ] **索引创建**:确保所有索引都已创建 #### 5. 测试 - [ ] **单元测试**:Repository 层、Service 层的单元测试 - [ ] **集成测试**:服务间交互的集成测试 - [ ] **HTTP 测试**:Gateway 接口的完整测试流程(参考 `用户服务HTTP完整测试流程.md`) --- ## 十一、下一步行动 ### 阶段 1: 需求确认(当前阶段)✅ **进行中** - [x] 与产品/业务确认上述 30 个问题(大部分已确认) - [x] 确定核心功能范围(已确定) - [x] 确定技术选型(已确定) - [ ] **待补充**:确认 User Service 接口补充需求 - [ ] **待补充**:确认 Social Service 资产点赞接口定义 ### 阶段 2: 详细设计 ⚠️ **部分完成** - [x] 完善数据库表结构(已完成,见 `pkg/models/asset.go`) - [ ] **待补充**:设计 Asset Service Proto 接口定义 - [ ] **待补充**:设计 User Service Proto 接口补充(`UpdateCrystalBalance`、`UpdateAssetsCount`) - [ ] **待补充**:设计 Social Service Proto 接口补充(资产点赞相关) - [x] 设计服务间交互协议(已设计) - [x] 设计错误处理机制(参考现有服务) ### 阶段 3: 开发实现 ❌ **未开始** - [ ] Repository 层实现 - [ ] Service 层实现 - [ ] Provider 层实现 - [ ] Gateway 集成 - [ ] 单元测试 ### 阶段 4: 测试和上线 ❌ **未开始** - [ ] 集成测试 - [ ] 性能测试 - [ ] 上线部署 --- ## 附录:参考文档 - [微服务架构设计文档](./微服务架构设计.md) - [用户服务实现文档](../services/userService/README.md) - [社交服务实现文档](../services/socialService/IMPLEMENTATION_COMPLETE.md)