boardx / boardx/workspacex

[backlog] 迭代 11:可点击原型——模型自动连跳转关系 + 预览模式 + 流程连线

Open
#2,917 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
0
Forks
0
Avg merge
1h 7m
Merged PRs (30d)
969

Description

## 用户诉求

> 生成的原型,可以生成可点击,连贯的吗?(2026-09-07)
>
> 取舍已定:**跳转关系由模型自动连**(人可改;否则每次整页重生成都要重连一遍)。

## 现状(为什么现在不能)

生成的是一棵**静态组件树**。画布上点节点是「选中它去改」(迭代 2 的 `focusNodeId`),不是跳转。21 个原语里没有任何一个带「点了去哪」——`button` 只有 `label`/`variant`/`full`(`design-prototype.ts:253`)。页与页之间零关系,所以它是可看、可改、可导出的高保真静态稿,不是能走通流程的可点击原型。

## 设计取舍(开工前要定,其中第 1 条建议已给)

**① 跳转关系存在哪** —— 建议 **B**:

| | 方案 A:节点 props 上加 `goTo` | 方案 B:屏级 `links: {from, item?, to}[]` |
|---|---|---|
| 单目标原语(button/chip/card/hero) | 直接,好写 | 需按 nodeId 查表(一个 Map,便宜) |
| 多项原语(list/tabs/bottomnav) | `items: string[]` 要配一条平行的 `goTo` 数组,且 `PROTOTYPE_FIELDS` 没有「按行给目标」这种字段类型,属性面板要新增一类控件 | 天然支持:`item` 指第几项 |
| 对既有契约的冲击 | 动 5–8 个 `*Props`,`PROTOTYPE_FIELDS` 与它的机械门控(键集合 == shape 键集合)全要跟着改 | **21 个 `*Props` 一个不动**,契约测试不受影响 |
| 校验 | 散在各 props 里 | 集中一处:目标页存在、`from` 是本页真实节点、不重复 |

**② 目标怎么寻址** —— 建议按**页序号**(`0 ≤ to < screens.length`)。仓库既有约定就是按位置配对(`prototype`/`frames`/`frameNotes` 三份平行数组按下标对应),按标签会在改名时断,按序号与现状一致。

**③ 模型给了悬空目标怎么办** —— 需要人定。既有纪律是「一页被拒 ⇒ 整个 `prototype` 写回被拒(半套原型比没有更糟)」,但悬空的**跳转**不至于让整页作废,倾向**只丢那一条 link、保留页面**。这与上面那条不一致,属于要显式写进 domain.md 的判断,不该我自己定。

## 工作量拆解

| # | 工作 | 规模 | 说明 |
|---|---|---|---|
| 1 | 契约:`PrototypeScreen.links` + 校验 + 契约测试 | M | 目标越界/悬空 `from`/自跳/重复各一条反证 |
| 2 | **存储:两张表各加一列** | **M(意料之外的税,见下)** | `design_projects.frame_links` + `design_project_prototype_versions.frame_links`,各带长度不变量 |
| 3 | 画布预览模式:点击执行跳转而非选中 | M | `PrototypeCanvas` 走 context,加一个 mode;单页视图跳转 = 切页 |
| 4 | 画板连线:页与页之间画箭头 | M | 已有 `data-frame-index` 与布局计算,加一层 SVG overlay(坐标换算是主要成本) |
| 5 | 属性面板:给选中节点设/改跳转目标 | S | `PROTOTYPE_FIELDS` 加一种 `frameRef` 字段类型(下拉列出各页) |
| 6 | 模型侧:prompt + few-shot + 纠偏 | S–M | 教它连线;`coercePrototypeRaw` 顺手把字符串页号转数字 |
| 7 | 导出:md 加「跳转关系」小节,JSON 规格自动带上 | S | links 挂在 screen 上 ⇒ JSON 免费 |
| 8 | e2e + 截图 + `ui.md` + 评分卡加一维 | M | 主链路:生成 → 预览模式点按钮 → 真的切到目标页 |

**总量 ≈ 一个完整迭代**,与已完成的迭代 5 / 迭代 6 同量级。

## ⚠ 读代码才发现的成本:平行数组税

一屏的数据在库里被拆成**三份平行数组**(`frames` 标签 / `prototype` 树 / `frame_notes` 说明),按下标配对。所以每加一项「每屏一份」的数据,代价是:一次迁移 + 项目表一列 + **版本表也要一列**(`20260906170000` 那张表同样存 `frames`/`prototype`)+ 读写两侧各一份长度不变量。

这个形状**刚刚已经咬过一次**:#2900 修的正是「只写 `frames` 不写 `prototype` ⇒ 强制清空」导致用户整份原型丢失。再加第四份平行数组,等于把同一类 bug 的面积再扩大一圈。

**建议在迭代 11 里顺手收敛**:把三(四)份平行数组合并成单列 `screens jsonb`(每项 `{frame, root, notes, links}`),长度不变量随之消失(不再有"对不上"这种状态)。代价是一次数据迁移 + 读写两侧重写,但换掉的是一整类"按位置对应"的脆弱性。这条要不要做、要不要单独成一个迭代,请人类定。

## 开工前的硬门(ADR-023)

这次改的是 **API 契约**(`PrototypeScreen` 变形),按契约先行流程,`contracts/design-prototype/design-signoff.md` 需要**人类重新签核第 ③ 件**,并过一次阶段一致性复核。**agent 不许自己改 status。** 在那之前这条只是 backlog,不开工。

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with ADR-023 and contracts/design-prototype/design-signoff.md, then inspect design-prototype.ts and migration 20260906170000. After the human decisions are signed off, trace PrototypeCanvas and the storage read/write paths. Done means the contract, persistence, preview navigation, links, export, and e2e, screenshot, ui.md, and scoring checks are covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, database, frontend, full-stack, testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.