ObjectOS
構建介面

應用與導航

把物件、檢視、頁面和儀表盤打包成一個帶品牌、可導航的外殼 —— 並精確控制誰能看到什麼。

應用是一個邏輯容器,把物件、檢視、頁面和儀表盤打包成一體化的體驗。它定義導航樹、品牌,以及 —— 最關鍵的 —— 誰能進來。

import { App } from '@objectstack/spec/ui'

export const CrmApp = App.create({
  name: 'crm_app',
  label: 'CRM',
  icon: 'briefcase',
  branding: { primaryColor: '#2563EB' },
  navigation: [
    { id: 'group_sales', type: 'group', label: 'Sales', icon: 'briefcase', children: [
      { id: 'nav_leads',    type: 'object', objectName: 'crm_lead',    label: 'Leads',    icon: 'funnel' },
      { id: 'nav_accounts', type: 'object', objectName: 'crm_account', label: 'Accounts', icon: 'building' },
    ]},
  ],
  requiredPermissions: ['crm_access'],
})

應用屬性

屬性型別必填說明
namestring機器名(snake_case
labelstring顯示名
iconstring應用圖示(Lucide)
description / versionstring用於列表展示的後設資料
activeboolean應用是否啟用(預設 true
isDefaultboolean是否為預設應用
navigationNavigationItem[]導航樹
brandingAppBrandingprimaryColorlogofavicon
requiredPermissionsstring[]誰可以開啟這個應用
homePageIdstring用作著陸頁的導航項 id
mobileNavigationobject移動端專屬導航

導航項

導航樹支援八種專案型別。常用的五種是 objectdashboardpageurlgroup;規範還定義了 reportactioncomponent 三種。

type落到哪裡關鍵配置
object物件的列表檢視objectName,外加可選的定位配置(見下)
dashboard一個儀表盤dashboardName
page一個自定義頁面pageName、可選 params
url一個外部 URLurltarget: '_blank'
group可摺疊分組childrenexpanded

每個導航項必須宣告唯一的 id(小寫 snake_case)—— homePageIdmobileNavigation.bottomNavItems 引用的就是它。公共屬性:labeliconorderbadge,再加下面的門控三件套。

定位 object 入口

三個可選欄位可以細化 object 入口落到哪裡,優先順序為 recordIdfiltersviewName

  • viewName —— 把入口錨定到某個具名列表檢視。
  • recordId —— 深鏈到單條記錄("我的資料");支援 {current_user_id} / {current_org_id} 模板變數。
  • filters —— 一次性的引數化切片:入口落到裸資料介面上,每個條件是一個可移除的 URL 篩選標籤。適合"分派給我"這類連結,不必專門寫檢視。這不是安全特性 —— 顯示什麼仍由行級許可權決定。
{ id: 'nav_my_open', type: 'object', label: 'My Open Deals', objectName: 'opportunity',
  filters: { owner_id: '{current_user_id}', status: 'open' }, icon: 'user-check' }

移動端導航

mobileNavigation: {
  mode: 'bottom_nav',                    // 'drawer'(默认)| 'bottom_nav' | 'hamburger'
  bottomNavItems: ['nav_home', 'nav_accounts', 'nav_contacts'],  // 导航项 id,最多 5 个
}

按受眾門控應用

同一份資料服務於兩類截然不同的受眾:設計 Schema 的構建者,和只錄入、檢視資料的終端使用者。預設就把這兩類介面分開 —— 別指望每位管理員手動把東西藏起來。

受眾介面門控方式
終端使用者(消費者)精心組織的應用 → page / view 入口App.requiredPermissions、導航項門控
構建者 / 管理員Setup / Studio、原始物件表格能力:setup.accessstudio.accessmanage_metadata

內建許可權集已經編碼了這種分割:member_defaultviewer_readonly 攜帶 studio.access / manage_metadata,因此構建者介面對他們不可見;admin_full_accessorganization_admin 則攜帶。

每個導航項支援三種相互獨立的門控:

門控型別隱藏該項,除非……
requiredPermissionsstring[]使用者持有該 RBAC 能力(如 manage_metadata
visibleCEL 表示式謂詞求值為 true(如 'org_admin' in current_user.positions
requiresObject / requiresServicestring具名物件 / 核心服務已安裝
navigation: [
  { id: 'nav_contacts', type: 'object', label: 'Contacts', objectName: 'showcase_contact' },
  // 仅构建者可见的入口 —— 消费者永远不会渲染它:
  { id: 'nav_designer', type: 'component', label: 'Object Designer',
    componentRef: 'metadata:resource', params: { type: 'object' },
    requiredPermissions: ['manage_metadata'] },
]

**隱藏,而不是停用。**停用但可見的構建者入口仍是噪音。被門控的導航項對缺少該能力的使用者根本不渲染 —— 不留下讓終端使用者困惑的灰色擺設。

還有兩個習慣能讓消費者介面保持乾淨:

  • 給終端使用者一個頁面,而不是原始表格。page 入口讓你精確策劃暴露的內容 —— 精選的列、固定的視覺化、只有你啟用的篩選和操作。object 入口給出的則是寬鬆的表格:可切換檢視、個人檢視、完整工具欄。
  • **也要策劃資料介面本身。**優先用精心組織的檢視,而不是放開原始物件讀取,把使用者扔到一個 40 列的表格上。

操作門控是雙面的:UI 隱藏或停用按鈕,同時服務端拒絕呼叫 —— 不存在"只在 UI 門控、服務端敞開"的坑。見操作

Setup 應用 —— 一個內建示例

平臺自身的管理 UI —— Setup(管理後臺)應用 —— 本身就是用同一套應用後設資料協議渲染的:導航、頁面與門控都宣告為資料,由渲染你的應用的同一個渲染器繪製。它的門控方式正是你的構建者介面應有的方式:藏在消費者許可權集不攜帶的 setup.access 能力後面。如果你想要"應用即後設資料"可以規模化的證據 —— 你已經在用了。

反模式

  • 把每個終端使用者都當成構建者級協作者,再一個個隱藏選項卡。應該讓消費者 / 構建者分割成為預設。
  • **停用而不是隱藏構建者入口。**可見但失效的擺設照樣讓人困惑。
  • 放開原始物件讀取,而其實一個精心組織的頁面就能恰好暴露終端使用者需要的內容。

下一步

頁面原因
檢視object 導航入口落到的地方
頁面面向終端使用者的精心組織的 page 入口
儀表盤dashboard 入口渲染的內容
操作按鈕及其雙面門控
許可權requiredPermissions 背後的許可權集
介面總覽各部分如何組合

On this page