用户 Profile API
用户个人资料管理接口,操作 profiles 表的 username、display_name 等字段。
身份字段(phone / email)禁止经本接口裸写:手机号绑定/换绑必须走
POST /my/phone/bind(OTP 校验 + 唯一性约束 + 写phone_verified_at),邮箱绑定走专门的邮箱绑定流程。PATCH /profile收到phone或400拒绝(DB 层另有列级权限收口兜底直连 PostgREST 旁路)。
路由前缀:/profile
源码:apps/backend/src/routes/profile.ts
认证
所有接口需要 JWT 认证:
Authorization: Bearer <JWT>端点
1. 获取当前用户 Profile
GET /profile获取当前登录用户的 Profile 信息。
响应 200 OK:
{
"success": true,
"data": {
"user_id": "uuid",
"username": "zhangsan",
"display_name": "张三",
"avatar_url": "https://example.com/avatar.jpg",
"bio": "个人简介",
"phone": "13800138000",
"phone_verified_at": "2026-06-23T10:00:00.000Z",
"created_at": "2026-01-01T00:00:00.000Z",
"updated_at": "2026-03-07T10:00:00.000Z"
}
}| 字段 | 类型 | 说明 |
|---|---|---|
phone | string | null | 业务手机号(profiles.phone)。判定「已绑定」必须看 phone_verified_at 非空,phone 本身可能是早于验证机制引入的历史脏数据。 |
phone_verified_at | string | null | 手机号通过 OTP 验证绑定的时间(ISO 8601)。非空 = 已验证绑定且是唯一标识;null = 未验证 / 未绑。 |
如果用户 Profile 尚未创建(注册异常),
data返回null。
错误码:
| HTTP | 错误 | 说明 |
|---|---|---|
| 401 | Unauthorized | 未认证 |
| 500 | Failed to get profile | 查询失败 |
| 500 | Internal server error | 服务端错误 |
2. 更新当前用户 Profile
PATCH /profile更新当前用户的 username 和/或 display_name。
请求体:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
username | string | null | 否 | 用户名(传 null 或空字符串可清空) |
display_name | string | null | 否 | 显示名(传 null 或空字符串可清空) |
bio | string | null | 否 | 个人简介 |
至少提供一个字段。
⚠️
phone/400(防止绕过 OTP 验证、phone_verified_at与唯一性约束)。手机号请走POST /my/phone/bind,邮箱请走专门的邮箱绑定流程。
username 格式要求:
- 3-39 字符
- 字母或数字开头
- 仅允许字母、数字、连字符(
-)、下划线(_) - 不允许连续连字符(
--) - 自动转为小写
display_name 格式要求:
- 1-50 字符
- 不允许包含空格
响应 200 OK:
{
"success": true,
"data": {
"user_id": "uuid",
"username": "zhangsan",
"display_name": "张三",
"avatar_url": "https://example.com/avatar.jpg",
"bio": "个人简介",
"phone": "13800138000",
"phone_verified_at": "2026-06-23T10:00:00.000Z",
"created_at": "2026-01-01T00:00:00.000Z",
"updated_at": "2026-03-07T12:00:00.000Z"
}
}错误码:
| HTTP | 错误 | 说明 |
|---|---|---|
| 400 | No valid fields to update | 未提供有效字段 |
| 400 | Username must be at least 3 characters | username 太短 |
| 400 | Username must be at most 39 characters | username 太长 |
| 400 | Username must start with a letter or number... | username 格式不合法 |
| 400 | Username cannot contain consecutive hyphens | username 含连续连字符 |
| 400 | Display name cannot be empty | display_name 为空 |
| 400 | Display name must be at most 50 characters | display_name 太长 |
| 400 | Display name cannot contain spaces | display_name 含空格 |
| 400 | phone must be bound via /my/phone/bind | 试图经本接口写 phone(必须走绑定流程) |
| 400 | email must be bound via the email binding flow | 试图经本接口写 email(必须走绑定流程) |
| 401 | Unauthorized | 未认证 |
| 409 | Username is already taken | username 已被占用 |
| 500 | Failed to update profile | 更新失败 |
| 500 | Internal server error | 服务端错误 |
3. 检查 Username 可用性
GET /profile/check-username/:username检查指定的 username 是否可用(排除当前用户自己)。
路径参数:
| 参数 | 说明 |
|---|---|
username | 要检查的用户名 |
响应 200 OK(可用):
{
"success": true,
"data": {
"available": true
}
}响应 200 OK(不可用 - 格式错误):
{
"success": true,
"data": {
"available": false,
"reason": "invalid_format",
"message": "Username must be at least 3 characters"
}
}响应 200 OK(不可用 - 已被占用):
{
"success": true,
"data": {
"available": false,
"reason": "taken",
"message": "Username is already taken"
}
}错误码:
| HTTP | 错误 | 说明 |
|---|---|---|
| 401 | Unauthorized | 未认证 |
| 500 | Internal server error | 服务端错误 |
补充端点
本节补充 plans/need-update-api.md 中尚未覆盖到 docs-site 的接口。端点标题保持严格的 METHOD /path 格式,便于后台文档覆盖率服务识别。
POST /profile/avatar
上传并更新当前用户头像。
认证:JWT Bearer Token。 请求:请求体为 JSON,包含创建、提交、安装、发布或业务动作所需字段。
响应:成功时返回创建或更新后的资源对象,或 { "success": true }。
常见错误:400 参数非法,401 未认证,403 权限不足,404 资源不存在;服务端或上游异常返回 500。