> 关键工具:v0(生成界面)+ Liveblocks(实时协作基础设施)

> 技术栈阶:中高阶——单机原型容易,多人实时是深水区

> 完整演示:构思 → 创建项目 → 提示词编写 → AI 制作 → 项目检验 → 落地

> 预计耗时:单机版 1 小时;接通实时协作再 2~3 小时

这一篇怎么读

这个项目要跨越 v0 的能力边界:单机看板(AI 拆卡片 + 拖拽,70%)容易,多人实时同步(30%)是硬核。本篇完整演示这个"先单机、再接协作"的两阶段建法。

阶段一 · 构思:先认清哪部分 AI 搞不定

  • 痛点:敏捷团队做需求规划,拆解费脑、多人协作要么挤一台电脑要么用笨工具。
  • 核心流程:输入业务目标 → AI 拆出 Epic/Story 卡片 → 多人在线一起拖拽、实时同步。
  • 关键判断(构思阶段就要定):这个项目分两段——单机版(v0 能轻松搞定)和实时协作(v0 搞不定,要专门接 Liveblocks)。认清这条边界,是整个项目最重要的决策。
  • 成功标准:两个人各开一个浏览器,同时拖卡片不打架、不丢失。

阶段二 · 创建项目:建工程 + 备好协作基础设施

这一步比前面的案例多一件事:注册实时协作服务、拿密钥

  1. 建界面工程:打开 v0.dev 新建 Chat(同案例 07)。
  2. 注册 Liveblocks:打开 liveblocks.io,注册,新建一个 project,在 dashboard 拿到:
  • 公开 key(pk_...,前端用)
  • 私有 key(sk_...,后端鉴权用,先留着)
  1. 规划环境变量(落地时要配进部署平台):
NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY=pk_xxx
LIVEBLOCKS_SECRET_KEY=sk_xxx

为什么先把协作服务备好

"实时协作"不是写几行代码就有的,它需要一个专门的后端服务来同步状态。提前注册好、拿到 key,是承认"这部分超出 v0 能力"的务实一步。

阶段三 · 具体提示词编写:分两阶段下工单

阶段一工单(单机版,给 v0)

单机版提示词

做一个"用户故事地图"看板,React + Tailwind。
【AI 拆解】顶部输入框 + "生成"。用户输入业务目标(如"让新用户三天内
  完成首次下单"),调用一次大模型拆成 2~3 个 Epic,每个 Epic 下 2~4 个
  Story。要求模型只返回 JSON:[{ "epic":"...", "stories":["...","..."] }]
【看板】每个 Epic 一列,列内是 Story 卡片;卡片可在列间拖拽(用 dnd-kit);
  卡片可删除,列底可手动加卡。
先做单机版,数据放 React state,实时协作下一步再加。

阶段二工单(接 Liveblocks)

实时协作提示词

把单机看板改成多人实时协作,用 Liveblocks:
- 卡片数据用 Liveblocks storage(LiveList/LiveObject),不要本地 state。
- 每个用户进来分配随机名字和颜色,顶部显示在线成员。
- 拖拽、增删都实时同步给所有人。
先把"数据同步"跑通,光标和冲突随后处理。

阶段四 · AI 制作:看产出了什么(关键片段)

单机版很顺,AI 给出拆解 + 看板。接 Liveblocks 后,数据从 useState 迁到协作存储,关键片段:

// 用 Liveblocks 的 storage 存卡片(关键片段)
const cards = useStorage(root => root.cards);          // 所有人共享同一份
const updateCard = useMutation(({ storage }, id, patch) => {
  storage.get('cards').get(id).update(patch);          // 改动自动广播给在线成员
}, []);
// 顶部在线成员
const others = useOthers();

跑起来:两个窗口能看到同一份卡片了。但同时拖动同一张卡,问题立刻出现——见下一步。

阶段五 · 项目检验(上):攻克并发冲突这个核心 30%

5.1 现象:同时拖拽 → 卡片闪烁、状态不一致

A 和 B 几乎同时把同一张卡拖到不同列,卡片"闪烁",最后状态还不一致。这就是概念版反复强调的并发冲突。

5.2 修法:用可排序 key 代替数组下标

这一步必须人深度介入,因为它牵涉"用什么数据结构表达卡片顺序"的架构决策:

冲突处理提示词

多人同时拖同一卡片会闪烁、状态不一致。请改:
- 卡片在列内的位置不要用数组下标,改用 fractional indexing
  (给每张卡一个可排序字符串 key,插两卡之间时取中间值),
  这样两人同时插不同位置不会互相覆盖。
- 卡片的"所属列"和"排序 key"都作为 Liveblocks storage 字段,
  依赖其 CRDT 合并能力收敛最终状态。
- 拖拽用乐观更新,但以服务器收敛后的状态为准。

这里是 AI 帮不上大忙的地方

"为什么闪烁"以及"该用 fractional indexing",AI 不会主动告诉你——它只会让协作"看起来能用"。是你必须懂"数组下标在并发下会冲突、要用可排序 key + CRDT"这个原理,才能下达正确指令。这就是 30% 的硬核所在。

5.3 断线重连

重连验证提示词

模拟断网 5 秒再恢复:断网期间的拖拽,恢复后应正确同步给他人,
不重复、不丢失。顶部加连接状态指示(在线/重连中)。

阶段五 · 项目检验(下):必须开双窗口测并发

协作类应用的铁律

单窗口测试永远是绿的,所有 bug 都藏在"两个人同时操作"里。 验收必须开两个浏览器窗口对着干。

检验项操作(两个窗口)期望
同卡并发同时拖同一张卡到不同列最终两边一致,不闪烁
同位插入同列同位置各插一张卡两张都在,顺序稳定
断线一窗口断网拖几下再恢复改动正确同步,无重复/丢失
在线成员开关窗口顶部成员实时增减

阶段六 · 落地:部署上线,真正给团队多人用

  1. 把 v0 项目同步到 GitHub + Vercel(v0 支持导出到 Vercel 项目)。
  2. 关键:在 Vercel 项目的 Environment Variables 里配上两个 Liveblocks key(NEXT_PUBLIC_......_SECRET_KEY),否则线上协作连不上。
  3. Vercel 自动构建,得到 https://story-map-xxx.vercel.app
  4. 把链接发给团队,多人同时打开就能协作——这才是这个产品的价值兑现。

落地最常见翻车

这个项目有个比单纯前端更隐蔽的坑:Liveblocks 的 ..._SECRET_KEY 用在服务端鉴权路由里,部署平台少配它,单机预览和本地都正常,唯独线上多人协作连不上——很难一眼看出。配 key 时务必两个都配齐(公开 key + 私有 key)。环境变量这道通用关卡的完整说明,见 案例 01 的落地一节

30% 复盘:人类到底守住了什么

v0 交付的单机看板(拆解 + 拖拽)是 70%,且很顺。让它"真能多人一起用"的 30%,是人类的架构判断:

30% 工程点人类做了什么不做会怎样
能力边界判断认清 v0 做不了实时,主动引入 Liveblocks在错误工具上死磕
并发顺序fractional indexing 代替数组下标同时拖拽闪烁、状态不一致
冲突收敛依托 CRDT 合并 + 乐观更新后操作覆盖先操作,改动消失
断线鲁棒验证重连不丢不重弱网下数据丢失

核心教训:越接近"多人实时",AI 越只能搭壳,正确性要靠你懂分布式协作的原理。 你不需要从零造 CRDT,但必须知道"何时需要它、为什么需要它"。

可复用心法与提示词模板

带得走的三条

  1. 先分清能力边界:把任务拆成"AI 能丝滑的"和"需要专门基础设施的"。
  2. 并发场景用可排序 key + CRDT:别用数组下标表示顺序。
  3. 协作必开双窗口验收:单窗口测不出并发 bug。

通用"给单机应用加实时协作"提示词骨架

把现有单机 <应用> 改成多人实时协作,用 <Liveblocks/Yjs>。
1. 共享数据从本地 state 迁到协作框架的 storage。
2. 顺序/位置用 fractional indexing 等可排序 key,依赖 CRDT 合并。
3. 操作用乐观更新,以服务器收敛状态为准。
4. 处理断线重连:不丢不重,显示连接状态。
5. 先打通数据同步,再处理光标与冲突。