From 770ca0e5127b2e756ce04ac678d8d4f642291721 Mon Sep 17 00:00:00 2001 From: zheng020 Date: Wed, 8 Apr 2026 18:04:16 +0800 Subject: [PATCH] docs: add task management system design document MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 包含: - 整体架构设计 - 数据库 ER 图和表结构 - 移动端 API 和 Dubbo 内部 RPC 定义 - 业务流程(每日任务、引导任务、展示收益) - Worker 设计(Advisory Lock 每日重置 + 收益自动发放) - activity-admin 页面规划 - 项目目录结构 Co-Authored-By: Claude Opus 4.6 --- ...026-04-08-task-management-system-design.md | 732 ++++++++++++++++++ 1 file changed, 732 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-08-task-management-system-design.md diff --git a/docs/superpowers/specs/2026-04-08-task-management-system-design.md b/docs/superpowers/specs/2026-04-08-task-management-system-design.md new file mode 100644 index 0000000..36a94da --- /dev/null +++ b/docs/superpowers/specs/2026-04-08-task-management-system-design.md @@ -0,0 +1,732 @@ +# 任务管理系统设计文档 + +> **创建日期:** 2026-04-08 +> **项目:** TopFans 任务管理系统 +> **服务:** activity-admin (Python FastAPI) + taskService (Go Dubbo-go) + 共享 PostgreSQL + +--- + +## 一、整体架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 移动端 │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ +│ │ 每日任务页面 │ │ 引导任务页面 │ │ 展示收益/奖励领取 │ │ +│ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │ +└─────────┼─────────────────┼─────────────────────┼───────────────┘ + │ │ │ + │ Triple/HTTP │ │ + ▼ ▼ ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ taskService (新服务,端口 20005) │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Mobile API Handler (HTTP/Triple) │ │ +│ │ /api/tasks/daily/* /api/tasks/guide/* /api/tasks/* │ │ +│ └──────────────────────────────────────────────────────────┘ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ DailyTaskService│ │OnboardingService│ │ RevenueService │ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ │ +│ ┌────────▼─────────────────────▼─────────────────────▼────────┐ │ +│ │ Repository Layer (GORM) │ │ +│ └───────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌─────────────▼─────────────┐ │ +│ │ DailyResetWorker │ │ +│ │ + RevenueAutoClaimWorker │ │ +│ │ (PostgreSQL Advisory │ │ +│ │ Lock,05:00 Asia/Shanghai)│ │ +│ └───────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ ▲ ▲ + │ Triple RPC │ │ + ▼ │ │ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ galleryService │ │ userService │ │ activity-admin │ +│ (OnExhibition │ │ (UpdateCrystal │ │ (任务定义管理) │ +│ Completed RPC)│ │ Balance + │ │ 直接操作DB │ +│ │ │ AddExperience)│ │ │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ ▲ ▲ + └────────────────────▼────────────────────┘ + PostgreSQL +``` + +--- + +## 二、设计决策汇总 + +### 2.1 服务职责划分 + +| 服务 | 职责 | +|------|------| +| activity-admin (Python) | 任务定义管理、进度查询、统计、手动重置 | +| taskService (Go) | 移动端 API、内部 RPC、奖励发放、定时任务 | +| PostgreSQL | 共用数据库 | + +### 2.2 核心设计决策 + +| 决策项 | 选择 | +|--------|------| +| 移动端 API 提供方 | 新建独立 taskService 微服务 | +| 引导完成上报 | 前端每步完成立即调用 `/api/tasks/guide/complete` | +| 每日任务重置 | PostgreSQL Advisory Lock,每天 05:00 Asia/Shanghai 执行 | +| 引导阶段推进 | 前端主动调用 `/api/tasks/onboarding/advance-stage` | +| 每日任务奖励 | 手动领取(单个或一键领取) | +| 引导任务奖励 | 阶段切换时统一发放 | +| 展示收益发放 | 统一到次日 05:00 自动发放,支持手动领取 | +| 展示收益计算 | 由调用方(galleryService)计算后传入 | +| 每日任务 scope | 每个 (user_id, star_id) 各自独立 | +| InitUserTasks | 只打新用户标记,不预创建任务进度 | +| 重置日志 | 记录到 task_reset_log 表 | +| 旧字段处理 | is_first_login_bonus_claimed、has_friend_display_bonus 标记废弃 | +| 奖励发放失败 | 记录日志 + 本地重试 N 次(可配置),仍失败标记 failed | +| 重置时区判断 | 按自然天,每天 05:00 执行一次 | +| 重置范围 | 全局所有用户所有 star_id | +| 引导上报 key | 动态配置,数据库存什么 key,前端就上报什么 key | +| 阶段切换检查 | 后端检查当前阶段所有任务是否已完成,未完成拒绝切换 | +| 引导任务 | 不允许重复完成,不重置 | +| claimed 状态 | 每日重置时也重置回 pending | +| 收益自动发放 | 分批发放,每条记录结果保存,失败重试 N 次(可配置) | +| 统计页面 | 多指标(完成率、领取率等)、多维度(star_id、时间范围) | +| Worker 设计 | 共用一个 Worker,05:00 先重置再发收益 | +| 日志监控 | 接入现有日志和监控体系 | +| 健康检查 | 不实现,复用 Dubbo-go 框架自带能力 | +| 错误码 | 复用现有 BaseResponse.code 体系 | +| 分页规范 | page + page_size + total | +| 引导状态返回 | POST `/api/tasks/guide/complete` 返回当前引导完整状态 | +| 锁 key 设计 | pg_advisory_lock(YYYYMMDD) | +| taskService 端口 | 20005 | +| taskService 调用 userService | 直接调用(UpdateCrystalBalance + AddExperience) | +| activity-admin | 直接操作数据库,不通过 taskService API | + +--- + +## 三、数据库设计 + +### 3.1 ER 图 + +``` +┌─────────────────────────┐ ┌─────────────────────────────┐ +│ task_definitions │ │ onboarding_stage_config │ +├─────────────────────────┤ ├─────────────────────────────┤ +│ id (PK) │ │ id (PK) │ +│ star_id │ │ stage │ +│ task_key │────▶│ required_task_keys (TEXT[]) │ +│ task_type │ │ crystal_reward │ +│ name │ │ exp_reward │ +│ description │ │ ... │ +│ crystal_reward │ └─────────────────────────────┘ +│ exp_reward │ ▲ +│ ... │ │ +└─────────────────────────┘ │ + │ │ + │ 1:N 1:N │ + ▼ │ +┌─────────────────────────┐ ┌─────────────────────────────┐ +│ user_daily_task_progress│ │ user_onboarding_progress │ +├─────────────────────────┤ ├─────────────────────────────┤ +│ id (PK) │ │ id (PK) │ +│ user_id │ │ user_id │ +│ star_id │ │ task_key ───────────────────┘ +│ task_key │◀────│ +│ status │ │ ┌─────────────────────────┐ +│ completed_at │ │ │user_onboarding_status │ +│ claimed_at │ │ ├─────────────────────────┤ +│ ... │ │ │ user_id (PK) │ +└─────────────────────────┘ │ │ current_stage │ + │ │ status │ + │ │ is_first_login_bonus_ │ + │ │ claimed (废弃) │ + │ │ has_friend_display_bonus│ + │ │ (废弃) │ + │ └─────────────────────────┘ + │ +┌─────────────────────────────┐ │ +│ exhibition_revenue_records │ │ +├─────────────────────────────┤ │ +│ id (PK) │ │ +│ user_id │ │ +│ star_id │ │ +│ exhibition_id │ │ +│ asset_id │ │ +│ slot_id │ │ +│ slot_owner_uid │ │ +│ slot_type ('own'/'friend') │ │ +│ crystal_amount │ │ +│ cycle_start_time │ │ +│ cycle_end_time │ │ +│ status ('claimable'/'...') │ │ +│ claimed_at │ │ +│ created_at │ │ +└─────────────────────────────┘ + +┌─────────────────────────────┐ +│ task_reset_log │ +├─────────────────────────────┤ +│ id (PK) │ +│ reset_type │ +│ last_reset_at │ +│ created_at │ +└─────────────────────────────┘ +``` + +### 3.2 表结构 + +#### task_definitions(任务定义表) + +```sql +CREATE TABLE task_definitions ( + id BIGSERIAL PRIMARY KEY, + star_id BIGINT, -- NULL=全局默认 + task_key VARCHAR(50) NOT NULL, + task_type VARCHAR(20) NOT NULL, -- 'daily' | 'onboarding' + name VARCHAR(100) NOT NULL, + description TEXT, + crystal_reward BIGINT DEFAULT 0, + exp_reward BIGINT DEFAULT 0, + sort_order INT DEFAULT 0, + is_active BOOLEAN DEFAULT true, + created_at BIGINT, + updated_at BIGINT +); +CREATE UNIQUE INDEX ix_task_def_star_key ON task_definitions(star_id, task_key); +``` + +#### user_daily_task_progress(每日任务进度表) + +```sql +CREATE TABLE user_daily_task_progress ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT NOT NULL, + star_id BIGINT NOT NULL, + task_key VARCHAR(50) NOT NULL, + status VARCHAR(20) DEFAULT 'pending', -- pending/completed/claimed + completed_at BIGINT, + claimed_at BIGINT, + created_at BIGINT, + updated_at BIGINT +); +CREATE UNIQUE INDEX ix_daily_progress_user_star_key + ON user_daily_task_progress(user_id, star_id, task_key); +``` + +#### user_onboarding_progress(引导任务进度表) + +```sql +CREATE TABLE user_onboarding_progress ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT NOT NULL, + task_key VARCHAR(50) NOT NULL, + status VARCHAR(20) DEFAULT 'pending', + completed_at BIGINT, + claimed_at BIGINT, + created_at BIGINT, + updated_at BIGINT +); +CREATE UNIQUE INDEX ix_onboard_progress_user_key + ON user_onboarding_progress(user_id, task_key); +``` + +#### user_onboarding_status(引导流程状态表) + +```sql +CREATE TABLE user_onboarding_status ( + user_id BIGINT PRIMARY KEY, + current_stage INT DEFAULT 0, -- 0=未开始,1~N=阶段 + status VARCHAR(20) DEFAULT 'pending', + -- 以下字段标记废弃,但仍保留 + is_first_login_bonus_claimed BOOLEAN DEFAULT false, + has_friend_display_bonus BOOLEAN DEFAULT false, + completed_at BIGINT, + claimed_at BIGINT, + created_at BIGINT, + updated_at BIGINT +); +``` + +#### onboarding_stage_config(引导阶段配置表) + +```sql +CREATE TABLE onboarding_stage_config ( + id BIGSERIAL PRIMARY KEY, + stage INT NOT NULL, + name VARCHAR(100) NOT NULL, + description TEXT, + required_task_keys TEXT[], -- PostgreSQL 数组类型 + crystal_reward BIGINT DEFAULT 0, + exp_reward BIGINT DEFAULT 0, + sort_order INT DEFAULT 0, + is_active BOOLEAN DEFAULT true, + created_at BIGINT, + updated_at BIGINT +); +``` + +#### exhibition_revenue_records(展示收益记录表) + +```sql +CREATE TABLE exhibition_revenue_records ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT NOT NULL, + star_id BIGINT NOT NULL, + exhibition_id BIGINT NOT NULL, + asset_id BIGINT NOT NULL, + slot_id BIGINT NOT NULL, + slot_owner_uid BIGINT NOT NULL, + slot_type VARCHAR(20) NOT NULL, -- 'own' | 'friend' + crystal_amount BIGINT NOT NULL, + cycle_start_time BIGINT NOT NULL, + cycle_end_time BIGINT NOT NULL, + status VARCHAR(20) DEFAULT 'claimable', + claimed_at BIGINT, + created_at BIGINT +); +CREATE INDEX ix_revenue_user_star_status + ON exhibition_revenue_records(user_id, star_id, status); +CREATE INDEX ix_revenue_star_status + ON exhibition_revenue_records(star_id, status); +``` + +#### task_reset_log(重置日志表) + +```sql +CREATE TABLE task_reset_log ( + id BIGSERIAL PRIMARY KEY, + reset_type VARCHAR(20) NOT NULL, -- 'daily' + last_reset_at BIGINT NOT NULL, + created_at BIGINT +); +``` + +--- + +## 四、API 设计 + +### 4.1 移动端 API(taskService HTTP/Triple) + +#### 每日任务 + +| 方法 | 路径 | 请求 | 说明 | +|------|------|------|------| +| GET | `/api/tasks/daily` | `star_id` | 获取每日任务列表及进度 | +| POST | `/api/tasks/daily/claim` | `{ task_key, star_id }` | 领取单个任务奖励 | +| POST | `/api/tasks/daily/claim-all` | `star_id` | 一键领取所有已完成任务奖励 | + +**GET /api/tasks/daily 响应:** +```json +{ + "tasks": [ + { + "task_key": "daily_login", + "name": "每日首次登录", + "description": "每日首次登录 App", + "crystal_reward": 20, + "exp_reward": 20, + "status": "pending", + "can_claim": false + } + ] +} +``` + +#### 引导任务 + +| 方法 | 路径 | 请求 | 说明 | +|------|------|------|------| +| POST | `/api/tasks/guide/complete` | `{ task_key }` | 上报引导步骤完成 | +| GET | `/api/tasks/onboarding/status` | - | 获取引导状态 | +| POST | `/api/tasks/onboarding/advance-stage` | `{ target_stage }` | 切换阶段 | +| POST | `/api/tasks/onboarding/claim-reward` | `{ stage }` | 领取当前阶段奖励 | + +**POST /api/tasks/guide/complete 响应:** +```json +{ + "user_id": 123, + "current_stage": 1, + "status": "in_progress", + "stages": [ + { + "stage": 1, + "name": "入门引导", + "required_task_keys": ["square_home", "profile_edit"], + "crystal_reward": 0, + "exp_reward": 0 + } + ] +} +``` + +**GET /api/tasks/onboarding/status 响应:** +```json +{ + "user_id": 123, + "current_stage": 1, + "status": "in_progress", + "stages": [ + { + "stage": 1, + "name": "入门引导", + "required_task_keys": ["square_home", "profile_edit"], + "crystal_reward": 0, + "exp_reward": 0 + } + ] +} +``` + +#### 展示收益 + +| 方法 | 路径 | 请求 | 说明 | +|------|------|------|------| +| GET | `/api/tasks/exhibition-revenue` | `star_id`, `status`, `page`, `page_size` | 获取收益记录列表 | +| POST | `/api/tasks/exhibition-revenue/claim` | `{ revenue_id, star_id }` | 领取单个收益 | +| POST | `/api/tasks/exhibition-revenue/claim-all` | `star_id` | 一键领取所有可领取收益 | + +**GET /api/tasks/exhibition-revenue 响应:** +```json +{ + "items": [ + { + "id": 123, + "exhibition_id": 456, + "asset_id": 789, + "slot_id": 1, + "slot_type": "own", + "crystal_amount": 100, + "cycle_start_time": 1712607600000, + "cycle_end_time": 1712694000000, + "status": "claimable", + "can_claim": true + } + ], + "total": 10, + "page": 1, + "page_size": 20 +} +``` + +### 4.2 Dubbo 内部 RPC + +#### taskService 作为服务端(被调用) + +**TaskInternalService:** + +```protobuf +service TaskInternalService { + // 用户注册时调用,只打新用户标记 + rpc InitUserTasks(InitUserTasksRequest) returns (InitUserTasksResponse); + + // 任务事件上报 + rpc ReportTaskEvent(ReportTaskEventRequest) returns (ReportTaskEventResponse); + + // 展品到期完成(galleryService 调用) + rpc OnExhibitionCompleted(OnExhibitionCompletedRequest) returns (OnExhibitionCompletedResponse); +} +``` + +**消息定义:** + +```protobuf +message InitUserTasksRequest { + int64 user_id = 1; +} + +message InitUserTasksResponse { + topfans.common.BaseResponse base = 1; + bool success = 2; +} + +message ReportTaskEventRequest { + int64 user_id = 1; + int64 star_id = 2; + string event_type = 3; + int64 timestamp = 4; +} + +message ReportTaskEventResponse { + topfans.common.BaseResponse base = 1; + bool task_completed = 2; + string task_key = 3; +} + +message OnExhibitionCompletedRequest { + int64 exhibition_id = 1; + int64 asset_id = 2; + int64 slot_id = 3; + int64 occupier_uid = 4; + int64 occupier_star_id = 5; + int64 slot_owner_uid = 6; + int64 crystal_amount = 7; + int64 start_time = 8; + int64 expire_at = 9; +} + +message OnExhibitionCompletedResponse { + topfans.common.BaseResponse base = 1; + int64 revenue_record_id = 2; +} +``` + +#### taskService 作为客户端(调用 userService) + +**userService 新增 RPC:** + +```protobuf +// 更新经验值请求(内部RPC调用,用于taskService发放经验奖励) +message AddExperienceRequest { + int64 user_id = 1; + int64 star_id = 2; + int64 delta = 3; +} + +message AddExperienceResponse { + topfans.common.BaseResponse base = 1; + int64 new_experience = 2; +} + +// 在 service UserSocialService 中添加: +rpc AddExperience(AddExperienceRequest) returns (AddExperienceResponse); +``` + +--- + +## 五、业务流程 + +### 5.1 每日任务流程 + +``` +1. 用户登录 → 前端调用 GET /api/tasks/daily?star_id=xxx +2. 后端返回该用户的每日任务列表(含 status) +3. 用户完成行为(如浏览展品)→ 前端调用 ReportTaskEvent +4. 后端自动标记任务完成(status=completed) +5. 用户点击"领取" → POST /api/tasks/daily/claim +6. 后端验证任务已完成 → 调用 userService.UpdateCrystalBalance → 调用 AddExperience → 更新状态为 claimed +7. 每日 05:00 Asia/Shanghai: + a. Advisory Lock 获取锁(pg_advisory_lock(YYYYMMDD)) + b. 查询 task_reset_log,如今天已有记录则跳过 + c. 所有非 pending 状态的记录恢复为 pending + d. 记录 task_reset_log + e. 释放锁 +``` + +### 5.2 引导任务流程 + +``` +1. 用户首次登录 → 前端调用 GET /api/tasks/onboarding/status +2. 返回 { current_stage: 0, status: 'pending', stages: [...] } +3. 前端根据 stage 配置显示引导步骤 +4. 用户完成引导步骤(如 square_home) +5. → POST /api/tasks/guide/complete { task_key: "square_home" } +6. 后端更新 user_onboarding_progress.status = 'completed' +7. 前端引导流程中,用户点击"进入下一阶段" +8. → POST /api/tasks/onboarding/advance-stage { target_stage: 2 } +9. 后端检查 stage 1 所有 task_key 是否都已 completed: + - 如未全部完成,返回错误 + - 如全部完成,current_stage++,返回最新状态 +10. 前端调用 POST /api/tasks/onboarding/claim-reward 领取阶段奖励 +11. 重复 3-10,直到所有引导完成 +``` + +### 5.3 展示收益流程 + +``` +1. galleryService 的 CleanupWorker 扫描到过期展品 +2. → 调用 taskService.OnExhibitionCompleted RPC +3. taskService 创建 exhibition_revenue_records(status=claimable) +4. 每日 05:00(紧接重置后): + a. 查询所有 status=claimable 的记录 + b. 分批处理(每批 N 条,可配置) + c. 调用 userService.UpdateCrystalBalance 发放水晶 + d. 成功则更新 status=claimed,失败则重试 N 次 + e. 仍失败则标记 status=failed +5. 用户打开移动端 → GET /api/tasks/exhibition-revenue +6. 用户点击领取 → POST /api/tasks/exhibition-revenue/claim +7. 后端调用 userService.UpdateCrystalBalance → 更新状态 +``` + +--- + +## 六、分页规范 + +所有列表查询统一分页参数: + +| 参数 | 类型 | 说明 | +|------|------|------| +| page | int | 页码,从 1 开始 | +| page_size | int | 每页条数,最大 100 | + +响应结构: +```json +{ + "items": [...], + "total": 100, + "page": 1, + "page_size": 20 +} +``` + +--- + +## 七、Worker 设计 + +### 7.1 DailyResetWorker + RevenueAutoClaimWorker + +**共用一个 Worker,每天 05:00 Asia/Shanghai 执行。** + +```go +// 伪代码 +func (w *Worker) run() { + // 尝试获取锁(日期作为锁ID) + lockID := time.Now().Format("20060102") // 如 "20230409" + if !w.acquireAdvisoryLock(lockID) { + return // 其他实例在执行 + } + defer w.releaseAdvisoryLock(lockID) + + // 1. 执行每日任务重置 + w.resetDailyTasks() + + // 2. 执行展示收益自动发放 + w.autoClaimExhibitionRevenue() +} + +func (w *Worker) resetDailyTasks() { + // 查询 task_reset_log,如今天已有记录则跳过 + // 更新所有 status != 'pending' 的记录为 'pending' + // 记录 task_reset_log +} + +func (w *Worker) autoClaimExhibitionRevenue() { + // 查询所有 status='claimable' 的记录 + // 分批处理(batch_size 可配置) + // 每批:调用 userService.UpdateCrystalBalance + // - 成功:更新 status='claimed' + // - 失败:重试 N 次(可配置),仍失败标记 status='failed' + // 每条记录处理结果保存到日志 +} +``` + +### 7.2 Advisory Lock 设计 + +- **锁 key:** 日期格式 `YYYYMMDD`(如 `20230409`) +- **获取锁:** `pg_try_advisory_lock(lockID)` +- **释放锁:** `pg_advisory_unlock(lockID)` +- **作用:** 保证多实例环境下每天只执行一次重置和自动发放 + +--- + +## 八、activity-admin 页面 + +| 页面 | 路由 | 功能 | +|------|------|------| +| 任务定义列表 | `/tasks/definitions` | 查看、新建、编辑、删除、启用/禁用任务定义 | +| 每日任务进度 | `/tasks/daily-progress` | 查询各用户的每日任务完成情况 | +| 引导任务进度 | `/tasks/onboarding-progress` | 查询各用户的引导任务完成情况 | +| 任务统计 | `/tasks/stats` | 任务完成率/领取率统计图表,支持 star_id、时间范围筛选 | +| 手动重置 | `/tasks/reset` | 手动触发每日任务重置 | +| 收益记录 | `/tasks/revenue` | 查看展示收益记录 | + +**统计页面指标:** +- 每日任务:完成人数、领取人数、完成率、领取率 +- 引导任务:各 stage 完成人数、总体完成率 +- 收益统计:总发放水晶数、待领取水晶数、已领取水晶数 + +**筛选维度:** +- star_id +- 时间范围(近7天、近30天、自定义) +- 任务类型(daily/onboarding) + +--- + +## 九、项目结构 + +### 9.1 目录结构 + +``` +backend/ +├── proto/ +│ ├── user.proto # 修改:新增 AddExperience RPC +│ └── task.proto # 新增:TaskInternalService +│ +├── services/ +│ ├── taskService/ # 新增 +│ │ ├── main.go +│ │ ├── config/ +│ │ │ └── task_config.go +│ │ ├── repository/ +│ │ │ └── task_repository.go +│ │ ├── service/ +│ │ │ ├── daily_task_service.go +│ │ │ ├── onboarding_service.go +│ │ │ └── exhibition_revenue_service.go +│ │ ├── provider/ +│ │ │ ├── task_mobile_provider.go # 移动端 API +│ │ │ └── task_internal_provider.go # 内部 RPC +│ │ ├── worker/ +│ │ │ └── daily_reset_worker.go +│ │ └── client/ +│ │ └── user_rpc_client.go +│ │ +│ └── userService/ # 修改 +│ ├── repository/ +│ │ └── fan_profile_repository.go # 新增 UpdateExperience +│ ├── service/ +│ │ └── user_service.go # 新增 AddExperience +│ └── provider/ +│ ├── user_provider.go # 新增 AddExperience +│ └── unified_provider.go # 新增 AddExperience +│ +├── pkg/ +│ └── proto/ +│ ├── user/ +│ │ └── *.go # 重新生成 +│ └── task/ +│ └── *.go # 新生成 +│ +└── scripts/ + └── v001_init_task_tables.sql +``` + +### 9.2 前端文件(activity-admin) + +``` +frontend/src/ +├── api/ +│ └── admin.js # 修改:新增任务相关 API +├── views/ +│ ├── TaskDefinitionList.vue +│ ├── TaskProgress.vue +│ ├── TaskStats.vue +│ ├── TaskReset.vue +│ └── RevenueList.vue +└── router/ + └── index.js # 修改:新增路由 +``` + +--- + +## 十、后续迭代项 + +以下内容在当前设计中预留扩展点,后续可根据业务需求添加: + +1. **引导任务细分** - `square_home` 等 key 是否需要与 star_id 关联 +2. **任务事件扩展** - ReportTaskEvent 的 event_type 可继续扩展 +3. **收益周期细分** - 当前 cycle_start/end_time 为基础字段,可扩展 cycle_name 等 +4. **统计图表扩展** - 当前预留 ECharts 位置,可扩展更多图表类型 +5. **手动重置扩展** - 当前支持全局重置,可扩展按 star_id 重置 + +--- + +## 十一、错误码规范 + +复用现有 `BaseResponse.code` 体系,不新增自定义业务错误码。 + +| 场景 | 处理方式 | +|------|----------| +| 领取未完成任务 | 静默返回成功,前端根据 status 阻止 | +| 领取已领取任务 | 静默返回成功,前端根据 status 阻止 | +| 阶段切换但任务未完成 | 返回错误,前端提示 | +| RPC 超时 | 记录日志,不自动重试(可手动补发) | +| 重置时其他实例在执行 | 跳过本次执行 |