Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
387 changes: 62 additions & 325 deletions examples/README.md

Large diffs are not rendered by default.

123 changes: 84 additions & 39 deletions examples/app-showcase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,36 @@ pnpm verify
## What it covers

### Data layer (ObjectQL)
- **All 49 field types** — `src/objects/field-zoo.object.ts` carries one field
of every `FieldType`, with the remainder appearing naturally on the backbone
objects.
- **All 49 field types** — `src/data/objects/field-zoo.object.ts` carries one
field of every `FieldType`, with the remainder appearing naturally on the
backbone objects.
- **Every relationship kind** — `lookup` (project → account, category → self),
`master_detail` (task → project), self-referencing **hierarchy/tree**
(`Category.parent`), and **many-to-many** via the
`showcase_project_membership` junction.
- **Formulas, validations, and a status state machine** on `Project` and
`Task`.
`Task` — only the rule types the runtime actually **enforces** are
demonstrated (the unenforced ones are tracked in #1475, not faked here).
- **An object extension** (`src/data/extensions/account.extension.ts`) merged
additively into `showcase_account` at registration — the package-extends-
an-object mechanism.
- **An analytics cube** (`src/data/analytics/showcase.cube.ts`) served by the
analytics service at `/api/v1/analytics/*`.

### View layer (ObjectUI)
- **All 8 list-view types** on a single object (`src/views/task.view.ts`):
- **All 8 list-view types** on a single object (`src/ui/views/task.view.ts`):
grid, kanban, gallery, calendar, timeline, gantt, map, chart. The Task object's
fields are chosen so one object can back every type.
- **All 5 form-view types**: simple, tabbed, wizard, split, drawer.
- **The full chart taxonomy** — `src/dashboards/chart-gallery.dashboard.ts`
- **The full chart taxonomy** — `src/ui/dashboards/chart-gallery.dashboard.ts`
has one widget per chart family (all 38 `ChartType`s).
- **All 4 report types**: tabular, summary, matrix, joined
(`src/reports/index.ts`).
- **Every analytics report type**: summary, matrix, joined
(`src/ui/reports/index.ts`) — a flat *tabular* list is deliberately an
object-bound ListView lens, not a report (ADR-0021).
- **The action matrix** — every `ActionType` (script/url/flow/modal/api/form)
across every `ActionLocation`.
- **A component-gallery page** placing the standard page components.
- **Four page-authoring models** — structured (full/slotted), constrained-JSX
`html`, and executed `react`, taught by the **Page Authoring** index page.

### Capability chains (the "complex abilities")
- **Security** (`src/security/index.ts`): a role hierarchy + a permission set
Expand All @@ -73,68 +81,105 @@ pnpm verify
and an org **policy**.
- **Automation**: a record-triggered flow → a screen-flow wizard → a multi-step
**approval** → an outbound **webhook** → a scheduled **job** → an **email**
template.
- **AI**: an **agent** wired to a **tool** and a **skill**.
template, plus live REST/Slack **connector actions**.
- **i18n / theming / portals**: `en` + `zh-CN` translations, light + dark
themes, and an external client portal.

> **Where is AI?** Deliberately absent. Agents are platform-owned (ADR-0063 —
> third parties author skills/tools, never agents), and the open framework
> exposes AI via `@objectstack/mcp` only. Rather than fake a demo, the
> coverage manifest **waives** `agent`/`tool`/`skill` with tracking issue
> [#2610](https://github.com/objectstack-ai/framework/issues/2610).

## The coverage manifest — how "confirm" works

`src/coverage.ts` declares what the showcase is supposed to cover and provides
the collectors the test uses. `test/coverage.test.ts` then **introspects the
protocol's own enums** (`FieldType`, `ChartTypeSchema`, `ReportType`,
`ActionType`, `ACTION_LOCATIONS`) and asserts every member appears at least
once across the registered metadata.
`src/coverage.ts` declares what the showcase is supposed to cover at **two
levels**, and `test/coverage.test.ts` proves both:

- **Kind level** — `KIND_COVERAGE` enumerates every metadata kind in
`DEFAULT_METADATA_TYPE_REGISTRY`. Each kind is either `demonstrated`
(pointing at the proof files, which must exist) or explicitly `waived`
(with a reason **and a tracking-issue link**). A new registry kind fails CI
until it is accounted for; nothing can silently go missing. The same
contract covers stack collections that aren't registry kinds
(`STACK_COLLECTION_COVERAGE`: analyticsCubes, objectExtensions, and the
waived mappings/connectors).
- **Variant level** — the test **introspects the protocol's own enums**
(`FieldType`, `ChartTypeSchema`, `ReportType`, `ActionType`,
`ACTION_LOCATIONS`) and asserts every member appears at least once across
the registered metadata.

Because the expected sets come from the **spec** — not a hand-maintained list —
the test fails automatically when the platform gains a new field type, chart
type, or report type that the showcase hasn't demonstrated yet. That keeps this
example a **living conformance fixture**, not a static snapshot. (`defineStack`
itself also runs full schema + cross-reference validation when the config is
imported, so `pnpm test` proves the whole stack loads cleanly.)
the tests fail automatically when the platform gains a new kind, field type,
chart type, or report type that the showcase hasn't demonstrated yet. That
keeps this example a **living conformance fixture**, not a static snapshot.
(`defineStack` itself also runs full schema + cross-reference validation when
the config is imported, so `pnpm test` proves the whole stack loads cleanly.)

The waiver policy is Prime Directive #10 in action: a capability the runtime
doesn't deliver is **never demoed** — it is waived, loudly, with an issue.

## Guided tour & capability map

The app's landing page is the **Capability Map** (`src/ui/pages/
capability-map.page.ts`) — one card per protocol domain linking the flagship
demos. Five **tour docs** (`src/docs/showcase_tour_*.md`) walk each domain,
with live ` ```metadata ` embeds (ADR-0051) rendered from the running
metadata; the **Showcase Manual** book curates them into a Guided Tour group,
served publicly via the library portal.

## Directory layout

`src/` mirrors the six protocol domains of the metadata registry
(`DEFAULT_METADATA_TYPE_REGISTRY`), with per-type directories inside each:

```
app-showcase/
├── objectstack.config.ts # defineStack — registers everything
├── src/
│ ├── coverage.ts # coverage manifest + collectors (the soul)
│ ├── objects/ # field-zoo + backbone + junction + tree
│ ├── views/ # all 8 list types + all 5 form types
│ ├── dashboards/ # chart gallery (all 38 chart types)
│ ├── reports/ # tabular / summary / matrix / joined
│ ├── actions/ # type × location matrix
│ ├── pages/ # component gallery
│ ├── apps/ # navigation linking every surface
│ ├── security/ # roles + FLS + RLS + sharing + policy
│ ├── flows/ approvals/ webhooks/ jobs/ emails/ # automation chain
│ ├── agents/ # agent + tool + skill
│ ├── themes/ translations/ datasources/ portals/
│ └── data/ # seed data sized to feed every view
│ ├── coverage.ts # coverage manifest (PINNED here: package export)
│ ├── docs/ # doc metadata (PINNED here & flat: CLI contract, ADR-0046)
│ ├── data/ # ── data domain ──
│ │ ├── objects/ # field-zoo + backbone + junction + tree + federated
│ │ ├── extensions/ # object-extension overlay on showcase_account
│ │ ├── analytics/ # showcase_delivery cube
│ │ ├── hooks/ seed/ # lifecycle hooks · seed data sized to feed every view
│ ├── ui/ # ── ui domain ──
│ │ ├── apps/ views/ pages/ dashboards/ datasets/ reports/ actions/
│ │ └── themes/ portals/
│ ├── automation/ # ── automation domain ──
│ │ └── flows/ jobs/ webhooks/
│ ├── system/ # ── system domain ──
│ │ └── datasources/ emails/ translations/ books/ server/
│ └── security/ # ── security domain: roles + FLS + RLS + sharing
└── test/
├── coverage.test.ts # introspects spec enums, asserts coverage
├── coverage.test.ts # registry kinds + spec enums, asserted
├── gap-fill.test.ts # cube shape + extension merge (real registry)
└── seed.test.ts # stack-loads + breadth smoke test
```

(The AI domain has no `src/ai/` on purpose — see the waiver note above.)

## Extending it

When you add a new variant to the platform, the coverage test will go red and
point at the gap. Add a field/view/widget that uses it, reference it in
`COVERAGE`, and the test goes green again.
`COVERAGE`, and the test goes green again. When you add a new **metadata
kind**, the kind-level test goes red instead: demonstrate it under the right
domain directory, or waive it with a reason + issue in `KIND_COVERAGE`.

## External datasource federation (ADR-0015)

The showcase ships a **code-defined external datasource** that demonstrates the
full federation path with **no external server** — `os dev` just works.

- `src/datasources/showcase-external.datasource.ts` — a second, read-only SQLite
- `src/system/datasources/showcase-external.datasource.ts` — a second, read-only SQLite
database (`schemaMode: 'external'`), separate from the managed standalone DB.
- `src/objects/external/{customer,order}.object.ts` — federated objects
- `src/data/objects/external/{customer,order}.object.ts` — federated objects
(`showcase_ext_customer`, `showcase_ext_order`) bound to the remote tables
`customers` / `orders` via `external.remoteName`. The object names deliberately
differ from the table names to show the remote-table remap.
- `src/datasources/external-fixture.ts` — the stack's `onEnable` hook. It
- `src/system/datasources/external-fixture.ts` — the stack's `onEnable` hook. It
idempotently provisions the fixture SQLite file (tables + seed rows), registers
a live read-only driver under the datasource name, and registers the federated
objects' read metadata.
Expand Down
1 change: 1 addition & 0 deletions examples/app-showcase/e2e/showcase-smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const APP = process.env.SHOWCASE_APP || 'com.example.showcase';
const base = (seg: string) => `/_console/apps/${APP}/${seg}`;

const SURFACES: { name: string; path: string; chart?: boolean }[] = [
{ name: 'Capability Map', path: base('page/showcase_capability_map') },
{ name: 'My Work', path: base('page/showcase_my_work') },
{ name: 'Approvals', path: base('page/showcase_review_queue') },
{ name: 'New Project Wizard', path: base('page/showcase_new_project_wizard') },
Expand Down
66 changes: 40 additions & 26 deletions examples/app-showcase/objectstack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,35 @@ import {
resolveCloudUrl,
} from '@objectstack/cloud-connection';

import * as objects from './src/objects/index.js';
import { ShowcaseExternalDatasource } from './src/datasources/showcase-external.datasource.js';
import { ExternalCustomer, ExternalOrder } from './src/objects/external/index.js';
import { setupShowcaseExternalDatasource } from './src/datasources/external-fixture.js';
import { registerRecalcEndpoint } from './src/server/recalc-endpoint.js';
import { TaskViews, ProjectViews, InquiryViews, BusinessUnitViews } from './src/views/index.js';
import { ShowcaseApp } from './src/apps/index.js';
import { ChartGalleryDashboard, OpsDashboard } from './src/dashboards/index.js';
import { ShowcaseTaskDataset, ShowcaseProjectDataset } from './src/datasets/index.js';
import { allReports } from './src/reports/index.js';
import { allActions } from './src/actions/index.js';
import { StartHerePage, ComponentGalleryPage, ProjectWorkspacePage, ProjectDetailPage, TaskWorkbenchPage, TaskTriagePage, TaskBoardPage, TaskCalendarPage, TaskGalleryPage, TaskSchedulePage, TaskTimelinePage, TaskMapPage, TaskAllViewsPage, ActiveProjectsPage, TaskDetailPage, ReviewQueuePage, NewProjectWizardPage, MyWorkPage, SettingsPage, StylingGalleryPage, CommandCenterPage, CommandCenterJsxPage, CrmWorkbenchPage, AccountCockpitPage, TaskDeskPage, PageVariablesPage, ContactFormPage, RenewalsPipelinePage } from './src/pages/index.js';
import { allFlows } from './src/flows/index.js';
import { allWebhooks } from './src/webhooks/index.js';
import { allHooks } from './src/hooks/index.js';
import { allJobs } from './src/jobs/index.js';
import { allEmails } from './src/emails/index.js';
import { allBooks } from './src/books/index.js';
import * as objects from './src/data/objects/index.js';
import { ShowcaseExternalDatasource } from './src/system/datasources/showcase-external.datasource.js';
import { ExternalCustomer, ExternalOrder } from './src/data/objects/external/index.js';
import { setupShowcaseExternalDatasource } from './src/system/datasources/external-fixture.js';
import { registerRecalcEndpoint } from './src/system/server/recalc-endpoint.js';
import { TaskViews, ProjectViews, InquiryViews, BusinessUnitViews } from './src/ui/views/index.js';
import { ShowcaseApp } from './src/ui/apps/index.js';
import { ChartGalleryDashboard, OpsDashboard } from './src/ui/dashboards/index.js';
import { ShowcaseTaskDataset, ShowcaseProjectDataset } from './src/ui/datasets/index.js';
import { allReports } from './src/ui/reports/index.js';
import { allActions } from './src/ui/actions/index.js';
import { CapabilityMapPage, StartHerePage, ComponentGalleryPage, ProjectWorkspacePage, ProjectDetailPage, TaskWorkbenchPage, TaskTriagePage, TaskBoardPage, TaskCalendarPage, TaskGalleryPage, TaskSchedulePage, TaskTimelinePage, TaskMapPage, TaskAllViewsPage, ActiveProjectsPage, TaskDetailPage, ReviewQueuePage, NewProjectWizardPage, MyWorkPage, SettingsPage, StylingGalleryPage, CommandCenterPage, CommandCenterJsxPage, CrmWorkbenchPage, AccountCockpitPage, TaskDeskPage, PageVariablesPage, ContactFormPage, RenewalsPipelinePage } from './src/ui/pages/index.js';
import { allFlows } from './src/automation/flows/index.js';
import { allWebhooks } from './src/automation/webhooks/index.js';
import { allHooks } from './src/data/hooks/index.js';
import { allJobs } from './src/automation/jobs/index.js';
import { allEmails } from './src/system/emails/index.js';
import { allBooks } from './src/system/books/index.js';
import {
allRoles,
allPermissionSets,
allSharingRules,
} from './src/security/index.js';
import { allThemes } from './src/themes/index.js';
import { ShowcaseTranslationBundle } from './src/translations/index.js';
import { allPortals } from './src/portals/index.js';
import { ShowcaseSeedData } from './src/data/index.js';
import { allThemes } from './src/ui/themes/index.js';
import { ShowcaseTranslationBundle } from './src/system/translations/index.js';
import { allPortals } from './src/ui/portals/index.js';
import { ShowcaseSeedData } from './src/data/seed/index.js';
import { allCubes } from './src/data/analytics/showcase.cube.js';
import { allObjectExtensions } from './src/data/extensions/account.extension.js';

// Ambient `process` for the env-var overrides below — the showcase tsconfig
// doesn't pull in `@types/node`, but the CLI provides the real `process` at
Expand All @@ -54,12 +56,17 @@ const marketplaceUrl = resolveCloudUrl();
* chains. It is built for three audiences at once:
*
* • Demonstration — a coherent project-delivery domain with seeded data
* so every view renders something real.
* so every view renders something real. The Capability Map landing page
* indexes every demo by protocol domain, and five tour docs
* (src/docs/showcase_tour_*.md) walk each domain with live metadata
* embeds.
* • Debugging — open in Studio (`pnpm dev` → http://localhost:3000/_studio)
* and click through the gallery navigation.
* • Verification — `pnpm verify` runs typecheck + the coverage test, which
* introspects the protocol's own enums and fails if any field/chart/
* report type is left uncovered.
* introspects the protocol's own contracts at two levels: every metadata
* kind in DEFAULT_METADATA_TYPE_REGISTRY must be demonstrated or
* explicitly waived (reason + issue), and every enum variant
* (field/chart/report/action) must appear at least once.
*/
export default defineStack({
manifest: {
Expand Down Expand Up @@ -149,12 +156,19 @@ export default defineStack({

// Data
objects: [...Object.values(objects), ExternalCustomer, ExternalOrder],
// Additive overlay merged into showcase_account at registration — the
// package-extends-an-object mechanism (see src/data/extensions/).
objectExtensions: allObjectExtensions,
// Analytics semantic layer served by the foundational analytics capability
// (`/api/v1/analytics/*`) — no `requires` token needed; the CLI always
// loads it and registers these cubes (see src/data/analytics/).
analyticsCubes: allCubes,

// UI
apps: [ShowcaseApp],
portals: allPortals,
views: [TaskViews, ProjectViews, InquiryViews, BusinessUnitViews],
pages: [StartHerePage, ComponentGalleryPage, ProjectWorkspacePage, ProjectDetailPage, TaskWorkbenchPage, TaskTriagePage, TaskBoardPage, TaskCalendarPage, TaskGalleryPage, TaskSchedulePage, TaskTimelinePage, TaskMapPage, TaskAllViewsPage, ActiveProjectsPage, TaskDetailPage, ReviewQueuePage, NewProjectWizardPage, MyWorkPage, SettingsPage, StylingGalleryPage, CommandCenterPage, CommandCenterJsxPage, CrmWorkbenchPage, AccountCockpitPage, TaskDeskPage, PageVariablesPage, ContactFormPage, RenewalsPipelinePage],
pages: [CapabilityMapPage, StartHerePage, ComponentGalleryPage, ProjectWorkspacePage, ProjectDetailPage, TaskWorkbenchPage, TaskTriagePage, TaskBoardPage, TaskCalendarPage, TaskGalleryPage, TaskSchedulePage, TaskTimelinePage, TaskMapPage, TaskAllViewsPage, ActiveProjectsPage, TaskDetailPage, ReviewQueuePage, NewProjectWizardPage, MyWorkPage, SettingsPage, StylingGalleryPage, CommandCenterPage, CommandCenterJsxPage, CrmWorkbenchPage, AccountCockpitPage, TaskDeskPage, PageVariablesPage, ContactFormPage, RenewalsPipelinePage],
dashboards: [ChartGalleryDashboard, OpsDashboard],
books: allBooks,
datasets: [ShowcaseTaskDataset, ShowcaseProjectDataset],
Expand Down
2 changes: 1 addition & 1 deletion examples/app-showcase/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@objectstack/example-showcase",
"version": "0.2.17",
"description": "Kitchen-sink showcase workspace — exercises every metadata type, every view type, every chart type, and the major end-to-end capability chains (security, automation, AI). Built for demonstration, debugging, and coverage-driven verification.",
"description": "Kitchen-sink showcase workspace — exercises every metadata type, every view type, every chart type, and the major end-to-end capability chains (security, automation, analytics). Built for demonstration, debugging, and coverage-driven verification.",
"license": "Apache-2.0",
"private": true,
"main": "./objectstack.config.ts",
Expand Down
Loading