Files
simple-memo/docs/growth_rules.md
T
sunct 3c3bf53ae4 docs(website): 添加简记memo产品原型和UI设计规范文档
- 新增「简记memo」一体化小程序产品原型设计文档
- 新增简记memo完整版UI视觉设计规范和界面细节
- 添加IDEA项目配置文件.gitignore
- 创建404页面HTML文件,包含响应式布局和错误提示
- 添加关于页面HTML文件,展示品牌介绍和团队信息
- 实现AES加解密工具函数,支持请求体加密
- 添加用户协议页面基础框架
2026-07-31 14:12:32 +08:00

20 KiB
Raw Blame History

成长等级系统规则文档

一、系统概述

成长等级系统是激励用户持续使用应用的核心机制,通过记录用户的日常行为(任务完成、记账、心情记录)来累计经验值,提升等级,解锁成就和特权。


二、API 接口

2.1 获取成长信息

接口路径: POST /growth/info

请求参数: 无

返回示例:

{
  "code": 0,
  "msg": "success",
  "data": {
    "id": 1,
    "level": 3,
    "title": "自律达人",
    "titleIcon": "⭐",
    "experience": 650,
    "nextLevelExp": 1500,
    "totalDays": 45,
    "streakDays": 12,
    "maxStreakDays": 20,
    "avgCompletionRate": 0,
    "todayProgress": {
      "tasksCompleted": 3,
      "taskExp": 15,
      "billsRecorded": 5,
      "billExp": 13,
      "moodRecorded": true,
      "moodExp": 5,
      "streakBonus": 5,
      "protectBonus": 0,
      "totalExp": 38,
      "maxDailyExp": 120
    },
    "achievements": [
      {
        "id": "first_record",
        "name": "初次尝试",
        "icon": "✨",
        "unlocked": true,
        "unlockDate": "2024-01-15"
      }
    ],
    "privileges": [
      "解锁心情日历",
      "解锁数据报表"
    ]
  }
}

2.2 获取成就列表

接口路径: POST /growth/achievements

请求参数:

参数名 类型 必填 说明
category string 过滤类别:streak/task/mood/bill

返回示例:

{
  "code": 0,
  "msg": "success",
  "data": {
    "unlocked": [
      {
        "id": "first_record",
        "name": "初次尝试",
        "icon": "✨",
        "category": "streak",
        "description": "完成第1天记录",
        "expReward": 10,
        "progress": 1,
        "target": 1,
        "unlocked": true
      }
    ],
    "locked": [
      {
        "id": "streak_7",
        "name": "一周打卡",
        "icon": "🌟",
        "category": "streak",
        "description": "连续记录7天",
        "expReward": 50,
        "progress": 3,
        "target": 7,
        "unlocked": false
      }
    ]
  }
}

2.3 增加经验

接口路径: POST /growth/add

请求参数:

参数名 类型 必填 说明
source string 来源:task/bill/mood
source_id string 关联记录ID

返回示例:

{
  "code": 0,
  "msg": "success",
  "data": {
    "expGained": 38,
    "totalExp": 688,
    "levelUp": false,
    "currentLevel": 3,
    "nextLevelExp": 1500,
    "newAchievements": []
  }
}

三、等级体系

3.1 等级列表

等级 头衔 图标 所需累计经验
Lv.1 新手冒险家 🎒 0
Lv.2 坚持学徒 📝 200
Lv.3 自律达人 600
Lv.4 习惯大师 💎 1500
Lv.5 传奇记录者 👑 3000
Lv.6 时光守望者 🏆 6000
Lv.7 超级达人 💫 10000
Lv.8 传说存在 🌟 15000
Lv.9 永恒传奇 22000
Lv.10 至高王者 👑 30000

3.2 等级经验计算逻辑

等级根据用户累计经验值自动计算:

func (h *growthHandler) getLevelByExp(exp int) int {
    level := 1
    for l := 10; l >= 1; l-- {
        if config, ok := LevelConfigs[l]; ok && exp >= config.Exp {
            level = l
            break
        }
    }
    return level
}

四、经验值获取规则

4.1 基础经验

来源 基础经验
完成任务 (task) 5 EXP
记账记录 (bill) 3 EXP
心情记录 (mood) 5 EXP

4.2 任务完成经验加成

今日完成任务数 经验计算
1-2个 5 EXP/个
3个以上 前2个 5 EXP/个,第3个起 10 EXP/个
5个以上 前2个 5 EXP/个,3-4个 10 EXP/个,第5个起 20 EXP/个

示例:

  • 完成2个任务:2 × 5 = 10 EXP
  • 完成3个任务:2 × 5 + 10 = 20 EXP
  • 完成5个任务:2 × 5 + 2 × 10 + 15 = 45 EXP

4.3 记账经验加成

今日记账笔数 经验计算
1-2笔 3 EXP/笔
3笔以上 前2笔 3 EXP/笔,第3笔起 8 EXP/笔
5笔以上 前2笔 3 EXP/笔,3-4笔 8 EXP/笔,第5笔起 13 EXP/笔

示例:

  • 记录2笔账单:2 × 3 = 6 EXP
  • 记录3笔账单:2 × 3 + 8 = 14 EXP
  • 记录5笔账单:2 × 3 + 2 × 8 + 13 = 33 EXP

4.4 心情记录经验

  • 每次记录心情:5 EXP
  • 每日仅限1次:通过 Redis 记录 mood_count:{userID}:{date},每日只能记录一次

4.5 连续打卡加成

连续打卡天数越多,加成越高:

连续天数范围 每日加成
1-7天 2 EXP/天
8-30天 5 EXP/天
31-90天 10 EXP/天
91天以上 15 EXP/天

4.6 新用户保护期

  • 新用户注册后享有 7天保护期
  • 保护期内享受 50%额外加成 (protectBonus = baseExp × 0.5)
  • 保护期内忘记打卡不会完全重置连续天数
  • 如果总记录天数 < 30天,保护期内的连续加成 翻倍
  • 保护期结束后 ProtectedDays 字段递减

4.7 每日经验上限

每日最高可获得 120 EXP,超过部分会被截断。


五、连续打卡机制

5.1 打卡判断逻辑

isFirstRecordToday := growth.LastRecordDate != today

if isFirstRecordToday {
    yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")

    if growth.LastRecordDate == yesterday {
        // 昨天也打卡了,连续天数+1
        growth.StreakDays++
    } else if growth.LastRecordDate == "" || growth.LastRecordDate < yesterday {
        // 昨天没打卡(断了)
        if growth.StreakDays > 0 {
            // 有连续记录但断了,根据之前的连续天数给予部分保留
            if growth.StreakDays <= 7 {
                growth.StreakDays = 0      // 7天内断了,直接清零
            } else if growth.StreakDays <= 30 {
                growth.StreakDays = 3      // 保留3天
            } else if growth.StreakDays <= 90 {
                growth.StreakDays = 7      // 保留7天
            } else {
                growth.StreakDays = 15     // 保留15天
            }
        }
        growth.StreakDays++
    }

    growth.TotalDays++
}

5.2 断签处理规则

之前的连续天数 断签后保留天数
≤7天 0天(完全重置)
8-30天 3天
31-90天 7天
>90天 15天

5.3 连续天数重置规则图解

用户连续打卡25天后忘记打卡:
┌─────────────────────────────────────┐
│  第1-7天: 连续7天                    │
│    ↓ 断了                           │
│  保留3天 → 再+1天 = 当前4天连续      │
└─────────────────────────────────────┘

用户连续打卡100天后忘记打卡:
┌─────────────────────────────────────┐
│  第1-90天: 连续90天                  │
│    ↓ 断了                           │
│  保留15天 → 再+1天 = 当前16天连续    │
└─────────────────────────────────────┘

六、成就系统

6.1 成就配置总览

成就ID 名称 类别 描述 奖励经验 目标类型 目标值
first_record 初次尝试 streak 完成第1天记录 10 total_days 1
streak_3 3天坚持 streak 连续记录3天 20 streak 3
streak_7 一周打卡 streak 连续记录7天 50 streak 7
streak_30 月度坚持 streak 连续记录30天 200 streak 30
streak_100 百日筑基 streak 连续记录100天 500 streak 100
streak_365 年度传奇 streak 连续记录365天 2000 streak 365
task_1 任务新手 task 完成第1个任务 10 total_tasks 1
task_100 任务达人 task 累计完成100个任务 200 total_tasks 100
task_500 任务大师 task 累计完成500个任务 800 total_tasks 500
perfect_day 完美一天 task 单日完成所有待办 30 perfect_day 1
perfect_week 完美一周 task 连续7天100%完成 200 perfect_week 7
mood_first 心情记录者 mood 第1次记录心情 10 total_moods 1
mood_30 月度心情家 mood 累计记录30天心情 100 total_moods 30
mood_100 心情收藏家 mood 累计记录100天心情 300 total_moods 100
happy_streak 阳光达人 mood 连续10天记录开心 150 happy_streak 10
bill_1 记账入门 bill 第1次记账 10 total_bills 1
bill_100 记账达人 bill 累计记账100笔 200 total_bills 100
bill_500 记账大师 bill 累计记账500笔 500 total_bills 500

6.2 成就分类

📅 坚持类 (streak)

  • first_record: 初次尝试 - 完成第1天记录
  • streak_3: 3天坚持 - 连续记录3天
  • streak_7: 一周打卡 - 连续记录7天
  • streak_30: 月度坚持 - 连续记录30天
  • streak_100: 百日筑基 - 连续记录100天
  • streak_365: 年度传奇 - 连续记录365天

任务类 (task)

  • task_1: 任务新手 - 完成第1个任务
  • task_100: 任务达人 - 累计完成100个任务
  • task_500: 任务大师 - 累计完成500个任务
  • perfect_day: 完美一天 - 单日完成所有待办
  • perfect_week: 完美一周 - 连续7天100%完成

😊 心情类 (mood)

  • mood_first: 心情记录者 - 第1次记录心情
  • mood_30: 月度心情家 - 累计记录30天心情
  • mood_100: 心情收藏家 - 累计记录100天心情
  • happy_streak: 阳光达人 - 连续10天记录开心

💰 记账类 (bill)

  • bill_1: 记账入门 - 第1次记账
  • bill_100: 记账达人 - 累计记账100笔
  • bill_500: 记账大师 - 累计记账500笔

6.3 成就解锁机制

成就在以下时机检查并解锁:

  1. 每次增加经验时:检查相关成就是否达成
  2. 升级时:额外检查所有成就是否达成

解锁成就后会立即发放经验奖励,并记录到 UserAchievement 表。


七、特权系统

7.1 等级特权一览

等级 解锁特权
Lv.1 基础功能
Lv.2 解锁心情日历
Lv.3 解锁心情日历、解锁数据报表
Lv.4 解锁心情日历、解锁数据报表、解锁自定义主题
Lv.5 解锁心情日历、解锁数据报表、解锁自定义主题、解锁全部功能
Lv.6 解锁心情日历、解锁数据报表、解锁自定义主题、解锁全部功能、解锁年度回顾
Lv.7+ 解锁心情日历、解锁数据报表、解锁自定义主题、解锁全部功能、解锁年度回顾、解锁数据导出

7.2 特权获取逻辑

func (h *growthHandler) getLevelPrivileges(level int) []string {
    privileges := []string{}

    switch level {
    case 1:
        // Lv.1 无特权
    case 2:
        privileges = append(privileges, "解锁心情日历")
    case 3:
        privileges = append(privileges, "解锁心情日历", "解锁数据报表")
    case 4:
        privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题")
    case 5:
        privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题", "解锁全部功能")
    case 6:
        privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题", "解锁全部功能", "解锁年度回顾")
    case 7:
        privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题", "解锁全部功能", "解锁年度回顾", "解锁数据导出")
    default:
        privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题", "解锁全部功能", "解锁年度回顾", "解锁数据导出")
    }

    return privileges
}

八、数据统计指标

8.1 用户成长数据 (UserGrowth)

字段 类型 说明
ID uint 主键
UserID uint 用户ID
Level int 当前等级
Experience int 当前累计经验
TotalDays int 累计记录天数
StreakDays int 当前连续打卡天数
MaxStreakDays int 历史最高连续天数
LastRecordDate string 最后记录日期 (YYYY-MM-DD)
ProtectedDays int 新用户保护期剩余天数
TotalTasks int 累计完成任务数
TotalBills int 累计记账笔数
TotalMoods int 累计心情记录数

8.2 每日进度 (DailyProgress)

字段 类型 说明
ID uint 主键
UserID uint 用户ID
RecordDate string 记录日期 (YYYY-MM-DD)
TaskCount int 今日完成任务数
BillCount int 今日记账笔数
MoodRecorded bool 今日是否记录心情
DailyExp int 今日获得总经验
ExpBreakdown string 经验明细 (JSON格式)

8.3 经验变化日志 (ExpChangeLog)

字段 类型 说明
ID uint 主键
UserID uint 用户ID
ChangeType string 变更类型:add/level_up
ExpDelta int 经验变化量
Source string 来源:task/bill/mood/level
SourceID string 关联记录ID
BeforeExp int 变化前经验
AfterExp int 变化后经验
RecordDate string 记录日期

8.4 用户成就 (UserAchievement)

字段 类型 说明
ID uint 主键
UserID uint 用户ID
AchievementID string 成就ID
UnlockDate string 解锁日期
ExpRewarded int 已奖励经验值

九、防刷机制

9.1 心情记录限制

if source == "mood" {
    key := fmt.Sprintf("mood_count:%d:%s", userID, today)
    count, _ := global.Redis.Exists(ctx, key).Result()
    if count > 0 {
        utils.Fail(c, "今日心情已记录")
        return
    }
}
  • 每日只能记录一次心情
  • 通过 Redis Key mood_count:{userID}:{date} 限制
  • Key 过期时间:25小时

9.2 并发控制

lockKey := fmt.Sprintf("lock:growth:%d", userID)
ok, _ := global.Redis.SetNX(ctx, lockKey, "1", 2*time.Second).Result()
if !ok {
    utils.Fail(c, "系统繁忙,请稍后重试")
    return
}
defer global.Redis.Del(ctx, lockKey)
  • 使用 Redis 分布式锁防止并发操作
  • 锁过期时间:2秒

十、经验计算示例

10.1 普通用户(第1天)

基础条件:无连续、无保护期
操作:完成1个任务

经验计算:
- 任务基础经验:5 EXP
- 连续加成:0 EXP(无连续)
- 保护期加成:0 EXP(保护期需 TotalDays >= 30 才翻倍)

今日总计:5 EXP

10.2 新用户(第7天,保护期内)

基础条件:连续7天,保护期剩余0天
操作:完成3个任务,记录心情

经验计算:
- 任务基础经验:2×5 + 10 = 20 EXP
- 心情经验:5 EXP
- 连续加成(1-7天):2 EXP
- 保护期加成:5 × 50% = 2.5 EXP ≈ 2 EXP
- 保护期连续加成翻倍:2 × 2 = 4 EXP(因为 TotalDays=7 < 30

今日总计:20 + 5 + 4 + 2 = 31 EXP

10.3 老用户(连续30天)

基础条件:连续30天,保护期已过
操作:完成5个任务,记录3笔账单,记录心情

经验计算:
- 任务经验:2×5 + 2×10 + 15 = 45 EXP
- 账单经验:2×3 + 8 = 14 EXP
- 心情经验:5 EXP
- 连续加成(8-30天):5 EXP
- 保护期加成:0 EXP(保护期已过)

今日总计:45 + 14 + 5 + 5 = 69 EXP

10.4 满级用户(连续100天)

基础条件:连续100天,保护期已过
操作:完成5个任务,记录5笔账单,记录心情

经验计算:
- 任务经验:45 EXP
- 账单经验:2×3 + 2×8 + 13 = 33 EXP
- 心情经验:5 EXP
- 连续加成(31-90天):10 EXP

今日总计:45 + 33 + 5 + 10 = 93 EXP

十一、数据库表结构

11.1 user_growths 表

CREATE TABLE `user_growths` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  `user_id` bigint unsigned NOT NULL COMMENT '用户ID',
  `level` int DEFAULT '1' COMMENT '当前等级',
  `experience` int DEFAULT '0' COMMENT '当前经验值',
  `total_days` int DEFAULT '0' COMMENT '累计记录天数',
  `streak_days` int DEFAULT '0' COMMENT '连续记录天数',
  `max_streak_days` int DEFAULT '0' COMMENT '最高连续天数',
  `last_record_date` varchar(10) DEFAULT '' COMMENT '最后记录日期',
  `protected_days` int DEFAULT '7' COMMENT '新用户保护期剩余天数',
  `total_tasks` int DEFAULT '0' COMMENT '累计完成任务数',
  `total_bills` int DEFAULT '0' COMMENT '累计记账笔数',
  `total_moods` int DEFAULT '0' COMMENT '累计心情记录数',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

11.2 daily_progress 表

CREATE TABLE `daily_progress` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  `user_id` bigint unsigned NOT NULL COMMENT '用户ID',
  `record_date` varchar(10) NOT NULL COMMENT '记录日期',
  `task_count` int DEFAULT '0' COMMENT '今日完成任务数',
  `bill_count` int DEFAULT '0' COMMENT '今日记账笔数',
  `mood_recorded` tinyint(1) DEFAULT '0' COMMENT '是否记录心情',
  `daily_exp` int DEFAULT '0' COMMENT '今日获得经验',
  `exp_breakdown` text COMMENT '经验明细JSON',
  PRIMARY KEY (`id`),
  KEY `idx_user_date` (`user_id`,`record_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

11.3 exp_change_logs 表

CREATE TABLE `exp_change_logs` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  `user_id` bigint unsigned NOT NULL COMMENT '用户ID',
  `change_type` varchar(20) NOT NULL COMMENT '变更类型',
  `exp_delta` int NOT NULL DEFAULT '0' COMMENT '经验变化量',
  `source` varchar(20) DEFAULT '' COMMENT '来源',
  `source_id` varchar(50) DEFAULT '' COMMENT '关联记录ID',
  `before_exp` int DEFAULT '0' COMMENT '变化前经验',
  `after_exp` int DEFAULT '0' COMMENT '变化后经验',
  `record_date` varchar(10) NOT NULL COMMENT '记录日期',
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_record_date` (`record_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

11.4 user_achievements 表

CREATE TABLE `user_achievements` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  `user_id` bigint unsigned NOT NULL COMMENT '用户ID',
  `achievement_id` varchar(50) NOT NULL COMMENT '成就ID',
  `unlock_date` varchar(10) NOT NULL COMMENT '解锁日期',
  `exp_rewarded` int DEFAULT '0' COMMENT '已奖励经验值',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_user_achievement` (`user_id`,`achievement_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

十二、版本历史

版本 更新日期 更新内容
v1.0 2024-01-01 初始版本,实现基础等级系统
v1.1 2024-02-15 新增成就系统,包含18个成就
v1.2 2024-03-20 新增连续打卡保护机制
v1.3 2024-04-25 优化经验计算规则,添加任务/账单完成加成
v1.4 2024-06-01 新增心情记录功能
v1.5 2024-08-15 优化防刷机制,使用Redis分布式锁

文档版本: v1.5
最后更新: 2024年8月15日
适用项目: simple-memo 后端成长等级系统
文档路径: /Users/sunct/WeChatProjects/simple-memo/docs/growth_rules.md