基于 SpacetimeDB 的实时聊天应用消息转发(Message Forwarding)功能规格与实现指南
【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB
本文围绕 SpacetimeDB 仓库中
tools/llm-oneshot/apps/chat-app/prompts/composed/17_forwarding.md这一 LLM 基准测试提示词规格展开,系统解读"实时聊天应用 + 消息转发"的完整功能需求、UI 契约、UI/样式规范,并结合仓库内的提示词模块化体系、TypeScript SDK 数据同步模型与自动化评测机制,为开发者提供一份可直接指导实现与验收的实战指南。
一、文档定位:LLM 基准测试中的"组合式提示词"
在 SpacetimeDB 仓库的 tools/llm-oneshot 目录下,维护着一套用于对比 SpacetimeDB 与 PostgreSQL 在不同功能集下 LLM 生成代码能力的基准测试工程。其聊天应用(chat-app)的提示词按"模块化 + 组合式(composed)"设计:
- prompts/features/ 存放单一功能积木,每个文件只描述一个功能,如 17_forwarding.md 单独描述消息转发;
- prompts/composed/ 存放累积式组合提示词,编号越大功能越全,例如
17_forwarding.md表示"基础聊天 + 前述全部功能 + 消息转发"; - prompts/language/ 存放语言/后端特定约束(如
typescript-spacetime.md、rust-spacetime.md、csharp-spacetime.md)。
根据 prompts/README.md 的说明,这套结构的核心动机是 DRY(Don't Repeat Yourself):功能描述只维护一份,再与语言文件拼接即可生成面向不同技术栈的完整提示词。组合方式为"语言文件在前、组合提示词在后",例如:
@language/typescript-spacetime.md @composed/17_forwarding.md execute值得注意的是,composed/ 目录实际已扩展到19_polls.md(慢速模式、投票),说明该提示词系统在 README 中标注的 12 级基础上仍在持续演进。
二、UI 与样式规范:完整继承的界面基线
关联文档在开头约三分之一篇幅定义了与功能无关的通用 UI 基线,这是所有组合提示词共享的部分,任何实现都必须遵守。
2.1 布局(Layout)
- 侧边栏(左侧,固定约 220px):应用标题/品牌、带状态的用户信息、房间列表、在线用户;
- 主区域(右侧,flex):房间头部栏、可滚动消息列表、固定在底部的输入栏;
- 面板(右侧滑入或浮层):话题(threads)、置顶消息(pinned messages)、用户资料(profiles)、设置(settings)。
2.2 视觉设计(Visual Design)
采用深色主题,并使用语言文件中的品牌色(见第七节)。核心规则:
| 维度 | 要求 |
|---|---|
| 背景 | 最深的色阶用于主背景,侧边栏与卡片用略亮色阶 |
| 文字 | 深底浅字,时间戳与次要信息使用弱化色 |
| 边框 | 1px 细边框,与背景低对比 |
| 间距 | 统一使用 8/12/16/24px 刻度 |
| 字体 | 系统字体栈,层级清晰(标题加粗、正文常规、元数据弱化小字) |
| 圆角 | 输入框、按钮、卡片、消息容器均圆角 |
2.3 组件规范(Components)
- 消息:发送者姓名(彩色)+ 时间戳(弱化)+ 文本;同一发送者的连续消息分组显示;操作按钮仅悬停时出现(具体按钮取决于启用的功能);
- 输入框:全宽、圆角、细边框、占位文本、聚焦环使用主色;
- 按钮:主操作填充主色,次级操作用描边/幽灵样式,需有清晰的 hover 与 active 状态;
- 徽章:小药丸形、带计数、对比色(如房间未读数);
- 模态/面板:右侧滑入 + 柔和背景遮罩,或下拉浮层;
- 状态指示:小圆点(绿=在线、黄=离开、红=请勿打扰、灰=离线);
- 房间列表:房间名带可选图标前缀(#),当前房间高亮,未读徽章。
2.4 交互与体验(Interaction & UX)
- 后端连接期间显示加载/连接中状态(spinner 或骨架屏),不得出现白屏;
- 空状态需给出有帮助的文案(如 "Create a room to get started");
- 错误反馈:行内错误或 toast 通知,绝不静默失败;
- 平滑过渡:面板、模态、状态变化使用淡入淡出/滑动;
- 悬停揭示:消息操作按钮、表情回应 tooltip、用户资料卡片;
- 键盘支持:Enter 发送消息,Escape 关闭模态/面板;
- 自动滚动到最新消息,向上滚动时出现"回到底部"按钮。
三、功能规格总览:20 项能力的累积式集合
关联文档的核心是"Important"声明:每个功能都附带一个 "UI contract" 小节,规定自动化测试所依赖的元素属性——它们定义了用户可见的接口。而架构、状态管理、后端设计则完全交给实现者自主决定。这意味着该文档刻意做到"接口契约与实现解耦",方便用统一脚本对不同实现做黑盒验收。
整个组合提示词(01–16 + Forwarding)包含以下功能族:
| 编号 | 功能 | 核心要点 |
|---|---|---|
| 1 | 基础聊天 | 设置昵称、创建/加入/离开房间、向已加入房间发消息、在线用户展示、合理校验(防刷屏、长度限制) |
| 2 | 打字指示 | 同一房间内广播"正在输入",数秒无活动自动过期,支持单/多人文案 |
| 3 | 已读回执 | 追踪谁看过哪些消息,展示"Seen by X, Y, Z",实时更新,不包含发送者本人 |
| 4 | 未读计数 | 房间列表未读徽章,按用户×房间记录最后读取位置,实时增减 |
| 5 | 定时消息 | 定时发送、作者可取消的待发列表、到点出现在房间 |
| 6 | 阅后即焚 | 设定时长后从数据库永久删除,UI 显示倒计时/消失提示 |
| 7 | 消息表情回应 | emoji 回应、计数实时更新、可切换自身回应、悬停显示回应者 |
| 8 | 编辑与历史 | 编辑自己的消息、"(edited)" 标记、他人可查看编辑历史、实时同步 |
| 9 | 实时权限 | 房间创建者为管理员,可踢/封禁,可晋升管理员,变更即时生效无需重连 |
| 10 | 丰富在线状态 | online/away/DND/invisible 四态、离线显示"Last active X minutes ago"、自动置为 away |
| 11 | 消息话题(线程) | 回复特定消息形成线程、父消息显示回复数与预览、线程视图、实时同步 |
| 12 | 私密房间与私聊 | 邀请制私密房(不进公开列表)、按用户名邀请、双人 DM、仅成员可见 |
| 13 | 房间活跃度 | 5 分钟内有 1+ 消息标 "Active"(绿),2 分钟内有 5+ 消息标 "Hot"(橙),实时变化 |
| 14 | 草稿同步 | 自动保存草稿、跨设备实时同步、每房间独立草稿、发送后清除 |
| 15 | 匿名到注册迁移 | 无账号可聊天、匿名身份跨会话保留、注册后身份与消息历史完整保留、房间成员关系转移 |
| 16 | 置顶消息 | 管理员与作者可置顶/取消、消息列表与"置顶面板"双入口、实时同步 |
| 17 | 用户资料 | 昵称/bio/头像可编辑、点击用户名弹出资料卡、修改后全局实时生效 |
| 18 | @提及与通知 | @username 高亮、生成通知、铃铛未读计数、通知面板可标记已读、点击跳转到源消息 |
| 19 | 收藏/已存消息 | 悬停收藏、侧边栏"Saved"面板、展示消息内容/发送者/频道/时间、个人私有、实时反映编辑 |
| 20 | 消息转发(Forwarding) | 悬停出现 Forward 按钮 → 频道选择器 → 目标频道出现带来源归属的副本,原消息不变,目标频道成员实时可见 |
四、逐功能 UI 契约详解(自动化验收接口)
由于组合提示词具有累积性(每个级别包含其前所有功能),下面按原文逐项保留各功能的 UI contract 关键元素。实现时必须确保这些可被自动化测试识别的属性存在。
4.1 基础聊天
- 姓名输入框:
placeholder包含 "name"(不区分大小写); - 姓名提交:文本为 "Join"、"Register"、"Set Name" 的
button,或type="submit"; - 创建房间:文本含 "Create"、"New" 或 "+" 的
button; - 房间名输入:
placeholder含 "room" 或 "name"; - 消息输入:
placeholder含 "message"; - 发送:在消息输入框按 Enter 发送;
- 房间列表:侧边栏/列表中房间名可见且可点击;
- 加入房间:点击房间名进入,或文本为 "Join" 的
button; - 离开房间:文本为 "Leave" 的
button; - 在线用户:可见用户列表/成员面板中以文本形式展示用户名。
4.2 打字指示
- 打字文本:他人输入时,可见文本包含 "typing";
- 自动过期:无活动 6 秒内指示文本消失。
4.3 已读回执
- 回执文本:他人查看后,消息附近出现含 "seen" 或 "read" 的文本;
- 读者姓名:回执文本包含查看者的显示名。
4.4 未读计数
- 徽章:侧边栏房间名旁出现数字徽章(如 "3");
- 清空:打开/进入房间后徽章消失。
4.5 定时消息
- 定时按钮:文本为 "Schedule"、
aria-label含 "schedule",或title含 "schedule" 的图标按钮; - 时间选择器:
input[type="datetime-local"]、input[type="time"]或input[type="number"]; - 待发列表:查看定时消息时可见 "Scheduled" 或 "Pending" 文本;
- 取消:待发消息旁有文本为 "Cancel" 的
button。
4.6 阅后即焚
- 开关:文本/标签含 "ephemeral"、"disappear" 或 "expire" 的
select/button/input; - 时长选项:可选项如 30s、1m、5m;
- 指示:消息上可见倒计时、"expires" 或 "disappearing" 文本;
- 删除:时长到期后消息文本从 DOM 中移除。
4.7 表情回应
- 触发:悬停时出现 emoji 文本按钮(👍 ❤️ 😂 😮 😢)或文本 "React" /
aria-label含 "react" 的按钮; - 展示:消息下方或旁边显示 emoji + 计数(如 "👍 2");
- 切换:再次点击同一 emoji 移除自己的回应;
- 悬停信息:回应元素的
title属性包含回应者姓名。
4.8 编辑与历史
- 编辑按钮:悬停在自己消息上出现文本为 "Edit" 的
button; - 编辑表单:编辑期间用行内
input/textarea替换消息内容,并有 "Save"button; - 编辑标记:已编辑消息可见 "(edited)";
- 历史:点击 "(edited)" 打开查看历史版本的视图。
4.9 实时权限
- 管理员指示:成员列表中管理员显示 "Admin"/"ADMIN";
- 成员面板:房间头部有文本为 "Members" 或 "Manage" 的
button; - 踢出:非管理员成员旁有文本为 "Kick" 的
button; - 晋升:非管理员成员旁有文本为 "Promote" 的
button; - 被踢反馈:被踢用户看到含 "kicked" 的文本或被重定向离开房间。
4.10 丰富在线状态
- 状态选择器:文本为 "Online"、"Away"、"Do Not Disturb"/"DND"、"Invisible" 的
select或按钮组; - 状态指示:用户名旁彩色圆点(绿=online、黄=away、红=DND、灰=invisible);
- 最后活跃:离线/离开用户显示含 "Last active" 或 "ago" 的文本。
4.11 话题线程
- 回复按钮:悬停时出现文本 "Reply" 或 "💬" 的
button; - 回复数:有回复的消息显示 "N replies" 或 "💬 N";
- 线程面板:点击回复按钮/计数打开包含父消息与全部回复的面板;
- 线程输入:面板内
placeholder含 "reply" 的input/textarea。
4.12 私密房间与私聊
- 私密开关:创建房间时
input[type="checkbox"]或文本/标签含 "Private" 的button; - 私密指示:侧边栏私密房间显示 "private" 文本或锁图标 🔒;
- 邀请按钮:房间头部或成员面板中文本为 "Invite" 的
button; - 邀请 UI:被邀请用户看到含房间名的 "Accept" 与 "Decline"
button; - DM 按钮:用户列表中用户名旁文本为 "DM" 或 "💬" 的
button。
4.13 活跃度指示
- Active 徽章:最近 5 分钟内有 1+ 消息的房间显示绿色 "Active"/"ACTIVE";
- Hot 徽章:最近 2 分钟内有 5+ 消息的房间显示橙色 "Hot"/"🔥";
- 出现位置:侧边栏房间名旁。
4.14 草稿同步
- 自动保存:输入即自动保存(无需保存按钮);
- 持久化:切换房间再切回,输入框恢复草稿文本;
- 跨会话:刷新页面后草稿仍恢复;
- 发送即清空:发送消息后清空该房间草稿。
4.15 匿名迁移
- 游客入口:文本为 "Guest"/"Anonymous"/"Join as Guest" 的
button,或自动分配 "Guest-XXXXX"/"Anon-XXXXX" 式名称; - 游客指示:匿名用户名旁显示 "guest"/"anon" 徽章/标签;
- 注册按钮:游客可见文本为 "Register" 或 "Sign Up" 的
button; - 注册表单:
placeholder含 "name" 或 "username" 的input; - 迁移:注册后此前所有消息显示新显示名。
4.16 置顶消息
- 置顶按钮:悬停时文本 "Pin" 或
aria-label含 "pin" 的button; - 置顶指示:置顶消息显示 "pinned" 文本或 📌 图标;
- 置顶面板:频道头部有 "Pinned"/"Pins"
button,打开后列出全部置顶消息; - 取消置顶:置顶消息上有 "Unpin"
button(面板内或悬停时)。
4.17 用户资料
- 资料编辑:侧边栏可访问文本 "Edit Profile"/"Profile" 或齿轮图标按钮;
- Bio 输入:
placeholder含 "bio" 或 "status" 的input/textarea; - 资料卡:点击用户名弹出显示姓名、bio、头像的 popover/模态;
- 姓名传播:修改显示名后所有消息归属实时更新。
4.18 @提及与通知
- 提及高亮:消息中的
@username视觉区分(加粗、着色或包裹进带样式的span); - 通知铃铛:侧边栏/头部有文本 "🔔" 或
aria-label含 "notification" 的button; - 未读数:铃铛旁数字徽章;
- 通知面板:点击铃铛显示含消息文本与频道名的通知列表;
- 标记已读:"Mark Read"/"Mark All Read"
button。
4.19 收藏/已存消息
- 收藏按钮:悬停时文本 "Bookmark"/"Save" 或
aria-label含 "bookmark"/"save" 的button; - 已存面板:侧边栏 "Saved"/"Bookmarks"
button打开面板; - 条目:每条已存消息显示消息文本与来源频道/发送者;
- 移除:面板内 "Remove"/"Unsave"
button。
五、消息转发(Forwarding)深度剖析
这是本关联文档的编号主题与新增核心功能,对应独立积木文件 features/17_forwarding.md。
5.1 功能需求(原文完整继承)
- 用户可以将一条消息转发到其作为成员的其他频道;
- 消息悬停时出现"Forward" 按钮,点击打开频道选择器(channel picker);
- 转发后,消息出现在目标频道,并带有"Forwarded from #原频道 by @用户"的归属标注;
- 原消息不被修改——转发创建的是副本(copy),而非移动或引用;
- 转发消息对目标频道全体成员实时可见。
5.2 UI 契约(原文完整继承)
| 契约项 | 自动化测试要求 |
|---|---|
| 转发按钮 | 消息悬停时出现文本为 "Forward" 或aria-label含 "forward" 的button |
| 频道选择器 | 列出用户可转发目标频道的列表或下拉框 |
| 归属标注 | 转发消息显示含 "Forwarded" 或 "forwarded from" 的文本 |
| 原消息不变 | 源消息上没有任何 "forwarded" 指示 |
5.3 基于 SpacetimeDB 数据模型的实现思路
结合仓库中 SpacetimeDB 的架构可以推断出一套与"副本 + 实时同步"语义天然契合的实现方案:
后端(reducer 层面):消息表增加forwarded_from(源频道名或 ID)与forwarded_by(转发者身份)两个字段。新增一个转发 reducer,例如forward_message(msg_id, target_room):
- 校验调用者是源房间与目标房间的成员;
- 读取源消息内容,在目标房间的消息表中插入一条新行(副本),并写入来源归属字段;
- 源房间中的消息行不做任何修改——这正符合"原消息不变、转发创建副本"的契约。
实时同步(subscription 层面):SpacetimeDB 的客户端通过订阅(subscription)与后端建立实时同步,目标频道成员订阅了该房间消息表后,新插入的转发副本会自动推送到所有订阅者,无需任何额外广播代码。这一机制在仓库的 TypeScript SDK 中有直接支撑:订阅通过ConnectionManager的subscribe与查询构建器完成,参见 sdks/typescript/src/react/SpacetimeDBProvider.ts 与 sdks/typescript/src/lib/query.ts(其中tables.user.where(...)这类带过滤条件的订阅示例也出现在 Angular 注入器中)。
客户端(React 组件层面):消息项组件悬停时渲染 "Forward" 按钮,点击后弹出频道选择器(仅列出当前用户已加入且非当前房间的频道);提交后调用转发 reducer;渲染时根据forwarded_from字段决定是否显示 "Forwarded from #xx by @xx" 归属行。
从数据流看,该功能在 SpacetimeDB 上只需要"一张表 + 一个 reducer + 一条订阅"即可闭环,这也是 prompts/README.md 中"转发/同步类功能对 SpacetimeDB 而言是 trivial 级别"结论的体现。
六、技术栈约束与品牌规范
关联文档的落地必须与语言文件组合使用。以 TypeScript 技术栈为例,language/typescript-spacetime.md 规定了如下硬约束:
- 架构:后端为 SpacetimeDB TypeScript 模块,客户端为 React + Vite + TypeScript;
- 模块名:
chat-app; - 目录约束:所有代码只能写在
.../backend/spacetimedb/(服务端)与.../client/src/(客户端)下,且必须位于带时间戳的文件夹chat-app-YYYYMMDD-HHMMSS/内,保持最小化与可读性; - 输出约束:只返回带文件头的代码块(见 output_instructions.md)。
同时 base_spacetime.md 规定应用使用 SpacetimeDB 品牌深色主题,官方品牌色取自语言文件:
| 用途 | 色值 |
|---|---|
| Primary(主色/成功色) | #4cf490(SpacetimeDB 绿) |
| Primary hover | #4cf490bf(绿 75% 透明度) |
| Secondary | #a880ff(SpacetimeDB 紫) |
| Background(shade2) | #0d0d0e(近黑) |
| Surface(shade1) | #141416(略亮) |
| Border(n6) | #202126 |
| Text(n1) | #e6e9f0(浅灰) |
| Text muted(n4) | #6f7987 |
| Accent | #02befa(SpacetimeDB 蓝) |
| Warning | #fbdc8e(黄) |
| Danger | #ff4c4c(红) |
| 可选头部渐变 | linear-gradient(266deg, #4cf490 0%, #8a38f5 100%)(绿到紫) |
应用标题统一为"SpacetimeDB Chat"。
七、自动化评测:如何验证"转发"是否达标
提示词系统配套了完整的评分机制(grading_rubric.md 与 grading_checklist.md),其核心方法论对转发功能同样适用:
7.1 评分规则
- 每个功能按0–3 分打分:0 = 未实现或完全损坏;1 = 部分实现且缺失核心功能;2 = 大体可用但有次要缺陷;3 = 完全符合规格;N/A = 未包含在提示词中;
- Prompt Level 到评分范围的映射:每个组合提示词级别只对"包含的功能"计分(如
01_basic对应功能 1–4、满分 12;级别越高覆盖越多); - UI 契约是评分的硬依据:评分强调"实际测试胜于代码分析","代码存在 ≠ 功能可用"。
7.2 针对转发的可执行验收清单(依据 UI 契约推导)
结合 grading_rubric.md 中"每功能独立测试"的方法学,转发功能可按以下步骤验证:
- 用户 A 在 #general 发送一条消息;
- 悬停该消息,确认出现文本 "Forward"(或
aria-label含 "forward")的按钮; - 点击后出现频道选择器,且只列出 A 已加入的频道;
- 选择 #design,确认 #design 中实时出现该消息副本,并带 "Forwarded from #general by @A" 归属文本;
- 回到 #general,确认源消息没有任何转发指示(原消息未被修改);
- 打开另一浏览器以用户 B(#design 成员)登录,确认 B 能实时收到转发副本;若 B 不是 #general 成员,则其看不到源消息;
- 验证转发者非目标频道成员时操作被拒绝(合理校验)。
这些用例恰好可以直接映射到"评分标准 3 分"的要求:转发入口可达、目标频道实时可见、归属标注正确、原消息不变。
7.3 真实评测样例
仓库中保留了真实生成的评测记录,例如 chat-app-20260102-162918/GRADING_RESULTS.md:该实例针对09_spacetime_private_rooms.md级别(功能 1–12)评分,后端 1008 行、前端约 1500 行、共 26 个文件,外部依赖仅spacetimedb、react、react-dom、vite、typescript,总分 34/36(94.4%),0 次重提示(reprompt)。这份记录同时印证了生成项目的典型结构:
chat-app-<时间戳>/ ├── backend/spacetimedb/ │ └── src/ │ ├── schema.ts # 表结构定义 │ └── index.ts # reducer 逻辑 └── client/ ├── src/ │ ├── App.tsx / main.tsx / styles.css │ ├── module_bindings/ # 生成绑定 │ └── components/ # 14 个组件 └── index.html它也为"转发功能"的实际落地提供了范本:schema 定义消息表结构,index.ts 定义 reducer,客户端组件负责悬停按钮、频道选择器与归属渲染。
八、结语
17_forwarding.md不仅是一份功能规格,更是一套**"契约先行、实现自决"**的工程化验收范式:通过把用户可见的 UI 契约从实现细节中剥离出来,它让同一个功能定义可以跨技术栈(SpacetimeDB 的 TypeScript/Rust/C#、PostgreSQL 的多种组合)统一评测。对于开发者而言,本文所梳理的完整功能族、转发功能的数据模型映射,以及可执行的验收清单,可以直接复用于:
- 基于 SpacetimeDB 构建包含转发能力的实时聊天应用(参考 sdks/typescript 的订阅/查询模型);
- 理解 LLM 生成代码的基准测试方法(参考 tools/llm-oneshot 整套提示词与评分体系);
- 以"UI 契约 + 黑盒测试"方式为自己开发的实时应用建立可自动化的验收标准。
转发这一看似简单的功能,在 SpacetimeDB 的"表 + reducer + 订阅"模型下,恰好是理解"副本语义 + 实时数据同步"的最佳最小示例:一次插入、一次订阅,其余全部交给数据库内置的实时同步机制完成。
【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考