docs: 补充 Phase 2b 设计文档和实施计划

- 设计文档新增 Mermaid 消息收发时序图
- IMService 依赖注入补充 *redis.Client(未读数 HASH 操作)
- 实施计划同步更新 Redis 依赖和 unreadKeyPrefix

Made-with: Cursor
This commit is contained in:
bujinyuan
2026-03-03 10:28:46 +08:00
parent de9f9c1ee1
commit 1f390fce56
2 changed files with 37 additions and 3 deletions

View File

@@ -127,7 +127,33 @@ IM Service.RecallMessage()
└── PubSub.PublishToUser(receiverID, im.message.recalled) └── PubSub.PublishToUser(receiverID, im.message.recalled)
``` ```
### 3.5 跨模块依赖(接口注入模式) ### 3.5 消息收发时序图
```mermaid
sequenceDiagram
participant Sender as 发送方Client
participant WS as WebSocketHandler
participant IM as IMService
participant DB as PostgreSQL
participant Redis as Redis
participant PubSub as PubSub
participant Receiver as 接收方Client
Sender->>WS: im.message.send {target_user_id, content, client_msg_id}
WS->>IM: SendMessage(senderID, targetUserID, content)
IM->>IM: FriendChecker.IsFriend()
IM->>IM: FindOrCreateConversation()
IM->>DB: INSERT im_messages
IM->>DB: UPDATE im_conversations
IM->>DB: UPDATE im_conversation_members (unread+1)
IM->>Redis: HINCRBY echo:im:unread:{receiverID} convID 1
IM-->>WS: messageID + conversationID
WS-->>Sender: im.message.send.ack {message_id, conversation_id}
IM->>PubSub: PublishToUser(receiverID, im.message.new)
PubSub-->>Receiver: im.message.new {消息详情}
```
### 3.6 跨模块依赖(接口注入模式)
沿用 Phase 2a 的接口注入标准,避免 `im` 包直接 import `contact` 包: 沿用 Phase 2a 的接口注入标准,避免 `im` 包直接 import `contact` 包:
@@ -317,12 +343,15 @@ type IMService struct {
conversationDAO *dao.ConversationDAO conversationDAO *dao.ConversationDAO
messageDAO *dao.MessageDAO messageDAO *dao.MessageDAO
pubsub *ws.PubSub // 复用 Phase 2a pubsub *ws.PubSub // 复用 Phase 2a
rdb *redis.Client // Redis 操作(未读数 HASH
friendChecker FriendChecker // 接口注入 → FriendshipDAO.IsFriend friendChecker FriendChecker // 接口注入 → FriendshipDAO.IsFriend
userInfoGetter UserInfoGetter // 接口注入 → FriendshipDAO.GetUsersByIDs userInfoGetter UserInfoGetter // 接口注入 → FriendshipDAO.GetUsersByIDs
} }
``` ```
Wire 注入链:`contact.FriendshipDAO` → 隐式实现 `FriendChecker` + `UserInfoGetter` Wire 注入链:
- `contact.FriendshipDAO` → 隐式实现 `FriendChecker` + `UserInfoGetter`
- `*redis.Client` → 直接注入(已在 InfraSet 中提供)
### 7.3 IMService 核心方法 ### 7.3 IMService 核心方法

View File

@@ -302,13 +302,18 @@ type FriendChecker interface {
type UserInfoGetter interface { type UserInfoGetter interface {
GetUsersByIDs(ctx context.Context, userIDs []int64) ([]authModel.User, error) GetUsersByIDs(ctx context.Context, userIDs []int64) ([]authModel.User, error)
} }
// Redis Key 前缀(未读数 HASH
const unreadKeyPrefix = "echo:im:unread:"
``` ```
**Step 2: 创建 IMService** **Step 2: 创建 IMService**
Create: `backend/go-service/app/im/service/im_service.go` Create: `backend/go-service/app/im/service/im_service.go`
IMService 注入:`ConversationDAO``MessageDAO``*ws.PubSub``FriendChecker``UserInfoGetter` IMService 注入:`ConversationDAO``MessageDAO``*ws.PubSub``*redis.Client``FriendChecker``UserInfoGetter`
注意:`*redis.Client` 用于操作未读数 Redis HASH`echo:im:unread:{user_id}`
核心方法(参考设计文档第七节): 核心方法(参考设计文档第七节):
- `SendMessage(ctx, senderID, targetUserID, content, msgType, clientMsgID)` — 核心链路:校验好友 → 查找/创建会话 → 写消息 → 更新 last_message → 增加未读 → 推送 - `SendMessage(ctx, senderID, targetUserID, content, msgType, clientMsgID)` — 核心链路:校验好友 → 查找/创建会话 → 写消息 → 更新 last_message → 增加未读 → 推送