蜜恋后端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

11 KiB

Dating App 后端(FastAPI)

这是 Dating App Function 阶段的 FastAPI 后端实现,默认使用 MySQL。数据库连接通过 DATABASE_URL 配置。

项目文档:

API 0.6.12 为个人资料新增职业、学历、身高、信仰、吸烟、饮酒、宠物、运动习惯 8 个可选字段,编辑资料接口可写入,Get Me 会返回并新增根据生日计算的 age;匹配成功后双方从喜欢/被喜欢名单移除;评论支持回复(parent_comment_id)和点赞/取消点赞。数据库迁移已完成,正式环境已发布。

运行

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 中创建数据库(表会由应用自动创建):

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:

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:

$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 同步接口定义。

数据库表、字段和表关系见:中文设计文档 或 English database design

已实现接口

  • 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。

自动化测试:

python -m pytest -q

生产环境需要替换 JWT_SECRET,关闭 DEV_RETURN_CODES,并设置 OSS_ENABLED=true 及 .env.example 中的 OSS 环境变量。开启后上传文件会保存到对象存储,数据库只保存对象标识。