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
10 changes: 10 additions & 0 deletions packages/platform-objects/src/apps/account.app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ export const ACCOUNT_APP: App = {
isDefault: false,
// Surface via the avatar dropdown, not the App Switcher — see App.hidden.
hidden: true,
// ADR-0010 §3.7 — author-facing protection block. Loader translates
// this into the `_lock` envelope at registration time. Every
// authenticated user depends on this app to manage their own
// sessions / API keys / linked accounts, so a tenant overlay that
// breaks it is a security-relevant outage — same class as Setup.
protection: {
lock: 'full',
reason: 'Core self-service security UI shipped by @objectstack/platform-objects — see ADR-0010.',
docsUrl: 'https://docs.objectstack.ai/adr/0010-metadata-protection',
},
branding: {
primaryColor: '#0ea5e9', // sky-500 — distinct from Setup's slate
},
Expand Down
10 changes: 3 additions & 7 deletions packages/platform-objects/src/apps/setup-nav.contributions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,9 @@ export const SETUP_NAV_CONTRIBUTIONS: NavigationContribution[] = [
{ id: 'nav_system_overview', type: 'dashboard', label: 'System Overview', dashboardName: 'system_overview', icon: 'activity' },
],
},
{
app: 'setup',
group: 'group_apps',
priority: BASE_PRIORITY,
items: [
],
},
// No group_apps contribution left here — both marketplace entries moved
// out (see header note); the group_apps shell anchor in setup.app.ts is
// filled entirely by capability plugins now.
{
app: 'setup',
group: 'group_people_org',
Expand Down
9 changes: 9 additions & 0 deletions packages/platform-objects/src/apps/studio.app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ export const STUDIO_APP: App = {
icon: 'hammer',
active: true,
isDefault: false,
// ADR-0010 §3.7 — author-facing protection block. Loader translates
// this into the `_lock` envelope at registration time. Same rationale
// as Setup: tenant overlay edits to the metadata workbench can lock
// implementers out of the very surface used to repair metadata.
protection: {
lock: 'full',
reason: 'Core developer workbench shipped by @objectstack/platform-objects — see ADR-0010.',
docsUrl: 'https://docs.objectstack.ai/adr/0010-metadata-protection',
},
// Studio is the metadata-authoring host, so its ambient copilot is
// pinned to the schema-architect agent. Resolved by the ambient chat
// endpoint via `app.defaultAgent` — no UI-side `?agent=` override
Expand Down
20 changes: 19 additions & 1 deletion packages/platform-objects/src/platform-objects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
SysMetadataHistoryObject,
} from './metadata/index.js';
import { SysSetting } from './system/index.js';
import { SETUP_APP, SETUP_NAV_CONTRIBUTIONS } from './apps/index.js';
import { ACCOUNT_APP, SETUP_APP, SETUP_NAV_CONTRIBUTIONS, STUDIO_APP } from './apps/index.js';
import { AppSchema } from '@objectstack/spec/ui';

const systemObjects = [
Expand Down Expand Up @@ -156,6 +156,24 @@ describe('@objectstack/platform-objects', () => {
});
});

describe('platform app protection (ADR-0010 §3.7)', () => {
// All three platform apps are core UI shipped by this package: a
// tenant overlay that breaks Setup/Studio locks admins/implementers
// out of the repair surface, and Account is every user's only
// self-service security surface. The loader translates `protection`
// into the `_lock` envelope; clients (e.g. objectui's
// isNavigationSyncableApp) rely on `_lock` to skip automatic
// navigation writes into these apps.
it.each([
['SETUP_APP', SETUP_APP],
['STUDIO_APP', STUDIO_APP],
['ACCOUNT_APP', ACCOUNT_APP],
])('%s declares a full lock', (_name, app) => {
expect(app.protection?.lock).toBe('full');
expect(() => AppSchema.parse(app)).not.toThrow();
});
});

describe('SETUP_NAV_CONTRIBUTIONS (ADR-0029 D7)', () => {
const shellGroupIds = new Set(
(SETUP_APP.navigation ?? []).map((n) => n.id),
Expand Down