Skip to content

Commit 251860b

Browse files
authored
Merge pull request #783 from objectstack-ai/copilot/implement-studio-ui-nodes
2 parents fccc9d9 + d71c274 commit 251860b

9 files changed

Lines changed: 1556 additions & 12 deletions

File tree

ROADMAP.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ObjectStack Protocol — Road Map
22

3-
> **Last Updated:** 2026-02-21
3+
> **Last Updated:** 2026-02-22
44
> **Current Version:** v3.0.6
55
> **Status:** Protocol Specification Complete · Runtime Implementation In Progress
66
@@ -30,8 +30,8 @@
3030

3131
## Current State Summary
3232

33-
ObjectStack v3.0 has achieved **comprehensive protocol specification** with 175 Zod schemas,
34-
27 service contracts, and 7,111 `.describe()` annotations providing machine-readable documentation.
33+
ObjectStack v3.0 has achieved **comprehensive protocol specification** with 193 Zod schemas,
34+
27 service contracts, and 8,425 `.describe()` annotations providing machine-readable documentation.
3535
The core kernel, data engine, metadata system, and developer tooling are production-ready.
3636
The primary focus now shifts to implementing the remaining 19 service contracts and hardening
3737
the ecosystem for enterprise workloads.
@@ -93,13 +93,13 @@ This strategy ensures rapid iteration while maintaining a clear path to producti
9393
| Packages (total) | 27 |
9494
| Apps | 2 (Studio, Docs) |
9595
| Examples | 4 (Todo, CRM, Host, BI Plugin) |
96-
| Zod Schema Files | 178 |
96+
| Zod Schema Files | 193 |
9797
| Exported Schemas | 1,100+ |
98-
| `.describe()` Annotations | 7,111+ |
98+
| `.describe()` Annotations | 8,425+ |
9999
| Service Contracts | 27 |
100100
| Contracts Implemented | 13 (52%) |
101-
| Test Files | 210 |
102-
| Tests Passing | 5,953 / 5,953 |
101+
| Test Files | 218 |
102+
| Tests Passing | 6,202 / 6,202 |
103103
| `@deprecated` Items | 3 |
104104
| Protocol Domains | 15 (Data, UI, AI, API, Automation, Cloud, Contracts, Identity, Integration, Kernel, QA, Security, Shared, Studio, System) |
105105

@@ -109,7 +109,7 @@ This strategy ensures rapid iteration while maintaining a clear path to producti
109109

110110
> **Goal:** Prioritize APIs and client capabilities needed by [ObjectUI](https://github.com/objectstack-ai/objectui/blob/main/ROADMAP.md) frontend development.
111111
> **Target:** v3.1 protocol to fill core platform gaps.
112-
> **Updated:** 2026-02-21
112+
> **Updated:** 2026-02-22
113113
> **Owner:** @hotlong
114114
115115
### 1. Comments & Collaboration API for ObjectUI
@@ -171,6 +171,12 @@ Multi-stage triggers, action pipelines, execution logs, and cron scheduling stan
171171
| BPMN boundary events (error/timer/signal) || `automation/flow.zod.ts``boundary_event` node type + `boundaryConfig` (interrupting/non-interrupting) |
172172
| BPMN wait event configuration || `automation/flow.zod.ts``waitEventConfig` (timer/signal/webhook/manual/condition event types) |
173173
| BPMN checkpoint reasons (parallel join, boundary) || `automation/execution.zod.ts``parallel_join`, `boundary_event` in `CheckpointSchema.reason` |
174+
| Wait node executor plugin protocol || `automation/node-executor.zod.ts``WaitExecutorConfigSchema`, `WaitResumePayloadSchema`, `NodeExecutorDescriptorSchema` (19 tests) |
175+
| BPMN XML interop protocol (import/export) || `automation/bpmn-interop.zod.ts``BpmnImportOptionsSchema`, `BpmnExportOptionsSchema`, `BpmnInteropResultSchema`, `BUILT_IN_BPMN_MAPPINGS` (20 tests) |
176+
| Studio Flow Builder protocol (canvas nodes/edges) || `studio/flow-builder.zod.ts``FlowBuilderConfigSchema`, `FlowCanvasNodeSchema`, `FlowCanvasEdgeSchema`, `BUILT_IN_NODE_DESCRIPTORS` (23 tests) |
177+
| Wait node runtime pause/resume executor | 🔴 | Runtime: `NodeExecutor` plugin for `wait` nodes (spec ready, runtime not yet implemented) |
178+
| Studio Flow Builder canvas UI | 🔴 | Runtime: visual canvas with parallel/join/boundary node controls (spec ready, UI not yet implemented) |
179+
| BPMN XML import/export plugin | 🔴 | Runtime: plugin-based BPMN 2.0 XML importer/exporter (spec ready, low priority) |
174180

175181
### 3. File Direct Upload & Resumable Upload Protocol
176182

@@ -305,7 +311,7 @@ business/custom objects, aligning with industry best practices (e.g., ServiceNow
305311
## Phase 1: Protocol Specification (✅ Complete)
306312

307313
> **Goal:** Define every schema, type, and contract as a Zod-first source of truth.
308-
> **Result:** 175 Zod schemas, 27 service contracts, 7,111+ `.describe()` annotations across 15 protocol domains.
314+
> **Result:** 193 Zod schemas, 27 service contracts, 8,425+ `.describe()` annotations across 15 protocol domains.
309315
310316
<details>
311317
<summary>Deliverables — All Completed (click to expand)</summary>
@@ -314,7 +320,7 @@ business/custom objects, aligning with industry best practices (e.g., ServiceNow
314320
- [x] **Driver Specifications** — Memory, PostgreSQL, MongoDB driver schemas + SQL/NoSQL abstractions
315321
- [x] **UI Protocol** — View (List/Form/Kanban/Calendar/Gantt), App, Dashboard, Report, Action, Page (16 types), Chart, Widget, Theme, Animation, DnD, Touch, Keyboard, Responsive, Offline, Notification, i18n, Content Elements, Enhanced Activity Timeline (`RecordActivityProps` unified timeline, `RecordChatterProps` sidebar/drawer), Unified Navigation Protocol (`NavigationItem` as single source of truth with 7 types: object/dashboard/page/url/report/action/group; `NavigationArea` for business domain partitioning; `order`/`badge`/`requiredPermissions` on all nav items), Airtable Interface Parity (`UserActionsConfig`, `AppearanceConfig`, `ViewTab`, `AddRecordConfig`, `InterfacePageConfig`, `showRecordCount`, `allowPrinting`)
316322
- [x] **System Protocol** — Manifest, Auth Config, Cache, Logging, Metrics, Tracing, Audit, Encryption, Masking, Migration, Tenant, Translation, Search Engine, HTTP Server, Worker, Job, Object Storage, Notification, Message Queue, Registry Config, Collaboration, Compliance, Change Management, Disaster Recovery, License, Security Context, Core Services, SystemObjectName/SystemFieldName Constants, StorageNameMapping Utilities
317-
- [x] **Automation Protocol** — Flow (autolaunched/screen/schedule), Workflow, State Machine, Trigger Registry, Approval, ETL, Sync, Webhook
323+
- [x] **Automation Protocol** — Flow (autolaunched/screen/schedule), Workflow, State Machine, Trigger Registry, Approval, ETL, Sync, Webhook, BPMN Semantics (parallel/join gateways, boundary events, wait events, default sequence flows), Node Executor Plugin Protocol (wait pause/resume, executor descriptors), BPMN XML Interop (import/export options, element mappings, diagnostics)
318324
- [x] **AI Protocol** — Agent, Agent Action, Conversation, Cost, MCP, Model Registry, NLQ, Orchestration, Predictive, RAG Pipeline, Runtime Ops, Feedback Loop, DevOps Agent, Plugin Development
319325
- [x] **API Protocol** — Protocol (104 schemas), Endpoint, Contract, Router, Dispatcher, REST Server, GraphQL, OData, WebSocket, Realtime, Batch, Versioning, HTTP Cache, Documentation, Discovery, Registry, Errors, Auth, Auth Endpoints, Metadata, Analytics, Query Adapter, Storage, Plugin REST API, Feed API (Feed CRUD, Reactions, Subscription), Automation API (CRUD + Toggle + Runs)
320326
- [x] **Security Protocol** — Permission, Policy, RLS, Sharing, Territory
@@ -323,7 +329,7 @@ business/custom objects, aligning with industry best practices (e.g., ServiceNow
323329
- [x] **Cloud Protocol** — Marketplace, App Store, Developer Portal, Marketplace Admin
324330
- [x] **Integration Protocol** — Connector (Database, SaaS, File Storage, GitHub, Message Queue, Vercel)
325331
- [x] **QA Protocol** — Testing framework schemas
326-
- [x] **Studio Protocol** — Plugin extension schemas
332+
- [x] **Studio Protocol** — Plugin extension schemas, Object Designer (field editor, relationship mapper, ER diagram), Page Builder (canvas, palette), Flow Builder (canvas nodes, edges, BPMN node descriptors, layout algorithms)
327333
- [x] **Contracts** — 27 service interfaces with full method signatures
328334
- [x] **Stack Definition**`defineStack()`, `defineView()`, `defineApp()`, `defineFlow()`, `defineAgent()` helpers
329335
- [x] **Stack Composition**`composeStacks()` for declarative multi-stack merging with conflict resolution (`error`/`override`/`merge`)
@@ -683,7 +689,8 @@ Final polish and advanced features.
683689
- [ ] Object Manager — unified object list with search, filter, card/table/tree views, quick preview, statistics
684690
- [ ] View Builder — drag-and-drop list/form/dashboard designers
685691
- [ ] Page Builder — drag-and-drop page designer with element palette (see [Gap Analysis](docs/design/airtable-interface-gap-analysis.md))
686-
- [ ] Flow Builder — visual automation flow editor
692+
- [x] Flow Builder Protocol — canvas node shapes, edge styles, BPMN node descriptors (parallel_gateway, join_gateway, boundary_event, wait), layout algorithms, palette categories (`studio/flow-builder.zod.ts`)
693+
- [ ] Flow Builder Runtime — visual automation flow editor with drag-and-drop canvas, node palette, property panel, minimap
687694
- [ ] Security Console — permission matrix, RLS policy editor
688695
- [ ] AI Playground — agent testing, NLQ sandbox
689696
- [ ] Code Editor — Monaco-based TypeScript editing with live preview
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
import { describe, it, expect } from 'vitest';
2+
import {
3+
BpmnElementMappingSchema,
4+
BpmnUnmappedStrategySchema,
5+
BpmnImportOptionsSchema,
6+
BpmnVersionSchema,
7+
BpmnExportOptionsSchema,
8+
BpmnDiagnosticSchema,
9+
BpmnInteropResultSchema,
10+
BUILT_IN_BPMN_MAPPINGS,
11+
type BpmnImportOptions,
12+
type BpmnExportOptions,
13+
type BpmnInteropResult,
14+
} from './bpmn-interop.zod';
15+
16+
// ---------------------------------------------------------------------------
17+
// BpmnElementMappingSchema
18+
// ---------------------------------------------------------------------------
19+
describe('BpmnElementMappingSchema', () => {
20+
it('should accept a valid mapping', () => {
21+
const mapping = BpmnElementMappingSchema.parse({
22+
bpmnType: 'bpmn:parallelGateway',
23+
flowNodeAction: 'parallel_gateway',
24+
});
25+
expect(mapping.bpmnType).toBe('bpmn:parallelGateway');
26+
expect(mapping.bidirectional).toBe(true); // default
27+
});
28+
29+
it('should accept mapping with notes', () => {
30+
const mapping = BpmnElementMappingSchema.parse({
31+
bpmnType: 'bpmn:serviceTask',
32+
flowNodeAction: 'http_request',
33+
bidirectional: true,
34+
notes: 'Maps HTTP/connector tasks',
35+
});
36+
expect(mapping.notes).toBe('Maps HTTP/connector tasks');
37+
});
38+
39+
it('should reject without required fields', () => {
40+
expect(() => BpmnElementMappingSchema.parse({})).toThrow();
41+
});
42+
});
43+
44+
// ---------------------------------------------------------------------------
45+
// BpmnUnmappedStrategySchema
46+
// ---------------------------------------------------------------------------
47+
describe('BpmnUnmappedStrategySchema', () => {
48+
it('should accept all strategies', () => {
49+
['skip', 'warn', 'error', 'comment'].forEach(s => {
50+
expect(BpmnUnmappedStrategySchema.parse(s)).toBe(s);
51+
});
52+
});
53+
});
54+
55+
// ---------------------------------------------------------------------------
56+
// BpmnImportOptionsSchema
57+
// ---------------------------------------------------------------------------
58+
describe('BpmnImportOptionsSchema', () => {
59+
it('should accept empty options with defaults', () => {
60+
const opts: BpmnImportOptions = BpmnImportOptionsSchema.parse({});
61+
expect(opts.unmappedStrategy).toBe('warn');
62+
expect(opts.importLayout).toBe(true);
63+
expect(opts.importDocumentation).toBe(true);
64+
expect(opts.validateAfterImport).toBe(true);
65+
});
66+
67+
it('should accept custom import options', () => {
68+
const opts = BpmnImportOptionsSchema.parse({
69+
unmappedStrategy: 'error',
70+
customMappings: [
71+
{ bpmnType: 'bpmn:businessRuleTask', flowNodeAction: 'script' },
72+
],
73+
importLayout: false,
74+
importDocumentation: true,
75+
flowName: 'imported_approval_flow',
76+
validateAfterImport: true,
77+
});
78+
expect(opts.unmappedStrategy).toBe('error');
79+
expect(opts.customMappings).toHaveLength(1);
80+
expect(opts.flowName).toBe('imported_approval_flow');
81+
});
82+
});
83+
84+
// ---------------------------------------------------------------------------
85+
// BpmnExportOptionsSchema
86+
// ---------------------------------------------------------------------------
87+
describe('BpmnExportOptionsSchema', () => {
88+
it('should accept empty options with defaults', () => {
89+
const opts: BpmnExportOptions = BpmnExportOptionsSchema.parse({});
90+
expect(opts.version).toBe('2.0');
91+
expect(opts.includeLayout).toBe(true);
92+
expect(opts.includeExtensions).toBe(false);
93+
expect(opts.prettyPrint).toBe(true);
94+
expect(opts.namespacePrefix).toBe('bpmn');
95+
});
96+
97+
it('should accept custom export options', () => {
98+
const opts = BpmnExportOptionsSchema.parse({
99+
version: '2.0.2',
100+
includeLayout: true,
101+
includeExtensions: true,
102+
prettyPrint: false,
103+
namespacePrefix: 'bpmn2',
104+
});
105+
expect(opts.version).toBe('2.0.2');
106+
expect(opts.includeExtensions).toBe(true);
107+
expect(opts.namespacePrefix).toBe('bpmn2');
108+
});
109+
});
110+
111+
// ---------------------------------------------------------------------------
112+
// BpmnVersionSchema
113+
// ---------------------------------------------------------------------------
114+
describe('BpmnVersionSchema', () => {
115+
it('should accept valid versions', () => {
116+
expect(BpmnVersionSchema.parse('2.0')).toBe('2.0');
117+
expect(BpmnVersionSchema.parse('2.0.2')).toBe('2.0.2');
118+
});
119+
120+
it('should reject invalid version', () => {
121+
expect(() => BpmnVersionSchema.parse('1.0')).toThrow();
122+
});
123+
});
124+
125+
// ---------------------------------------------------------------------------
126+
// BpmnDiagnosticSchema
127+
// ---------------------------------------------------------------------------
128+
describe('BpmnDiagnosticSchema', () => {
129+
it('should accept a warning diagnostic', () => {
130+
const diag = BpmnDiagnosticSchema.parse({
131+
severity: 'warning',
132+
message: 'BPMN element bpmn:businessRuleTask has no direct mapping',
133+
bpmnElementId: 'Task_12345',
134+
});
135+
expect(diag.severity).toBe('warning');
136+
expect(diag.bpmnElementId).toBe('Task_12345');
137+
});
138+
139+
it('should accept all severities', () => {
140+
['info', 'warning', 'error'].forEach(s => {
141+
expect(() => BpmnDiagnosticSchema.parse({
142+
severity: s,
143+
message: 'test',
144+
})).not.toThrow();
145+
});
146+
});
147+
});
148+
149+
// ---------------------------------------------------------------------------
150+
// BpmnInteropResultSchema
151+
// ---------------------------------------------------------------------------
152+
describe('BpmnInteropResultSchema', () => {
153+
it('should accept a successful result', () => {
154+
const result: BpmnInteropResult = BpmnInteropResultSchema.parse({
155+
success: true,
156+
mappedCount: 15,
157+
unmappedCount: 0,
158+
});
159+
expect(result.success).toBe(true);
160+
expect(result.diagnostics).toEqual([]); // default
161+
});
162+
163+
it('should accept a result with diagnostics', () => {
164+
const result = BpmnInteropResultSchema.parse({
165+
success: true,
166+
diagnostics: [
167+
{ severity: 'warning', message: 'Unmapped element: bpmn:textAnnotation' },
168+
{ severity: 'info', message: 'Imported 12 nodes and 15 edges' },
169+
],
170+
mappedCount: 12,
171+
unmappedCount: 1,
172+
});
173+
expect(result.diagnostics).toHaveLength(2);
174+
expect(result.unmappedCount).toBe(1);
175+
});
176+
177+
it('should accept a failed result', () => {
178+
const result = BpmnInteropResultSchema.parse({
179+
success: false,
180+
diagnostics: [
181+
{ severity: 'error', message: 'Invalid BPMN XML: missing process element' },
182+
],
183+
});
184+
expect(result.success).toBe(false);
185+
expect(result.diagnostics[0].severity).toBe('error');
186+
});
187+
});
188+
189+
// ---------------------------------------------------------------------------
190+
// BUILT_IN_BPMN_MAPPINGS
191+
// ---------------------------------------------------------------------------
192+
describe('BUILT_IN_BPMN_MAPPINGS', () => {
193+
it('should validate all built-in mappings', () => {
194+
BUILT_IN_BPMN_MAPPINGS.forEach(m => {
195+
expect(() => BpmnElementMappingSchema.parse(m)).not.toThrow();
196+
});
197+
});
198+
199+
it('should include BPMN parallel gateway mapping', () => {
200+
const parallel = BUILT_IN_BPMN_MAPPINGS.find(m => m.bpmnType === 'bpmn:parallelGateway');
201+
expect(parallel).toBeDefined();
202+
expect(parallel?.flowNodeAction).toBe('parallel_gateway');
203+
});
204+
205+
it('should include boundary event mapping', () => {
206+
const boundary = BUILT_IN_BPMN_MAPPINGS.find(m => m.bpmnType === 'bpmn:boundaryEvent');
207+
expect(boundary).toBeDefined();
208+
expect(boundary?.flowNodeAction).toBe('boundary_event');
209+
});
210+
211+
it('should include wait/intermediate catch event mapping', () => {
212+
const wait = BUILT_IN_BPMN_MAPPINGS.find(m => m.bpmnType === 'bpmn:intermediateCatchEvent');
213+
expect(wait).toBeDefined();
214+
expect(wait?.flowNodeAction).toBe('wait');
215+
});
216+
217+
it('should map all core BPMN elements', () => {
218+
const bpmnTypes = BUILT_IN_BPMN_MAPPINGS.map(m => m.bpmnType);
219+
expect(bpmnTypes).toContain('bpmn:startEvent');
220+
expect(bpmnTypes).toContain('bpmn:endEvent');
221+
expect(bpmnTypes).toContain('bpmn:exclusiveGateway');
222+
expect(bpmnTypes).toContain('bpmn:parallelGateway');
223+
expect(bpmnTypes).toContain('bpmn:serviceTask');
224+
expect(bpmnTypes).toContain('bpmn:scriptTask');
225+
expect(bpmnTypes).toContain('bpmn:userTask');
226+
expect(bpmnTypes).toContain('bpmn:callActivity');
227+
expect(bpmnTypes).toContain('bpmn:boundaryEvent');
228+
});
229+
});

0 commit comments

Comments
 (0)