Files
inchstep/docs/数据库设计文档.md
2026-06-25 08:39:47 +08:00

15 KiB
Raw Permalink Blame History

寸进(InchStep)数据库设计文档

文档版本:v1.0
数据库:MySQL 8.0
ORMGORMAutoMigrate
字符集:utf8mb4 / utf8mb4_unicode_ci
更新日期:2026-06-24


目录

  1. 文档概述
  2. 数据库全局配置
  3. 数据模型详情
  4. ER 关系图
  5. 索引策略
  6. 迁移说明
  7. 查询场景与优化

1. 文档概述

本文档定义寸进平台 v1.0 的全部数据模型、表结构、索引策略和迁移策略。数据模型映射自 server/internal/models/ 中的 Go 结构体,通过 GORM AutoMigrate 自动管理表结构。


2. 数据库全局配置

`ini

连接参数

DB_HOST=127.0.0.1 DB_PORT=13306 DB_USER=root DB_PASS=123456 DB_NAME=inchstep CHARSET=utf8mb4 COLLATION=utf8mb4_unicode_ci LOC=Asia/Shanghai `

2.1 GORM 连接配置

`go dsn := "root:123456@tcp(127.0.0.1:13306)/inchstep?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"

// 关键配置: // - parseTime=true: 将 MySQL DATETIME 映射为 Go time.Time // - loc=Asia/Shanghai: 时区感知,影响连续天数计算 `


3. 数据模型详情

3.1 users(用户表)

字段 类型 约束 说明
id varchar(32) PK 唯一 IDcuid 风格)
phone varchar(20) UNIQUE, NULL 手机号
nickname varchar(50) NULL 昵称
avatar varchar(255) NULL 头像 URL
bio varchar(100) NULL 个性签名
motto varchar(50) NULL 个人目标简介
privacy int DEFAULT 2 1=公开 2=好友 3=私密
points int DEFAULT 0 总积分
created_at datetime NOT NULL 创建时间
updated_at datetime NOT NULL 更新时间

GORM 映射:

go type User struct { ID string gorm:"primaryKey;type:varchar(32)" json:"id" Phone *string gorm:"uniqueIndex;type:varchar(20)" json:"phone,omitempty" Nickname *string gorm:"type:varchar(50)" json:"nickname,omitempty" Avatar *string gorm:"type:varchar(255)" json:"avatar,omitempty" Bio *string gorm:"type:varchar(100)" json:"bio,omitempty" Motto *string gorm:"type:varchar(50)" json:"motto,omitempty" Privacy PrivacyLevel gorm:"default:2" json:"privacy" Points int gorm:"default:0" json:"points" CreatedAt time.Time gorm:"column:created_at" json:"createdAt" UpdatedAt time.Time gorm:"column:updated_at" json:"updatedAt" }

索引

  • PRIMARY KEY (id)
  • UNIQUE INDEX idx_phone (phone)

3.2 checkin_items(打卡项表)

字段 类型 约束 说明
id varchar(32) PK 唯一 ID
user_id varchar(32) FK, NOT NULL, INDEX 所属用户
name varchar(100) NOT NULL 打卡项名称
icon varchar(50) NULL 图标
category varchar(20) NOT NULL 分类:study/health/habit/hobby/goal
daily_goal varchar(200) NULL 每日目标
cycle_type varchar(20) DEFAULT 'daily' 周期:daily/weekly/every_other_day/custom
privacy int DEFAULT 2 隐私级别
status varchar(20) DEFAULT 'active' 状态:active/paused/archived/deleted
created_at datetime NOT NULL 创建时间

GORM 映射:

go type CheckInItem struct { ID string gorm:"primaryKey;type:varchar(32)" json:"id" UserID string gorm:"column:user_id;type:varchar(32);not null;index" json:"userId" Name string gorm:"type:varchar(100);not null" json:"name" Icon *string gorm:"type:varchar(50)" json:"icon,omitempty" Category CheckInCategory gorm:"type:varchar(20);not null" json:"category" DailyGoal *string gorm:"column:daily_goal;type:varchar(200)" json:"dailyGoal,omitempty" CycleType CycleType gorm:"column:cycle_type;default:daily;type:varchar(20)" json:"cycleType" Privacy PrivacyLevel gorm:"default:2" json:"privacy" Status ItemStatus gorm:"default:active;type:varchar(20)" json:"status" CreatedAt time.Time gorm:"column:created_at" json:"createdAt" }

索引

  • PRIMARY KEY (id)
  • INDEX idx_user_id (user_id)

3.3 checkin_records(打卡记录表)

字段 类型 约束 说明
id varchar(32) PK 唯一 ID
item_id varchar(32) FK, NOT NULL, INDEX 所属打卡项
user_id varchar(32) FK, NOT NULL, INDEX 所属用户
check_date datetime NOT NULL, INDEX 打卡日期
status varchar(20) DEFAULT 'normal' normal/makeup
note varchar(500) NULL 备注文字
images text NULL 图片 URLJSON 数组)
created_at datetime NOT NULL 记录创建时间

GORM 映射:

go type CheckInRecord struct { ID string gorm:"primaryKey;type:varchar(32)" json:"id" ItemID string gorm:"column:item_id;type:varchar(32);not null;index" json:"itemId" UserID string gorm:"column:user_id;type:varchar(32);not null;index" json:"userId" CheckDate time.Time gorm:"column:check_date;not null;index" json:"checkDate" Status RecordStatus gorm:"default:normal;type:varchar(20)" json:"status" Note *string gorm:"type:varchar(500)" json:"note,omitempty" Images *string gorm:"type:text" json:"images,omitempty" CreatedAt time.Time gorm:"column:created_at" json:"createdAt" }

索引

  • PRIMARY KEY (id)
  • INDEX idx_user_id (user_id)
  • INDEX idx_item_id (item_id)
  • INDEX idx_check_date (check_date)
  • COMPOSITE INDEX idx_user_date (user_id, check_date)(查询推荐)

3.4 achievements(成就定义表)

字段 类型 约束 说明
id varchar(50) PK 成就 ID(如 irst_checkin
name varchar(100) NOT NULL 成就名称
description varchar(200) NULL 描述
icon varchar(50) NULL 图标
rarity varchar(20) DEFAULT 'bronze' bronze/silver/gold
condition varchar(200) NULL 达成条件描述

GORM 映射:

go type Achievement struct { ID string gorm:"primaryKey;type:varchar(50)" json:"id" Name string gorm:"type:varchar(100);not null" json:"name" Description *string gorm:"type:varchar(200)" json:"description,omitempty" Icon *string gorm:"type:varchar(50)" json:"icon,omitempty" Rarity string gorm:"default:bronze;type:varchar(20)" json:"rarity" Condition *string gorm:"type:varchar(200)" json:"condition,omitempty" }

3.5 user_achievements(用户成就关联表)

字段 类型 约束 说明
user_id varchar(32) PK, FK 用户 ID
achievement_id varchar(50) PK, FK 成就 ID
unlocked_at datetime NOT NULL 解锁时间

联合主键(user_id, achievement_id)

3.6 posts(动态表)

字段 类型 约束 说明
id varchar(32) PK 唯一 ID
user_id varchar(32) FK, NOT NULL, INDEX 发布者
content text NULL 文字内容
images text NULL 图片 URLJSON 数组)
privacy int DEFAULT 1 1=公开 2=好友 3=私密
likes int DEFAULT 0 点赞数(计数器)
comments int DEFAULT 0 评论数(计数器)
created_at datetime NOT NULL 发布时间

索引

  • PRIMARY KEY (id)
  • INDEX idx_created_at (created_at)(广场排序)
  • INDEX idx_user_id (user_id)

3.7 friends(好友关系表)

字段 类型 约束 说明
user_id varchar(32) PK, FK 用户 A
friend_id varchar(32) PK, FK 用户 B
status varchar(20) DEFAULT 'pending' pending/accepted
created_at datetime NOT NULL 请求时间

联合主键(user_id, friend_id)(双向好友关系需两条记录)

3.8 groups(打卡小组表)

字段 类型 约束 说明
id varchar(32) PK 唯一 ID
name varchar(20) NOT NULL 小组名称
cover varchar(255) NULL 封面图片
intro varchar(200) NULL 小组简介
type varchar(20) DEFAULT 'public' public/private
max_member int DEFAULT 50 人数上限
created_by varchar(32) NOT NULL 创建者
created_at datetime NOT NULL 创建时间

3.9 group_members(小组成员表)

字段 类型 约束 说明
group_id varchar(32) PK, FK 小组 ID
user_id varchar(32) PK, FK 用户 ID
role varchar(20) DEFAULT 'member' admin/member
joined_at datetime NOT NULL 加入时间

联合主键(group_id, user_id)


4. ER 关系图

` ┌─────────┐ ┌──────────────┐ ┌────────────────┐ │ users │1───N→│ checkin_items│1───N→│ checkin_records│ └─────────┘ └──────────────┘ └────────────────┘ │ 1 │ │ │ │ 1 N │ │ ├──────────────┐ │ │ 1 │ 1 │ ▼ ▼ ▼ ┌──────────┐ ┌──────────────┐ │ friends │ │ posts │ └──────────┘ └──────────────┘ │ │ N ▼ ┌────────────────┐ ┌──────────────────────┐ ┌──────────────┐ │ groups │1───N→│ group_members │N───1│ users │ └────────────────┘ └──────────────────────┘ └──────────────┘

┌──────────────┐ ┌──────────────────────┐ ┌──────────────┐ │ achievements │1───N→│ user_achievements │N───1│ users │ └──────────────┘ └──────────────────────┘ └──────────────┘ `

关系说明

左表 关系 右表 说明
users 1 → N checkin_items 一个用户可创建多个打卡项
checkin_items 1 → N checkin_records 一个打卡项有多条打卡记录
users 1 → N checkin_records 一个用户有多条打卡记录
users 1 → N friends 一个用户可有多个好友
users 1 → N posts 一个用户可发布多条动态
users 1 → N user_achievements 一个用户可解锁多个成就
groups 1 → N group_members 一个小组有多个成员
achievements 1 → N user_achievements 一个成就可被多个用户解锁

5. 索引策略

5.1 高频查询与索引覆盖

查询场景 涉及表 使用索引 优化建议
用户登录(手机号) users idx_phone
用户打卡项列表 checkin_items idx_user_id
打卡项打卡记录 checkin_records idx_item_id, idx_check_date 复合索引 (item_id, check_date)
连续天数计算 checkin_records idx_user_id, idx_check_date 必须按 check_date DESC
月度统计 checkin_records idx_user_id, idx_check_date 复合索引 (user_id, check_date)
动态广场排序 posts idx_created_at 只查 privacy=1
好友列表 friends idx_user_id
小组成员 group_members idx_group_id

5.2 索引定义(迁移推荐)

`sql -- 已有索引(由 GORM 自动创建) -- users: PRIMARY(id), UNIQUE(phone) -- checkin_items: PRIMARY(id), INDEX(user_id) -- checkin_records: PRIMARY(id), INDEX(item_id), INDEX(user_id), INDEX(check_date) -- posts: PRIMARY(id), INDEX(user_id), INDEX(created_at)

-- 推荐手动添加的复合索引 CREATE INDEX idx_records_user_date ON checkin_records(user_id, check_date); CREATE INDEX idx_records_item_date ON checkin_records(item_id, check_date); `


6. 迁移说明

6.1 开发环境(AutoMigrate

开发环境使用 GORM AutoMigrate 自动创建/更新表结构。服务启动时执行:

go db.AutoMigrate( &models.User{}, &models.CheckInItem{}, &models.CheckInRecord{}, &models.Achievement{}, &models.UserAchievement{}, &models.Post{}, &models.Friend{}, &models.Group{}, &models.GroupMember{}, )

6.2 生产环境

生产环境建议:

  1. 开发阶段:使用 AutoMigrate 快速迭代
  2. 预发布阶段:生成 SQL 迁移脚本,人工审核后执行
  3. 生产阶段:使用版本化迁移工具(如 golang-migrate

6.3 初始化数据

服务启动时自动初始化成就数据(10 个预定义成就徽章):

go func (s *PointsService) InitAchievements() error { for _, a := range predefinedAchievements { s.db.Where("id = ?", a.ID).FirstOrCreate(&a) } return nil }


7. 查询场景与优化

7.1 连续天数计算

sql -- 查询逻辑:按日期降序获取某打卡项的所有记录 SELECT check_date FROM checkin_records WHERE item_id = ? AND user_id = ? ORDER BY check_date DESC;

优化策略

  • (item_id, user_id, check_date) 复合索引
  • Redis 缓存结果,打卡时更新

7.2 动态广场分页

sql SELECT p.*, u.nickname, u.avatar FROM posts p LEFT JOIN users u ON p.user_id = u.id WHERE p.privacy = 1 ORDER BY p.created_at DESC LIMIT 20 OFFSET 0;

7.3 月度统计

`sql SELECT COUNT(*) FROM checkin_records WHERE user_id = ? AND check_date >= ? AND check_date < ?;

SELECT category, COUNT(*) as count FROM checkin_items WHERE user_id = ? AND status = 'active' GROUP BY category; `

7.4 好友列表

sql SELECT friend_id FROM friends WHERE user_id = ? AND status = 'accepted';


附录:表总览

# 表名 说明 行数预估(万 DAU
1 users 用户 5 万
2 checkin_items 打卡项 20 万(人均 4 项)
3 checkin_records 打卡记录 5000 万(日均 50 万)
4 achievements 成就定义 10 条(静态)
5 user_achievements 用户成就 10 万
6 posts 动态 100 万
7 friends 好友关系 20 万
8 groups 打卡小组 1 万
9 group_members 小组成员 10 万