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는 더 이상 타입을 추론할 수 없습니다. 이는 개발 중 타입 관련 오류를 잡기 어렵게 만들어 런타임 오류로 이어지고, 코드의 유지보수성과 신뢰성이 떨어지며, 다른 사람이 이해하기도 어려워집니다.
이것이 모든 것이 타입을 가져야 하는 이유입니다. 따라서 이름(first name)과 성(last name)을 가진 새 개체를 만든다면, 다루는 개체의 구조를 정의하는 이름과 성을 포함한 인터페이스나 타입을 만들어야 합니다.

View File

@@ -0,0 +1,39 @@
---
title: 사용자 지정 개체
---
개체는 조직 고유의 데이터(레코드, 속성 및 값)를 저장할 수 있는 구조입니다. Twenty에는 표준 개체와 사용자 지정 개체가 모두 제공됩니다.
표준 개체는 모든 사용자에게 제공되는 속성이 있는 내장 개체입니다. Twenty의 표준 개체 예시로는 Company(회사)와 Person(사람)이 있습니다. 표준 개체는 모든 Twenty 사용자에게 제공되는 표준 필드를 가지고 있으며, 예를 들어 Company.displayName과 같습니다.
사용자 지정 개체는 조직 고유의 정보를 저장하기 위해 생성할 수 있는 개체입니다. 이들은 내장되어 있지 않으며, 워크스페이스의 구성원이 표준 개체로는 적합하지 않은 정보를 보관하기 위해 사용자 지정 개체를 생성하고 사용자 정의할 수 있습니다.
## 고급 스키마
<div style={{textAlign: 'center'}}>
<img src="/images/docs/server/custom-object-schema.png" alt="고급 스키마" />
</div>
<br />
## 작동 원리
사용자 지정 개체는 개체의 형태, 이름 및 유형을 결정하는 메타데이터 테이블에서 비롯됩니다. 이 모든 정보는 테이블로 구성된 메타데이터 스키마 데이터베이스에 있습니다.
* **DataSource**: 데이터가 존재하는 위치를 설명합니다.
* **Object**: 개체를 설명하고 DataSource와 연결됩니다.
* **Field**: 개체의 필드를 설명하고 개체와 연결됩니다.
사용자 지정 개체를 추가하려면 /metadata API를 쿼리하십시오. 이는 메타데이터를 해당 API에 따라 업데이트하고, 메타데이터를 기반으로 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의 경우, 사용자 수준이 아니라 워크스페이스 수준에서 설정됩니다.
## 새로운 기능 플래그 추가
`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');
```
## 배포를 위한 기능 플래그 구성
테이블 `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을 반환하는 공개 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
```
작업 공간 디렉토리의 루트에는 개별 작업 공간을 위한 스키마를 맞춤화하는 `createGraphQLSchema` 함수가 포함된 `workspace.factory.ts` 파일이 있습니다. 이 함수는 메타데이터를 사용하여 작업 공간별 스키마를 생성합니다. 스키마와 리졸버 구조를 분리하여, 이러한 개별 요소를 결합하는 `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. 새 큐에 대한 큐 이름을 열거형 `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,87 @@
---
title: 백엔드 명령어
icon: terminal
---
## 유용한 명령어
이 명령어들은 packages/twenty-server 폴더에서 실행되어야 합니다.
다른 폴더에서 `npx nx {command} twenty-server` (또는 `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를 백엔드에 사용합니다.
Prisma가 우리가 처음으로 사용한 ORM이었습니다. 그러나 사용자들이 사용자 지정 필드와 사용자 지정 객체를 만들 수 있도록 하려면 세밀하게 제어할 수 있어야 하므로 더 낮은 수준이 더 합리적이었습니다. 현재 프로젝트는 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/)을 사용하여 Twenty를 3000개 이상의 앱과 손쉽게 동기화하세요. 작업을 자동화하고 생산성을 높여 고객 관계를 강화하세요!
## Zapier 소개
Zapier는 팀이 매일 사용하는 앱을 연결하여 워크플로우를 자동화할 수 있게 하는 도구입니다. 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
```