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 2s

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,22 @@
---
title: ベストプラクティス',
---
この文書は、バックエンドで作業する際に従うべきベストプラクティスを概説しています。
## モジュール化アプローチを採用する
バックエンドは、NestJSを使用する際の基本原則であるモジュラーアプローチを採用しています。 コードを再利用可能なモジュールに分割し、クリーンで整理されたコードベースを維持してください。
各モジュールは特定の機能や機能性をカプセル化し、明確なスコープを持つべきです。 このモジュラーアプローチにより、関心事を明確に分離し、不要な複雑さを排除します。
## モジュールで使用するサービスを公開する
常に、明確で単一の責務を持つサービスを作成してください。これにより、コードの可読性と保守性が向上します。 サービスには意味のある一貫した名前を付けてください。
他のモジュールで使用したいサービスを公開する必要があります。 サービスを他のモジュールへ公開することは、NestJS の強力な依存性注入システムによって可能であり、コンポーネント間の疎結合を促進します。
## `any` 型の使用を避ける
変数を `any` として宣言すると、TypeScript の型チェッカーは型チェックを行わなくなり、その変数にはあらゆる型の値を割り当てられるようになります。 TypeScript は、値に基づいて変数の型を決定するために型推論を使用します。 `any` として宣言すると、TypeScript は型を推論できなくなります。 これにより、開発中に型に関連したエラーを捕捉しにくくなり、実行時エラーを引き起こし、コードのメンテナンス性、信頼性が低下し、他の人が理解しづらくなります。
これがすべてに型を持たせるべき理由です。 したがって、名と姓を持つ新しいオブジェクトを作成する場合は、操作しているオブジェクトの構造を定義する、名と姓を含むインターフェースまたは型を作成する必要があります。

View File

@@ -0,0 +1,39 @@
---
title: カスタムオブジェクト
---
オブジェクトは、組織独自のデータ(記録、属性、値)を保存するための構造です。 Twenty provides both standard and custom objects. Twenty は標準オブジェクトとカスタムオブジェクトの両方を提供します。
標準オブジェクトは、すべてのユーザーが利用可能な一連の属性を備えた組み込みのオブジェクトです。 標準オブジェクトは、すべてのユーザーが利用可能な一連の属性を備えた組み込みのオブジェクトです。 Examples of standard objects in Twenty include Company and Person. 標準オブジェクトは、すべてのユーザーが利用可能な一連の属性を備えた組み込みのオブジェクトです。 Examples of standard objects in Twenty include Company and Person. 標準オブジェクトには、Twenty のすべてのユーザーが利用できる標準フィールドがあり、例えば Company.displayName があります。
カスタムオブジェクトは、組織に固有の情報を保存するために作成できるオブジェクトです。 カスタムオブジェクトは、組織に固有の情報を保存するために作成できるオブジェクトです。 カスタムオブジェクトは、組織に固有の情報を保存するために作成できるオブジェクトです。 組み込みではないため、ワークスペースメンバーは、標準オブジェクトに適さない情報を保持するためにカスタムオブジェクトを作成およびカスタマイズできます。
## 上位スキーマ
<div style={{textAlign: 'center'}}>
<img src="/images/docs/server/custom-object-schema.png" alt="上位スキーマ" />
</div>
<br />
## 仕組み
カスタムオブジェクトは、オブジェクトの形状、名前、およびタイプを決定するメタデータテーブルから来ます。 このすべての情報は、テーブルで構成されるメタデータスキーマデータベースに存在します: このすべての情報は、テーブルで構成されるメタデータスキーマデータベースに存在します: このすべての情報は、テーブルで構成されるメタデータスキーマデータベースに存在します:
* **DataSource**: データの存在場所を示します。
* **オブジェクト**: オブジェクトを説明し、DataSourceにリンクします。
* **フィールド**: オブジェクトのフィールドを概説し、オブジェクトに接続します。
カスタムオブジェクトを追加するには、workspaceMemberが/metadata APIをクエリします。 これにより、メタデータが適切に更新され、メタデータに基づいてGraphQLスキーマが計算され、後で使用するためにGQLキャッシュに保存されます。 これにより、メタデータが適切に更新され、メタデータに基づいてGraphQLスキーマが計算され、後で使用するためにGQLキャッシュに保存されます。 これにより、メタデータが適切に更新され、メタデータに基づいてGraphQLスキーマが計算され、後で使用するためにGQLキャッシュに保存されます。
<div style={{textAlign: 'center'}}>
<img src="/images/docs/server/add-custom-objects.jpeg" alt="カスタムオブジェクトを追加するために/metadata APIをクエリ" />
</div>
<br />
データを取得するには、/graphqlエンドポイントを介してクエリを行い、Query Resolverを通過させるプロセスが必要です。
<div style={{textAlign: 'center'}}>
<img src="/images/docs/server/custom-object-schema.png" alt="データを取得するために/graphqlエンドポイントをクエリします" />
</div>

View File

@@ -0,0 +1,46 @@
---
title: 機能フラグ
---
機能フラグは試験的な機能を隠すために使用されます。 機能フラグは試験的な機能を隠すために使用されます。 Twentyでは、それらはワークスペースレベルで設定されており、ユーザーレベルではありません。 機能フラグは試験的な機能を隠すために使用されます。 Twentyでは、それらはワークスペースレベルで設定されており、ユーザーレベルではありません。
## 新しい機能フラグの追加
`FeatureFlagKey.ts`に機能フラグを追加します:
```ts
type FeatureFlagKey =
| 'IS_FEATURENAME_ENABLED'
| ...;
```
また、`feature-flag.entity.ts`の列挙型にも追加します:
```ts
enum FeatureFlagKeys {
IsFeatureNameEnabled = 'IS_FEATURENAME_ENABLED',
...
}
```
**バックエンド**機能に機能フラグを適用するには、次を使用します:
```ts
@Gate({
featureFlag: 'IS_FEATURENAME_ENABLED',
})
```
**フロントエンド**機能に機能フラグを適用するには、次を使用します:
```ts
const isFeatureNameEnabled = useIsFeatureEnabled('IS_FEATURENAME_ENABLED');
```
## デプロイメント用の機能フラグを設定する
Table `core.featureFlag` 内の対応するレコードを変更します:
| id | キー | workspaceId | 値 |
| ---- | ------------------------ | ----------- | --- |
| ランダム | `IS_FEATURENAME_ENABLED` | WorkspaceID | `真` |

View File

@@ -0,0 +1,125 @@
---
title: フォルダ構成
info: 当社のサーバーフォルダ構造の詳細な観察
---
バックエンドのディレクトリ構造は以下の通りです:
```
server
└───ability
└───constants
└───core
└───database
└───decorators
└───filters
└───guards
└───health
└───integrations
└───metadata
└───workspace
└───utils
```
## 能力
各エンティティの権限を定義し、ハンドラーを含みます。
## デコレータ
NestJS で機能を拡張するためのカスタムデコレーターを定義します。
詳細については、[カスタムデコレータ](https://docs.nestjs.com/custom-decorators) を参照してください。
## フィルター
GraphQLエンドポイントで発生する可能性のある例外を処理するための例外フィルターを含みます。
## ガード
詳細については、[ガード](https://docs.nestjs.com/guards) を参照してください。
## ヘルス
データベースが期待通りに動作しているかを確認するためのJSONを返す公開されたREST API (healthz) を含みます。
## メタデータ
カスタムオブジェクトを定義し、GraphQL API (graphql/metadata) を利用可能にします。
## ワークスペース
メタデータに基づいてカスタムGraphQLスキーマを生成し、提供します。
### ワークスペースディレクトリ構造
```
workspace
└───workspace-schema-builder
└───factories
└───graphql-types
└───database
└───interfaces
└───object-definitions
└───services
└───storage
└───utils
└───workspace-resolver-builder
└───factories
└───interfaces
└───workspace-query-builder
└───factories
└───interfaces
└───workspace-query-runner
└───interfaces
└───utils
└───workspace-datasource
└───workspace-manager
└───workspace-migration-runner
└───utils
└───workspace.module.ts
└───workspace.factory.spec.ts
└───workspace.factory.ts
```
ワークスペースディレクトリのルートには、`workspace.factory.ts` が含まれ、`createGraphQLSchema` 関数が含まれています。 この関数は、メタデータを使用して、個々のワークスペース用のスキーマを調整し、ワークスペース固有のスキーマを生成します。 スキーマとリゾルバーの構築を分離することで、`makeExecutableSchema` 関数を使用し、これらの個別要素を組み合わせます。 この関数は、メタデータを使用して、個々のワークスペース用のスキーマを調整し、ワークスペース固有のスキーマを生成します。 スキーマとリゾルバーの構築を分離することで、`makeExecutableSchema` 関数を使用し、これらの個別要素を組み合わせます。 この関数は、メタデータを使用して、個々のワークスペース用のスキーマを調整し、ワークスペース固有のスキーマを生成します。 スキーマとリゾルバーの構築を分離することで、`makeExecutableSchema` 関数を使用し、これらの個別要素を組み合わせます。
この戦略は、組織化だけでなく、パフォーマンスやスケーラビリティを向上させるための型定義のキャッシングのような最適化にも役立ちます。
### ワークスペーススキーマビルダー
GraphQLスキーマを生成し、含まれるもの:
#### ファクトリー:
GraphQL関連の構造を生成するための専門的なコンストラクター。
* type.factoryは、フィールドメタデータを`TypeMapperService`を使用してGraphQLタイプに変換します。
* type-definition.factoryは、`objectMetadata`から導出されるGraphQLの入力または出力オブジェクトを作成します。
#### GraphQLタイプ
列挙型、入力、オブジェクト、スカラーを含み、スキーマ構築の基礎となります。
#### インターフェースとオブジェクト定義
GraphQLエンティティの設計図を含み、`MONEY`や`URL`のような定義済みおよびカスタムタイプが含まれます。
#### サービス
FieldMetadataTypeに対応するGraphQLスカラーまたはクエリ修飾子を関連付けるためのサービスを含みます。
#### ストレージ
GraphQLタイプの重複を防ぐための再利用可能な型定義を含む`TypeDefinitionsStorage`クラスを含みます。
### ワークスペースリゾルバービルダー
GraphQLスキーマのクエリおよび変更を行うリゾルバー関数を作成します。
このディレクトリ内の各ファクトリーは、様々なテーブルに適用可能な`FindManyResolverFactory`のように、異なるリゾルバータイプを生成する役割を果たします。
### ワークスペースクエリランナー
データベースで生成されたクエリを実行し、その結果を解析します。

View File

@@ -0,0 +1,41 @@
---
title: メッセージキュー
---
キューは非同期処理を実行するための手段を提供します。 それらは、登録時にウェルカムメールを送信するなどのバックグラウンドタスクを実行するために使用できます。
各ユースケースには `MessageQueueServiceBase` から拡張された独自のキュークラスが必要です。
現在のところ、キュードライバとして `bull-mq`[bull-mq](https://bullmq.io/) のみをサポートしています。
## 新しいキューを作成して使用する手順
1. enum `MESSAGE_QUEUES` に、新しいキュー用のキュー名を追加します。
2. 依存トークンとしてキュー名を持つキューのファクトリ実装を提供します。
3. 依存性トークンとしてキュー名を使用して、作成したキューを必要なモジュール/サービスにインジェクトします。
4. トークンベースのインジェクションを用いたワーカークラスをプロデューサーと同様に追加します。
### 使用例
```ts
class Resolver {
constructor(@Inject(MESSAGE_QUEUES.custom) private queue: MessageQueueService) {}
async onSomeAction() {
//business logic
await this.queue.add(someData);
}
}
//async worker
class CustomWorker {
constructor(@Inject(MESSAGE_QUEUES.custom) private queue: MessageQueueService) {
this.initWorker();
}
async initWorker() {
await this.queue.work(async ({ id, data }) => {
//worker logic
});
}
}
```

View File

@@ -0,0 +1,92 @@
---
title: バックエンドコマンド
icon: terminal
---
## 便利なコマンド
これらのコマンドは packages/twenty-server フォルダから実行してください。
これらのコマンドは packages/twenty-server フォルダから実行してください。
これらのコマンドは packages/twenty-server フォルダから実行してください。
これらのコマンドは packages/twenty-server フォルダから実行してください。
これらのコマンドは packages/twenty-server フォルダから実行してください。
これらのコマンドは packages/twenty-server フォルダから実行してください。
From any other folder you can run `npx nx {command} twenty-server` (or `npx nx run twenty-server:{command}`).
### 初期設定
```
npx nx database:reset twenty-server # setup the database with dev seeds
```
### サーバーの起動
```
npx nx run twenty-server:start
```
### Lint
```
npx nx run twenty-server:lint # pass --fix to fix lint errors
```
### テスト
```
npx nx run twenty-server:test:unit # run unit tests
npx nx run twenty-server:test:integration # run integration tests
```
注: 統合テストを実行する前にデータベースをリセットする必要がある場合、 `npx nx run twenty-server:test:integration:with-db-reset` を実行できます。
### データベースのリセット
データベースをリセットおよびシードしたい場合は、次のコマンドを実行してください:
```bash
npx nx run twenty-server:database:reset
```
### マイグレーション
#### Core/Metadata スキーマ (TypeORM) のオブジェクトに対して
```bash
npx nx run twenty-server:database:migrate:generate
```
## 技術スタック
Twenty は主にバックエンドに NestJS を使用しています。
最初に使用した ORM は Prisma でした。 最初に使用した ORM は Prisma でした。 But in order to allow users to create custom fields and custom objects, a lower-level made more sense as we need to have fine-grained control. 最初に使用した ORM は Prisma でした。 But in order to allow users to create custom fields and custom objects, a lower-level made more sense as we need to have fine-grained control. 現在のプロジェクトでは TypeORM を使用しています。
現在の技術スタックは次のようになっています。
**コア**
* [NestJS](https://nestjs.com/)
* [TypeORM](https://typeorm.io/)
* [GraphQL Yoga](https://the-guild.dev/graphql/yoga-server)
**データベース**
* [Postgres](https://www.postgresql.org/)
**サードパーティ統合**
* [Sentry](https://sentry.io/welcome/) バグトラッキング用
**テスト**
* [Jest](https://jestjs.io/)
**ツール**
* [Yarn](https://yarnpkg.com/)
* [Oxlint](https://oxc.rs/docs/guide/usage/linter.html)
**開発**
* [AWS EKS](https://aws.amazon.com/eks/)

View File

@@ -0,0 +1,85 @@
---
title: Zapierアプリ
---
[Zapier](https://zapier.com/) を使って、3000以上のアプリと Twenty を簡単に同期できます。 タスクを自動化し、生産性を高め、顧客関係を強化しよう!
## Zapierについて
Zapierは、チームが毎日使用するアプリを連携させてワークフローを自動化するツールです。 Zapierの基本的な概念は、Zapsと呼ばれる自動化ワークフローであり、トリガーとアクションを含みます。 Zapierは、チームが毎日使用するアプリを連携させてワークフローを自動化するツールです。 Zapierの基本的な概念は、Zapsと呼ばれる自動化ワークフローであり、トリガーとアクションを含みます。 Zapierの基本的な概念は、Zapsと呼ばれる自動化ワークフローであり、トリガーとアクションを含みます。
Zapierの仕組みについてもっと知りたい方は[こちら](https://zapier.com/how-it-works)をご覧ください。
## セットアップ
### ステップ 1: Zapier パッケージをインストール
```bash
cd packages/twenty-zapier
yarn
```
### ステップ 2: CLI でログイン
Zapierの資格情報を使用してCLIでログインしてください。
```bash
zapier login
```
### ステップ3:環境変数をセットアップします
`packages/twenty-zapier`フォルダーから実行します。
```bash
cp .env.example .env
```
アプリケーションをローカルで実行し、[http://localhost:3000/settings/api-webhooks](http://localhost:3000/settings/api-webhooks)にアクセスしてAPIキーを生成してください。
.envファイルの**YOUR_API_KEY**値を生成したAPIキーで置き換えてください。
## 開発
<Warning>
`zapier`コマンドを実行する前に`yarn build`を実行してください。
</Warning>
### テスト
```bash
yarn test
```
### Lint
```bash
yarn format
```
### コードを編集しながら監視&コンパイル
```bash
yarn watch
```
### Zapierアプリを検証
```bash
yarn validate
```
### Zapierアプリをデプロイ
```bash
yarn deploy
```
### すべてのZapier CLIコマンドを列挙
```bash
zapier
```

View File

@@ -0,0 +1,79 @@
---
title: バグ報告、要望、プルリクエスト
icon: bug
info: Issue を報告し、機能を要望し、コードで貢献する
---
## バグの報告
バグを報告するには、[GitHubで問題を作成](https://github.com/twentyhq/twenty/issues/new)してください。
[Discord](https://discord.gg/cx5n4Jzs57)でヘルプを求めることもできます。
## 機能リクエスト
バグかどうか不明で、機能リクエストに近いと感じる場合は、代わりに[ディスカッションを開く](https://github.com/twentyhq/twenty/discussions/new)べきです。
## プルリクエストを提出する
Twentyへのコード貢献は、プルリクエスト(PR)から始まります。
### 始める前に
1. 関連する作業がないか[既存の Issue](https://github.com/twentyhq/twenty/issues)を確認してください
2. 新機能については、まず Issue を作成して議論してください
3. プロジェクトの[行動規範](https://github.com/twentyhq/twenty/blob/main/.github/CODE_OF_CONDUCT.md)を確認してください
### フォークとクローン
1. GitHubでリポジトリをフォークする
2. フォークをクローンする:
```bash
git clone https://github.com/YOUR_USERNAME/twenty.git
cd twenty
```
3. upstream リモートを追加する:
```bash
git remote add upstream https://github.com/twentyhq/twenty.git
```
### ブランチを作成する
```bash
git checkout -b feature/your-feature-name
```
説明的なブランチ名を使用する:
* `feature/add-export-button`
* `fix/login-redirect-issue`
* `docs/update-api-guide`
### 変更を加える
1. クリーンで適切にドキュメント化されたコードを書く
2. 既存のコードスタイルに従う
3. 新しい機能にはテストを追加する
4. 必要に応じてドキュメントを更新する
### プルリクエストを提出する
1. ブランチをプッシュする:
```bash
git push origin feature/your-feature-name
```
2. GitHubでプルリクエストを作成する
3. PR テンプレートに記入する
4. 関連する Issue をリンクする
### PR チェックリスト
* [ ] コードがプロジェクトのスタイルガイドに準拠している
* [ ] ローカルでテストが通っている
* [ ] ドキュメントが更新されている
* [ ] PR の説明に変更内容が記載されている

View File

@@ -0,0 +1,329 @@
---
title: ベストプラクティス',
icon: star
---
このドキュメントでは、フロントエンド作業におけるベストプラクティスを概要化しています。
## 状態管理
React と Jotai はコードベース内の状態管理を行います。
### Jotai の atom を使用して状態を保存する
状態を保存するために必要なだけ多くのアトムを作成するのがよいです。
<Warning>
プロップドリリングを必要以上に控えるより、追加のアトムを使用する方が良いです。
</Warning>
```tsx
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
export const myAtomState = createAtomState<string>({
key: 'myAtomState',
defaultValue: 'default value',
});
export const MyComponent = () => {
const [myAtom, setMyAtom] = useAtomState(myAtomState);
return (
<div>
<input
value={myAtom}
onChange={(e) => setMyAtom(e.target.value)}
/>
</div>
);
}
```
### 状態を保存するために `useRef` を使用しないでください
状態の保存に `useRef` を使用するのは避けてください。
状態を保存したい場合は、`useState` または `useAtomState` を用いた Jotai の atom を使用してください。
いくつかの再レンダリングを防ぐために `useRef` が必要だと感じた場合は、[再レンダリングの管理方法](#managing-re-renders)を参照してください。
## 再レンダリングの管理
React で再レンダリングを管理するのは難しいことがあります。
不必要な再レンダリングを避けるためのいくつかのルールをご紹介します。
再レンダリングの原因を理解することで、常に再レンダリングを避けることができることを念頭に置いてください。
### ルートレベルで作業する
新機能での再レンダリングをルートレベルで排除することで、簡単に避けることができるようになりました。
`PageChangeEffect` サイドカーコンポーネントには、ページ変更時に実行するすべてのロジックを保持する `useEffect` が1つだけ含まれています。
その方法で、再レンダリングを引き起こす場所が 1 つだけあることを認識できます。
### コードベースに `useEffect` を追加する前に、常に考えてください。
再レンダリングは、しばしば不要な `useEffect` によって引き起こされます。
`useEffect` が必要か、イベントハンドラ関数でロジックを動かせるか考えるべきです。
「handleClick」関数や「handleChange」関数の中で、ロジックを簡単に動かすことができます。
Apollo などのライブラリで `onCompleted`、`onError` などとしても見つかることがあります。
### 兄弟コンポーネントを使用して、`useEffect` またはデータ取得ロジックを抽出します。
ルートコンポーネントに `useEffect` を追加する必要があると思われる場合は、サイドカーコンポーネント内で展開することを検討する必要があります。
Apollo フックを使用してデータ取得ロジックにも同じことを適用できます。
```tsx
// ❌ Bad, will cause re-renders even if data is not changing,
// because useEffect needs to be re-evaluated
export const PageComponent = () => {
const [data, setData] = useAtomState(dataState);
const [someDependency] = useAtomState(someDependencyState);
useEffect(() => {
if(someDependency !== data) {
setData(someDependency);
}
}, [someDependency]);
return <div>{data}</div>;
};
export const App = () => (
<PageComponent />
);
```
```tsx
// ✅ Good, will not cause re-renders if data is not changing,
// because useEffect is re-evaluated in another sibling component
export const PageComponent = () => {
const [data, setData] = useAtomState(dataState);
return <div>{data}</div>;
};
export const PageData = () => {
const [data, setData] = useAtomState(dataState);
const [someDependency] = useAtomState(someDependencyState);
useEffect(() => {
if(someDependency !== data) {
setData(someDependency);
}
}, [someDependency]);
return <></>;
};
export const App = () => (
<>
<PageData />
<PageComponent />
</>
);
```
### atom ファミリー状態とセレクターを使用する
atom ファミリー状態とセレクターは、再レンダリングを回避するための優れた方法です。
アイテムのリストを保存する必要があるときに有用です。
### `React.memo(MyComponent)` を使用してはいけません
`React.memo()` の使用を避けてください。それは再レンダリングの原因を解決するのではなく、再レンダリングの連鎖を破り、予期しない動作を引き起こす可能性があり、コードのリファクタリングが非常に困難になります。
### `useCallback` または `useMemo` の使用を制限する
それらは通常必要ではなく、気付かない程度のパフォーマンス向上のためにコードの可読性と保守性を低下させます。
## コンソールログ
`console.log` は開発中において、変数の値やコードの流れについてリアルタイムの洞察を提供するために有効です。 しかし、これをプロダクションコードに残すと、いくつかの問題を引き起こす可能性があります。 しかし、これをプロダクションコードに残すと、いくつかの問題を引き起こす可能性があります。
1. **パフォーマンス**: 過剰なログはクライアントサイドアプリケーションのランタイムパフォーマンスに影響を与える可能性があります。
2. **セキュリティ**: センシティブなデータをログに記録すると、ブラウザのコンソールを確認するだけで重要な情報が露見する恐れがあります。
3. **清潔性**: コンソールにログが溢れると、開発者やツールが見るべき重要な警告やエラーが不明瞭になる可能性があります。
4. **プロフェッショナリズム**: エンドユーザーやクライアントがコンソールを確認したときに、多くのログが表示されると、そのコードの品質や仕上がりを疑問視されることがあります。
`console.logs` はすべて削除してからコードをプロダクションにプッシュしてください。
## 命名について
### 変数の命名
変数名は、その変数の目的や機能を正確に描写する必要があります。
#### 汎用的な名前の問題
プログラミングにおいて汎用的な名前は理想的ではありません。なぜなら、それらは特異性に欠け、曖昧さをもたらし、コードの可読性を低下させるからです。 そのような名前は変数や関数の目的を伝えず、開発者がコードの意図を深く探らない限り理解を困難にします。 これにより、デバッグ時間が増加し、エラーの発生率が高まり、メンテナンスやコラボレーションが難しくなります。 一方で、説明的な命名はコードを自己説明的にし、ナビゲートしやすくし、コードの品質と開発者の生産性を向上させます。
```tsx
// ❌ Bad, uses a generic name that doesn't communicate its
// purpose or content clearly
const [value, setValue] = useState('');
```
```tsx
// ✅ Good, uses a descriptive name
const [email, setEmail] = useState('');
```
#### 変数名で避けるべき言葉のいくつか
* ダミー
### イベントハンドラー
イベントハンドラの名前は `handle` で始めるべきであり、`on` はコンポーネントのプロップ内のイベントを命名するためのプレフィックスとして使用されます。
```tsx
// ❌ Bad
const onEmailChange = (val: string) => {
// ...
};
```
```tsx
// ✅ Good
const handleEmailChange = (val: string) => {
// ...
};
```
## オプショナルプロップ
オプショナルプロップにデフォルト値を渡すことは避けてください。
**例**
以下に定義された `EmailField` コンポーネントを取る:
```tsx
type EmailFieldProps = {
value: string;
disabled?: boolean;
};
const EmailField = ({ value, disabled = false }: EmailFieldProps) => (
<TextInput value={value} disabled={disabled} fullWidth />
);
```
**使用方法**
```tsx
// ❌ Bad, passing in the same value as the default value adds no value
const Form = () => <EmailField value="username@email.com" disabled={false} />;
```
```tsx
// ✅ Good, assumes the default value
const Form = () => <EmailField value="username@email.com" />;
```
## プロップとしてのコンポーネント
可能な限り、未初期化のコンポーネントをプロップとして渡してください。子コンポーネントが必要なプロップを自分で決定できるようにします。
そのための最も一般的な例はアイコンコンポーネントです。
```tsx
const SomeParentComponent = () => <MyComponent Icon={MyIcon} />;
// In MyComponent
const MyComponent = ({ MyIcon }: { MyIcon: IconComponent }) => {
const theme = useTheme();
return (
<div>
<MyIcon size={theme.icon.size.md}>
</div>
)
};
```
Reactがコンポーネントを認識するためには、PascalCaseを使用し、その後に`<MyIcon>`でインスタンス化する必要があります。
## プロップのドリリングを最小限に抑える
Reactのコンテキストでのプロップドリリングとは、多くのコンポーネントレイヤーを通じて状態変数やそのセットを渡すことを意味します。中間のコンポーネントがそれを使用していない場合であってもです。 時には必要ですが、過度のプロップドリリングは次の結果を導きかねません。 時には必要ですが、過度のプロップドリリングは次の結果を導きかねません。 時には必要ですが、過度のプロップドリリングは次の結果を導きかねません。
1. **可読性の低下**:プロップがどこから始まり、どこで使われているかを追跡するのが、深くネストされたコンポーネント構造では複雑になり得ます。
2. **メンテナンスの難しさ**:あるコンポーネントのプロップ構造に変更があると、他のコンポーネントに変更が必要になる場合があります。それが直接プロップを使用していなくても。
3. **コンポーネントの再利用性の低下**:多くのプロップを単に下位に渡すコンポーネントは、汎用性が低くなり、異なるコンテキストでの再利用が難しくなります。
もし過度のプロップドリリングをしていると感じた場合は、[状態管理のベストプラクティス](#state-management)を参照してください。
## インポート
インポート時は、完全なパスや相対パスを指定するのではなく、指定されたエイリアスを選択してください。
**ハンドルの別名**
```js
{
alias: {
"~": path.resolve(__dirname, "src"),
"@": path.resolve(__dirname, "src/modules"),
"@testing": path.resolve(__dirname, "src/testing"),
},
}
```
**使用方法**
```tsx
// ❌ Bad, specifies the entire relative path
import {
CatalogDecorator
} from '../../../../../testing/decorators/CatalogDecorator';
import {
ComponentDecorator
} from '../../../../../testing/decorators/ComponentDecorator';
```
```tsx
// ✅ Good, utilises the designated aliases
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from 'twenty-ui/testing';
```
## スキーマ検証
[Zod](https://github.com/colinhacks/zod)は型未定義オブジェクトのスキーマバリデーターです。
```js
const validationSchema = z
.object({
exist: z.boolean(),
email: z
.string()
.email('Email must be a valid email'),
password: z
.string()
.regex(PASSWORD_REGEX, 'Password must contain at least 8 characters'),
})
.required();
type Form = z.infer<typeof validationSchema>;
```
## 重大な変更
変更が他の部分に影響を及ぼしていないことを確実にするために、進む前に徹底的な手動テストを行ってください。テストがまだ広範囲に統合されていないためです。

View File

@@ -0,0 +1,110 @@
---
title: フォルダ構成
icon: folder-tree
info: 当社のフォルダ構造の詳細な解説
---
このガイドでは、プロジェクトのディレクトリ構成の詳細と、それが Twenty の整理と保守性にどのように寄与するかを解説します。
このフォルダ構成の規約に従うことで、特定の機能に関連するファイルを見つけやすくなり、アプリケーションのスケーラビリティと保守性を確保できます。
```
front
└───modules
│ └───module1
│ │ └───submodule1
│ └───module2
│ └───ui
│ │ └───display
│ │ └───inputs
│ │ │ └───buttons
│ │ └───...
└───pages
└───...
```
## ページ
アプリケーションのルートで定義されたトップレベルのコンポーネントを含みます。 それらは、modules フォルダからより低レベルのコンポーネントをインポートします(詳細は下記を参照)。
## モジュール
各モジュールは、単一の機能または機能のグループを表し、それぞれ固有のコンポーネント、状態、動作ロジックで構成されています。
以下の構造に従う必要があります。 モジュール内にモジュール(サブモジュール)をネストでき、同じルールが適用されます。
```
module1
└───components
│ └───component1
│ └───component2
└───constants
└───contexts
└───graphql
│ └───fragments
│ └───queries
│ └───mutations
└───hooks
│ └───internal
└───states
│ └───selectors
└───types
└───utils
```
### コンテキスト
コンテキストは、各レベルでプロップスを手動で渡すことなく、コンポーネントツリーを通じてデータを渡す方法です。
詳細は[Reactコンテキスト](https://react.dev/reference/react#context-hooks)を参照してください。
### GraphQL
フラグメント、クエリ、ミューテーションを含みます。
詳細は[GraphQL](https://graphql.org/learn/)を参照してください。
* フラグメント
フラグメントはクエリの再利用可能な一部分で、さまざまな箇所で使用できます。 フラグメントを使用することで、コードを重複させることを避けやすくなります。
詳細は[GraphQLフラグメント](https://graphql.org/learn/queries/#fragments)を参照してください。
* クエリ
詳細は[GraphQLクエリ](https://graphql.org/learn/queries/)を参照してください。
* ミューテーション
詳細は[GraphQLミューテーション](https://graphql.org/learn/queries/#mutations)を参照してください。
### フック
詳細は[フック](https://react.dev/learn/reusing-logic-with-custom-hooks)を参照してください。
### ステート
ステート管理のロジックを含みます。 [Jotai](https://jotai.org) がこれを管理します。
* セレクター: 派生アトム(`createAtomSelector` を使用)は、他のアトムから値を計算し、自動的にメモ化されます。
Reactの組み込みステート管理は依然としてコンポーネント内のステートを処理します。
### ユーティリティ
再利用可能な純粋関数のみを含むべきです。 それ以外の場合は、`hooks`フォルダにカスタムフックを作成します。
## UI
アプリケーションで使用される再利用可能なUIコンポーネントをすべて含みます。
このフォルダには、特定の種類のコンポーネント用に `data`、`display`、`feedback`、`input` といったサブフォルダを含めることができます。 各コンポーネントは自己完結型で再利用可能でなければならず、アプリケーションのさまざまな部分で使用できます。
UIコンポーネントを`modules`フォルダ内の他のコンポーネントから分離することで、一貫したデザインを維持し、UIの変更がコードベースの他の部分(ビジネスロジック)に影響を与えないようにするのが容易になります。
## インターフェースと依存関係
`ui` フォルダを除く任意のモジュールから、他のモジュールのコードをインポートできます。 これにより、そのコードは簡単にテストできます。
### 内部
各部分(フック、ステート、...) は、モジュール内でのみ使用される部分を含む `internal` フォルダを持つことができます。

View File

@@ -0,0 +1,91 @@
---
title: フロントエンドコマンド
icon: terminal
---
## 便利なコマンド
### アプリの開始
```bash
npx nx start twenty-front
```
### APIのGraphQLスキーマに基づいてGraphQLスキーマを再生成する
```bash
npx nx run twenty-front:graphql:generate --configuration=metadata
```
または
```bash
npx nx run twenty-front:graphql:generate
```
### リント
```bash
npx nx run twenty-front:lint # pass --fix to fix lint errors
```
## 翻訳
```bash
npx nx run twenty-front:lingui:extract
npx nx run twenty-front:lingui:compile
```
### テスト
```bash
npx nx run twenty-front:test # run jest tests
npx nx run twenty-front:storybook:serve:dev # run storybook
npx nx run twenty-front:storybook:test # run tests # (needs yarn storybook:serve:dev to be running)
npx nx run twenty-front:storybook:coverage # (needs yarn storybook:serve:dev to be running)
```
## 技術スタック
プロジェクトは、最小限のボイラープレートコードを持つシンプルでクリーンなスタックを持っています。
**アプリ**
* [React](https://react.dev/)
* [Apollo](https://www.apollographql.com/docs/)
* [GraphQL Codegen](https://the-guild.dev/graphql/codegen)
* [Jotai](https://jotai.org/)
* [TypeScript](https://www.typescriptlang.org/)
**テスト**
* [Jest](https://jestjs.io/)
* [Storybook](https://storybook.js.org/)
**ツール**
* [Yarn](https://yarnpkg.com/)
* [Craco](https://craco.js.org/docs/)
* [Oxlint](https://oxc.rs/docs/guide/usage/linter.html)
## アーキテクチャ
### ルーティング
[React Router](https://reactrouter.com/)はルーティングを処理します。
不要な [re-renders](/l/ja/developers/contribute/capabilities/frontend-development/best-practices-front#managing-re-renders) を避けるために、すべてのルーティングロジックは `PageChangeEffect` の `useEffect` にあります。
### 状態管理
[Jotai](https://jotai.org/)は状態管理を行います。
状態管理に関する詳細な情報は[ベストプラクティス](/l/ja/developers/contribute/capabilities/frontend-development/best-practices-front#state-management)を参照してください。
## テスト
[Jest](https://jestjs.io/)はユニットテストのツールであり、[Storybook](https://storybook.js.org/)はコンポーネントテスト用です。
Jestは主にユーティリティ関数のテスト用で、コンポーネントのテスト自体ではありません。
Storybookは、独立したコンポーネントの挙動をテストし、デザインシステムを表示するためのものです。

View File

@@ -0,0 +1,178 @@
---
title: ホットキー
---
## イントロダクション
ホットキーをリッスンする必要がある場合、通常は `onKeyDown` イベントリスナーを使用します。
しかし、`twenty-front` では、同時にマウントされている異なるコンポーネントで使用される同じホットキーの間で競合が生じることがあります。
例えば、Enterキーをリッスンするページと、Enterキーをリッスンするモーダル、さらにそのモーダル内のSelectコンポーネントもEnterキーをリッスンしている場合、全てが同時にマウントされると競合が生じる可能性があります。
## `useScopedHotkeys` フック
この問題を解決するために、どのような競合もなくホットキーをリッスンすることを可能にするカスタムフックがあります。
コンポーネント内に配置すると、コンポーネントがマウントされ、指定された**ホットキースコープ**がアクティブなときだけホットキーをリッスンします。
## 実際にホットキーをリッスンする方法は?
ホットキーをリッスンするための設定には2つのステップがあります:
1. ホットキーをリッスンする[ホットキースコープ](#what-is-a-hotkey-scope-)を設定します
2. ホットキーをリッスンするために `useScopedHotkeys` フックを使用します
他のUI要素(例:左側のメニューやコマンドメニュー)もホットキーをリッスンする可能性があるため、ホットキースコープの設定は単純なページでも必要です。
## ホットキーのユースケース
一般的に、ホットキーが必要となる動作は2つあります:
1. ページにマウントされたコンポーネントで
2. ユーザーのアクションでフォーカスをとるモーダルタイプのコンポーネントで
2番目のユースケースは再帰的に発生します:例えばモーダル内のドロップダウン。
### ページ内でホットキーをリッスン
例:
```tsx
const PageListeningEnter = () => {
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
// 1. Set the hotkey scope in a useEffect
useEffect(() => {
setHotkeyScopeAndMemorizePreviousScope(
ExampleHotkeyScopes.ExampleEnterPage,
);
// Revert to the previous hotkey scope when the component is unmounted
return () => {
goBackToPreviousHotkeyScope();
};
}, [goBackToPreviousHotkeyScope, setHotkeyScopeAndMemorizePreviousScope]);
// 2. Use the useScopedHotkeys hook
useScopedHotkeys(
Key.Enter,
() => {
// Some logic executed on this page when the user presses Enter
// ...
},
ExampleHotkeyScopes.ExampleEnterPage,
);
return <div>My page that listens for Enter</div>;
};
```
### モーダルタイプのコンポーネントでホットキーをリッスン
この例では、親にモーダルを閉じるように指示するためにEscapeキーをリッスンするモーダルコンポーネントを使用します。
ここで、ユーザーの操作がスコープを変更します。
```tsx
const ExamplePageWithModal = () => {
const [showModal, setShowModal] = useState(false);
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
const handleOpenModalClick = () => {
// 1. Set the hotkey scope when user opens the modal
setShowModal(true);
setHotkeyScopeAndMemorizePreviousScope(
ExampleHotkeyScopes.ExampleModal,
);
};
const handleModalClose = () => {
// 1. Revert to the previous hotkey scope when the modal is closed
setShowModal(false);
goBackToPreviousHotkeyScope();
};
return <div>
<h1>My page with a modal</h1>
<button onClick={handleOpenModalClick}>Open modal</button>
{showModal && <MyModalComponent onClose={handleModalClose} />}
</div>;
};
```
その後、モーダルコンポーネント内で:
```tsx
const MyDropdownComponent = ({ onClose }: { onClose: () => void }) => {
// 2. Use the useScopedHotkeys hook to listen for Escape.
// Note that escape is a common hotkey that could be used by many other components
// So it's important to use a hotkey scope to avoid conflicts
useScopedHotkeys(
Key.Escape,
() => {
onClose()
},
ExampleHotkeyScopes.ExampleModal,
);
return <div>My modal component</div>;
};
```
mount/unmount で useEffect を使うだけで、競合を避けるのに十分なことがわからない場合は、このパターンを使用することが重要です。
これらの競合はデバッグが難しく、useEffectsを使わないよりも頻繁に発生する可能性があります。
## ホットキースコープとは?
ホットキースコープは、ホットキーがアクティブなコンテキストを表す文字列です。 通常、enumとしてエンコードされます。 通常、enumとしてエンコードされます。 通常、enumとしてエンコードされます。
ホットキースコープを変更すると、このスコープをリッスンしているホットキーが有効になり、他のスコープをリッスンしているホットキーが無効になります。
一度に1つのスコープしか設定できません。
例として、各ページのホットキースコープは`PageHotkeyScope` enumで定義されています:
```tsx
export enum PageHotkeyScope {
Settings = 'settings',
CreateWorkspace = 'create-workspace',
SignInUp = 'sign-in-up',
CreateProfile = 'create-profile',
PlanRequired = 'plan-required',
ShowPage = 'show-page',
PersonShowPage = 'person-show-page',
CompanyShowPage = 'company-show-page',
CompaniesPage = 'companies-page',
PeoplePage = 'people-page',
OpportunitiesPage = 'opportunities-page',
ProfilePage = 'profile-page',
WorkspaceMemberPage = 'workspace-member-page',
TaskPage = 'task-page',
}
```
内部的には、現在選択されているスコープはアプリケーション全体で共有されるJotai atomに格納されています:
```tsx
export const currentHotkeyScopeState = createState<HotkeyScope>({
key: 'currentHotkeyScopeState',
defaultValue: INITIAL_HOTKEYS_SCOPE,
});
```
しかし、このatomは手動で扱ってはいけません! 次のセクションでその使用方法を見ていきます。
## 内部的にはどう機能しているのか?
[react-hotkeys-hook](https://react-hotkeys-hook.vercel.app/docs/intro)の上に薄いラッパーを作成し、より効率的にし、不必要な再レンダリングを避けます。
また、ホットキーのスコープの状態を処理し、アプリケーション全体で利用できるようにするためのJotai atomも作成します。

View File

@@ -0,0 +1,8 @@
---
title: ストーリーブック
description: TwentyのUIコンポーネントライブラリを閲覧
---
ストーリーブックで私たちの完全なコンポーネントライブラリおよびドキュメントを参照してください。
[ストーリーブックを開く →](https://storybook.twenty.com)

View File

@@ -0,0 +1,291 @@
---
title: スタイルガイド
icon: paintbrush
---
このドキュメントには、コードを書く際に従うべきルールが含まれています。
ここでの目標は、一貫性があり、読みやすく、メンテナンスしやすいコードベースにすることです。
そのためには、簡潔すぎるよりも少し冗長な方が良いです。
常に念頭に置いておくべきなのは、コードは書くよりも読む機会の方が多いということです。特に、誰でも貢献できるオープンソースプロジェクトでは、その傾向が強くなります。
ここでは定義されていない、多くの規則がありますが、リンターにより自動的にチェックされます。
## React
### 関数コンポーネントを使用する
常にTSXの関数コンポーネントを使用してください。
`const`を使ったデフォルトの`import`は避けてください。読むことや、コード補完でのインポートが難しくなるからです。
```tsx
// ❌ Bad, harder to read, harder to import with code completion
const MyComponent = () => {
return <div>Hello World</div>;
};
export default MyComponent;
// ✅ Good, easy to read, easy to import with code completion
export function MyComponent() {
return <div>Hello World</div>;
};
```
### プロパティ
プロップスの型を作成し、エクスポートの必要がない場合にはそれを`(ComponentName)Props`と呼んでください。
プロップスの分割代入を使用する。
```tsx
// ❌ Bad, no type
export const MyComponent = (props) => <div>Hello {props.name}</div>;
// ✅ Good, type
type MyComponentProps = {
name: string;
};
export const MyComponent = ({ name }: MyComponentProps) => <div>Hello {name}</div>;
```
#### プロップス型の定義に`React.FC`または`React.FunctionComponent`を使用しない
```tsx
/* ❌ - Bad, defines the component type annotations with `FC`
* - With `React.FC`, the component implicitly accepts a `children` prop
* even if it's not defined in the prop type. This might not always be
* desirable, especially if the component doesn't intend to render
* children.
*/
const EmailField: React.FC<{
value: string;
}> = ({ value }) => <TextInput value={value} disabled fullWidth />;
```
```tsx
/* ✅ - Good, a separate type (OwnProps) is explicitly defined for the
* component's props
* - This method doesn't automatically include the children prop. If
* you want to include it, you have to specify it in OwnProps.
*/
type EmailFieldProps = {
value: string;
};
const EmailField = ({ value }: EmailFieldProps) => (
<TextInput value={value} disabled fullWidth />
);
```
#### JSX要素内で単一の変数プロップスプレーディングを使用しない
`{...props}`のようにJSX要素内で単一の変数プロップスプレーディングを避けてください。 この方法は、コンポーネントが受け取るプロップスを不明確にするため、コードの可読性が低下し、メンテナンスが困難になります。 この方法は、コンポーネントが受け取るプロップスを不明確にするため、コードの可読性が低下し、メンテナンスが困難になります。 この方法は、コンポーネントが受け取るプロップスを不明確にするため、コードの可読性が低下し、メンテナンスが困難になります。
```tsx
/* ❌ - Bad, spreads a single variable prop into the underlying component
*/
const MyComponent = (props: OwnProps) => {
return <OtherComponent {...props} />;
}
```
```tsx
/* ✅ - Good, Explicitly lists all props
* - Enhances readability and maintainability
*/
const MyComponent = ({ prop1, prop2, prop3 }: MyComponentProps) => {
return <OtherComponent {...{ prop1, prop2, prop3 }} />;
};
```
根拠:
* ひと目で、コードがどのプロップスを渡しているかが明確になり、理解とメンテナンスが容易になります。
* これにより、コンポーネント間のプロップスによる密結合を防ぐのに役立ちます。
* プロップスを明示的にリストすれば、lintingツールが綴り間違いや未使用のプロップスを特定しやすくなります。
## JavaScript
### `??`(ヌリッシュ合体演算子)を使う
```tsx
// ❌ Bad, can return 'default' even if value is 0 or ''
const value = process.env.MY_VALUE || 'default';
// ✅ Good, will return 'default' only if value is null or undefined
const value = process.env.MY_VALUE ?? 'default';
```
### `?.`(オプショナルチェイニング)を使う
```tsx
// ❌ Bad
onClick && onClick();
// ✅ Good
onClick?.();
```
## TypeScript
### `type`を使い、常に`interface`の代わりにする
`type`は多くの場合、`interface`と重複し、`type`の方が柔軟性が高いため、常に`type`を使用してください。
```tsx
// ❌ Bad
interface MyInterface {
name: string;
}
// ✅ Good
type MyType = {
name: string;
};
```
### 列挙型の代わりに文字列リテラルを使う
[文字列リテラル](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) は、TypeScriptで列挙型のような値を扱うための推奨方法です。 それらはPickやOmitで拡張するのが簡単で、特にコード補完を伴う開発者の体験を向上させます。 それらはPickやOmitで拡張するのが簡単で、特にコード補完を伴う開発者の体験を向上させます。 Pick や Omit で拡張しやすく、特にコード補完の面で、より良い開発者体験を提供します。
なぜTypeScriptが列挙型を避けることを推奨しているかは[ここ](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#enums)をご覧ください。
```tsx
// ❌ Bad, utilizes an enum
enum Color {
Red = "red",
Green = "green",
Blue = "blue",
}
let color = Color.Red;
```
```tsx
// ✅ Good, utilizes a string literal
let color: "red" | "green" | "blue" = "red";
```
#### GraphQLと内部ライブラリ
GraphQLのcodegenが生成する列挙型を使用する必要があります。
内部ライブラリを使用する際にも列挙型を使用する方が良いので、内部ライブラリが内部APIに関連しない文字列リテラル型を公開する必要がなくなります。
例:
```TSX
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
setHotkeyScopeAndMemorizePreviousScope(
RelationPickerHotkeyScope.RelationPicker,
);
```
## スタイリング
### StyledComponentsを使用する
コンポーネントを[Linaria styled](https://github.com/callstack/linaria)でスタイル設定する。
```tsx
// ❌ Bad
<div className="my-class">Hello World</div>
```
```tsx
// ✅ Good
const StyledTitle = styled.div`
color: red;
`;
```
スタイル付きコンポーネントを"Styled"で接頭辞にして、"本物の"コンポーネントと区別する。
```tsx
// ❌ Bad
const Title = styled.div`
color: red;
`;
```
```tsx
// ✅ Good
const StyledTitle = styled.div`
color: red;
`;
```
### テーマ
大部分のコンポーネントのスタイルをテーマに基づかせるのが推奨される手法です。
#### 測定の単位
Styledコンポーネント内で`px`または`rem`値を直接使用しない 必要な値は一般的にテーマに既に定義されているため、これらの目的でテーマを利用することが推奨されます。 必要な値は一般的にテーマに既に定義されているため、これらの目的でテーマを利用することが推奨されます。 必要な値は一般的にテーマに既に定義されているため、これらの目的でテーマを利用することが推奨されます。
#### カラー
新しい色を追加するのではなく、テーマから既存のパレットを使用してください。 パレットが適合しない場合には、コメントを残してチームがそれを修正できるようにしてください。 パレットが適合しない場合には、コメントを残してチームがそれを修正できるようにしてください。 パレットが適合しない場合には、コメントを残してチームがそれを修正できるようにしてください。
```tsx
// ❌ Bad, directly specifies style values without utilizing the theme
const StyledButton = styled.button`
color: #333333;
font-size: 1rem;
font-weight: 400;
margin-left: 4px;
border-radius: 50px;
`;
```
```tsx
// ✅ Good, utilizes the theme
const StyledButton = styled.button`
color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.regular};
margin-left: ${({ theme }) => theme.spacing(1)};
border-radius: ${({ theme }) => theme.border.rounded};
`;
```
## タイプ無しのインポートの強制
タイプインポートを避けてください。 この標準を強制するために、Oxlint のルールがあらゆる型インポートをチェックして報告します。 これにより、TypeScriptコードの一貫性と可読性が維持されます。
```tsx
// ❌ Bad
import { type Meta, type StoryObj } from '@storybook/react';
// ❌ Bad
import type { Meta, StoryObj } from '@storybook/react';
// ✅ Good
import { Meta, StoryObj } from '@storybook/react';
```
### なぜタイプなしインポートなのか
* **一貫性**: 型インポートを避け、型と値の両方に単一のアプローチを使用することで、モジュールインポートスタイルの一貫性が保たれます。
* **可読性**: 型専用インポートは、値をインポートしているのか型をインポートしているのかを明確にすることで、コードの可読性を高めます。 これにより曖昧さが減り、インポートされたシンボルの目的を理解しやすくなります。
* **維持性**: コードベースの維持性を向上させます。開発者がコードを確認/変更する際に、タイプのみのインポートを特定して見つけることができるからです。
### Oxlintルール
Oxlint のルール `typescript/consistent-type-imports` は、型インポート禁止の標準を強制します。 このルールは、タイプインポート違反のエラーや警告を生成します。
このルールは、意図せず型をインポートしてしまう稀なエッジケースに特化して対処することに留意してください。 TypeScript自体、[TypeScript 3.8 リリースノート](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html)でこのプラクティスを避けています。 ほとんどの状況で、タイプのみのインポートを使用する必要はありません。 ほとんどの状況で、タイプのみのインポートを使用する必要はありません。 ほとんどの状況で、タイプのみのインポートを使用する必要はありません。
コードがこのルールに準拠していることを確実にするため、開発ワークフローの一環として Oxlint を実行してください。

View File

@@ -0,0 +1,138 @@
---
title: Figma で作業する
info: Twenty の Figma を使用した共同作業方法を学ぶ
---
Figma は、デザイナーと開発者の間のコミュニケーションの壁を埋めるのを助ける協働インターフェース設計ツールです。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
このガイドは、Figma を使って共同作業する方法を説明します。
## アクセス
1. **共有リンクにアクセスする:** プロジェクトの Figma ファイルは [ここ](https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty) からアクセスできます。
2. **サインイン:** まだサインインしていない場合、Figma はサインインを促します。
開発者モードや専用のフレーム選択など、キー機能はサインインしたユーザーのみが利用できます。
<Warning>
アカウントがないと効果的に協力することはできません。
</Warning>
## Figma 構造
左側のサイドバーで、Twenty の Figma の異なるページにアクセスできます。 それらは次のように整理されています: それらは次のように整理されています: それらは次のように整理されています: それらは次のように整理されています: それらは次のように整理されています:
* **コンポーネントページ:** これは最初のページです。 デザイナーはこれを使用して、デザインファイル全体で使用される再利用可能なデザイン要素を作成および整理します。 例えば、ボタン、アイコン、シンボル、またはその他の再利用可能なコンポーネントとして使用されます。 これにより、デザイン全体で一貫性を保つことができます。
* **メインページ:** 2 番目のページはメインページで、プロジェクトの完全なユーザーインターフェースを示しています。 ***再生*** を押すことで、アプリプロトタイプを完全に使用できます。 **メインページ:** 2 番目のページはメインページで、プロジェクトの完全なユーザーインターフェースを示しています。 ***再生*** を押すことで、アプリプロトタイプを完全に使用できます。 ***再生*** を押すことで、アプリプロトタイプを完全に使用できます。
* **特徴ページ:** その他のページは、通常、進行中の機能に専念しています。 それらはアプリケーションまたはウェブサイトの特定の機能またはモジュールのデザインを含みます。 通常、まだ進行中です。 それらはアプリケーションまたはウェブサイトの特定の機能またはモジュールのデザインを含みます。 通常、まだ進行中です。 それらはアプリケーションまたはウェブサイトの特定の機能またはモジュールのデザインを含みます。 通常、まだ進行中です。 それらはアプリケーションまたはウェブサイトの特定の機能またはモジュールのデザインを含みます。 通常、まだ進行中です。
## 役立つヒント
閲覧専用アクセスでは、デザインの編集はできませんが、デザインをコードに変換する際に役立つすべての機能にアクセスできます。
### 開発者モードを使用する
Figma の Dev モードは、デザインナビゲーションの容易化、効果的なアセット管理、効率的な通信ツール、ツールボックス統合、迅速なコードスニペット、主要レイヤー情報の提供により、開発者の生産性を向上させ、デザインと開発の間のギャップを埋めます。 Dev Mode についての詳細は [こちら](https://www.figma.com/dev-mode/) で確認できます。
ツールバーの右部分で「開発者」モードに切り替えることで、デザインスペックの確認、CSS のコピー、アセットへのアクセスが可能です。
### プロトタイプを使用する
キャンバス上の任意の要素をクリックし、インターフェースの右上隅にある「再生」ボタンを押してプロトタイプビューにアクセスします。 プロトタイプモードでは、あたかも最終製品であるかのようにデザインに触れることができます。 画面間のフローや、ボタン、リンク、メニューなどのインターフェース要素が操作時にどのように動作するかを示します。
1. **トランジションとアニメーションの理解:** プロトタイプモードでは、デザイナーによって画面や UI 要素間に追加されたトランジションやアニメーションを表示でき、開発者に意図された動作やスタイルを視覚的に明確に指示します。
2. **実装の明確化:** プロトタイプは曖昧さを減らすのにも役立ちます。 開発者はそれを操作することで、特定の要素の機能や外観をより良く理解することができます。
Figma プラットフォームの学習に関するより包括的な詳細とガイダンスについては、公式の [Figma ドキュメント](https://help.figma.com/hc/en-us) を訪れることができます。
### 距離を測定する
要素を選択し、`Option` キー(Mac)または `Alt` キー(Windows)を押したまま、別の要素の上にカーソルを合わせると、それらの間の距離が表示されます。
### VSCode 用 Figma 拡張機能(推奨)
[Figma for VS Code](https://marketplace.visualstudio.com/items?itemName=figma.figma-vscode-extension) を使用すると、デザインファイルのナビゲート、検査、デザイナーとのコラボレーション、変更の追跡、実装の促進ができます - すべてをテキストエディターから離れることなく行えます。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
これは推奨拡張機能の一部です。
## コラボレーション
1. **コメントの使用:** ツールバーの左側にあるバブルアイコンをクリックしてコメント機能を使用できます。
2. **カーソルチャット:** Figma の魅力的な機能のひとつにカーソルチャットがあります。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 **カーソルチャット:** Figma の魅力的な機能のひとつにカーソルチャットがあります。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 **カーソルチャット:** Figma の魅力的な機能のひとつにカーソルチャットがあります。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 **カーソルチャット:** Figma の魅力的な機能のひとつにカーソルチャットがあります。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 **カーソルチャット:** Figma の魅力的な機能のひとつにカーソルチャットがあります。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 **カーソルチャット:** Figma の魅力的な機能のひとつにカーソルチャットがあります。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 **カーソルチャット:** Figma の魅力的な機能のひとつにカーソルチャットがあります。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。 他の Figma を同時に使用している誰かを見た場合、`/` キー(Windows)または `;` キー(Mac)を押してメッセージを送信します。

View File

@@ -0,0 +1,324 @@
---
title: ローカルセットアップ
icon: laptop-code
description: 寄稿者(または好奇心旺盛な開発者)のためのガイドで、ローカルにTwentyを実行したい人向けです。
---
## 前提条件
<Tabs>
<Tab title="LinuxとmacOS">
Twentyをインストールして使用する前に、以下をコンピュータにインストールしてください。
* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [Node v24.5.0](https://nodejs.org/en/download)
* [yarn v4](https://yarnpkg.com/getting-started/install)
* [nvm](https://github.com/nvm-sh/nvm/blob/master/README.md)
<Warning>
`npm`は使えません。代わりに`yarn`を使用してください。
`npm`は使えません。代わりに`yarn`を使用してください。 Yarnは今Node.jsに同梱されているので、別途インストールする必要はありません。
Yarnを有効にするには、まだしていない場合は`corepack enable`を実行するだけです。
`npm`は使えません。代わりに`yarn`を使用してください。 Yarnは今Node.jsに同梱されているので、別途インストールする必要はありません。
Yarnを有効にするには、まだしていない場合は`corepack enable`を実行するだけです。Yarnを有効にするには、まだしていない場合は`corepack enable`を実行するだけです。
</Warning>
</Tab>
<Tab title="Windows(WSL)">
1. WSLをインストール
管理者としてPowerShellを開き、次のコマンドを実行します。
```powershell
wsl --install
```
コンピュータを再起動するプロンプトが表示されるはずです。 表示されなければ、手動で再起動してください。 表示されなければ、手動で再起動してください。 表示されなければ、手動で再起動してください。
再起動後、PowerShellウィンドウが開き、Ubuntuをインストールします。 これには少し時間がかかるかもしれません。
再起動後、PowerShellウィンドウが開き、Ubuntuをインストールします。 これには少し時間がかかるかもしれません。
Ubuntuインストールのためにユーザー名とパスワードを設定するプロンプトが表示されます。
2. gitをインストールして設定する
```bash
sudo apt-get install git
git config --global user.name "Your Name"
git config --global user.email "youremail@domain.com"
```
3. nvm、node.js、yarnをインストールする
<Warning>
`nvm`を使用して正しい`node`バージョンをインストールします。 `.nvmrc`は、すべての寄稿者が同じバージョンを使用することを保証します。
`.nvmrc`は、すべての寄稿者が同じバージョンを使用することを保証します。
</Warning>
```bash
sudo apt-get install curl
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
```
nvmを使用できるようにするには、ターミナルを閉じて再度開いてください。 次のコマンドを実行します。 次のコマンドを実行します。 次のコマンドを実行します。
```bash
nvm install # installs recommended node version
nvm use # use recommended node version
corepack enable
```
</Tab>
</Tabs>
---
## ステップ1:Gitクローン
ターミナルで次のコマンドを実行します。
<Tabs>
<Tab title="SSH(推奨)">
SSHキーの設定をまだ行っていない場合は、[こちら](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/about-ssh)で学べます。```bash
git clone git@github.com:twentyhq/twenty.git
```
```bash
git clone git@github.com:twentyhq/twenty.git
```
</Tab>
<Tab title="HTTPS">
```bash
git clone https://github.com/twentyhq/twenty.git
```
</Tab>
</Tabs>
## ステップ 2: ルートディレクトリに移動する
```bash
cd twenty
```
プロジェクトのルートで次のステップのすべてのコマンドを実行する必要があります。
## ステップ3:PostgreSQLデータベースをセットアップします
<Tabs>
<Tab title="Linux">
**オプション1(推奨):** データベースをローカルにプロビジョニングするには:
LinuxマシンにPostgreSQLをインストールするには、次のリンクを使用してください:[PostgreSQL のインストール](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
注意:`psql`の前に`sudo -u postgres`を追加して、パーミッションエラーを避ける必要があるかもしれません。
**オプション2:** dockerをインストールしている場合:
```bash
make -C packages/twenty-docker postgres-on-docker
```
</Tab>
<Tab title="Mac OS">
**オプション1(推奨):** `brew`でローカルにデータベースをプロビジョニングするには:
```bash
brew install postgresql@16
export PATH="/opt/homebrew/opt/postgresql@16/bin:$PATH"
brew services start postgresql@16
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
PostgreSQLサーバーが稼働しているかどうかを確認するには、以下を実行してください。
```bash
brew services list
```
macOSでHomebrew経由でインストールする場合、
インストーラーがデフォルトで`postgres`ユーザーを作成しないことがあります。 代わりに、macOSのユーザー名(例:「john」)と一致するPostgreSQLロールを作成します。
必要に応じて、`postgres`ユーザーを確認して作成するには、次の手順を実行してください。
```bash
# Connect to PostgreSQL
psql postgres
or
psql -U $(whoami) -d postgres
```
psqlプロンプト(postgres=#)で次を実行します。
```bash
# List existing PostgreSQL roles
\du
```
以下のような出力が表示されます。
```bash
Role name | Attributes | Member of
-----------+-------------+-----------
john | Superuser | {}
```
`postgres`ロールがリストに表示されない場合は、次のステップに進んでください。
`postgres`ロールを手動で作成します。
```bash
CREATE ROLE postgres WITH SUPERUSER LOGIN;
```
これにより、ログイン権限を持つ `postgres` というスーパーユーザーロールが作成されます。
```bash
Role name | Attributes | Member of
-----------+-------------+-----------
postgres | Superuser | {}
john | Superuser | {}
```
**オプション2:** dockerをインストールしている場合:
```bash
make -C packages/twenty-docker postgres-on-docker
```
</Tab>
<Tab title="Windows(WSL)">
以下のすべてのステップは、WSLターミナル(仮想マシン内)で実行されます。
**オプション1:** PostgreSQLをローカルでプロビジョニングするには:
Linux仮想マシンにPostgreSQLをインストールするには、次のリンクを使用してください:[PostgreSQL のインストール](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
注意:`psql`の前に`sudo -u postgres`を追加して、パーミッションエラーを避ける必要があるかもしれません。
**オプション2:** dockerをインストールしている場合:
WSLでDockerを実行すると、手順が少し複雑になります。
追加の手順を含む[Docker Desktop WSL2](https://docs.docker.com/desktop/wsl)の有効化などの追加の手順に精通している場合にのみこのオプションを使用してください。
```bash
make -C packages/twenty-docker postgres-on-docker
```
</Tab>
</Tabs>
これで、`localhost:5432` でデータベースにアクセスできます。
上記の Docker オプションを使用した場合、デフォルトの認証情報は、ユーザー `postgres` とパスワード `postgres` です。 ネイティブの PostgreSQL インストールの場合は、マシン上で設定された認証情報とロールを使用してください。
## ステップ4:Redisデータベース(キャッシュ)をセットアップ
Twenty は、最高のパフォーマンスを提供するために Redis キャッシュを必要とします。
<Tabs>
<Tab title="Linux">
**オプション1:** Redisをローカルでプロビジョニングするには:
LinuxマシンにRedisをインストールするには、次のリンクを使用してください:[Redisインストール](https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/)
**オプション2:** dockerをインストールしている場合:
```bash
make -C packages/twenty-docker redis-on-docker
```
</Tab>
<Tab title="Mac OS">
**オプション1(推奨):** `brew`でredisをローカルプロビジョニングするには:
```bash
brew install redis
```
Redis サーバーを起動する:
```bash
brew services start redis
```
**オプション2:** dockerをインストールしている場合:
```bash
make -C packages/twenty-docker redis-on-docker
```
</Tab>
<Tab title="Windows(WSL)">
**オプション1:** Redisをローカルでプロビジョニングするには:
Linux仮想マシンにRedisをインストールするには、次のリンクを使用してください:[Redisインストール](https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/)
**オプション2:** dockerをインストールしている場合:
```bash
make -C packages/twenty-docker redis-on-docker
```
</Tab>
</Tabs>
クライアント GUI が必要な場合は、[Redis Insight](https://redis.io/insight/)(無料版あり)をお勧めします。
## ステップ5:環境変数をセットアップします
環境変数や`.env`ファイルを使ってプロジェクトを設定します。 詳細は[こちら](https://docs.twenty.com/l/ja/developers/self-hosting/setup)。 詳細は[こちら](/l/ja/developers/self-host/capabilities/setup)。
`/front`と`/server`内の`.env.example`ファイルをコピーします:
```bash
cp ./packages/twenty-front/.env.example ./packages/twenty-front/.env
cp ./packages/twenty-server/.env.example ./packages/twenty-server/.env
```
<Info>
**マルチワークスペースモード:** デフォルトでは、Twenty は単一ワークスペースモードで動作し、ワークスペースは 1 つだけ作成できます。 マルチワークスペース対応を有効にするには(サブドメインベースの機能のテストに有用)、サーバーの `.env` ファイルで `IS_MULTIWORKSPACE_ENABLED=true` を設定してください。 詳細は[マルチワークスペースモード](/l/ja/developers/self-host/capabilities/setup#multi-workspace-mode)を参照してください。
</Info>
## ステップ6:依存関係をインストールします
Twentyサーバーを構築し、データベースにデータをシードするには、以下のコマンドを実行します:
```bash
yarn
```
`npm`または`pnpm`は使えません
## ステップ7:プロジェクトを実行する
<Tabs>
<Tab title="Linux">
Linuxディストリビューションによっては、Redisサーバーが自動的に開始されるかもしれません。
そうでない場合は、[Redisインストールガイド](https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/)を参照し、お使いのディストリビューションに合わせて確認してください。
</Tab>
<Tab title="Mac OS">
Redisはすでに稼働しているはずです。 稼働していなかった場合は、以下を実行してください:
```bash
brew services start redis
```
</Tab>
<Tab title="Windows(WSL)">
Linuxディストリビューションによっては、Redisサーバーが自動的に開始されるかもしれません。
そうでない場合は、[Redisインストールガイド](https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/)を参照し、お使いのディストリビューションに合わせて確認してください。
</Tab>
</Tabs>
次のコマンドでデータベースをセットアップします:
```bash
npx nx database:reset twenty-server
```
サーバー、ワーカー、フロントエンドサービスを開始します:
```bash
npx nx start twenty-server
npx nx worker twenty-server
npx nx start twenty-front
```
または、すべてのサービスを一度に開始することができます:
```bash
npx nx start
```
## ステップ 8: Twentyを使用する
**フロントエンド**
Twentyのフロントエンドは[http://localhost:3001](http://localhost:3001)で稼働しています。
デフォルトのデモアカウントを使用してログインできます: `tim@apple.dev` (パスワード: `tim@apple.dev`)
**バックエンド**
* Twentyのサーバーは[http://localhost:3000](http://localhost:3000)で稼働しています
* GraphQL API は [http://localhost:3000/graphql](http://localhost:3000/graphql) でアクセスできます
* REST API は [http://localhost:3000/rest](http://localhost:3000/rest) でアクセスできます
## トラブルシューティング
問題が発生した場合は、[トラブルシューティング](/l/ja/developers/self-host/capabilities/troubleshooting)を確認して解決策を見つけてください。