# Dating App 后端项目交接总览 > 这份文档是给后续接手本项目的开发者或模型使用的工作记录。每次老板提出新要求、代码完成新功能或数据库发生变更,都要同步更新本文件。 ## 1. 项目基本信息 - 项目:Dating App Function 阶段后端 - 技术:FastAPI、SQLAlchemy 2、MySQL 8、JWT - 工作目录:`E:\homework\工作` - 正式数据库:MySQL `dating_app` - 本地数据库连接:`127.0.0.1:3306` - 当前代码和正式环境 API 版本:`0.6.12` - 最近成功发布:2026-10-21 Jenkins `#46` - 最新 OpenAPI 文件:`docs/openapi-0.6.12.json` - Postman 说明:`docs/Postman导入说明.md` - 自动化测试命令:`python -m pytest -q` 当前代码曾使用过 `8000` 端口的旧服务。新版服务测试地址是 `http://127.0.0.1:8001`,打开 `http://127.0.0.1:8001/docs` 可以查看 Swagger。不要把旧的临时外网地址当成当前可用地址;`localhost` 只能由本机访问。 ## 2. 老板已确认的核心要求 ### 已确认并已实现 1. MVP 阶段不使用一次性密码 OTP。 2. 邮箱和手机号不再是两个输入项,统一为一个输入字段:`email_or_phone`。 3. 邮箱或手机号存储在同一个数据库字段:`users.email_or_phone`。 4. 注册成功后账号立即激活,不需要再请求验证码或验证验证码。 5. 注册接口只返回 token,不返回完整用户 JSON。 6. 注册和登录字段、异常情况需要重新检查,并补充单元/接口测试。 7. 注册页面需要邮箱或手机号、密码和确认密码;后端也必须校验两次密码一致。 8. 每周日下午 5 点前通过微信向老板提交周工作总结(形式不限),内容包含本周开展的工作、发现或解决的问题、对项目或产品的思考以及下周工作安排。 ### 图片中刚提出、已实现的要求 老板最新图片表达的是:用户选择兴趣选项后,点击 `Other` 可以增加额外兴趣,最多添加 1、2、3、4 个。后续用户明确要求不限制最多数量。 后端现在支持这个功能。兴趣独立保存,数量不设上限;提交时至少需要 2 个。现有的 `bio` 和 Feed 问答不代替兴趣功能。 已完成内容: - 用户兴趣关联表 `user_interests`; - `Other` 自定义兴趣保存; - 至少 2 个兴趣校验,不限制最多数量; - 获取和替换当前用户兴趣的接口; - 注册和个人资料响应返回兴趣列表。 建议的请求数据形式: ```json { "interests": [ "Photography", "Dogs", "我的自定义兴趣" ] } ``` 目前兴趣功能已完成代码、数据库迁移和自动化测试;预设兴趣选项由客户端展示,后端允许任意文本,包含 `Other` 自定义值。 ### 2026-10-10 线上测试账号与功能验收要求 - 对方要求创建 20 个新用户,测试喜欢/跳过、帖子及互动、聊天等接口,并提供一个可登录的测试账号。 - 用户明确限定只清理能识别的旧测试账号;由于没有旧账号清单,不能删除正式环境现有用户。本次创建的 20 个 QA 账号保留作前端联调。 - 登录接口使用 `email_or_phone` 和密码,数字用户 ID 用于用户资料、滑动等路径参数,不能代替登录账号。 ### 2026-10-14 帖子/评论作者头像与点赞名单要求 - 用户授权按前端两张截图直接更新功能:评论列表作者有头像,Explore/帖子作者有头像,帖子显示点赞者 ID 和姓名。 - 对方最后补充希望点赞的同一个接口返回点赞者 ID/姓名,因此 POST 点赞改为成功信息、数量、本人状态和简短名单,不再返回完整帖子正文/媒体。 - 本轮未要求发布,交付本地 API 0.6.9 及文档,正式版本仍以最后确认的 0.6.8 为准。 ## 3. 按时间记录的已完成工作 ### 2026-09-03:临时公网地址尝试 - 本地 API 已用独立 SQLite 演示数据库启动在 `http://127.0.0.1:8001`,未修改正式 MySQL 数据。 - Cloudflare Quick Tunnel 能生成临时域名,但当前网络无法解析 `argotunnel.com` 的边缘 SRV 记录,外部访问返回 `530`,因此生成的域名不可交付。 - `localtunnel` 在当前网络环境也未能建立连接。 - 当前没有可用公网 `base_url`;恢复 DNS/网络后可运行 `cloudflared tunnel --url http://127.0.0.1:8001`,并用 `/health` 返回 `{"status":"ok"}` 验证后再交给前端。 - 本次临时演示启动脚本为 `start_temp_api_v060.py`,仅用于本地 SQLite 演示,不应作为正式部署配置。 ### 第一天:注册、登录和基础资料 - 完成邮箱/手机号注册、密码登录。 - 密码使用哈希保存,不保存明文密码。 - 完成 access token、refresh token、刷新和退出登录。 - 完成 `/api/v1/auth/me` 启动时检查登录状态。 - 完成基础资料:姓名、性别、生日、城市、简介。 - 完成头像、介绍视频、身份证/护照上传。 - 完成 MySQL 基础表和外键关系。 ### 第二天:Meet、滑动匹配和搜索 - 获取还没有滑过的候选用户。 - 左滑跳过、右滑喜欢。 - 双方互相喜欢时自动匹配。 - 取消喜欢时删除对应匹配。 - 按姓名、简介、城市和距离搜索。 - 保存用户位置并计算附近距离。 - 保护身份证/护照文件,不在公开候选资料中暴露。 ### 第三天:Explore 和 Chat - 文字/图片/视频类型帖子。 - Explore 信息流、帖子详情、删除自己的帖子。 - 帖子点赞、取消点赞、防止重复点赞。 - 评论新增、列表和删除自己的评论。 - 一对一聊天会话,只有匹配双方可以访问。 - 发送文字、分页读取消息、撤回自己的消息。 ### 第四天:帖子媒体和 AI Feed 问答 - 帖子图片和短视频上传、下载、删除。 - 支持 JPG、PNG、WebP、MP4、MOV、WebM。 - 每个帖子最多 9 张图片或 1 个视频,不能混用。 - 五个默认双语 Feed 偏好问题。 - 支持布尔和文本回答。 - 支持回答新增、修改、查看、筛选未回答和删除。 ### 最近一次认证改动:MVP 0.4.0 - 删除应用中的 `/api/v1/auth/request-code` 和 `/api/v1/auth/verify` 路由。 - `RegisterRequest` 和 `LoginRequest` 都使用 `email_or_phone`。 - 邮箱自动转小写,手机号/其他账号会去除首尾空格。 - 注册用户状态直接为 `active`。 - 注册响应只有:`access_token`、`refresh_token`、`token_type`。 - `UserResponse` 使用 `email_or_phone`,不再返回 `email`、`phone`、验证状态字段。 - MySQL 迁移脚本:`sql/migrate_auth_mvp_no_otp.sql`。 - 数据库旧的邮箱、手机号、验证字段和 `verification_codes` 表没有删除,以避免破坏历史数据;新代码不再使用它们。 ### 最新兴趣功能:API 0.5.0 - 新增 `user_interests` 表,一名用户可以拥有任意数量的兴趣。 - 注册请求可以直接携带 `interests`,个人资料响应会返回兴趣列表。 - `GET /api/v1/users/me/interests` 获取兴趣。 - `PUT /api/v1/users/me/interests` 整体替换兴趣列表。 - 每次提交至少 2 个兴趣,不设置最多 4 个的限制。 - 兴趣会去除首尾空格并按不区分大小写的方式去重;空值会被拒绝。 - `Other` 不需要单独的数据库字段,客户端把自定义文本作为普通兴趣项提交。 - 数据库迁移脚本:`sql/migrate_user_interests.sql`。 ### 注册确认密码:API 0.5.1 - `RegisterRequest` 新增必填字段 `confirm_password`。 - 后端注册时校验 `password == confirm_password`,缺失或不一致返回 `422`。 - `confirm_password` 只用于校验,不保存到数据库,也不会出现在任何响应中。 - OpenAPI 文件更新为 `docs/openapi-0.5.1.json`。 ### 2026-09-01:注册接口共享文档交付 - 根据老板要求,将注册部分单独整理成简洁的前后端对接说明,不再把全部接口一次性放入共享文档。 - 注册接口文档:`docs/注册接口-共享文档内容.md`。 - 文档只保留注册 URL、前端发送的 JSON、后端返回的 token、参数规则和错误示例。 - 注册 URL:`POST {{base_url}}/api/v1/auth/register`。 - 前端必须发送 `email_or_phone`、`password`、`confirm_password`;邮箱或手机号使用同一个字段。 - 后端成功返回 `201`,只返回 `access_token`、`refresh_token`、`token_type`,不返回完整用户 JSON。 - 已记录 `422`(缺少字段、确认密码不一致、空账号)和 `409`(账号已注册)示例。 - 文档使用 `{{base_url}}` 占位符;本地测试地址为 `http://127.0.0.1:8001`,部署后只需替换 Base URL。 - 本次注册相关自动化测试结果:`3 passed, 10 deselected`。 - 本次只对注册相关输入输出进行了实际测试;其他接口以完整 OpenAPI 和已有测试记录为准,不宣称全部接口逐条实测。 ### 2026-09-01:同城、同国家和匹配度排序(API 0.6.0) - 根据共享 PDF 的蓝色修改,为用户资料新增可选字段 `country`。 - `GET /api/v1/meet` 按同城、同国家、其他国家分组,同组内按匹配百分比从高到低返回。 - `GET /api/v1/search` 新增独立的 `city`、`country` 查询参数,可单独使用或组合使用;文本搜索 `q` 也会搜索国家。 - `GET /api/v1/explore/feed` 使用同样的位置和匹配度优先顺序,最后以新帖优先打破并列。 - 新排序使用 `offset` 分页;旧 `before_id` 保留为按时间 ID 截断的兼容模式,不能和非零 `offset` 同时使用。 - `DiscoveryUserResponse` 和 Explore 作者响应新增 `country`、`compatibility_percentage`。 - 匹配度由共同兴趣的 Jaccard 相似度与双方共同回答的 Feed 问题答案一致率计算;只有一种可比较数据时使用该项,两种都有时取平均,没有数据时返回 0。 - PDF 把头像和介绍视频写进注册 JSON,这在二进制上传上不可用;已在精简共享文档中修正为注册成功后分别调用 `/api/v1/users/me/image` 和 `/api/v1/users/me/video`。 - 非破坏性 MySQL 迁移:`sql/migrate_country_and_matching.sql`。 - 用户已于 2026-09-01 确认在正式 MySQL `dating_app` 执行 `sql/migrate_country_and_matching.sql`。当前环境此前通过命令行连接时返回 `1045 Access denied`,因此本次执行结果来自用户确认;后续获得可用的 `DATABASE_URL` 后仍应通过 `DESCRIBE user_profiles` 和 `SHOW INDEX FROM user_profiles` 复核。 - 精简共享内容:`docs/注册接口-共享文档内容.md`,只保留 URL、Frontend sends、Backend returns。 - 安全要求核查:`docs/security-requirements-review-2026-09-01.md`。JWT、短 access token、refresh 轮换、密码哈希已实现;生产 HTTPS、AES-256-GCM 混合加密和密钥管理尚未实现,不能对外宣称已完成。 ## 4. 当前主要接口 ### 认证 - `POST /api/v1/auth/register`:统一账号、密码和确认密码注册,直接返回 token。 - `POST /api/v1/auth/login`:统一账号密码登录。 - `POST /api/v1/auth/refresh`:刷新并轮换 token。 - `POST /api/v1/auth/logout`:撤销 refresh session。 - `GET /api/v1/auth/me`:获取当前用户。 - `POST /api/v1/auth/oauth`:微信/谷歌登录绑定占位接口。 本次注册共享文档:`docs/注册接口-共享文档内容.md`。 ### 用户、Meet 和搜索 - `GET/PATCH /api/v1/users/me` - `GET /api/v1/users/me/interests` - `PUT /api/v1/users/me/interests` - `PUT /api/v1/users/me/location` - `POST /api/v1/users/me/image` - `POST /api/v1/users/me/video` - `POST /api/v1/users/me/identity` - `GET /api/v1/meet` - `POST /api/v1/meet/swipes`:`pass`、`like`、`super_like` - `DELETE /api/v1/meet/swipes/{target_user_id}`:取消键,撤销三种滑动 - `DELETE /api/v1/meet/likes/{target_user_id}`:兼容旧客户端的取消喜欢 - `GET /api/v1/matches` - `GET /api/v1/search` ### Explore、Chat 和 Feed - `/api/v1/explore/posts`、`/api/v1/explore/feed`、帖子媒体、点赞和评论接口。帖子/评论的 `author.profile_image_url` 表示作者头像;完整帖子含 `liked_by_users` 简短名单。 - `GET /api/v1/explore/posts/{post_id}/like` 返回点赞者 ID/姓名数组;POST 同路径返回 `PostLikeResponse` 精简结果,DELETE 同路径继续返回完整 `PostResponse`。 - `/api/v1/chat/conversations`、消息发送、分页和撤回接口。 - `/api/v1/feed/questions`、回答新增/修改/删除、我的回答接口。 0.6.9 参数和响应以 `docs/openapi-0.6.9.json` 为准;正式环境已发布并验证。 ## 5. 数据库现状 核心表包括: - `users` - `user_profiles` - `user_interests` - `user_locations` - `user_sessions` - `auth_identities` - `user_media` - `swipes` - `matches` - `posts` - `post_media` - `post_likes` - `post_comments` - `conversations` - `chat_messages` - `feed_questions` - `user_question_answers` 当前 `users` 新字段为: ```text email_or_phone VARCHAR(320) UNIQUE ``` 当前 `user_profiles` 新增字段为: ```text country VARCHAR(120) NULL ``` 认证迁移文件:`sql/migrate_auth_mvp_no_otp.sql`。国家字段迁移文件:`sql/migrate_country_and_matching.sql`。迁移均为非破坏性,不主动删除历史数据。 ## 6. 测试和交付状态 最后一次完整自动化测试结果(本地 API 0.6.12,2026-10-21): ```text 26 passed ``` 测试覆盖注册、登录、邮箱大小写、手机号登录、错误密码、参数校验、OTP 路由不存在、token 刷新、退出、个人资料、Meet、搜索、匹配、媒体、Explore、Chat 和 Feed 问答。 以下为早期真实 MySQL 联调记录,版本号不代表当前正式环境: - 注册返回的 key 只有 `access_token`、`refresh_token`、`token_type`; - 注册账号状态为 `active`; - 邮箱大小写不同仍能登录; - `/health` 返回 `{"status":"ok"}`; - OpenAPI 版本为 `0.6.0`,包含 `confirm_password`、`country`、城市/国家搜索和匹配度响应,不包含 OTP 两个路径。 2026-10-10 正式环境人工接口验收:新建 20 个合成 QA 账号(ID `54`–`73`),20 个账号均可登录、公开资料均可读取。使用这些账号完成 51 项检查,覆盖个人资料、兴趣、位置、头像上传和读取、Meet 和搜索、pass/like/super_like 及撤销、双向喜欢/匹配和取消、活动总数、文字/图片帖子和媒体读取、Explore 和公开帖子列表、点赞/取消点赞、评论新增/删除、聊天创建/发送/撤回、Feed 问答新增/删除、token 刷新和退出。保留 1 组匹配、示例帖子及聊天供联调;临时创建的匹配、帖子、评论、媒体和问答已按测试步骤清理。未测试介绍视频的真实播放、证件上传、OAuth 登录或全部 20 人互相操作,不能据此宣称所有接口均已实测。 ## 7. 后续模型接手流程 每次收到新需求时按以下顺序处理: 1. 先读取本文件、`README.md`、相关设计文档和最新 OpenAPI 文件。 2. 明确新需求属于“已完成功能调整”还是“全新待开发功能”。 3. 检查现有模型、schema、路由、SQL 和测试,避免重复造接口。 4. 修改代码后补对应测试。 5. 运行 `python -m pytest -q`。 6. 如果改了接口,重新生成最新的 OpenAPI 文件或升级版本号。 7. 如果改了数据库,新增非破坏性迁移脚本,并记录执行结果。 8. 更新本文件的“老板要求”“已完成工作”“当前接口”“测试和交付状态”。 9. 对照共享的 `Dating APP api` 文档(以用户提供的最新 PDF 或 Google 文档版本为准),整理本次新增或改变的接口说明,明确插入位置和可直接粘贴的内容;用户确认已写过的部分不要重复提供。 10. 用中文向用户说明:完成了什么、还缺什么、Postman 如何测试,以及共享文档这次需要补充什么。 固定交付规则:任何代码、接口、数据库、测试结果或对接文档更新,都必须在同一次任务中同步更新本文件,不能留到后续补记。 对外沟通语言规则:用户看不懂英文。凡是拟回复外国同事的聊天消息,先用中文向用户解释对方说了什么,并把建议回复完整写成中文供用户审阅;用户没有明确要求英文版时,不直接给英文回复,也不声称已经替用户发送。共享 API 文档如需按原格式提供英文接口内容,应另附中文说明,不能用英文对外回复代替中文解释。 共享文档维护规则:`Dating APP api` 是与对方协作的接口文档。以后每次新增或修改接口、请求/响应字段、调用顺序、约束或上线状态,都要在交付时核对它,并按原文的 `URL`、`Authentication`、`Request`、`Backend Response` 等格式提供准确的英文补充内容和具体插入位置。以当前后端代码及最新 OpenAPI 为事实依据;本地 PDF 只是导出时的快照,不能据此断言在线 Google 文档尚未更新。未实际编辑在线文档时,明确说明内容需由用户粘贴,不得声称已同步。若用户已贴入同样内容,只报告无需重复更新。 ### 2026-09-02:公网上线尝试 - 今日目标:将注册接口通过公网 HTTPS 地址提供给前端同事测试。 - 启动前检查确认项目需要从环境变量读取正式 `DATABASE_URL`;仓库内只有 `.env.example` 占位配置,不保存生产密码。 - 使用用户提供的远程 MySQL 账号进行连接验证时,服务器返回 `1045 Access denied`,并识别来源 IP 为 `223.166.86.200`。 - 因正式 MySQL 尚未通过连接验证,今天暂未启动对外服务,也未使用 SQLite 代替正式数据库创建公网链接。 - 继续上线前置条件:确认 `dating` 账号密码正确,并在 MySQL 授权中允许来自 `223.166.86.200` 的连接;连接成功后再启动 `uvicorn`(8001)和 Cloudflare Tunnel,并用公网 `/health`、`/api/v1/auth/register` 实测。 ### 2026-09-02:临时 Cloudflare 地址已建立 - 因用户没有正式公网部署权限,已按要求使用 Cloudflare Quick Tunnel 做当天联调。 - 本地服务运行在 `127.0.0.1:8001`,临时公网 Base URL:`https://medications-will-vast-permissions.trycloudflare.com`。 - 已验证 `GET /health` 返回 `200` 和 `{"status":"ok"}`。 - 已验证 `POST /api/v1/auth/register` 通过公网返回 `201`,token-only 响应正常。 - 本次临时服务使用独立 SQLite 演示数据库 `dating_app_online_demo.db`,不连接正式 MySQL,也不代表生产环境数据;正式 MySQL 连接恢复后必须重启服务并改回正式 `DATABASE_URL`。 - Cloudflare Tunnel 和后端进程必须保持运行;任一进程停止,临时地址就会失效。Quick Tunnel 地址也可能在下次启动时变化。 ### 2026-09-02:阿里云 OSS 媒体存储接入 - 新增可切换的存储层:`OSS_ENABLED=false` 时继续使用本地 `UPLOAD_DIR`,方便自动化测试;设置为 `true` 后,用户头像、介绍视频和 Explore 帖子媒体会上传到阿里云 OSS。 - OSS 配置全部通过环境变量提供:`OSS_ENDPOINT`、`OSS_ACCESS_KEY_ID`、`OSS_ACCESS_KEY_SECRET`、`OSS_BUCKET_NAME`、`OSS_BASE_PREFIX`、`OSS_DOMAIN`。示例配置已补充到 `.env.example`,没有保存真实密钥。 - 当前部署参数约定:上海 Endpoint、Bucket `bs-qinghe`、对象前缀 `melove/`、自定义域名 `https://oss.baskbuddy.com`。Endpoint 会强制使用 HTTPS。 - 数据库的 `user_media.storage_path` 和 `post_media.storage_path` 现在可保存 `oss://melove/...` 对象标识;数据库仍只保存元数据,不保存视频二进制内容。 - OSS 模式下读取接口返回 1 小时有效的签名下载地址;身份证/护照仍按原有权限校验,不公开对象地址。删除用户或帖子媒体时会同步删除 OSS 对象。 - 已安装 `oss2==2.18.6`。使用提供的临时凭据完成桶访问以及 `melove/` 前缀下临时对象的上传、读取、删除验证,测试对象已清理。 - 生产启动前必须在服务器环境变量中设置真实 OSS 凭据,不能把密钥写入 Git、文档、Postman 或聊天记录;本次截图中的密钥也应在阿里云控制台轮换。 ### 2026-09-04:根据新版共享 PDF 的核查结果 - 已阅读 `Dating APP api (2).pdf`。PDF 的注册流程要求仍是:先调用 JSON 注册接口,成功取得 Bearer access token 后,再分别以 `multipart/form-data` 调用头像和介绍视频上传接口;不能把二进制文件直接放进注册 JSON。 - PDF 中的接口路径与当前 API 0.6.0/OpenAPI 一致:`POST /api/v1/auth/register`、`POST /api/v1/users/me/image`、`POST /api/v1/users/me/video`;OpenAPI 中两个上传接口均声明了 `multipart/form-data` 和 Bearer 安全要求,且没有旧 OTP 路由。 - 在本机执行完整自动化测试,结果为 `14 passed`。 - PDF 给出的临时地址 `https://counters-translate-ferry-sherman.trycloudflare.com` 于本次核验时 DNS 无法解析;旧地址也不可用。因此当前不能把该地址作为 Postman 的可用 `base_url`,需要重新建立并验证公网部署后才能填写共享文档。 - 当前代码仍未实现生产 HTTPS 部署、AES-256-GCM payload 加密、混合加密及生产密钥管理;这些安全要求不能据此宣称已经完成。 - 今日后续顺序:确认正式 MySQL 可连接;确认服务启用了正确的 OSS 环境变量;重新建立公网 HTTPS;依次实测 `/health`、注册、头像上传和视频上传;通过后再更新共享接口文档并让前端导入 `openapi-0.6.0.json`。 - 本次核验发现本机 MySQL `3306` 正在监听,但当前配置使用的 `root`/`password` 被拒绝(MySQL `1045 Access denied`);终端也没有设置 `DATABASE_URL`、`JWT_SECRET` 或 OSS 环境变量,不能据此启动正式服务。 - 为验证接口实现,已启动隔离的 `dating_app_temp_v060.db` SQLite 服务并完成烟测:`/health` 为 `200`,OpenAPI 版本为 `0.6.0`,注册为 `201` 且只返回 `access_token`、`refresh_token`、`token_type`,头像上传和视频上传均为 `200`。该结果只代表本地演示服务,不代表正式 MySQL、OSS 或公网部署已通过。 - 继续公网联调前需要在服务器/本机环境中配置可用的正式 `DATABASE_URL`、生产 `JWT_SECRET`,以及 `OSS_ENABLED=true` 所需的 OSS 参数,并确认 MySQL 授权允许当前来源;不要把密码、AccessKey 或私钥发送到聊天或提交到文档/Git。 ### 2026-09-04:正式数据库、OSS 与长期地址核验 - 使用用户提供的远程 MySQL 参数进行连接测试:`47.116.134.234:3306` 网络端口可达,但账号 `dating` 返回 MySQL `1045 Access denied`。当前无法确认数据库名、表结构或执行 API 联调;需要在服务器端确认密码/账号,并授权当前来源 IP `223.166.86.200`(或使用安全的服务器内网部署方式)。 - 使用用户提供的 OSS 参数访问 `bs-qinghe`:服务端返回 `InvalidAccessKeyId`(403),当前 AccessKey 不可用。需要在阿里云 RAM/OSS 控制台确认账号状态、重新生成最小权限 AccessKey,并在服务环境变量中配置;截图中的 AccessKey 已暴露,建议立即停用并轮换。 - 长期公网地址核验:`47.116.134.234` 的 80/443/22 端口可达,现有 HTTPS 内容是 bashBuddy Gitea,不是 Dating App API;`gitea.baskbuddy.com` 和 `www.baskbuddy.com` 已指向该服务器,`api.baskbuddy.com` 尚无 DNS 记录。 - 推荐长期部署方案:增加 DNS `api.baskbuddy.com` 的 A 记录指向 `47.116.134.234`,在该服务器 nginx 新增 API 虚拟主机并反向代理到 FastAPI(例如 `127.0.0.1:8001`),使用 Let's Encrypt 或云厂商证书配置 TLS。此步骤需要域名 DNS 管理权限和服务器 SSH/root 或 nginx 管理权限,不能仅在本地项目目录完成。 - 本轮没有修改远程数据库、OSS、DNS 或服务器配置,也没有把任何真实凭据写入文件;目前仍不能交付正式公网 `base_url`。 ### 2026-09-04:共享接口补充和当日临时公网测试 - 新增 `docs/向老板索要的部署权限与当前缺项.md`,集中记录已经掌握的部署信息、实际缺少的授权、长期部署条件和可发给老板的技术依据;文档不包含任何密码或 AccessKey Secret。 - 新增 `docs/Explore-NewsFeed-共享接口内容.md`,按共享 PDF 的 `URL`、`Frontend sends`、`Backend returns` 格式整理 Meet、城市/国家搜索和 Explore Feed,可直接复制到共享文档。 - 当日临时公网 Base URL:`https://racks-chips-frequently-und.trycloudflare.com`。已验证 `/health` 为 `200`、OpenAPI 版本为 `0.6.0`、注册为 `201`、头像上传为 `200`、视频上传为 `200`。 - 已通过公网实际验证 Explore/NewsFeed:Meet 返回同城用户后再返回同国家用户,并包含匹配度;`city=Shanghai&country=China` 组合搜索仅返回符合条件的用户;Explore Feed 返回作者的 `city`、`country` 和 `compatibility_percentage`。测试示例中同城匹配度为 `100`,同国家匹配度为 `33`。 - 本次临时服务仍使用隔离 SQLite 数据库 `dating_app_temp_v060.db` 和本地上传目录,不连接正式 MySQL,也未启用 OSS。Cloudflare Quick Tunnel 和本地 FastAPI 进程停止后该 URL 即失效,不能当作长期部署地址。 ### 2026-09-07:公司 OSS 与云 MySQL 连接核验 - 根据老板提供的 OSS 配置,当前项目已有的 `app/storage.py` 可以直接使用阿里云 OSS;Endpoint 会强制使用 HTTPS,Bucket 为 `bs-qinghe`,对象前缀使用 `melove/`。图中原始 `qinghe/` 前缀不应继续使用,当前代码默认值已经是 `melove/`。 - 未将 AccessKey 或 Secret 写入代码、`.env`、Git 或本交接文档;运行时必须通过服务器环境变量注入 `OSS_ENABLED=true`、`OSS_ENDPOINT`、`OSS_ACCESS_KEY_ID`、`OSS_ACCESS_KEY_SECRET`、`OSS_BUCKET_NAME`、`OSS_BASE_PREFIX` 和 `OSS_DOMAIN`。 - 使用老板提供的当前 OSS 凭据做了最小权限连接核验:`melove/` 前缀下临时对象写入返回 `200`、读取返回 `200`、删除返回 `204`,临时对象已立即清理。说明当前 OSS 凭据具备应用所需的基本读写删除权限。 - 云 MySQL `47.116.134.234:3306` 端口可达,但 `dating` 账号从当前来源 IP `223.166.86.200` 登录 `dating_app` 返回 `1045 Access denied`。尚未执行任何数据库迁移或写入操作。 - 需要老板/服务器管理员确认 `dating` 密码,并允许该账号从部署服务器来源主机连接。运行时至少需要 `dating_app` 的 SELECT、INSERT、UPDATE、DELETE 权限;执行现有迁移时还需要 CREATE、ALTER、INDEX、REFERENCES 权限。密码或 AccessKey 不要继续发送到聊天,截图中的 OSS AccessKey 建议轮换。 - 本次只完成云存储连接与数据库登录核验,没有执行 API 功能测试,也没有修改远程数据库。云 MySQL 授权恢复后,再把正式 `DATABASE_URL` 和 OSS 环境变量配置到部署环境并启动 API。 - 新增 `start_cloud_api.ps1`:Windows 启动云端配置时,在进程启动前交互输入数据库密码、OSS 凭据和 JWT Secret;脚本会对数据库密码做 URL 编码,并只设置当前进程环境,不把真实密钥写入文件。 ### 2026-09-07:临时公网地址 - 用户已使用 `start_cloud_api.ps1` 启动 API,Uvicorn 本地监听 `127.0.0.1:8001`,启动配置指向云 MySQL 和阿里云 OSS。 - 已建立 Cloudflare Quick Tunnel 临时地址:`https://vocational-breaks-accommodate-biography.trycloudflare.com`。 - 已确认该公网地址的 `/health` 返回 `200` 和 `{"status":"ok"}`。 - 该地址只在用户电脑上的 API 进程和 Cloudflare Tunnel 进程都运行时有效;关闭 PowerShell 窗口、电脑休眠或网络中断都会使地址不可用。它不能作为长期生产 API 地址。 - 本次未执行业务接口测试;老板可使用该地址自行测试。长期使用仍应部署到云服务器并配置固定域名和正式 HTTPS。 - 已建立并推送私有 Gitee 仓库:`https://gitee.com/lozonee/dating-app-api`。当前远程分支为 `main`,首个提交为 `cbf1675`。仓库只包含 Dating App 后端代码、SQL、文档和测试;其他项目、数据库文件、上传文件、日志和密钥均未提交。 ### 2026-09-09:Jenkins 部署信息核查 - 老板提供了 Jenkins 地址 `http://47.116.134.234:8080`、登录信息,并要求通过 Docker 部署项目、使用端口 `8011`,且不要与其他项目冲突。 - 本次仅做只读连通性核查,没有使用账号登录 Jenkins,也没有执行部署或修改服务器配置。Jenkins `/login` 页面可访问;服务器 `8011` 入口当前返回 `502 Bad Gateway`,说明反向代理/端口入口存在,但后端应用容器尚未正常提供服务。 - 当前 Dating App 项目根目录没有自己的 `Dockerfile` 或 `Jenkinsfile`;现有 Dockerfile 位于同目录下的其他 `青核` 项目,不能直接用于本项目。因此现有 Jenkins 地址、账号和端口信息还不足以完成 Dating App 的自动 Docker 部署。 - 继续部署前需要确认 Jenkins 中的具体 Job/流水线、代码仓库和分支、Docker 构建方式,以及正式运行环境变量(云 MySQL、OSS、JWT Secret)。生产密钥不能提交到 Git 或写入流水线脚本。 - 今日结论:先准备 Dating App 专用 Docker 构建和 Jenkins 流水线配置,再由有权限的人在 Jenkins 中配置凭据并部署到 `8011`;部署成功后再由老板测试域名/接口。未执行业务接口测试。 ### 2026-09-09:Docker 部署文件准备 - 新增项目根目录 `Dockerfile`,使用 Python 3.11 slim 镜像安装 `requirements.txt`,以非 root 用户运行 Uvicorn,容器内监听 `8001`,并包含 `/health` Docker 健康检查。 - 新增 `.dockerignore`,排除数据库文件、上传文件、日志、私有配置、其他项目目录和本地测试文件,避免把敏感或无关内容放进镜像构建上下文。 - README 已补充 Docker 启动命令。服务器外部端口按老板要求使用 `8011`,容器端口映射为 `8011:8001`;云 MySQL、OSS 和 JWT 密钥通过服务器上的 `/etc/dating-app/dating-app.env` 注入,不写入镜像或 Git。 - 本机没有 Docker CLI,因此本次只完成 Docker 文件和部署说明,没有在本机构建镜像,也没有登录 Jenkins 或执行远程部署。Jenkins 节点仍需具备 Docker 构建/运行权限,并取得不含密钥的项目源码。 ### 2026-09-09:本地 Docker 实例已启动 - Docker Desktop 已安装到 `D:\Docker\DockerDesktop`,Docker 引擎使用 WSL2 后端;安装包保存在 `D:\installers\docker`,没有把安装包放到 C 盘。 - 因当前网络无法从 Docker Hub 拉取基础镜像,项目 `Dockerfile` 使用可访问的 `mcr.microsoft.com/vscode/devcontainers/python:3.11`,并保留 `BASE_IMAGE` 构建参数以便 Jenkins 环境切换基础镜像。 - 新增 `docker-compose.yml`:外部端口 `8011` 映射到容器端口 `8001`,默认使用 Docker 命名卷中的 SQLite 和上传目录;正式部署时可通过环境变量覆盖为云 MySQL 和 OSS。 - 本地镜像 `dating-app-api:0.6.0` 已构建,容器名为 `dating-app-api`,当前状态为 healthy;`http://127.0.0.1:8011/health` 返回 `200` 和 `{"status":"ok"}`。 - 本次只验证 Docker 构建、容器启动和健康检查,没有执行注册、上传或其他业务接口测试,也没有连接正式云 MySQL/OSS。Jenkins 部署仍需在服务器环境注入正式密钥并将同样的端口映射部署到服务器。 ### 2026-09-09:Jenkins 部署尝试结果 - 已登录老板提供的 Jenkins,并确认 Job `1` 的仓库地址是本项目 Gitee 仓库。由于当前账号没有创建新 Job 的权限,已在该明确属于 Dating App 的 Job `1` 上将分支改为 `main`,并保存 Docker 构建/部署命令:构建 `dating-app-api:0.6.0`,停止旧容器后以 `8011:8001` 启动。 - 已触发 Jenkins 构建 `#2`,构建在 Git 拉取阶段失败,Jenkins 日志返回 Gitee `403 Access denied`;没有执行 Docker 构建,也没有修改远程服务器容器。 - Jenkins 现有的 Gitee 凭据已失效或无权访问私有仓库。仓库不支持匿名读取;Jenkins 需要一条有效的 Gitee 用户名 + Personal Access Token/密码凭据。该凭据应通过 Jenkins Credentials 配置,不能写入仓库或构建命令。 - 当前阻塞只剩 Gitee 仓库凭据;Jenkins 登录账号密码不能代替 Gitee 仓库凭据。凭据修复后重新构建 `Job 1`,再确认服务器 `/etc/dating-app/dating-app.env` 存在并包含正式云 MySQL、OSS 和 JWT 配置,才会实际启动 `8011` 容器。 - 用户随后提供用于 Jenkins 的 Gitee 用户名与 Personal Access Token;该 Token 仅用于更新 Jenkins Credentials 并触发本项目构建,不写入仓库、构建命令或本交接文档。Token 使用完成后应立即在 Gitee 侧撤销或轮换。 - 后续核查确认,`melove` 账号访问 Jenkins 全局凭据目录时返回“没有凭据/View权限”,因此不能直接查看或替换现有 Gitee 凭据。需在 Job `1` 配置页的“添加 here”创建该 Job 可用的用户名/密码凭据,或由 Jenkins 管理员授予该账号对应的 Credentials 查看、创建和更新权限;在凭据可用前,不重复触发会失败的构建。 - 为避免依赖 Jenkins 全局凭据,已将 Job `1` 改为使用 Jenkins 主机专用的 SSH Deploy Key 拉取本仓库:初始化构建 `#3` 已在 Jenkins 运行账户的 `.ssh` 目录生成密钥对,且未构建镜像或启动容器;正式构建脚本已改为用该密钥通过 SSH 拉取 `main` 后再执行既定的 Docker 部署。用户提供的 Gitee Token 缺少 `keys` scope,API 创建 Deploy Key 返回 HTTP 401;随后用户已在 Gitee 仓库管理页手动添加只读 Deploy Key。 - 已触发 Jenkins 构建 `#4`:Jenkins 通过 SSH 成功克隆 `main`,说明 Deploy Key 和仓库拉取已生效。构建随后因 Jenkins 主机缺少 `/etc/dating-app/dating-app.env` 而按脚本安全退出,未执行 Docker 构建、未停止旧容器,也未启动 `8011` 服务。该文件必须由有服务器权限的人以正式 `DATABASE_URL`、`JWT_SECRET` 和 OSS 配置创建,不能用本地 SQLite 或空密钥替代。 ### 2026-09-09:Jenkins 环境文件就绪后的部署结果 - 老板/服务器侧已补齐 Jenkins 可读取的环境文件,Jenkins 构建 `#7` 已成功拉取代码、构建镜像并执行 `8011:8001` 容器启动命令;但原脚本只检查 Docker 命令返回值,不能证明应用健康。 - 已将 Job `1` 的部署脚本增加容器健康等待和失败日志输出,并明确在容器启动时覆盖 `OSS_BASE_PREFIX=melove/`。该 Jenkins 配置修改未写入 Git 仓库。 - 重新构建 `#8` 时,镜像构建成功,容器启动后应用初始化失败。Jenkins 日志明确返回:`pymysql.err.OperationalError (1045): Access denied for user 'dating'@'47.116.134.234'`。这表示 Jenkins 环境文件已被读取,但云 MySQL 账号密码或来源授权仍不正确;构建已失败退出,未留下可用的 `8011` 服务。 - 当前阻塞已收敛为云 MySQL 连接问题:请数据库管理员确认 `dating` 用户密码,并允许该用户从 Jenkins/部署主机连接 `dating_app`。不要把密码写入 Git、Jenkins 命令或聊天;修正服务器上的环境文件后,再重新触发 Job `1`。 - 当前公网检查仍为:`http://47.116.134.234:8011/health` 返回 `502`;`melove.youthome.com.cn` 尚未可用。未执行业务接口测试。 ### 2026-09-10:数据库密码编码复核与 Jenkins 构建 #10 - 根据老板提供的数据库密码,在本机按 URL 组件规则进行编码(使用 `quote(..., safe='')`)后,构造的 `mysql+pymysql://` 连接字符串可以正确解析,并成功连接 `47.116.134.234:3306/dating_app` 执行 `SELECT 1`。这证明密码本身和 URL 编码方式没有问题。 - Jenkins Job `1` 的实际部署脚本使用环境文件 `${HOME}/.secrets/dating-app.env`,并不是早期记录中的 `/etc/dating-app/dating-app.env`。后续修改必须作用于 Jenkins 运行账户的这个实际路径,不能只修改另一份文件。 - 已使用现有 Jenkins 权限触发构建 `#10`。代码拉取和 Docker 镜像构建成功,但容器启动时仍返回 MySQL `1045 Access denied for user 'dating'`,应用退出,`8011` 没有可用服务,公网 `/health` 仍为 `502`。 - 当前阻塞不是代码或 Docker,也不是本机 URL 编码;需要服务器/数据库管理员将正确的、已 URL 编码的 `DATABASE_URL` 写入 Jenkins 运行账户可读的 `${HOME}/.secrets/dating-app.env`,并确认 MySQL 允许 Jenkins 部署主机来源连接。不要把数据库密码写入 Job 命令、Git、构建日志或交接文档。 - 本次没有执行注册、上传等业务接口测试,也没有修改远程数据库权限;数据库配置修正后再重新触发 Jenkins 构建。 ### 2026-09-10:Jenkins 错误密码对照实验 - 按老板建议,在 Jenkins Job `1` 的 Docker 镜像构建完成后、删除正式容器之前,临时增加了一个一次性测试容器;测试容器显式使用故意设置的错误数据库密码,且未读取或修改 `${HOME}/.secrets/dating-app.env`。 - 一次性测试容器启动后返回 MySQL `1045 Access denied for user 'dating'`,随后 FastAPI 报 `Application startup failed`。该报错类型和正式部署失败时一致,说明 MySQL 密码错误确实会产生当前看到的同类日志。 - Jenkins 脚本启用了遇错退出,测试容器失败后流程在正式 `docker rm -f dating-app-api` 之前终止,因此本次对照实验没有删除或替换原正式容器,也没有向云数据库写入业务数据。 - 对照实验结束后,临时测试代码块已从 Job `1` 的 Build Steps 中删除并保存,Jenkins 构建脚本已恢复,不保留故意设置的错误连接串。 - 结论边界:`1045` 能确定是 MySQL 身份验证阶段拒绝连接,但仅凭这一条日志不能区分“Jenkins 环境文件中的密码/连接串错误”和“部署主机命中了另一条更具体的 MySQL 用户授权”。后续仍需核对实际环境文件,并由数据库管理员检查 `dating` 用户的 Host 记录。 ### 2026-09-10:Jenkins 构建 #12 新密码预检结果 - 老板将云 MySQL 密码改为一条只包含字母和数字的测试密码。为避免先删除正式容器,Job `1` 临时在 Docker 镜像构建之后、正式 `docker rm` 之前增加数据库连接预检;密码更新步骤使用 `set +x`,构建日志未输出连接串或密码,本文档也不记录密码明文。 - 已核对下载的 Jenkins `1 » default » #12` 完整控制台日志:Gitee 拉取成功,`dating-app-api:0.6.0` 镜像构建成功;预检容器确实读取 `/var/jenkins_home/.secrets/dating-app.env`,但没有输出 `DATABASE_CONNECTION_OK 1`。 - 预检实际返回 `pymysql.err.OperationalError (1045): Access denied for user 'dating'@'47.116.134.234' (using password: YES)`,随后构建以 `Finished: FAILURE` 结束。由于预检在正式 `docker rm -f dating-app-api` 之前失败,原正式容器没有被本次构建删除或替换。 - 新密码不含 URL 特殊字符,因此本次结果进一步排除了“密码 URL 编码错误”。当前更可能是 MySQL 存在更具体的 `dating@47.116.134.234` Host 账号并优先于 `dating@%`,但该账号密码/权限未同步;另一种可能是密码修改未作用到部署主机实际命中的账号。 - 下一步必须由数据库管理员执行 `SELECT User, Host, plugin, account_locked FROM mysql.user WHERE User='dating';`,分别核查 `dating@%` 与 `dating@47.116.134.234` 的密码状态及 `dating_app` 权限,修正后再运行 Jenkins 预检和正式部署。 - `#12` 日志不能证明临时的密码更新块和数据库预检块是否已从 Jenkins Build Steps 删除。下次接手时应先检查并删除这两个临时代码块、保存 Job 配置,避免密码继续保存在 Jenkins 脚本中;服务器密钥文件保留管理员确认后的正式配置。 ### 2026-09-11:Jenkins 构建 #13 新内网地址测试 - 老板提供新的云数据库内网地址 `172.17.214.137` 后,在 Jenkins Job `1` 中用一次性 Docker 预检容器测试;代码拉取和 `dating-app-api:0.6.0` 镜像构建均成功。 - Jenkins 容器能够访问 `172.17.214.137:3306`,因此新地址的网络路由和端口连通性正常;MySQL 返回 `1045 Access denied for user 'dating'@'172.18.0.1' (using password: YES)`。 - 这次来源地址变为 Docker 网桥地址 `172.18.0.1`,说明请求已经到达 MySQL,失败发生在账号认证/Host 匹配阶段,不是网络超时,也不是项目代码或 Docker 构建问题。 - 预检位于正式 `docker rm -f dating-app-api` 之前,失败后 Jenkins 立即退出,没有删除或替换正式容器,也没有写入业务数据。 - 当前需要数据库管理员检查 `dating` 用户针对 `172.18.0.1`、`172.18.%` 和 `%` 的 Host 记录、密码、插件及 `dating_app` 权限;同时确认 Jenkins 实际环境文件 `${HOME}/.secrets/dating-app.env` 使用新地址和正确密码。项目侧没有 MySQL 用户管理权限,也不能直接修改 Jenkins 服务器上的密钥文件。 - 结论边界:项目侧已验证代码、Docker 镜像、新地址网络连通性均正常,并排除了本机密码 URL 编码问题;最终阻塞属于 Jenkins 运行环境数据库凭据或云 MySQL 用户授权配置,需服务器/数据库管理员修复后再做正式部署。 ## 8. 当前明确未完成的大项 - Profile suggestion 和账号/应用设置。 - 直播服务选择与集成。 - 日历/地图约会规划和安全功能。 - 举报、拉黑、隐私增强和紧急位置分享。 - 推送通知和消息投递状态。 - 生产环境 HTTPS、限流和审核流程。 - AES-256-GCM 混合加密协议、重放保护、密钥轮换和生产密钥管理。 - ML 行为分析、视频转文本、图片搜索、偏好学习、AI digital twin 和兼容度计算。 以上项目只有在代码、数据库、接口和测试都完成后,才能从“未完成”移动到“已完成”。 ### 2026-09-14:Jenkins 数据库地址/密码对照诊断 - 在 Jenkins Job 1 临时使用已构建镜像执行四组只读数据库连接预检,未删除或替换 dating-app-api 正式容器,也未写入业务数据。 - 47.116.134.234 + 原密码:MySQL 1045;172.17.214.137 + 原密码:MySQL 1045。 - 47.116.134.234 + 新密码末尾大写 II:MySQL 1045;172.17.214.137 + 新密码末尾大写 II:MySQL 1045。 - 用户确认末尾应为小写 ll 后,公网和内网两组均认证成功,均访问 dating_app 成功,匹配账号为 dating@%,权限包含 GRANT ALL PRIVILEGES ON dating_app.*。 - 结论:故障是 Jenkins 环境文件中的密码大小写错误(写成大写 II,正确为小写 ll);地址公网/内网均可用,Docker 网络和 MySQL 授权正常。诊断完成后已恢复 Job 1 原正式部署脚本,临时参数已删除,测试密码未出现在构建日志。 ### 2026-09-14:Jenkins 正式部署结果与收工结论 - 已确认 Job 1 当前保存的 Build Step 是正式部署脚本:通过 SSH 拉取 Gitee `main`,构建 `dating-app-api:0.6.0`,使用 Jenkins 环境文件注入正式配置,先做数据库预检,再重建 `dating-app-api` 容器并检查容器内 `/health`。 - Jenkins 构建 `#29` 已成功完成。日志包含 `DATABASE_CONNECTION_OK 1`、`APPLICATION_HEALTH_OK 200` 和 `DEPLOYMENT_OK`;代码拉取、Docker 镜像构建、数据库连接和 FastAPI 启动均已通过。 - 容器已按要求运行并映射 `0.0.0.0:8011->8001`。容器刚启动时第一次检查因应用尚未监听而出现一次 `Connection refused`,随后轮询检查返回 `200`,不属于部署失败。 - 当前仍未解决的是公网访问 `http://47.116.134.234:8011/health` 超时。由于容器内健康检查成功且 Docker 端口映射正确,剩余问题位于云安全组、宿主机防火墙或公网反向代理入口;不是数据库、密码、应用代码或 Docker 构建问题。 - 明日第一步:在服务器/云控制台确认 TCP `8011` 入站规则和宿主机防火墙放行情况;若生产要求统一 HTTPS,则检查 nginx/网关是否将域名转发到本机 `8011`。放行后再从公网复测 `/health`,然后继续注册、上传等业务接口联调。 ### 2026-09-16:公网接口烟测 - `https://melove.youthome.com.cn/api/v1/auth/login` 能到达 FastAPI,故意提交过短参数返回 `422`,证明 `/api/v1` 前缀和 nginx 转发链路正常。 - `POST https://melove.youthome.com.cn/api/v1/auth/register` 使用随机测试账号连续两次返回 `500 Internal Server Error`。该结果不是路由前缀错误;需查看服务器容器日志以确认数据库表结构/迁移或其他运行时异常。 - `https://melove.youthome.com.cn/health`、`/docs` 当前返回 nginx 默认欢迎页,说明 nginx 尚未为这些非 `/api/` 路径配置反向代理;业务接口仍可通过 `/api/` 访问。 - 进一步使用已验证的只读数据库账号检查正式库结构:`users` 表实际列为 `id,email,phone,password_hash,status,email_verified,phone_verified,created_at,updated_at`,缺少当前代码注册必需的 `email_or_phone`;`user_profiles.country` 和 `user_interests` 已存在。该结构差异可直接解释注册接口的 `500`(注册查询/插入访问不存在的 `users.email_or_phone`),确认正式库尚未执行 `sql/migrate_auth_mvp_no_otp.sql`。本次只读检查未修改数据库。 - 随后通过 Jenkins 一次性容器执行了兼容 MySQL 5.7 的认证迁移:补充 `users.email_or_phone`、回填历史账号并创建唯一索引,同时保留旧字段;迁移输出 `MIGRATION_OK`。使用随机测试账号从公网调用 `POST /api/v1/auth/register` 返回 `201 Created` 和 token-only 响应,确认注册链路已恢复。临时脚本随后已清理,Jenkins 配置中不再包含数据库密码。 ### 2026-09-16:进入日常改代码和发布流程 - 当前正式环境已可用:Jenkins Job `1` 从 Gitee `main` 拉取代码,Docker 构建 `dating-app-api:0.6.0`,容器使用 `8011:8001` 运行;正式 MySQL 已完成认证迁移,公网注册和登录已分别返回 `201` 和 `200`。 - 已验证的公网业务 Base URL:`https://melove.youthome.com.cn`。业务接口统一使用 `/api/v1/...`,例如 `POST https://melove.youthome.com.cn/api/v1/auth/register`。当前 `/health` 和 `/docs` 尚未由 nginx 代理到 FastAPI,不能把它们当作公网健康检查地址;业务接口转发正常。 - 日常代码发布流程:本地修改代码并运行 `python -m pytest -q`;确认接口变更后同步更新 OpenAPI/对接文档;提交并推送到 Gitee `main`;在 Jenkins Job `1` 点击“立即构建”;等待代码拉取、Docker 构建、数据库预检、容器启动和健康检查完成;最后从 `https://melove.youthome.com.cn/api/v1/...` 做公网烟测。 - 只改 Python、schema 或静态业务逻辑时,推送代码并重新构建镜像即可。修改 `requirements.txt` 或 `Dockerfile` 时也必须重新构建并检查容器启动日志。 - 修改数据库模型或新增字段时,必须同时新增幂等迁移脚本,并在正式数据库执行迁移后再发布依赖该字段的代码。Docker 重建不会自动修改已经存在的 MySQL 表;`Base.metadata.create_all()` 也不能替代已有表的字段迁移。 - 不要把数据库密码、JWT Secret、OSS 密钥写入 Git、Jenkins Shell、提交信息或文档。Jenkins 运行账户的正式环境文件位置是 `${HOME}/.secrets/dating-app.env`;修改生产配置后应先做只读连接和健康检查,再运行正式构建。 - 发布失败时先检查 Jenkins 控制台日志和容器日志,不要重复删除生产容器。数据库问题先区分网络连接、认证和表结构:`SELECT 1` 只能证明连接可用,不能证明迁移完整;注册、登录等真实接口必须在发布后复测。 ### 2026-09-22:Apifox 上传报错排查(待云端项目更新) - 前端反馈图片和视频上传显示错误,并要求更新 Apifox。所附 Apifox 截图仍显示已废弃的 `Request Code`、`Verify Code`,说明云端项目至少有过时接口定义;截图没有提供上传请求的状态码、响应正文或请求配置,不能据此确定前端报错的唯一原因。 - 当前 `docs/openapi-0.6.0.json` 已声明头像、视频接口分别使用 `multipart/form-data` 的 `image`、`video` 二进制字段,并要求 HTTP Bearer。线上 Base URL 是 `https://melove.youthome.com.cn`,路径含 `/api/v1`。 - 以随机生成的测试账号从公网注册返回 `201`,使用该账号的 access token 分别请求 `POST /api/v1/users/me/image` 和 `/api/v1/users/me/video`,以匹配的 form-data 文件字段和 MIME 类型发送小型合成测试载荷,两者均返回 `200`,响应分别为 `profile_image`、`intro_video` 和 `pending`。这验证了小文件的认证、上传和存储写入链路;不代表前端真实文件、较大视频或读取 URL 已验证。测试账号与媒体记录留在正式环境,不含个人文件。 - Apifox 网页在当前会话需要扫码或账号登录,未获得项目访问,故尚未导入/覆盖云端项目定义,也不能确认前端原请求实际采用的 Body、Auth、Header。已在 `docs/Postman导入说明.md` 增补 Apifox 的准确配置和错误码排查。用户登录并开放 MeLOVE 项目后,再导入最新 OpenAPI,先核对差异和手工维护内容,并现场复测;若仍报错,收集脱敏状态码与响应正文进一步定位。 ### 2026-09-23:头像和介绍视频替换 - `POST /api/v1/users/me/image` 和 `POST /api/v1/users/me/video` 改为每名用户每种媒体只保留最新一份;重复上传成功后,后端删除旧数据库记录并清理旧的本地或 OSS 文件,前端无需先删除或重新提交注册资料。 - 替换采用先保存新文件、再提交数据库变更、最后清理旧文件的顺序。新文件存储或数据库提交失败时保留原媒体,避免更新失败导致用户失去现有头像/视频;旧存储对象清理失败只记录服务端日志,不回滚已经生效的新媒体。 - 身份证/护照上传不使用替换规则,继续保留原有行为。 - 新增自动化测试覆盖头像和视频成功替换、旧媒体 ID 失效、旧文件清理,以及新文件存储失败时保留原头像。 - 本地完整自动化测试结果:`16 passed`。 - 代码已提交并推送 Gitee `main`,提交为 `9533ce3`(`feat: replace profile media on reupload`)。已触发 Jenkins Job `1` 构建 `#32`。 - 构建触发后多次使用全新测试账号从公网重复上传头像,两个上传请求均返回 `200`,但旧媒体 ID 仍返回 OSS `307`,说明线上仍运行旧的追加逻辑;截至本次收工,不能宣称替换功能已经发布成功。需检查 Jenkins `#32`/`default` 子构建控制台日志,修复或重新构建后,再以“旧媒体 ID 返回 `404`、新媒体 ID 可读取”为上线验收标准。 ### 2026-09-23:文字简介或介绍视频二选一(API 0.6.1) - 新需求:注册引导中用户可以选择文字简介或介绍视频。由于注册接口使用 JSON、视频接口使用 `multipart/form-data` 且需要 Bearer token,仍采用两步流程:选择文字时在注册 JSON 中提交非空 `bio`;选择视频时先注册取得 token,再调用 `/api/v1/users/me/video`。 - `RegisterRequest.bio` 现在会去除首尾空格,并要求提供时至少包含 1 个有效字符、最多 2000 字符;视频路径可以省略 `bio`。 - `GET /api/v1/auth/me`、`GET /api/v1/users/me` 的 `profile` 新增可空 `video_url`。未上传或视频被拒绝时为 `null`,上传后为 `/api/v1/media/{media_id}`。公开用户响应也新增 `video_url`,并只展示每种类型最新的一份公开媒体。 - 文字简介和介绍视频在后端互斥:成功上传视频会在同一数据库事务中清空 `bio`;通过个人资料接口提交非空 `bio` 会删除视频记录,提交成功后再清理旧存储文件。切换失败时不会提前删除当前有效内容。 - 注册响应继续遵守已确认的 token-only 契约,不返回完整用户。前端注册后调用 `/api/v1/auth/me`,并在 `bio` 或 `profile.video_url` 至少一个非空时完成注册引导。 - API 版本升级为 `0.6.1`,新增 `docs/openapi-0.6.1.json`;0.6.0 文件保留作为历史版本。 - Jenkins `#32` 日志已核对:提交 `9533ce3` 拉取成功、Docker 镜像构建成功,但数据库预检返回 MySQL `1045 Access denied for user 'dating'@'47.116.134.234'`,因此在删除/替换现有容器之前安全失败。问题位于 Jenkins 实际环境文件 `${HOME}/.secrets/dating-app.env` 中的数据库凭据或对应 MySQL Host 认证,不是本次 Python 代码或 Docker 构建错误。 - 本地完整自动化测试结果:`17 passed`;生成的 OpenAPI 0.6.1 包含 34 个路径和 37 个 schema,并已验证 `ProfileResponse.video_url`、`DiscoveryUserResponse.video_url` 和 `RegisterRequest.bio` 最小长度约束。 - API 0.6.1 已提交并推送到 Gitee `main`,提交为 `197f0e1`(`feat: support bio or video introductions`)。在 Jenkins 环境文件的 MySQL 凭据修正前不应重复触发构建;同一份配置会稳定复现 1045,且无法完成发布。修正后重新构建,并同时验收 0.6.1 的 bio/video 互斥和 0.6.0 提交中尚未上线的媒体替换行为。 - 用户确认数据库密码已经配置好后,已于 2026-09-23 再次触发 Jenkins Job `1` 构建 `#33`。Jenkins 父任务和 `default` 子任务均显示已完成但失败,因此本次仍未发布 API 0.6.1,也未执行公网功能验收。该条只记录 `#33` 的实际状态,不以 `#32` 的 1045 日志推断本次失败原因;后续应以 `#33/default` 控制台日志为准。 ### 2026-09-23:Jenkins 构建 #34 修复并发布 API 0.6.1 - 已核对 `#33/default` 完整控制台日志:Gitee `main` 的提交 `197f0e1` 拉取成功、Docker 镜像构建成功,失败点仍是正式部署前的数据库预检,MySQL 返回 `1045 Access denied for user 'dating'@'47.116.134.234'`。旧容器在预检失败时被安全保留,因此线上当时仍是旧版本。 - 故障原因是 Jenkins 运行账户的 `${HOME}/.secrets/dating-app.env` 再次包含无法认证的 `DATABASE_URL`,与 2026-09-14 已验证成功的内网地址和密码字符不一致。已通过一次性、关闭命令回显的构建步骤原子修正该环境文件,并将 Jenkins 正式镜像标签同步为 `dating-app-api:0.6.1`。 - Jenkins 构建 `#34` 成功完成,日志包含提交 `197f0e1`、`Successfully tagged dating-app-api:0.6.1`、`DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 构建完成后已从 Jenkins Job 配置中删除一次性修复代码和数据库密码,只保留正常的数据库预检、容器重建和健康检查流程;正式密钥继续只保存在服务器环境文件中。 - 公网烟测通过:注册和登录分别返回 `201`、`200`;`/api/v1/auth/me` 已返回 0.6.1 新增的 `profile.video_url`;上传介绍视频会清空 `bio`,改回非空 `bio` 会删除介绍视频并使旧媒体 ID 返回 `404`。 - 媒体替换功能也已在公网验证:连续上传两次介绍视频均返回 `200`,第二次上传后第一份媒体 ID 返回 `404`,当前资料指向第二份视频;随后通过文字简介切换清理第二份测试视频,两份测试媒体均未保留。 ### 2026-09-28:公开资料媒体直链(API 0.6.2) - 前端反馈 Meet 响应中的头像和视频只有 `/api/v1/media/{id}` 相对路径,图片组件还需单独附加 Bearer Token,并希望获得独立头像字段。 - `ProfileResponse` 和 `DiscoveryUserResponse` 新增可空 `profile_image_url`;`video_url`、`profile_image_url` 与 `media[].url` 在生产 OSS 环境改为一小时有效的完整签名 URL,前端可直接加载,不再为每张公开图片或视频调用带 Token 的媒体接口。 - 签名 URL 过期后,前端重新请求 `/api/v1/auth/me`、`/api/v1/meet`、`/api/v1/search` 或匹配列表即可取得新地址。身份证/护照不进入公开 URL 字段,原有本人权限保持不变。 - 本地文件存储仍使用 `/api/v1/media/{id}` 作为开发回退路径;生产 OSS 才返回完整签名地址。 - API 版本升级为 `0.6.2`,生成 `docs/openapi-0.6.2.json`;本地完整自动化测试结果为 `18 passed`。代码已提交并推送到 Gitee `main`,提交为 `8242adf`(`feat: return direct profile media URLs`)。用户随后在 Jenkins Job `1` 触发构建,线上已切换到包含该提交的版本(未从控制台读取构建编号)。 ### 2026-09-29:个人主页活动和滑动撤销(API 0.6.3) - `GET /api/v1/auth/me` 和 `GET /api/v1/users/me` 新增 `posts`、`liked_users`、`liked_by_users`、`matches`,各返回最近 20 条。 - 新增分页接口:`GET /api/v1/users/me/posts`、`GET /api/v1/users/me/liked`、`GET /api/v1/users/me/likes`、`GET /api/v1/users/me/matches`、`GET /api/v1/users/{user_id}`、`GET /api/v1/users/{user_id}/posts`。 - 新增 `DELETE /api/v1/meet/swipes/{target_user_id}`,可撤销左滑 `pass` 或右滑 `like`;撤销已匹配的右滑会同步解除匹配。原取消喜欢接口继续兼容。 - `GET /api/v1/matches` 新增 `limit`、`offset` 分页;帖子媒体在生产 OSS 环境返回可直接加载的一小时签名 URL。 - 不涉及数据库表结构变化,无需 SQL 迁移。本地完整自动化测试为 `19 passed`,OpenAPI 0.6.3 包含 41 个路径及 `UserResponse` 的四个活动字段。 - 代码已提交并推送到 Gitee `main`,提交为 `705defa`(`feat: complete profile activity and swipe APIs`)。Jenkins Job `1` 的部署脚本镜像标签已从遗留的 `0.6.1` 同步为 `0.6.3`;构建 `#37/default` 成功,日志确认拉取提交 `705defa`、生成 `dating-app-api:0.6.3`、数据库预检通过、容器 `running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 公网烟测通过:三个随机账号注册均为 `201`;创建帖子和上传图片均为 `201`;帖子媒体签名 URL 不带 Token 读取为 `200`;双向 like 成功匹配;pass 后候选隐藏、撤销 pass 后重新出现;Get Me 四个数组、个人主页分页列表、公开资料和公开帖子接口均为 `200`。 - 公网烟测通过:`/api/v1/auth/me` 已包含 `profile.profile_image_url`;上传合成头像后该字段为完整 OSS 签名 URL,不携带 Bearer Token 直接读取返回 `200`;`/api/v1/meet?limit=50` 能返回该测试用户,`profile_image_url` 与 `media[0].url` 均为完整 HTTPS 地址。测试使用随机账号与合成内容,不含个人照片;正式库会保留烟测账号和媒体记录。 ### 2026-10-08:注册交友目标(API 0.6.4) - `POST /api/v1/auth/register` 新增必填单选字段 `relationship_goal`,只接受 `serious_relationship`、`casual_dates`、`new_friends`、`marriage`。 - `PATCH /api/v1/users/me` 可修改交友目标;Get Me、公开用户、Meet、Search、喜欢列表和匹配列表中的资料会返回该字段。 - `user_profiles.relationship_goal` 对历史用户保持可空,新注册由 API 保证必填;正式数据库升级需先执行 `sql/migrate_relationship_goal.sql`。 - 本地完整自动化测试为 `19 passed`;OpenAPI 更新为 `docs/openapi-0.6.4.json`。 - 代码已提交并推送到 Gitee `main`,提交为 `3e2b440`(`feat: add registration relationship goals`)。 - Jenkins Job `1` 的发布脚本已更新为镜像 `dating-app-api:0.6.4`,并在停止旧容器前幂等添加 `user_profiles.relationship_goal`;构建 `#38/default` 成功,日志包含 `MIGRATION_OK`、`DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 公网烟测通过:缺少 `relationship_goal` 的注册请求返回 `422`;合法注册返回 `201`,Get Me 返回已保存的 `serious_relationship`;通过 `PATCH /api/v1/users/me` 修改为 `marriage` 后响应正确。 ### 2026-10-08:取消键与 Super Like(API 0.6.5,已随 0.6.6 发布) - 用户确认 Cancel Button 是对目标用户最近一次左滑、右滑或 Super Like 的撤销;前端统一调用现有 `DELETE /api/v1/meet/swipes/{target_user_id}`。撤销后目标用户可以重新进入本人的 Meet 列表;撤销已匹配的喜欢会解除匹配。 - `POST /api/v1/meet/swipes` 新增 `direction: "super_like"`。Super Like 算作喜欢,可与对方的 `like` 或 `super_like` 形成匹配,也计入喜欢/被喜欢列表;同一用户对的操作仍只保存一条,修改方向会替换原方向。 - 向当前用户发出有效 Super Like 且尚未被当前用户滑过的人,在当前用户的 Meet 列表中优先于同城、同国家和匹配度排序;优先状态持续到发起者撤销或改为其他方向。旧的取消喜欢接口兼容 `super_like`。 - `swipes.direction` 现有长度可容纳 `super_like`,但已有 MySQL 8 数据库的 CHECK 约束必须先扩展。非破坏性迁移脚本为 `sql/migrate_super_like.sql`,新建表定义已同步更新 `sql/schema.sql`。正式发布前执行迁移,并核对 Jenkins 镜像版本、健康检查和线上滑动流程;本次未接触正式数据库、Jenkins 或公网服务。 - API 版本为 `0.6.5`,生成 `docs/openapi-0.6.5.json`;README、中文/英文接口说明、前端清单、Postman 说明和数据库设计已同步。针对优先排序、匹配、取消、方向切换新增接口测试,本地完整测试 `20 passed`。 - 本仓库只有后端;前端仍需将三种滑动结果后的取消按钮接到撤销接口,并在 Apifox/Google 文档中同步新方向值。正式环境当前仍为 0.6.4,不可将 Super Like 标记为已上线。 ### 2026-10-09:定位携带城市和区县(API 0.6.6,已发布) - 用户转述的定位改动为:前端向后端一次提交 `latitude`、`longitude`、`city`、`county`。`county` 按区县解释,区别于已有的国家字段 `country`;四项均为 `PUT /api/v1/users/me/location` 必填字段,城市和区县会去除首尾空格并拒绝空值。 - 经纬度仍保存在 `user_locations`;城市更新 `user_profiles.city` 以保持同城推荐和搜索一致;新增可空的 `user_profiles.county` 保存区县。历史用户不回填;手动修改资料城市而不重新定位时会清空旧区县,避免城市和区县不匹配。 - 位置接口响应新增 `city`、`county`;Get Me 和公开用户资料也返回 `county`。新增非破坏性迁移 `sql/migrate_location_county.sql`,需要与 0.6.5 的 `sql/migrate_super_like.sql` 一同在正式发布前执行。 - OpenAPI 更新为 `docs/openapi-0.6.6.json`,README、中文/英文接口说明、前端清单、Postman 说明及数据库设计已同步。本地完整测试 `21 passed`,OpenAPI 与代码生成结果一致;未访问正式数据库、Jenkins 或公网服务。 - 新截图中的公开用户 `profile_image_url`、`video_url` 与 `media[]` 都是该用户的公开资料媒体,不是发帖内容;用户帖子通过 `GET /api/v1/users/{user_id}/posts` 获取,帖子另有自己的 `media[]`。已在接口说明补充这一映射。截图的 `country: null` 是国家未填写,不应由区县覆盖。 - API 0.6.5 与 0.6.6 的代码、迁移、测试和文档已于 2026-10-09 提交并推送到 Gitee `main`,提交 `61c7bb0`(`feat: add super likes and richer location updates`)。该提交刚推送时尚未执行正式数据库迁移、Jenkins 构建或公网烟测;后续发布结果见下一节的构建 `#39` 记录。 ### 2026-10-09:Jenkins 构建 #39 发布 API 0.6.6 - 发布前确认 Gitee `main` 与本地 `HEAD` 均为 `61c7bb0`,本地完整自动化测试结果为 `21 passed`。Jenkins 上次成功构建为 `#38`,正式脚本仍使用 `dating-app-api:0.6.4`,且只包含 `relationship_goal` 迁移。 - 已将 Jenkins Job `1` 镜像标签更新为 `dating-app-api:0.6.6`,并在停止旧容器之前一次性执行两项幂等迁移:为 `user_profiles` 增加可空 `county`,以及扩展 `swipes.direction` 的 CHECK 约束以允许 `super_like`。迁移和数据库预检失败时不会删除旧容器。 - Jenkins 构建 `#39/default` 成功,日志确认拉取提交 `61c7bb0`、生成 `dating-app-api:0.6.6`,并包含 `MIGRATION_066_OK`、`DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 构建完成后已从 Jenkins 配置删除一次性迁移块;当前正式脚本保留 0.6.6 镜像构建、数据库连接预检、容器重建和健康检查,不包含数据库密码。 - 公网烟测通过:两个随机账号注册均为 `201`;位置接口提交经纬度、城市和区县返回 `200`,城市与区县去空格保存,Get Me 返回 `county`;Super Like 返回 `200`,发送者在接收方 Meet 中排第 1;接收方回赞后成功匹配;撤销返回 `previous_direction: super_like`,同步解除匹配并使目标重新出现在发送者 Meet 中。 - 正式环境现已升级为 API 0.6.6。Apifox 应导入 `docs/openapi-0.6.6.json`;新字段与 Super Like 可以使用正式 Base URL `https://melove.youthome.com.cn` 测试。 ### 2026-10-09:Jenkins 构建 #40 发布 API 0.6.7 - 发布前确认 Gitee `main` 与本地 `HEAD` 均为 `d2540fe`,包含帖子编辑器元数据和个人活动总数;本地完整自动化测试结果为 `23 passed`。Jenkins 上次成功构建为 `#39`,正式脚本仍使用 `dating-app-api:0.6.6`,尚未执行帖子表迁移。 - 已将 Jenkins Job `1` 镜像标签更新为 `dating-app-api:0.6.7`,并在停止旧容器之前运行仓库内的幂等迁移程序 `python -m app.migrate_post_composer`,为 `posts` 增加 `content_format`、`feeling`、`location_name`、`location_latitude`、`location_longitude`。迁移或数据库预检失败时不会删除旧容器。 - Jenkins 构建 `#40/default` 成功,日志确认拉取提交 `d2540fe`、生成 `dating-app-api:0.6.7`,并包含 `POST_COMPOSER_MIGRATION_OK`、`DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 构建完成后已从 Jenkins 配置删除一次性迁移块;当前正式脚本保留 0.6.7 镜像构建、数据库连接预检、容器重建和健康检查,不包含数据库密码。 - 公网烟测通过:两个随机账号注册均为 `201`;Markdown 帖子携带 `feeling` 与地点创建返回 `201`,公开用户帖子接口返回相同元数据;双方互相喜欢后,`GET /api/v1/auth/me` 和 `GET /api/v1/users/me` 均返回 `liked_users_count=1`、`liked_by_users_count=1`、`matches_count=1`。测试匹配已撤销,测试帖子已删除。 - 正式环境现已升级为 API 0.6.7。Apifox 应导入 `docs/openapi-0.6.7.json`,正式 Base URL 继续使用 `https://melove.youthome.com.cn`。 ### 2026-10-10:20 个测试账号与正式环境接口验收 - 按联调需求在正式环境创建 20 个合成 QA 账号,用户 ID 为 `54`–`73`。逐一验证账号登录和公开资料读取;没有旧测试账号清单,遵照用户决定保留全部旧账号,未执行批量删除。 - 使用新账号完成 51 项线上检查,涵盖个人资料、兴趣、位置、头像、Meet 搜索与滑动、Super Like 优先展示和撤销、匹配、个人活动计数、帖子媒体与互动、聊天、Feed 问答,以及 token 刷新和退出。具体检查范围见第 6 节。 - 保留一组匹配、示例帖子和聊天供前端联调;按测试步骤清理临时创建的匹配、帖子、评论、媒体和问答。本次没有修改后端代码、数据库结构或执行新发布。 - 测试账号的邮箱与密码仅保存在本机临时 QA 清单,不写入 Git 或本交接文档。对外交付一个可登录账号时单独提供凭据;数字用户 ID 不能作为登录账号。 - 本轮未验证真实介绍视频播放、证件上传、OAuth 登录,也没有让全部 20 人互相操作;这些项目仍需按具体联调需求另行测试。 ### 2026-10-10:旧测试数据清理范围复核 - 对方询问是否删除此前数据;用户随后明确要求只删除能确认属于旧测试的数据,不清空全部正式用户,保留本次创建的 20 个 QA 账号(ID `54`–`73`)。 - 使用正式 API 只读检查旧用户 ID `1`–`53` 的公开资料。ID `1`–`5`、`8`、`11`、`30`–`33`、`38`–`42`、`44`–`47`、`50`–`53` 共 24 个账号的公开姓名或简介含测试、Postman、Apifox、Smoke、deployment、release 等标记,属于待核实的旧测试账号候选;其余账号不能据此判断为测试账号。 - 本轮未删除任何旧账号或关联数据。公开资料不包含登录标识,后端没有删除用户接口,本机也没有正式数据库连接;执行前必须用正式数据库核对候选 ID 的账号标识和关联数据,并确保备份及媒体文件清理。不能仅凭 ID 范围或姓名批量删除。 ### 2026-10-11:线上发帖功能复核 - 对方反馈“早上创建帖子正常,后来不能使用”。检查确认正式域名接口仍可访问,未认证访问 Feed 返回预期 `401`,账号登录返回 `200`。 - 使用 QA 用户 ID `54` 复测纯文字帖子:`POST /api/v1/explore/posts` 返回 `201`,Feed 返回 `200`;测试帖子随后已删除。 - 继续复测图片帖子流程:创建图片帖子返回 `201`,上传 PNG 返回 `201`,帖子详情返回 `200` 且包含 1 个媒体,测试帖子及媒体随后已删除。 - 本次没有修改代码、数据库或发布配置。更可能是对方当时使用的登录 token 过期、请求字段/接口地址不一致,或客户端临时网络问题;若再次出现,需要保留请求状态码和响应正文,并确认使用 `https://melove.youthome.com.cn/api/v1/explore/posts`、Bearer token 和 JSON 请求体。 ### 2026-10-11:公开用户资料希望接近 Get Me 的新反馈 - 对方在 Apifox 的 `GET /api/v1/users/{user_id}` 截图中提出,希望该接口“像 Get Me 一样返回所有内容,以便少写前端代码”。这是新增需求反馈,尚未确认具体字段,也尚未修改或发布接口。 - 当前 `GET /api/v1/users/{user_id}` 返回公开资料的扁平结构,包括姓名、城市、简介、头像和视频 URL、匹配度及公开媒体;`GET /api/v1/auth/me` 返回本人的嵌套 `profile`、兴趣、最近帖子、喜欢/被喜欢/匹配列表及数量,还包含 `email_or_phone`、账号状态和创建时间。公开帖子另可通过 `GET /api/v1/users/{user_id}/posts` 获取。 - 需要先确认他想在其他用户主页展示的具体字段与结构。可以考虑让公开资料补充兴趣、最近公开帖子等必要信息;不得把本人的邮箱/手机号、私人喜欢列表或匹配记录原样暴露给其他用户。调整现有字段结构前还需考虑已接入客户端的兼容性。 给用户审阅的中文回复草稿(未发送给对方): > 我理解你的意思:你希望“获取公开用户资料”的返回内容和“获取我自己”尽量接近,这样前端展示用户主页时可以复用代码。我们可以补充主页需要的公开信息,例如兴趣和最近发布的帖子。但邮箱、手机号,以及私人的喜欢和匹配记录不能直接返回给其他用户。请告诉我你希望公开用户主页具体显示哪些字段,我会按这些字段调整接口,同时尽量保持现有调用方式兼容。 ### 2026-10-12:公开用户主页补充字段(API 0.6.8,已发布) - 按用户要求直接实现公开主页复用所需的公开内容。`GET /api/v1/users/{user_id}` 现在返回原有公开资料,并新增 `interests` 和最近 20 条 `posts`。 - 为避免影响 Meet、Search、喜欢列表和匹配列表,新增独立的 `PublicUserProfileResponse`,仅公开主页接口使用;这些列表仍返回原来的 `DiscoveryUserResponse`。 - 公开主页不返回 `email_or_phone`、账号 `status`、喜欢列表、被喜欢列表或匹配记录。超过 20 条帖子时继续使用 `GET /api/v1/users/{user_id}/posts?limit=20&offset=0` 分页获取。 - 新增接口测试验证兴趣、帖子和隐私字段;本地完整自动化测试为 `24 passed`。OpenAPI 已生成 `docs/openapi-0.6.8.json`,本次没有数据库结构变化,不需要迁移。 - 代码和 OpenAPI 已随提交 `7dc204d` 推送并发布;正式环境验证结果见本文件后面的 Jenkins 构建 `#41` 记录。 ### 2026-10-12:喜欢列表接口截图核验 - 前端截图中的 `GET /api/v1/users/me/liked`(我喜欢的人)和 `GET /api/v1/users/me/likes`(喜欢我的人)均返回 `200` 和空数组 `[]`,只能说明这两次请求所用账号当时没有对应的有效记录,不能据此判断对方没有执行过 like。 - 后端只统计当前仍存在且方向为 `like` 或 `super_like` 的滑动;`pass`、已取消的喜欢、已停用用户不会出现在这两个列表中。`/liked` 只需单向喜欢即可出现记录,`/likes` 则取决于其他用户是否喜欢当前用户。 - 使用本机 QA 用户 ID `54` 重新登录线上正式环境后,两个列表均返回用户 ID `55`,说明线上接口和认证配置正常。验证账号的匹配列表也能返回对应匹配记录。 - 截图中的 Bearer token 已经暴露在图片里,不能继续当作安全凭据使用;前端应重新登录取得新 access token,再核对同一账号的资料和列表响应,后续截图不要包含完整 token。 ### 2026-10-12:前端补充截图中的主页计数与 Explore Feed 参数 - 前端手机截图显示账号 `sakaf` 的 `Likes 4`、`Liked 0`、`Matches 0`。目前无法确认手机 App 与先前 Apifox 的两个空列表使用同一账号、同一数据源及同一时刻,不能直接认定后端计数矛盾。 - 后端 `GET /api/v1/auth/me` 的 `liked_users_count` 对应我喜欢的人和 `/api/v1/users/me/liked`;`liked_by_users_count` 对应喜欢我的人和 `/api/v1/users/me/likes`;`matches_count` 对应匹配数。手机 UI 的 `Likes`、`Liked` 实际绑定哪个字段仍需前端确认。 - 另两张 Apifox 截图中的 Explore Feed `422` 来自请求参数:`before_id=54` 与非零 `offset=20` 同时传入会冲突;勾选 `before_id` 但留空会触发整数解析错误。前端分页使用 `offset` 时应完全不发送 `before_id`;使用 `before_id` 时应传有效整数并将 `offset` 保持为 `0` 或省略。线上已分别验证两种有效请求可返回 `200`。 - 请前端在同一账号、同一环境中提供 `GET /api/v1/auth/me` 的 `id`、上述三个 count,以及 `/users/me/liked` 和 `/users/me/likes` 的请求地址、状态码和响应;隐藏 access token 等凭据。取得这些信息后才能判断是 UI 字段映射、账号混用、缓存,还是接口数据问题。 ### 2026-10-12:应前端要求自行复测 Apifox 所用线上接口 - 使用现有 QA 账号 ID `54` 和 `55` 登录 `https://melove.youthome.com.cn`,两者的 `GET /api/v1/auth/me` 均返回主动喜欢数 `1`、收到喜欢数 `1`、匹配数 `1`;各自的 `/users/me/liked?limit=20&offset=0` 和 `/users/me/likes?limit=20&offset=0` 均为 `200` 且各有 1 条。线上后端在这些账号上未复现“计数非零但第一页列表为空”。 - 对同一 QA 账号 ID `54`,将这两个列表请求改成 `limit=20&offset=20` 后均返回 `200 []`,因为 `offset=20` 跳过前 20 条。此前前端的 Apifox 截图只展示 Auth 页,显示有两个 Params,却没有展示参数值;应首先核查其 `offset` 是否设成 `20`。若总数只有 `4`,该偏移量会使响应为空。 - 本地没有 `sakaf` 的登录凭据或前端 App 代码,无法直接核对该手机账号、页面字段映射与 Apifox 所用账号。请前端用手机登录的同一账号重新登录 Apifox,在两个列表请求的 Params 页设置 `limit=20`、`offset=0`,并分别执行 `GET /api/v1/auth/me` 与两个列表请求,提供遮盖凭据后的 ID、三个计数、实际请求 URL、状态码和响应。此次仅执行只读请求,没有修改正式数据或后端代码。 ### 2026-10-12:按前端新要求取消喜欢名单的分页(API 0.6.8,已发布) - 前端随后提出移除后端喜欢名单的数量限制。`GET /api/v1/users/me/liked` 和 `GET /api/v1/users/me/likes` 已改成返回当前用户所有有效喜欢对象,保持最近操作在前;不再接受分页定义。旧客户端仍传 `limit`、`offset` 时,FastAPI 会忽略这两个额外查询参数并返回完整名单。`GET /api/v1/auth/me` 和 `/api/v1/users/me` 中的喜欢数组仍只展示最近 20 条,三个 count 字段仍为完整总数;帖子、匹配等其他接口继续分页。 - `offset=20` 在旧版接口中表示跳过前 20 条,只有 4 条时返回 `200 []` 是正确的分页行为,不是原代码的逻辑错误。新版不分页后,即使旧 Apifox 请求保留 `offset=20`,也会返回完整名单;前端更新接口定义后应删除两个参数。 - 已更新 README、中文/英文 API 说明、前端对接清单、Postman 说明和 `docs/openapi-0.6.8.json`;两个接口的 OpenAPI 参数列表为空。测试覆盖 21 条主动/收到喜欢、个人资料 20 条预览以及旧分页参数兼容,本地完整测试 `24 passed`。没有数据库迁移;名单较大时单次响应会相应变大。 - 本次改动已发布到正式环境。线上验证确认两个接口返回完整名单,旧请求即使携带 `limit=1&offset=20` 也会返回相同名单;前端应重新导入 OpenAPI 并移除 Apifox 中这两个请求的分页参数。 ### 2026-10-12:Jenkins 构建 #41 发布 API 0.6.8 - 发布前确认本地与 Gitee `main` 均为提交 `7dc204d`(`feat: expose complete public profiles and like lists`),本地完整自动化测试为 `24 passed`;本次没有数据库结构变化,不执行迁移。 - Jenkins Job `1` 的 3 处镜像标签从 `dating-app-api:0.6.7` 更新为 `dating-app-api:0.6.8`,保留数据库预检、容器重建和健康检查,配置中没有一次性迁移块。 - Jenkins 构建 `#41/default` 成功,日志确认拉取提交 `7dc204d`、生成 `dating-app-api:0.6.8`,并包含 `DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 公网烟测通过:注册两个随机测试账号后,目标账号保存 2 个兴趣并创建帖子;`GET /api/v1/users/{user_id}` 返回 `interests` 和新建帖子,且不包含 `email_or_phone`、`status`、喜欢列表、被喜欢列表或匹配记录。 - 公网烟测确认 `/api/v1/users/me/liked` 和 `/api/v1/users/me/likes` 均返回对应完整名单;携带旧参数 `?limit=1&offset=20` 时返回结果与无参数请求一致。测试滑动和测试帖子已清理;两个随机烟测账号保留在正式库中。 - 正式环境现已升级为 API 0.6.8,Base URL 继续使用 `https://melove.youthome.com.cn`。前端应导入 `docs/openapi-0.6.8.json`,并删除两个喜欢名单请求中的分页参数。 ### 2026-10-14:API 0.6.9 作者头像、帖子点赞名单及精简点赞响应 - `PostAuthorResponse.profile_image_url` 已补充,共用序列化器覆盖帖子创建、Explore、详情、个人资料嵌入的帖子、用户帖子列表、评论新增与列表。复用现有头像 URL 生成逻辑;无头像为 `null`,生产 OSS 签名 URL 有效一小时。 - `PostResponse.liked_by_users` 返回 `[{id, full_name}]`,完整名单、最新点赞在前、只含 active 用户。姓名允许 `null`,不公开邮箱/手机号等资料;`like_count` 与名单长度一致,inactive 用户的已有赞不计入公开数量。 - POST `/api/v1/explore/posts/{post_id}/like` 响应从完整 `PostResponse` 改为 `PostLikeResponse`:`message: "like successful"`、`like_count`、`liked_by_me`、`liked_by_users`。这是前端需要适配的响应变化,不能用新响应替换完整帖子对象;重复点赞维持幂等行为。 - GET 同一 `/like` 地址新增只查询简短名单功能,不分页,不要求调用者已点赞。DELETE 取消点赞保持返回完整 `PostResponse`,其中名单与状态同步更新。 - 无数据库迁移;复用现有用户资料、媒体、PostLike 数据。名单较大时响应大小及序列化开销会随人数增加。 - 新增两项接口测试,验证有/无头像、签名头像地址、多处帖子响应、评论新增/列表、精简响应字段、重复点赞、多人排序、空名单、取消点赞、inactive 过滤及数量一致性、GET 未登录 401 与帖子不存在 404。本地完整测试 `26 passed in 22.93s`,测试使用临时 SQLite,未操作正式用户或线上数据。 - 已生成并验证 `docs/openapi-0.6.9.json`:同一 /like 路径具有 GET/POST/DELETE,响应分别为简短数组/精简结果/完整帖子。`git diff --check` 通过。 - 已同步 README、中文/英文 API 说明、前端对接清单、Postman 导入说明。共享 Google 文档补充位置和英文粘贴内容在 `docs/Google文档补充-0.6.9.md`,附中文操作说明;未直接编辑 Google 文档或 Apifox。 - 本次代码和新版规范已随提交 `747359b` 推送并发布,正式环境验证结果见下面的 Jenkins 构建 `#42` 记录。 ### 2026-10-15:Jenkins 构建 #42 发布 API 0.6.9 - 发布前确认本地完整自动化测试为 `26 passed`,OpenAPI 版本和代码均为 0.6.9;本次没有数据库结构变化,不执行迁移。 - 代码和文档已提交并推送到 Gitee `main`,提交为 `747359b`(`feat: add post liker summaries and author avatars`)。 - Jenkins Job `1` 的 3 处镜像标签从 `dating-app-api:0.6.8` 更新为 `dating-app-api:0.6.9`,保留数据库预检、容器重建和健康检查,配置中没有一次性迁移块。 - Jenkins 构建 `#42/default` 成功,日志确认拉取提交 `747359b`、生成 `dating-app-api:0.6.9`,并包含 `DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 公网烟测通过:帖子作者的 `profile_image_url` 为可直接读取的 OSS 签名 URL;无头像的评论作者返回 `profile_image_url: null`;完整帖子返回 `liked_by_users`。 - 点赞 POST 只返回 `message`、`like_count`、`liked_by_me`、`liked_by_users`,重复点赞保持幂等;GET 点赞名单按最新点赞在前返回;取消点赞后完整帖子中的数量、状态和名单同步更新。 - 烟测创建的帖子、评论和点赞已随测试帖子删除;3 个随机烟测账号及其中 1 个合成头像保留在正式库中。正式 Base URL 继续使用 `https://melove.youthome.com.cn`,前端应导入 `docs/openapi-0.6.9.json`。 ### 2026-10-15:核对 Dating APP api (3).pdf 与共享文档补充内容 - 用户提供的 PDF 标注版本为 `0.6.7`,内容覆盖注册、头像/视频、当前用户、资料、位置、刷新 token、Meet、滑动、取消按钮、搜索、Explore、公开资料、公开帖子、创建帖子和帖子媒体;它是旧版快照,不能直接覆盖当前 0.6.9 字段。 - 已按 PDF 原有顺序生成可直接复制的 `docs/Google文档完整内容-从Registration-0.6.9.md`,从 Registration API 开始,补入正式 0.6.9 的 `author.profile_image_url`、`liked_by_users`、点赞精简响应、GET 点赞名单和评论作者头像说明,并保留 Cancel Button、Super Like 持续优先级、Explore 分页规则等已确认行为。 - 根据当前代码、正式发布记录和需求覆盖清单,蓝色功能项中已完成并发布的包括注册/登录与 token、头像和介绍视频、位置、Meet 排序、pass/like/super_like、Cancel Button、搜索、Explore、公开主页和帖子媒体。安全部分的 HTTPS、JWT、密码哈希和 refresh token 已实现;PDF 中 AES-256-GCM、混合加密、加密 payload 解密中间层和生产密钥管理仍未实现,不能向前端汇报为已完成。 - PDF 的创建帖子示例没有 0.6.9 新增的 `liked_by_users` 和作者头像字段;复制时应以新文件为准。PDF 中“Music not supported yet”仍然准确。 ### 2026-10-15:接手交接与现状核验 - 新接手方按第 7 节流程通读了本文件、`README.md`、`docs/openapi-0.6.9.json`、`docs/Dating-App-API-前端对接清单.md`、`docs/Google文档补充-0.6.9.md` 和 `docs/Google文档完整内容-从Registration-0.6.9.md`,确认当前交付状态仍为正式版本 `0.6.9`、Jenkins 构建 `#42`。 - 代码核验:本地 `HEAD` 与 `origin/main` 均为 `3350152`(`docs: record API 0.6.9 production release`),工作区无代码改动;本地完整自动化测试重跑结果为 `26 passed in 26.61s`,与第 6 节记录一致。 - 正式环境可连通性核验(只读,未修改线上数据):`POST https://melove.youthome.com.cn/api/v1/auth/login` 使用过短密码返回 `422`,使用不存在的账号返回 `401`;`GET /api/v1/auth/me` 与 `GET /api/v1/feed/questions` 不带 token 均返回 `401`。说明 nginx 到 FastAPI 的转发链路和应用鉴权均正常。 - 本次核验发现一处文档与实际部署不一致:公网域名只把 `/api/v1/...` 转发给容器,`https://melove.youthome.com.cn/health`、`/docs` 和 `/` 都落到 nginx 默认欢迎页(`200` 但内容是 `Welcome to nginx!`),不是应用的 `/health` JSON。`docs/Dating-App-API-前端对接清单.md` 的“Health check `GET {{base_url}}/health`”因此会让前端误判。后续二选一处理:请服务器管理员在 nginx 增加 `/health` 转发,或把前端连通性检查改为调用 `/api/v1/...`;当前本地 `http://127.0.0.1:8001/health` 仍返回 `{"status":"ok"}`。 - 仓库整理:上一次任务生成的 `docs/Google文档完整内容-从Registration-0.6.9.md` 此前只存在于本地且未提交,本次随本记录一并提交;`.gitignore` 增加 `tmp/`,避免 PDF 渲染出的临时图片和截图被误提交。 ### 2026-10-16:英文同事询问 Chat 章节与“创建聊天链接” - 用户提供的微信截图(`问题1.png`,带微信翻译)中,英文同事连问三句:`Hello, bro did you update it`(谷歌文档更新了吗)、`And can you explain the chat section`(解释一下聊天部分)、`Can you check the create chat Link`(检查一下创建聊天的链接)。用户已回复“我在谷歌文档中更新了,您可以看一下”。 - 定位到原因:交付给共享文档的内容 `docs/Google文档完整内容-从Registration-0.6.9.md` 只写到第 18 项(帖子点赞与评论),**没有 Chat 章节**,所以对方看不到聊天接口;他问的“create chat link”就是创建会话的地址。 - 已对照当前代码 `app/main.py` 核验聊天接口:`GET /api/v1/chat/conversations`(会话列表,按最新匹配在前,对方非 active 时跳过,未建会话时 `id` 为 `null`);`POST /api/v1/chat/conversations/{match_id}`(创建或获取会话,无请求体,成功 `201`,重复调用返回同一会话;不带 `match_id` 对 `/api/v1/chat/conversations` 发 POST 返回 `405`;`match_id` 来自滑动响应的 `match_id` 或 `GET /api/v1/matches`,不属于自己的 match 返回 `404`);`GET/POST /api/v1/chat/conversations/{conversation_id}/messages`(`limit` 1–100 默认 50,`before_id` 可选,页内按时间正序;发送 `content` 1–5000,`message_type` 仅 `text`);`DELETE /api/v1/chat/messages/{message_id}`(仅本人可撤回,返回 `content=null`、`is_deleted=true`,否则 `403`/`404`)。本次为只读核对,未修改代码或线上数据。 - 已生成可直接粘贴的英文补充:`docs/Google文档补充-Chat章节.md`,包含插入位置(第 18 项之后、`Requirement Coverage` 之前)、`19. Chat` 全部五个接口的 URL / Authentication / Request / Backend Response 示例与规则,以及 `How Each API Link Works` 需补的两条聊天流程。本次未直接编辑在线 Google 文档,内容需由用户粘贴。 - 待对方确认的差异:聊天响应里的 `other_user` 目前只有 `id`、`full_name`、`city`、`country`,没有头像地址;如果前端按帖子和评论的做法要求聊天列表/会话显示头像,需要作为新需求开发。 ### 2026-10-16:老板新增每周工作汇报要求并交付本周周报 - 老板要求从本周起每周日下午 5 点前通过微信提交周工作总结,形式不限,需覆盖本周开展的工作、发现或解决的问题、对项目或产品的思考以及下周工作安排。 - 已按交接文档中 2026-10-12 至 2026-10-16 的记录整理周报:两批接口开发并上线(API 0.6.8 公开主页字段与取消喜欢名单分页、API 0.6.9 作者头像与点赞名单及点赞精简响应)、本地测试 24 与 26 项全部通过、Jenkins #41 与 #42 两次发布成功、前端与英文同事的联调支持、文档与交接维护。 - 周报同时记录了三类问题与风险:前端参数用法导致的误报(offset 跳页、before_id 留空或与 offset 混用)、对接文档版本落后、公网 /health 与 /docs 未转发到后端;并列出下周计划(跟进 0.6.9 接口导入、处理 /health 转发、确认聊天头像需求、评估加密方案排期、旧测试账号清理需先取得清单或数据库权限)。 - 周报成稿在 `docs/周工作总结-2026-10-12至10-16.md`,可直接复制到微信;本次未替用户发送消息。 ### 2026-10-19:按英文同事微信反馈实现 API 0.6.10(已发布) - 触发来源:工作目录下 1.jpg / 2.png / 3.jpg / 4.png 四张微信截图,同事吴启明(PARVEJ)反馈三点:`For unlike post just return unlike successful`、`you did not give the link for edit comment and post`、`You create post doesn't support image and video together`。 - 实现内容(API 0.6.10): 1. `DELETE /api/v1/explore/posts/{post_id}/like` 从返回完整 PostResponse 改为返回 `PostUnlikeResponse`(`message`、`like_count`、`liked_by_me`、`liked_by_users`),与点赞精简响应保持一致;重复取消保持未点赞状态。 2. 新增 `PATCH /api/v1/explore/posts/{post_id}` 编辑自己的帖子(content、content_format、feeling、location;文字帖必须保留文字/心情/地点至少一项),`PATCH /api/v1/explore/comments/{comment_id}` 编辑自己的评论(content 1-2000 字符);非作者 403,不存在 404,非法 422。 3. 上传帖子媒体改为允许同一条帖子同时含图片和视频:最多 9 张图片 + 1 个视频,两者同时存在时 `post_type` 为 `mixed`;`position` 参数范围放宽到 0-9。 - 无数据库迁移:Post、PostComment 已含 updated_at 等所需字段;复用现有 PostMedia、post_response、post_author_response。 - 测试:新增 `test_edit_post_and_comment` 与 `test_post_supports_image_and_video_together`,并收紧 unlike 响应断言;本地完整测试 `28 passed in 22.72s`。 - 已生成并验证 `docs/openapi-0.6.10.json`(PATCH 帖子、PATCH 评论、DELETE 点赞返回 PostUnlikeResponse 等契约),`git diff --check` 通过。 - 已同步 README、中英文接口说明、前端对接清单、Postman 说明;共享 Google 文档的可粘贴英文内容在 `docs/Google文档补充-0.6.10.md`,附中文操作说明,未直接编辑在线文档或 Apifox。 - 发布前复核补了两个边界修复:PATCH 帖子的 `content`、`content_format` 显式传 `null` 现在返回 422,不再写入数据库非空列;删除混用帖子的图片或视频后会按剩余媒体重新计算 `post_type`(`mixed`/`image`/`video`,无媒体但有正文时回到 `text`)。修正后完整测试仍为 `28 passed`。 - 当前交付状态:代码与文档已提交并推送到 Gitee `main`,功能提交为 `904ae04`(`feat: add post editing and mixed media uploads`);发布结果见下面的 Jenkins 构建 `#43` 记录。 ### 2026-10-19:Jenkins 构建 #43 发布 API 0.6.10 - 发布前确认本地完整自动化测试为 `28 passed`,OpenAPI 版本和代码均为 0.6.10;本次没有数据库结构变化,不执行迁移。 - Jenkins Job `1` 的 3 处镜像标签从 `dating-app-api:0.6.9` 更新为 `dating-app-api:0.6.10`,保留数据库预检、容器重建和健康检查,配置中没有一次性迁移脚本。 - Jenkins 构建 `#43/default` 成功,日志确认拉取提交 `904ae04`、生成 `dating-app-api:0.6.10`,并包含 `DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 公网烟测通过:`PATCH /api/v1/explore/posts/{post_id}` 可编辑正文、格式、心情和地点,非作者返回 403,`content: null` 返回 422;`PATCH /api/v1/explore/comments/{comment_id}` 可编辑评论,非作者返回 403。 - 公网烟测通过:同一帖子成功上传图片和视频后 `post_type` 为 `mixed`,第二段视频返回 409;取消点赞返回 `message`、`like_count`、`liked_by_me`、`liked_by_users`,不含完整帖子,重复取消保持幂等。 - 正式环境现已升级为 API 0.6.10,Base URL 继续使用 `https://melove.youthome.com.cn`。测试帖子、评论、点赞和媒体已随测试帖子删除;3 个随机烟测账号保留在正式库中。前端应导入 `docs/openapi-0.6.10.json`。 ### 2026-10-19:英文同事询问 Search 接口说明 - 同事发来 `Can explain the search link` 和一张 Apifox 截图(保存为工作目录下 5.jpg),截图是 `GET /api/v1/search` 的 Params 页,列出 q、city、country、latitude、longitude、max_distance_km、limit。 - 已对照当前代码 `app/main.py` 的 `search_users` 核验参数语义和排序/过滤逻辑,答复见会话;本次只读核对,未修改代码或数据。 ### 2026-10-19:交付共享 Google 文档 0.6.10 纯文本全文 - 用户提供最新导出 `Dating APP api (6).pdf`(24 页,正文仍标 0.6.9,已含 19 Chat),要求给一份从 Registration API 开始、可直接粘贴的完整内容,并去掉 Markdown 痕迹。 - 已生成 `docs/Google文档完整内容-0.6.10.txt`,共 827 行,纯文本、无 `*`、`#`、反引号和分隔线;结构与现有文档一致(1-19 章 + Requirement Coverage + How Each API Link Works + Typical Frontend Order)。 - 相对 PDF 的更新:版本改为 0.6.10 并标注 Jenkins 43 已发布;第 12 章 Search 补全 q、city、country、latitude、longitude、max_distance_km、limit 及排序规则;新增 16.1 编辑帖子;第 17 章改为最多 9 图 + 1 视频可混用、position 0-9、post_type 为 mixed;第 18 章取消点赞改为精简响应并补编辑评论、删除评论;覆盖清单和调用流程同步更新。 - 本次只生成文档内容,未直接编辑在线 Google 文档。 ### 2026-10-19:按参考模板生成软件著作权申请材料 - 模板来源:`参考模板(1)` 中的 `申请表信息.txt`、`XXX软件使用说明书.docx`、`XXX软件源程序V1.0.docx`;模板本身是骨架,并附有常见驳回点提示(三处软件名称必须一致、代码不能有大量空行和测试注释、说明书不能只有截图)。 - 以本项目服务端为对象生成三件套,软件全称统一为 `MeLOVE交友社交平台服务端软件`,版本 `V1.0`,输出目录 `docs/软著申请/`。 - 申请表信息:按模板字段填写开发/运行硬件、Windows 11 开发环境、Linux+Docker 运行平台、Python 语言、MySQL 8/Nginx/OSS 支撑环境、开发目的、面向领域、主要功能和技术特点;源程序量按提交文档实际行数填 2043。 - 使用说明书:A4 排版,含封面、文件修订记录、目录、总体功能描述、运行环境、编译环境、安装说明、软件使用、设计理论、软件结束、其他功能,以及主要接口清单附录;共 10 页,正文使用宋体小四、页眉含软件名和版本、页脚页码,并在第 4 章嵌入本地 Swagger 接口文档真实截图。 - 源程序:从 `app/` 的实际 Python 源码提取,去除空行和整行注释,长行按 100 字符折行,连续编号,每页 50 行,页眉为软件名+版本+“源程序”,页脚页码;共 2043 行、41 页,A4。 - 已用 Word 导出同名 PDF,供直接提交;Word 与 PDF 均已生成并核对页数。软著名称在申请表、说明书页眉、源程序页眉三处保持一致。 - 说明:当前说明书截图来自本地 Swagger 接口文档,适合服务端软件;如申请主体希望展示移动端界面,需要补充 App 截图后替换图 1。作者栏暂填“项目组”,公司名称、著作权人等信息需用户补充。 ### 2026-10-19:核对前端“已有 match 但列表为空” - 用户提供 7.png、8.jpg:同事吴启明(PARVEJ)反馈 `List matches doesn't return anything`、`This already have a match but returning nothing`;Apifox 截图为 `GET /api/v1/matches`,token 的 sub 为用户 80。 - 已在正式环境做小范围复现:新建两个账号(ID 89、90),互相 like 后第二次滑动返回 `matched=true, match_id=9`;分别调用 `GET /api/v1/matches?limit=20&offset=0`、`GET /api/v1/users/me/matches?limit=20&offset=0`,两边都正确返回该 match,`matches_count` 从 0 变为 1。说明列表接口和 CASE 关联逻辑在线上正常。 - 因此该反馈更可能是请求侧问题:offset 非 0、token 过期或不属于该 match 的账号、另一方账号已停用、match 已被 pass/取消删除。需要对方提供同一 token 下 `GET /api/v1/auth/me` 的 `matches_count` 与 `matches`,以及 `/api/v1/matches` 的完整请求 URL(含参数)和响应。 - 备选修复:若确认是 offset 导致,可参照喜欢名单把 `/api/v1/matches` 与 `/api/v1/users/me/matches` 改为不分页返回全部;本次未改代码。 - 副作用说明:复现用的账号 89、90 及 match 9 保留在正式库(后端没有删除账号的接口)。 ### 2026-10-19:API 0.6.11 匹配列表取消分页(已发布) - 前端反馈:`GET /api/v1/auth/me` 显示有 2 条匹配,但 `GET /api/v1/matches` 返回空。两者使用同一 `user_matches` 查询,唯一可能造成差异的是 `/matches` 请求带了非 0 的 `offset`(例如 20)。 - 修复:`user_matches` 支持 `limit=None`;`GET /api/v1/matches` 和 `GET /api/v1/users/me/matches` 去掉 `limit`、`offset` 查询参数,直接返回全部有效匹配(最近的在前),旧客户端携带这两个参数会被忽略。`/api/v1/auth/me` 内嵌的 matches 数组仍保持最近 20 条预览,`matches_count` 仍为完整总数。 - 测试:在已有匹配测试中补充断言,确认两个匹配接口携带 `?limit=1&offset=20` 时仍返回完整列表;本地完整测试 `28 passed`。 - 版本升至 `0.6.11`,已生成并验证 `docs/openapi-0.6.11.json`(两个匹配接口的 parameters 为空);同步 README、中英文接口说明、前端对接清单、Postman 说明。 - 共享 Google 文档的可粘贴全文已更新为 `docs/Google文档完整内容-0.6.11.txt`,并新增 9.1 Get Matches 小节说明匹配列表不分页。 - 交付状态:代码和文档已提交并推送到 Gitee `main`,功能提交为 `fc520a5`(`feat: return complete match lists without pagination`);发布结果见下面的 Jenkins 构建 `#44` 记录。 ### 2026-10-19:Jenkins 构建 #44 发布 API 0.6.11 - 发布前确认本地完整自动化测试为 `28 passed`,OpenAPI 版本和代码均为 0.6.11;本次没有数据库结构变化,不执行迁移。 - Jenkins Job `1` 的 3 处镜像标签从 `dating-app-api:0.6.10` 更新为 `dating-app-api:0.6.11`,保留数据库预检、容器重建和健康检查,配置中没有一次性迁移脚本。 - Jenkins 构建 `#44/default` 成功,日志确认拉取提交 `fc520a5`、生成 `dating-app-api:0.6.11`,并包含 `DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 公网烟测通过:两个新账号互相 like 后生成 match 10;`GET /api/v1/auth/me` 返回 `matches_count=1` 和对应 `matches`;`GET /api/v1/matches?limit=1&offset=20` 与 `GET /api/v1/users/me/matches?limit=1&offset=20` 均返回该匹配,且与不带参数的结果完全一致。 - 测试滑动已撤销,match 10 已清理;两个随机烟测账号保留在正式库中。正式环境现已升级为 API 0.6.11,Base URL 继续使用 `https://melove.youthome.com.cn`。前端应导入 `docs/openapi-0.6.11.json`,并删除两个匹配请求中的分页参数。 ### 2026-10-19:用户确认发布 API 0.6.11,公网验证通过 - 用户表示已导入 OpenAPI 并在正式环境发布 0.6.11。 - 公网回归验证(新建账号 ID 93、94,match_id 11):`GET /api/v1/matches?limit=1&offset=20` 返回 200 且包含该 match;`GET /api/v1/users/me/matches?limit=1&offset=20` 同样返回 1 条;`GET /api/v1/auth/me` 的 `matches_count` 为 1。证明旧分页参数已被忽略,修复在正式环境生效。 - `/openapi.json` 仍被 nginx 默认页占用,无法从公网直接读取版本号;版本确认以用户发布说明和接口行为为准。 - 验证账号 93、94 及 match 11 保留在正式库(无删除账号接口)。 ### 2026-10-21:个人资料新增 8 个板块字段(API 0.6.12,已发布) - 需求来源:同事微信“Add this information into edit profile / When get me link also should return this”,配图 2-5 为编辑资料页:职业、学历、身高、信仰、吸烟、饮酒、宠物、运动习惯;另有 Display Name、生日年龄、性别、城市、交友目标、简介、兴趣(原有字段)。 - 实现:`user_profiles` 新增 8 个可空字段 `occupation`、`education`、`height_cm`、`beliefs`、`smoking`、`drinking`、`pets`、`exercise`;`PATCH /api/v1/users/me` 可只提交需要修改的字段并支持传 null 清空;`GET /api/v1/auth/me` 和 `/api/v1/users/me` 的 profile 返回这些字段,并新增根据 birth_date 计算的 `age`。 - 校验:occupation/education/pets/beliefs 最多 120 字符,smoking/drinking/exercise 最多 50 字符,height_cm 范围 100-250。原有 full_name 120、bio 2000 的后端上限保持不变(设计稿显示 30/500,由前端限制)。 - 数据库迁移:新增 `sql/migrate_profile_details.sql`,幂等添加 8 个可空列;**必须在部署代码前在正式库执行**。 - 测试:新增资料详情写入与 Get Me 返回、age 计算、height_cm 越界 422 的用例;本地完整测试 `29 passed`。 - 版本升至 `0.6.12`,生成并验证 `docs/openapi-0.6.12.json`;同步 README、中英文接口说明、前端对接清单、Postman 说明;共享 Google 文档全文更新为 `docs/Google文档完整内容-0.6.12.txt`。 - 公开资料(Meet/Search/Match/GET users/{id})本次未加这 8 个字段;如果要在对方的 profile card 上展示,需要下一步扩展 `DiscoveryUserResponse`/公开主页。 - 交付状态:已随 `20613f6` 推送并发布,正式验证结果见本文件后面的 Jenkins `#46` 记录。 ### 2026-10-21:复核同事历史需求并补齐匹配移除、评论回复与评论点赞 - 用户提供 4 张历史/新需求截图,逐条核对: 1. 互相喜欢后加入 match list、从 likes/liked 列表移除 —— 原先未做,本次已实现。 2. 回复评论、点赞评论 —— 原先未做,本次已实现。 3. 取消点赞只返回成功、编辑评论/帖子链接、图片视频可混用 —— 已在 0.6.10 完成并发布,本次不改。 - 匹配规则:`liked_users` 和 `profile_activity_response` 中的两个喜欢名单、`liked_users_count`、`liked_by_users_count` 均排除已匹配用户;匹配列表不变。 - 评论回复:`post_comments` 增加可空 `parent_comment_id` 自关联外键;`CommentCreate` 支持 `parent_comment_id`,父评论必须属于同一帖子,否则 404;`CommentResponse` 增加 `parent_comment_id`、`reply_count`、`like_count`、`liked_by_me`,GET 仍返回扁平列表,由前端按 parent 分组。 - 评论点赞:新增 `comment_likes` 表(comment_id + user_id 唯一)和 `POST/DELETE /api/v1/explore/comments/{comment_id}/like`,返回 message、like_count、liked_by_me,重复点赞幂等。 - 数据库迁移:新增 `sql/migrate_comment_interactions.sql`(parent 列、索引、外键、comment_likes 表),与 `sql/migrate_profile_details.sql` 一起在部署前执行;`sql/schema.sql` 已同步。 - 测试:更新匹配后喜欢名单断言,新增评论回复和评论点赞用例;本地完整测试 `30 passed`。 - 版本保持 `0.6.12`,已重新生成 `docs/openapi-0.6.12.json`,同步 README、中英文接口说明、前端对接清单、Postman 说明和 `docs/Google文档完整内容-0.6.12.txt`。 ### 2026-10-21:0.6.12 代码已推送,迁移与 Jenkins 待有权限者执行 - 已将 0.6.12 的代码、迁移、测试和文档提交为 `20613f6`(`feat: add profile details and comment interactions`)并推送到 Gitee `main`;远端 HEAD 已确认等于 `20613f6`。 - 部署阻塞:生产 MySQL(47.116.134.234:3306,用户 dating)需要密码,本机无可用凭据;Jenkins(47.116.134.234:8080)对未登录请求返回 403,当前 Codex 浏览器会话也没有 Jenkins 标签页/登录态。因此本次未能执行迁移,也未能触发构建。 - 必须先执行迁移再部署,否则 0.6.12 代码读取 user_profiles 新增列会报 Unknown column: 1. `sql/migrate_profile_details.sql` 2. `sql/migrate_comment_interactions.sql` - 迁移后 Jenkins Job 1 三处镜像标签改为 `dating-app-api:0.6.12` 并构建,构建成功后验证:GET /auth/me 返回 8 个资料字段和 age、PATCH /users/me 可写、评论可带 parent_comment_id 并有点赞接口、匹配用户不再出现在喜欢名单。 ### 2026-10-21:Jenkins 构建 #45/#46 完成 API 0.6.12 迁移与发布 - 发布前重跑完整自动化测试为 `30 passed`,代码、OpenAPI 和数据库迁移均来自提交 `20613f6`。 - 首次构建 `#45` 将镜像和一次性迁移步骤放入 Jenkins,但迁移容器缺少 `-i`,heredoc 未传入容器,Python 读取空输入后直接成功退出;随后新容器替换旧版本,正式注册出现 `500`。这是迁移执行方式问题,不是迁移 SQL 或业务代码错误。 - 立即在迁移容器补上 `-i` 并重新构建 `#46`。日志明确包含 `MIGRATION_0612_OK`、`Successfully tagged dating-app-api:0.6.12`、`DATABASE_CONNECTION_OK 1`、`running|healthy`、`DEPLOYMENT_OK` 和 `Finished: SUCCESS`。 - 迁移核验通过:`user_profiles` 的 8 个新列存在,`post_comments.parent_comment_id` 存在,`comment_likes` 表存在。构建完成后已从 Jenkins 配置删除一次性迁移块,只保留 0.6.12 镜像构建、数据库预检、容器重建和健康检查。 - 公网烟测通过:注册与 Get Me 正常,8 个资料字段可写入;生日 `2000-01-01` 返回 `age=26`;评论可回复,`reply_count` 正确;评论点赞/取消点赞正常。 - 公网烟测通过:两个账号互相 like 后形成匹配,双方喜欢与被喜欢名单均排除已匹配用户,`matches_count` 仍为 1。测试匹配、帖子和评论已清理;两个随机烟测账号保留。 - 正式环境现已升级为 API 0.6.12,Base URL 继续使用 `https://melove.youthome.com.cn`。前端应导入 `docs/openapi-0.6.12.json`。 ### 2026-10-25:周报与离职交接资料整理 - 本周周报已整理为 `docs/周工作总结-2026-10-19至10-25.md`,记录 API 0.6.10—0.6.12 的开发、发布、测试和交接状态。 - 当前正式后端版本仍为 API 0.6.12,本地完整自动化测试为 `30 passed`,正式环境 0.6.12 已完成迁移、构建和公网烟测。 - 按交接要求盘点可提交内容:后端源码、测试、SQL 表结构与迁移、Docker/部署文件、OpenAPI 和接口文档可作为代码交接材料;数据库快照、上传文件、日志、实际密钥和用户数据不放入普通代码仓库。 - 目标 Gitea 仓库暂定为 `lishibo/milian`。截至本记录,本机没有可用的 Gitea Personal Access Token,远端 API 返回 `401 token is required`,仓库尚未创建,文件尚未推送。