A fork-ready console scaffold wired against a real ObjectStack backend.
src/App.tsx owns the routing tree and is the file you edit; everything the user
then sees inside it — objects, fields, views, relationships, dashboards — is
served by the backend, not defined here.
The whole app is ~70 lines of JSX in src/App.tsx, assembled from
building blocks exported by @object-ui/app-shell
(ConsoleShell.tsx):
| Piece | What it gives you |
|---|---|
ConsoleShell |
Top-level provider stack: theme, navigation, favorites, notifications, Suspense. Goes inside BrowserRouter, around Routes. |
AuthenticatedRoute |
AuthGuard + ConnectedShell + RequireOrganization, the guard for protected routes. requireOrganization={false} opts out (the /organizations route shows this). |
ConnectedShell |
The data layer — AdapterProvider (an ObjectStackAdapter at VITE_SERVER_URL) + MetadataProvider. |
RootRedirect / SystemRedirect |
/ → /home once metadata loads; legacy /system/* → /apps/setup/*. |
Default* pages |
Drop-in login / register / forgot-password / home / organizations screens — replace any one with your own component. |
DefaultAppContent |
Mounted at /apps/:appName/*. This is the console proper: layout, command palette, and the object / record / dashboard / report / page routes. |
Auth is AuthProvider from @object-ui/auth pointed at
${VITE_SERVER_URL}/api/v1/auth. src/main.tsx registers ten view
plugins by side-effect import (grid, kanban, calendar, charts, list, detail, view,
form, dashboard, report) and loads UI translations from
${VITE_SERVER_URL}/api/v1/i18n/translations/:lang.
vite.config.ts aliases 29 @object-ui/* specifiers to
packages/*/src so plugin registration hits one ComponentRegistry singleton — a
monorepo detail. Drop the aliases when you consume published packages. The list is
closed under its own import graph — aliased source imports only aliased
packages — and test/vite-alias-closure.test.ts
re-derives that graph on every run so the list cannot silently drift out of date
again.
- Not a schema or relationship modelling example. Nothing in this directory
declares an object, a field or a relationship — there is no schema JSON here at
all; those live on the server. If you came here to see how relationships are
modelled, you want
../schema-catalog/and the docs (content/docs/fields/lookup.mdxfor lookup / master-detail). - Not a bring-your-own-backend example. The data layer is hardwired to
ObjectStackAdapter. For your own REST/GraphQL API see../byo-backend-console/. - Not an offline demo. There is no mock server here; nothing past the login screen renders without a live backend.
# from the monorepo root
pnpm install
cd examples/console-starter
pnpm dev # Vite; no server.port is set, so the default 5173pnpm dev needs no prior build. Every workspace package the app reaches is on
the alias list, so Vite serves all of them from src. This was not always true:
five packages the aliased sources import — @object-ui/mobile,
@object-ui/providers, @object-ui/sdui-parser, @object-ui/plugin-editor,
@object-ui/react-runtime — were missing from the list, fell back to node
resolution onto packages/*/dist, and produced 500s behind an empty #root with
nothing on the page to say why (objectui#3528).
pnpm build and pnpm type-check still need pnpm -w build first. Those run
tsc, which resolves @object-ui/* through node_modules rather than through the
Vite aliases — and each package's types entry points at dist/index.d.ts, which
exists only after a build. Skip it and tsc reports TS2307: Cannot find module '@object-ui/app-shell' or its corresponding type declarations:
# from the monorepo root
pnpm -w build
cd examples/console-starter
pnpm buildVITE_SERVER_URL is the one setting that matters — the adapter, auth, i18n and
action endpoints all hang off it. An empty value means same-origin, for when the
ObjectStack server serves the console itself.
| File | Value |
|---|---|
.env.development |
empty (same-origin) |
.env.production |
empty (same-origin) |
Both files ship empty. In dev, the Vite server proxies /api/* to
http://localhost:3000 by default; to point dev at a different backend while
keeping one origin, set DEV_PROXY_TARGET, e.g.
DEV_PROXY_TARGET=https://demo.objectstack.ai pnpm dev.
Point it at any ObjectStack server. If you need one locally, this repo's live-e2e
helper e2e/live/ci/start-backend.sh boots a
real objectstack dev on port 4010 with a seeded admin — it is the CI lane's
script, so expect it to fetch the showcase app metadata and npm install
published @objectstack/* packages first.
(VITE_USE_MOCK_SERVER appears in both .env files, copied from apps/console.
Nothing in this repo reads it. There is no mock mode.)
Measured with nothing listening on :3000, pnpm dev on a free port, headless
Chromium on /:
/ redirects to /login. The root route is wrapped in AuthenticatedRoute
(objectui#4042), so the guard resolves the session before RootRedirect — and the
/meta/* reads behind it — ever mount. The branded "Initializing application... /
Connecting to data source" screen still appears, but only as a transient frame
while GET /api/v1/auth/get-session is in flight; the redirect lands within a few
hundred milliseconds of that request being refused. /login then renders in full
but cannot sign in. The browser console shows ERR_CONNECTION_REFUSED for
/api/v1/auth/get-session, /api/v1/auth/config and
/api/v1/i18n/translations/en.
A stored credential does not change this. isAuthenticated is
user !== null && session !== null, and both come only from the server's
get-session answer — localStorage holds a bearer token, never a session — so
seeding auth-session-token and reloading / still lands on /login. With the
backend down no cold load reaches an authenticated state, so nothing below the
guard renders. (Not measured: a session signed in against a live backend that is
then killed under it; until the next reload that one still holds its in-memory
session.)
Full table in the examples catalog. Short version:
hello-world/— the JSON → UI pipeline, one schema, no backend.byo-backend-console/— embed ObjectUI in your own app, against your own API.console-starter/(this one) — stand up a new ObjectStack console: fork it and editsrc/App.tsx.schema-catalog/— not an app; the canonical schema corpus used by the docs and tests.
apps/console/src/App.tsx is the same composition with more routes — read it when
you outgrow this one.