Skip to content

Commit b634e29

Browse files
Copilothotlong
andauthored
docs: add ObjectUI frontend development plan (comprehensive issue content)
Add docs/OBJECTUI_DEVELOPMENT_PLAN.md with the full development plan for building the ObjectStack frontend UI based on ObjectUI, covering: - 5-phase development roadmap (core renderers → app shell → pages → dashboards → builder) - Technology stack decisions (React 19, Shadcn, TanStack Table, dnd-kit, etc.) - Package structure design (packages/objectui/) - Field type → widget mapping (30+ types) - Component registry architecture - Priority and timeline estimates Agent-Logs-Url: https://github.com/objectstack-ai/framework/sessions/5928c168-576b-4bd0-a0ed-d964faf8f066 Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent db088d2 commit b634e29

1 file changed

Lines changed: 399 additions & 0 deletions

File tree

docs/OBJECTUI_DEVELOPMENT_PLAN.md

Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
## 概述
2+
3+
本 Issue 汇总基于 ObjectUI 开发完整 ObjectStack 前端界面的最终开发方案。ObjectUI 是 ObjectStack 的 **Server-Driven UI (SDUI) 渲染引擎**,基于 `@objectstack/spec` 的 UI 协议(ViewSchema、PageSchema、AppSchema、ActionSchema、ThemeSchema)将 JSON 元数据渲染为 Shadcn/Tailwind 品质的 React 组件。
4+
5+
### 定位
6+
7+
```
8+
@objectstack/spec (协议层) → 定义 UI 的 JSON Schema(what)
9+
@objectstack/client + client-react → 数据/元数据获取 hooks(how to get data)
10+
ObjectUI (渲染层) → 将 JSON 元数据渲染为 React 组件(how to render)
11+
apps/studio (开发工具) → 元数据编辑 IDE(设计器)
12+
```
13+
14+
**ObjectUI ≠ Studio**
15+
- **Studio** = 面向开发者的元数据编辑器(当前仓库 `apps/studio/`
16+
- **ObjectUI** = 面向终端用户的业务应用渲染引擎(新建 `packages/objectui/`
17+
18+
---
19+
20+
## 现有基础设施
21+
22+
### ✅ 已完成 — 协议层(`@objectstack/spec`
23+
24+
| Schema | 文件 | 描述 |
25+
|:---|:---|:---|
26+
| `AppSchema` | `spec/src/ui/app.zod.ts` | App 导航壳:navigation tree、areas、branding |
27+
| `ViewSchema` (ListView + FormView) | `spec/src/ui/view.zod.ts` | 7 种视图类型 (grid/kanban/gallery/calendar/timeline/gantt/map) + 表单 |
28+
| `PageSchema` | `spec/src/ui/page.zod.ts` | 16 种页面类型,Region 布局、FlexiPage + Airtable Interface 混合 |
29+
| `DashboardSchema` | `spec/src/ui/dashboard.zod.ts` | Widget 组合面板:KPI、Chart、Pivot、Matrix |
30+
| `ActionSchema` | `spec/src/ui/action.zod.ts` | 交互抽象:script / url / modal / flow / api |
31+
| `ThemeSchema` | `spec/src/ui/theme.zod.ts` | 设计令牌:颜色、排版、间距、圆角、模式 |
32+
| `PageComponentSchema` | `spec/src/ui/component.zod.ts` | 组件 Props 定义(RecordDetails、RelatedList、Activity 等) |
33+
| `WidgetSchema` | `spec/src/ui/widget.zod.ts` | 自定义 Widget 生命周期(onMount/onUpdate/onUnmount) |
34+
| I18n、Responsive、Keyboard、Touch、DnD、Offline、Animation、Notification | `spec/src/ui/*.zod.ts` | 完整的 PWA 级 UI 协议 |
35+
36+
### ✅ 已完成 — 客户端 SDK
37+
38+
| Hook || 描述 |
39+
|:---|:---|:---|
40+
| `useQuery` / `useMutation` | `client-react` | 数据 CRUD |
41+
| `usePagination` / `useInfiniteQuery` | `client-react` | 分页/无限滚动 |
42+
| `useObject` / `useView` / `useFields` / `useMetadata` | `client-react` | 元数据获取 |
43+
| `useDataSubscription` / `useMetadataSubscription` | `client-react` | 实时订阅 |
44+
| `ObjectStackProvider` / `useClient` | `client-react` | 上下文提供 |
45+
46+
### ✅ 已完成 — REST API
47+
48+
| API | 描述 |
49+
|:---|:---|
50+
| `GET /api/v1/meta/objects/:name` | Object Schema (字段、关系、验证) |
51+
| `GET /api/v1/meta/views/:name` | View 定义 (列、排序、筛选) |
52+
| `GET /api/v1/meta/apps` | App 列表 (导航、图标、权限) |
53+
| `GET /api/v1/data/:object` | 数据查询 (OData-style filter/sort/select) |
54+
| `POST /PUT /DELETE /api/v1/data/:object` | 数据 CRUD |
55+
56+
---
57+
58+
## 开发方案:分 5 个阶段
59+
60+
### Phase 1: 核心渲染引擎 (`packages/objectui/`)
61+
62+
> **目标**:能将 ViewSchema JSON 渲染为 Shadcn 品质的 React 组件
63+
64+
#### 1.1 ViewRenderer — 视图渲染工厂
65+
66+
```
67+
ViewSchema.type → React Component
68+
'grid' → <DataGrid /> (TanStack Table + virtual scroll)
69+
'kanban' → <KanbanBoard /> (dnd-kit)
70+
'gallery' → <GalleryGrid /> (CSS Grid / Masonry)
71+
'calendar' → <CalendarView /> (FullCalendar or custom)
72+
'timeline' → <TimelineView /> (custom)
73+
'gantt' → <GanttChart /> (custom or gantt-task-react)
74+
'map' → <MapView /> (Mapbox/Leaflet)
75+
```
76+
77+
**核心 API 设计**
78+
79+
```typescript
80+
// packages/objectui/src/index.tsx
81+
82+
// 1. View Renderer — 根据 ViewSchema 类型分发
83+
export function ViewRenderer({ view, object }: { view: ListView; object: string }) {
84+
// useQuery + useObject 获取数据和字段定义
85+
// 根据 view.type 选择对应组件
86+
}
87+
88+
// 2. Form Renderer — 根据 FormViewSchema 渲染表单
89+
export function FormRenderer({ form, object, recordId? }: Props) {
90+
// useObject 获取字段定义
91+
// 根据 form.sections 渲染分组字段
92+
}
93+
94+
// 3. Field Renderer — 根据 FieldType 渲染单个字段
95+
export function FieldRenderer({ field, value, mode }: Props) {
96+
// mode: 'display' | 'edit' | 'filter'
97+
// field.type: 'text' | 'number' | 'date' | 'select' | 'reference' | ...
98+
}
99+
```
100+
101+
**关键实现细节**
102+
103+
| 组件 | Spec 对应 | 依赖库 | 优先级 |
104+
|:---|:---|:---|:---:|
105+
| `<DataGrid />` | `ListViewSchema` (type: grid) | TanStack Table v8 + TanStack Virtual | 🔴 P0 |
106+
| `<FormRenderer />` | `FormViewSchema` + `FormSectionSchema` | React Hook Form + Zod resolver | 🔴 P0 |
107+
| `<FieldRenderer />` | `FieldSchema.type` (30+ 字段类型) | Shadcn UI primitives | 🔴 P0 |
108+
| `<KanbanBoard />` | `KanbanConfigSchema` | dnd-kit | 🟡 P1 |
109+
| `<CalendarView />` | `CalendarConfigSchema` | date-fns + custom | 🟡 P1 |
110+
| `<GalleryGrid />` | `GalleryConfigSchema` | CSS Grid | 🟡 P1 |
111+
112+
#### 1.2 FieldType → Widget 映射
113+
114+
```
115+
text → <Input />
116+
textarea → <Textarea />
117+
number → <NumberInput />
118+
currency → <CurrencyInput />
119+
percent → <PercentInput />
120+
date → <DatePicker />
121+
datetime → <DateTimePicker />
122+
time → <TimePicker />
123+
boolean → <Switch /> or <Checkbox />
124+
select → <Select /> (single)
125+
multiselect → <MultiSelect /> (tags)
126+
reference → <RecordPicker /> (lookup)
127+
multi_reference→ <MultiRecordPicker />
128+
email → <Input type="email" />
129+
url → <Input type="url" /> with preview
130+
phone → <PhoneInput />
131+
rating → <StarRating />
132+
image → <ImageUpload />
133+
file → <FileUpload />
134+
rich_text → <RichTextEditor /> (Tiptap)
135+
json → <CodeEditor /> (Monaco)
136+
formula → <FormulaDisplay /> (read-only)
137+
autonumber → <Badge /> (read-only)
138+
```
139+
140+
---
141+
142+
### Phase 2: App Shell — 应用导航框架
143+
144+
> **目标**:将 `AppSchema` 渲染为完整的应用壳
145+
146+
#### 2.1 AppShell 组件
147+
148+
```typescript
149+
// packages/objectui/src/app/AppShell.tsx
150+
151+
export function AppShell({ app }: { app: App }) {
152+
return (
153+
<SidebarProvider>
154+
<AppSidebar app={app} /> {/* 左侧导航 */}
155+
<main>
156+
<SiteHeader app={app} /> {/* 顶部栏 */}
157+
<Outlet /> {/* 页面内容 */}
158+
</main>
159+
</SidebarProvider>
160+
);
161+
}
162+
```
163+
164+
#### 2.2 导航渲染
165+
166+
| AppSchema 字段 | 渲染为 |
167+
|:---|:---|
168+
| `app.navigation[]` | 递归侧边栏菜单 (GroupNavItem → 折叠组, ObjectNavItem → 链接) |
169+
| `app.areas[]` | 顶部 Area 切换器 (类似 Salesforce App Launcher) |
170+
| `app.branding` | Logo + 主题色 |
171+
| `app.mobileNavigation` | 移动端底部 Tab / 抽屉菜单 |
172+
173+
#### 2.3 路由系统
174+
175+
```
176+
/app/:appName → App Shell
177+
/app/:appName/object/:objectName → 默认 ListView
178+
/app/:appName/object/:objectName/view/:viewName → 指定 ListView
179+
/app/:appName/object/:objectName/:id → 记录详情 (FormView)
180+
/app/:appName/dashboard/:dashboardName → Dashboard
181+
/app/:appName/page/:pageName → Custom Page
182+
```
183+
184+
---
185+
186+
### Phase 3: Page Renderer — 页面组合引擎
187+
188+
> **目标**:将 `PageSchema` 渲染为组件组合页面
189+
190+
#### 3.1 PageRenderer
191+
192+
```typescript
193+
export function PageRenderer({ page }: { page: Page }) {
194+
// 1. 根据 page.type 选择布局模板
195+
// 2. 遍历 page.regions,每个 region 渲染其 components
196+
// 3. 每个 component 根据 type 分发到 ComponentRegistry
197+
}
198+
```
199+
200+
#### 3.2 ComponentRegistry(核心扩展点)
201+
202+
```typescript
203+
const COMPONENT_REGISTRY: Record<string, React.ComponentType<any>> = {
204+
// Structure
205+
'page:header': PageHeader,
206+
'page:tabs': PageTabs,
207+
'page:card': PageCard,
208+
209+
// Record Context
210+
'record:details': RecordDetails, // → 字段详情面板
211+
'record:highlights': RecordHighlights, // → KPI 高亮卡
212+
'record:related_list': RecordRelatedList, // → 关联记录列表
213+
'record:activity': RecordActivity, // → 活动/评论流
214+
215+
// AI
216+
'ai:chat_window': AIChatWindow,
217+
'ai:suggestion': AISuggestion,
218+
219+
// Elements (Airtable Interface parity)
220+
'element:text': TextElement,
221+
'element:number': NumberElement,
222+
'element:button': ButtonElement,
223+
'element:filter': FilterElement,
224+
'element:form': FormElement,
225+
'element:record_picker': RecordPicker,
226+
};
227+
```
228+
229+
---
230+
231+
### Phase 4: Dashboard & Reports
232+
233+
> **目标**:将 `DashboardSchema` 渲染为 KPI/图表面板
234+
235+
| Widget 类型 | 渲染组件 | 图表库 |
236+
|:---|:---|:---|
237+
| `chart` | `<ChartWidget />` | Recharts 或 ECharts |
238+
| `kpi` | `<KPICard />` | Shadcn Card + 数字动画 |
239+
| `table` | `<TableWidget />` | 复用 DataGrid |
240+
| `pivot` | `<PivotTable />` | TanStack Table + grouping |
241+
| `list` | `<ListWidget />` | 复用 DataGrid (简化版) |
242+
243+
---
244+
245+
### Phase 5: Interface Builder (Design → Publish)
246+
247+
> **目标**:可视化拖拽构建界面,参考 Issue #823 分析
248+
249+
此阶段实现 Airtable-style Interface Designer:
250+
- **设计模式**:拖拽组件到画布,右侧属性面板
251+
- **预览模式**:以终端用户视角预览
252+
- **发布流程**:Draft → Staged → Published 三阶段生命周期
253+
- **版本管理**:版本快照、回滚、差异对比
254+
255+
详见 Issue #823 的架构设计。
256+
257+
---
258+
259+
## 技术栈决策
260+
261+
| 领域 | 选择 | 理由 |
262+
|:---|:---|:---|
263+
| **UI 框架** | React 19 | 与 client-react、Studio 统一 |
264+
| **组件库** | Shadcn UI + Radix | 可定制、无锁定、对标 ThemeSchema |
265+
| **样式** | Tailwind CSS 4 | 设计令牌驱动、响应式 |
266+
| **表格** | TanStack Table v8 + TanStack Virtual | 虚拟滚动、列排序/筛选/分组/固定 |
267+
| **表单** | React Hook Form + Zod | Zod-first 验证、与 Spec FieldValidation 对齐 |
268+
| **拖拽** | dnd-kit | Kanban + Interface Builder + DnD 排序 |
269+
| **图表** | Recharts (轻量) 或 ECharts (全功能) | Dashboard Widget 渲染 |
270+
| **富文本** | Tiptap v2 | rich_text 字段类型 |
271+
| **路由** | TanStack Router | 类型安全、与 Studio 统一 |
272+
| **状态** | Zustand + React Query (TanStack Query) | 服务器状态 + 本地 UI 状态 |
273+
| **日期** | date-fns | Calendar/Timeline/Gantt 视图 |
274+
| **国际化** | 运行时渲染 `I18nLabelSchema` | 协议内置 i18n |
275+
276+
---
277+
278+
## 包结构
279+
280+
```
281+
packages/objectui/
282+
├── src/
283+
│ ├── index.tsx # 公开 API 入口
284+
│ ├── provider.tsx # <ObjectUIProvider> (配置 + 客户端注入)
285+
│ │
286+
│ ├── app/ # App Shell 层
287+
│ │ ├── AppShell.tsx # 主布局 (sidebar + header + outlet)
288+
│ │ ├── AppSidebar.tsx # 导航渲染 (NavigationItemSchema → 递归菜单)
289+
│ │ ├── AppLauncher.tsx # App 切换器
290+
│ │ └── AppRouter.tsx # 路由配置
291+
│ │
292+
│ ├── views/ # View Renderers
293+
│ │ ├── ViewRenderer.tsx # 视图分发工厂
294+
│ │ ├── DataGrid.tsx # grid 视图
295+
│ │ ├── KanbanBoard.tsx # kanban 视图
296+
│ │ ├── GalleryGrid.tsx # gallery 视图
297+
│ │ ├── CalendarView.tsx # calendar 视图
298+
│ │ ├── TimelineView.tsx # timeline 视图
299+
│ │ ├── GanttChart.tsx # gantt 视图
300+
│ │ └── MapView.tsx # map 视图
301+
│ │
302+
│ ├── forms/ # Form Renderers
303+
│ │ ├── FormRenderer.tsx # 表单布局工厂
304+
│ │ ├── FormSection.tsx # 分组渲染
305+
│ │ └── FormWizard.tsx # 向导模式
306+
│ │
307+
│ ├── fields/ # Field Renderers (30+ 字段类型)
308+
│ │ ├── FieldRenderer.tsx # 字段分发工厂
309+
│ │ ├── TextField.tsx
310+
│ │ ├── NumberField.tsx
311+
│ │ ├── DateField.tsx
312+
│ │ ├── SelectField.tsx
313+
│ │ ├── ReferenceField.tsx # Lookup / Record Picker
314+
│ │ └── ...
315+
│ │
316+
│ ├── pages/ # Page Renderers
317+
│ │ ├── PageRenderer.tsx # 页面分发工厂
318+
│ │ ├── RecordPage.tsx # 记录详情页
319+
│ │ ├── HomePage.tsx # 首页
320+
│ │ └── BlankPage.tsx # 自由画布
321+
│ │
322+
│ ├── dashboard/ # Dashboard Renderers
323+
│ │ ├── DashboardRenderer.tsx
324+
│ │ ├── ChartWidget.tsx
325+
│ │ ├── KPICard.tsx
326+
│ │ └── PivotTable.tsx
327+
│ │
328+
│ ├── actions/ # Action Execution Engine
329+
│ │ ├── ActionRunner.tsx
330+
│ │ └── ActionButton.tsx
331+
│ │
332+
│ └── theme/ # ThemeSchema → CSS Variables
333+
│ ├── ThemeProvider.tsx
334+
│ └── tokens.ts
335+
336+
├── package.json
337+
├── tsconfig.json
338+
└── vitest.config.ts
339+
```
340+
341+
---
342+
343+
## 依赖关系
344+
345+
```
346+
@objectstack/spec ← 协议定义 (Zod schemas)
347+
@objectstack/client ← HTTP 客户端 (data + metadata API)
348+
@objectstack/client-react ← React hooks (useQuery, useObject, useView, ...)
349+
350+
351+
@objectstack/objectui ← UI 渲染引擎 (本 Issue 开发目标)
352+
353+
354+
apps/studio ← 开发者 IDE (导入 objectui 组件)
355+
apps/portal ← 终端用户业务应用 (未来)
356+
```
357+
358+
---
359+
360+
## 实施优先级
361+
362+
| 阶段 | 内容 | 预估工期 | 依赖 |
363+
|:---:|:---|:---:|:---|
364+
| **P0** | Phase 1: DataGrid + FormRenderer + FieldRenderer (核心三件套) | 4-6 周 | spec + client-react |
365+
| **P0** | Phase 2: AppShell + Navigation + Router | 2-3 周 | Phase 1 |
366+
| **P1** | Phase 1 续: Kanban + Calendar + Gallery 视图 | 3-4 周 | Phase 1 |
367+
| **P1** | Phase 3: PageRenderer + ComponentRegistry | 3-4 周 | Phase 2 |
368+
| **P1** | Phase 4: Dashboard + Chart Widgets | 2-3 周 | Phase 1 |
369+
| **P2** | Phase 5: Interface Builder (参见 #823) | 12-16 周 | Phase 1-4 |
370+
| **P2** | 移动端适配 (mobileNavigation + Touch) | 3-4 周 | Phase 2 |
371+
| **P2** | 离线模式 (OfflineConfigSchema) | 2-3 周 | Phase 1 |
372+
373+
**总预估**: 核心可用 (P0) = 6-9 周, 完整功能 (P0+P1) = 15-20 周
374+
375+
---
376+
377+
## 与现有 Issue 的关系
378+
379+
| Issue | 关系 |
380+
|:---|:---|
381+
| #823 Assessment: Airtable Interface Designer | Phase 5 的架构基础,Interface Builder 设计方案 |
382+
| #1159 Studio 优化 | Studio 是设计器,ObjectUI 是渲染器,两者互补 |
383+
| #989 统一前后端 API 查询语法 | ObjectUI 的 DataGrid 依赖 API 查询语法正确性 |
384+
| #866 Filter operators broken | ObjectUI 的 filter/sort 功能依赖此 fix |
385+
| #724 基础设施核心服务 | ObjectUI 的 realtime/search/notification 功能依赖 |
386+
387+
---
388+
389+
## 验收标准
390+
391+
- [ ] 能基于 `defineStack()` 中的 objects + views + apps 定义,**零代码**渲染出完整 CRUD 应用
392+
- [ ] DataGrid 支持排序、筛选、分页、虚拟滚动、行选择、内联编辑
393+
- [ ] FormRenderer 支持 simple / tabbed / wizard 布局,含字段级验证
394+
- [ ] AppShell 支持递归侧边栏导航、Area 切换、移动端适配
395+
- [ ] 所有 30+ 字段类型在 display / edit / filter 三种模式下均有渲染实现
396+
- [ ] Dashboard 支持 KPI 卡片 + 图表 + 表格 Widget 组合
397+
- [ ] 主题令牌 (ThemeSchema) 驱动所有颜色/排版/间距,支持亮/暗模式
398+
- [ ] 完整的 TypeScript 类型推导,无 `any` 泄漏
399+
- [ ] 组件测试覆盖率 > 60%

0 commit comments

Comments
 (0)