spark-server/.cursor/rules/message-deliver.mdc
zhr ae9a71034d feat: implement Spark IM V3 modular monolith
Add HTTP /v1 MVC, TCP send path, groups with server-side member-avatar collage, object-storage upload, and friends/favorites around the architecture-v3 layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 19:52:11 +08:00

22 lines
1.2 KiB
Plaintext

---
description: Message persist, deliver queue, and Redis inbox rules.
globs: internal/module/{message,deliver,inbox,sync,conversation}/**/*.go
alwaysApply: false
---
# Message / deliver / inbox
Send path: permission → INSERT `messages` + UPDATE `conversations.last_msg_id` → `DeliverQueue.Push` → `SEND_ACK`. No ACK if enqueue fails.
Idempotency: `UNIQUE(sender_id, conversation_id, client_msg_id)`. Conflicts return the original `MsgId`.
Queue: `RPUSH` / `BRPOPLPUSH` to `deliver:processing` / `LREM` ack. On boot `RequeueStale`. Dedup with `SETNX deliver:done:{msgId}`.
`DeliverJob` flags: `ExcludeDevice`, `NotPush`, `NotMailbox`. Sender device does not get `MESSAGE`; other devices of the sender must.
Inbox: Redis ZSET `im:dialog:unread|read:{uid}`, preview, unread hash. Mailbox MySQL is only missed push + control events (recall/kick/friend). Never write `NEW_MESSAGE` mailbox for a successful online push.
P2P conversation key is `(user_small, user_big)`. Sync messages with `id > last_msg_id`.
`messages.content` is a BLOB of serialized JSON bytes for a typed payload (text/image/voice/video/emoji/gif/file/location/system). Do not store a raw string. Media bytes stay in object storage; content holds the object key plus metadata.