Skip to content

Latest commit

 

History

History
298 lines (236 loc) · 10.1 KB

File metadata and controls

298 lines (236 loc) · 10.1 KB
title App Metadata
description Define application containers with navigation, branding, and access control

App Metadata

An App is a logical container that bundles objects, views, pages, and dashboards into a cohesive application experience. It defines the navigation structure, branding, and access permissions.

Basic Structure

{/* os:check */}

const crmApp = {
  name: 'crm',
  label: 'CRM',
  version: '1.0.0',
  description: 'Customer Relationship Management',
  icon: 'briefcase',
  active: true,

  branding: {
    primaryColor: '#1a73e8',
    logo: '/assets/crm-logo.svg',
    favicon: '/assets/favicon.ico',
  },

  navigation: [
    { id: 'nav_accounts', type: 'object', label: 'Accounts', objectName: 'account', icon: 'building' },
    { id: 'nav_contacts', type: 'object', label: 'Contacts', objectName: 'contact', icon: 'users' },
    { id: 'nav_opportunities', type: 'object', label: 'Opportunities', objectName: 'opportunity', icon: 'trending-up' },
    { id: 'nav_sales_dashboard', type: 'dashboard', label: 'Sales Dashboard', dashboardName: 'sales_overview', icon: 'bar-chart' },
  ],

  requiredPermissions: ['crm_access'],
};

App Properties

Property Type Required Description
name string Machine name (snake_case)
label string Display name
version string optional App version
description string optional App description
icon string optional App icon (Lucide)
active boolean optional Is app active (default: true)
isDefault boolean optional Is default app
navigation NavigationItem[] optional Navigation tree
branding AppBranding optional Visual customization
requiredPermissions string[] optional Required permissions to access
homePageId string optional ID of the navigation item to serve as the landing page
objects unknown[] optional Objects belonging to this app
apis unknown[] optional Custom APIs belonging to this app
mobileNavigation object optional Mobile-specific navigation

Navigation Items

The navigation tree supports nine item types, combined to create rich menu structures: object, dashboard, page, url, report, action, component, group and separator. Each is documented below.

type is the discriminator: a value outside that list is rejected with the full set of valid ones, and every other key is checked against the branch you picked rather than against all nine.

Object Navigation

Links to an object's list view:

{ id: 'nav_accounts', type: 'object', label: 'Accounts', objectName: 'account', icon: 'building', viewName: 'all_accounts' }

Three optional target fields refine where the entry lands. They are mutually exclusive — combining filters with recordId or viewName is rejected at validation, and the only tolerated pairing is the legacy recordId + viewName (where recordId wins and viewName is ignored):

  • viewName — anchor the entry to a named list view.
  • recordId — deep-link straight to one record ("My Profile"); supports {current_user_id} / {current_org_id} template variables.
  • filters — a one-off parameterized slice: the entry lands on the bare data surface (/:objectName/data) with each condition serialized as a removable filter[<field>]=<value> URL chip, not anchored to any saved view. Use it for drill-throughs and "assigned to me"-style links instead of authoring a view; values support the same template variables. The surface shows what row-level permissions allow — it is not a security feature.
{ id: 'nav_my_open', type: 'object', label: 'My Open Deals', objectName: 'opportunity',
  filters: { owner_id: '{current_user_id}', status: 'open' }, icon: 'user-check' }

Dashboard Navigation

Links to a dashboard:

{ id: 'nav_analytics', type: 'dashboard', label: 'Analytics', dashboardName: 'sales_overview', icon: 'bar-chart' }

Page Navigation

Links to a custom page:

{ id: 'nav_settings', type: 'page', label: 'Settings', pageName: 'app_settings', icon: 'settings', params: { tab: 'general' } }

URL Navigation

Links to an external URL:

{ id: 'nav_help', type: 'url', label: 'Help Center', url: 'https://help.example.com', icon: 'help-circle', target: '_blank' }

Group Navigation

Groups items into collapsible sections with children:

{
  id: 'grp_sales',
  type: 'group',
  label: 'Sales',
  icon: 'dollar-sign',
  expanded: true,
  children: [
    { id: 'nav_accounts', type: 'object', label: 'Accounts', objectName: 'account', icon: 'building' },
    { id: 'nav_contacts', type: 'object', label: 'Contacts', objectName: 'contact', icon: 'users' },
    { id: 'nav_opportunities', type: 'object', label: 'Opportunities', objectName: 'opportunity', icon: 'trending-up' },
  ],
}

Report Navigation

Links to a saved report:

{ id: 'nav_pipeline', type: 'report', label: 'Pipeline Report', reportName: 'sales_pipeline', icon: 'file-bar-chart' }

Action Navigation

Runs an action instead of navigating to a surface. The reference lives in a nested actionDef block — actionName is not a top-level key on the item:

{
  id: 'nav_import',
  type: 'action',
  label: 'Import Records',
  icon: 'upload',
  actionDef: {
    actionName: 'bulk_import',
    params: { objectName: 'account', mode: 'upsert' },
  },
}

actionDef accepts only actionName and params. params itself is open by design — the action owns its own parameter contract, so the app schema does not validate what goes inside it.

Component Navigation

Renders a registered component. componentRef is a component-registry key, not a file path:

{ id: 'nav_directory', type: 'component', label: 'Directory', componentRef: 'metadata:directory', icon: 'contact' }

params is handed to the component as props and is open by design — the props are the component's own contract.

Separator

A visual divider in the navigation list. It renders no target and carries no label — the only keys it accepts are type, an optional id, and an optional order:

{ type: 'separator', order: 30 }

Common Navigation Properties

All navigation items except separator share these base properties. Every item must declare a unique id (lowercase snake_case) — it is required by the schema and is referenced by homePageId and mobileNavigation.bottomNavItems. (On a separator, id is optional and the remaining properties below are rejected — a divider has nothing to label, gate, or badge.)

Property Type Description
id string Unique identifier (snake_case, required)
label string Display label
icon string Icon name (Lucide)
order number Sort order within the same level (lower = first)
badge string | number Badge text or count displayed on the item
visible Expression Visibility predicate (CEL expression)
requiredPermissions string[] Permissions required to see/access this item
requiresObject string Hide/disable unless the named object is registered
requiresService string Hide/disable unless the named kernel service is registered

Branding

Customize the visual appearance of the app:

branding: {
  primaryColor: '#1a73e8',    // Hex color code
  logo: '/assets/logo.svg',   // Logo URL
  favicon: '/assets/icon.ico', // Favicon URL
}
Property Type Description
primaryColor string Primary brand color (hex)
logo string Logo image URL
favicon string Favicon URL

Mobile Navigation

Configure mobile-specific navigation behavior:

mobileNavigation: {
  mode: 'bottom_nav',
  bottomNavItems: ['nav_home', 'nav_accounts', 'nav_contacts', 'nav_settings'],
}

mode accepts 'drawer' (default), 'bottom_nav', or 'hamburger'. bottomNavItems lists the navigation item ids to surface in the bottom bar (max 5).

Complete Example

{/* os:check */}

const projectApp = {
  name: 'project_management',
  label: 'Project Management',
  version: '2.0.0',
  description: 'Track projects, tasks, and team workload',
  icon: 'folder-kanban',
  active: true,

  branding: {
    primaryColor: '#6366f1',
    logo: '/assets/pm-logo.svg',
  },

  navigation: [
    {
      id: 'nav_home',
      type: 'page',
      label: 'Home',
      pageName: 'pm_home',
      icon: 'home',
    },
    {
      id: 'grp_projects',
      type: 'group',
      label: 'Projects',
      icon: 'folder',
      expanded: true,
      children: [
        { id: 'nav_projects', type: 'object', label: 'Projects', objectName: 'project', icon: 'folder' },
        { id: 'nav_tasks', type: 'object', label: 'Tasks', objectName: 'project_task', icon: 'check-square', viewName: 'task_board' },
        { id: 'nav_milestones', type: 'object', label: 'Milestones', objectName: 'milestone', icon: 'flag' },
      ],
    },
    {
      id: 'grp_reports',
      type: 'group',
      label: 'Reports',
      icon: 'bar-chart',
      children: [
        { id: 'nav_overview', type: 'dashboard', label: 'Overview', dashboardName: 'project_overview', icon: 'layout-dashboard' },
        { id: 'nav_team_workload', type: 'dashboard', label: 'Team Workload', dashboardName: 'team_workload', icon: 'users' },
      ],
    },
    {
      id: 'nav_docs',
      type: 'url',
      label: 'Documentation',
      url: 'https://docs.example.com/pm',
      icon: 'book-open',
      target: '_blank',
    },
  ],

  requiredPermissions: ['pm_access'],
  homePageId: 'nav_home',
};

Related