snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 3s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
---
title: 受信メールへの自動返信
description: AI を使用して受信メールをトリアージし、スレッド返信を自動的に送信するワークフローを構築します。
---
受信メールに数秒で対応 — 数時間ではなく。 このワークフローは、AI Agent を使用してノイズ(ニュースレター、スパム、自動返信)を除去し、実際のメッセージに対するパーソナライズされた応答をドラフトします。 そして、元の会話の中でスレッド返信として送信します。
## メールスレッドの仕組み
すべてのメールには、送信者のメールサーバーによって割り当てられる一意の識別子である非表示の `Message-ID` ヘッダーが含まれています。 メールに返信すると、メールクライアントはフィンガープリントを参照する `In-Reply-To` ヘッダーを設定します。 Gmail、Outlook、その他すべてのクライアントはメッセージをスレッドにまとめています。
Twenty では、そのフィンガープリントは Message オブジェクトに `headerMessageId` として保存されます。 ワークフローはそれをつかみ、返信メール送信アクションのIn-Reply-To 項目に渡します。
## ワークフローの構築
### ステップ 1: 新しいワークフローを作成
**設定->ワークフロー**に進み\*\*+新しいワークフロー\*\*をクリックしてください。
### ステップ2:受信メッセージをトリガーする
**レコードが作成されたら** **メッセージ**を選択します。
メールがTwentyに届くたびに、これは火事になります。
<img src="/images/user-guide/workflows/auto-reply/workflow-overview.png" style={{width:'100%'}} />
### ステップ 3: 送金者を調べてください
**レコードを検索**アクションを追加します。
送信者のアドレスはメッセージ自体にありません — 関連するメッセージ参加者レコードにあります。
| フィールド | 値 |
| ---------- | ----------------------------- |
| **オブジェクト** | メッセージ参加者 |
| **フィルター** | メッセージ **です** `{{trigger.id}}` |
| **フィルター** | ロールは **以下から** |
| **制限** | 1 |
これにより、`handle` で送信者のメールアドレスと、`displayName` で送信者の名前が表示されます。
<img src="/images/user-guide/workflows/auto-reply/find-sender.png" style={{width:'100%'}} />
### ステップ 4: トリアージしてAIとの返信をドラフトする
**AI エージェント** アクションを追加します。 この単一のステップは、2つのことを行います: 電子メールに返信が値するかどうかを決定し、その場合は1つを書き込みます。
次のようなプロンプトを使用します。
```
You are an email triage assistant for a sales team. Read the following
inbound email and decide if it deserves a reply.
Subject: {{trigger.subject}}
Body: {{trigger.text}}
From: {{Find Sender.first.displayName}} ({{Find Sender.first.handle}})
If this email is spam, a newsletter, an automated notification, or
otherwise does not need a human reply, respond with exactly: SKIP
Otherwise, write a short, professional reply (3-4 sentences max) that:
- Acknowledges their specific message
- Lets them know someone from the team will follow up shortly
- Is warm but not overly casual
Respond with only the reply text, no subject line or greeting prefix.
```
AI Agent は、次のステップが参照できるレスポンスを `response` フィールドに出力します。
<img src="/images/user-guide/workflows/auto-reply/ai-triage.png" style={{width:'100%'}} />
### ステップ5:AIの決定に支局
**If/Else**アクションを追加して、AIが返信するかスキップするかを確認します。
| フィールド | 値 |
| ----------- | ------------------------------------ |
| **条件** | AI Agent の`response` **`SKIP`を含まない** |
| **If true** | メール送信を続ける |
| **それ以外** | 何もしない (ワークフロー終了) |
スパム、ニュースレター、自動生成されたメッセージは削除されます。 他のすべてが次のステップに移動します。
<img src="/images/user-guide/workflows/auto-reply/should-reply.png" style={{width:'100%'}} />
### ステップ 6: スレッド返信を送信
"if true" ブランチに **メール送信** アクションを追加します。 **詳細オプション**をクリックし、**返信内に追加**をクリックします。
| フィールド | 値 |
| --------------- | -------------------------------------- |
| **宛先** | `{{Find Sender.first.handle}}` |
| **件名** | `Re: {{trigger.subject}}` |
| **本文** | `{{AI Triage & Draft Reply.response}}` |
| **In-Reply-To** | `{{trigger.headerMessageId}}` |
In-Reply-To フィールドは、新しい会話ではなく返信になります。 受信者は、Gmail、Outlook、または他のクライアントでは、元の電子メールの下でスレッド化されていることを確認します。
<img src="/images/user-guide/workflows/auto-reply/send-email.png" style={{width:'100%'}} />
<Tip>
**In-Reply-To** はトリガーから `message.headerMessageId` を期待します — 受信者のアドレスではなく、メールの固有の指紋です。 空白のままにすると、電子メールは単独のメッセージとして送信されます。
</Tip>
<Warning>
Gmail は件名を使用してメッセージをスレッドにグループ化します。 元のスレッドの中に返信を表示するには、件名が `Re:` (コロンとスペースを含む) で始まる必要があります。 In-Reply-To ヘッダーが正しく設定されている場合でも、返信は別個の会話として表示されます。
</Warning>
### ステップ 7: テストして有効化
**テスト**をクリックし、メールクライアントを確認してください。 返信は元のメッセージの下に入れ子になっているように見えます。
あなたがそれに満足しているときに有効にします。
## 上に構築するアイデア
* **VIPへの返信のみ** — 送信者のドメインを確認するブランチを追加します。
* **意図でルート化** — サポートリクエストとは異なる販売お問い合わせに対応するために、別個の AI Agent プロンプトを使用してください。
* **返信する前にエンリッチする** — 送信者の会社を引っ張ったり、AIプロンプトに履歴を出すために検索レコードのステップを追加し、よりパーソナライズされた返信を求めます。

View File

@@ -0,0 +1,179 @@
---
title: Closed Won の自動化
description: 商談が成約(Closed Won)になったときに、成約後の活動を自動化します。
---
商談がクローズしたら、複数のことを行う必要があります:会社のステータスを更新し、チームメンバーに通知し、オンボーディングタスクを作成します。 これらをひとつのワークフローで自動化します。
## 問題
商談が "Closed Won" に移動したとき:
* 会社タイプを "Prospect" から "Customer" に変更する必要があります
* オンボーディングタスクを作成する必要があります
* カスタマーサクセスチームに通知する必要があります
* 営業担当者への確認が必要です
これを手作業で行うのは時間がかかり、ミスの原因になります。
## 解決策
成約後のすべての作業を自動で処理するワークフローを作成します。
## ワークフローのセットアップを完了
### ステップ 1: ワークフローを作成
1. 「**Settings → Workflows**」に移動
2. 「**+ New Workflow**」をクリック
3. 名前を "Deal Won - Post-Win Automation" にします
### ステップ 2: トリガーを設定
1. 「**Record is Updated**」を選択
2. 「**Opportunities**」を選択
3. "Fields to monitor" で **Stage** を選択
### ステップ 3: ステージフィルターを追加
1. 「**Filter**」アクションを追加
2. 条件: `{{trigger.object.stage}}` が "Closed Won" と等しい
### ステップ 4: 会社タイプを更新
1. 「**Update Record**」アクションを追加
2. 設定:
| フィールド | 値 |
| ------------- | ------------------------------- |
| **オブジェクト** | 会社 |
| **レコード** | `{{trigger.object.company.id}}` |
| **種類** | 顧客 |
| **初回ディール日** | `{{trigger.object.closedAt}}` |
| **アカウントオーナー** | `{{trigger.object.owner.id}}` |
### ステップ 5: オンボーディングタスクを作成
1. 「**Create Record**」アクションを追加
2. 設定:
| フィールド | 値 |
| ---------- | ---------------------------------------------------------------------------------------------------- |
| **オブジェクト** | タスク |
| **タイトル** | `Onboarding: {{trigger.object.name}}` |
| **担当者** | カスタマーサクセスチームのメンバー |
| **期日** | 今から3日後 |
| **優先** | 高 |
| **関連会社** | `{{trigger.object.company.id}}` |
| **関連商談** | `{{trigger.object.id}}` |
| **説明** | `New customer onboarding for {{trigger.object.company.name}}. Deal value: {{trigger.object.amount}}` |
### ステップ 6: カスタマーサクセスに通知
1. 「**Send Email**」アクションを追加
2. 設定:
| フィールド | 値 |
| ------ | -------------------------------------------------- |
| **宛先** | customer-success@yourcompany.com |
| **件名** | `🎉 New Customer: {{trigger.object.company.name}}` |
| **本文** | 下記の例を参照してください |
**メール本文の例**:
```
Hi CS Team,
We have a new customer!
Company: {{trigger.object.company.name}}
Deal: {{trigger.object.name}}
Value: {{trigger.object.amount}}
Sales Rep: {{trigger.object.owner.name}}
Close Date: {{trigger.object.closedAt}}
An onboarding task has been created automatically.
Let's give them a great start!
```
### ステップ 7: 営業担当者に確認を送信
1. さらに「**Send Email**」アクションを追加
2. 設定:
| フィールド | 値 |
| ------ | --------------------------------------------------------------- |
| **宛先** | `{{trigger.object.owner.email}}` |
| **件名** | `✅ Deal Closed: {{trigger.object.name}}` |
| **本文** | おめでとうございます! ディールの処理が完了しました。 カスタマーサクセスチームに通知され、オンボーディングが開始されました。 |
### ステップ 8: テストして有効化
1. テスト用の商談を "Closed Won" に移動してテストします
2. 確認:
* 会社の種別が "Customer" に変更された
* オンボーディングタスクが作成された
* CS チームがメールを受信した
* 営業担当者が確認を受け取った
3. 準備ができたら有効化します
## Closed Lost の処理
失注ディール向けに同様のワークフローを作成します:
### トリガー
* レコードが更新(Opportunities、Stage = "Closed Lost")
### アクション
1. 「**Create Record**」: "Lost Deal Analysis" 用のタスク
2. 「**Update Record**」: 失注理由を会社レコードに追加
3. 「**Send Email**」: 失注の旨をマネージャーに通知
## 高度な設定: 多段階のオンボーディング
複雑なオンボーディングには、複数のタスクを作成します:
```javascript
export const main = async (params) => {
const tasks = [
{ title: "Welcome call", daysFromNow: 1, assignee: "CS" },
{ title: "Send onboarding materials", daysFromNow: 2, assignee: "CS" },
{ title: "Technical setup", daysFromNow: 5, assignee: "Support" },
{ title: "30-day check-in", daysFromNow: 30, assignee: "CS" }
];
return { tasks };
};
```
配列から各タスクを作成するには **Iterator** を使用します。
## カスタマイズのアイデア
### 他のツールも最新状態に保つ
* **HTTP Request** で請求システムに顧客を作成する
### 条件付きアクション
「**Filter**」アクションを使用して次を行います:
* エンタープライズと SMB で異なるオンボーディング
* 地域に基づいて担当者を変える
* 小規模ディールでは通知をスキップ
### 取引の詳細を含める
整形には「**Code**」アクションを使用:
* ディールのサマリードキュメント
* CS チーム向けの引き継ぎメモ
* カスタムのオンボーディングチェックリスト
## 関連
* [ワークフローのアクション](/l/ja/user-guide/workflows/capabilities/workflow-actions)
* [ワークフローからメールを送信](/l/ja/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,136 @@
---
title: 停滞した商談を検出
description: 商談が更新されていない場合にマネージャーに自動的に通知します。
---
商談が停滞したときにマネージャーにアラートを送信して、パイプラインの健全性を保ちましょう。 このワークフローは、指定した日数の間更新されていない商談をチェックします。
## 問題
更新されずに放置された商談は次のような事態を招きます:
* 商談が冷え込む
* 予測の信頼性低下
* 収益の損失
## 解決策
停滞した商談を見つけ、マネージャーにメールを送信する定期実行のワークフローを作成します。
## ステップバイステップの設定
### ステップ 1: ワークフローを作成
1. 「**Settings → Workflows**」に移動
2. 「**+ New Workflow**」をクリック
3. 名前を "停滞商談アラート" にします
### ステップ 2: トリガーを設定
1. 「**On a Schedule**」を選択
2. 毎日実行に設定 (例: 毎朝 8 時)
### ステップ 3: 停滞した商談を検索
1. 「**Search Records**」アクションを追加
2. 設定:
| フィールド | 値 |
| ---------- | ----------------------------------------------- |
| **オブジェクト** | 商談 |
| **フィルター** | Updated At が (today - 7 days) より前 |
| **フィルター** | Stage が "Closed Won" ではなく、かつ "Closed Lost" でもない |
| **制限** | 100 |
### ステップ 4: 該当があるか確認
1. 「**Filter**」アクションを追加
2. 条件: `{{searchRecords.length}}` が 0 より大きい
3. 停滞した商談がない場合、ワークフローはここで停止します
### ステップ 5: アラートを整形 (コードアクション)
メールを整形するために「**Code**」アクションを追加します:
```javascript
export const main = async (params) => {
const opportunities = params.opportunities;
// Group opportunities by owner
const byOwner = {};
opportunities.forEach(opp => {
const ownerEmail = opp.owner?.email || 'unassigned';
if (!byOwner[ownerEmail]) {
byOwner[ownerEmail] = [];
}
byOwner[ownerEmail].push({
name: opp.name,
amount: opp.amount,
lastUpdated: opp.updatedAt,
stage: opp.stage
});
});
// Format summary for manager
let summary = "Stale Opportunities Report\n\n";
Object.entries(byOwner).forEach(([owner, opps]) => {
summary += `${owner}: ${opps.length} stale opportunities\n`;
opps.forEach(opp => {
summary += ` - ${opp.name} (${opp.stage})\n`;
});
summary += "\n";
});
return {
summary,
totalCount: opportunities.length
};
};
```
### ステップ 6: アラートメールを送信
「**Send Email**」アクションを追加:
| フィールド | 値 |
| ------ | ------------------------------------ |
| **宛先** | sales-manager@yourcompany.com |
| **件名** | `🚨 要対応の停滞商談が {{code.totalCount}} 件` |
| **本文** | `{{code.summary}}` |
### ステップ 7: テストして有効化
1. ワークフローを実行するには「**Test**」をクリック
2. メールに正しいデータが含まれていることを確認します
3. 準備ができたら有効化します
## カスタマイズオプション
### 停滞のしきい値を変更
「**Search Records**」フィルターを編集し、7 日を希望の期間に変更します:
* 高回転の営業には 3 日
* エンタープライズの商談には 14 日
* 長いセールスサイクルには 30 日
### 個々の担当者にアラート
マネージャー宛ての 1 通のメールではなく、**Iterator** を使用して、各担当者に自分の停滞中の商談についてのパーソナライズされたメールを送信します。
### エスカレーションを追加
深刻度を段階的に上げた複数のワークフローを作成します:
1. 7 日目: 担当者にメール
2. 14 日目: 担当者 + マネージャーにメール
3. 21 日目: マネージャーが介入できるようタスクを作成
### Slack にも通知
メールの代わりに、またはメールに加えて、**HTTP Request** を使用して Slack の Webhook に投稿します。
## 関連
* [ワークフローのアクション](/l/ja/user-guide/workflows/capabilities/workflow-actions)
* [ワークフローからメールを送信](/l/ja/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,69 @@
---
title: 受信メール数を表示
description: 各連絡先から受信したメール数を自動的にカウントして表示するワークフローを作成します。
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/workflow-number-of-emails-received.png" style={{width:'100%'}} />
## 概要
このワークフローは新しいメールを受信するたびにトリガーされ、その送信者からのメールの合計数で Person レコード上のカスタムフィールドを更新します。
## 前提条件
このワークフローを設定する前に、**People** オブジェクトにカスタムフィールドを作成します:
1. 「**設定 → データモデル → People**」に移動します
2. 新しい **Number** フィールドを追加します
3. 「この人物から受信したメール数」などの名前を付けます
## ステップバイステップの設定
<VimeoEmbed videoId="1148700336" title="デモ動画" />
### ステップ 1: トリガーを設定
1. 「**Workflows**」に移動し、新しいワークフローを作成します
2. トリガーとして **Record is Created** を選択します
3. **Message Participants**(Advanced objects 内にあります)を選択します
<Note>
Message Participant は、メッセージ ID と person ID の組み合わせで、メッセージごとに一意のレコードを作成します。 これは、送信者(または受信者)のメールアドレスを含む `handle` フィールドにアクセスできるため、Messages を直接扱うよりも追跡が容易です。
</Note>
### ステップ 2: Role でフィルター
1. 「**Filter**」アクションを追加します
2. 条件を設定します: **Role** が **FROM** と等しい
これにより、この人物が送信したメッセージのみをカウントし、相手宛てに送られたメッセージは含めないようにします。
### ステップ 3: 同じ Handle を持つすべての Message Participants を検索
1. 「**Search Records**」アクションを追加します
2. オブジェクトとして **Message Participants** を選択します
3. フィルターを追加します: **Handle** がトリガーの handle(送信者のメールアドレス)と等しい、かつ **Role** が **FROM** と等しい
4. **Limit** を 1 から **200**(最大値)に増やします
これにより、このメールアドレスからのすべてのメッセージを見つけ、合計数を取得します。
<Note>
Search Records アクションは、返せるレコードが最大 200 件に制限されています。 ただし、個々のレコードではなく `totalCount` の値のみを使用するため、このステップではこの人物が送信したメールの総数が返されます。
</Note>
### ステップ 4: Create or Update Record アクションで Person レコードを更新
1. 「**Create or Update Record**」アクションを追加します
2. オブジェクトとして **People** を選択します
3. Message Participant の `handle` とメールアドレスを照合して該当の人物を特定します
4. カスタムの「受信メール数」フィールドを `{{searchRecords.totalCount}}` に設定します
Search Records アクションの `totalCount` の値は、この人物から受信したメールの総数を表します。
## 関連
* [ワークフローのアクション](/l/ja/user-guide/workflows/capabilities/workflow-actions)
* [カスタムフィールドの作成方法](/l/ja/user-guide/data-model/how-tos/customize-your-data-model)
* [Search Records アクション](/l/ja/user-guide/workflows/capabilities/workflow-actions#search-records)

View File

@@ -0,0 +1,170 @@
---
title: 関連レコードのデータを表示
description: ワークフローを使用して、関連レコードのデータ(例:商談上の会社情報)を表示します。
---
関連レコードのデータを自分のレコード上に直接表示します — たとえば、会社の従業員数をその会社の商談に表示します。 入れ子フィールドがネイティブに利用可能になるまで、このワークフローによる回避策が役立ちます。
## 一般的な使用例
| ソース | コピー先 | コピーするフィールド |
| --- | ---- | -------------- |
| 会社 | 商談 | 業種、会社規模、ARR |
| 人物 | 商談 | メール、電話、役職 |
| 商談 | 会社 | 直近の商談金額、直近の受注日 |
## 基本的なフィールドのコピー
### 例: 連絡先のメールを商談にコピー
**目標**: 商談で連絡担当者を設定したとき、その人物のメールを商談にコピーして簡単に参照できるようにする。
### 前提条件
ワークフローを作成する前に、**設定 → データモデル → 商談** でコピー先フィールドを作成します:
* 連絡先メール(タイプ: Email)
* 連絡先電話(タイプ: Phone)
### セットアップ
1. **トリガー**: レコードが更新(商談、連絡担当者フィールド)
2. **フィルター**: 連絡担当者が空でないことを確認
3. **レコード検索**: リンクされた人物を見つける
* オブジェクト: People
* フィルター: ID が `{{trigger.object.pointOfContact.id}}` に等しい
4. **レコードを更新**:
* オブジェクト: Opportunities
* レコード: `{{trigger.object.id}}`
* 連絡先メール: `{{searchRecords[0].email}}`
* 連絡先電話: `{{searchRecords[0].phone}}`
## 複数フィールドのコピー
### 例: 関連するすべての商談に会社情報を同期
**目標**: 会社の詳細が変更されたら、関連するすべての商談を更新する。
### セットアップ
1. **トリガー**: レコードが更新(会社)
* フィールド: 業種、会社規模、年間売上高
2. **レコード検索**: この会社のすべての商談を見つける
* オブジェクト: Opportunities
* フィルター: 会社 ID が `{{trigger.object.id}}` に等しい
3. **イテレーター**: 各商談をループ処理する
4. **レコードを更新** (イテレーター内):
* オブジェクト: Opportunities
* レコード: `{{iterator.currentItem.id}}`
* 会社の業種: `{{trigger.object.industry}}`
* 会社規模: `{{trigger.object.companySize}}`
* 会社のARR: `{{trigger.object.annualRevenue}}`
## レコード作成時のコピー
### 例: 会社データで商談を事前入力
**目標**: 会社にリンクされた商談を作成するとき、主要な会社情報を自動コピーする。
### 前提条件
**設定 → データモデル → 商談** でコピー先フィールドを作成します:
* 会社の業種(タイプ: Text)
* 会社規模(タイプ: Number)
### セットアップ
1. **トリガー**: レコードが作成(商談)
* フィルター: 会社が空でない
2. **レコード検索**: リンクされた会社の詳細を取得
* オブジェクト: Companies
* フィルター: ID が `{{trigger.object.company.id}}` に等しい
3. **レコードを更新**:
* オブジェクト: Opportunities
* レコード: `{{trigger.object.id}}`
* 会社の業種: `{{searchRecords[0].industry}}`
* 会社規模: `{{searchRecords[0].employees}}`
<Note>
**タスクとノートの制限**: タスクとノートのリレーションは多対多としてハードコードされており、ワークフローのトリガーやアクションではまだ使用できません。 これらのリレーションにアクセスするには、代わりに[API](/l/ja/developers/extend/api)を使用してください。
</Note>
## 双方向同期
### 例: 主担当者を同期した状態に保つ
**目標**: 会社の主担当者が変更されたら、その人物を更新する。 人物が主担当者になったときは、会社を更新する。
### ワークフロー 1: 会社 → 人物
1. **トリガー**: レコードが更新(会社、主担当者フィールド)
2. **レコードを更新**: 人物の "Is Primary Contact" を true に設定
3. **レコード検索**: 以前の主担当者を見つける
4. **レコードを更新**: 以前の連絡先の "Is Primary Contact" を false に設定
### ワークフロー 2: 人物 → 会社
1. **トリガー**: レコードが更新(人物、Is Primary Contact = true)
2. **レコードを更新**: 会社の主担当者をこの人物に設定
<Note>
無限ループを避けるため、双方向同期の取り扱いには注意してください。 更新前に値が実際に変更されたかを確認するフィルターを使用する。
</Note>
## コードによる複雑なマッピング
### 例: コピー時にデータを変換
**目標**: 人物から商談へ電話番号をコピーし、フォーマットする。
```javascript
export const main = async (params) => {
const { phone } = params;
if (!phone) return { formattedPhone: null };
// Remove non-numeric characters
const digits = phone.replace(/\D/g, '');
// Format as (XXX) XXX-XXXX
const formatted = digits.length === 10
? `(${digits.slice(0,3)}) ${digits.slice(3,6)}-${digits.slice(6)}`
: phone;
return { formattedPhone: formatted };
};
```
## ベストプラクティス
### ループを回避する
* 互いにトリガーし合って終わらないワークフローを作成しない
* 特定のフィールド条件を使用する
* 値が実際に変更されたかを確認するチェックを追加する
### 欠損データの取り扱い
* コピー前に常にソースレコードの存在を確認する
* 任意フィールドには既定値を用意する
* ソースフィールドが空の場合はフィルターでスキップする
### パフォーマンス
* 多数のレコードにコピーする場合はバッチ更新を使用する
* 大規模な同期処理にはスケジュールされたワークフローを使用する
* 複数レコードの更新にはイテレーターの使用を検討する
## 関連
* [ワークフローのアクション](/l/ja/user-guide/workflows/capabilities/workflow-actions)
* [ワークフローのトリガー](/l/ja/user-guide/workflows/capabilities/workflow-triggers)

View File

@@ -0,0 +1,202 @@
---
title: 数式フィールド
description: ネイティブ対応が提供されるまで、ワークフローを使って数式フィールドを作成します。
---
Twenty は現時点でネイティブの数式フィールドをまだサポートしていません(2026 年に提供予定)ですが、ワークフローを使えば同等の結果を実現できます。 この回避策により、単純な連結から複雑なビジネスロジックまで、フィールド値を自動計算して入力できます。
## 一般的な使用例
| ユースケース | 数式例 |
| ------------ | ---------------------------- |
| **氏名** | First Name + " " + Last Name |
| **見込み金額** | Amount × Probability |
| **期日までの日数** | Due Date - Today |
| **ステージ滞在日数** | Today - Stage Entry Date |
| **リードスコア** | 複数の基準に基づくポイント |
<Tip>
パイプラインのステージでの時間を追跡する完全な例については、[商談が各ステージにとどまる時間を追跡](/l/ja/user-guide/views-pipelines/how-tos/track-time-in-stage) を参照してください。
</Tip>
## 基本の式:連結
### 例:氏名を自動入力
**目的**: 名と姓を自動的に結合して氏名フィールドにする。
### セットアップ
1. **トリガー**: レコードが更新または作成される(People)
2. **フィルター**: 名または姓が変更されたかを確認
3. **コードアクション**:
```javascript
export const main = async (params) => {
const { firstName, lastName } = params;
const fullName = [firstName, lastName]
.filter(Boolean)
.join(' ');
return { fullName };
};
```
4. **レコードを更新**: 氏名を `{{code.fullName}}` に設定
## 数値の式:見込み金額
### 例:見込み収益を計算
**目的**: 商談金額に確度を掛けて見込み金額を算出する。
ワークフロー全体については、[パイプラインで見込み金額を表示する方法](/l/ja/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline) を参照してください。
### セットアップ
1. **トリガー**: レコードが更新される(Opportunities、Amount または Probability フィールド)
2. **コードアクション**:
```javascript
export const main = async (params) => {
const { amount, probability } = params;
const expectedAmount = (amount || 0) * (probability || 0) / 100;
return { expectedAmount };
};
```
3. **レコードを更新**: 見込み金額を `{{code.expectedAmount}}` に設定
## 日付の式:日数計算
### 例:タスクの期日までの日数
**目的**: タスクの期日まで残り何日かを計算する。
### セットアップ
1. **トリガー**: レコードが更新または作成される(Tasks、Due Date フィールド)
2. **コードアクション**:
```javascript
export const main = async (params) => {
const { dueDate } = params;
if (!dueDate) {
return { daysUntilDue: null };
}
const due = new Date(dueDate);
const today = new Date();
const diffTime = due - today;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return { daysUntilDue: diffDays };
};
```
3. **レコードを更新**: 期日までの日数を `{{code.daysUntilDue}}` に設定
<Note>
負の値は期限超過のタスクを示します。 このフィールドを使用して、緊急度でタスクをフィルターまたは並べ替えることができます。
</Note>
## 条件付き式:リードスコア
### 例:条件に基づいてリードスコアを計算
**目的**: 企業規模、業種、エンゲージメントに基づいてリードにスコアを付与する。
### セットアップ
1. **トリガー**: レコードが更新される(People または Companies)
2. **コードアクション**:
```javascript
export const main = async (params) => {
const { companySize, industry, hasEmail, hasPhone, source } = params;
let score = 0;
// Company size scoring
if (companySize === 'Enterprise') score += 30;
else if (companySize === 'Mid-Market') score += 20;
else if (companySize === 'SMB') score += 10;
// Industry scoring
const targetIndustries = ['Technology', 'Finance', 'Healthcare'];
if (targetIndustries.includes(industry)) score += 25;
// Contact info scoring
if (hasEmail) score += 10;
if (hasPhone) score += 15;
// Source scoring
if (source === 'Referral') score += 20;
else if (source === 'Website') score += 10;
return { leadScore: score };
};
```
3. **レコードを更新**: リードスコアを `{{code.leadScore}}` に設定
## テキストの式:ドメイン抽出
### 例:メールからドメインを抽出
**目的**: メールのドメインを自動抽出して保存する。
### セットアップ
1. **トリガー**: レコードが更新される(People、Email フィールド)
2. **コードアクション**:
```javascript
export const main = async (params) => {
const { email } = params;
if (!email) return { domain: null };
const domain = email.split('@')[1]?.toLowerCase();
return { domain };
};
```
3. **レコードを更新**: ドメインフィールドを `{{code.domain}}` に設定
## ベストプラクティス
### パフォーマンス
* 関連するフィールド変更時のみトリガーする
* 計算が不要なレコードをスキップするためにフィルターを使用する
* 大量のワークフローでは複雑な計算を避ける
### エラーハンドリング
* 計算の前に null/undefined の値を確認する
* データが欠落している場合はデフォルト値を使用する
* 計算が失敗したときは明確なエラーメッセージを返す
### テスト
* エッジケース(空のフィールド、ゼロ値)でテストする
* 有効化する前に計算を手動で検証する
* 意図しない結果がないかワークフローの実行を監視する
## 関連
* [パイプラインで見込み金額を表示する方法](/l/ja/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline)
* [ステージ内の時間を追跡する方法](/l/ja/user-guide/views-pipelines/how-tos/track-time-in-stage)
* [ワークフローのアクション](/l/ja/user-guide/workflows/capabilities/workflow-actions)

View File

@@ -0,0 +1,127 @@
---
title: レビュー対象のノートをチームメンバーに通知
description: ノートのレビュー担当に同僚を割り当てたとき、自動でメール通知を送信します。
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<Note>
**ノート内でチームメンバーを直接タグ付けすることはまだサポートされていません。** この機能は 2026 年後半に提供予定です。 当面の間、このワークフローが実用的な回避策となります。
</Note>
## 課題
ノート内で同僚をタグ付けして、レビュー通知が届くようにしたい。 現時点では、Twenty はノートやタスクでの @メンションをサポートしていません。
## 回避策
ノート本文でのタグ付けの代わりに、次のようにします。
1. Notes オブジェクトに **Reviewer** リレーションフィールドを作成する
2. ノートの作成または編集時にレビュアーを割り当てる
3. ワークフローをレビューアに自動的にメールを送信し、ノートへのリンクが付いています。
<Warning>
**制限**: この方法では、フィールドごとに 1 人のレビュアーしか割り当てられません。 複数人に通知する必要がある場合は、リレーションフィールドを追加で作成します(例: Reviewer 1、Reviewer 2)。 一度に多数のコラボレーターをタグ付けする必要がある場合、拡張性は高くありません。
</Warning>
## ステップバイステップの設定
### ステップ 1: Reviewer フィールドを作成
<img src="/images/user-guide/workflows/reviewer-field-for-note.png" style={{width:'100%'}} />
1. 「**設定 → データモデル → Notes**」に移動します
2. **Add Field** をクリック
3. 設定:
| 設定 | 値 |
| ------------- | ----------------------- |
| **Name** | Reviewer |
| **種類** | リレーション |
| **関連オブジェクト** | ワークスペースメンバー |
| **リレーションタイプ** | 複数のノート → 1人のワークスペースメンバー |
4. フィールドを保存
### ステップ 2: ワークフローを作成
<VimeoEmbed videoId="1151897168" title="デモ動画" />
#### ワークフローのトリガーを作成
1. メインビューに移動し、新しいワークフローを作成します
2. トリガーとして **Record Updated** を選択します
3. オブジェクトとして **Note** を選択し、**Reviewer** フィールドを指定します。
4. これにより、ノートのレビュアーが更新されるたびにトリガーされます。
#### レビュアーが割り当てられた直後かを確認するフィルターを追加
レビュアーが割り当てられたときのみ続行するように、**フィルター** アクションを追加します:
| 条件 | 値 |
| ------------ | ----- |
| **Reviewer** | 空ではない |
#### ワークスペースメンバーを検索
1. 「**Search Records**」アクションを追加します
2. 「Advanced Objects」内の **Workspace Member** を選択
3. フィルターを追加:
| 条件 | 値 |
| ------ | ---------------------------- |
| **ID** | が `{{note.reviewerId}}` に等しい |
これにより、メールアドレスや氏名を含むワークスペースメンバーの完全なレコードが取得されます。
#### 通知メールを送信
1. 「**Send Email**」アクションを追加します
2. 設定:
| フィールド | 値 |
| ------ | --------------------------------------------------- |
| **宛先** | Search Record → First Workspace Member → User Email |
| **件名** | ノートのレビューをお願いします |
| **本文** | 下記の例を参照してください |
**メール本文の例:**
```text
Hi {{searchRecord.firstWorkspaceMember.name.firstName}},
You've been assigned to review a note.
View the note here:
https://yourSubDomain.twenty.com/object/note/{{recordIsUpdated.id}}
Best,
Twenty
```
<Note>
`yourSubDomain` を実際の Twenty ワークスペースのサブドメインに置き換えてください。
</Note>
#### テストと有効化
1. ワークフローを手動で実行するには「**Test**」をクリックします
2. ノートを作成または編集し、レビュアーを割り当てます
3. レビュアーの受信トレイに通知メールが届いているか確認します
4. ワークフローを有効化します
## 使用方法
セットアップ後、チームは次の手順でこのワークフローを利用できます。
1. 新しいノートを作成(または既存のノートを編集)
2. **Reviewer** フィールドで同僚を選択
3. 同僚に、ノートへの直接リンク付きメールが自動送信されます
## 関連
* [ワークフローのトリガー](/l/ja/user-guide/workflows/capabilities/workflow-triggers)
* [ワークフローからメールを送信](/l/ja/user-guide/workflows/capabilities/send-emails-from-workflows)
* [カスタムフィールドの作成方法](/l/ja/user-guide/data-model/how-tos/create-custom-fields)
* [リレーションフィールドの作成方法](/l/ja/user-guide/data-model/how-tos/create-relation-fields)

View File

@@ -0,0 +1,106 @@
---
title: 期限のタスクに関するメールアラートを送信
description: 差し迫ったタスクや期限超過のタスクについてチームメンバーに自動通知します。
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/email_tasks_due.png" style={{width:'100%'}} />
本日が期限のタスクについて、各チームメンバーに毎日メールでリマインダーを送信します。
## 概要
このワークフローはスケジュールで実行され、以下を実行します:
1. すべてのワークスペースメンバーを取得
2. 各メンバーを順に処理
3. 各メンバーの本日が期限のタスクを検索
4. 整形し、パーソナライズされたメールを送信
## ステップバイステップの設定
<VimeoEmbed videoId="1147463514" title="デモ動画" />
### ステップ 1: トリガーを設定
1. 「**Settings → Workflows**」に移動し、新しいワークフローを作成します
2. トリガーとして「**On a Schedule**」を選択します
3. 毎日 8:00 の cron 式を使用します: `0 8 * * *`
### ステップ 2: すべてのワークスペースメンバーを検索
1. 「**Search Records**」アクションを追加します
2. 「**Workspace Members**」(advanced objects 内)を選択します
3. フィルターは不要です—すべてのメンバーが取得されます
### ステップ 3: Iterator を追加
1. 「**Iterator**」アクションを追加します
2. 入力配列を前のステップのワークスペースメンバーに設定します
3. Iterator 内のすべてのアクションはメンバーごとに1回実行されます
### ステップ 4: 本日が期限のタスクを検索(Iterator 内)
1. Iterator 内で「**Search Records**」アクションを追加します
2. オブジェクトとして「**Tasks**」を選択します
3. フィルターを追加:
* **Assignee** = 現在のワークスペースメンバー(Iterator から)
* **Due Date** = 今日
### ステップ 5: タスクをメール本文に整形(Iterator 内)
タスクをリンク付きの読みやすいリストに整形するために「**Code**」アクションを追加します:
```javascript
export const main = async (params: {
tasksDue?: Array<{ id: string; title: string }> | null | string;
}) => {
const tasksDue =
typeof params.tasksDue === "string"
? JSON.parse(params.tasksDue)
: params.tasksDue;
if (!Array.isArray(tasksDue) || tasksDue.length === 0) {
return {
formattedTasks: "No tasks due today."
};
}
const formattedTasks = tasksDue
.map(
t =>
`${t.title}\nhttps://yourSubDomain.twenty.com/object/task/${t.id}`
)
.join("\n\n");
return { formattedTasks };
};
```
<Note>
`yourSubDomain` を実際の Twenty ワークスペースのサブドメインに置き換えてください。
</Note>
### ステップ 6: メールを送信(Iterator 内)
1. 「**Send Email**」アクションを追加します(引き続き Iterator 内)
2. 設定:
| フィールド | 値 |
| ------ | --------------------------------------------------------- |
| **宛先** | `{{iterator.currentItem.userEmail}}`(ワークスペースメンバーのメールアドレス) |
| **件名** | 本日が期限のタスク |
| **本文** | `{{code.formattedTasks}}` |
### ステップ 7: テストして有効化
1. ワークフローを手動で実行するには「**Test**」をクリックします
2. 受信トレイでメールを確認します
3. ワークフローを有効化します
## 関連
* [ワークフローのアクション](/l/ja/user-guide/workflows/capabilities/workflow-actions)
* [ワークフローからメールを送信](/l/ja/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Code アクションで配列を扱う](/l/ja/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)