topfans/backend/proto/设计说明.md
2026-04-07 22:29:48 +08:00

7.6 KiB
Raw Blame History

Proto文件设计说明 - 3.1 认证Service层

一、设计依据

本proto设计基于以下技术文档

  • 微服务架构设计文档 - 确定服务职责和API设计
  • 数据库设计文档 - 确定数据结构和字段定义
  • 开发功能顺序文档 - 确定Service层接口需求
  • JWT设计 - 确定Token相关字段和验证流程

二、核心设计要点

2.1 单Token方案

  • LoginResponseRegisterResponse 只返回 access_token
  • RefreshTokenRequest 使用 access_token 刷新(不是 refresh_token
  • Token存储在 users.access_token 字段中
  • 单设备登录新登录会覆盖旧Token

2.2 Token中包含star_id

  • JWT Claims包含user_id, star_id, updated_at
  • 前端可以直接从Token解析获取 star_id
  • 无需额外拼接或传递 star_id

2.3 粉丝身份隔离

  • 所有业务操作都基于 user_id + star_id
  • FanProfile 使用联合唯一索引 (user_id, star_id)
  • 切换身份时生成新Token包含新的 star_id

2.4 数据库字段映射

User表字段映射

message User {
  int64 id = 1;                      // users.id
  string mobile = 2;                 // users.mobile
  string avatar_url = 3;             // users.avatar_url
  string global_wallet_address = 4;  // users.global_wallet_address
  bool is_active = 5;                // users.is_active
  int64 created_at = 6;              // users.created_at
}

注意:不包含敏感字段(password_hash, access_token, token_expires_at

FanProfile表字段映射

message FanProfile {
  int64 id = 1;              // fan_profiles.id
  int64 user_id = 2;         // fan_profiles.user_id
  int64 star_id = 3;         // fan_profiles.star_id核心隔离键
  string nickname = 4;       // fan_profiles.nickname
  int32 level = 5;           // fan_profiles.level
  int32 times = 6;           // fan_profiles.times剩余铸造次数
  int32 social = 7;          // fan_profiles.social好友个数
  int64 experience = 8;      // fan_profiles.experience
  int64 coin_balance = 9;    // fan_profiles.coin_balance
  int64 crystal_balance = 10; // fan_profiles.crystal_balance
  repeated string tags = 11; // fan_profiles.tagsJSONB数组
  int64 created_at = 12;     // fan_profiles.created_at
}

三、认证相关消息设计

3.1 RegisterRequest / RegisterResponse

RegisterRequest

  • mobile - 手机号(必填)
  • password - 密码(必填)
  • star_id - 选择第一个粉丝身份的明星ID必填
  • nickname - 第一个粉丝身份的昵称(必填)

RegisterResponse

  • base - 基础响应(状态码、消息、时间戳)
  • access_token - JWT Token已包含 star_id
  • expires_in - Token过期时间7天=604800秒
  • user - 创建的用户信息
  • fan_profile - 创建的粉丝档案

业务逻辑

  1. 创建用户(users表)
  2. 创建第一个粉丝档案(fan_profiles表,事务)
  3. 生成JWT Token包含 user_id, star_id, updated_at
  4. 更新用户Tokenusers.access_token, users.token_expires_at

3.2 LoginRequest / LoginResponse

LoginRequest

  • mobile - 手机号(必填)
  • password - 密码(必填)

LoginResponse

  • base - 基础响应
  • access_token - JWT Token已包含 star_id
  • expires_in - Token过期时间
  • user - 用户信息
  • fan_profile - 当前粉丝档案根据Token中的 star_id
  • fan_profiles - 用户的所有粉丝身份列表

业务逻辑

  1. 根据手机号查询用户
  2. 验证密码bcrypt比对
  3. 验证用户是否激活
  4. 获取用户的粉丝档案列表
  5. 生成JWT Token包含当前 star_id,从第一个粉丝档案获取)
  6. 更新用户Token

3.3 RefreshTokenRequest / RefreshTokenResponse

RefreshTokenRequest

  • access_token - 旧的access_token单token方案

RefreshTokenResponse

  • base - 基础响应
  • access_token - 新的Access Token
  • expires_in - Token过期时间

业务逻辑

  1. 解析旧Token即使过期也要解析
  2. 查询用户
  3. 验证旧Token是否匹配数据库中的Token
  4. 验证 updated_at 是否匹配如果用户信息更新Token失效
  5. 生成新Token
  6. 更新数据库中的Token

3.4 ValidateTokenRequest / ValidateTokenResponse

ValidateTokenRequest

  • access_token - 要验证的Token

ValidateTokenResponse

  • base - 基础响应
  • user_id - Token关联的用户ID
  • star_id - Token关联的明星ID
  • is_valid - Token是否有效
  • expires_at - Token过期时间戳毫秒

业务逻辑

  1. 解析Token
  2. 验证签名和过期时间
  3. 验证Token是否匹配数据库中的Token
  4. 验证 updated_at 是否匹配
  5. 返回验证结果

3.5 LogoutRequest / LogoutResponse

LogoutRequest

  • access_token - 要失效的Token可选

LogoutResponse

  • base - 基础响应

业务逻辑

  1. 从Token中提取 user_id
  2. 清除用户Tokenusers.access_token = NULL, users.token_expires_at = NULL

四、消息设计原则

4.1 字段编号规则

  • 1-15常用字段占用1字节
  • 16-2047一般字段
  • 不要重用已删除字段的编号
  • 新增字段只能追加,不能删除

4.2 数据类型选择

  • ID类型:使用 int64(支持大整数)
  • 时间戳:使用 int64Unix时间戳毫秒
  • 布尔值:使用 bool
  • 数组:使用 repeated 关键字
  • 可选字段proto3中所有字段默认都是可选的

4.3 命名规范

  • 消息类型PascalCaseRegisterRequest
  • 字段名snake_caseaccess_token
  • RPC方法PascalCaseRegister

4.4 响应结构

  • 所有Response的第一个字段必须是 topfans.common.BaseResponse base = 1;
  • BaseResponse 包含状态码、错误消息、时间戳

五、REST API映射

使用 google.api.annotations 定义REST API路径

rpc Login(LoginRequest) returns (LoginResponse) {
  option (google.api.http) = {
    post: "/api/v1/auth/login"
    body: "*"
  };
}

支持通过 grpc-gateway 自动生成REST API无需手动实现HTTP路由。

六、与Service层接口的对应关系

Service接口 → Proto消息

Service方法 Request Response
Register(req) RegisterRequest RegisterResponse
Login(req) LoginRequest LoginResponse
Logout(req) LogoutRequest LogoutResponse
RefreshToken(req) RefreshTokenRequest RefreshTokenResponse
ValidateToken(req) ValidateTokenRequest ValidateTokenResponse

注意Service层接口应使用proto定义的类型而不是原生类型。

七、后续扩展

当前proto定义覆盖了3.1认证Service层的需求。后续可以添加

  • 用户信息Service相关消息已在proto中定义
  • 粉丝身份Service相关消息已在proto中定义
  • 社交功能相关消息(后续添加)

八、验证检查清单

  • 所有必需的消息类型已定义
  • 字段类型与数据库设计一致
  • 单Token方案已正确实现
  • Token中包含 star_id 的设计已体现
  • 粉丝身份隔离设计已体现
  • REST API路径已定义
  • RPC服务定义完整
  • 字段编号无冲突
  • 命名规范一致

九、下一步

  1. 生成proto Go代码运行 make proto 或手动执行protoc命令
  2. 验证生成的代码可以正常导入
  3. 更新 pkg/errors/errors.go 使用proto类型
  4. 开始开发Service层使用proto类型