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

236 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Proto文件设计说明 - 3.1 认证Service层
## 一、设计依据
本proto设计基于以下技术文档
- **微服务架构设计文档** - 确定服务职责和API设计
- **数据库设计文档** - 确定数据结构和字段定义
- **开发功能顺序文档** - 确定Service层接口需求
- **JWT设计** - 确定Token相关字段和验证流程
## 二、核心设计要点
### 2.1 单Token方案
-`LoginResponse``RegisterResponse` 只返回 `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表字段映射
```protobuf
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表字段映射
```protobuf
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. 更新用户Token`users.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. 清除用户Token`users.access_token = NULL`, `users.token_expires_at = NULL`
## 四、消息设计原则
### 4.1 字段编号规则
- 1-15常用字段占用1字节
- 16-2047一般字段
- 不要重用已删除字段的编号
- 新增字段只能追加,不能删除
### 4.2 数据类型选择
- **ID类型**:使用 `int64`(支持大整数)
- **时间戳**:使用 `int64`Unix时间戳毫秒
- **布尔值**:使用 `bool`
- **数组**:使用 `repeated` 关键字
- **可选字段**proto3中所有字段默认都是可选的
### 4.3 命名规范
- **消息类型**PascalCase`RegisterRequest`
- **字段名**snake_case`access_token`
- **RPC方法**PascalCase`Register`
### 4.4 响应结构
- 所有Response的第一个字段必须是 `topfans.common.BaseResponse base = 1;`
- `BaseResponse` 包含状态码、错误消息、时间戳
## 五、REST API映射
使用 `google.api.annotations` 定义REST API路径
```protobuf
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中定义
- 社交功能相关消息(后续添加)
## 八、验证检查清单
- [x] 所有必需的消息类型已定义
- [x] 字段类型与数据库设计一致
- [x] 单Token方案已正确实现
- [x] Token中包含 `star_id` 的设计已体现
- [x] 粉丝身份隔离设计已体现
- [x] REST API路径已定义
- [x] RPC服务定义完整
- [x] 字段编号无冲突
- [x] 命名规范一致
## 九、下一步
1. 生成proto Go代码运行 `make proto` 或手动执行protoc命令
2. 验证生成的代码可以正常导入
3. 更新 `pkg/errors/errors.go` 使用proto类型
4. 开始开发Service层使用proto类型