资讯动态

基于 SpacetimeDB 构建 Discord 风格实时聊天应用:从消息编辑历史到阅后即焚的完整实践

发布时间:2026/9/14 20:57:27 来源:尧图企业网站定制
基于 SpacetimeDB 构建 Discord 风格实时聊天应用从消息编辑历史到阅后即焚的完整实践【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB本文围绕仓库中一份以 SpacetimeDB 为后端、React TypeScript 为前端的 Discord-like 实时聊天应用完整实现展开讲解其核心功能实时消息、在线状态、带完整历史的消息编辑、表情回复、已读回执、打字指示器、未读计数、定时消息、阅后即焚消息、角色权限如何落地并从源码层面剖析其表结构设计、Reducer 业务逻辑、订阅同步机制与已知缺陷。读完本文你将掌握如何用 SpacetimeDB 的表、Reducer、订阅与调度Scheduled机制从零搭建一个可扩展的多房间实时聊天应用。应用概览与功能清单该示例位于 tools/llm-oneshot/apps/chat-app/typescript/gemini-3-pro/spacetime/chat-app-20260107-120000/README.md是一个基于 SpacetimeDB 构建的实时聊天应用功能上对齐 Discord 的常见交互尤其强调带编辑历史的消息编辑。从分级评分记录 GRADING_RESULTS.md 可知该实现属于 Prompt Level 5Message Editing with History评估的 8 项特性合计得分 20.5/2485.4%。核心聊天功能实时消息消息对所有用户即时可见无需刷新页面。用户在线状态可查看谁在线online / offline 状态指示并有 lastSeen 时间戳。显示名称用户可自定义显示名称服务端限制长度 50 字符。房间管理支持创建房间、加入/退出房间房间可带可选描述。高级功能带历史的消息编辑编辑消息并查看完整编辑历史前后内容对照、时间、编辑者。消息表情回复对消息用 emoji 发表情内置 ❤️ 五种支持切换开/关。已读回执跟踪消息的已读状态消息下方显示Seen by X, Y, Z。打字指示器实时看到谁正在输入单人/多人文案区分。未读消息计数房间列表上的徽标计数按用户 × 房间分别记录。定时消息安排消息在未来发送延迟 10 秒24 小时可取消。阅后即焚消息定时自毁的消息时长 10 秒1 小时服务端到点彻底删除。房间邀请与会话管理配套 membership 与角色数据模型owner / admin / member。管理员/版主角色房间管理权限例如删除他人消息需 author 或 owner/admin 身份。项目结构与模块划分原文档给出了如下目录结构结合仓库实际文件做如下对照注意仓库中业务逻辑实际集中写在index.tsreducers.ts被合并chat-app-20260107-120000/ ├── backend/spacetimedb/ # SpacetimeDB 服务端模块TypeScript │ ├── src/ │ │ ├── index.ts # 模块入口 全部 Reducer 业务逻辑含生命周期钩子与调度 Reducer │ │ └── schema.ts # 数据库表结构定义11 张表 │ ├── package.json # 依赖 spacetimedb ^1.11.0 │ └── tsconfig.json └── client/ # React 前端Vite ├── src/ │ ├── App.tsx # 主聊天 UI侧边栏、消息区、输入区 │ ├── main.tsx # 应用入口 SpacetimeDB 连接构建 │ ├── config.ts # 模块名与 WebSocket 地址配置 │ ├── styles.css # Discord 风格深色主题样式 │ └── module_bindings/ # 生成的前端类型绑定编译期生成 ├── package.json # react ^18.3.1 / spacetimedb ^1.11.0 / vite ^6.0.3 ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── index.html两个 package.json后端 与 前端均依赖spacetimedb: ^1.11.0服务端用它定义表与 Reducer前端则用它提供的 React Hook 与连接客户端实现实时同步。环境准备与四步运行指南原文档的运行流程完整保留如下并补充各步骤的关键说明。前置条件已安装并运行 SpacetimeDB当前仓库通过spacetime start启动本地实例。Node.js 与 npm前端为 Vite 6 工程后端为 TypeScript ESM 工程。第 1 步启动 SpacetimeDBspacetime start启动后本地默认监听ws://localhost:3000前端 config.ts 中SPACETIMEDB_URI ws://localhost:3000与此对应。第 2 步发布后端模块cd backend/spacetimedb spacetime publish chat-app --clear-database -y --module-path .--clear-database发布时清空旧数据库适合开发期反复迭代-y跳过确认提示--module-path .指定模块源码目录为当前目录。第 3 步安装依赖# 后端 cd backend/spacetimedb npm install # 前端 cd ../../client npm install第 4 步启动前端cd client npm run dev应用默认运行在http://localhost:5173前端package.json中dev脚本会先执行kill-port清理 5173 端口再启动 Vite。核心亮点带完整历史的消息编辑原文档重点描述的这一特性是本应用的核心卖点对应后端的edit_messageReducer 与前端App.tsx的编辑交互完整实现链路如下编辑入口自己的消息旁出现 ✏️ Edit 按钮App.tsx中isOwnMessage判断见 client/src/App.tsx。编辑提交调用conn.reducers.edit_message({ messageId, newContent })。权限校验后端 index.ts 中先ctx.db.message.id.find(messageId)校验消息存在再比对senderId与ctx.sender不匹配即抛SenderError(Can only edit your own messages)。历史留痕每次编辑先向message_edit表插入一条记录previousContent、newContent、editedAt、editedBy再更新message表的content与editedAt字段。历史展示消息头出现 (edited) 标记点击 Show History 展开编辑历史面板旧内容以删除线、新内容以高亮显示按editedAt时间升序排列。实时同步所有编辑通过 SpacetimeDB 订阅机制即时推送到所有在线观看者。该特性的数据模型核心是message_edit表——用一条不可变的历史记录表 消息表当前内容的组合天然形成对消息修改的完整审计轨迹。后端实现剖析11 张表与 15 个业务 Reducer表结构设计schema.tsschema.ts 定义了 11 张表全部标记public: true除调度表需单独注意见下文已知问题并通过多列 BTree 索引支撑查询表名关键字段索引useridu64 自增主键、identity、name、online、lastSeenidentity、nameroomid、name、description可选、createdBy、createdAtnameroom_memberid、roomId、identity、roleowner/admin/member、joinedAtroom_identity、room_id、identitymessageid、roomId、senderId、senderName、content、sentAt、editedAt可选、isEphemeral、ephemeralExpiresAt可选room_id、sender_timestampmessage_editid、messageId、previousContent、newContent、editedAt、editedBymessage_id、message_timestampreactionid、messageId、userId、emoji、reactedAtmessage_id、message_userread_receiptid、messageId、userId、readAtmessage_id、user_id、user_messageroom_read_positionid、roomId、userId、lastReadMessageId、lastReadAtroom_user、user_idtyping_indicatorid、roomId、userId、userName、startedTypingAtroom_user、room_idscheduled_messagescheduledId自增、scheduledAtscheduleAt、roomId、senderId、senderName、contentroom_senderephemeral_messagescheduledId自增、scheduledAtscheduleAt、messageIdmessage_id设计上值得注意的点身份体系用户以t.identity()为主标识对应 SpacetimeDB 的调用者身份同时用自增u64作为行主键identity 建立唯一索引。外键式关联room_member.roomId、message.roomId、message_edit.messageId、reaction.messageId等通过索引构建跨表查询路径。调度表scheduled_message与ephemeral_message使用t.scheduleAt()字段并分别绑定调度 Reducersend_scheduled_message与cleanup_ephemeral_message这是 SpacetimeDB 定时任务的声明式入口。自增主键全部行 id 用t.u64().primaryKey().autoInc()插入时传0n由数据库自动分配。Reducer 业务逻辑index.tsindex.ts 集中了 15 个业务 Reducer、2 个调度 Reducer 与 2 个生命周期钩子可按功能分组用户管理set_name校验非空、≤50 字符存在则更新、不存在则自动建用户。房间管理create_room创建者自动成为 owner 并初始化已读位置、join_room查重、自动建用户、初始化已读位置、leave_room级联清理打字指示器、已读位置与成员关系。消息管理send_message非空、≤2000 字符、必须是房间成员、自动清理本人的打字指示器、edit_message上文详述、delete_message作者本人或 owner/admin 可删级联删除 reaction、read_receipt、message_edit 及对应的 ephemeral 调度。表情回复toggle_reaction同一用户对同一消息的同一 emoji 幂等切换重复调用即取消。已读mark_message_read单条消息写 read_receipt 并推进 room_read_position、mark_room_read整房间批量标记。打字指示器start_typing先清本人旧记录再插入新记录、stop_typing。定时消息schedule_message延迟 10 秒24 小时校验用ctx.timestamp.microsSinceUnixEpoch delaySeconds * 1_000_000n计算ScheduleAt.time、cancel_scheduled_message仅本人可取消。阅后即焚send_ephemeral_message时长 10 秒1 小时插入标记isEphemeral的消息并同时登记一条 ephemeral 调度。调度 Reducersend_scheduled_message到点把消息真正写入 message 表调度行自动删除、cleanup_ephemeral_message到点级联清理消息及全部关联数据。生命周期钩子clientConnected上线置 onlinetrue、clientDisconnected置离线并清理该用户的打字指示器。一个典型的定时消息闭环是schedule_message写scheduled_message行 → SpacetimeDB 调度器在scheduledAt触发send_scheduled_message→ 写入真实消息 → 调度行自动清理。阅后即焚同理只是触发的是cleanup_ephemeral_message。这种数据即调度的模型避免了外部任务队列是 SpacetimeDB 降低实时应用后端复杂度的核心体现。前端实现剖析响应式表格状态与订阅前端 App.tsx 是单文件主 UI配合 main.tsx 的连接建立流程连接构建DbConnection.builder().withUri(SPACETIMEDB_URI).withModuleName(MODULE_NAME)在onConnect回调中把连接与身份存入window.__db_conn/window.__my_identity供 App 组件读取onConnectError处理未授权401时清除本地 token 并刷新。订阅所有表通过conn.subscriptionBuilder().subscribe([...SQL 列表]).run()一次订阅 10 张表user、room、room_member、message、message_edit、reaction、read_receipt、room_read_position、typing_indicator、scheduled_message其中ephemeral_message无需订阅其用途只是触发清理。响应式状态useTable(tables.xxx)把每张表映射为响应式行集合——服务端任何变更都会自动触发前端重渲染这就是实时优先体验的来源。Reducer 调用所有交互统一走conn.reducers.xxx({...})例如发送消息、编辑、回复、已读、打字、取消定时。UI 上前端把各表数据加工成所需视图getUnreadCount基于room_read_position计算未读数并渲染徽标getMessageReactions把reaction行按 emoji 聚合为计数与是否本人已点getEditHistory把message_edit行按时间排序渲染历史面板getUserName根据 identity 反查显示名。用到的关键 SpacetimeDB 概念原文档列出的核心概念在本项目中均有对应落点结合源码进一步明确带关系的表与索引11 张表通过u64/identity外键式字段关联并为高频查询room_id、room_identity、message_user 等声明 BTree 索引。Reducer 即事务每个 Reducer 是原子事务操作SenderError用于向调用方回传业务错误如非房间成员只能编辑自己的消息。订阅实时同步前端订阅 SQL 后表数据变更自动推送并驱动 React 重渲染。身份系统ctx.sender为调用者身份用于鉴权编辑/删除/取消定时消息的所有权校验与自动建用户。调度操作t.scheduleAt() 绑定调度 Reducer支撑定时消息与阅后即焚。公开视图/可见性表public: true决定客户端能否订阅是数据可见性的开关scheduled_message漏配导致的缺陷见下节。架构决策与设计权衡原文档的架构决策逐条展开深色主题对齐 Discord 视觉风格styles.css 中 CSS 变量驱动的深色配色。实时优先所有功能优先保证实时同步数据变更即时上屏。基于权限owner / admin / member 三级角色配合身份体系实现消息删除等操作的权限边界。可扩展的表情reaction表按 (messageId, userId, emoji) 建模新增 emoji 只需前端加按钮。服务端处理阅后即焚自毁消息的清理由服务端调度 Reducer 保证不依赖客户端。完整编辑审计message_edit历史表让每次修改都留下可追溯记录。已知问题与改进方向仓库内 GRADING_RESULTS.md 对实现逐项打分并记录了缺陷可作为阅读源码时的对照清单无加入/退出房间 UIhandleJoinRoom回调已定义但未接到任何按钮上多用户聊天能力不完整。scheduled_message表漏配public: true客户端无法订阅该表导致待发送消息列表与取消功能收不到数据。阅后即焚时间戳构造错误后端以普通对象{ microsSinceUnixEpoch: expiresAt }而非 Timestamp 实例写ephemeralExpiresAt客户端读不到到期时间倒计时指示不显示。表情回复无 hover 名单代码已聚合data.users但 UI 未展示谁点了赞。打字指示器无超时自动过期仅在 blur、发送、断线时清理长时间挂起会持续显示。Token 未持久化onConnect中未localStorage.setItem(auth_token, token)且未.withToken()刷新页面会丢失身份。useTable用法与官方 Hook 签名不一致示例中直接取行集合而官方返回[rows, isLoading]元组。多列索引使用.filter()对复合索引如room_identity、room_user的前置列做 filter 遍历评分记录提示该模式存在隐患。这些缺陷同时也是很好的逆向教材——每一条都对应 SpacetimeDB 的实际使用边界表可见性、Timestamp 序列化、订阅权限、调度清理修掉它们即可把本应用打磨到生产可用。小结这份示例的价值在于它把 SpacetimeDB 的核心抽象表、Reducer、订阅、身份、调度完整地用于一个贴近真实产品的聊天场景并留下了可评估、可复盘的完整源码与评分记录。从带历史的消息编辑这个单一亮点出发你可以沿着 schema.ts 与 index.ts 两条主线理解实时多人在线应用的典型数据建模与事务边界再结合 GRADING_RESULTS.md 中的缺陷清单快速定位并修复真实项目中常见的集成坑。若想继续深入可在本地按上文四步流程启动后重点体验消息编辑历史、表情聚合与定时/阅后即焚两条调度链路再对照源码验证每一处实时更新的数据流向。【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价