business: fix contact projection and phone sharing
(cherry picked from commit c0a0e5b52240ed415d3b43ba77659821887bf50b)
This commit is contained in:
parent
d84fa6e126
commit
860e581d06
18 changed files with 703 additions and 36 deletions
|
|
@ -18,7 +18,7 @@ status 取值:done(真实实现) / stub(兼容响应) / todo(已发现未实
|
|||
> PG 集成测试覆盖 AuthKeyStore 与业务 store 往返(TestBusinessStoresRoundTrip)。
|
||||
> active session 已缓存 raw auth_key_id、业务 auth_key_id、session_id、user_id;router 入口只做一次 temp→perm 与 auth_key→user_id 解析,业务服务按 user_id 查询;普通注册 user_id 从 1780243200 起递增。
|
||||
> 二阶段私聊文本消息链路已落地:`messages.sendMessage` 事务内写 `private_messages` / 双端 `message_boxes` / `dialogs` / `user_update_events` / `dispatch_outbox`,`pts` 与 owner 视角 `box_id` 由 Redis 原子计数并可从 PG durable log 恢复;outbox worker 批量推送在线 session,链路指标覆盖发送、限流、outbox claim/deliver/fail。
|
||||
> 联系人与 dialog owner 视角已补齐:`contacts.addContact/importContacts/deleteContacts/updateContactNote/getContactIDs/getStatuses/search`、dialog pinned/manual unread/peer settings、`messages.*DialogFilter*` 与 `folders.editPeerFolders` 均真实落库;`contacts` 保存每个 owner 对同一 user 的独立姓名/电话/备注,`dialogs` 保存置顶顺序、manual unread、action bar 隐藏态与 archive folder_id,自定义 filters 独立存 `dialog_filters`。
|
||||
> 联系人与 dialog owner 视角已补齐:`contacts.addContact/acceptContact/importContacts/deleteContacts/updateContactNote/getContactIDs/getStatuses/search`、dialog pinned/manual unread/peer settings、`messages.*DialogFilter*` 与 `folders.editPeerFolders` 均真实落库;`contacts` 保存每个 owner 对同一 user 的独立姓名/电话/备注,`dialogs` 保存置顶顺序、manual unread、action bar 隐藏态与 archive folder_id,自定义 filters 独立存 `dialog_filters`。
|
||||
> username 生命周期已补齐:注册仍按 Telegram 语义只创建手机号/姓名账号,后续通过 `account.checkUsername/updateUsername` 设置或清除主 username;PG 以 `lower(username)` partial unique index 防并发占用,`contacts.resolveUsername/resolvePhone` 可用于 TDesktop 搜索/链接解析。
|
||||
> 注册资料闭环已补齐:TDesktop 手机号验证码后进入 sign-up 页,`auth.signUp` 携带 first_name/last_name 完成建号;主界面 Settings/Profile 的姓名与 bio 变更走 `account.updateProfile`,写入 `users.first_name/last_name/about` 并向其它设备可靠推送 `updateUserName`。
|
||||
> 联系人 reset、dialog pinned/order/manual unread/peer settings、dialog filters/order/reload、folder peers 已写入账号级 durable update log,并同事务写入 `dispatch_outbox`;离线设备可通过 `updates.getDifference` 恢复这些状态变化,在线其它端由 outbox worker 可靠投递且排除当前 session。
|
||||
|
|
@ -153,7 +153,7 @@ outbox 多 worker 并发 + 发送事务乱序提交 → **主动推送可能乱
|
|||
| messages.getDialogs | done | real | 从按 user_id HASH 分区的 dialogs/message_boxes/users 查询当前账号私聊会话,并合并 channel_dialogs/channels/channel_messages;支持 exclude_pinned、folder_id(0 主列表/1 归档/2+自定义 filter)、offset_date/offset_id/offset_peer seek pagination、limit、hash notModified;channel offset_peer 校验非零 access_hash;channel dialog 返回持久 `read_outbox_max_id`,可恢复离线/丢失的 `updateReadChannelOutbox`;不会把返回的 channel 宽泛标记为 active viewer,避免 typing/reaction 等瞬时事件误推给全体 dialog 列表;登录后可见 777000 官方系统会话 |
|
||||
| messages.getPinnedDialogs | done | real | 从 dialogs + channel_dialogs 合并查询 pinned 会话,返回 top messages/users/channels,并附持久化 update state |
|
||||
| messages.getPeerDialogs | done | real | 按 InputDialogPeer 精确查询当前账号会话,返回 dialog/top message/users/update state;channel peer 同样返回持久 `read_outbox_max_id`;公开 username channel/supergroup 对非成员返回只读 preview dialog/top message,private/ban/kick/view_messages 不暴露;未建会话的 user peer 返回空 dialog 占位;peer vector cap=100 |
|
||||
| messages.getPeerSettings | done | real | 当前 owner 视角 peerSettings:非联系人显示 add/block,联系人显示 shareContact;若该 owner 已 hide peer settings bar 则返回空 action bar;附带当前 owner 视角用户资料 |
|
||||
| messages.getPeerSettings | done | real | 当前 owner 视角 peerSettings:非联系人显示 add/block;当前 owner 已保存对方但双方未 mutual 时显示 shareContact;acceptContact/add/import 形成 mutual 后清除 shareContact;若该 owner 已 hide peer settings bar 则返回空 action bar;附带当前 owner 视角用户资料 |
|
||||
| messages.getMessages | done | real-private | TDesktop reply/webpage/media lazy load 入口;当前按 owner 视角 `InputMessageID` 精确拉取私聊 message_box,ID 不存在返回 messageEmpty,单次最多 100 个 |
|
||||
| messages.getHistory | done | real | 从按 owner_user_id HASH 分区的 message_boxes 按当前账号+peer 查询历史;支持 offset_id、offset_date、add_offset、limit、max_id、min_id、hash,查询条件走分区索引与 seek pagination;`add_offset` clamp 到 `[-100,100]`,避免异常客户端触发超大跳过扫描或内存分配 |
|
||||
| messages.readHistory | done | real-partial | 标记 reader dialog 的 read_inbox_max_id/unread_count 并清 manual unread;真正发生已读时给 reader 生成 updateReadHistoryInbox,同时推进 sender dialog 的 read_outbox_max_id 并生成 updateReadHistoryOutbox;发送消息时不预先推进 read_outbox,避免假已读 |
|
||||
|
|
@ -354,6 +354,7 @@ outbox 多 worker 并发 + 发送事务乱序提交 → **主动推送可能乱
|
|||
| contacts.getStatuses | done | persisted-presence | 返回当前通讯录联系人 `contactStatus`;状态来自运行时 presence、活跃 session 兜底与持久化 `users.last_seen_at`,离线联系人返回精确 `userStatusOffline.was_online`,未知用户退回 `userStatusRecently`。当前未接 account privacy,粗粒度 `recently/lastWeek/lastMonth/empty` 隐私降级仍为后续项 |
|
||||
| contacts.importContacts | done | real | 按手机号匹配已注册用户,写入当前 owner 视角的联系人姓名/电话/备注,返回 imported/users,并写 durable updatePeerSettings + updateContactsReset + dispatch_outbox |
|
||||
| contacts.addContact | done | real | 写入当前 owner 视角联系人资料;禁止 self/空姓名/不存在 user,维护 reverse mutual,并写 durable updatePeerSettings + updateContactsReset + dispatch_outbox |
|
||||
| contacts.acceptContact | done | real-share-phone | TDesktop “Share my phone number” 入口;要求当前 owner 已有该联系人,否则 CONTACT_REQ_MISSING;把当前用户手机号/姓名写入对方 owner 视角联系人,维护 mutual,返回 updatePeerSettings(shareContact=false)+updateContactsReset,并为双方写 durable peer settings / contacts reset |
|
||||
| contacts.deleteContacts | done | real | 删除当前 owner 的联系人关系,并清理对方 reverse mutual;写 durable updatePeerSettings + updateContactsReset + dispatch_outbox |
|
||||
| contacts.updateContactNote | done | real | 更新当前 owner 对某个联系人的备注与备注实体,不影响其它 owner 对同一 user 的备注,并写 durable updateContactsReset + dispatch_outbox |
|
||||
| contacts.search | done | real | TDesktop 搜索框 peer 分支;strip `@`、空/过短查询报 SEARCH_QUERY_EMPTY/QUERY_TOO_SHORT,limit cap=50;联系人 user 进 MyResults,非联系人 user 进 Results;公开 username channel/supergroup 同步返回 PeerChannel + Chats,当前已加入的放 MyResults,其它公开命中放 Results 并以 left chat 标记只读预览,避免 TDesktop 误显示已加入;用户搜索走手机号前缀/username/姓名/owner 保存姓名索引,公开频道搜索走 username/title trgm 索引 |
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ go test ./internal/loadtest/ -run TestMessageSendBaseline -v -count=1 -timeout 3
|
|||
- active session 缓存 `auth_key_id + user_id`;router 额外按业务 auth_key 缓存 `user_id`,并用 singleflight 合并启动期并发 miss,避免同一永久 auth_key 派生的多个 temp session 重复查授权表。
|
||||
- `update_states` 主键是 `(auth_key_id, user_id)`;同设备退出登录或换账号只清 auth_key 设备状态,不删除账号级 `user_update_events`。
|
||||
- 一个账号多设备共享 `user_update_events`,各设备通过自己的 `auth_key_id + user_id` 状态和 `updates.getDifference` 补偿。
|
||||
- 联系人备注、dialog pinned/order/manual unread、peer settings 都是 owner 视角数据;写业务表后同步写账号级 durable update event,并把投递任务写入 `dispatch_outbox`,避免“只在线 push、离线设备永远不知道”的状态漂移。
|
||||
- 联系人备注、联系人 mutual/shareContact 状态、dialog pinned/order/manual unread、peer settings 都是 owner 视角数据;写业务表后同步写账号级 durable update event,并把投递任务写入 `dispatch_outbox`,避免“只在线 push、离线设备永远不知道”的状态漂移。
|
||||
|
||||
## ACK / Global Sequence Note
|
||||
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ internal/store/
|
|||
在线 session 需先完成 `updates.getState/getDifference` 才接收主动 updates,未 ready 的推送先暂存;
|
||||
同时写入账号级 `user_update_events`,`updates.getDifference` 可补偿登录官方消息与官方会话已读事件。—— ✅
|
||||
- **P4 消息闭环**:私聊文本 `messages.sendMessage/forwardMessages/readHistory/editMessage/deleteMessages/deleteHistory`、reply_to/forward header 元数据、双端 `message_boxes`、已读 inbox/outbox 回执、`user_update_events`、Redis `pts/box_id` allocator、transactional outbox、在线 session 批量推送、窗口限流、链路指标和游标分页已落地;媒体、群组/频道、完整 qts/seq 仍是后续阶段。
|
||||
- **P4.1 联系人与 dialog owner 视角**:`contacts.addContact/importContacts/deleteContacts/updateContactNote/getContactIDs/getStatuses` 与 `messages.toggleDialogPin/reorderPinnedDialogs/markDialogUnread/getDialogUnreadMarks/hidePeerSettingsBar/getPeerSettings` 已接入 PG-backed 服务;集成测试覆盖不同 owner 对同一 user 的独立备注、备注 hash、reverse mutual、dialog 用户视角、置顶重排、manual unread 与隐藏 action bar。—— ✅
|
||||
- **P4.1 联系人与 dialog owner 视角**:`contacts.addContact/acceptContact/importContacts/deleteContacts/updateContactNote/getContactIDs/getStatuses` 与 `messages.toggleDialogPin/reorderPinnedDialogs/markDialogUnread/getDialogUnreadMarks/hidePeerSettingsBar/getPeerSettings` 已接入 PG-backed 服务;`contacts.acceptContact` 复用联系人反向 upsert,把当前用户手机号/姓名写入对方 owner 视角并清除双方单向联系人 shareContact action;集成测试覆盖不同 owner 对同一 user 的独立备注、备注 hash、reverse mutual、dialog 用户视角、置顶重排、manual unread 与隐藏 action bar。—— ✅
|
||||
- **P4.2 设置类 durable updates**:联系人 reset、dialog pinned、pinned order、manual unread、peer settings、dialog filters/order/reload 与 folder peers 均写入 `user_update_events`,并同事务写 `dispatch_outbox`;`updates.getDifference` 与 outbox TL 转换支持这些事件,且保存 pinned order / peer settings flags / dialog filter payload / folder peers / exclude auth key,在线 push 不再是唯一通知路径,也不会与 reliable outbox 双重推送。—— ✅
|
||||
- **P4.3 删除消息/清空历史**:`messages.deleteMessages/deleteHistory` 已支持 owner 视角软删除、`revoke` 对端清理、dialog top 重算/删除/`just_clear` 保留空 dialog、`updateDeleteMessages` durable payload(`message_ids` + `pts_count=len(message_ids)`)与 outbox 投递;后续新消息会正常重建被删除的 dialog。—— ✅
|
||||
- **P4.4 Dialog 分组/归档**:`messages.getDialogFilters/updateDialogFilter/updateDialogFiltersOrder/toggleDialogFilterTags` 与 `folders.editPeerFolders` 已接入 PG-backed 服务;集成测试覆盖 folder_id 0/1 主列表/归档、自定义 filter、tags 和归档还原。—— ✅
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue