データモデル
オブジェクト、フィールド、リレーションシップ、バリデーション、インデックス — AI に説明するか、TypeScript で記述します。
データモデル
データモデルは、アプリにとって唯一の信頼できる情報源です。オブジェクトが 存在するようになると、ObjectOS は REST API、Console ビュー、RBAC の チェックポイント、監査ログのエントリ、そして AI ツールへの公開を — 無償で 提供します。
**ほとんどのお客様はスキーマを手書きすることはありません。**必要なものを AI Builder で説明すると、プラットフォームが オブジェクト、フィールド、インデックス、翻訳を作成します。このページでは その基盤となる構造を説明します — AI が生成しているものを理解し、必要に 応じて直接編集できるようにするためです。
オーサリングのパス
| パス | 具体例 |
|---|---|
| AI Builder(推奨) | 「subject、description、priority、status、assignee を持つ support_ticket オブジェクトを作成して。」 |
| Console のクリックビルド | Console → Objects → New Object → フォーム |
TypeScript(*.object.ts) | 下に示す TS — 通常はフォークしたテンプレートの中で記述 |
この 3 つはいずれも同じスキーマを生成します。スキーマが正規のものであり、 それ以外はすべて派生物です。
オブジェクトの構造
// src/objects/task.ts
import { ObjectSchema, Field } from '@objectstack/spec/data';
export const Task = ObjectSchema.create({
name: 'todo_task',
label: 'Task',
pluralLabel: 'Tasks',
icon: 'check-square',
description: 'A single unit of work.',
fields: {
subject: Field.text({ label: 'Subject', required: true, maxLength: 200 }),
description: Field.markdown({ label: 'Description' }),
status: Field.select({
label: 'Status',
options: [
{ label: 'To Do', value: 'todo', default: true },
{ label: 'In Progress', value: 'in_progress' },
{ label: 'Done', value: 'done' },
],
}),
due: Field.date({ label: 'Due' }),
assignee: Field.lookup('sys_user', { label: 'Assignee' }),
},
enable: {
trackHistory: true, // record field changes in audit log
apiEnabled: true, // expose REST endpoints (default true)
feeds: true, // chatter / comments / @mentions
},
});スタックに登録します:
// objectstack.config.ts
import { defineStack } from '@objectstack/spec';
import * as objects from './src/objects';
export default defineStack({
manifest: { id: 'my.app', namespace: 'myapp', version: '0.1.0', type: 'app', name: 'My App' },
objects: Object.values(objects),
});必要なのはこれだけです。os dev が再コンパイルを行い、/api/v1/data/todo_task、
Console の Task ビュー、そして Console のパーミッション行がすべて表示されます。
フィールドタイプ
ObjectStack には約 25 種類のフィールドタイプが付属します。よく使われるものは 次のとおりです:
スカラー
| タイプ | 格納する内容 | ヘルパー |
|---|---|---|
text | 短い文字列 | Field.text({ maxLength, required }) |
textarea | 長い文字列 | Field.textarea(...) |
markdown | markdown 形式のリッチテキスト | Field.markdown(...) |
number | 整数 | Field.number({ min, max }) |
decimal | 正確な小数(金額など) | Field.decimal({ precision, scale }) |
boolean | 真偽値 | Field.boolean({ defaultValue }) |
date | カレンダー日付 | Field.date(...) |
datetime | タイムスタンプ | Field.datetime(...) |
email | バリデーション済みメールアドレス | Field.email(...) |
url | バリデーション済み URL | Field.url(...) |
phone | バリデーション済み電話番号 | Field.phone(...) |
json | 任意の JSON | Field.json(...) |
選択肢
| タイプ | 用途 |
|---|---|
select | 単一選択(列挙) |
multiselect | 複数選択 |
リレーションシップ
| タイプ | カーディナリティ | ヘルパー |
|---|---|---|
lookup | 一対多(FK) | Field.lookup({ reference: 'sys_user' }) |
masterDetail | カスケード削除付きの一対多 | Field.masterDetail({ reference: 'order' }) |
ファイルとメディア
| タイプ | 格納する内容 |
|---|---|
file | ストレージサービス経由の単一ファイル |
image | プレビュー付きの画像ファイル |
計算 / 派生
| タイプ | 動作 |
|---|---|
formula | CEL 式から読み取り時に計算 |
summary | 関連レコードの集計(sum/count/avg) |
autonumber | シーケンス(INV-{000001}) |
created, lastModified | システムが保守するタイムスタンプ |
createdBy, lastModifiedBy | システムが保守するユーザー参照 |
必須 / 一意 / デフォルト
すべてのスカラーフィールドで共通の修飾子:
Field.text({
label: 'Code',
required: true,
unique: true, // unique constraint enforced at DB level
defaultValue: '',
helpText: 'Internal short code',
})バリデーション
インライン:
Field.number({ label: 'Quantity', min: 1, max: 9999 })
Field.text({ label: 'SKU', pattern: '^[A-Z]{3}-[0-9]{4}$' })オブジェクトレベルのルール(フィールド間):
ObjectSchema.create({
name: 'order',
fields: { /* ... */ },
validations: [
{
name: 'discount_lt_total',
message: 'Discount cannot exceed total',
condition: 'discount < total',
},
],
});バリデーションはあらゆる書き込み時に実行されます — REST、Console、ObjectQL のいずれでも — そのため「裏口」は存在しません。
インデックスとパフォーマンス
ObjectSchema.create({
name: 'order',
fields: { /* ... */ },
indexes: [
{ fields: ['status', 'created_at'] },
{ fields: ['account', 'created_at'], unique: false },
],
});ドライバーはスキーマ同期時に実際の DB インデックスを作成します。
フィールドグループ
長いフォームでは、Console 内でフィールドをグループ化します:
ObjectSchema.create({
name: 'task',
fieldGroups: [
{ key: 'core', label: 'Task', icon: 'check-square' },
{ key: 'planning', label: 'Planning', icon: 'calendar' },
{ key: 'meta', label: 'Metadata', icon: 'info', defaultExpanded: false },
],
fields: {
subject: Field.text({ label: 'Subject', group: 'core' }),
due: Field.date({ label: 'Due', group: 'planning' }),
},
});ライフサイクルと所有権
ObjectSchema.create({
name: 'task',
ownership: 'own', // 'own' | 'shared' | 'system'
enable: {
apiEnabled: true, // generated REST endpoints
trackHistory: true, // audit log of field changes
feeds: true, // sys_comment / sys_activity / @mentions
softDelete: true, // tombstone instead of hard delete
},
});システムオブジェクト(すべてのプロジェクトで無償)
これらを宣言する必要はありません — 常に存在します:
| オブジェクト | 内容 |
|---|---|
sys_user | ユーザーアカウント |
sys_org | 組織 / テナント |
sys_member | 組織のメンバーシップ |
sys_role, sys_permission_set | RBAC のプリミティブ |
sys_audit_log | 監査証跡(監査機能がロードされている場合) |
sys_file, sys_attachment | ファイルのメタデータ(ストレージがロードされている場合) |
sys_comment, sys_activity | フィード / chatter(フィードがロードされている場合) |
sys_session, sys_api_key | 認証アーティファクト |
sys_webhook, sys_webhook_delivery | Webhook サブスクリプション(有効化されている場合) |
lookup フィールドでは名前で参照します — 例: Field.lookup({ reference: 'sys_user' })。
ポリモーフィックなプラットフォーム機能
feeds: true と trackHistory: true を有効にすると、オブジェクトは
自動的に次の機能に参加します:
sys_comment(thread_id =<object>:<id>)sys_attachment(parent_object =<object>、parent_id =<id>)sys_activity(タイムライン)sys_audit_log(フィールドレベルの差分)
これらをオブジェクトごとに配線する必要はありません — プラットフォーム上で ポリモーフィックに動作します。
次に読むべきもの
- パーミッション — オブジェクトへのアクセスを制御
- フロー / 自動化 — レコードの変更に反応
- API アクセス — 生成された REST を呼び出す
os explain— レンダリングされたスキーマを出力@objectstack/specソース — スキーマが契約であり、ここに記載されているものはすべてそこから派生します