Skip to content

Commit 19f60a2

Browse files
Copilothotlong
andcommitted
Update design document with App.interfaces[] and Decision Log #12
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 742ec51 commit 19f60a2

1 file changed

Lines changed: 50 additions & 1 deletion

File tree

docs/design/airtable-interface-gap-analysis.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ ties them together — specifically:
5858

5959
| Area | Airtable | ObjectStack |
6060
|:---|:---|:---|
61-
| **Interface as a first-class entity** | ✅ Multi-page app per base |`InterfaceSchema` + `InterfaceNavItemSchema` in App navigation |
61+
| **Interface as a first-class entity** | ✅ Multi-page app per base |`InterfaceSchema` + `App.interfaces[]` drives sidebar |
6262
| **Drag-and-drop element canvas** | ✅ Free-form element placement | 🟡 Region-based composition |
6363
| **Record Review workflow** | ✅ Built-in record-by-record review |`RecordReviewConfigSchema` in `PageSchema` |
6464
| **Element-level data binding** | ✅ Each element binds to any table/view |`ElementDataSourceSchema` per component |
@@ -345,6 +345,50 @@ ObjectStack's UI Protocol already **exceeds Airtable** in several significant ar
345345

346346
## 6. Schema Improvement Proposals
347347

348+
This section details the schema changes to support Airtable Interface parity.
349+
350+
**Note:** Many of these proposals have been **IMPLEMENTED** in Phase A (see Section 7.1).
351+
The code samples below reflect the current state of the schemas.
352+
353+
### 6.0 App Schema Enhancements
354+
355+
To enable the new Interface-driven navigation model, `AppSchema` has been enhanced with:
356+
357+
```typescript
358+
// Implemented: src/ui/app.zod.ts
359+
360+
export const AppSchema = z.object({
361+
// ... existing fields ...
362+
363+
/**
364+
* Interface names registered in this App.
365+
* Sidebar renders as a two-level menu: Interface (collapsible group) → Pages (menu items).
366+
*/
367+
interfaces: z.array(z.string()).optional()
368+
.describe('Interface names available in this App. Sidebar renders as Interface→Pages two-level menu.'),
369+
370+
/** Default interface to activate on App launch */
371+
defaultInterface: z.string().optional()
372+
.describe('Default interface to show when the App opens'),
373+
374+
/**
375+
* Navigation Tree Structure (Global Utility Entries Only).
376+
* Now repurposed for global utility items (Settings, Help, external links)
377+
* rendered at the bottom of the sidebar.
378+
*/
379+
navigation: z.array(NavigationItemSchema).optional()
380+
.describe('Global utility navigation items (Settings, Help, external links) — rendered at bottom of sidebar'),
381+
382+
// ... remaining fields ...
383+
});
384+
```
385+
386+
**Key Changes:**
387+
- Added `interfaces[]` — declares which interfaces belong to the app
388+
- Added `defaultInterface` — specifies which interface to show on app launch
389+
- Repurposed `navigation[]` — now for global utility entries only (Settings, Help, etc.)
390+
- The runtime auto-generates the main sidebar from `interfaces[]` and their `pages[]`
391+
348392
### 6.1 Interface Schema (New)
349393

350394
A new `InterfaceSchema` to represent the Airtable "Interface" concept — a self-contained,
@@ -360,6 +404,10 @@ export const InterfaceSchema = z.object({
360404
.describe('Display name'),
361405
description: z.string().optional()
362406
.describe('Purpose description'),
407+
icon: z.string().optional()
408+
.describe('Icon name for sidebar display (Lucide icon)'),
409+
group: z.string().optional()
410+
.describe('Business group label for sidebar grouping (e.g. "Sales Cloud", "Service Cloud")'),
363411
object: z.string().optional()
364412
.describe('Primary object binding (snake_case)'),
365413
pages: z.array(InterfacePageSchema)
@@ -655,6 +703,7 @@ export const EmbedConfigSchema = z.object({
655703
| 9 | Keep `InterfaceSchema` and `AppSchema` separate — do NOT merge | **App** = navigation container (menu tree, routing, mobile nav). **Interface** = content surface (ordered pages, data binding, role-specific views). Merging would conflate navigation topology with page composition. An App can embed multiple Interfaces via `InterfaceNavItemSchema`. This mirrors Salesforce App/FlexiPage and Airtable Base/Interface separation. | 2026-02-16 |
656704
| 10 | Add `InterfaceNavItemSchema` to bridge App↔Interface | `AppSchema.navigation` lacked a way to reference Interfaces. Added `type: 'interface'` nav item with `interfaceName` and optional `pageName` to enable App→Interface navigation without merging the schemas. | 2026-02-16 |
657705
| 11 | Keep all 16 page types — no merge, disambiguate in docs | Reviewed overlapping pairs: `record` vs `record_detail` (component-based layout vs auto-generated field display), `home` vs `overview` (platform landing vs interface navigation hub), `app`/`utility`/`blank` (distinct layout contexts). Each serves a different use case at a different abstraction level. Added disambiguation comments to `PageTypeSchema`. | 2026-02-16 |
706+
| 12 | App.interfaces[] drives sidebar as Interface→Pages two-level menu | App's `navigation` was a hand-written tree that conflicted with Interface's `pages[]`. New model: App declares `interfaces[]`, runtime renders Interface.label as collapsible group → Interface.pages[] as menu items. `navigation` retained for global utility entries only (Settings, Help). Eliminates dual-navigation confusion. Added `defaultInterface` to specify startup interface. Interface gets `icon` and `group` fields for sidebar rendering. | 2026-02-16 |
658707

659708
---
660709

0 commit comments

Comments
 (0)