# 更新日志 本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/),版本号形如 `v主版本.次版本.修订号`。 ## [v1.0.0] - 2026-10-01 首个正式版本:一个可运行、可阅读的即时通讯 / 客服系统。 ### 新增 - **注册 / 登录**:JWT + bcrypt;「请记住我」把登录态写进 `localStorage`,token 剩余有效期不足 12 小时时自动续签。 - **单点登录**:同一账号在别处登录后旧 token 立即失效,前端提示「账号在别处登录」并自动清理本地态跳回登录页。 - **好友关系**:按账号 / 昵称模糊搜索,发起 / 同意 / 拒绝好友申请;对方已申请我时我再申请等价于互相确认,直接成为好友。 - **实时聊天**:WebSocket 投递,支持文本、emoji 与图片表情(`content_type=image`);对方不在线时进入离线队列,上线后按原顺序补发。 - **未读数**:服务端按已读游标算出,打开会话即标记已读。 - **好友管理**:删除好友是单向软删除(只清我这一侧的列表与记录),拉黑是单向拦截(仅拦截「被拉黑方 → 拉黑方」方向),可随时移出黑名单自动恢复。 - **业务事件**:`friend_request` / `friend_accepted` / `not_friend` / `unfriended` / `blacklisted` 主动推送。 - **聊天页面**:同一套 DOM 响应式适配 PC 与手机,亮色 / 跟随系统 / 深色三态、字号与字重可调、中英文切换,设置落 `localStorage`。 - **SVG 头像**:`GET /avatar?name=&label=` 按用户名哈希配色动态渲染并缓存,服务不依赖任何图片资源。 - **健康检查**:`GET /healthz` 返回当前在线连接数。 ### 实现要点 - 主键选型:`im_user` / `im_friend_request` 用雪花 ID,`im_message` 用 UUID v7,均由应用侧在落库前生成且整体按时间递增;对外一律按字符串序列化,避免前端大整数精度丢失。 - 分层单向依赖:`api / ws / task → service → dao → db`;推送实现 `*ws.Hub` 在 `main` 中经 `service.SetNotifier` 注入,业务层不反向依赖 `ws` 包。 - 消息链路:收到上行报文 → 补全发送者资料 → 扇出给接收方全部连接 → 无活跃连接则写入离线队列 → 同时投递待落库队列,由后台任务 `BRPOP` 阻塞消费写入 PostgreSQL,失败转错误队列而非丢弃。 - 未读数用已读游标(`GREATEST` 保证并发下只前进不后退)而不是逐条打已读标记:消息异步落库,用游标可避免「标记已读早于消息落库」造成的假未读。 - 删除好友 / 拉黑 / 清空会话都只写 `im_contact_state`,`im_friend` 行始终保留。 - 发送前双向校验「仍互为好友」与「接收方未拉黑我」,不通过则既不转发也不落库,只回一个事件并让前端撤回乐观渲染的消息。 - 连接保活:服务端 54s 发一次 ping,客户端 60s 内无响应判定断线;单次写超时 10s,发送缓冲写满即断开该连接而不阻塞其他用户。 ### 工程 - 前端是原生 Vue 2 + Axios 静态页,由后端直接托管,无构建流程、无外部图片资源。 - 配置集中在 `config.yaml`,除 `seed.*` 外都能用 `IM_*` 环境变量覆盖。 - 演示数据 `seed` 默认关闭,开启后幂等写入演示账号并两两互加好友,开箱即可互发消息。 - `docker-compose.yml` 提供 PostgreSQL + Redis;应用监听 `SIGINT` / `SIGTERM`,退出时等待 10s 让在途请求结束并关闭数据库连接。 - HTTP 不设写超时(WebSocket 长连接会被掐断),只设读超时与空闲超时。 - `bootstrap.min.css` 按页面实际用到的 class 从 121KB 裁剪到约 12KB,裁剪脚本在 `tools/`。 - `build.sh` 交叉编译 windows / linux / macOS(amd64 / arm64)共 6 个平台的归档(含 `config.yaml`、`web/` 与 `start.sh` / `start.bat` 启动脚本)并生成 `checksums.txt`;推送 `v*` 标签由 GitHub Actions 自动创建或更新 Release。 - Windows 启动脚本 `start.bat` 在进程退出后保留窗口并显示退出码与常见失败原因,不会闪退;脚本自身保持纯 ASCII,避免 `chcp 65001` 下 cmd 解析多字节字符出错。 - 入口包内嵌 IANA 时区数据库(`_ "time/tzdata"`):没装 Go、系统也没有 tzdata 的机器(典型是 Windows)同样能解析 `timezone: Asia/Shanghai`,否则 pgx 建连时直接报 `unknown time zone`。 - Release 说明取自 `docs/release-notes/.md`,本文件为中文版本历史。 ### 测试 - `tools/e2e` 是只依赖被测接口(HTTP + WebSocket)的端到端回归脚本,覆盖「注册 → 登录 → 搜索 → 加好友 → 在线消息 → 聊天记录 → 已读 → 离线消息 → 登录态」全链路,以及拒绝重申请、互相申请直接成为好友、并发消息、超长消息、伪造 `sender` 等边界。 - 当前基线:**94 项断言全部通过**;全部通过时退出码为 `0`,任一项失败为 `1`,可直接接入 CI。 ### 已知局限 - 无 TLS:HTTPS / WSS 需由前置反向代理终结,并透传 `Upgrade` / `Connection` 升级头。 - 消息异步落库:正常情况下毫秒级完成,极端情况下接口返回与持久化之间存在极短时间差。 - 单会话最多返回 200 条历史消息,未提供向前翻页。 - 多实例部署必须为每个实例显式配置不同的 `snowflake.node_id`(0~1023),否则同毫秒内可能生成重复的用户 / 好友申请 ID。 - 在线状态由单进程内存中的连接中心维护,跨实例需共享 Redis 中的在线集合。 [v1.0.0]: https://github.com/kite88/mini-im/releases/tag/v1.0.0