Skip to content

Commit 1e3ba83

Browse files
authored
Merge pull request #220 from objectstack-ai/copilot/develop-frontend-interface
2 parents bbe000c + 6d36c84 commit 1e3ba83

File tree

17 files changed

+1832
-43
lines changed

17 files changed

+1832
-43
lines changed

APPS_WEB_ROADMAP.md

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
# apps/web — Frontend Development Plan & Roadmap
2+
3+
> Complete plan for building the **ObjectOS Admin Console & Business App Shell** (`apps/web`).
4+
5+
## 1. Executive Summary
6+
7+
`apps/web` is a **Vite + React 19 SPA** that serves two purposes:
8+
9+
1. **Admin Console** (`/settings/*`) — System administration pages for managing organizations, users, permissions, plugins, jobs, metrics, and more.
10+
2. **Business App Shell** (`/apps/:appId/*`) — A metadata-driven workspace that renders ObjectStack business applications (CRM, HRM, Finance, etc.) by assembling ObjectUI controls.
11+
12+
### Current State (Baseline)
13+
14+
| Area | Status |
15+
|---|---|
16+
| Auth (sign-in, sign-up, 2FA, OAuth) | ✅ Complete (6 pages) |
17+
| Settings / Admin Console | ✅ Complete (16 pages) |
18+
| Business App Shell | 🟡 Placeholder only — single `app.tsx` stub |
19+
| Object List View | ❌ Not started |
20+
| Object Record View | ❌ Not started |
21+
| API Client Layer | ❌ Not started |
22+
| Metadata-driven Navigation | ❌ Not started |
23+
| ObjectUI Integration | ❌ Not started |
24+
25+
### Goal
26+
27+
Build the **Business App Shell** layer so that any ObjectStack app registered via the plugin manifest can be rendered in the browser with:
28+
29+
- Dynamic sidebar navigation derived from object metadata
30+
- Object list pages with sortable/filterable tables
31+
- Object record detail pages with form views
32+
- Proper loading, empty, and error states
33+
- API integration via TanStack Query → `/api/v1/*`
34+
35+
---
36+
37+
## 2. Architecture
38+
39+
```
40+
┌─────────────────────────────────────────────────────────┐
41+
│ apps/web (SPA) │
42+
│ │
43+
│ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │
44+
│ │ Auth │ │ Admin Console│ │ Business App Shell│ │
45+
│ │ Pages │ │ /settings/* │ │ /apps/:appId/* │ │
46+
│ └──────────┘ └──────────────┘ └──────────────────┘ │
47+
│ │ │
48+
│ ┌────┴────┐ │
49+
│ │ AppLayout│ │
50+
│ │ + Object │ │
51+
│ │ Nav │ │
52+
│ └────┬────┘ │
53+
│ ┌──────────┼──────────┐ │
54+
│ │ │ │ │
55+
│ ObjectList ObjectRecord AppHome│
56+
│ (table) (form/detail) (dash) │
57+
│ │
58+
│ ┌─────────────────────────────────────────────────┐ │
59+
│ │ Shared Infrastructure │ │
60+
│ │ api.ts │ use-metadata.ts │ use-records.ts │ │
61+
│ │ types/metadata.ts │ app-registry.ts │ │
62+
│ └─────────────────────────────────────────────────┘ │
63+
└──────────────────────┬──────────────────────────────────┘
64+
│ HTTP (TanStack Query)
65+
66+
ObjectStack Hono Server
67+
/api/v1/* (REST + GraphQL)
68+
```
69+
70+
### Key Principles
71+
72+
1. **Metadata-Driven**: Object definitions (fields, labels, icons) drive the UI — no hardcoded business logic in the frontend.
73+
2. **API-First**: All data flows through `/api/v1/*` endpoints via TanStack Query.
74+
3. **Progressive Enhancement**: Start with basic table/form views, later integrate ObjectUI controls.
75+
4. **Lazy Loading**: All page components are lazy-loaded for optimal code splitting.
76+
5. **Type Safety**: Full TypeScript types for metadata, records, and API responses.
77+
78+
---
79+
80+
## 3. Type System
81+
82+
### Core Metadata Types (`src/types/metadata.ts`)
83+
84+
```typescript
85+
// Object field definition — mirrors @objectstack/spec
86+
interface FieldDefinition {
87+
name: string;
88+
type: 'text' | 'number' | 'boolean' | 'datetime' | 'select' | 'reference' | 'textarea' | 'email' | 'url' | 'phone' | 'currency' | 'percent' | 'object';
89+
label: string;
90+
required?: boolean;
91+
readonly?: boolean;
92+
defaultValue?: unknown;
93+
options?: { label: string; value: string }[]; // for 'select' type
94+
referenceTo?: string; // for 'reference' type
95+
group?: string; // field grouping
96+
}
97+
98+
// Object definition — describes a business entity
99+
interface ObjectDefinition {
100+
name: string;
101+
label: string;
102+
pluralLabel: string;
103+
icon?: string;
104+
description?: string;
105+
fields: Record<string, FieldDefinition>;
106+
primaryField?: string; // which field is the "name" field
107+
listFields?: string[]; // which fields to show in list view
108+
}
109+
110+
// App definition — describes a business application
111+
interface AppDefinition {
112+
id: string;
113+
name: string;
114+
description: string;
115+
icon?: string;
116+
objects: string[]; // object names belonging to this app
117+
defaultObject?: string; // landing object
118+
status: 'active' | 'paused';
119+
category: 'system' | 'business' | 'custom';
120+
}
121+
```
122+
123+
---
124+
125+
## 4. Phase Roadmap
126+
127+
### Phase 1: Foundation (Current Sprint) ✅
128+
129+
**Goal**: Build the core infrastructure for metadata-driven business apps.
130+
131+
| Deliverable | File(s) | Description |
132+
|---|---|---|
133+
| API client | `src/lib/api.ts` | `@objectstack/client` SDK with mock fallback |
134+
| Metadata types | `src/types/metadata.ts` | TypeScript interfaces for objects, fields, apps |
135+
| Metadata hooks | `src/hooks/use-metadata.ts` | TanStack Query hooks: `useAppObjects`, `useObjectDefinition` |
136+
| Record hooks | `src/hooks/use-records.ts` | TanStack Query hooks: `useRecords`, `useRecord`, mutations |
137+
| Object list page | `src/pages/apps/object-list.tsx` | Table view with sorting, pagination |
138+
| Object record page | `src/pages/apps/object-record.tsx` | Detail view with field rendering |
139+
| App home page | `src/pages/apps/app.tsx` | Enhanced dashboard with object cards |
140+
| Dynamic app navigation | `AppLayout.tsx` | Sidebar nav items from object metadata |
141+
| Routing update | `App.tsx` | Add `/:objectName` and `/:objectName/:recordId` routes |
142+
143+
### Phase 2: Rich Data Views (Next Sprint)
144+
145+
| Deliverable | Description |
146+
|---|---|
147+
| Inline editing | Click-to-edit fields in record detail |
148+
| Column configuration | Users choose which columns to display |
149+
| Search & filters | Global search bar + field-level filters on list view |
150+
| Bulk actions | Multi-select rows for batch operations |
151+
| Related lists | Show child/related records on detail page |
152+
| Pagination controls | Page size selector, prev/next, jump-to-page |
153+
154+
### Phase 3: ObjectUI Integration
155+
156+
| Deliverable | Description |
157+
|---|---|
158+
| `@objectui/form` | Metadata-driven form control |
159+
| `@objectui/grid` | Advanced data grid with virtual scrolling |
160+
| `@objectui/kanban` | Kanban board view for pipeline objects |
161+
| `@objectui/chart` | Dashboard chart widgets |
162+
| View switcher | Toggle between Table / Kanban / Calendar views |
163+
| Layout builder | Drag-and-drop page layout configuration |
164+
165+
### Phase 4: Workflow & Automation UI
166+
167+
| Deliverable | Description |
168+
|---|---|
169+
| Workflow status badges | Show current workflow state on records |
170+
| Approval buttons | Approve/reject actions on pending records |
171+
| Workflow visualizer | BPMN-lite flow diagram for workflow definitions |
172+
| Automation rules UI | Visual rule builder for triggers and actions |
173+
| Activity timeline | Show audit log / activity feed on records |
174+
175+
### Phase 5: Offline & Sync
176+
177+
| Deliverable | Description |
178+
|---|---|
179+
| Service Worker | PWA support for offline access |
180+
| Local SQLite (WASM) | Client-side data cache via `@objectos/browser` |
181+
| Sync engine | Push mutations / pull deltas from server |
182+
| Conflict resolution UI | Manual conflict resolution for sync conflicts |
183+
| Optimistic updates | Instant UI feedback before server confirmation |
184+
185+
### Phase 6: Polish & Performance
186+
187+
| Deliverable | Description |
188+
|---|---|
189+
| Virtual scrolling | Handle 10K+ rows in list views |
190+
| Keyboard navigation | Full keyboard shortcut support |
191+
| Accessibility audit | WCAG 2.1 AA compliance |
192+
| i18n integration | Multi-locale support via `@objectos/i18n` |
193+
| Theme system | Light/dark mode + custom brand colors |
194+
| Performance budget | Bundle size limits, Lighthouse CI |
195+
196+
---
197+
198+
## 5. API Contract
199+
200+
The frontend uses the official `@objectstack/client` SDK to interact with the server.
201+
202+
### Client SDK Usage
203+
204+
```typescript
205+
import { ObjectStackClient } from '@objectstack/client';
206+
207+
const client = new ObjectStackClient({ baseUrl: '/api/v1' });
208+
209+
// Metadata
210+
client.meta.getObject('lead') // → ObjectDefinition
211+
client.meta.getItems('object') // → { type: 'object', items: ObjectDefinition[] }
212+
client.meta.getItems('app') // → { type: 'app', items: AppDefinition[] }
213+
client.meta.getItem('app', 'crm') // → AppDefinition
214+
215+
// Data
216+
client.data.find('lead', { top: 20 }) // → { records: T[], total: number }
217+
client.data.get('lead', 'lead-001') // → { record: T }
218+
client.data.create('lead', { ... }) // → { record: T }
219+
client.data.update('lead', 'id', { }) // → { record: T }
220+
client.data.delete('lead', 'id') // → { deleted: true }
221+
```
222+
223+
> When the server is unreachable, hooks fall back to mock data from `lib/mock-data.ts`.
224+
> This allows the UI to be developed independently of the backend.
225+
226+
---
227+
228+
## 6. File Structure (Target)
229+
230+
```
231+
apps/web/src/
232+
├── App.tsx # Root router
233+
├── main.tsx # Entry point
234+
├── index.css # Global styles
235+
236+
├── types/
237+
│ └── metadata.ts # Object, Field, App type definitions
238+
239+
├── lib/
240+
│ ├── api.ts # @objectstack/client SDK singleton
241+
│ ├── auth-client.ts # Better-Auth client
242+
│ ├── app-registry.ts # App registry (mock → API)
243+
│ ├── mock-data.ts # Mock metadata & records for dev
244+
│ └── utils.ts # cn() utility
245+
246+
├── hooks/
247+
│ ├── use-metadata.ts # Object/app metadata queries
248+
│ ├── use-records.ts # CRUD record queries & mutations
249+
│ └── use-mobile.ts # Mobile breakpoint detection
250+
251+
├── components/
252+
│ ├── layouts/
253+
│ │ ├── AppLayout.tsx # Business app shell + dynamic nav
254+
│ │ └── SettingsLayout.tsx # Admin console layout
255+
│ ├── auth/ # Auth guards & layouts
256+
│ ├── dashboard/ # App switcher, nav user, org switcher
257+
│ ├── records/
258+
│ │ ├── RecordTable.tsx # Reusable data table
259+
│ │ ├── FieldRenderer.tsx # Render field value by type
260+
│ │ └── RecordForm.tsx # (Phase 2) Editable record form
261+
│ └── ui/ # shadcn/ui primitives
262+
263+
├── pages/
264+
│ ├── home.tsx
265+
│ ├── sign-in.tsx / sign-up.tsx / ...
266+
│ ├── settings/ # 16 admin pages
267+
│ └── apps/
268+
│ ├── app.tsx # App home dashboard
269+
│ ├── object-list.tsx # Object list view (table)
270+
│ └── object-record.tsx # Object record detail
271+
272+
└── test/
273+
└── setup.ts
274+
```
275+
276+
---
277+
278+
## 7. Development Workflow
279+
280+
```bash
281+
# Terminal 1: ObjectStack API server
282+
pnpm objectstack:serve # → http://localhost:5320
283+
284+
# Terminal 2: Vite dev server (HMR)
285+
pnpm web:dev # → http://localhost:5321
286+
287+
# Vite proxies /api/v1/* → localhost:5320 automatically
288+
```
289+
290+
### Testing
291+
292+
```bash
293+
# Unit tests (Vitest + jsdom)
294+
cd apps/web && npx vitest run
295+
296+
# Type checking
297+
cd apps/web && npx tsc --noEmit
298+
299+
# Build
300+
pnpm web:build
301+
```
302+
303+
---
304+
305+
## 8. Success Criteria
306+
307+
### Phase 1 (Foundation) — Definition of Done
308+
309+
- [ ] User can navigate to `/apps/crm` and see a sidebar with object links
310+
- [ ] Clicking an object link navigates to `/apps/crm/leads` (object list)
311+
- [ ] Object list page shows a table with columns derived from metadata
312+
- [ ] Clicking a row navigates to `/apps/crm/leads/:id` (record detail)
313+
- [ ] Record detail page renders field values by type (text, number, date, select, etc.)
314+
- [ ] Loading spinners shown while data is fetching
315+
- [ ] Empty states shown when no records exist
316+
- [ ] Error states shown when API calls fail
317+
- [ ] All existing tests continue to pass
318+
- [ ] Build succeeds with no TypeScript errors

apps/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"test:watch": "vitest"
1313
},
1414
"dependencies": {
15+
"@objectstack/client": "1.1.0",
1516
"@radix-ui/react-dialog": "^1.1.15",
1617
"@radix-ui/react-dropdown-menu": "^2.1.16",
1718
"@radix-ui/react-select": "^2.2.6",

apps/web/src/App.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ const NotificationsPage = lazy(() => import('./pages/settings/notifications'));
3333

3434
// ── Business Apps ─────────────────────────────────────────────
3535
const BusinessAppPage = lazy(() => import('./pages/apps/app'));
36+
const ObjectListPage = lazy(() => import('./pages/apps/object-list'));
37+
const ObjectRecordPage = lazy(() => import('./pages/apps/object-record'));
3638

3739
export function App() {
3840
const fallback = (
@@ -82,6 +84,8 @@ export function App() {
8284
{/* ── Business Apps (/apps/:appId/*) ── */}
8385
<Route path="/apps/:appId" element={<AppLayout />}>
8486
<Route index element={<BusinessAppPage />} />
87+
<Route path=":objectName" element={<ObjectListPage />} />
88+
<Route path=":objectName/:recordId" element={<ObjectRecordPage />} />
8589
</Route>
8690

8791
</Route>

0 commit comments

Comments
 (0)