i18n - docs translations (#22715)
Created by Github action <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22715?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: github-actions <github-actions@twenty.com>
This commit is contained in:
committed by
GitHub
parent
a0cf4cc9e1
commit
ebee7d71b9
@@ -4,7 +4,7 @@ description: インストールの前後にロジックを実行して、シー
|
||||
icon: wrench
|
||||
---
|
||||
|
||||
インストールフックは、インストールまたはアップグレードのライフサイクル中に実行される特別なロジック関数です。 これらは通常の[ロジック関数](/l/ja/developers/extend/apps/logic/logic-functions)と同じハンドラーランタイムを共有し、`InstallPayload` を受け取りますが、`definePostInstallLogicFunction()` と `definePreInstallLogicFunction()` という独自の define 関数で宣言され、通常のトリガーモデル (HTTP、cron、データベースイベント) の外側で動作します。
|
||||
インストールフックは、インストールまたはアップグレードのライフサイクル中に実行される特別なロジック関数です。 これらは通常の[ロジック関数](/l/ja/developers/extend/apps/logic/logic-functions)と同じハンドラーランタイムを共有し、`InstallPayload`(`{ previousVersion?: string; newVersion: string }` — 新規インストールでは `previousVersion` は `undefined`)を受け取りますが、独自の define 関数で宣言され、通常のトリガーモデル (HTTP、cron、データベースイベント) の外側で動作します。
|
||||
|
||||
各アプリは、**プレインストール関数は最大 1 つ**、**ポストインストール関数も最大 1 つ**まで定義できます。 どちらかが複数検出された場合、マニフェストのビルドはエラーになります。
|
||||
|
||||
@@ -19,111 +19,59 @@ icon: wrench
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="definePostInstallLogicFunction" description="ワークスペースのメタデータマイグレーションが適用された後に実行されます">
|
||||
## ひと目でわかる概要
|
||||
|
||||
ポストインストール関数は、アプリのワークスペースへのインストールが完了した後に自動的に実行されます。 サーバーは、アプリのメタデータが同期され、SDK クライアントが生成された**後に**これを実行します。そのため、ワークスペースは完全に利用できる状態となり、新しいスキーマが適用されています。 代表的なユースケースには、デフォルトデータの投入、初期レコードの作成、ワークスペース設定の構成、またはサードパーティのサービスでのリソースのプロビジョニングが含まれます。
|
||||
| | `definePreInstallLogicFunction` | `definePostInstallLogicFunction` |
|
||||
| ------ | -------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| 実行回数 | メタデータマイグレーションの前 — **以前の**スキーマとデータはまだそのまま残っている | マイグレーションと SDK 生成の後 — **新しい**スキーマが適用されている |
|
||||
| 実行 | 常に同期的であり、インストールをブロックする | デフォルトでは非同期(キュー投入され、最大 3 回再試行);`shouldRunSynchronously: true` の指定で同期実行に切り替え可能 |
|
||||
| 失敗時 | スキーマ変更の前にインストールが**中止**される | 非同期: 最大 3 回まで再試行される。 同期: 呼び出し元は `POST_INSTALL_ERROR` を受け取る(スキーマ変更はロールバック**されない**) |
|
||||
| 典型的な用途 | マイグレーションで失われるデータのバックアップや修復を行う;スローすることでリスクの高いアップグレードを拒否する | デフォルトデータのシーディング、ワークスペースの構成、外部リソースの登録 |
|
||||
|
||||
```ts src/logic-functions/post-install.ts
|
||||
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
|
||||
**経験則:** 既定では post-install を使用する。 マイグレーション自体が破壊的で、消える前の状態を先に扱う必要がある場合にのみ、pre-install を使ってください。
|
||||
|
||||
const handler = async (payload: InstallPayload): Promise<void> => {
|
||||
console.log('Post install logic function executed successfully!', payload.previousVersion);
|
||||
};
|
||||
| やりたいこと… | 使用 |
|
||||
| ---------------------------------------- | -------------------------------------------------- |
|
||||
| データのシーディング、ワークスペースの構成、外部リソースの登録 | `post-install` |
|
||||
| インストール応答をブロックすべきでない長時間処理を実行する | `post-install`(既定の非同期モード。ワーカーによる再試行あり) |
|
||||
| インストールが返った直後に呼び出し元がすぐに依存する高速なセットアップを実行する | `post-install`(`shouldRunSynchronously: true` を指定) |
|
||||
| 次のマイグレーションで失われるデータを読み取る、またはバックアップする | `pre-install` |
|
||||
| 既存データを破損させる恐れのあるアップグレードを拒否する | `pre-install`(ハンドラーからスロー) |
|
||||
| すべてのアップグレードで調整処理を実行する | `shouldRunOnVersionUpgrade: true` を指定したいずれかのフック |
|
||||
|
||||
export default definePostInstallLogicFunction({
|
||||
universalIdentifier: 'f7a2b9c1-3d4e-5678-abcd-ef9876543210',
|
||||
name: 'post-install',
|
||||
description: 'Runs after installation to set up the application.',
|
||||
timeoutSeconds: 300,
|
||||
shouldRunOnVersionUpgrade: false,
|
||||
shouldRunSynchronously: false,
|
||||
handler,
|
||||
});
|
||||
```
|
||||
## 両方のフックに共通する動作
|
||||
|
||||
CLI を使用して、いつでもポストインストール関数を手動で実行することもできます:
|
||||
* 設定は、トリガー設定を除いた `defineLogicFunction` の設定に `shouldRunOnVersionUpgrade` を加えたものです。
|
||||
* **実行タイミング**: 既定では新規インストール時のみ。 アップグレード時にも実行するには、`shouldRunOnVersionUpgrade: true` を設定します。 `previousVersion` / `newVersion` を使って、アップグレードパスに応じて分岐させます。
|
||||
* **べき等性が重要です**: 非同期 post-install は再試行される可能性があり、さらに `shouldRunOnVersionUpgrade` が有効な場合はいずれのフックもアップグレード時に再実行されます。
|
||||
* 通常のロジック関数の環境(`APPLICATION_ID`、`APP_ACCESS_TOKEN`、`API_URL`)が注入されるため、アプリのトークンを使って Twenty API を呼び出せます。
|
||||
* フックはビルド時に自動的にアプリケーションマニフェストにアタッチされます(`preInstallLogicFunction` / `postInstallLogicFunction`)。[`defineApplication()`](/l/ja/developers/extend/apps/config/application) 内で参照する必要はありません。
|
||||
* デフォルトの `timeoutSeconds` は 300 に設定されており、データシーディングのような長めのセットアップ作業を許容します。
|
||||
* **開発モードでは実行されません**: `yarn twenty dev` はインストールフローをスキップしてファイルを直接同期するため、フックはそこで一切実行されません。 代わりに手動でトリガーしてください:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty dev:function:exec --postInstall
|
||||
```
|
||||
|
||||
主なポイント:
|
||||
* ポストインストール関数は `definePostInstallLogicFunction()` を使用します — トリガー設定(`cronTriggerSettings`, `databaseEventTriggerSettings`, `httpRouteTriggerSettings`, `toolTriggerSettings`, `workflowActionTriggerSettings`)を省いた専用のバリアントです。
|
||||
* ハンドラーは `InstallPayload`(`{ previousVersion?: string; newVersion: string }`)を受け取ります。`newVersion` は現在インストール中のバージョン、`previousVersion` は以前にインストールされていたバージョン(新規インストール時は `undefined`)です。 これらの値を使用して新規インストールとアップグレードを区別し、バージョン固有のマイグレーションロジックを実行します。
|
||||
* **フックが実行されるタイミング**: 既定では新規インストール時のみ。 アプリを以前のバージョンからアップグレードする際にも実行したい場合は、`shouldRunOnVersionUpgrade: true` を指定してください。 省略した場合、このフラグは既定で `false` となり、アップグレード時にはフックはスキップされます。
|
||||
* **実行モデル — 既定は非同期、同期はオプトイン**: `shouldRunSynchronously` フラグは、ポストインストールが実行される*方法*を制御します。
|
||||
* `shouldRunSynchronously: false` *(既定)* — フックは `retryLimit: 3` で**メッセージキューに投入**され、ワーカー内で非同期に実行されます。 ジョブがキューに投入されるとすぐにインストールのレスポンスが返るため、処理が遅い、または失敗するハンドラーでも呼び出し元をブロックしません。 ワーカーは最大 3 回まで再試行します。 **長時間実行のジョブに使用** — 大規模データセットのシーディング、低速なサードパーティ API の呼び出し、外部リソースのプロビジョニングなど、妥当な HTTP 応答時間枠を超える可能性のある処理。
|
||||
* `shouldRunSynchronously: true` — フックは**インストールフロー内でインライン実行**されます(プレインストールと同じエグゼキューター)。 ハンドラーが完了するまでインストールリクエストはブロックされ、スローした場合はインストールの呼び出し元が `POST_INSTALL_ERROR` を受け取ります。 自動再試行はありません。 **応答前に完了必須の高速な処理に使用** — 例: ユーザーへのバリデーションエラーの表示、インストール呼び出し直後にクライアントが依存するクイックセットアップ。 ポストインストールが実行される時点ではメタデータのマイグレーションはすでに適用済みである点に注意してください。そのため、同期モードで失敗してもスキーマ変更は**ロールバックされません** — エラーが表出するだけです。
|
||||
* ハンドラーが冪等であることを必ず確認してください。 非同期モードではキューが最大 3 回まで再試行する場合があります。いずれのモードでも、`shouldRunOnVersionUpgrade: true` の場合はアップグレード時にフックが再度実行されることがあります。
|
||||
* ハンドラー内では(他のロジック関数と同様に)環境変数 `APPLICATION_ID`、`APP_ACCESS_TOKEN`、`API_URL` が利用できます。そのため、アプリにスコープされたアプリケーションアクセストークンで Twenty API を呼び出せます。
|
||||
* アプリケーションごとにポストインストール関数は 1 つのみ許可されます。 複数検出された場合、マニフェストのビルドはエラーになります。
|
||||
* ビルド時に、関数の `universalIdentifier`、`shouldRunOnVersionUpgrade`、`shouldRunSynchronously` はアプリケーションマニフェストの `postInstallLogicFunction` フィールドに自動的に付与されます。[`defineApplication()`](/l/ja/developers/extend/apps/config/application) でそれらを参照する必要はありません。
|
||||
* デフォルトのタイムアウトは 300 秒(5 分)に設定されており、データシーディングのような長めのセットアップ作業を許容します。
|
||||
* **dev モードでは実行されません**: アプリがローカル登録(`yarn twenty dev`)された場合、サーバーはインストールフローを完全にスキップし、CLI ウォッチャー経由でファイルを直接同期します。したがって、`shouldRunSynchronously` に関わらず、dev モードではポストインストールは実行されません。 稼働中のワークスペースに対して手動でトリガーするには、`yarn twenty dev:function:exec --postInstall` を使用します。
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="definePreInstallLogicFunction" description="ワークスペースのメタデータマイグレーションが適用される前に実行されます">
|
||||
|
||||
プレインストール関数は、インストール中に自動的に実行されるロジック関数で、**ワークスペースのメタデータマイグレーションが適用される前**に実行されます。 ポストインストール(`InstallPayload`)と同じペイロード型を共有しますが、インストールフローの早い段階に位置するため、これから行われるマイグレーションが依存する状態を準備できます。典型的な用途には、データのバックアップ、新しいスキーマとの互換性の検証、再構成または削除予定のレコードのアーカイブなどがあります。
|
||||
|
||||
```ts src/logic-functions/pre-install.ts
|
||||
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
|
||||
|
||||
const handler = async (payload: InstallPayload): Promise<void> => {
|
||||
console.log('Pre install logic function executed successfully!', payload.previousVersion);
|
||||
};
|
||||
|
||||
export default definePreInstallLogicFunction({
|
||||
universalIdentifier: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
|
||||
name: 'pre-install',
|
||||
description: 'Runs before installation to prepare the application.',
|
||||
timeoutSeconds: 300,
|
||||
shouldRunOnVersionUpgrade: true,
|
||||
handler,
|
||||
});
|
||||
```
|
||||
|
||||
CLI を使用して、いつでもプレインストール関数を手動で実行することもできます:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty dev:function:exec --preInstall
|
||||
```
|
||||
|
||||
主なポイント:
|
||||
* プレインストール関数は `definePreInstallLogicFunction()` を使用します — ポストインストールと同じ特化設定ですが、異なるライフサイクルスロットに割り当てられます。
|
||||
* プレインストールとポストインストールの両ハンドラーは同じ `InstallPayload` 型(`{ previousVersion?: string; newVersion: string }`)を受け取ります。 一度インポートして、両方のフックで再利用してください。
|
||||
* **フックが実行されるタイミング**: ワークスペースのメタデータマイグレーション(`synchronizeFromManifest`)の直前に配置されます。 実行前に、サーバーは純粋に追加のみの「簡易同期」を実行し、ワークスペースのメタデータに**新しい**バージョンのプレインストール関数を登録します — それ以外には一切手を触れません — その後に実行されます。 この同期は追加のみのため、ハンドラーが実行される時点でも前バージョンのオブジェクト、フィールド、データはそのまま残っています。マイグレーション前の状態を安全に読み取り、バックアップできます。
|
||||
* **実行モデル**: プレインストールは**同期的**に実行され、**インストールをブロック**します。 ハンドラーがスローした場合、スキーマ変更が適用される前にインストールは中止され、ワークスペースは一貫した状態のまま前のバージョンに留まります。 これは意図的な設計です。プレインストールは、リスクの高いアップグレードを拒否できる最後の機会です。
|
||||
* ポストインストールと同様に、アプリケーションごとにプレインストール関数は 1 つのみ許可されます。 ビルド時に、アプリケーションマニフェストの `preInstallLogicFunction` に自動的に追加されます。
|
||||
* **dev モードでは実行されません**: ポストインストールと同様に、ローカル登録されたアプリではインストールフローが完全にスキップされるため、`yarn twenty dev` 下ではプレインストールは実行されません。 手動でトリガーするには、`yarn twenty dev:function:exec --preInstall` を使用します。
|
||||
<AccordionGroup>
|
||||
<Accordion title="definePostInstallLogicFunction" description="ワークスペースのメタデータマイグレーションが適用された後に実行されます">
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="プレインストール vs ポストインストール: どちらをいつ使うか" description="適切なインストールフックの選択">
|
||||
|
||||
両方のフックは同じインストールフローの一部で、同じ `InstallPayload` を受け取ります。 違いは、ワークスペースのメタデータマイグレーションとの相対的な実行タイミング(**いつ**実行されるか)であり、それによって安全に扱えるデータが変わります。
|
||||
|
||||
プレインストールは常に**同期的**です(インストールをブロックでき、中止することも可能)。 ポストインストールは**既定で非同期**(ワーカーにエンキューされ自動再試行あり)ですが、`shouldRunSynchronously: true` で同期実行にオプトインできます。 各モードの使い分けは、上の `definePostInstallLogicFunction` のアコーディオンを参照してください。
|
||||
|
||||
**新しいスキーマの存在を前提とする処理には `post-install` を使用してください。** これは一般的なケースです:
|
||||
|
||||
* 新規に追加されたオブジェクトやフィールドに対するデフォルトデータのシーディング(初期レコード、デフォルトビュー、デモコンテンツの作成)。
|
||||
* アプリにクレデンシャルが付与された後に、サードパーティサービスにウェブフックを登録すること。
|
||||
* 同期済みメタデータに依存するセットアップを完了させるために自前の API を呼び出すこと。
|
||||
* あらゆるアップグレード時に状態を調整すべき、冪等な「存在を保証する」ロジック — `shouldRunOnVersionUpgrade: true` と組み合わせます。
|
||||
|
||||
例 — インストール後に既定の `PostCard` レコードをシードする:
|
||||
アプリのインストールが完了した後に実行されます: メタデータは同期され、SDK クライアントが生成され、新しいスキーマはクエリ可能な状態になります。 例 — 新規インストール時に既定のレコードをシードする:
|
||||
|
||||
```ts src/logic-functions/post-install.ts
|
||||
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
|
||||
import { createClient } from './generated/client';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
|
||||
const handler = async ({ previousVersion }: InstallPayload): Promise<void> => {
|
||||
if (previousVersion) return; // fresh installs only
|
||||
|
||||
const client = createClient();
|
||||
await client.postCard.create({
|
||||
data: { title: 'Welcome to Postcard', content: 'Your first card!' },
|
||||
const client = new CoreApiClient();
|
||||
await client.mutation({
|
||||
createPostCard: {
|
||||
__args: { data: { name: 'Welcome to Postcard', content: 'Your first card!' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -133,22 +81,28 @@ export default definePostInstallLogicFunction({
|
||||
description: 'Seeds a welcome post card after install.',
|
||||
timeoutSeconds: 300,
|
||||
shouldRunOnVersionUpgrade: false,
|
||||
shouldRunSynchronously: false,
|
||||
handler,
|
||||
});
|
||||
```
|
||||
|
||||
**`pre-install` を、マイグレーションが既存データを破壊または破損しかねない場合に使用してください。** プレインストールは*以前の*スキーマに対して実行され、失敗するとアップグレードをロールバックするため、リスクのある処理に最適です:
|
||||
`shouldRunSynchronously` フラグは実行モデルを制御します:
|
||||
|
||||
* **削除または再構成される予定のデータのバックアップ** — 例: v2 でフィールドを削除するため、マイグレーション実行前にその値を別のフィールドへコピーする、またはストレージへエクスポートする必要がある場合。
|
||||
* **新しい制約により無効化されるレコードのアーカイブ** — 例: フィールドが `NOT NULL` になるため、先に null 値の行を削除または修正する必要がある場合。
|
||||
* 互換性を**検証し、現在のデータをクリーンに移行できない場合はアップグレードを拒否** — ハンドラーからスローすれば、変更が適用されないままインストールが中止されます。 これは、マイグレーションの途中で非互換性に気付くよりも安全です。
|
||||
* 関連付けが失われるスキーマ変更に先立って、**データの名称変更やキーの再割り当て**を行う。
|
||||
* `false` *(既定)* — メッセージキューに投入され(`retryLimit: 3`)、ワーカーによって実行される。 ジョブがキューに投入されるとすぐにインストールのレスポンスが返ります。 **長時間実行される処理に使用** — 大規模データセットのシーディング、低速なサードパーティ API など。
|
||||
* `true` — インストールフロー中にインラインで実行される。 ハンドラーが終了するまでインストールリクエストはブロックされます。スローされたエラーは `POST_INSTALL_ERROR` として呼び出し元に伝播します(再試行なし)。 **高速かつ、レスポンス前に完了している必要がある処理に使用します。** この時点ではマイグレーションはすでに適用済みであるため、失敗してもスキーマ変更はロールバックされず、エラーが表面化するだけです。
|
||||
|
||||
例 — 破壊的なマイグレーションの前にレコードをアーカイブする:
|
||||
</Accordion>
|
||||
<Accordion title="definePreInstallLogicFunction" description="ワークスペースのメタデータマイグレーションが適用される前に実行されます">
|
||||
|
||||
メタデータマイグレーションの前、**以前の**スキーマに対して実行されます — マイグレーションで失われるデータをバックアップしたり、リスクの高いアップグレードを拒否したりするのに適した場所です。 実行前に、サーバーは純粋に追加のみの「簡易同期」を実行し、新しいバージョンのプレインストール関数だけを登録します。あなたのハンドラーが実行される際には、それ以外 — 以前のバージョンのオブジェクト、フィールド、データ — には一切手を触れません。
|
||||
|
||||
プレインストールは常に**同期的**であり、インストールをブロックします。 ハンドラーがスローした場合、スキーマ変更が行われる前にインストールは中止され、ワークスペースは一貫した状態のまま前のバージョンに留まります。 これは意図的な設計です。プレインストールは、リスクの高いアップグレードを拒否できる最後の機会です。
|
||||
|
||||
例 — マイグレーションでレガシーフィールドが削除される前に、その値をコピーする:
|
||||
|
||||
```ts src/logic-functions/pre-install.ts
|
||||
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
|
||||
import { createClient } from './generated/client';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
|
||||
const handler = async ({ previousVersion, newVersion }: InstallPayload): Promise<void> => {
|
||||
// Only the 1.x → 2.x upgrade drops the legacy `notes` field.
|
||||
@@ -156,24 +110,24 @@ const handler = async ({ previousVersion, newVersion }: InstallPayload): Promise
|
||||
return;
|
||||
}
|
||||
|
||||
const client = createClient();
|
||||
const legacyRecords = await client.postCard.findMany({
|
||||
where: { notes: { isNotNull: true } },
|
||||
const client = new CoreApiClient();
|
||||
const { postCards } = await client.query({
|
||||
postCards: {
|
||||
__args: { filter: { notes: { isNot: null } } },
|
||||
edges: { node: { id: true, notes: true } },
|
||||
},
|
||||
});
|
||||
|
||||
if (legacyRecords.length === 0) return;
|
||||
|
||||
// Copy legacy `notes` into the new `description` field before the migration
|
||||
// drops the `notes` column. If this fails, the upgrade is aborted and the
|
||||
// workspace stays on v1 with all data intact.
|
||||
await Promise.all(
|
||||
legacyRecords.map((record) =>
|
||||
client.postCard.update({
|
||||
where: { id: record.id },
|
||||
data: { description: record.notes },
|
||||
}),
|
||||
),
|
||||
);
|
||||
// Copy legacy `notes` into `description` before the migration drops the
|
||||
// column. If this fails, the upgrade aborts and the workspace stays on v1.
|
||||
for (const { node } of postCards.edges) {
|
||||
await client.mutation({
|
||||
updatePostCard: {
|
||||
__args: { id: node.id, data: { description: node.notes } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default definePreInstallLogicFunction({
|
||||
@@ -186,21 +140,5 @@ export default definePreInstallLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
**経験則:**
|
||||
|
||||
| やりたいこと… | 使用 |
|
||||
| ----------------------------------------------- | --------------------------------------------------------------- |
|
||||
| デフォルトデータのシーディング、ワークスペースの構成、外部リソースの登録 | `post-install` |
|
||||
| インストールの応答をブロックすべきでない長時間のシーディングやサードパーティ呼び出しを実行する | `post-install`(既定 — `shouldRunSynchronously: false`、ワーカーの再試行あり) |
|
||||
| インストール呼び出しが返った直後に呼び出し元が依存する高速なセットアップを実行する | `post-install`(`shouldRunSynchronously: true` を指定) |
|
||||
| 次のマイグレーションで失われるデータを読み取る、またはバックアップする | `pre-install` |
|
||||
| 既存データを破損させる恐れのあるアップグレードを拒否する | `pre-install`(ハンドラーからスロー) |
|
||||
| すべてのアップグレードで調整処理を実行する | `post-install`(`shouldRunOnVersionUpgrade: true` を指定) |
|
||||
| 初回インストール時のみの一度限りのセットアップを行う | `post-install`(`shouldRunOnVersionUpgrade: false` を指定、既定) |
|
||||
|
||||
<Note>
|
||||
迷ったら、既定は**post-install**にしましょう。 マイグレーション自体が破壊的で、消える前の状態を先に扱う必要がある場合にのみ、pre-install を使ってください。
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
@@ -86,6 +86,22 @@ export default defineObject({
|
||||
**ベースフィールドは自動的に追加されます。** カスタムオブジェクトを定義すると、Twenty は `id`、`name`、`createdAt`、`updatedAt`、`createdBy`、`updatedBy`、`deletedAt` などの標準フィールドを自動的に作成します。 これらを `fields` 配列で宣言する必要はありません。カスタムフィールドのみを追加してください。 同じ名前でフィールドを宣言することでデフォルトフィールドを上書きすることもできますが、これはほとんどの場合お勧めできません。
|
||||
</Note>
|
||||
|
||||
## フィールドタイプ
|
||||
|
||||
`twenty-sdk/define` からエクスポートされる、`FieldType` 値の完全な一覧:
|
||||
|
||||
| カテゴリ | タイプ |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| テキスト | `TEXT`、`RICH_TEXT`、`ARRAY`(文字列の配列)、`RAW_JSON` |
|
||||
| 数値 | `NUMBER`(`universalSettings.dataType`: `'float'` / `'int'` / `'bigint'`)、`NUMERIC`(任意精度)、`RATING`、`POSITION` |
|
||||
| 日付 | `DATE`, `DATE_TIME` |
|
||||
| 選択 | `BOOLEAN`、`SELECT`、`MULTI_SELECT` |
|
||||
| 複合 | `FULL_NAME`、`ADDRESS`、`EMAILS`、`PHONES`、`LINKS`、`CURRENCY`、`ACTOR`、`FILES` |
|
||||
| 識別子とリレーション | `UUID`、`RELATION`、`MORPH_RELATION`([Relations](/l/ja/developers/extend/apps/data/relations) を参照) |
|
||||
| システム | `TS_VECTOR`(サーバーによって管理される全文検索ベクター) |
|
||||
|
||||
複合タイプは複数のサブフィールドを保持します(例: `FULL_NAME` = 名 + 姓、`CURRENCY` = `amountMicros` + `currencyCode`)。 `SELECT` と `MULTI_SELECT` は、上記の例のように `options` 配列を必要とします。
|
||||
|
||||
## デフォルト値
|
||||
|
||||
文字列リテラルのデフォルト値は、文字列**の内部で**シングルクォートで囲む必要があります。つまり、`defaultValue: "'Draft'"` のように書き、`defaultValue: "Draft"` のようには書きません。 そのため上記の `status` フィールドでは、`` `'${PostCardStatus.DRAFT}'` `` を使用しています。
|
||||
|
||||
+32
-16
@@ -14,26 +14,39 @@ my-twenty-app/
|
||||
default-role.ts # Permissions for logic functions
|
||||
constants/
|
||||
universal-identifiers.ts # Auto-generated UUIDs and metadata
|
||||
front-components/
|
||||
main-page.tsx # Welcome page component
|
||||
navigation-menu-items/
|
||||
main-page.navigation-menu-item.ts # Sidebar entry for the welcome page
|
||||
page-layouts/
|
||||
main-page.page-layout.ts # Standalone page hosting the component
|
||||
__tests__/
|
||||
setup-test.ts
|
||||
app-install.integration-test.ts
|
||||
.github/workflows/ci.yml # GitHub Actions
|
||||
public/ # Static assets
|
||||
vitest.config.ts # Test runner config
|
||||
application-config.test.ts # Unit test
|
||||
global-setup.ts # Integration test setup (sync + uninstall)
|
||||
schema.integration-test.ts # Integration test against a live server
|
||||
.github/workflows/
|
||||
ci.yml # Lint, typecheck, unit + integration tests
|
||||
cd.yml # Deploy + install on push to main
|
||||
public/
|
||||
logo.svg # Static assets
|
||||
vitest.config.ts # Integration test runner config
|
||||
vitest.unit.config.ts # Unit test runner config
|
||||
tsconfig.json, tsconfig.spec.json
|
||||
.nvmrc, .yarnrc.yml, .oxlintrc.json
|
||||
README.md, LLMS.md
|
||||
README.md, AGENTS.md, CLAUDE.md
|
||||
```
|
||||
|
||||
## 主要ファイル
|
||||
|
||||
| ファイル / フォルダー | 目的 |
|
||||
| ---------------------------------------- | --------------------------------- |
|
||||
| `src/application-config.ts` | **必須。** アプリのメイン設定ファイルです。 |
|
||||
| `src/default-role.ts` | ロジック関数がアクセスできる範囲を制御するデフォルトのロールです。 |
|
||||
| `src/constants/universal-identifiers.ts` | 自動生成される UUID とアプリのメタデータ(表示名、説明)。 |
|
||||
| `src/__tests__/` | 統合テスト(セットアップ + サンプルテスト)。 |
|
||||
| `public/` | アプリとともに提供される静的アセット(画像、フォント)。 |
|
||||
| ファイル / フォルダー | 目的 |
|
||||
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
||||
| `src/application-config.ts` | **必須。** アプリのメイン設定ファイルです。 |
|
||||
| `src/default-role.ts` | ロジック関数がアクセスできる範囲を制御するデフォルトのロールです。 |
|
||||
| `src/constants/universal-identifiers.ts` | 自動生成される UUID とアプリのメタデータ(表示名、説明)。 |
|
||||
| `src/front-components/`, `src/navigation-menu-items/`, `src/page-layouts/` | スターター用のウェルカムページ:スタンドアロンのページレイアウトによってレンダリングされ、サイドバーからアクセスできるフロントコンポーネントです。 |
|
||||
| `src/__tests__/` | ユニットテストと統合テスト(グローバルセットアップ付き)があり、実際のサーバーに対してアプリを同期します。 |
|
||||
| `public/` | アプリとともに提供される静的アセット(画像、フォント)。 |
|
||||
| `AGENTS.md` / `CLAUDE.md` | アプリ上で作業する AI コーディングエージェント向けのガイダンス。 |
|
||||
|
||||
<Note>
|
||||
**ファイル構成は自由です。** 上記のフォルダーはあくまで慣習であり、SDK はファイルがどこにあっても、`export default defineEntity(...)` 呼び出しに対する AST 解析によってエンティティを検出します。
|
||||
@@ -47,15 +60,18 @@ Twenty の両方の SDK パッケージは、`dependencies` ではなく `devDep
|
||||
{
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"twenty-client-sdk": "^2.13.0",
|
||||
"twenty-sdk": "^2.13.0"
|
||||
"twenty-client-sdk": "2.20.0",
|
||||
"twenty-sdk": "2.20.0",
|
||||
"twenty-ui": "1.0.0-alpha.1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
スキャフォルダーは `twenty-sdk` と `twenty-client-sdk` を自身のバージョンに固定します — アップグレードする際はこの 2 つを同期させてください。
|
||||
|
||||
* **`twenty-sdk`** は、`twenty` CLI とビルド/スキャフォールディング用のツールを提供します。 これは開発時とビルド時にのみ実行され、公開済みアプリのランタイムによってインポートされることは決してありません。
|
||||
* **`twenty-client-sdk`** はアプリのコード(`CoreApiClient`、`MetadataApiClient`、`RestApiClient`)によってインポートされますが、Twenty がランタイムで提供します — ロジック関数は生成された SDK レイヤーからそれを取得し、フロントエンドコンポーネントはサーバー提供のモジュールから解決します。 インストール済みのコピーは型チェックとデプロイ時のビルドにのみ使用されるため、デプロイされたバンドルに同梱される必要はありません。
|
||||
|
||||
どちらかのパッケージを `dependencies` の下に置いたままだと、インストールされたアプリのランタイムバンドルに取り込まれてしまい、不要な重荷になります。 いずれかが `dependencies` の下に残っていると、`twenty build` は警告を出力します。
|
||||
どちらかのパッケージを `dependencies` の下に置いたままだと、インストールされたアプリのランタイムバンドルに取り込まれてしまい、不要な重荷になります。 いずれかがまだ `dependencies` の下にリストされている場合、`twenty dev:build` は警告を出力します。
|
||||
|
||||
アプリ独自のランタイム依存関係(ロジック関数が実際にランタイムでインポートするライブラリ)は、通常どおり `dependencies` の下に追加してください。
|
||||
|
||||
@@ -6,17 +6,17 @@ description: 数分で最初の Twenty アプリを作成しましょう。
|
||||
|
||||
## 前提条件
|
||||
|
||||
* **Node.js 24+** — [こちらからダウンロード](https://nodejs.org/)
|
||||
* **Node.js 24.5+** — [こちらからダウンロード](https://nodejs.org/)
|
||||
* **Yarn 4** — Corepack 経由で Node.js に同梱されています。 有効化: `corepack enable`
|
||||
* **Docker** — [こちらからダウンロード](https://www.docker.com/products/docker-desktop/)。 ローカルの Twenty サーバーを実行するために必要です。 すでに別の場所で Twenty が稼働している場合はスキップしてください。
|
||||
|
||||
Twenty アプリの構築は 3 つのフェーズで構成されます。 スキャフォルダーはそれらをハッピーパスの 1 つのコマンドにまとめますが、各フェーズは別個の概念です — 何かが失敗したとき、いまどのフェーズにいるかが分かると、直すべき箇所が特定できます。
|
||||
|
||||
| フェーズ | やること | ツール | 結果 |
|
||||
| --------------- | ----------------------- | ----------------------------- | ------------------------ |
|
||||
| **1. スキャフォールド** | アプリのソースコードを生成する | `npx create-twenty-app` | ディスク上の TypeScript プロジェクト |
|
||||
| **2. サーバーを起動** | 同期先となる Twenty サーバーを起動する | Docker + `yarn twenty server` | 稼働中の Twenty インスタンス |
|
||||
| **3. 同期** | コードをサーバーにライブ同期する | `yarn twenty dev` | 変更が UI に反映されます |
|
||||
| フェーズ | やること | ツール | 結果 |
|
||||
| --------------- | ----------------------- | ----------------------------------- | ------------------------ |
|
||||
| **1. スキャフォールド** | アプリのソースコードを生成する | `npx create-twenty-app` | ディスク上の TypeScript プロジェクト |
|
||||
| **2. サーバーを起動** | 同期先となる Twenty サーバーを起動する | Docker + `yarn twenty docker:start` | 稼働中の Twenty インスタンス |
|
||||
| **3. 同期** | コードをサーバーにライブ同期する | `yarn twenty dev` | 変更が UI に反映されます |
|
||||
|
||||
---
|
||||
|
||||
@@ -28,7 +28,7 @@ Twenty アプリの構築は 3 つのフェーズで構成されます。 スキ
|
||||
npx create-twenty-app@latest my-twenty-app
|
||||
```
|
||||
|
||||
名前と説明の入力を求められます — 既定値でよければ **Enter** を押します。 これにより、`my-twenty-app/` にスターターの `application-config.ts`、デフォルトロール、CI ワークフロー、統合テストを含む TypeScript プロジェクトが生成されます。
|
||||
スキャフォルダーは非対話型であり、ディレクトリ名がアプリ名になります。 生成されるメタデータをカスタマイズするには、`--display-name` と `--description` を指定します(後から `src/constants/universal-identifiers.ts` 内で編集することもできます)。 これにより、`my-twenty-app/` にスターターの `application-config.ts`、デフォルトロール、CI/CD ワークフロー、および統合テストを含む TypeScript プロジェクトが生成されます。
|
||||
|
||||
**このフェーズ後:** マシン上にアプリのソースコードがあります。 まだ実行はされていません — それはフェーズ 2 です。
|
||||
|
||||
@@ -38,28 +38,14 @@ npx create-twenty-app@latest my-twenty-app
|
||||
|
||||
アプリは同期先としての Twenty サーバーを必要とします。 サーバーは、UI、GraphQL API、PostgreSQL を備えた完全な Twenty インスタンスで、Docker 上でローカルに実行されます。 ローカルのコードは定義をそのサーバーにアップロードし、UI に反映されます。
|
||||
|
||||
スキャフォルダーが起動を提案します:
|
||||
スキャフォルダーが環境を自動的に起動します。Docker が動作している状態で、`twentycrm/twenty-app-dev` イメージを取得し、ポート `2020` で起動して、事前にデモデータが投入されたワークスペース(`tim@apple.dev`)に対して CLI を認証します — サインインは不要です。
|
||||
|
||||
> **ローカルの Twenty インスタンスをセットアップしますか?**
|
||||
|
||||
* **Yes(推奨)** — `twentycrm/twenty-app-dev` Docker イメージを取得し、ポート `2020` で起動します。 まず Docker が起動していることを確認してください。
|
||||
* **No** — すでに接続したい Twenty サーバーがある場合に選択します。 後で `yarn twenty remote:add` で接続を設定できます。
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="ローカルインスタンスを開始しますか?" />
|
||||
</div>
|
||||
|
||||
サーバーが起動すると、サインイン用にブラウザーが開きます。 あらかじめ用意されたデモアカウントを使用します:
|
||||
|
||||
* **メールアドレス:** `tim@apple.dev`
|
||||
* **パスワード:** `tim@apple.dev`
|
||||
既存の Twenty サーバーに接続する場合は、代わりに `--url \<your-server-url>` を指定してください。 リモートサーバーは OAuth で認証されます。ブラウザーが開き、サインインして **Authorize** をクリックすると、CLI にワークスペースへのアクセス権が付与されます。 (ローカルでも `--authentication-method oauth` を指定して OAuth を利用できます。その場合は `tim@apple.dev` / `tim@apple.dev` でサインインします。)
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="Twenty のログイン画面" />
|
||||
</div>
|
||||
|
||||
次の画面で **Authorize** をクリックします — これにより、CLI にワークスペースへのアクセスが許可されます。
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/images/docs/developers/extends/apps/authorize.png" alt="Twenty CLI の承認画面" />
|
||||
</div>
|
||||
@@ -117,28 +103,32 @@ yarn twenty dev
|
||||
|
||||
### CI やスクリプト向けの一回限りの同期
|
||||
|
||||
単一のビルド+同期を実行して終了するには `--once` を指定します — パイプラインは同じでウォッチャーはありません:
|
||||
ウォッチャーなしで同じパイプラインを 1 回だけ実行するには、`plan` と `apply` を使用します。
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty dev --once
|
||||
yarn twenty plan # preview the metadata changes without applying them
|
||||
yarn twenty apply # show the plan, then apply it
|
||||
```
|
||||
|
||||
| コマンド | 動作 | 使用する場面 |
|
||||
| ---------------------------------- | ------------------------------------------- | -------------------------------------------- |
|
||||
| `yarn twenty dev` | ソースファイルを監視し、変更のたびに再同期します。 停止するまで実行し続けます。 | 対話的なローカル開発。 |
|
||||
| `yarn twenty dev --once` | ビルドと同期を一度だけ実行し、成功時はコード `0`、失敗時は `1` で終了します。 | CI、pre-commit フック、AI エージェント、スクリプト化されたワークフロー。 |
|
||||
| `yarn twenty dev --once --dry-run` | メタデータの変更をビルドして出力しますが、**実際には適用しません**。 | 同期によってどのような変更が行われるかを、実行を確定する前に確認します。 |
|
||||
| コマンド | 動作 | 使用する場面 |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
||||
| `yarn twenty dev` | ソースファイルを監視し、変更のたびに再同期します。 停止するまで実行し続けます。 | 対話的なローカル開発。 |
|
||||
| `yarn twenty apply` | ビルドと同期を一度だけ実行し、成功時はコード `0`、失敗時は `1` で終了します。 破壊的な変更がある場合に確認を求めます(スキップするには `--force` を指定します)。 | CI、pre-commit フック、AI エージェント、スクリプト化されたワークフロー。 |
|
||||
| `yarn twenty plan` | メタデータの変更をビルドして出力しますが、**実際には適用しません**。 | 同期によってどのような変更が行われるかを、実行を確定する前に確認します。 |
|
||||
|
||||
どちらのモードも、認証済みのリモートが必要です。 `--dry-run` について詳しくは、[Syncing & recovery](/l/ja/developers/extend/apps/operations/sync-and-recovery#previewing-changes-dry-run) を参照してください。
|
||||
すべてのモードで、認証済みのリモートが必要です。 `plan` の詳細については、[Syncing & recovery](/l/ja/developers/extend/apps/operations/sync-and-recovery#previewing-changes-plan) を参照してください。
|
||||
|
||||
<Note>
|
||||
`yarn twenty dev --once` および `yarn twenty dev --once --dry-run` は非推奨であり、それぞれ `yarn twenty apply` および `yarn twenty plan` のエイリアスです。
|
||||
</Note>
|
||||
|
||||
### Dev モードのオプション
|
||||
|
||||
| フラグ | 説明 |
|
||||
| ------------------------------------- | --------------------------------------------------- |
|
||||
| `--once` | 一度ビルドと同期を実行したら終了します。 |
|
||||
| `--dry-run` | `--once` を使用すると、メタデータの変更を適用せずにプレビューできます。 何も書き込みません。 |
|
||||
| `--debounceMs \<ms>` | ファイル変更のデバウンス遅延をミリ秒単位で設定します (既定値: `2000`)。 |
|
||||
| `--verbose` / `--debug` | 詳細なビルドログ、同期リクエスト、およびエラートレースを表示します。 |
|
||||
| フラグ | 説明 |
|
||||
| ------------------------------------- | ----------------------------------------- |
|
||||
| `--force` | 確認なしで破壊的な変更(削除)を適用します。 |
|
||||
| `--debounceMs \<ms>` | ファイル変更のデバウンス遅延をミリ秒単位で設定します (既定値: `1000`)。 |
|
||||
| `--verbose` / `--debug` | 詳細なビルドログ、同期リクエスト、およびエラートレースを表示します。 |
|
||||
|
||||
## 構築できるもの
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@ yarn twenty dev:add frontComponent
|
||||
| ビュー | `yarn twenty dev:add view` | `src/views/\<name>.ts` |
|
||||
| ナビゲーションメニュー項目 | `yarn twenty dev:add navigationMenuItem` | `src/navigation-menu-items/\<name>.ts` |
|
||||
| ページレイアウト | `yarn twenty dev:add pageLayout` | `src/page-layouts/\<name>.ts` |
|
||||
| ページレイアウトタブ | `yarn twenty dev:add pageLayoutTab` | `src/page-layout-tabs/\<name>.ts` |
|
||||
| コマンドメニュー項目 | `yarn twenty dev:add commandMenuItem` | `src/command-menu-items/\<name>.ts` |
|
||||
| ビューフィールド | `yarn twenty dev:add viewField` | `src/view-fields/\<name>.ts` |
|
||||
| 接続プロバイダー | `yarn twenty dev:add connectionProvider` | `src/connection-providers/\<name>.ts` |
|
||||
|
||||
## スキャフォルダーが生成するもの
|
||||
|
||||
|
||||
+2
-2
@@ -5,10 +5,10 @@ icon: wrench
|
||||
---
|
||||
|
||||
* **Docker のエラー** — `yarn twenty docker:start` の前に Docker Desktop(またはデーモン)が起動していることを確認してください。 エラーメッセージに、OS に適した起動コマンドが表示されます。
|
||||
* **Node のバージョンが違います** — 24 以上が必要です。 `node -v` で確認してください。
|
||||
* **誤った Node のバージョン** — 24.5 以上が必要です(`engines.node: ^24.5.0`)。 `node -v` で確認してください。
|
||||
* **Yarn 4 が見つからない** — `corepack enable` を実行してください。
|
||||
* **依存関係の破損** — `rm -rf node_modules && yarn install`。
|
||||
* **`twenty-sdk` が v2.8.0 へのアップグレード後にエラーになる** — v2.8.0 で `dependencies` から `devDependencies` に移動しました。 [Project Structure → Dependencies](/l/ja/developers/extend/apps/getting-started/project-structure#dependencies) を参照してください。
|
||||
* **`twenty build` は `dependencies` 配下の `twenty-client-sdk` について警告します** — これは Twenty によって実行時に提供されるため、`twenty-sdk` と同様に `devDependencies` へ移動する必要があります。 [Project Structure → Dependencies](/l/ja/developers/extend/apps/getting-started/project-structure#dependencies) を参照してください。
|
||||
* **`twenty dev:build` は `dependencies` 配下の `twenty-client-sdk` について警告します** — これは Twenty によって実行時に提供されるため、`twenty-sdk` と同様に `devDependencies` へ移動する必要があります。 [Project Structure → Dependencies](/l/ja/developers/extend/apps/getting-started/project-structure#dependencies) を参照してください。
|
||||
|
||||
行き詰まりましたか? [Twenty の Discord](https://discord.com/channels/1130383047699738754/1130386664812982322)でヘルプを依頼してください。
|
||||
|
||||
@@ -13,7 +13,6 @@ export default defineCommandMenuItem({
|
||||
universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
||||
label: 'Open Dashboard',
|
||||
shortLabel: 'Dashboard',
|
||||
icon: 'IconLayoutDashboard',
|
||||
isPinned: true,
|
||||
availabilityType: 'GLOBAL',
|
||||
frontComponentUniversalIdentifier: '74c526eb-cb68-4cf7-b05c-0dd8c288d948',
|
||||
@@ -22,51 +21,23 @@ export default defineCommandMenuItem({
|
||||
|
||||
## 設定フィールド
|
||||
|
||||
| フィールド | 必須 | 説明 |
|
||||
| --------------------------------------- | --- | ------------------------------------------------------------------------------------------------ |
|
||||
| `universalIdentifier` | はい | コマンドの安定した一意の ID |
|
||||
| `label` | はい | コマンドメニュー(Cmd+K)に表示されるフルラベル |
|
||||
| `frontComponentUniversalIdentifier` | はい | このコマンドが開くフロントコンポーネントの `universalIdentifier` |
|
||||
| `shortLabel` | いいえ | ピン留めされたクイックアクションボタンに表示される短いラベル |
|
||||
| `icon` | いいえ | ラベルの横に表示するアイコン名(例:'IconBolt'、'IconSend') |
|
||||
| `isPinned` | いいえ | `true` の場合、ページ右上にクイックアクションボタンとして表示します |
|
||||
| `availabilityType` | いいえ | コマンドの表示場所を制御します:'GLOBAL'(常に利用可能)、'RECORD_SELECTION'(レコード選択時のみ)、または 'FALLBACK'(他のコマンドが一致しないときに表示) |
|
||||
| `availabilityObjectUniversalIdentifier` | いいえ | コマンドを特定のオブジェクトタイプのページに制限します(例:Company レコードのみ) |
|
||||
| `conditionalAvailabilityExpression` | いいえ | 表示可否を動的に制御するブール式(下記参照) |
|
||||
| フィールド | 必須 | 説明 |
|
||||
| --------------------------------------- | --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `universalIdentifier` | はい | コマンドの安定した一意の ID |
|
||||
| `label` | はい | コマンドメニュー(Cmd+K)に表示されるフルラベル |
|
||||
| `frontComponentUniversalIdentifier` | はい | このコマンドが開くフロントコンポーネントの `universalIdentifier` |
|
||||
| `shortLabel` | いいえ | ピン留めされたクイックアクションボタンに表示される短いラベル |
|
||||
| `icon` | いいえ | **非推奨** — アプリケーションアイコンが優先されるため無視されます。設定されている場合は、ビルド時に警告が出力されます。 |
|
||||
| `isPinned` | いいえ | `true` の場合、ページ右上にクイックアクションボタンとして表示します |
|
||||
| `availabilityType` | いいえ | コマンドの表示場所を制御します:`'GLOBAL'`(常に利用可能)、`'GLOBAL_OBJECT_CONTEXT'`(オブジェクトコンテキストを持つページ上のみ ― インデックスページおよびレコードページ)、`'RECORD_SELECTION'`(レコード選択時のみ)、または`'FALLBACK'`(他のコマンドが一致しないときに表示) |
|
||||
| `availabilityObjectUniversalIdentifier` | いいえ | コマンドを特定のオブジェクトタイプのページに制限します(例:Company レコードのみ) |
|
||||
| `conditionalAvailabilityExpression` | いいえ | 表示可否を動的に制御するブール式(下記参照) |
|
||||
|
||||
## ヘッドレスコマンド
|
||||
|
||||
[ヘッドレスフロントコンポーネント](/l/ja/developers/extend/apps/layout/front-components#headless-vs-non-headless)とペアになったコマンドメニュー項目は、ワンクリックアクション(コードの実行、ナビゲーション、確認と実行)を提供するための一般的な方法です。 Front Components のページでは、アクション実行後にアンマウントするパターンを処理する [SDK Command components](/l/ja/developers/extend/apps/layout/front-components#sdk-command-components)(`Command`、`CommandLink`、`CommandModal`、`CommandOpenSidePanelPage`)について説明しています。
|
||||
|
||||
一般的なフロー:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
});
|
||||
```
|
||||
一般的なフロー:ヘッドレスコンポーネントが `<Command execute={...} />` をレンダーし([完全なサンプル](/l/ja/developers/extend/apps/layout/front-components#sdk-command-components)を参照)、コマンドメニュー項目がそれを指すようにします:
|
||||
|
||||
```ts src/command-menu-items/run-action.command-menu-item.ts
|
||||
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
||||
@@ -74,7 +45,6 @@ import { defineCommandMenuItem } from 'twenty-sdk/define';
|
||||
export default defineCommandMenuItem({
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
frontComponentUniversalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
});
|
||||
```
|
||||
|
||||
@@ -49,14 +49,13 @@ export default defineCommandMenuItem({
|
||||
universalIdentifier: 'd4e5f6a7-b8c9-0123-defa-456789012345',
|
||||
shortLabel: 'Hello',
|
||||
label: 'Hello World',
|
||||
icon: 'IconBolt',
|
||||
isPinned: true,
|
||||
availabilityType: 'GLOBAL',
|
||||
frontComponentUniversalIdentifier: '74c526eb-cb68-4cf7-b05c-0dd8c288d948',
|
||||
});
|
||||
```
|
||||
|
||||
`yarn twenty dev` で同期するか(または 1 回限りで `yarn twenty dev --once` を実行すると)、ページ右上にクイックアクションが表示されます:
|
||||
`yarn twenty dev` で同期するか(または 1 回限りで `yarn twenty apply` を実行すると)、ページ右上にクイックアクションが表示されます:
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/images/docs/developers/extends/apps/quick-action.png" alt="右上のクイックアクションボタン" />
|
||||
@@ -88,11 +87,11 @@ export default defineCommandMenuItem({
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { useRecordId, enqueueSnackbar } from 'twenty-sdk/front-component';
|
||||
import { useSelectedRecordIds, enqueueSnackbar } from 'twenty-sdk/front-component';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const SyncTracker = () => {
|
||||
const recordId = useRecordId();
|
||||
const [recordId] = useSelectedRecordIds();
|
||||
|
||||
useEffect(() => {
|
||||
enqueueSnackbar({ message: `Tracking record ${recordId}`, variant: 'info' });
|
||||
@@ -116,7 +115,7 @@ export default defineFrontComponent({
|
||||
|
||||
`twenty-sdk` パッケージは、ヘッドレスのフロントコンポーネント向けに設計された4つの Command ヘルパーコンポーネントを提供します。 各コンポーネントは、マウント時にアクションを実行し、エラーをスナックバー通知で処理し、完了時にフロントコンポーネントを自動的にアンマウントします。
|
||||
|
||||
`twenty-sdk/command` からインポートします:
|
||||
`twenty-sdk/front-component` からインポートします:
|
||||
|
||||
* **`Command`** — `execute` プロップ経由で非同期コールバックを実行します。
|
||||
* **`CommandLink`** — アプリのパスにナビゲートします。 Props: `to`, `params`, `queryParams`, `options`.
|
||||
@@ -127,8 +126,8 @@ export default defineFrontComponent({
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
import { Command } from 'twenty-sdk/front-component';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
@@ -160,7 +159,6 @@ import { defineCommandMenuItem } from 'twenty-sdk/define';
|
||||
export default defineCommandMenuItem({
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
frontComponentUniversalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
});
|
||||
```
|
||||
@@ -169,7 +167,7 @@ export default defineCommandMenuItem({
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
import { CommandModal } from 'twenty-sdk/front-component';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
@@ -202,7 +200,7 @@ export default defineFrontComponent({
|
||||
|
||||
`httpRouteTriggerSettings` で宣言されたロジック関数は、そのルートパスで HTTP 経由でアクセスできます。 Twenty は、関数が提供されるベース URL を `TWENTY_FUNCTIONS_URL` としてワーカーに注入し、呼び出しを認証する `TWENTY_APP_ACCESS_TOKEN` も併せて渡します。 独自の関数を呼び出すための専用 SDK クライアントはまだないため、シンプルな `fetch` を使って呼び出してください。
|
||||
|
||||
> **Twenty Cloud では、HTTP トリガーのロジック関数はワークスペースごとの専用ドメインで提供されます**。`https://\<your-workspace-subdomain>.twenty.com\<path>` がそのドメインであり、これが `TWENTY_FUNCTIONS_URL` が解決される先とまったく同じです。 外部から呼び出す場合は、関数の **HTTP trigger** 設定、もしくはアプリケーションの **Settings** タブから、正確な URL をコピーしてください。
|
||||
> **Twenty Cloud では、HTTP トリガーのロジック関数はワークスペースごとの専用ドメインで提供されます**。`https://\<your-workspace-subdomain>.withtwenty.com\<path>` がそのドメインであり、これが `TWENTY_FUNCTIONS_URL` が解決される先とまったく同じです。 外部から呼び出す場合は、関数の **HTTP trigger** 設定、もしくはアプリケーションの **Settings** タブから、正確な URL をコピーしてください。
|
||||
|
||||
<Warning>
|
||||
レガシーな `/s/` 関数ルートは**非推奨**となっており、**2026-07-24 に無効化されます**。 代わりに(上記の)`TWENTY_FUNCTIONS_URL` を使用し、その日までにハードコードされた `/s/` URL をすべて移行してください。 `/s/` ルートはセルフホスティング向けには引き続き利用可能です。
|
||||
@@ -212,7 +210,7 @@ export default defineFrontComponent({
|
||||
|
||||
```tsx src/front-components/sync-prs.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { Command } from 'twenty-sdk/front-component';
|
||||
|
||||
const SyncPrs = () => {
|
||||
const execute = async () => {
|
||||
@@ -316,13 +314,13 @@ try {
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import {
|
||||
useUserId,
|
||||
useRecordId,
|
||||
useSelectedRecordIds,
|
||||
useFrontComponentId,
|
||||
} from 'twenty-sdk/front-component';
|
||||
|
||||
const RecordInfo = () => {
|
||||
const userId = useUserId();
|
||||
const recordId = useRecordId();
|
||||
const [recordId] = useSelectedRecordIds();
|
||||
const componentId = useFrontComponentId();
|
||||
|
||||
return (
|
||||
@@ -405,12 +403,11 @@ export default defineFrontComponent({
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { useRecordId } from 'twenty-sdk/front-component';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk/front-component';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
import { enqueueSnackbar, closeSidePanel, useSelectedRecordIds } from 'twenty-sdk/front-component';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
const [recordId] = useSelectedRecordIds();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
@@ -451,10 +448,10 @@ export default defineFrontComponent({
|
||||
複数の選択されたレコードを処理するには `useSelectedRecordIds()` を使用してください。 これは一括操作に役立ちます:
|
||||
|
||||
```tsx src/front-components/bulk-export.tsx
|
||||
import { defineFrontComponent, numberOfSelectedRecords } from 'twenty-sdk/define';
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { useSelectedRecordIds } from 'twenty-sdk/front-component';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk/front-component';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
|
||||
const BulkExport = () => {
|
||||
const selectedRecordIds = useSelectedRecordIds();
|
||||
@@ -492,12 +489,19 @@ export default defineFrontComponent({
|
||||
name: 'bulk-export',
|
||||
description: 'Export selected records',
|
||||
component: BulkExport,
|
||||
command: {
|
||||
universalIdentifier: 'd0e1f2a3-b4c5-6789-defa-012345678902',
|
||||
label: 'Bulk Export',
|
||||
availabilityType: 'RECORD_SELECTION',
|
||||
conditionalAvailabilityExpression: numberOfSelectedRecords > 0,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
レコードの選択に制限された[コマンドメニューアイテム](/l/ja/developers/extend/apps/layout/command-menu-items)として表示します:
|
||||
|
||||
```ts src/command-menu-items/bulk-export.command-menu-item.ts
|
||||
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
||||
|
||||
export default defineCommandMenuItem({
|
||||
universalIdentifier: 'd0e1f2a3-b4c5-6789-defa-012345678902',
|
||||
label: 'Bulk Export',
|
||||
availabilityType: 'RECORD_SELECTION',
|
||||
frontComponentUniversalIdentifier: 'd0e1f2a3-b4c5-6789-defa-012345678901',
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ export default defineNavigationMenuItem({
|
||||
|
||||
* `position` はサイドバーでの表示順を制御します。
|
||||
|
||||
* enum には、ユーザーが作成したレコードのお気に入りを内部的に扱うために使用される `NavigationMenuItemType.RECORD` も含まれています。これはアプリのマニフェストからは使用できません(レコードを参照するフィールドが存在しません)。
|
||||
|
||||
* `icon` と `color` は任意で、エントリの見た目をカスタマイズします。
|
||||
|
||||
* `folderUniversalIdentifier` は、任意の項目で利用でき、その項目を `FOLDER` タイプの親の内側にネストするために使用します。
|
||||
|
||||
@@ -33,17 +33,32 @@ export default defineView({
|
||||
## 主なポイント
|
||||
|
||||
* `objectUniversalIdentifier` は、このビューを適用するオブジェクトを指定します。 定義したカスタムオブジェクトでも、Twenty の標準オブジェクトでも可能です。
|
||||
* `key` はビューの種類を決定します。`ViewKey.INDEX` は、そのオブジェクトのメインのリストビューです。
|
||||
* `key: ViewKey.INDEX` は、そのビューがオブジェクトのメイン一覧ビュー(`OBJECT` ナビゲーション項目を開いたときに表示されるビュー)であることを示します。
|
||||
* `fields` は、どの列をどの順序で表示するかを制御します。 各フィールドは `fieldMetadataUniversalIdentifier` を参照します。
|
||||
* さらに高度な構成のために、`filters`、`filterGroups`、`groups`、`fieldGroups` も定義できます。
|
||||
* さらに高度な構成のために、`filters`、`filterGroups`、`sorts`、`groups`、`fieldGroups` も定義できます。
|
||||
* 同じオブジェクトに複数のビューがある場合、`position` が表示順を制御します。
|
||||
|
||||
## オプションのプロパティ
|
||||
|
||||
| プロパティ | 値 | 説明 |
|
||||
| ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
||||
| `type` | `ViewType.TABLE` (デフォルト), `ViewType.KANBAN`, `ViewType.CALENDAR` | レコードのレイアウト方法。 (`FIELDS_WIDGET` / `TABLE_WIDGET` も存在しますが、ページレイアウトウィジェットによって内部的に使用されます。) |
|
||||
| `visibility` | `ViewVisibility.WORKSPACE` (デフォルト), `ViewVisibility.UNLISTED` | ビューがワークスペース全体で一覧表示されるか、ピッカーから非表示にするか。 |
|
||||
| `openRecordIn` | `ViewOpenRecordIn.SIDE_PANEL` (デフォルト), `ViewOpenRecordIn.RECORD_PAGE` | レコードをクリックしたときに、どこで開くか。 |
|
||||
| `sorts` | `{ fieldMetadataUniversalIdentifier, direction: ViewSortDirection.ASC \| DESC }[]` | デフォルトのソート順。 |
|
||||
| `isCompact` | `boolean` | 行をコンパクトに表示します。 |
|
||||
| `mainGroupByFieldMetadataUniversalIdentifier` + `shouldHideEmptyGroups` | — | レコードをフィールドでグループ化します(例: かんばんのカラム)。 |
|
||||
| `kanbanAggregateOperation`, `kanbanAggregateOperationFieldMetadataUniversalIdentifier`, `kanbanColumnWidth` | `AggregateOperations.*` | かんばんカラムの集計とサイズ設定。 |
|
||||
| `calendarLayout`, `calendarFieldMetadataUniversalIdentifier` | `ViewCalendarLayout.DAY` / `WEEK` / `MONTH` | カレンダービュー: レイアウトと、レコードの位置を決める日付フィールド。 |
|
||||
|
||||
上記のすべての enum は `twenty-sdk/define` からエクスポートされています。
|
||||
|
||||
## フィルター
|
||||
|
||||
ビューには、あらかじめフィルターを適用した状態で提供できます。 各フィルターには 3 つの要素があります: フィルタリング対象の**フィールド**、**オペランド**(どのように比較するか)、**値**(何と比較するか)。 この 3 つがすべてそろっている必要があります — フィールドの型に適用できないオペランドを使用すると、同期時に拒否されます。
|
||||
|
||||
```ts
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { ViewFilterOperand } from 'twenty-sdk/define';
|
||||
|
||||
filters: [
|
||||
{
|
||||
|
||||
@@ -51,8 +51,12 @@ export default defineLogicFunction({
|
||||
```
|
||||
|
||||
利用可能なトリガーの種類:
|
||||
* **httpRoute**:`/s/` エンドポイント配下で、HTTP のパスとメソッドで関数を公開します:
|
||||
> 例:`path: '/post-card/create'` は `https://your-twenty-server.com/s/post-card/create` で呼び出せます
|
||||
* **httpRoute**: ワークスペースの **関数 ベース URL** の HTTP パスとメソッドにあなたの関数を公開します。値 Twenty_FUNCTIONS_URL\` (Twenty Cloud 上) ワークスペースごとの専用ドメイン:
|
||||
> 例:`path: '/post-card/create'` は `https://your-workspace.withtwenty.com/post-card/create` で呼び出せます
|
||||
|
||||
<Warning>
|
||||
レガシーの `/s/` prefix route (`https://your-20-server.com/s/post-card/create`)は\*\*Twenty Cloudで非推奨になっており、**2026-07-24**で無効になります。 分離された関数ドメインを設定しない自己ホストおよびローカルインスタンスでも使用できます — 設定時は `TWENTY_FUNCTIONS_URL` を使用してください。 そして、 `\<server-url>/s/\<path>` に戻ります。
|
||||
</Warning>
|
||||
|
||||
<Note>
|
||||
(ヘッドレスの)フロントコンポーネントからルートトリガー型ロジック関数を呼び出す方法については、[ロジック関数を呼び出す](/l/ja/developers/extend/apps/layout/front-components#calling-a-logic-function)を参照してください。
|
||||
|
||||
@@ -40,13 +40,13 @@ Twenty アプリの **ロジックレイヤー** は、*実行される* コー
|
||||
|
||||
ロジック関数は 1 つ以上のトリガーを選択します。以下の各項目は、`defineLogicFunction()` 上の個別のフィールドです。
|
||||
|
||||
| トリガー | 実行タイミング | 設定 |
|
||||
| --------------- | --------------------------------------------------- | ------------------------------- |
|
||||
| **HTTP ルート** | リクエストが `/s/\<path>` エンドポイントに到達したとき | `httpRouteTriggerSettings` |
|
||||
| **クロン** | CRON 式が一致したとき | `cronTriggerSettings` |
|
||||
| **データベースイベント** | ワークスペースのレコードが作成、更新、または削除されたとき | `databaseEventTriggerSettings` |
|
||||
| **AI ツール** | Twenty の AI 機能が関数を呼び出すことを決定したとき | `toolTriggerSettings` |
|
||||
| **ワークフローアクション** | ワークフローステップが関数を呼び出したとき | `workflowActionTriggerSettings` |
|
||||
| トリガー | 実行タイミング | 設定 |
|
||||
| --------------- | ------------------------------- | ------------------------------- |
|
||||
| **HTTP ルート** | リクエストがあなたの関数の公開 URL に一致しました | `httpRouteTriggerSettings` |
|
||||
| **クロン** | CRON 式が一致したとき | `cronTriggerSettings` |
|
||||
| **データベースイベント** | ワークスペースのレコードが作成、更新、または削除されたとき | `databaseEventTriggerSettings` |
|
||||
| **AI ツール** | Twenty の AI 機能が関数を呼び出すことを決定したとき | `toolTriggerSettings` |
|
||||
| **ワークフローアクション** | ワークフローステップが関数を呼び出したとき | `workflowActionTriggerSettings` |
|
||||
|
||||
関数は分離された Node.js プロセス内でサンドボックス実行され、[`defineApplication()`](/l/ja/developers/extend/apps/config/application) で宣言されたロールにスコープされた型付き API クライアントを通じてワークスペースにアクセスします。
|
||||
|
||||
|
||||
@@ -4,7 +4,25 @@ description: 関数の実行、ログのストリーミング、アプリのイ
|
||||
icon: terminal
|
||||
---
|
||||
|
||||
`dev`、`dev:build`、`dev:add`、`dev:typecheck` 以外にも、`yarn twenty` CLI には関数の実行、ログの表示、アプリのインストール管理のためのコマンドがあります。
|
||||
`yarn twenty` CLI は、アプリ関連のすべてを操作するためのインターフェースです。 コマンド一覧:
|
||||
|
||||
| コマンド | 機能 | 以下でドキュメント化 |
|
||||
| ----------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `dev` | ソースファイルを監視し、変更をライブ同期します | [クイックスタート](/l/ja/developers/extend/apps/getting-started/quick-start) |
|
||||
| `plan` | メタデータの変更を適用せずにプレビュー | [Syncing & recovery](/l/ja/developers/extend/apps/operations/sync-and-recovery#previewing-changes-plan) |
|
||||
| `apply` | プランを表示した後にメタデータの変更を適用 | [Syncing & recovery](/l/ja/developers/extend/apps/operations/sync-and-recovery) |
|
||||
| `dev:build` | アプリをコンパイルし、API クライアントを生成します(`.tgz` にパッケージするには `--tarball` を使用) | [公開](/l/ja/developers/extend/apps/operations/publishing) |
|
||||
| `dev:typecheck` | TypeScript の型チェックを実行 | [テスト](/l/ja/developers/extend/apps/operations/testing) |
|
||||
| `dev:add` | 新しいエンティティをスキャフォールディング | [スキャフォールディング](/l/ja/developers/extend/apps/getting-started/scaffolding) |
|
||||
| `dev:generate-client` | 型付き API クライアントを再生成 | このページ |
|
||||
| `dev:function:exec` / `dev:function:logs` | 関数を実行し、そのログをストリーミング | このページ |
|
||||
| `dev:translations-extract` | 翻訳可能な文字列を `locales/` カタログに抽出 | [翻訳](/l/ja/developers/extend/apps/translations/overview) |
|
||||
| `dev:catalog-sync` | マーケットプレイスのカタログ同期をトリガー | [公開](/l/ja/developers/extend/apps/operations/publishing#how-marketplace-discovery-works) |
|
||||
| `app:publish` / `app:install` / `app:uninstall` | リリースライフサイクル | [公開](/l/ja/developers/extend/apps/operations/publishing) とこのページ |
|
||||
| `docker:*` | ローカルの Twenty サーバーコンテナを管理 | [ローカルサーバー](/l/ja/developers/extend/apps/getting-started/local-server) |
|
||||
| `remote:*` | サーバー接続を管理 | このページ |
|
||||
|
||||
すべてのコマンドは、デフォルトではない特定のリモートを対象にするために `-r, --remote \<name>` を受け付けます。
|
||||
|
||||
## 関数の実行(`yarn twenty dev:function:exec`)
|
||||
|
||||
@@ -20,8 +38,9 @@ yarn twenty dev:function:exec -u e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
|
||||
# Pass a JSON payload
|
||||
yarn twenty dev:function:exec -n create-new-post-card -p '{"name": "Hello"}'
|
||||
|
||||
# Execute the post-install function
|
||||
# Execute the install hooks
|
||||
yarn twenty dev:function:exec --postInstall
|
||||
yarn twenty dev:function:exec --preInstall
|
||||
```
|
||||
|
||||
## 関数ログの表示(`yarn twenty dev:function:logs`)
|
||||
@@ -100,6 +119,12 @@ yarn twenty remote:list
|
||||
|
||||
# Set the active remote
|
||||
yarn twenty remote:use <name>
|
||||
|
||||
# Check that the active remote's authentication is still valid
|
||||
yarn twenty remote:status
|
||||
|
||||
# Remove a remote
|
||||
yarn twenty remote:remove <name>
|
||||
```
|
||||
|
||||
認証情報は `~/.twenty/config.json` に保存されます。
|
||||
|
||||
@@ -229,7 +229,7 @@ yarn twenty dev:catalog-sync
|
||||
# yarn twenty dev:catalog-sync --remote production
|
||||
```
|
||||
|
||||
マーケットプレイスに表示されるメタデータは、`defineApplication()` の設定に由来します。`displayName`、`description`、`author`、`category`、`logoUrl`、`screenshots`、`aboutDescription`、`websiteUrl`、`termsUrl` などのフィールドです。
|
||||
マーケットプレイスに表示されるメタデータは、`defineApplication()` 設定から取得されます。上記の [Marketplace metadata](#marketplace-metadata) を参照してください。
|
||||
|
||||
<Note>
|
||||
アプリで`defineApplication()`内に`aboutDescription`が定義されていない場合、マーケットプレイスはnpm上のパッケージの`README.md`を概要ページのコンテンツとして自動的に使用します。 つまり、npm と Twenty のマーケットプレイスの両方に対して、1 つの README を維持できます。 マーケットプレイスで異なる説明文を使用したい場合は、`aboutDescription` を明示的に設定してください。
|
||||
|
||||
@@ -15,33 +15,44 @@ icon: compass
|
||||
| やりたいこと… | コマンド | ノート |
|
||||
| ------------------------------ | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| ライブ同期でローカルに反復開発する | `yarn twenty dev` | ファイルを監視し、変更のたびに同期します。 |
|
||||
| 1 回だけ同期して終了(CI、スクリプト、フック向け) | `yarn twenty dev --once` | 1 回ビルドして同期し、その後終了します。 |
|
||||
| 変更を**適用せずに**プレビュー | `yarn twenty dev --once --dry-run` | 差分を計算して表示しますが、何も書き込みません。 |
|
||||
| 1 回だけ同期して終了(CI、スクリプト、フック向け) | `yarn twenty apply` | 1 回ビルドして同期し、その後終了します。 破壊的変更の確認をスキップするには、`--force` を追加します。 |
|
||||
| 変更を**適用せずに**プレビュー | `yarn twenty plan` | 差分を計算して表示しますが、何も書き込みません。 |
|
||||
| ワークスペースからアプリを削除する | `yarn twenty app:uninstall` | プロンプトをスキップするには、`--yes` を追加します。 |
|
||||
| サーバーに tarball をアップロードする | `yarn twenty app:publish --private` | `package.json` のバージョンが**厳密により高い**必要があります — [Publishing](/l/ja/developers/extend/apps/operations/publishing) を参照してください。 |
|
||||
| マーケットプレイス(npm)に公開する | `yarn twenty app:publish` | — |
|
||||
| デプロイ済みバージョンをインストール / アップグレードする | `yarn twenty app:install` | 現在デプロイされているバージョンをインストールします。 |
|
||||
| ローカルサーバーを消去してクリーンに開始する | `yarn twenty docker:reset` | ローカルデータを**すべて**削除します — 最終手段です。 |
|
||||
|
||||
<Note>
|
||||
`yarn twenty dev --once` および `yarn twenty dev --once --dry-run` は、`yarn twenty apply` と `yarn twenty plan` の非推奨エイリアスとして依然として動作します。
|
||||
</Note>
|
||||
|
||||
### ローカル同期ではバージョンの更新は不要
|
||||
|
||||
厳密に増加する `version` のルール(デプロイ時の `VERSION_ALREADY_EXISTS`、インストール時の `APP_ALREADY_INSTALLED` / `CANNOT_DOWNGRADE_APPLICATION`)は、リリースパスである **`app:publish` / `app:install`** に適用されます。 `yarn twenty dev` はマニフェストをその場で同期し、バージョン変更を要求することはないため、反復するのに `package.json` を触る必要はありません。 ローカルの変更をテストするためにバージョンを上げている場合は、開発ループが必要なところでリリース経路を使ってしまっています。
|
||||
|
||||
## 同期出力の読み方
|
||||
|
||||
各同期では、適用された(`--dry-run` の場合は適用されるはずだった)メタデータ変更が出力されます。
|
||||
各同期では、適用した(`plan` の場合は適用される)メタデータの変更が出力されます。Terraform と同様に、エンティティごとにその属性を含むブロックが 1 つずつ表示され、その後にサマリー行が続きます。
|
||||
|
||||
```text filename="Terminal"
|
||||
Metadata changes: 2 created, 1 updated, 1 deleted
|
||||
created objectMetadata rocket
|
||||
created fieldMetadata timelineActivities
|
||||
updated fieldMetadata launchedAt
|
||||
deleted pageLayout legacyTab
|
||||
✓ Synced
|
||||
# objectMetadata "rocket" will be created
|
||||
+ icon = "IconRocket"
|
||||
+ labelSingular = "Rocket"
|
||||
+ ...
|
||||
|
||||
# fieldMetadata "launchedAt" will be updated
|
||||
~ isNullable = false -> true
|
||||
|
||||
Plan: 2 to add, 1 to change, 1 to destroy.
|
||||
|
||||
✓ Synced My App (4 files)
|
||||
```
|
||||
|
||||
これは最初の診断手段です。どのオブジェクト、フィールド、レイアウトが変更されたかを正確に示すので、UI を確認する前に、同期が想定どおりに動作したかを確認できます。
|
||||
|
||||
破壊的変更(`to destroy`)は、何を削除するかとあわせて一覧表示され(例: `objectMetadata "auditNote" — drops the table and all its rows`)、対話的な確認、またはスクリプト内での `--force` が必要です。
|
||||
|
||||
同期が単一のエンティティで失敗した場合、エラーには問題のエンティティとその `universalIdentifier` が、次のように示されます。
|
||||
|
||||
```text
|
||||
@@ -50,39 +61,42 @@ Migration action 'create' for 'fieldMetadata' (universalIdentifier: 2020...4337)
|
||||
|
||||
その識別子を使って、推測で衝突元を探すのではなく、マニフェスト内(必要であればワークスペース内)のエンティティを特定してください。
|
||||
|
||||
## 変更内容のプレビュー(ドライラン)
|
||||
## 変更内容のプレビュー(プラン)
|
||||
|
||||
`yarn twenty dev --once --dry-run` はマニフェストをビルドし、サーバーにマイグレーションプランを問い合わせ、その内容を**何も適用せずに**表示します。 コミットする前に「この同期は何を変更するか?」という問いに安全に答える方法です。
|
||||
`yarn twenty plan` はマニフェストをビルドし、サーバーにマイグレーションプランを問い合わせ、その内容を **何も適用せずに** 表示します。 コミットする前に「この同期は何を変更するか?」という問いに安全に答える方法です。
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty dev --once --dry-run
|
||||
yarn twenty plan
|
||||
```
|
||||
|
||||
```text filename="Terminal"
|
||||
Building manifest...
|
||||
Computing metadata diff (dry run, nothing will be applied)...
|
||||
Metadata changes: 1 created, 1 updated
|
||||
created fieldMetadata timelineActivities
|
||||
updated objectMetadata rocket
|
||||
✓ Dry run complete for My App — no changes were applied
|
||||
Computing metadata plan (read-only, nothing will be applied)...
|
||||
|
||||
# fieldMetadata "timelineActivities" will be created
|
||||
+ ...
|
||||
|
||||
Plan: 1 to add, 1 to change, 0 to destroy.
|
||||
|
||||
✓ Plan complete for My App — no changes were applied
|
||||
```
|
||||
|
||||
ドライランでは次のことが行われます。
|
||||
プランの例:
|
||||
|
||||
* **何も書き込みません** — メタデータマイグレーション、アプリケーションレコードの更新、デフォルトのロール / タブの変更、API クライアントの生成は一切行いません。
|
||||
* 実際の同期が適用するのと**同じ差分**を返すため、作成 / 更新 / 削除されるエンティティを事前に確認できます。
|
||||
* リスクの高い変更の前や、AI 生成の変更をレビューするとき、または予期せぬ変更が行われそうな場合にスクリプトを失敗させたいときなどに有用です。
|
||||
|
||||
<Note>
|
||||
ドライランでは**メタデータ**の変更のみをプレビューします。また、アプリが少なくとも一度は同期されている(ワークスペース側がその存在を知っている)必要があります。 一度も同期されていないアプリに対して実行すると、サーバーはそのアプリがインストールされていないと報告します — まず一度 `yarn twenty dev` を実行してください。
|
||||
プランでは **メタデータ** の変更のみがプレビューされます。また、アプリが少なくとも一度は同期されている(ワークスペース側がその存在を知っている)必要があります。 一度も同期されていないアプリに対して実行すると、サーバーはそのアプリがインストールされていないと報告します — まず一度 `yarn twenty dev` を実行してください。
|
||||
</Note>
|
||||
|
||||
## リカバリーラダー
|
||||
|
||||
ローカルのメタデータが正しくないように見える場合は、次の順番でエスカレートし、問題が解消したところで止めてください。 各ステップは前のものよりも影響が大きくなります。
|
||||
|
||||
1. **再同期。** `yarn twenty dev --once` を再度実行します。 同期はべき等であり、クリーンなマニフェストを再実行しても安全で、多くの場合は一時的な不具合が解消されます。
|
||||
2. **プランをプレビュー。** `yarn twenty dev --once --dry-run` を実行して、次の同期が何を変更しようとしているのかを、適用せずに正確に確認します。
|
||||
1. **再同期。** `yarn twenty apply` を再度実行します。 同期はべき等であり、クリーンなマニフェストを再実行しても安全で、多くの場合は一時的な不具合が解消されます。
|
||||
2. **プランをプレビュー。** `yarn twenty plan` を実行して、次の同期が何を変更しようとしているのかを、適用せずに正確に確認します。
|
||||
3. **名前付きエラーを読む。** 同期が失敗した場合は、メッセージ内のメタデータタイプと `universalIdentifier`(上記参照)を確認し、そのエンティティをマニフェスト内で特定します。 コンフリクトは、重複または再利用された識別子を指していることがほとんどです。
|
||||
4. **アンインストールして再インストール。** `yarn twenty app:uninstall` を実行し、その後再度同期します(`yarn twenty dev`)。 これにより、ワークスペースの残りを維持したまま、アプリのメタデータをクリーンな状態から再構築します。
|
||||
5. **フルリセット(最後の手段)。** `yarn twenty docker:reset` を実行し、その後再シードと再同期を行います。
|
||||
|
||||
@@ -78,6 +78,13 @@ yarn add -D vitest vite-tsconfig-paths
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020';
|
||||
const TWENTY_API_KEY = process.env.TWENTY_API_KEY ?? '<the pre-seeded local dev key>';
|
||||
|
||||
// Make env vars available to globalSetup (test.env only applies to workers)
|
||||
process.env.TWENTY_API_URL = TWENTY_API_URL;
|
||||
process.env.TWENTY_API_KEY = TWENTY_API_KEY;
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
tsconfigPaths({
|
||||
@@ -88,66 +95,74 @@ export default defineConfig({
|
||||
test: {
|
||||
testTimeout: 120_000,
|
||||
hookTimeout: 120_000,
|
||||
fileParallelism: false,
|
||||
include: ['src/**/*.integration-test.ts'],
|
||||
setupFiles: ['src/__tests__/setup-test.ts'],
|
||||
globalSetup: ['src/__tests__/global-setup.ts'],
|
||||
env: {
|
||||
TWENTY_API_URL: 'http://localhost:2020',
|
||||
TWENTY_API_KEY: 'your-api-key',
|
||||
TWENTY_API_URL,
|
||||
TWENTY_API_KEY,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
テストを実行する前にサーバーに到達可能であることを検証するセットアップファイルを作成します:
|
||||
サーバーに到達可能であることを検証し、SDK 用のテスト用コンフィグ(`~/.twenty/config.test.json`)を書き込み、テストが実行される前にアプリを同期するグローバルセットアップファイルを作成します。
|
||||
|
||||
```ts src/__tests__/setup-test.ts
|
||||
```ts src/__tests__/global-setup.ts
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { beforeAll } from 'vitest';
|
||||
|
||||
const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020';
|
||||
const TEST_CONFIG_DIR = path.join(os.tmpdir(), '.twenty-sdk-test');
|
||||
import { appDevOnce, appUninstall } from 'twenty-sdk/cli';
|
||||
|
||||
const APP_PATH = process.cwd();
|
||||
const CONFIG_DIR = path.join(os.homedir(), '.twenty');
|
||||
|
||||
export async function setup() {
|
||||
const apiUrl = process.env.TWENTY_API_URL!;
|
||||
const apiKey = process.env.TWENTY_API_KEY!;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Verify the server is running
|
||||
const response = await fetch(`${TWENTY_API_URL}/healthz`);
|
||||
|
||||
const response = await fetch(`${apiUrl}/healthz`);
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Twenty server is not reachable at ${TWENTY_API_URL}. ` +
|
||||
'Start the server before running integration tests.',
|
||||
);
|
||||
throw new Error(`Twenty server is not reachable at ${apiUrl}.`);
|
||||
}
|
||||
|
||||
// Write a temporary config for the SDK
|
||||
fs.mkdirSync(TEST_CONFIG_DIR, { recursive: true });
|
||||
|
||||
// Write the SDK's test config (the CLI reads config.test.json when NODE_ENV=test)
|
||||
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(TEST_CONFIG_DIR, 'config.json'),
|
||||
path.join(CONFIG_DIR, 'config.test.json'),
|
||||
JSON.stringify({
|
||||
remotes: {
|
||||
local: {
|
||||
apiUrl: process.env.TWENTY_API_URL,
|
||||
apiKey: process.env.TWENTY_API_KEY,
|
||||
},
|
||||
},
|
||||
remotes: { local: { apiUrl, apiKey } },
|
||||
defaultRemote: 'local',
|
||||
}, null, 2),
|
||||
);
|
||||
});
|
||||
|
||||
// Start from a clean slate, then sync the app
|
||||
await appUninstall({ appPath: APP_PATH }).catch(() => {});
|
||||
|
||||
const result = await appDevOnce({ appPath: APP_PATH });
|
||||
if (!result.success) {
|
||||
throw new Error(`Dev sync failed: ${result.error?.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function teardown() {
|
||||
await appUninstall({ appPath: APP_PATH });
|
||||
}
|
||||
```
|
||||
|
||||
## プログラム用 SDK API
|
||||
|
||||
`twenty-sdk/cli` サブパスは、テストコードから直接呼び出せる関数をエクスポートします:
|
||||
|
||||
| 関数 | 説明 |
|
||||
| -------------- | ------------------------------- |
|
||||
| `appBuild` | アプリをビルドし、必要に応じて tarball にパッケージ化 |
|
||||
| `appDeploy` | tarball をサーバーにアップロード |
|
||||
| `appInstall` | アクティブなワークスペースにアプリをインストール |
|
||||
| `appUninstall` | アクティブなワークスペースからアプリをアンインストール |
|
||||
| 関数 | 説明 |
|
||||
| -------------- | -------------------------------------------- |
|
||||
| `appBuild` | アプリをビルドし、必要に応じて tarball にパッケージ化 |
|
||||
| `appDeploy` | tarball をサーバーにアップロード |
|
||||
| `appDevOnce` | アプリを 1 回ビルドして同期します(`yarn twenty apply` と同じ)。 |
|
||||
| `appInstall` | アクティブなワークスペースにアプリをインストール |
|
||||
| `appUninstall` | アクティブなワークスペースからアプリをアンインストール |
|
||||
|
||||
各関数は、`success: boolean` と `data` または `error` のいずれかを含む結果オブジェクトを返します。
|
||||
|
||||
@@ -238,64 +253,10 @@ yarn test:watch
|
||||
yarn twenty dev:typecheck
|
||||
```
|
||||
|
||||
これは `tsc --noEmit` を実行し、型エラーを報告します。
|
||||
これは、あなたのアプリの `tsconfig.json` に対して `tsc --noEmit` を実行し、型エラーを報告します。 スキャフォルドされたアプリには、テストファイル(`tsconfig.spec.json`)も対象とする `yarn typecheck` スクリプトも同梱されています。
|
||||
|
||||
## GitHub Actions による CI
|
||||
|
||||
スキャフォルダーは、すぐに使える GitHub Actions ワークフローを `.github/workflows/ci.yml` に生成します。 `main` へのプッシュやプルリクエストのたびに、統合テストを自動実行します。
|
||||
スキャフォルダーは、すぐに使えるワークフローを `.github/workflows/ci.yml` に生成します。 `main` へのすべてのプッシュおよびすべてのプルリクエスト時に、ランナー内で一時的な Twenty サーバーを起動(`twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test` アクション経由)し、そのサーバーを指すように `TWENTY_API_URL` / `TWENTY_API_KEY` を設定した上で、`yarn lint`、`yarn typecheck`、`yarn test:unit`、`yarn test` を実行します。 シークレットは一切不要で、ワークフローの先頭にある `TWENTY_VERSION` 環境変数を通じてサーバーバージョンを固定できます。
|
||||
|
||||
ワークフローの内容:
|
||||
|
||||
1. コードをチェックアウトする
|
||||
2. `twentyhq/twenty/.github/actions/spawn-twenty-docker-image` アクションを使って一時的な Twenty サーバーを起動する
|
||||
3. `yarn install --immutable` で依存関係をインストールする
|
||||
4. アクションの出力から注入された `TWENTY_API_URL` と `TWENTY_API_KEY` を用いて `yarn test` を実行する
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
シークレットを設定する必要はありません。`spawn-twenty-docker-image` アクションがランナー内で一時的な Twenty サーバーを直接起動し、接続情報を出力します。 `GITHUB_TOKEN` シークレットは GitHub によって自動的に提供されます。
|
||||
|
||||
`latest` の代わりに特定の Twenty バージョンを固定するには、ワークフローの先頭にある `TWENTY_VERSION` 環境変数を変更します。
|
||||
スキャフォルドされた 2 つのワークフロー(`ci.yml` と `cd.yml` デプロイパイプライン)の詳細な手順については、[Publishing → Automated CI/CD](/l/ja/developers/extend/apps/operations/publishing#automated-cicd-scaffolded-workflows) を参照してください。
|
||||
|
||||
+7
-3
@@ -88,9 +88,11 @@ const GenerateDocumentForm = () => {
|
||||
}, []);
|
||||
|
||||
const generate = async () => {
|
||||
const apiBaseUrl = process.env.TWENTY_API_URL;
|
||||
// Prefer the injected functions URL; fall back to the legacy /s prefix (self-hosted/local)
|
||||
const functionsBaseUrl =
|
||||
process.env.TWENTY_FUNCTIONS_URL || `${process.env.TWENTY_API_URL}/s`;
|
||||
const token = process.env.TWENTY_APP_ACCESS_TOKEN ?? process.env.TWENTY_API_KEY;
|
||||
const res = await fetch(`${apiBaseUrl}/s/documents/generate`, {
|
||||
const res = await fetch(`${functionsBaseUrl}/documents/generate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
||||
body: JSON.stringify({ templateId, recordId }),
|
||||
@@ -181,7 +183,9 @@ const DocumentViewer = () => {
|
||||
const recordId = useFrontComponentExecutionContext((c) => c.recordId ?? null);
|
||||
// ...load { content, file } for recordId, then derive the links:
|
||||
const pdfUrl = document.file?.[0]?.url;
|
||||
const webUrl = `${process.env.TWENTY_API_URL ?? ''}/s/documents/view?id=${recordId}`;
|
||||
const functionsBaseUrl =
|
||||
process.env.TWENTY_FUNCTIONS_URL || `${process.env.TWENTY_API_URL ?? ''}/s`;
|
||||
const webUrl = `${functionsBaseUrl}/documents/view?id=${recordId}`;
|
||||
|
||||
// Render the template body, plus quick links to the web page and the PDF.
|
||||
// Links open in a new tab so they don't navigate the embedded component.
|
||||
|
||||
+8
-2
@@ -9,8 +9,14 @@ description: HTTP 経由で関数をトリガーし、ドキュメントを Web
|
||||
* ドキュメントを生成するUI呼び出しの **POST** エンドポイントと
|
||||
* ドキュメントを印刷可能なウェブページとしてレンダリングするパブリック**GET** エンドポイント。
|
||||
|
||||
どちらも `httpRouteTriggerSettings` を使用します。 アプリのルートはあなたの
|
||||
20のサーバーの`/s`の下で提供されます(例:`http://localhost:2020/s/documents/generate`)。
|
||||
どちらも `httpRouteTriggerSettings` を使用します。 ローカル開発サーバーでは、アプリのルートは `/s` プレフィックスの下で提供されます(例:`http://localhost:2020/s/documents/generate`)。
|
||||
|
||||
<Note>
|
||||
Twenty Cloud では、ルートはワークスペースの専用関数ドメイン
|
||||
で提供されます。URL Twenty は `TWENTY_FUNCTIONS_URL` として挿入され、`/s` プレフィックスはありません。 `/s`
|
||||
プレフィックスは非推奨で、自己ホストおよびローカルインスタンスのみが使用できます。
|
||||
[ロジック関数の呼び出し](/l/ja/developers/extend/apps/layout/front-components#calling-a-logic-function)を参照してください。
|
||||
</Note>
|
||||
|
||||
## POST route — オンデマンドで生成
|
||||
|
||||
|
||||
+3
-3
@@ -76,11 +76,11 @@ CI と同じゲートを実行します。
|
||||
yarn lint # oxlint
|
||||
yarn typecheck # tsgo
|
||||
yarn test:unit # unit tests
|
||||
yarn twenty dev --once --dry-run # preview the metadata diff
|
||||
yarn twenty plan # preview the metadata diff
|
||||
```
|
||||
|
||||
ドライランは、それを適用せずにサーバー上で何が変更されるかを正確にプリントします —
|
||||
良い最終正常性チェックです。
|
||||
このプランは、適用せずにサーバー上で何が変わるかを正確に出力します。
|
||||
最終確認として有用です。
|
||||
[Testing](/l/ja/developers/extend/apps/operations/testing) と
|
||||
[Syncing & recovery](/l/ja/developers/extend/apps/operations/sync-and-recovery) を参照してください。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user