objectstack-data について
objectstack-dataは、ObjectStackのデータモデル作成者向けのプロトコルリファレンススキルです。オブジェクト、フィールド、関係、アクセス制御、ライフサイクル、データソースに加え、条件付きフィールド規則とスキーマ変更の制約を扱います。
主な機能
- 01オブジェクトとフィールド定義を参照
- 02関係・インデックス・検証を解説
- 03アクセス制御とデータライフサイクルを記載
- 04データソースとフェデレーション設定を説明
- 05条件規則とスキーマ変更を解説
活用シーン
- 01ObjectStackのオブジェクトとフィールドを設計
- 02データアクセスと保持ポリシーを設定
- 03フィールドの条件付き表示や必須条件を定義
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ objectstack-ai/ objectstack --skill objectstack-dataインストール後、Claude Code で/objectstack-dataを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/hooks-security-seeds-datasources.jsonREADME.mdobjects-fields-relationships.jsonreferences/seeds.md_index.mdlint-rules.mdexamples-objects.mddata-hooks.mdrules/datasources.mdfield-types.mdnaming.mdindexing.mdvalidation.mdsecurity.mdlifecycle.mdrelationships.md詳細
データモデリング — ObjectStack Data Protocol
スキルの範囲
| ニーズ | 代わりに使用 |
|---|---|
| レコードをクエリ、フィルタリング、または集計する | objectstack-query |
| REST API エンドポイントまたは認証を定義する | objectstack-api |
| ビュー、ダッシュボード、またはアプリを構築する | objectstack-ui |
| プラグインを作成する、またはサービスを登録する | objectstack-platform |
クイックリファレンス — 詳細ルール
誤った例と正しい例を含む包括的なドキュメントについては、以下を参照してください。
- 命名規則 — snake_case のルール、オプション値、設定プロパティ
- フィールドタイプ — 49 種類すべてのフィールドタイプと設定
- リレーションシップ — lookup と master_detail の使い分け、中間テーブルのパターン、削除時の動作
- 検証ルール — すべての検証タイプ、スクリプトの反転、重大度レベル
- インデックス戦略 — btree/gin/gist/fulltext、複合インデックス、部分インデックス
- データライフサイクルと保持 —
lifecycleクラス(record/audit/telemetry/transient/event)、保持/TTL/ローテーション/アーカイブポリシー。❗ 追記専用オブジェクトではいずれかの指定が必須です(以下のライフサイクル フック とは別です) - ライフサイクルフック — 8 つのライフサイクルイベント、
handlerとサンドボックス化されたbody(ctx と capability の契約)、登録、標準パターン - データソースとフェデレーション —
defineDatasource、外部/フェデレーションオブジェクト(remoteName/columnMap)、自動接続の制御、認証情報。❌ 外部オブジェクトではfield.columnNameを使用しないでください - セキュリティとアクセス制御 — 権限セット、割り当て行、RLS ポリシー、
secret/requiredPermissions、tenancy、プラットフォーム全体のセキュリティ態勢
コアコンセプト
オブジェクト定義
オブジェクトは、ObjectStack の基本的なデータエンティティです。データベーステーブルに対応し、CRUD API を自動的に公開します。
必須プロパティ:
| プロパティ | 型 | 規約 | 説明 |
|---|---|---|---|
name | string | snake_case | 不変の機械識別子(/^[a-z_][a-z0-9_]*$/) |
fields | map | キーは snake_case | フィールド定義 |
sharingModel | enum | 以下の4つのいずれか | 組織全体のデフォルトレコード可視性(OWD)。Zod では任意項目ですが、sharingModel を明示的に設定せずに公開しようとすると、422 の lint エンベロープ security-owd-unset により拒否されます。未設定は意思決定ではありません(メンテナーの判断、2026-08-13)。すべてのオブジェクトで設定してください |
sharingModel — 正規の4つの値(ADR-0090 D4、レガシーエイリアスは削除済み)。省略されたカスタムオブジェクトは実行時に private として解決されますが、その前に公開時のチェックで拒否されます。
| 値 | 読み取り/書き込みできるユーザー |
|---|---|
private | 所有者のみ(共有ルール、RLS、または readScope/writeScope で範囲を拡大) |
public_read | すべてのユーザーが読み取り可能。書き込みは所有者のみ |
public_read_write | すべてのユーザーが読み取りと書き込み可能 |
controlled_by_parent | マスターレコードから継承(master_detail の子) |
重要な任意プロパティ:
| プロパティ | デフォルト | 説明 |
|---|---|---|
label | name から自動生成 | 人が読める単数形のラベル |
pluralLabel | — | 複数形(例:「Accounts」)。リファレンスアプリの31個すべてのオブジェクトに設定されています。label と合わせて設定してください |
icon | — | ナビゲーション、リストヘッダー、ルックアップピッカー用のアイコン名。リファレンスアプリの31個すべてのオブジェクトに設定されています |
highlightFields | 派生 | レコードのコンパクトな表示に使用する、順序付きのフィールドキーです。親レコードの詳細ページで関連リストに表示される列、およびルックアップピッカーに表示される項目を指定します。子オブジェクトに宣言してください(リレーションシップを参照) |
namespace | — | スキーマキーではありません。ObjectSchema.create() は不明なキーを拒否するため、設定するとビルドエラーになります。代わりに、接頭辞を name に直接含めてください(例:name: 'crm_account') |
datasource | 'default' | 仮想化データの対象データソース ID |
nameField | 派生(例:'name'/'title') | レコードタイトルの正規フィールド。レコードの表示名として使用される、保存済みフィールドです。単一のテキスト/メールフィールドを使用するか、複合タイトルの場合は数式フィールド(returnType: 'text')を使用してください |
displayNameField | — | nameField の非推奨エイリアス(フォールバックとして引き続き使用されます) |
titleFormat | — | 非推奨ですが削除されていません(ADR-0079)。レンダリング専用のため、サーバーから返したり、クエリしたりすることはできません。nameField を使用してください(こちらが優先されます)。複合タイトルの場合は、returnType: 'text' の数式フィールドを nameField に指定してください |
enable | — | 機能フラグ(trackHistory、searchable、apiEnabled など) |
fieldGroups | — | フォーム/詳細ページ用の、論理フィールドグループの順序付きリスト(フィールドグループを参照) |
lifecycle | record のセマンティクス(永続) | データ保持/ローテーション/アーカイブの契約。追記専用で書き込み頻度の高いオブジェクトでは必須です。telemetry/transient/event/audit クラスには上限を定めるポリシーを宣言する必要があり、宣言しないと解析に失敗します(データライフサイクルと保持を参照) |
オブジェクトの機能(enable)
オブジェクトごとにシステムの動作を切り替えます。
| フラグ | デフォルト | 目的 |
|---|---|---|
trackHistory | false | フィールド単位の監査証跡 |
searchable | true | グローバル検索用にレコードをインデックス化 |
apiEnabled | true | 自動 REST + MCP API 経由で公開 |
apiMethods | all | 6 つのプリミティブ(get、list、create、update、delete、bulk)の許可リスト。派生動詞(search/export/upsert/…)は自動的に適用されます |
files | false | 添付ファイルとドキュメントの管理 |
feeds | true | ソーシャルフィード、コメント、メンション — オプトアウト:明示的に false を指定するとフィード UI が非表示になり、新しいコメントが拒否されます |
activities | true | アクティビティのタイムライン(CRUD をミラーする sys_activity) — オプトアウト:明示的に false を指定するとミラーリングが停止し、タイムラインが非表示になります |
clone | true | レコードのディープクローン |
検索フィールド(searchableFields)
オブジェクトの searchableFields は、$search が検索する正規のフィールド集合です(ADR-0061)。
未設定の場合、検索フィールドは nameField とオブジェクトの短文テキスト列および列挙型列(text / email / phone / url / autonumber /
textarea / markdown / select / status)に自動設定されます。明示的に固定するには宣言してください。ビューで範囲を狭めることはできますが、広げることはできません。
⛔ 関連レコードのタイトルで検索する — 値を必ずミラーリングする
$search はクエリ対象オブジェクト自身の列を検索します。ドット付きパスは検索対象になりません。fields / sort / filters とは異なり、検索軸ではパスをたどって解決しません。また、searchableFields(または $searchFields のオーバーライド)に指定した project_id.name は、黙って除外されるのではなく拒否されます。
これは唯一の指針です。毎回このとおりにしてください。 関連レコードのタイトルで検索するには、そのタイトルをこのオブジェクト上の保存フィールドにコピーし、そのフィールドを検索可能として宣言します。プロジェクト名で検索するタスクリストの場合:
// `project_name` is a stored, denormalized mirror of the parent's title.
{
name: 'task',
enable: { searchable: true },
fields: {
name: { type: 'text', required: true },
project_id: { type: 'lookup', reference: 'project' },
project_name: { type: 'text', label: 'Project Name' }, // ← the mirror
},
searchableFields: ['name', 'project_name'],
}
?search=apollo は name $contains 'apollo' OR project_name $contains 'apollo' に展開されます。すべてのドライバーで、パスをたどることなく、単一テーブルを 1 回スキャンします。(オブジェクトで searchableFields が宣言されていない場合、text のミラーフィールドも自動設定されるフィールド集合に含まれます。)
❌ formula フィールドには絶対にミラーリングしないでください。 formula フィールドは仮想フィールドです。ドライバーはその列を実体化しないため、これに対する $contains 述語には検索対象がありません(SQL ドライバーは、存在しない列を対象とした WHERE を生成してしまいます)。また、CEL が読み取れるのはこのレコード自身のフィールド(record.<field>)だけなので、formula ではそもそも関連タイトルを取得できません。この誤りは黙って処理されるのではなく拒否されます。searchableFields 内の formula(オブジェクト自身のフィールド集合を含む)は os validate エラー(searchable-field-unsearchable)となり、これを指定したリクエストは 400 INVALID_FIELD になります。以前は両方ともクリアされ、その後は検索に一致しませんでした。
ミラーの保守はトレードオフです。ミラーは非正規化データであり、値を書き込む処理が実行された時点でのみ最新になります。次の両方の書き込み経路をカバーしてください。
| タイミング | ミラーを保守する処理 |
|---|---|
| タスクが作成されたとき、または別のプロジェクトに付け替えられたとき | task の beforeInsert / beforeUpdate フック — 入力された project_id に対応する親の name を読み取り、project_name に設定します |
| プロジェクト名が変更されたとき | project の afterUpdate フック — そのプロジェクトのタスクの project_name を再設定します |
フックを経由しない経路(一括インポート、直接 SQL)で書き込まれた行には、1 回限りのバックフィルが必要です。ライフサイクルフックを参照してください。
どちらの表記も明示的に拒否されます。os validate は searchable-field-unknown を報告し、ドット付きパスを指定したリクエストは 400 INVALID_FIELD になります。それぞれのメッセージには、対応方法が記載されています。
オブジェクト間の検索パスは、今後対応する予定がないのではなく、設計上拒否されています。このためのプロジェクトごとの慣習を新たに作らないでください。ミラーフィールドが答えです。
→ references/examples-objects.md § Field Groups (MVP) にそのまま移動しました。
条件付きフィールドルール
データモデルに属し、フィールドの編集箇所すべてで適用するルールは、フィールド定義に設定します。対象には、デフォルトのフォーム、Studio で作成したフォーム、インラインのマスターディテールグリッド、公開フォーム、API 経由の書き込みが含まれます。
import { P } from '@objectstack/spec';
import { ObjectSchema, Field } from '@objectstack/spec/data';
export const Invoice = ObjectSchema.create({
name: 'invoice',
sharingModel: 'private',
fields: {
status: Field.select({
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Sent', value: 'sent' },
{ label: 'Paid', value: 'paid' },
{ label: 'Void', value: 'void' },
],
}),
paid_at: Field.datetime({
visibleWhen: P`record.status == 'paid'`,
requiredWhen: P`record.status == 'paid'`,
}),
locked_total: Field.currency({
readonlyWhen: P`record.status == 'paid'`,
}),
},
});
- ObjectUI フォームで関連性のないフィールドを非表示にするには、
visibleWhenを使用します。 - 状態によってロックされるフィールドには
readonlyWhenを使用します。述語がTRUEの場合、ObjectQL の書き込み処理は受信した変更を無視します。 readonly: trueが適用されるのはエンドユーザー向けの画面であり、信頼されたシステムライターではありません。 非システムの書き込み(REST/UI、およびデフォルトのrunAs:'user'フロー)では、フィールドは非システムの書き込みから除外されます。書き込みは成功と報告されますが、値は保存されません。システムコンテキストでの書き込み(runAs:'system'フロー、システムフック、シード、インポート、マイグレーション)は対象外となり、書き込みが行われます。したがって、「ユーザーは編集できないが、自動化によって維持する」というパターンは、フィールドにreadonlyを宣言し、維持するフローをrunAs:'system'で実行することで表現します(objectstack-automation を参照)。readonlyを削除して実現するものではありません。runAs:'user'のupdate_recordノードからreadonlyフィールドに書き込むと、ビルド時のエラーになります(os validate/os build)。- 条件付きで必須にするには
requiredWhenを使用します。ObjectQL バリデーターは送信時にこれを適用します。conditionalRequiredエイリアスはプロトコル 17 で削除されました。出力すると解析エラーになります。 - 意図に応じて選択してください — 不変条件か、遷移のゲートか。 すべての保存済みレコードに当てはまる事実は不変条件であり、
validations[]のscriptルールを使用します。これに違反する行は、修正されるまで編集できません。「レコードがpaidに達したら必須」のような遷移条件にはrequiredWhen/フィールドの制約を使用します。これは保存済みの行ではなく、書き込みを判定します。「X のとき必須」は不変条件のように見えますが、そうではありません。不変条件をゲートとして記述しても、それ自体が適用されることはありません。 - インラインの
master_detailグリッドでは、述語は子行のrecordを基準に行ごとに評価されるため、明細行のルールは子フィールドに設定してください。 - 複雑な述語には objectstack-formula を読み込み、
P\...`を使って CEL を出力してください。Salesforce 形式のAND、IN (...)、{field}` 構文は使用しないでください。
→ references/examples-objects.md § クイックスタートテンプレートにそのまま移動しました。
既存データベースのスキーマ進化
メタデータから DB への同期は追加のみです。起動時に新しいテーブルやカラムは作成されますが、既存のカラムが変更または削除されることはありません。すでにデータがあるオブジェクトに対する追加以外の変更は、物理スキーマとの不一致を暗黙に生じさせます。また、書き込み時にはデータベースのカラム定義が優先されます。
| 変更 | 再起動時の既存 DB |
|---|---|
| オブジェクト/フィールド/インデックスの追加 | ✅ 自動で適用(追加のみ) |
storage: { notNull: true } の削除(NOT NULL の緩和) | ⚠️ 自動適用されません — 不一致は category: 'needs_confirm'(relax_not_null)となるため、os migrate apply で確定します。required のみを緩和してもカラムは変わりません |
unique のスコープをグローバルからテナント単位に変更 | 開発環境では自動修復。それ以外では os migrate apply(replace_unique_index) |
| 型/長さの変更、フィールドの削除、名前の変更 | os migrate apply(削除/制約強化には --allow-destructive) |
| 宣言済みインデックスの削除、またはそのカラムの変更 | os migrate apply(削除時、または UNIQUE として再構築する場合は --allow-destructive) |
required は NOT NULL の設定ではありません(ADR-0113)。 required は書き込み時の契約です。値を省略した挿入をエンジンが拒否しますが、カラムについては何も規定しません。物理的な制約は別途明示的にオプトインする storage: { notNull: true } であり、不一致検出ではこれを比較します。そのため、デプロイ済みオブジェクトの required を厳しくしても安全です(既存の null 行は引き続き読み取れます)。一方、null 行がある状態で storage.notNull を宣言するのは、破壊的なマイグレーションです。requiredWhen とこの 2 つを併用することはできません。条件付きの契約を、無条件のカラム制約にはできないためです。
よくある兆候:/meta ではフィールドが省略可能(required も storage.notNull もない)と報告される一方、値を省略した書き込みが、明確なバリデーションエラー 400 ではなく生のドライバーエラーで失敗します。これはバリデーターの不具合ではなく、古い NOT NULL カラムです。os migrate plan を実行してプレビューし、os migrate apply で調整するか、storage: { notNull: true } を宣言してそのカラムを正式な定義としてください。CLI の詳細については、objectstack-platformを参照してください。
よく使うパターン
命名規則の概要
| コンテキスト | 規則 | 例 |
|---|---|---|
オブジェクトの name | snake_case | project_task |
| フィールドキー | snake_case | first_name、due_date |
| スキーマプロパティ | camelCase | maxLength、lookupFilters |
オプションの value | 小文字 | in_progress |
誤りと正しい例については、rules/naming.mdを参照してください。
フィールド型の選択
49 種類の型を利用できます。主なカテゴリは次のとおりです。
- テキスト:
text、textarea、email、url、phone、password、markdown、html、richtext— ⚠️ 汎用オブジェクトのpasswordは、保存時に平文です(読み取り時はマスクされますが、ハッシュ化はされません)。認証情報にはsecretを推奨します - シークレット:
secret— 登録済みのICryptoProviderを介して、認証情報(DB パスワード、API キー、トークン)を可逆的に保存時暗号化します。読み取り時はマスクされ、フェイルクローズで動作します(ADR-0100)。認証情報に推奨される型です - 数値:
number、currency、percent - 日付/時刻:
date、datetime、time - ロジック:
boolean、toggle - 選択:
select、multiselect、radio、checkboxes - リレーショナル:
lookup、master_detail、tree、user—userは人物選択フィールドです(sys_userに特化した lookup で、lookupと同じ形式で保存されます) - メディア:
image、file、avatar、video、audio - 計算:
formula、summary、autonumber—formulaフィールドではexpressionに CEL 式を指定します(@objectstack/specのF\...`` を使用)。objectstack-formulaスキルを参照してください - 埋め込み:
composite、repeater、record— 親行に保存される埋め込み JSON サブオブジェクトです(個別のテーブル/FK はありません) - 拡張:
location、address、code、json、color、rating、slider、signature、qrcode、progress、tags、vector
全リファレンスについては、rules/field-types.mdを参照してください。
関係パターン
| パターン | 実装 |
|---|---|
| 1 対多(独立) | 子に lookup フィールド |
| 1 対多(所有) | 子に master_detail フィールド |
| 多対多(シンプル) | 複数値の lookup(multiple: true)— ID の 配列カラム |
| 多対多(属性あり) | 2 つの lookup フィールドを持つ中間オブジェクト |
| 階層型 | tree フィールド(自己参照) |
詳しい例については、rules/relationships.md を参照してください。
multiple: trueの lookup ≠ 中間オブジェクトです。 複数値の lookup ({ type: 'lookup', reference: 'x', multiple: true })は、レコード上に ID の 配列として保存され、読み取られます。フローの値では位置を指定して 要素を参照します({record.tags.0})。これは中間テーブルではありません。 中間オブジェクト(2 つの lookup)を使用するのは、関係そのものに 属性(role、added_at、…)が含まれる場合に限ります。
検証パターン
⚠️ スクリプト検証のロジックは逆です: 式が true の場合、検証は失敗します。
挿入時に、ペイロードから省略された任意フィールドは、検証述語内では
nullとして読み取られます。そのためrecord.due_date == nullは、 明示的なnullと同様に、省略されたフィールドにも一致します。 (更新時は、以前のレコードから値が引き継がれます。)
検証タイプの完全な一覧(ValidationRuleSchema の判別子):
script— 数式式(ロジックは逆)state_machine— 有効な状態遷移format— 正規表現または組み込み形式cross_field— フィールド間の値を比較json_schema— JSON フィールドを JSON Schema に照らして検証conditional— 述語が成立するwhenの場合にのみ、ネストされたルールを適用
unique検証タイプはありません(仕様から削除されました)。 複合条件を含む一意性は、一意インデックスで適用し、そのスコープを指定してください(ADR-0120):indexes: [{ fields: ['department', 'email'], unique: 'organization' }]。
すべてのタイプと例については、rules/validation.md を参照してください。
インデックスパターン
宣言で使用できる項目は fields / unique / name のみです。 unique
のデフォルトは false です。該当する場合は省略してください。
indexes: [
{ fields: ['status', 'created_at'] }, // composite
{ fields: ['email'], unique: 'organization' }, // unique per organization
{ fields: ['hostname'], unique: 'global' }, // unique platform-wide
{ name: 'idx_acct_status', fields: ['status'] }, // custom name
]
typeとpartialはプロトコル 17 で廃止されました:どちらもドライバーで 読み取られたことがないため、記述したtypeはアクセス方式を選択せず、記述したpartialは述語が破棄されて完全なインデックスが生成されていました。どちらもtscエラーおよび解析エラーになりました。os migrate meta --from 16で変更点を確認できます。--writeは証明可能な変更を適用します。それ以外は手動で対応してください。
一意インデックスではスコープを指定する必要があります —
'organization'(組織ごとに 1 件、NULL セーフ)または'global'(インストール全体で 1 件)。 宣言されたインデックスでunique: trueとだけ記述するのは、非推奨の'global'の表記です。「組織ごと」と読めて実際の動作が逆になるため、os lintは警告し、プロトコル 18 では拒否されます。FIELD でのunique: trueは'organization'を意味し、引き続き有効です。
複合インデックス、一意性のスコープ、データベースレイヤーで partial/gin/gist インデックスを作成する方法については、rules/indexing.md を参照してください。
→ そのまま references/examples-objects.md の § Lifecycle Hooks に移動しました(フックのリファレンス自体は references/data-hooks.md です)。
オブジェクト拡張モデル
所有していないオブジェクトにフィールド/検証/インデックスを追加するには、
defineObjectExtension({ extend, fields, priority }) を記述し、
defineStack({ objectExtensions: [...] }) に登録します。priority はマージ順序を設定します(デフォルト
200、範囲 0–999)。拡張で追加はできますが、削除はできません。⛔ オブジェクトレベルの
ownership(レコード所有権の列挙型
'user' | 'business_unit' | 'org' | 'none')とは別のキーです。スキーマ:
node_modules/@objectstack/spec/src/data/object.zod.ts(ObjectExtensionSchema)。
セキュリティとアクセス制御
オブジェクトごとのアクセス制御は、オブジェクトスキーマではなく権限セットで定義します。オブジェクトレベルのpermissionsキーは存在せず、hooksキーもありません。ObjectSchema.create()は、どちらも不明なキーとして拒否します。
ルールの全文は、**セキュリティとアクセス制御**を参照してください。
アクセス深度(scope-depth)— ERPの「自分のユニットを見る/自分のユニットとその下位を見る」軸
所有者スコープが設定された(private)オブジェクトでは、権限セット内のオブジェクトごとの権限付与にreadScope/writeScopeを指定すると、RLSポリシーを手作業で記述せずに、宣言的に所有者との一致範囲を広げられます(ADR-0057 D1):own(デフォルト)· own_and_reports · unit · unit_and_below · org。リクエスト時にowner_id IN (…)セットに解決され、RLSと同様にAND条件で挿入されます。⚠️ オープンコアの境界(ADR-0016):オープンソースで動作するのはownとorgのみです。階層を基準とする3つの値には有料の@objectstack/security-enterpriseプラグインが必要です。このプラグインがない場合はデフォルトでownに制限され、権限付与でrequires: ['hierarchy-security']を宣言していないとdefineStackはエラーになります。スキーマ:PermissionSetSchema.objects.*。
→ references/examples-objects.md § Metadata Protection(protection)にそのまま移動しました。
→ Seed Data & Fixtures(defineSeed())は、references/seeds.md(クイックスタート · Seedのフィールド · インポートモード · externalIdの選択 · リレーションシップ参照 · 動的な値(CEL) · シードのベストプラクティス)にそのまま移動しました。
→ Linting & Generation Qualityは、references/lint-rules.mdにそのまま移動しました。
作業を検証する
*.object.ts/*.seed.tsを新規作成または編集した後は、完了を報告する前に、作成時のゲートを実行してください。
os validate # Zod schema + CEL predicates (record.<field> existence) + bindings
# or: os build # the same gates, plus emits dist/
これにより、通常は実行時に何も通知されず失敗する問題を検出できます。たとえば、requiredWhen/readonlyWhen/visibleWhen、バリデーションルール、数式、行レベルのセキュリティ/共有の述語で、フィールド参照をそのまま記述した場合(record.doneではなくdone)、評価結果がnullになり、条件が発動しません。os lintは別の検査であり、このスキルの規約(リレーションシップ、マスター詳細、ロールアップ)に対するデータモデルの追加チェックも行います。これも実行してください。ただし、os validateの代わりにはなりません。(注意:ソースに変更を加えずにos buildを連続して2回実行した場合、出力はバイト単位で同一でなければなりません。前述の決定性ゲートを参照してください。)スキャフォールドされたプロジェクトでは、ゲートのコマンドはnpm run validateです。
リファレンス
Zodスキーマの一覧(各スキーマの説明付き)は、references/_index.mdを参照してください。ここからnode_modules/@objectstack/spec/src/内のファイルに移動できます。フィールドの正確な形状を確認するには、必ずソースをReadしてください。プロパティ名の記憶に頼らないでください。