chat.list_messages | query before_seq/after_seq/limit/offset/thread_id/author_id 与 ListMessageQuery 逐字一致(lib/service/chat/src/services/messages.rs:207-216,且带 deny_unknown_fields,前端未多送键);响应 MessagePage { items,total,limit,offset,has_more,oldest_seq,newest_seq }(messages.rs:141-149)与前端兜底对象 api.ts:115 完全对齐 |
chat.send_message | body content/nonce/reply_to_id/thread_id/thread_broadcast/attachments/urgent 与 SendMessageCmd(messages.rs:169-188)一致;attachments 前后端都是 string[] ↔ Vec<Uuid>(前端 SendMessageInput.attachments?: string[],chat.ts:65);nonce 走 nz(),空值省略而非发 null,符合 Option<String> |
chat.get_message | pathParams{room_id,message_id} ↔ Path((room_id, message_id)),路由 /chat/rooms/{room_id}/messages/{message_id}(routes.rs:56-60) |
chat.update_message / chat.delete_message | body {content} ↔ UpdateMessageCmd { content: String }(messages.rs:190-193);path 2 段一致 |
chat.bulk_delete_messages | body { message_ids } ↔ BulkDeleteCmd { message_ids: Vec<Uuid> }(messages.rs:195-198);路由 /messages/bulk-delete(routes.rs:51-54) |
chat.forward_message | body { target_room_id, comment } ↔ ForwardMessageCmd(messages.rs:200-206) |
chat.add_reaction / chat.remove_reaction | body { emoji } ↔ ReactionCmd { emoji: String };响应为裸 Vec<ReactionAggDto>(handlers/reactions.rs:32,59),前端 listOf<ReactionAgg> 取法正确 |
chat.list_reactions | 裸 Vec<ReactionUserDto>(handlers/reactions.rs:81-90),前端 listOf 正确 |
chat.set_message_pin | body { pinned } ↔ PinCmd { pinned: bool }(messages.rs:200),路由 PUT .../pin(routes.rs:61-64) |
chat.get_read_state / chat.mark_read | MarkReadCmd { message_id?, seq? }(services/read_state.rs:34-41);响应 ReadStateDto(同文件 18-26) |
chat.list_space_read_states | 响应 SpaceReadStates { items: Vec<ReadStateDto> }(read_state.rs:28-31),前端 state?.items ?? [] 与之一致 |
chat.get_draft / chat.delete_draft | query thread_id ↔ DraftQuery { thread_id: Option<Uuid> }(handlers/drafts.rs:10-13),路由同路径 GET/DELETE(routes.rs:150-155) |
chat.upsert_draft | body { content, thread_id } ↔ UpsertDraftCmd { thread_id: Option<Uuid>, content: String }(services/drafts.rs:20-25) |
chat.create_thread | path (room_id, message_id) + body { name } ↔ CreateThreadCmd { name: Option<String> }(services/threads.rs:42),路由 /messages/{message_id}/threads(routes.rs:74-77) |
chat.list_threads / chat.list_my_threads | list_threads 响应 ThreadPage = Page<ThreadDto>(threads.rs:39),前端读 page.items 正确;list_my_threads 用 PageQuery(handlers/threads.rs:74-83),前端只送 limit 合法 |
chat.get_thread / chat.update_thread | path 1 段 ↔ /chat/threads/{thread_id}(routes.rs:80-83);UpdateThreadCmd 字段名一致(null 三态问题见可疑 #3) |
chat.follow_thread | body { notify_level } ↔ ThreadMemberCmd { notify_level: Option<ThreadNotifyLevel> }(threads.rs:57-61);枚举值 "None" | "All"(packages/apiclient/chat/follow-thread.schemas.ts:105)与前端 'All' | 'None' | null 一致 |
chat.mark_thread_read | body { message_id } ↔ MarkThreadReadCmd { message_id: Option<Uuid> }(handlers/read_state.rs:76-80) |
chat.list_space_presences / chat.get_presence | 分别为裸 Vec<PresenceDto> 与 PresenceDto(handlers/presence.rs:62-72,41-48);前端 listOf / unwrapApi 取法对应 |
chat.create_attachment | body { filename, content_type, size } ↔ CreateAttachmentCmd { filename, content_type, size: i64, description?: Option<String> }(services/attachments.rs:59-65),响应 UploadIntentDto { id, upload_url, expires_secs } |
chat.finalize_attachment | body { width, height, duration_secs } ↔ FinalizeAttachmentCmd(attachments.rs:75-82),path 1 段 ↔ /chat/attachments/{attachment_id}/finalize(routes.rs:122-125) |
chat.voice_config / chat.voice_token | 路由 /chat/voice/config(path 0)与 POST /chat/rooms/{room_id}/voice/token(path 1)(routes.rs:186-187),与 OPS 表 path 值一致 |
chat.voice_participants / chat.voice_space_states | 裸 Vec<VoiceParticipantDto> 与 VoiceSpaceStatesDto(handlers/voice.rs:70-99),前端取法对应 |
chat.list_hands / raise_hand / cancel_hand | VoiceHandsDto { hands, can_moderate, my_state }(services/voice.rs:149-153);三个动作 path 1 段,/@me 删除走 cancel_hand(routes.rs:212) |
chat.approve_hand / deny_hand / revoke_hand / kick_participant | 均为 path 2 段 (room_id, user_id) ↔ Path<(Uuid, i64)>(handlers/voice.rs:223-231,271-279) |
chat.moderate_mute | params: { muted } 走 query(OPS 标 query: true)↔ 后端 Query(ModerateQuery { muted: bool })(handlers/voice.rs:281-313),位置正确 |
chat.get_voice_layout / chat.save_voice_layout | 响应 VoiceLayoutDto { tiles }(services/voice.rs:64-68),前端 data?.tiles ?? {} 正确;请求 VoiceLayoutPatchDto { tiles, removed }(voice.rs:73-80)与前端 { tiles, removed } 一致 |
chat.update_room(空间侧 moveRoom) | parent_id 三态由 deserialize_opt_opt(services/rooms.rs:62-65)真正支持,null 回空间根有效 |
chat.create_room | CreateRoomCmd { name: String, kind?, topic?, is_private, nsfw, user_limit?, rate_limit_per_user?, parent_id? }(services/rooms.rs:501-517),path 1 段 space_name ↔ /chat/spaces/{space_name}/rooms(routes.rs:39-42) |
chat.list_space_rooms | 后端裸 Vec<RoomBriefDto>(services/rooms.rs:69-73,handlers/rooms.rs:24),前端 unwrapApi<RoomBrief[]>(shell-api.ts:40)取法正确 |
chat.list_dms / chat.open_dm / chat.close_dm | Page<DmDto> + PageQuery(handlers/dms.rs:46-53),前端读 items 并送 limit 合法;OpenDmCmd { peer_user_id?: Option<i64> }(services/dms.rs:34-39)与前端 { peer_user_id } 一致;close_dm DELETE /chat/dms/{room_id}(routes.rs:119) |
notifications.list_notifications | query limit/offset/unread/type ↔ ListNotificationsQuery { limit, offset, #[serde(rename="type")] notification_type, unread }(lib/service/auth/src/handlers/list_notifications.rs:13-20,带 deny_unknown_fields);响应 Page<NotificationDto>,前端读 page.items 正确;realtime/client.ts:294 的 {limit:1,offset:0} 同样合法 |
notifications.delete_notification | DELETE /me/notifications/{notification_id}(handlers/delete_notification.rs:9-26),path 1 段一致 |
| 实时回填一致性 | services/realtime/client.ts:316 的 message-create/message-update 回填用 get_message{room_id,message_id},与 REST 同一 DTO(MessageDto);client.ts:294 的 notification-create 回填用 list_notifications?limit=1 取 items[0]——单条字段与 NotificationDto 同源,形状一致 |