Files
kefu/im/deploy/im.bchongw.com_部署记录.md
Your NameandClaude Opus 5 acd8933dbb 后端:资料距离、语音图片会员限制、免短信注册、AI 托管回复修复
- 单用户资料接口补上距离:此前只有推荐/附近列表会算距离,资料页和
  聊天头部因此无内容可显示。沿用同一套 haversine 与隐私开关。
- 语音/图片消息可限定会员发送,两个开关在管理端「运营配置」中修改
  (迁移 032)。校验放在 persistMessageContext,HTTP 与 WebSocket
  两条发送路径都覆盖;文本消息永不受限。
- 短信服务关闭时注册不再要求验证码:关掉之后没人能拿到验证码,继续
  要求就等于关闭注册通道。重置密码不做同样放宽,那里缺验证码等于
  凭手机号夺号。app/config 增加 smsVerification 供客户端决定表单形态。
- 修复 AI 托管账号之间不回复:原规则按「发送方是否托管账号」拦截,
  把真人操作测试号的正常对话也挡了。改为标记 worker 自己写入的回复,
  只对 AI 生成的消息跳过入队。
- ai.default_model_id 同时接受模型 ID 与名称,填名称时不再被 MySQL
  静默转成 0 而使配置失效。
- 聊天媒体留存管理与清理任务(迁移 033,两台线上均已应用)。

新增集成测试均针对真实 MySQL:会员限制、免短信注册、AI 入队规则、
默认模型解析、资料距离。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 10:00:08 +08:00

429 lines
36 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# im.bchongw.com 正式环境部署记录
初次部署日期:2026-08-30
宝塔项目接管及 H5 发布日期:2026-08-31
运行方式:宝塔 Go 项目(域名、HTTPS、管理端/H5 网关)+ 独立 MySQL 8.4 LTS(非 Docker)
此前 Go 服务由独立 systemd 管理,没有出现在宝塔 Go 项目列表。现已纠正:后端的启动、停止、重启、日志和开机启动均纳入宝塔 Go 项目管理;原 systemd 服务已停止并禁用,保留用于回滚。
2026-08-31 已进一步将域名与 HTTPS 从原 HTML 网关迁入 Go 项目:`xingyu_im` 直接绑定 `im.bchongw.com:80`,开启外网映射和 HTTPS(443),HTTP 强制跳转 HTTPS。原 HTML 网关的项目记录已合并,网页文件、发布版本、证书及业务数据全部保留,没有重复绑定同一域名。
## 在宝塔哪里操作
| 宝塔入口 | 项目 | 用途 |
| --- | --- | --- |
| 网站 → Go 项目 | `xingyu_im` | 后端启停/重启、运行日志、环境文件、域名管理、外网映射、SSL 和管理端/H5/API/WSS 网关 |
| 数据库 → MySQL | `im`(远程数据库类型,实际连接本机 `127.0.0.1:3307`) | 查看与管理现有 IM 数据库 |
关闭已打开的设置窗口并刷新宝塔项目列表,进入 `xingyu_im → 域名管理` 即可看到 `im.bchongw.com`、端口 `80`;`SSL` 中可看到有效证书和强制 HTTPS 状态。这里的端口 80 是域名绑定入口,不表示关闭 HTTPS;SSL 监听端口为 443。
## 对外地址
- API:`https://im.bchongw.com`
- 健康检查:`https://im.bchongw.com/healthz`
- WebSocket:`wss://im.bchongw.com/ws`
- 管理端网页:`https://im.bchongw.com/admin/`
- uni-app H5:`https://im.bchongw.com/app/`
- 管理 API:`https://im.bchongw.com/admin/v1`
HTTP 会永久重定向到 HTTPS。后端和独立数据库只监听本机回环地址,不直接暴露到公网。
## 服务与目录
| 项目 | 值 |
| --- | --- |
| 宝塔 Go 项目 | `xingyu_im` |
| Go 监听地址 | `127.0.0.1:18888` |
| 当前可执行文件 | `/www/server/xingyu-im/bt/xingyu-api` |
| 启动命令 | `/www/server/xingyu-im/bt/start.sh` |
| 后端生效环境文件 | `/etc/xingyu-im-bt.env`(`root:www 0640`) |
| Go 运行用户 | `www` |
| Go 日志 | `/www/wwwlogs/go/xingyu_im.log` |
| 运维/接管脚本 | `/www/server/xingyu-im/ops`(仅 root 可访问) |
| 旧 systemd 服务 | `xingyu-im.service`,已停止并禁用,不能与宝塔 Go 项目同时启动 |
| 旧后端版本/环境备份 | `/www/server/xingyu-im/releases/20260830-1345`、`/etc/xingyu-im.env` |
| 上传目录 | `/www/wwwroot/xingyu-data/uploads` |
| 宝塔站点目录 | `/www/wwwroot/im.bchongw.com` |
| Go 项目绑定域名 | `im.bchongw.com:80`,外网映射已开启 |
| 宝塔 Nginx 主配置 | `/www/server/panel/vhost/nginx/go_xingyu_im.conf` |
| 管理端/H5/WS 路由扩展配置 | `/www/server/panel/vhost/nginx/extension/xingyu_im/xingyu_routes.conf` |
| Go 项目证书目录 | `/www/server/panel/vhost/cert/xingyu_im`(证书文件链接到 Let's Encrypt 自动续签目录) |
| 网站访问日志 | `/www/wwwlogs/xingyu_im.log` |
| 管理端发布根目录 | `/www/wwwroot/xingyu-admin/releases` |
| 管理端当前版本 | `/www/wwwroot/xingyu-admin/releases/20260831-095050` |
| 管理端入口软链接 | `/www/wwwroot/im.bchongw.com/admin` |
| H5 当前版本 | `/www/wwwroot/xingyu-h5/releases/20260831-091056` |
| H5 入口软链接 | `/www/wwwroot/im.bchongw.com/app` |
| MySQL 服务 | `xingyu-mysql8.service` |
| MySQL 版本 | `8.4.11 LTS` |
| MySQL 监听地址 | `127.0.0.1:3307` |
| MySQL 配置 | `/etc/xingyu-mysql8.cnf` |
| MySQL 数据目录 | `/www/server/xingyu-mysql8-data` |
服务器原有宝塔 MySQL 5.6 保持不变;项目使用独立 MySQL 8.4 实例,避免影响现有网站。该实例通过宝塔自带的“添加远程数据库”功能接入,数据库条目 ID 为 `3`,没有重新建库或迁移业务数据。MySQL 8 实例本身仍由 `xingyu-mysql8.service` 托管;不要通过宝塔软件商店替换原有 MySQL 5.6。
## 常用运维命令
```bash
cd /www/server/panel
./pyenv/bin/python /www/server/xingyu-im/ops/baota_panel_takeover.py status
./pyenv/bin/python /www/server/xingyu-im/ops/baota_bind_go_domain.py verify
systemctl status xingyu-mysql8 --no-pager
tail -n 200 /www/wwwlogs/go/xingyu_im.log
curl -fsS http://127.0.0.1:18888/healthz
curl -fsS https://im.bchongw.com/healthz
/www/server/nginx/sbin/nginx -t
```
后端重启:在宝塔“网站 → Go 项目 → xingyu_im”中点“重启”。不要再执行 `systemctl restart xingyu-im`。启动脚本会等待旧 Go 进程释放 18888 端口,已修复宝塔立即重启与 go-zero 优雅退出产生的端口冲突。
只重新加载 Nginx:
```bash
/etc/init.d/nginx reload
```
验收脚本(会实际重启一次后端,维护窗口使用):
```bash
cd /www/server/panel
./pyenv/bin/python /www/server/xingyu-im/ops/baota_panel_takeover.py verify
```
## 管理员凭据
初始管理员用户名和密码保存在服务器 root 专用文件:
```text
/root/.xingyu-initial-credentials
```
文件权限为 `0600`。首次登录后应在管理端修改密码;引导密码已从 `/etc/xingyu-im.env` 清空,不会在服务重启时重复创建管理员。
## HTTPS 与续签
- 证书:Let's Encrypt
- 当前到期时间:2026-11-28
- 自动续签:`certbot-renew.timer`
- Nginx 重载钩子:`/etc/letsencrypt/renewal-hooks/deploy/reload-baota-nginx`
- Go 项目证书文件:`/www/server/panel/vhost/cert/xingyu_im/fullchain.pem`、`privkey.pem`,软链接到 `/etc/letsencrypt/live/im.bchongw.com/` 下的同名文件,续签后无需手动复制。
- ACME 验证目录:`/www/wwwroot/im.bchongw.com`;Go 路由扩展保留 `/.well-known/acme-challenge/` 的静态验证入口。
- 2026-08-31 域名迁入 Go 项目后,再次执行证书续签 dry-run 成功。
当前续签由 Certbot 负责。不要同时另建一套宝塔自动申请任务;如果以后改用宝塔托管申请,应先安排切换续签机制和证书路径。
检查续签任务:
```bash
systemctl status certbot-renew.timer --no-pager
certbot renew --dry-run --no-random-sleep-on-renew
```
## 前端生产配置
uni-app:
```dotenv
VITE_API_ORIGIN=https://im.bchongw.com
VITE_WS_ORIGIN=wss://im.bchongw.com
VITE_H5_BASE=/app/
```
以上配置保存在项目 `mobile/.env.production`;开发模式仍默认使用本机接口和根路径。运行 `pnpm type-check` 与 `pnpm build:h5` 后,产物位于 `mobile/dist/build/h5`。
管理端:
```dotenv
VITE_BASE=/admin/
VITE_GLOB_API_URL=/admin/v1
```
管理端和 API 使用同一域名,采用相对接口地址,避免跨域配置和域名切换造成的构建耦合。
当前后端 CORS 仅允许 `https://im.bchongw.com`。H5 或管理端部署到其他正式域名后,需要把对应 HTTPS Origin 追加到 `/etc/xingyu-im-bt.env` 的 `IM_ALLOWED_ORIGINS`,再到宝塔 Go 项目中重启。此文件使用 `export KEY=value` 格式,包含密钥,不能放到网站根目录或公开下载。
管理端、H5、WebSocket 及 ACME 路由保存在上述 `xingyu_routes.conf` 扩展中,由宝塔 Go 项目主配置自动包含。维护这些路由时编辑扩展文件,执行 `nginx -t` 成功后再重载。H5 发布脚本 `baota_publish_h5.py` 已兼容此布局;不要重新创建同域名的 HTML 项目。
### 2026-08-31 管理端登录后 404 修复
根因不是缺少伪静态:管理端使用 hash 路由,`#/analytics` 不会发送给 Nginx。原代码的业务路由使用 `dashboard:view` 等权限码作为 `meta.authority`,但路由守卫传入的是 `super` 等角色名,导致已授权页面被错误过滤。
本次修改:
- 路由初始化从 `/admin/v1/auth/codes` 获取最新权限码,按权限码生成本地业务路由;不再混用角色名,也不受旧浏览器“后端菜单模式”偏好影响。
- 刷新页面重新加载权限,替换过期的权限缓存;保留登录后回到原深链接的行为。
- 账号安全页面同样要求登录,仅登录和第三方回调页面公开。
- 新增 7 项路由回归测试;加上原有权限/路由测试,共 18 项通过。类型检查和生产构建通过。
- 新包 SHA-256:`d6fa3ed37a710222dabee9c7e72812f8fe1c4821ff31a1014f484ca4c0b8791b`。
- 新版本通过原子切换 `admin` 软链接上线,旧版 `/www/wwwroot/xingyu-admin/releases/20260830-142433` 保留用于回滚;新目录兼容保留旧版散列资源,避免尚未刷新的标签页加载旧资源时 404。
- 已验证线上登录页面可渲染、新入口/仪表盘 JS 返回 200、入口 HTML 不缓存、API 健康检查和 H5 正常。新版本的生产管理员实际登录及登录后界面验收尚待用户授权;未通过其他方式绕过登录限制。
管理端发布脚本:`/www/server/xingyu-im/ops/baota-publish-admin.sh`。上传构建包至 `/tmp` 后,使用 root 执行:
```bash
bash /www/server/xingyu-im/ops/baota-publish-admin.sh /tmp/admin-build.zip <构建包SHA256>
```
脚本校验构建包、保留旧版本并原子切换网页入口;验证失败自动切回旧版本,不重启 Go、不修改数据库或 Nginx 配置。升级后已打开的管理端页面需要刷新(必要时使用 `Ctrl+F5`)加载新路由代码。
## 验收结果
- 后端单元测试通过并使用 Linux/amd64 静态二进制发布。
- 发布文件 SHA-256:`23ab263e16593b6f588e42bf480e08f364f8f46a12cf8c143077b767860b8b30`。
- 数据库迁移 `001` 至 `026` 全部执行成功,共 66 张业务表。
- 本机和公网健康检查均返回 HTTP 200。
- HTTPS 证书链和域名校验通过。
- 未认证 WSS 握手返回 HTTP 401,证明 WSS 反向代理已进入后端鉴权层。
- 管理员登录、JWT 会话、RBAC 仪表盘接口通过。
- 会员套餐公开接口返回 3 个初始套餐。
- 自动续签 dry-run 成功。
- Go 项目已设置宝塔开机启动/守护,MySQL 8 服务已设置 systemd 开机启动;本次未执行整机重启测试。
- 新增 `/swap-xingyu` 1 GB Swap 作为 OOM 保护,`vm.swappiness=10`。
- 首次管理端发布的 Vue/TypeScript 类型检查及生产构建通过,原生产包 SHA-256:`404b42391f201e4f500f16275941594ae1569459aa44617c8466b021571dcb3f`;当前包见上述登录 404 修复记录。
- 管理端首页、SPA 路由回退、运行时接口配置和管理员登录 API 均通过线上验收。
- 真实浏览器访问自动进入 `https://im.bchongw.com/admin/#/auth/login`,页面控制台无错误、无警告。
- 上一版管理端保留在 `/www/wwwroot/xingyu-admin/releases/20260830-1410`,可通过切换入口软链接快速回滚。
- 2026-08-31 已通过宝塔原生 Go 项目接口执行重启,PID 发生变化,随后本机及公网健康检查恢复正常。
- 宝塔 Go 列表接口返回 `xingyu_im`、`run=true`、`listen=[18888]`、`listen_ok=true`。
- 域名迁入后,宝塔 Go 项目域名接口返回 `im.bchongw.com:80`,外网映射开启;Go 项目 SSL 接口返回证书已启用、强制 HTTPS 已启用、证书到期日 2026-11-28。
- 域名迁入后,HTTP 健康检查返回 301,HTTPS 健康检查、`/admin/`、`/app/` 均返回 200,未认证 WSS 请求返回 401;证书模拟续签再次通过。本次只平滑重载 Nginx,未重启后端或迁移数据库。
- 宝塔数据库连接验证通过,IM 业务表数量保持 66 张;原有网站和数据库未替换。
- H5 类型检查与生产构建通过,发布包 SHA-256:`04f02657050cf0fa4e6d97d3736ec995255f6aef14672048a76266297ff759b0`。
- H5 启动页 → 登录页真实浏览器跳转通过,生产页面使用 `/app/` 资源基址;favicon 返回 HTTP 200,H5/管理端控制台无错误、无警告。
- 宝塔面板 URL 使用自签名证书,自动浏览器被证书校验阻止;面板项目列表、数据库连接及启停采用该服务器实际安装的宝塔模块接口验证,未绕过浏览器证书校验。
## 本次接管回滚备份
- 后端、原站点记录及面板数据库快照:`/www/backup/xingyu-panel-takeover-20260831-085613`
- H5 发布前 Nginx 配置:`/www/backup/xingyu-h5-publish-20260831-091056`
- 域名迁入 Go 项目前的项目/域名记录、面板站点数据库快照和原 HTML Nginx 配置:`/www/backup/xingyu-go-domain-20260831-092720`
- 原后端二进制和原环境文件仍保留;不要在宝塔 Go 项目运行时启动旧 systemd 服务,以免抢占同一端口。
- 面板数据库快照仅用于灾难恢复,不能直接覆盖当前面板数据库,否则会覆盖其他站点后续变更。正常回滚应仅还原本项目的记录和配置。
## 备份范围
至少备份以下内容:
```text
/www/server/xingyu-mysql8-data
/www/wwwroot/xingyu-data/uploads
/etc/xingyu-im.env
/etc/xingyu-im-bt.env
/etc/xingyu-mysql8.cnf
/www/server/xingyu-im/releases
/www/server/xingyu-im/bt
/www/server/xingyu-im/ops
/www/wwwroot/xingyu-admin/releases
/www/wwwroot/xingyu-h5/releases
/www/server/panel/vhost/nginx/go_xingyu_im.conf
/www/server/panel/vhost/nginx/extension/xingyu_im
/www/server/panel/vhost/cert/xingyu_im
/www/server/panel/data/db/site.db
/www/server/panel/data/db/database.db
/etc/letsencrypt
/root/.xingyu-initial-credentials
```
所有包含密钥或密码的备份必须加密并限制访问。
## 2026-08-31 测试用户同步上线
本次仅发布测试用户相关功能到现有宝塔 Go 项目和同域名管理端/H5,没有迁移托管环境,也没有改变支付、短信、对象存储或第三方登录的配置值。
### 数据与显示规则
- 已在生产 `im` 库导入批次 `cn-adults-20260831-v1`,共 **100 人:男 50、女 50**;本次 ID 为 1–100,公开编号为 `TESTCN000001` 至 `TESTCN000100`。
- 每条资料均为 `is_test=1`,有独立的 `test_batch` 字段,昵称带 `测试·` 前缀,个人简介注明虚构测试资料。管理端支持按“测试用户 / 正式注册用户”和批次筛选,客户端的推荐、附近、用户列表和个人主页显示测试标签。
- 头像为 **10 张 AI 生成的虚构中国成年人肖像(5 男、5 女),每张复用 10 次**,并非 100 张不同头像,也非真实用户照片。生成来源说明保存在发布目录 `avatar-provenance.json`。
- 仅创建用户、资料及隐私设置,不创建手机号、有效登录密码、登录会话、实名认证、付费会员、订单、动态或聊天记录。隐私设置关闭虚构在线状态、最后活跃时间和距离展示。
- 导入前正式注册用户为 0;导入后仍为 0。管理端的正式用户、新增、活跃和资料完善率统计排除测试用户,另行显示测试用户数量。
- 重复运行已验证:`created=0, skipped=100`,不会重复新增或覆盖已存在的资料。
### 发布与备份位置
| 内容 | 位置 |
| --- | --- |
| 发布前数据库、后端、环境文件和发布状态备份 | `/www/backup/xingyu-test-users-20260831-113046` |
| 发布结果记录 | `/www/backup/xingyu-test-users-20260831-113046/result.json` |
| 新后端、导入工具、头像、迁移和前端压缩包 | `/www/server/xingyu-im/releases/test-users-20260831-113046` |
| 新管理端目录 | `/www/wwwroot/xingyu-admin/releases/test-users-20260831-113046` |
| 新 H5 目录 | `/www/wwwroot/xingyu-h5/releases/test-users-20260831-113046` |
| 上一管理端目录(保留) | `/www/wwwroot/xingyu-admin/releases/20260831-095050` |
| 上一 H5 目录(保留) | `/www/wwwroot/xingyu-h5/releases/20260831-091056` |
| 发布脚本 | `/www/server/xingyu-im/ops/baota_publish_test_users.py` |
发布包 SHA-256:`9a783aef2f6b37d025a0e33454081d43136f06a863c2c80cb9c87e973627933a`。
后端 SHA-256:`92b306000ab787e2eb20e69daf25cc3374d082a88f7301e24811a2b7d0022d9d`。
管理端 ZIP SHA-256:`eafa92003b31ce78ca24b28576c4dfc5e45a99754de5d004b3c0727575b71e30`。
H5 ZIP SHA-256:`e10e213e293776c67f8e248eaf2d56735bd122ce6d279a6a156efc2cccce0b57`。
### 迁移和运行目录注意事项
生产原有迁移 001–026 校验一致,本次仅新增执行 **028_test_users.sql**。工作区中另一批原生 App 第三方登录功能未合并到本次后端发布,**027_app_oauth_login.sql 仍未执行**。不要因版本号存在间隔而直接补执行它,后续发布该功能应单独评估、部署和验证。
发布目录中的 `backend-source.zip` 是本次实际构建的后端源码快照,已隔离未发布的原生 OAuth 改动;本地对应源码目录为 `.tools/test-users-release-20260831/backend`。当前开发工作区并不等同于这份生产快照,不能以最新的工作区内容代替本次发布产物复现。管理端和 H5 以本次归档的 ZIP 和上述哈希为准;本地 `dist` 可能被后续构建替换。
H5 的 OAuth 请求已兼容线上严格 JSON 解码:不发送空 `appProof` 或 H5 不需要的 `platform` 字段;有值的原生 App 字段仍保留在开发源码中。
发现线上存储配置为 `storage.local.directory=./uploads`,宝塔实际工作目录为 `/www/server/xingyu-im/bt`,该相对目录原先不存在。本次创建软链接:
```text
/www/server/xingyu-im/bt/uploads -> /www/wwwroot/xingyu-data/uploads
```
头像保存到既有持久化目录,并经 `https://im.bchongw.com/uploads/<文件名>.png` 访问。没有改动原有存储配置值,也没有覆盖其他头像文件。
### 本次验收
- 后端源码快照 `go test ./...`、管理端类型检查/生产构建、H5 类型检查/生产构建通过;测试标签与 OAuth 请求兼容回归用例通过。
- 数据库独立复核:100 条测试资料、100 个测试昵称标签、男女各 50;正式注册用户数量保持 0。
- 所有 10 张头像均经 HTTPS 返回 200 和 PNG 内容;生产入口 HTML 与发布包一致,管理端入口 JS、用户管理/仪表盘模块及 H5 测试标签模块的响应内容 SHA-256 与发布包一致。
- `/healthz` 返回 200;管理接口、推荐接口和 WebSocket 在未登录时均返回 401,未为测试或验收创建管理员会话。
- 订单、动态、聊天消息、订阅、用户会话数量均保持 0,管理员数量保持 1。
- Go 服务通过宝塔原生项目管理接口重启,未启用旧 systemd 服务;前端以软链接原子切换,保留旧散列资源,未改动 Nginx 配置。
- 初次发布时,验收脚本仅读取首条 `Cache-Control`,误判管理端缺少 `no-store` 并自动回退应用。实际响应同时含有 `no-cache` 与 `no-store, no-cache, must-revalidate` 两条头。本次修正为读取全部同名响应头,校验已导入批次和备份后恢复相同发布包,最终验收通过,没有重复导入或恢复整库。
- 发布前数据库 gzip 备份完整性复核通过。备份仅限 root 访问;不得直接恢复整库覆盖发布后的真实注册或业务数据。
- 本次未进行生产管理员登录后的真实浏览器验收,未绕过此前的登录授权限制。
访问 [管理端用户管理](https://im.bchongw.com/admin/#/users),将用户类型筛选为“测试用户”;访问 [H5](https://im.bchongw.com/app/) 后刷新加载新版。已安装的原生 App 不会因网页发布而自动升级,新版专用标签组件需要重新构建/安装 App;测试资料和昵称前缀已经由服务端提供。
## 2026-08-31 测试头像迁移至腾讯云 COS
根据用户后续指示,将上文 100 个测试用户共用的 10 张头像上传至管理端已配置的腾讯云 COS,并替换生产数据库链接。
- 存储桶:`gz-1349751149`,区域 `ap-guangzhou`。
- 对象前缀:`media/test-users/cn-adults-20260831-v1/`;对象名包含原文件 SHA-256 的前 20 位及原文件名,防止缓存混淆和名称冲突。
- 新地址格式:`https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/media/test-users/cn-adults-20260831-v1/<sha20>-<原文件名>.png`,无临时签名和过期查询参数。
- 备份目录:`/www/backup/xingyu-cos-avatars-20260831-115707`。`before.json` 保存逐用户的新旧链接和文件摘要,`uploaded.json` 保存对象上传结果,`result.json` 保存迁移统计;目录权限 0700,文件权限 0600。
- 已新增上传 10 个对象,匿名 GET 逐张验证与本地 PNG 内容一致后,在单个 MySQL 事务中更新 100 条 `user_profiles.avatar_url`;再次核对 COS 链接 100 条、原本地头像链接 0 条,男女数量仍各 50。
- 外部网络独立检查全部 10 个 COS URL,均返回 HTTP 200 和 `image/png`。原本地文件全部保留,不删除也不覆盖其他对象。
- 线上在迁移前已选用 `tencent_cos`;本次未修改任何系统配置值,也没有修改任何对象 ACL 或存储桶权限。凭证仅在服务器进程内读取解密,没有打印或复制到本地。
- Go 主服务 PID 保持不变,无需重新部署前端或重启后端。客户端/管理端重新加载用户列表即可获取新地址。
迁移工具源码:`backend/cmd/migrate-test-avatars-cos`;服务器工具:`/www/server/xingyu-im/ops/migrate-test-avatars-cos`。本次二进制 SHA-256 为 `68d55ce62b2e515f5e0dee27ff048353e13477f434f0f875a43cf400250e52fc`。离线回归测试覆盖配置密文兼容、路径和 HTTPS 校验、重复上传不覆盖、已有对象冲突拒绝、匿名访问和内容一致性。
如需撤销本次头像链接修改,仅针对 `before.json` 中的用户逐行核对当前链接仍等于记录的 `newUrl`,再在事务内恢复为 `oldUrl`;不能覆盖后来由用户或管理员修改的头像,不能恢复整库覆盖后续业务数据。先确认本地旧地址可访问,COS 对象也应保留到引用核对结束。
## 2026-08-31 应用功能发布(12:11)
用户授权“部署线上”后,已将本次后端、管理端及 H5 发布到现有宝塔项目。此次发布替代上文测试用户版本;没有改动 Nginx、服务器环境变量或已有支付、短信、存储及第三方登录配置值。
- 管理端“用户管理”增加“新增用户”,后端新增 `users:create` 权限,并授予现有超级管理员角色。
- 密码取消长度和字符复杂度限制,移除前端强度提示;仍保留必填、旧密码身份验证和两次输入一致性检查。原 bcrypt 密码兼容,超过 bcrypt 字节上限的新密码采用 Argon2id 保存,不截断输入。
- 上线 App 第三方登录接口及管理端 App 渠道开关;现有渠道启用状态保持不变,新 App 开关默认关闭,需要有效的平台参数及对应客户端配置才能使用。
- H5 使用正式 HTTPS/WSS 地址。原生 App 的服务器地址修正、登录入口和表单变化仍需重新构建并安装 App,不会随本次网页发布自动更新。
### 发布产物与备份
- 服务器发布目录:`/www/server/xingyu-im/releases/application-20260831-121140`。
- 管理端当前目录:`/www/wwwroot/xingyu-admin/releases/application-20260831-121140`。
- H5 当前目录:`/www/wwwroot/xingyu-h5/releases/application-20260831-121140`。
- 发布包 SHA-256:`865952392f733cefcdd9ad257fd701a55be57c434a55f381a7045a5b035d0c17`。
- 新后端 SHA-256:`54e699a73fd6d3cec7baae3b1224a03cca6f2ddfdcb91c23f05e1fa258514b56`。
- 备份目录:`/www/backup/xingyu-application-20260831-121140`,权限 0700。包括发布前完整 `im.sql.gz`、原二进制、兼容回滚二进制、环境文件及发布前后状态记录;数据库和环境文件权限 0600。
- 本次应用迁移 `027_app_oauth_login.sql` 和 `029_admin_create_users.sql`,保留已上线的 028;数据库现有 001–029 共 29 条迁移记录,历史校验值一致。
- 本地发布包和源码快照:`.deploy/application-20260831-120612`。服务器发布目录中的 `backend-source.zip` 归档了实际构建源码、兼容回滚源码及测试夹具,不在公开网站目录内。
前端保留旧散列资源,入口软链接原子切换;后端通过宝塔 Go 项目接口重启。若需回滚,使用备份中的 `xingyu-api-compatible-rollback`(SHA-256:`c041e6549b06e32314e131cabcdc5bd2035ae08f494feb5cb3f5b8b332d1035b`),并将前端软链接切回各自的 `test-users-20260831-113046` 目录。此回滚程序基于上一线上源码,只补充 Argon2id 密码验证,以免新长密码在回滚后无法登录;不要直接使用不支持新哈希的原二进制。增量迁移保留,不得恢复整库覆盖发布后的数据。
### 本次验证
- 新后端及兼容回滚源码快照的 `go test ./...` 均通过,管理端及移动端类型检查通过,管理端与 H5 生产构建通过。
- 公网 HTTPS 证书校验通过;管理端、H5、健康检查和 App/H5 登录渠道接口均返回 200。两个入口 HTML 和 5 个入口资源的内容与发布包一致,入口 HTML 包含 `no-store`。
- 管理接口及 WebSocket 未登录请求均返回 401;未为验收创建账户、修改密码或创建管理员会话。
- `/proc` 中唯一运行的后端进程 PID 为 733469,运行映像摘要与新后端一致,确认不是仅替换了磁盘文件。
- 发布前后现有配置值及测试用户资料指纹一致;100 个测试用户的 COS 头像保持不变。复核时用户总数 100、管理员 1、用户会话 2、订单 0、动态 0,未导入额外测试数据。
- 数据库备份 gzip 完整性验证通过,回滚材料已保留;未实际执行生产回滚,也未进行登录后的业务写入验收。
访问 [管理端](https://im.bchongw.com/admin/) 或 [H5](https://im.bchongw.com/app/) 后强制刷新加载新版。如已有会话未刷新到新增权限,可退出后重新登录。
## 2026-08-31 IM 未读数与时间格式修复(12:47)
针对 App 给对方发消息后自己的列表出现未读红点、时间显示 `NaN:NaN` 的问题,已发布后端小范围修复。
- 原先使用 `last_seq - read_seq`,把自己发出的消息也计入未读。现按会话成员实际收到的消息统计:发送者不是本人、序号超过已读/清空/加入位置,且消息未撤回或被管理端下架。发送消息不会自动清除之前尚未阅读的对方消息。
- `lastMessageAt` 由直接返回 `sql.NullTime` 对象改成 RFC3339 时间字符串;没有消息时返回 `null`。
- HTTP 读取消息、更新已读状态会通过 WebSocket 通知当前用户的其他连接;已读位置不会超过实际消息序号,失败不会假装成功。
- 发布前只读检查发现 2 个只有自己发信、却被旧逻辑标为未读的会话。没有为修复清空聊天、修改 read_seq 或创建测试会话,旧记录由新计数逻辑自动正确展示。
本次基于 12:11 实际生产源码,只修改 `backend/internal/app/im.go` 并加入其回归测试;发布前逐文件核对归档差异恰为这两项。保留 App OAuth、管理员新增用户和密码处理等已上线功能,001–029 迁移未改动或重跑,管理端和 H5 发布目录未切换。
- 后端发布目录:`/www/server/xingyu-im/releases/im-unread-20260831-124713`。
- 后端 SHA-256:`812ceedad7a7714ad9d04558946370d5665b0a2a9231b0e1282cb65def9f03ab`。
- 发布包 SHA-256:`230a4755988c2dc4c90a10f00955445e655e11dd6719ece5985707d45f010017`。
- 回滚备份:`/www/backup/xingyu-im-unread-20260831-124713/xingyu-api-original`,其摘要为上一版 `54e699a73fd6d3cec7baae3b1224a03cca6f2ddfdcb91c23f05e1fa258514b56`;目录 0700,另有 `before.json`、`result.json`。
- 经宝塔原生 Go 项目重启后,唯一服务进程 PID 为 733915,运行映像摘要与发布文件一致;`/healthz` 正常,未登录的会话接口、管理接口、WebSocket 均返回 401。
- 发布脚本:`deploy/baota_publish_im_unread.py`,包含生产版本检查、源码差异白名单、迁移一致性检查、二进制备份及失败自动回滚。回滚只替换应用二进制,不恢复数据库。
本地验证通过:后端完整测试;隔离 MySQL 中 8 个 HTTP/WebSocket 收发、重复发送、已读、撤回、下架等场景;客户端 6 个回归用例(含实际聊天页隐藏后不再标已读、HTTP/WS 回显去重、陈旧请求不恢复红点、旧时间格式兼容);加上图标、原生组件和测试标签共 19 个客户端用例;Vue 类型检查及 App/H5 生产构建。
客户端代码还修复了重复回显、隐藏聊天页误标已读、返回列表及多连接未读同步。这部分在本地 `mobile`,App 资源位于 `mobile/dist/build/app`,**没有生成或安装签名 APK,也没有把这批客户端改动发布到线上 H5**。已安装 App 重新进入消息页即可取得后端修正后的未读数和时间;要包含全部客户端修复,需重新同步运行或打包安装。未进行生产账号登录后的真机验收。
## 2026-08-31 头像缩略图上线(18:00)
用户授权“部署上线”后,已发布头像处理后端和新版 H5。后端以 12:47 的实际生产源码为基础,只有头像处理、对应测试、文档及依赖共 9 个文件变化;聊天未读修复、密码规则、管理员新增用户和 App OAuth 等现有功能保持不变。没有执行数据库迁移,也没有修改 Nginx、存储配置、原有头像或聊天记录。
- 新版 H5 头像上传发送 `purpose=avatar`,服务端生成最长边 640px 展示图、256px 缩略图,并保留实际上传的原文件。小头像使用缩略图,推荐卡片使用展示图;加载缩略图失败时回退一次到展示图。
- 普通图片、封面、语音和证据上传保留原逻辑。历史头像及第三方头像没有批量下载或替换,不会因本次发布自动变小。
- H5 从本次冻结的 `mobile` 源码构建,包含此前已在本地完成的聊天同步、图标和原生组件兼容修复;这更新了上文“尚未发布客户端改动到 H5”的状态。管理端静态目录没有切换。
- 当前采用 `tencent_cos`,生成文件使用原有存储配置,不启用云端图片处理或调整对象 ACL。
### 产物及回滚
- 后端发布目录:`/www/server/xingyu-im/releases/avatars-20260831-180014`。
- 后端 SHA-256:`b7eeb926d063855e4271815872ba8c90e226554a3824d48e0995479a671e546e`。
- 发布包 SHA-256:`28901eeaa88355886cf74899b4e3390cb0baeb5275c1126024f884b34731b404`。
- 后端源码归档 SHA-256:`bc6c1bafc57d3b7e772e7823d89485d6dbce6cc11ff33fc74a01878665a73f10`。
- H5 目录:`/www/wwwroot/xingyu-h5/releases/avatars-20260831-180014`;H5 ZIP SHA-256:`00facb91404f06147e9d1f85d872fcc8019878e3a09e45dee8c156db74665214`。
- 备份目录:`/www/backup/xingyu-avatars-20260831-180014`,权限 0700;包括旧二进制、权限 0600 的完整数据库 gzip 备份,以及发布前后状态 JSON。
- 回滚目标:旧二进制摘要 `812ceedad7a7714ad9d04558946370d5665b0a2a9231b0e1282cb65def9f03ab`,旧 H5 目录 `/www/wwwroot/xingyu-h5/releases/application-20260831-121140`。旧前端资源已兼容保留,切换通过软链接完成。若回滚仅替换程序和前端入口,不恢复数据库覆盖发布后的业务数据。
- 发布脚本:`deploy/baota_publish_avatars.py`。发布目录保存 `backend-source.zip`、`mobile-source.zip`、构建产物、校验清单和脚本;本地对应 `.deploy/avatars-20260831-175508`。
### 验证结果
- 隔离后端源码完整测试通过;冻结的前端源码类型检查、49 项回归测试和 H5 构建通过。
- 服务器执行与发布源码一致的 Linux 测试二进制,11 个选定测试及其子用例全部通过,覆盖头像生成、方向校正、GIF/WebP、尺寸限制、实际 HTTP 上传/读取、失败清理和普通媒体兼容。这些测试仅使用临时目录、内存数据库/存储,不接触生产账号及 COS 对象。
- 通过宝塔 Go 项目重启;验证唯一运行进程 PID 9373,其 `/proc` 运行映像摘要与新后端一致。
- 公网 HTTPS 证书校验通过,H5 的全部 84 个文件内容摘要与本次发布包一致;健康检查、管理端访问正常,上传接口、会话接口及 WebSocket 的未登录请求均返回 401。
- 发布前后配置值与 100 个测试用户头像指纹一致。复核用户 100、资料 100、管理员 1、媒体记录 0、聊天消息 5、迁移记录 29;未为验收创建账户、修改头像或写入媒体记录。
- 完整数据库 gzip 备份校验通过;没有实际执行生产回滚,也没有进行生产用户登录后的 COS 上传或真机验收。
访问 [H5](https://im.bchongw.com/app/) 后强制刷新即可使用新上传流程。已安装的 App 不会随网页发布自动升级,需要重新打包安装;本次未生成或安装签名 APK。
## 2026-09-01 测试头像缩略图补齐(11:06)
排查 App“附近”列表头像加载慢时,确认 10 个测试头像的 `-thumb.jpg` 对象全部返回 404。客户端因此先等待缩略图失败,再回退下载约 1.8–2.0MB 的 PNG 原图,每张头像产生两次请求。
- 已在原 COS 前缀 `media/test-users/cn-adults-20260831-v1/` 下新增 10 个确定名称的 256px JPEG 缩略图,原 10 个 PNG 对象未覆盖。
- 外网独立 HEAD 复核 10/10 均为 HTTP 200、`image/jpeg`,单张 8,630–13,355 字节;10 张合计由原图 19,859,686 字节降至 110,178 字节,减少 99.45%。
- 生产数据库中 100 条测试用户头像链接前后指纹一致,更新行数为 0;未修改 COS 配置、用户资料或其他媒体。
- 备份与验证记录位于 `/www/backup/xingyu-cos-avatars-thumbnails-20260901-110619`,目录仅 root 可读。迁移二进制 SHA-256 为 `9516326bb0cd9b3e5090ee0a567de164bbfa8644545b5c7021918ea56ff92695`。
- 此操作只新增静态对象,无需重启后端。客户端重新进入“附近”页后即可直接请求缩略图。
## 2026-09-03 语音上传兼容修复(10:20)
已将手机录音上传兼容修复发布到 `im.bchongw.com`。服务端新增对无 ID3 标签、直接以 MPEG 音频帧开头的 MP3 录音识别,并兼容客户端显式传入 `purpose=voice`;原有图片、头像和普通媒体上传契约保持不变。
- 发布目录:`/www/server/xingyu-im/releases/voice-upload-20260903-102001`。
- 回滚备份:`/www/backup/xingyu-voice-upload-20260903-102001/xingyu-api-original`。
- 新后端 SHA-256:`ac1b0c9f5a48b2386fbecb604003fc97299951e580c97e02f8765e1e0228deee`。
- 上一后端 SHA-256:`b250dd522a74a8812d392e5ed3ae17b2981c799978abf402770dfff1c7442086`。
- 源码归档 SHA-256:`0dbc6fd23c2bd8e69cc0a15e21d3b1f5b60e7586c91dd20ef486a46071ad047b`。
- 本次没有数据库迁移、业务数据写入、Nginx 改动或前端目录切换。
发布前完整执行 `go test ./...`,包含裸 MPEG Layer III 录音上传回归用例。发布后宝塔 Go 项目 PID 为 `58246`,磁盘文件与 `/proc` 运行映像摘要均为新版本;本机和公网健康检查返回 200,未认证媒体上传请求返回 401。
## 2026-09-03 聊天媒体查询修复(11:50)
管理端“聊天媒体”页面已发布,但数据库漏执行 `033_chat_media_management.sql`,导致列表接口查询不存在的 `im_message_media` 表并返回“查询聊天媒体失败”。本次先完成整库 gzip 备份,再补执行该迁移。
- 数据库备份:`/www/backup/xingyu-chat-media-migration-20260903-115013/im.sql.gz`,备份目录权限 0700、文件权限 0600,gzip 完整性检查通过。
- 迁移:`033_chat_media_management.sql`,SHA-256 `677c8dfe790e5996326f29967e41dba1f6a2a8018112be7eb42dc9fab1c600df`;迁移记录与工作区文件校验值一致。
- 历史媒体消息 0 条,管理表 0 条;列表联表查询与统计查询均执行成功。
- 自动清理保持关闭,默认保留天数为 90 天;本次未删除、覆盖或上传任何聊天文件。
- 管理端发布目录仍为 `/www/wwwroot/xingyu-admin/releases/20260903-112753`。宝塔实际运行二进制 `/www/server/xingyu-im/bt/xingyu-api` SHA-256 为 `5a97957780900428cc106f2140d640d2d04963729eeeefb396fc8fffc32763a4`,已包含聊天媒体接口,与副站一致,无需重启。
- 复核 `https://im.bchongw.com/healthz`、管理端入口均返回 200;未登录访问聊天媒体接口返回 401,确认路由与鉴权正常。