ObjectStackObjectStack

Setup App

The platform's built-in administration UI — what it is, what it shows, and how it is wired

Setup App

The Setup App (/apps/setup) is the built-in administration console for every ObjectStack project. It surfaces the platform sys_* objects, the System Overview dashboard, and a set of settings pages behind a left-hand navigation tree.

Under ADR-0029 D7 the app is not a fixed navigation tree. SETUP_APP ships as a thin shell of stable, empty navigation group anchors ("slots"); the actual menu entries are contributed at runtime by the packages that own the underlying objects, via navigationContributions. The runtime merges every contribution into the app's navigation tree by group id + priority on read, so the rendered menu reflects exactly which capability plugins are loaded — a disabled capability contributes nothing and its slot stays empty.

The app itself ships from the dedicated @objectstack/setup package (package id com.objectstack.setup), which registers it at runtime. Per ADR-0048 (one app per package), /apps/setup — resolvable as /apps/<packageId> — maps to exactly this app.

Where it lives

FilePurpose
packages/platform-objects/src/apps/setup.app.tsThe App definition — the navigation shell (group anchors), branding, required permissions
packages/platform-objects/src/apps/setup-nav.contributions.tsSETUP_NAV_CONTRIBUTIONS — the nav entries owned by @objectstack/platform-objects, merged into the shell at runtime
packages/platform-objects/src/apps/dashboards/system_overview.dashboard.ts"Overview → System Overview" dashboard
packages/apps/setup/src/index.ts@objectstack/setup package — SetupAppPlugin.start() performs the runtime registration via manifest.register({ apps: [SETUP_APP], navigationContributions: SETUP_NAV_CONTRIBUTIONS })

The requiredPermissions: ['setup.access'] permission declared on the Setup App is contributed by plugin-security (in its default permission sets), not by the package that registers the app. Other capability plugins (e.g. plugin-audit, plugin-webhooks, plugin-approvals) contribute their own Setup nav entries into the shared group anchors.

setup.app.ts defines the stable group anchors (the shell); the entries under each group are merged in from the contributing packages. The group anchors are:

Group (anchor id)Filled by
Overview (group_overview)System Overview dashboard — platform-objects
Apps (group_apps)Capability plugins only (e.g. marketplace via cloud-connection); empty otherwise
People & Organization (group_people_org)Users · Departments · Teams · Organizations · Invitations — platform-objects
Access Control (group_access_control)Positions / Permission Sets — plugin-security; Sharing Rules / Record Shares — plugin-sharing; API Keys — platform-objects
Approvals (group_approvals)plugin-approvals
Configuration (group_configuration)All Settings · Branding · Authentication · Email · File Storage · AI & Embedder · Knowledge · Feature Flags — platform-objects
Diagnostics (group_diagnostics)Sessions · Notification Events — platform-objects; Audit Logs — plugin-audit
Integrations (group_integrations)plugin-webhooks
Advanced (group_advanced)OAuth Applications · Signing Keys (JWKS) · Identity Links · User Preferences — platform-objects

The exact rendered menu depends on which capability plugins are loaded. A few notable entries:

  • Sessions (sys_session) — better-auth session records, contributed into group_diagnostics.
  • OAuth Applications (sys_oauth_application) — third-party OAuth client registrations, contributed into group_advanced.
  • Signing Keys (JWKS) (sys_jwks) — JWKS keys used for OIDC / JWT signing, contributed into group_advanced. The nav item is gated on the manage_platform_settings capability, and the object itself is access: { default: 'private' } (ADR-0066 ④) — signing keys are never covered by the wildcard grant, so non-admins are denied server-side. (sys_verification and sys_device_code are deliberately not in the nav: sensitive, ephemeral secrets — not browsable, and also private.)
  • Audit Logs (sys_audit_log) — contributed by plugin-audit into group_diagnostics. (The sys_activity and sys_comment objects also live in plugin-audit, but they are not contributed as Setup nav entries.)

Why a shell + contributions

The Setup App is a shell of empty group anchors rather than a fixed navigation tree because the objects it surfaces are owned by different capability plugins (auth / security / sharing / audit / webhooks / approvals). Letting each package contribute its own menu entries keeps the menu for an object shipping with the package that owns the object — the UI-layer analog of object extend. Benefits:

  • The rendered menu always matches the loaded capabilities: a disabled plugin contributes nothing and its slot stays empty.
  • No code in setup.app.ts needs to know about objects that live in other packages; entries are merged by group id + priority on read.
  • The shell can still be type-checked against App from @objectstack/spec/ui, and contributions against NavigationContribution.

Customising it

You do not edit setup.app.ts to add entries — it only holds the empty group anchors. To add a new entry:

  1. Register the object/dashboard in the package that owns it (or in a project-local plugin if it is project-specific).
  2. Add a NavigationContribution targeting the relevant group id (app: 'setup', group: 'group_*') — either in SETUP_NAV_CONTRIBUTIONS for @objectstack/platform-objects-owned objects, or in the navigationContributions of the plugin that owns the object.
  3. If the entry needs its own permission, declare it where the relevant permissions live (e.g. setup.access is granted in plugin-security's default permission sets) so the requiredPermissions check picks it up.

For project-local Setup-style entries, define a separate App in your project — Setup is reserved for platform-level administration.

On this page