# Dating App API 完整接口说明 > API version: `0.6.12` > 面向前端与后端开发者的接口参考文档。 > 0.6.12 已完成正式数据库迁移并发布,通过公网接口验证。 ## 1. 通用说明 ### 1.1 Base URL ```text {{base_url}} ``` 本地测试地址: ```text http://127.0.0.1:8001 ``` 生产地址由部署环境提供,客户端通过配置项设置 `base_url`,不要在代码中写死具体域名。 ### 1.2 请求格式 - JSON 接口请求头:`Content-Type: application/json` - 文件上传接口请求格式:`multipart/form-data` - 除注册、登录、OAuth、健康检查外,接口都需要登录。 - 登录接口使用:`Authorization: Bearer ` - `access_token` 默认有效 15 分钟,`refresh_token` 默认有效 30 天。 ### 1.3 通用错误 参数错误:`422 Unprocessable Entity` ```json { "detail": [ { "loc": ["body", "field_name"], "msg": "说明文字", "type": "validation_error" } ] } ``` 未登录或 token 无效:`401` ```json {"detail": "需要登录"} ``` 账号被停用或没有权限:`403` 资源不存在:`404` ## 2. 数据结构 ### 2.1 注册请求 RegisterRequest 必填字段: | 字段 | 类型 | 说明 | |---|---|---| | `email_or_phone` | string | 邮箱或手机号,二选一但使用同一个字段,3-320 字符 | | `password` | string | 密码,8-128 字符 | | `confirm_password` | string | 确认密码,8-128 字符,必须和 `password` 完全一致 | | `relationship_goal` | string | 必填单选:`serious_relationship`、`casual_dates`、`new_friends` 或 `marriage` | 可选字段:`full_name`(最多 120)、`gender`(最多 30)、`birth_date`(`YYYY-MM-DD`)、`city`(最多 120)、`country`(最多 120)、`bio`(去除首尾空格后 1-2000 字符)、`interests`(兴趣数组)。 用户的介绍内容在 `bio` 和介绍视频中二选一。选择文字简介时在注册 JSON 中提交非空 `bio`;选择视频时可以省略 `bio`,注册成功取得 access token 后调用 `/api/v1/users/me/video`。因为注册请求是 JSON,不能直接携带视频文件。 `confirm_password` 只用于注册时校验,不保存到数据库,也不会出现在任何响应中。 注册响应继续只返回 token。前端随后调用 `GET /api/v1/auth/me`:未上传头像或视频时,`profile.profile_image_url` 或 `profile.video_url` 为 `null`;上传后,生产环境返回可直接加载的一小时 OSS 签名 URL。两者互斥:上传视频会清空已有 `bio`,之后通过个人资料接口提交非空 `bio` 会删除介绍视频。前端应在 `bio` 或 `video_url` 其中一个非空时才完成注册引导。 ### 2.2 用户 UserResponse ```json { "id": 1, "email_or_phone": "user@example.com", "status": "active", "profile": { "full_name": "Test User", "gender": "female", "birth_date": "2000-01-01", "city": "Shanghai", "county": "Huangpu", "country": "China", "relationship_goal": "serious_relationship", "bio": "I like traveling.", "profile_image_url": "https:///melove/users/1/avatar.jpg?", "video_url": null, "interests": ["Photography", "Movies"] }, "posts": [], "liked_users": [], "liked_by_users": [], "matches": [], "liked_users_count": 0, "liked_by_users_count": 0, "matches_count": 0, "created_at": "2026-09-01T10:00:00" } ``` `GET /api/v1/auth/me` 和 `GET /api/v1/users/me` 会在这四个数组中分别返回最近 20 条本人帖子、我喜欢的人、喜欢我的人和匹配对象。`liked_users_count`、`liked_by_users_count`、`matches_count` 是对应三类关系的总数,不受 20 条列表上限影响;喜欢包含 `like` 和 `super_like`,均只统计当前有效用户。完整或分页数据使用 4.9-4.14 的独立接口。注册、登录和资料更新响应不包含这些总数字段。 ### 2.3 TokenResponse ```json { "access_token": "", "refresh_token": "", "token_type": "bearer", "user": { "...": "UserResponse" } } ``` 注册接口是例外,只返回 token,不返回 `user`: ```json { "access_token": "", "refresh_token": "", "token_type": "bearer" } ``` ### 2.4 公开用户 DiscoveryUserResponse ```json { "id": 2, "full_name": "Bob", "gender": "male", "birth_date": "1998-05-20", "city": "Shanghai", "county": "Huangpu", "country": "China", "relationship_goal": "serious_relationship", "bio": "Likes hiking", "profile_image_url": "https:///melove/users/2/avatar.jpg?", "video_url": "https:///melove/users/2/intro.mp4?", "distance_km": 1.24, "compatibility_percentage": 85, "media": [ {"id": 10, "media_type": "profile_image", "url": "https:///melove/users/2/avatar.jpg?"} ] } ``` 公开用户响应中的 `profile_image_url` 是头像地址,`video_url` 是介绍视频地址;`media[]` 是同一用户公开资料媒体的明细列表,按 `media_type` 区分头像和介绍视频,不是用户发布的帖子。公开主页接口额外返回 `interests` 和最近 20 条公开 `posts`,方便前端用一次请求渲染主页。邮箱/手机号、账号状态、喜欢列表和匹配记录不会返回;超过 20 条帖子时调用 `GET /api/v1/users/{user_id}/posts` 分页获取。 ### 2.5 兴趣、位置、帖子和聊天结构 兴趣响应:`{"interests": ["Photography", "Dogs"]}` 位置响应:`{"latitude": 31.2304, "longitude": 121.4737, "city": "上海市", "county": "黄浦区", "updated_at": "2026-09-01T10:00:00"}` 滑动响应:`{"direction": "like", "matched": true, "match_id": 15}`。未匹配时 `match_id` 为 `null`。 帖子响应字段:`id`、`content`、`post_type`、`content_format`、`feeling`、`location`、`author`、`like_count`、`comment_count`、`liked_by_me`、`liked_by_users`、`media`、`created_at`。`location` 是发帖时选定地点的快照,与作者当前资料城市和位置分开保存。 帖子和评论的 `author` 均包含 `id`、`full_name`、`profile_image_url`、`city`、`country`、`compatibility_percentage`。未上传头像时 `profile_image_url` 为 `null`;生产环境返回一小时有效的 OSS 签名 URL,可直接展示,过期后重新请求。所有 PostResponse(Explore、详情、个人资料内的帖子和用户帖子列表)均包含 `liked_by_users: [{"id": 2, "full_name": "Reader"}]`;无点赞时为 `[]`,按最近点赞在前排序,只包含 active 用户,`like_count` 等于名单长度。姓名可能为 `null`;名单不含联系方式或完整用户资料。 聊天消息字段:`id`、`conversation_id`、`sender_id`、`content`、`message_type`、`is_deleted`、`created_at`。撤回后 `content` 为 `null`,`is_deleted` 为 `true`。 ## 3. Authentication 认证接口 ### 3.1 健康检查 **GET** `{{base_url}}/health` 认证:不需要。 前端发送:无 body。 成功:`200` ```json {"status": "ok"} ``` ### 3.2 注册 **POST** `{{base_url}}/api/v1/auth/register` 认证:不需要。 请求体:`application/json` ```json { "email_or_phone": "user@example.com", "password": "password123", "confirm_password": "password123", "relationship_goal": "serious_relationship", "full_name": "Test User", "gender": "female", "birth_date": "2000-01-01", "city": "Shanghai", "country": "China", "bio": "I like traveling.", "interests": ["Photography", "Movies"] } ``` 手机号注册只需把 `email_or_phone` 改为手机号。成功:`201`,返回 2.3 中的 token-only 结构。 错误:`409` 邮箱/手机号已注册;`422` 缺少必填字段、`relationship_goal` 值无效、两次密码不一致或兴趣少于 2 个。 MVP 不使用 OTP,注册后账号直接为 `active`。 ### 3.3 登录 **POST** `{{base_url}}/api/v1/auth/login` 认证:不需要。 请求体: ```json { "email_or_phone": "user@example.com", "password": "password123" } ``` 成功:`200`,返回 TokenResponse。错误:`401` 账号或密码错误;`403` 账号已停用;`422` 参数错误。 ### 3.4 OAuth 登录/注册占位接口 **POST** `{{base_url}}/api/v1/auth/oauth` 认证:不需要。 请求体: ```json { "provider": "google", "provider_user_id": "google-user-id-123", "email": "user@example.com", "full_name": "OAuth User" } ``` `provider` 只能是 `wechat` 或 `google`;`email`、`full_name` 可选。成功:`200`,返回 TokenResponse。错误:`422` 参数错误。 ### 3.5 刷新 token **POST** `{{base_url}}/api/v1/auth/refresh` 认证:不需要 Bearer token,但必须提交有效 refresh token。 请求体: ```json {"refresh_token": ""} ``` 成功:`200`,返回新的 TokenResponse;旧 refresh token 会失效。错误:`401` refresh token 无效、已过期或已撤销;`422` 参数错误。 ### 3.6 退出登录 **POST** `{{base_url}}/api/v1/auth/logout` 认证:不需要 Bearer token。 请求体: ```json {"refresh_token": ""} ``` 成功:`200` ```json {"message": "已退出登录"} ``` ### 3.7 获取当前用户 **GET** `{{base_url}}/api/v1/auth/me` 认证:需要 Bearer token。 前端发送:无 body。 成功:`200`,返回 UserResponse。启动 App 时可调用此接口判断 token 是否仍然有效。 ### 3.8 获取当前用户(兼容地址) **GET** `{{base_url}}/api/v1/users/me` 认证:需要 Bearer token。 功能和 3.7 完全相同,返回 UserResponse。 ## 4. User Profile 用户资料和媒体 ### 4.1 修改个人资料 **PATCH** `{{base_url}}/api/v1/users/me` 认证:需要 Bearer token。 请求体可只提交需要修改的字段: ```json { "full_name": "New Name", "gender": "female", "birth_date": "2000-01-01", "city": "Beijing", "country": "China", "relationship_goal": "marriage", "bio": "Updated bio", "occupation": "Creative Director at Studio Drift", "education": "NYU Gallatin School", "height_cm": 175, "beliefs": "spiritual_agnostic", "smoking": "non_smoker", "drinking": "socially", "pets": "golden_retriever", "exercise": "active_4x_week", "interests": ["Travel", "Music"] } ``` 新增可选资料字段:`occupation`、`education`(各最多 120 字符)、`height_cm`(整数,100-250)、`beliefs`(最多 120)、`smoking`、`drinking`(各最多 50)、`pets`(最多 120)、`exercise`(最多 50)。传 `null` 可清空对应字段。`GET /api/v1/auth/me` 会返回这些字段,并额外返回根据 `birth_date` 计算的 `age`。 成功:`200`,返回更新后的 UserResponse。兴趣如提交则至少 2 个;错误:`422` 字段格式或兴趣不符合要求。 ### 4.2 获取我的兴趣 **GET** `{{base_url}}/api/v1/users/me/interests` 认证:需要 Bearer token。 成功:`200` ```json {"interests": ["Photography", "Dogs", "My custom interest"]} ``` ### 4.3 替换我的兴趣 **PUT** `{{base_url}}/api/v1/users/me/interests` 认证:需要 Bearer token。 请求体: ```json {"interests": ["Photography", "Dogs", "My custom interest"]} ``` 至少 2 项,不限制最多数量;`Other` 不需要特殊字段,直接把自定义文字作为数组项。成功:`200`,返回兴趣数组。错误:`422` 少于 2 项、空字符串或单项超过 120 字符。 ### 4.4 更新位置 **PUT** `{{base_url}}/api/v1/users/me/location` 认证:需要 Bearer token。 请求体: ```json {"latitude": 31.2304, "longitude": 121.4737, "city": "上海市", "county": "黄浦区"} ``` 纬度范围 `-90` 到 `90`,经度范围 `-180` 到 `180`;`city` 和 `county` 必填,去除首尾空格后须为 1-120 字符。城市写入用户资料并参与同城推荐;区县单独保存在 `county`,不等于国家字段 `country`。成功:`200`,返回四个位置字段及 `updated_at`;`GET /api/v1/auth/me` 和公开用户资料也返回 `profile.county` 或 `county`。错误:`422` 缺字段、空城市/区县或坐标超出范围。 ### 4.5 上传自我介绍视频 **POST** `{{base_url}}/api/v1/users/me/video` 认证:需要 Bearer token。 请求格式:`multipart/form-data`,字段名 `video`,支持 `video/mp4`、`video/quicktime`、`video/webm`,最大 100 MB。 每名用户只保留最新一份介绍视频;再次上传成功后,旧视频记录和旧文件会被替换。若新文件存储失败,原视频保持不变。 成功:`200` ```json {"id": 11, "media_type": "intro_video", "review_status": "pending"} ``` 错误:`413` 文件过大;`415` 文件类型不支持;`422` 未上传文件。 ### 4.6 上传头像 **POST** `{{base_url}}/api/v1/users/me/image` 认证:需要 Bearer token。 请求格式:`multipart/form-data`,字段名 `image`,支持 JPG、PNG、WebP,最大 10 MB。 每名用户只保留最新一张头像;再次上传成功后,旧头像记录和旧文件会被替换。若新文件存储失败,原头像保持不变。 成功返回媒体 id、类型和审核状态;错误:`413`、`415`、`422`。 ### 4.7 上传身份证/护照 **POST** `{{base_url}}/api/v1/users/me/identity` 认证:需要 Bearer token。 请求格式:`multipart/form-data`,字段名 `document`,支持 JPG、PNG、PDF,最大 10 MB。 成功返回媒体 id、类型和审核状态;该文件只有本人可访问。错误:`413`、`415`、`422`。 ### 4.8 获取用户媒体文件 **GET** `{{base_url}}/api/v1/media/{media_id}` 认证:需要 Bearer token。 路径参数:`media_id` 为媒体 id。 成功:`200`,返回文件二进制内容;公开头像/视频可被其他 active 用户读取,身份证/护照只有本人可读取。错误:`403` 无权限;`404` 文件不存在。 Meet、Search、Match 和个人资料响应中的 `profile_image_url`、`video_url`、`media[].url` 在生产 OSS 环境为一小时有效的完整签名 URL,前端图片/视频组件可直接使用,不需要再次附加 Bearer Token。URL 过期后重新请求相应的资料列表即可取得新 URL。身份证/护照不会出现在这些公开 URL 字段中。 ### 4.9 获取本人帖子 **GET** `{{base_url}}/api/v1/users/me/posts?limit=20&offset=0` 认证:需要 Bearer token。`limit` 为 1-50,`offset` 为 0-5000。成功返回 `PostResponse` 数组,新帖在前。 ### 4.10 获取公开用户资料 **GET** `{{base_url}}/api/v1/users/{user_id}` 认证:需要 Bearer token。成功返回目标用户的 `PublicUserProfileResponse`,包括公开资料、`interests` 和最近 20 条 `posts`;不会返回邮箱/手机号、账号状态、喜欢列表或匹配记录。目标不存在或已停用返回 `404`。 ### 4.11 获取公开用户帖子 **GET** `{{base_url}}/api/v1/users/{user_id}/posts?limit=20&offset=0` 认证:需要 Bearer token。成功返回目标用户的 `PostResponse` 数组,新帖在前;目标不存在或已停用返回 `404`。 ### 4.12 获取我喜欢的人 **GET** `{{base_url}}/api/v1/users/me/liked` 认证:需要 Bearer token。成功返回当前用户主动右滑喜欢的完整 `DiscoveryUserResponse` 数组,最近操作在前;已经匹配成功的用户会被排除。该接口不分页;旧请求中的 `limit`、`offset` 参数会被忽略。 ### 4.13 获取喜欢我的人 **GET** `{{base_url}}/api/v1/users/me/likes` 认证:需要 Bearer token。成功返回主动喜欢当前用户的完整 `DiscoveryUserResponse` 数组,最近操作在前;已经匹配成功的用户会被排除。该接口不分页;旧请求中的 `limit`、`offset` 参数会被忽略。 ### 4.14 获取我的匹配对象 **GET** `{{base_url}}/api/v1/users/me/matches` 认证:需要 Bearer token。成功返回完整的 `MatchResponse` 数组,与 `/api/v1/matches` 数据一致,便于个人主页分区加载。该接口不分页,旧的 `limit`、`offset` 参数会被忽略。 ## 5. Meet、Swipe、Match 和 Search ### 5.1 获取推荐用户 **GET** `{{base_url}}/api/v1/meet?limit=20` 认证:需要 Bearer token。 查询参数:`limit` 可选,1-50,默认 20。 成功:`200`,返回 DiscoveryUserResponse 数组;只返回 active 用户,且不会重复返回已经滑过的用户。向当前用户发出有效 `super_like` 的用户最优先;其余按同城、同国家、其他国家排序,同组内按 `compatibility_percentage` 从高到低排序。 ### 5.2 左滑、右滑或超级喜欢 **POST** `{{base_url}}/api/v1/meet/swipes` 认证:需要 Bearer token。 请求体: ```json {"target_user_id": 2, "direction": "like"} ``` `direction` 可为 `pass`(左滑)、`like`(右滑)或 `super_like`(超级喜欢)。`super_like` 会让发起者在目标用户的 Meet 列表中优先出现,直到发起者撤销或改为其他滑动;目标用户已经滑过发起者时不会再次显示。成功:`200`,返回 SwipeResponse;双方的操作均为 `like` 或 `super_like` 时,`matched=true` 并生成 `match_id`。错误:`400` 不能操作自己;`404` 目标用户不存在;`422` 参数错误。 ### 5.3 取消喜欢 **DELETE** `{{base_url}}/api/v1/meet/likes/{target_user_id}` 认证:需要 Bearer token。 成功:`200` `{"message":"已取消喜欢"}`,并解除对应匹配。兼容旧客户端,可取消 `like` 或 `super_like`;取消键请统一使用 5.4 的撤销滑动接口。错误:`404` 没有可取消的喜欢记录。 ### 5.4 取消键:撤销左滑、右滑或超级喜欢 **DELETE** `{{base_url}}/api/v1/meet/swipes/{target_user_id}` 认证:需要 Bearer token。删除本人对目标用户保存的 `pass`、`like` 或 `super_like` 记录,使目标用户可以再次出现在自己的 Meet 推荐列表;撤销 `super_like` 也会立即取消在目标用户列表中的优先展示。如果撤销的是已形成匹配的喜欢,同时解除对应匹配。成功:`200`,例如 `{"message":"已撤销滑动","previous_direction":"super_like"}`。错误:`404` 没有可撤销的滑动记录。 ### 5.5 获取匹配列表 **GET** `{{base_url}}/api/v1/matches` 认证:需要 Bearer token。 该接口不分页,返回全部有效匹配,最近的在前;旧的 `limit`、`offset` 参数会被忽略。成功:`200`,返回 MatchResponse 数组,每项包含 `id`、`matched_at` 和对方公开资料 `user`。返回条数等于 `GET /api/v1/auth/me` 中的 `matches_count`。 ### 5.6 搜索用户 **GET** `{{base_url}}/api/v1/search` 认证:需要 Bearer token。 查询参数: | 参数 | 类型 | 说明 | |---|---|---| | `q` | string | 可选,搜索姓名、简介、城市、国家,最多 200 字符 | | `city` | string | 可选,按城市筛选,可与 country 同时提供 | | `country` | string | 可选,按国家筛选,可与 city 同时提供 | | `latitude` | number | 可选,必须和 longitude 同时提供 | | `longitude` | number | 可选,必须和 latitude 同时提供 | | `max_distance_km` | number | 可选,最大 500;不传坐标时使用自己的位置 | | `limit` | integer | 可选,1-50,默认 20 | 成功:`200`,返回 DiscoveryUserResponse 数组,包含 `country` 和 `compatibility_percentage`。错误:`422` 坐标只提供一个,或距离筛选缺少坐标/自己的位置。 ## 6. Explore 动态 ### 6.1 创建帖子 **POST** `{{base_url}}/api/v1/explore/posts` 认证:需要 Bearer token。 请求体: ```json { "content": "Feeling **happy** and *relaxed* today", "post_type": "text", "content_format": "markdown", "feeling": "happy", "location": {"name": "Blue Bottle Coffee, Soho NYC", "latitude": 40.723, "longitude": -73.998} } ``` `post_type` 可选 `text`、`image`、`video`,默认 `text`。`content` 最多 5000 字符;文字帖至少包含非空文字、心情或地点之一。`feeling` 可选,提交 1-50 字符的心情代码或标签,例如 `happy`。`location` 可选,`name` 必填且为 1-255 字符,经纬度可以都不传或同时传,范围分别为 `-90..90` 和 `-180..180`。地点是帖子内容,不会修改用户资料或当前位置;选定地点及提交的坐标会显示给能查看帖子的用户。 `content_format` 为 `plain`(默认)或 `markdown`。前端粗体按钮把选中文字写成 `**bold**`,斜体按钮写成 `*italic*`,并提交 `content_format: "markdown"`;后端原样保存 Markdown 源文本,不返回 HTML。前端显示时按该字段渲染并对生成的 HTML 做安全处理。旧帖子按 `plain` 返回。音乐字段暂未开放。 图片或视频帖先用此接口创建,取得 `id`,再调用 6.5 的媒体上传接口;单帖最多 9 张图片加 1 个视频,可以混合使用;同时含图片和视频时 `post_type` 为 `mixed`。成功:`201`,返回包含新字段的 PostResponse。 ### 6.2 获取 Explore 信息流 **GET** `{{base_url}}/api/v1/explore/feed?limit=20&offset=0` 认证:需要 Bearer token。 参数:`limit` 1-50,默认 20;新排序使用 `offset` 分页。旧参数 `before_id` 保留为按时间 ID 截断的兼容模式,不能与非零 `offset` 同时使用。成功:`200`,每条帖子包含 `content_format`、`feeling` 和 `location`;按作者同城、同国家、其他国家分组,同组按匹配度排序,最后以新帖优先打破并列。 ### 6.3 获取帖子详情 **GET** `{{base_url}}/api/v1/explore/posts/{post_id}` 认证:需要 Bearer token。 成功:`200`,返回 PostResponse;错误:`404` 帖子不存在或作者不可用。 ### 6.4 删除帖子 **DELETE** `{{base_url}}/api/v1/explore/posts/{post_id}` 认证:需要 Bearer token。只能删除自己的帖子。成功:`200` `{"message":"帖子已删除"}`;错误:`403` 无权限;`404` 不存在。 ### 6.5 上传帖子媒体 **POST** `{{base_url}}/api/v1/explore/posts/{post_id}/media?position=0` 认证:需要 Bearer token,且必须是帖子作者。 请求格式:`multipart/form-data`,字段名 `media`;`position` 可选,0-8。支持 JPG、PNG、WebP、MP4、MOV、WebM。 每条帖子最多 9 张图片和 1 个视频,可同时存在于同一帖子;同时含图片和视频时 `post_type` 为 `mixed`。成功:`201`,返回 `PostMediaResponse`(`id`、`media_type`、`mime_type`、`size_bytes`、`position`、`url`)。生产 OSS 环境的 `url` 是一小时有效的完整签名 URL,可直接加载且不需要 Bearer Token。错误:`403`、`404`、`409` 类型/数量冲突、`413`、`415`。 ### 6.6 获取帖子媒体 **GET** `{{base_url}}/api/v1/explore/media/{media_id}` 认证:需要 Bearer token。 成功:`200`,返回文件二进制内容;错误:`404` 帖子或媒体不存在。 ### 6.7 点赞帖子 **POST** `{{base_url}}/api/v1/explore/posts/{post_id}/like` 认证:需要 Bearer token。 成功:`200`,返回精简的 PostLikeResponse,不再返回完整帖子正文、作者和媒体: ```json { "message": "like successful", "like_count": 1, "liked_by_me": true, "liked_by_users": [{"id": 2, "full_name": "Reader"}] } ``` 重复点赞不会增加数量;前端用返回的数量、状态和名单更新已有帖子。错误:`401` 未登录;`404` 帖子不存在。 #### 单独查询点赞者 **GET** `{{base_url}}/api/v1/explore/posts/{post_id}/like` 认证:需要 Bearer token,无请求体或分页参数。成功:`200`,直接返回 `[{"id": 2, "full_name": "Reader"}]`,无点赞时为 `[]`;只含 active 用户,最近点赞在前。错误:`401` 未登录;`404` 帖子不存在。 ### 6.8 取消帖子点赞 **DELETE** `{{base_url}}/api/v1/explore/posts/{post_id}/like` 认证:需要 Bearer token。 成功:`200`,返回精简的 PostUnlikeResponse —— `{"message":"unlike successful","like_count":0,"liked_by_me":false,"liked_by_users":[...]}`,不再返回完整帖子。重复请求保持未点赞状态。 ### 6.9 获取评论 **GET** `{{base_url}}/api/v1/explore/posts/{post_id}/comments` 认证:需要 Bearer token。 成功:`200`,返回 CommentResponse 数组;每条评论的 `author.profile_image_url` 为头像地址,无头像时为 `null`,并包含 `parent_comment_id`、`reply_count`、`like_count`、`liked_by_me`。评论以扁平列表返回,前端按 `parent_comment_id` 组织回复。错误:`404` 帖子不存在。 ### 6.10 发表评论 **POST** `{{base_url}}/api/v1/explore/posts/{post_id}/comments` 认证:需要 Bearer token。 请求体: ```json {"content": "Looks great!"} ``` 内容 1-2000 字符且不能全是空格。回复某条评论时额外传 `parent_comment_id`: ```json {"content": "我同意", "parent_comment_id": 12} ``` 成功:`201`,返回 CommentResponse,包含 `author.profile_image_url`;错误:`404` 帖子或父评论不存在;`422` 内容无效。 ### 6.11 删除评论 **DELETE** `{{base_url}}/api/v1/explore/comments/{comment_id}` 认证:需要 Bearer token,只能删除自己的评论。成功:`200` `{"message":"评论已删除"}`;错误:`403`、`404`。 ### 6.12 编辑帖子 **PATCH** `{{base_url}}/api/v1/explore/posts/{post_id}` 认证:需要 Bearer token,且只能是帖子作者。 请求体(只提交需要修改的字段): ```json {"content": "更新后的文字", "content_format": "markdown", "feeling": "happy", "location": {"name": "新地点"}} ``` 可编辑字段:`content`(最多 5000 字)、`content_format`(`plain`/`markdown`)、`feeling`(1-50 字符)、`location`。未提交的字段保持不变;提交 `null` 可清空 `feeling` 或 `location`。文字帖子必须保留文字、心情或地点至少一项。成功:`200`,返回更新后的完整 PostResponse。错误:`403` 非作者;`404` 帖子不存在;`422` 字段无效。 ### 6.13 编辑评论 **PATCH** `{{base_url}}/api/v1/explore/comments/{comment_id}` 认证:需要 Bearer token,且只能是评论作者。 请求体: ```json {"content": "更新后的评论"} ``` `content` 必须为 1-2000 字符且不能全是空格。成功:`200`,返回更新后的 CommentResponse。错误:`403` 非作者;`404` 评论不存在;`422` 内容无效。 ### 6.14 给评论点赞 **POST** `{{base_url}}/api/v1/explore/comments/{comment_id}/like` 认证:需要 Bearer token,无请求体。 成功:`200` ```json {"message": "like successful", "like_count": 1, "liked_by_me": true} ``` 重复点赞不会增加数量。错误:`401` 未登录;`404` 评论不存在或帖子作者已停用。 ### 6.15 取消评论点赞 **DELETE** `{{base_url}}/api/v1/explore/comments/{comment_id}/like` 认证:需要 Bearer token,无请求体。 成功:`200` ```json {"message": "unlike successful", "like_count": 0, "liked_by_me": false} ``` 重复请求保持未点赞状态。错误:`401` 未登录;`404` 评论不存在或帖子作者已停用。 ## 7. Feed 问答 ### 7.1 获取 Feed 问题 **GET** `{{base_url}}/api/v1/feed/questions?unanswered_only=false` 认证:需要 Bearer token。 `unanswered_only` 可选,默认 `false`;设为 `true` 只返回当前用户尚未回答的问题。成功:`200`,返回问题数组,每项包含 `id`、`code`、中英文问题、`answer_type`(`boolean` 或 `text`)、当前答案和回答时间。 ### 7.2 获取我的 Feed 回答 **GET** `{{base_url}}/api/v1/feed/answers/me` 认证:需要 Bearer token。 成功:`200`,返回当前用户已回答的问题数组。 ### 7.3 新增或修改 Feed 回答 **PUT** `{{base_url}}/api/v1/feed/questions/{question_id}/answer` 认证:需要 Bearer token。 请求体示例(布尔题): ```json {"answer": true} ``` 文字题: ```json {"answer": "Coffee and a walk"} ``` 成功:`200` ```json {"question_id": 1, "answer": true, "answered_at": "2026-09-01T10:00:00"} ``` 错误:`404` 问题不存在/已停用;`422` 答案类型和题目类型不匹配或内容为空。 ### 7.4 删除 Feed 回答 **DELETE** `{{base_url}}/api/v1/feed/questions/{question_id}/answer` 认证:需要 Bearer token。 成功:`200` `{"message":"回答已删除"}`;错误:`404` 回答不存在。 ## 8. Chat 聊天 聊天仅对已经匹配的双方开放。 ### 8.1 获取会话列表 **GET** `{{base_url}}/api/v1/chat/conversations` 认证:需要 Bearer token。 成功:`200`,返回会话数组,每项包含 `id`、`match_id`、`other_user`、`last_message`、`created_at`、`updated_at`。 ### 8.2 创建或获取会话 **POST** `{{base_url}}/api/v1/chat/conversations/{match_id}` 认证:需要 Bearer token,必须是该匹配的其中一方。 前端发送:无 body。 成功:`201`,返回 ConversationResponse;如果会话已存在,返回已有会话。错误:`404` 匹配不存在、不是匹配双方或对方不可用。 ### 8.3 获取聊天消息 **GET** `{{base_url}}/api/v1/chat/conversations/{conversation_id}/messages?limit=50&before_id=100` 认证:需要 Bearer token,必须是会话双方之一。 参数:`limit` 1-100,默认 50;`before_id` 可选,用于分页。成功:`200`,返回 ChatMessageResponse 数组,按时间正序返回。 ### 8.4 发送聊天消息 **POST** `{{base_url}}/api/v1/chat/conversations/{conversation_id}/messages` 认证:需要 Bearer token,必须是会话双方之一。 请求体: ```json { "content": "Hello, nice to meet you!", "message_type": "text" } ``` `content` 1-5000 字符,`message_type` 目前只能是 `text`。成功:`201`,返回 ChatMessageResponse;错误:`404` 会话不存在或无权访问;`422` 内容为空或格式错误。 ### 8.5 撤回聊天消息 **DELETE** `{{base_url}}/api/v1/chat/messages/{message_id}` 认证:需要 Bearer token,只能撤回自己发送的消息。成功:`200`,返回撤回后的 ChatMessageResponse(`content=null`、`is_deleted=true`);错误:`403` 不是自己的消息;`404` 消息不存在或无权访问。 ## 9. 前端注册和登录流程 1. 注册页面显示邮箱/手机号、密码、确认密码和可选资料。 2. 前端先检查 `password === confirm_password`,然后将两个密码字段一起提交给注册接口。 3. 注册成功后保存返回的 `access_token` 和 `refresh_token`。确认密码不保存。 4. 不调用 OTP 接口;当前版本没有 `/api/v1/auth/request-code` 和 `/api/v1/auth/verify`。 5. App 启动时调用 `/api/v1/auth/me`。返回 `200` 进入首页;返回 `401` 清除 token 并回到登录页。 6. access token 过期时,用 refresh token 调 `/api/v1/auth/refresh`,保存新 token 对;刷新失败则重新登录。 ## 10. Postman 导入和测试 1. 打开 Postman,点击 `Import` -> `Files`。 2. 导入 `docs/openapi-0.6.12.json`,选择导入为 Postman Collection。 3. 在 Collection Variables 中设置:`base_url = http://127.0.0.1:8001`。 4. 先发送 `POST /api/v1/auth/register` 或 `POST /api/v1/auth/login`。 5. 复制响应中的 `access_token`,在需要登录的请求中选择 `Authorization` -> `Bearer Token` 粘贴。 6. 测试文件上传时选择 `Body` -> `form-data`,文件字段名必须使用本文对应的字段名。 建议最小测试顺序:`health` -> `register` -> `login` -> `auth/me` -> `update profile` -> `meet` -> `swipe` -> `matches` -> `explore` -> `feed questions` -> `chat`。 ## 11. 规范文件 完整机器可读接口定义:`docs/openapi-0.6.12.json`。如本文和 OpenAPI 出现不一致,以当前后端 `/openapi.json` 和最新版 OpenAPI 文件为准。