# Dating App 后端(FastAPI) 这是 Dating App Function 阶段的 FastAPI 后端实现,默认使用 MySQL。数据库连接通过 `DATABASE_URL` 配置。 项目文档: - [完整接口说明](docs/Dating-App-API-完整接口说明.md) - [前端对接清单](docs/Dating-App-API-前端对接清单.md) - [数据库设计](docs/database-design.md) - [Postman 导入说明](docs/Postman导入说明.md) - [OpenAPI 0.6.12](docs/openapi-0.6.12.json) API 0.6.12 为个人资料新增职业、学历、身高、信仰、吸烟、饮酒、宠物、运动习惯 8 个可选字段,编辑资料接口可写入,Get Me 会返回并新增根据生日计算的 age;匹配成功后双方从喜欢/被喜欢名单移除;评论支持回复(parent_comment_id)和点赞/取消点赞。数据库迁移已完成,正式环境已发布。 ## 运行 ```powershell python -m venv .venv .\.venv\Scripts\Activate.ps1 pip install -r requirements.txt $env:DATABASE_URL = "mysql+pymysql://用户名:密码@127.0.0.1:3306/dating_app?charset=utf8mb4" uvicorn app.main:app --reload --port 8001 ``` 启动前先在 MySQL 中创建数据库(表会由应用自动创建): ```sql CREATE DATABASE dating_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ``` 已有数据库升级到 API 0.6.4 时,除既有迁移外还需执行非破坏性迁移 `sql/migrate_relationship_goal.sql`,为 `user_profiles` 增加 `relationship_goal` 字段。 升级到 API 0.6.5 前还需执行 `sql/migrate_super_like.sql`,将已有 `swipes.direction` 的约束扩展为允许 `super_like`。先迁移正式数据库,再发布新代码。 升级到 API 0.6.6 前还需执行 `sql/migrate_location_county.sql`,为 `user_profiles` 增加可空的 `county` 区县字段。位置接口现在要求经纬度、城市、区县一并提交。 升级到 API 0.6.7 前需执行 `sql/migrate_post_composer.sql`,为已有 `posts` 表增加文字格式、心情和地点字段。历史帖子默认为 `plain` 且没有心情、地点。API 0.6.8 的公开主页字段、0.6.9 的头像/点赞名单响应、0.6.10 的编辑接口与混合媒体、0.6.11 的匹配列表均不涉及数据库迁移。升级到 0.6.12 前需依次执行 `sql/migrate_profile_details.sql`(user_profiles 增加 8 个可空资料字段)和 `sql/migrate_comment_interactions.sql`(post_comments 增加 parent_comment_id,新增 comment_likes 表)。 如果暂时没有 MySQL,可临时设置 `DATABASE_URL=sqlite:///./dating_app.db` 做本地测试;正式环境按项目方案使用 MySQL。 Windows 本地启动云 MySQL + 阿里云 OSS 时,可运行 `.\start_cloud_api.ps1`。脚本会在启动时安全询问数据库密码、OSS 凭据和 JWT Secret;这些值只存在于当前 API 进程环境中,不会写入项目文件。正式服务器部署时,应使用服务器的环境变量或密钥管理服务提供同样的配置。 ## Docker 部署 项目根目录的 `Dockerfile` 用于生产容器,容器内 FastAPI 固定监听 `8001`。以下示例将宿主机端口 `8011` 映射到容器端口 `8001`: ```bash docker build -t dating-app-api:0.6.12 . docker rm -f dating-app-api 2>/dev/null || true docker run -d \ --name dating-app-api \ --restart unless-stopped \ -p 8011:8001 \ --env-file "${HOME}/.secrets/dating-app.env" \ dating-app-api:0.6.12 ``` `${HOME}/.secrets/dating-app.env` 由服务器管理员维护,至少需要提供正式 `DATABASE_URL`、生产 `JWT_SECRET`、`OSS_ENABLED=true` 以及 OSS 配置。这个文件不应提交到 Git 或放入 Jenkins 工作区。当前 Jenkins 已通过只读 Deploy Key 拉取 Gitee 仓库。 ## 日常改代码和发布 正式公网地址为 `https://melove.youthome.com.cn`,业务接口统一使用 `/api/v1/...`。当前 Jenkins Job `1` 从 Gitee `main` 分支拉取代码,构建镜像并以 `8011:8001` 启动 `dating-app-api` 容器。Jenkins 运行账户读取的正式环境文件为 `${HOME}/.secrets/dating-app.env`,其中包含数据库、JWT 和 OSS 配置;不要把这些值写入 Git、Jenkins Shell、提交信息或文档。 每次发布按以下顺序执行: 1. 本地修改代码,运行 `python -m pytest -q`。 2. 接口变化同步更新最新 OpenAPI 文件和对接文档。 3. 数据库模型变化新增幂等 SQL 迁移,并先在正式 MySQL 执行迁移;Docker 重建不会自动修改已有表。 4. 提交并推送 Gitee `main`,在 Jenkins Job `1` 点击“立即构建”。 5. 检查代码拉取、Docker 构建、数据库预检、容器健康检查和控制台日志。 6. 使用 `https://melove.youthome.com.cn/api/v1/...` 做公网烟测,重点复测本次改动涉及的接口。 只修改 Python、schema 或业务逻辑时,推送代码并重新构建即可;修改 `requirements.txt` 或 `Dockerfile` 后还要检查镜像构建和容器启动日志。发布失败时先查看 Jenkins 控制台日志与容器日志,区分数据库网络、认证、表结构和应用错误,再决定是否回滚或补迁移。 本地 Windows Docker Desktop 也可以直接使用 Compose 启动一个隔离实例。默认使用 Docker 命名卷中的 SQLite 和本地文件存储,不会接触正式云数据库或 OSS: ```powershell $docker = "D:\Docker\DockerDesktop\resources\bin\docker.exe" & $docker compose -p dating-app up -d --build ``` 本地实例地址为 `http://127.0.0.1:8011`。需要连接正式云 MySQL/OSS 时,通过环境变量覆盖 `docker-compose.yml` 中的默认值,不要把真实凭据写进该文件。 打开 `http://127.0.0.1:8001/docs` 查看接口文档。 Postman 或 Apifox 可导入最新的 [`docs/openapi-0.6.12.json`](docs/openapi-0.6.12.json) 同步接口定义。 数据库表、字段和表关系见:[中文设计文档](docs/database-design.md) 或 [English database design](docs/database-design-en.md) ## 已实现接口 - `POST /api/v1/auth/register`:使用统一的 `email_or_phone` 字段、密码、确认密码和必填的四选一 `relationship_goal` 注册,可直接提交非空 `bio`,成功后返回 token,不需要验证码 - `POST /api/v1/auth/login`:使用统一的 `email_or_phone` 字段和密码登录 - `POST /api/v1/auth/refresh`:使用 refresh token 换取新的 access/refresh token - `POST /api/v1/auth/logout`:撤销 refresh session - `GET /api/v1/auth/me`:应用启动时验证 access token,并返回当前用户、本人帖子、我喜欢的人、喜欢我的人和匹配对象(各最近 20 条) - `POST /api/v1/auth/oauth`:微信/谷歌账号登录或注册占位接口 - `GET/PATCH /api/v1/users/me`:读取和更新个人资料 - `GET /api/v1/users/me/interests`:读取当前用户的全部兴趣 - `PUT /api/v1/users/me/interests`:替换当前用户的兴趣列表,至少 2 个,不设上限 - `POST /api/v1/users/me/video`:上传或替换自我介绍视频,最大 100MB;每名用户只保留最新一份 - `POST /api/v1/users/me/image`:上传或替换个人头像;每名用户只保留最新一份 - `POST /api/v1/users/me/identity`:上传身份证/护照,最大 10MB - `PUT /api/v1/users/me/location`:更新当前位置 - 位置请求需同时提供 `latitude`、`longitude`、`city`、`county`;城市用于同城推荐,区县返回在个人和公开资料中 - `GET /api/v1/users/me/posts`:分页查看本人帖子 - `GET /api/v1/users/{user_id}`、`GET /api/v1/users/{user_id}/posts`:查看公开用户资料和帖子 - `GET /api/v1/users/me/liked`、`GET /api/v1/users/me/likes`:查看完整的我喜欢的人和喜欢我的人名单,不再分页 - `GET /api/v1/users/me/matches`:分页查看匹配对象 - `GET /api/v1/meet`:获取尚未滑过的候选用户;向当前用户发出 Super Like 的用户最优先,其余按同城、同国家和匹配度排序 - `POST /api/v1/meet/swipes`:`pass` 左滑、`like` 右滑、`super_like` 超级喜欢;双方互相喜欢(含 Super Like)时自动匹配 - `DELETE /api/v1/meet/swipes/{target_user_id}`:取消键,撤销保存的左滑、右滑或 Super Like,让该用户重新进入推荐列表 - `DELETE /api/v1/meet/likes/{target_user_id}`:取消喜欢并解除对应匹配 - `GET /api/v1/matches`:查看完整匹配列表(不分页,旧 `limit`、`offset` 参数会被忽略) - `GET /api/v1/search`:按姓名、简介、城市、国家和距离搜索用户,支持城市/国家组合筛选 - `POST /api/v1/explore/posts`:发布文字/图片/视频类型帖子,保存可选心情、地点和 `plain`/`markdown` 文字格式;图片/视频先创建帖子再上传媒体,音乐暂不支持 - `GET /api/v1/explore/feed`:按同城、同国家和匹配度优先获取 Explore 信息流 - `GET/PATCH/DELETE /api/v1/explore/posts/{post_id}`:查看、编辑或删除自己的帖子 - `GET/POST/DELETE /api/v1/explore/posts/{post_id}/like`:查询点赞者名单、点赞或取消点赞 - `GET/POST /api/v1/explore/posts/{post_id}/comments`:查看或发表评论,POST 传 parent_comment_id 可回复;`PATCH /api/v1/explore/comments/{comment_id}`:编辑自己的评论;`POST/DELETE /api/v1/explore/comments/{comment_id}/like`:点赞或取消点赞评论 - `DELETE /api/v1/explore/comments/{comment_id}`:删除自己的评论 - `POST /api/v1/explore/posts/{post_id}/media`:为帖子上传图片或短视频,同一条帖子最多 9 张图片加 1 个视频,可混合 - `GET/DELETE /api/v1/explore/media/{media_id}`:读取或删除帖子媒体 - `GET /api/v1/chat/conversations`:查看已匹配用户的会话列表 - `POST /api/v1/chat/conversations/{match_id}`:为匹配关系创建或获取会话 - `GET/POST /api/v1/chat/conversations/{conversation_id}/messages`:查看或发送聊天消息 - `DELETE /api/v1/chat/messages/{message_id}`:撤回自己的消息 - `GET /api/v1/feed/questions`:获取 AI Feed 问题,可筛选尚未回答的问题 - `PUT/DELETE /api/v1/feed/questions/{question_id}/answer`:提交、修改或删除回答 - `GET /api/v1/feed/answers/me`:查看当前用户的全部回答 ## 接口测试 Swagger:启动服务后打开 `http://127.0.0.1:8001/docs`。 FastAPI 自带的 Swagger UI 和 Postman 都可以完成当前接口的手动调试。MVP 阶段不使用 OTP。 注册介绍内容采用两步流程:用户选择文字简介时,在注册 JSON 中提交非空 `bio`;用户选择视频时,注册后使用 access token 调用视频上传接口。`GET /api/v1/auth/me` 的 `profile.profile_image_url` 和 `profile.video_url` 在对应媒体未上传时为 `null`,生产环境上传后返回一小时有效的完整 OSS 签名 URL,前端可直接加载而无需再次携带 Token。文字简介与视频互斥:上传视频会清空 `bio`,之后提交非空 `bio` 会删除介绍视频。前端只有在 `bio` 或 `video_url` 其中一个非空时才应完成注册引导。 认证说明:access token 默认有效 15 分钟,refresh token 默认有效 30 天。客户端安全保存两个 token;应用启动时调用 `/api/v1/auth/me`,返回 200 就进入首页,否则回到登录页。refresh token 只以哈希形式保存到 `user_sessions` 表,logout 会撤销对应 session。 自动化测试: ```powershell python -m pytest -q ``` 生产环境需要替换 `JWT_SECRET`,关闭 `DEV_RETURN_CODES`,并设置 `OSS_ENABLED=true` 及 `.env.example` 中的 OSS 环境变量。开启后上传文件会保存到对象存储,数据库只保存对象标识。