프런트 컴포넌트를 사용할 수 있는 위치
프런트 컴포넌트는 Twenty 내에서 두 위치에 렌더링될 수 있습니다:- 사이드 패널 — 비헤드리스 프런트 컴포넌트는 오른쪽 사이드 패널에서 열립니다. 이는 명령 메뉴에서 프런트 컴포넌트를 트리거할 때의 기본 동작입니다.
- 위젯(대시보드 및 레코드 페이지) — 프런트 컴포넌트를 페이지 레이아웃 내 위젯으로 삽입할 수 있습니다. 대시보드 또는 레코드 페이지 레이아웃을 구성할 때 사용자는 프런트 컴포넌트 위젯을 추가할 수 있습니다.
- 명령 메뉴 항목과 연결 — 명령 메뉴(Cmd+K)에 등록하고, 선택적으로 고정된 빠른 작업으로 등록합니다.
- 페이지 레이아웃에 위젯으로 포함 — 레코드 상세 페이지 또는 대시보드에 배치합니다.
기본 예제
프런트 컴포넌트가 실제로 동작하는 모습을 가장 빨리 확인하는 방법은defineCommandMenuItem과 연결하여 페이지 오른쪽 상단에 빠른 작업 버튼으로 표시되게 하는 것입니다.
src/front-components/hello-world.tsx
src/command-menu-items/hello-world.command-menu-item.ts
yarn twenty dev로 동기화한 후(또는 일회성으로 yarn twenty dev --once를 실행한 경우), 페이지 우측 상단에 빠른 작업이 표시됩니다:

구성 필드
| 필드 | 필수 | 설명 |
|---|---|---|
universalIdentifier | 예 | 이 컴포넌트의 안정적인 고유 ID |
component | 예 | React 컴포넌트 함수 |
name | 아니요 | 표시 이름 |
description | 아니요 | 컴포넌트가 수행하는 작업에 대한 설명 |
isHeadless | 아니요 | 컴포넌트에 보이는 UI가 없다면 true로 설정하세요(아래 참조) |
프런트 컴포넌트를 페이지에 배치하기
명령 외에도, 페이지 레이아웃에 위젯으로 추가하여 레코드 페이지에 프런트 컴포넌트를 직접 임베드할 수 있습니다. 자세한 내용은 페이지 레이아웃을 참조하세요.헤드리스 vs 비헤드리스
프런트 컴포넌트는isHeadless 옵션으로 제어되는 두 가지 렌더링 모드를 제공합니다:
비헤드리스(기본값) — 컴포넌트가 가시적인 UI를 렌더링합니다. 명령 메뉴에서 트리거되면 사이드 패널에서 열립니다. isHeadless가 false이거나 생략된 경우의 기본 동작입니다.
헤드리스 (isHeadless: true) — 컴포넌트가 백그라운드에서 보이지 않게 마운트됩니다. 사이드 패널을 열지 않습니다. 헤드리스 컴포넌트는 로직을 실행한 뒤 스스로 언마운트하는 작업에 맞게 설계되었습니다 — 예: 비동기 작업 실행, 페이지로 이동, 확인 모달 표시. 아래에 설명된 SDK Command 컴포넌트와 자연스럽게 짝을 이룹니다.
src/front-components/sync-tracker.tsx
null을 반환하기 때문에, Twenty는 해당 컴포넌트에 대한 컨테이너 렌더링을 생략합니다 — 레이아웃에 빈 공간이 생기지 않습니다. 컴포넌트는 여전히 모든 훅과 호스트 통신 API에 접근할 수 있습니다.
SDK Command 컴포넌트
twenty-sdk 패키지는 헤드리스 프런트 컴포넌트를 위해 설계된 네 가지 Command 헬퍼 컴포넌트를 제공합니다. 각 컴포넌트는 마운트 시 동작을 실행하고, 스낵바 알림을 표시하여 오류를 처리하며, 완료되면 프런트 컴포넌트를 자동으로 언마운트합니다.
twenty-sdk/command에서 임포트하세요:
Command—executeprop을 통해 비동기 콜백을 실행합니다.CommandLink— 앱 경로로 이동합니다. Props:to,params,queryParams,options.CommandModal— 확인 모달을 엽니다. 사용자가 확인하면execute콜백을 실행합니다. Props:title,subtitle,execute,confirmButtonText,confirmButtonAccent.CommandOpenSidePanelPage— 특정 사이드 패널 페이지를 엽니다. Props:page,pageTitle,pageIcon.
Command를 사용해 명령 메뉴에서 동작을 실행하는 헤드리스 프런트 컴포넌트의 전체 예시는 다음과 같습니다:
src/front-components/run-action.tsx
src/command-menu-items/run-action.command-menu-item.ts
CommandModal을 사용하는 예시는 다음과 같습니다:
src/front-components/delete-draft.tsx
로직 함수 호출하기
Front 컴포넌트는 샌드박스된 Web Worker 안에서 브라우저 측에서 실행되고, logic functions는 서버 측에서 실행됩니다. 두 요소 사이에는 프로세스 내에서의 직접 호출이 없습니다. 대신, Front 컴포넌트는 HTTP를 통해 로직 함수에 접근합니다.httpRouteTriggerSettings로 선언된 로직 함수는 ${TWENTY_API_URL}/s\<path>의 /s/ 엔드포인트 아래에 노출됩니다. 여러분의 Front 컴포넌트는 twenty-client-sdk/rest의 RestApiClient를 사용해 해당 라우트를 호출하며, Twenty가 워커에 주입하는 TWENTY_APP_ACCESS_TOKEN으로 인증합니다.
RestApiClient는 바로 이런 용도로 설계되었습니다. 이는 워커 환경에서 TWENTY_API_URL과 TWENTY_APP_ACCESS_TOKEN을 읽어 Authorization: Bearer 헤더를 추가하고, JSON을 직렬화 및 파싱하며, 토큰이나 URL이 없거나 응답이 2xx가 아닐 경우 RestApiClientError를 발생시켜, 여러분이 각 컴포넌트마다 이러한 보일러플레이트를 다시 구현하지 않아도 되도록 해 줍니다.
헤드리스 Front 컴포넌트는 Command 컴포넌트를 통해 마운트 시점에 호출을 실행한 뒤, 자동으로 언마운트될 수 있습니다:
src/front-components/sync-prs.tsx
httpRouteTriggerSettings.path 앞에 /s가 접두사로 붙습니다. isAuthRequired: true를 유지하세요. 클라이언트가 컴포넌트용으로 Twenty가 발행한 앱 액세스 토큰을 제공합니다:
src/logic-functions/fetch-prs.logic-function.ts
TWENTY_API_URL과 TWENTY_APP_ACCESS_TOKEN은 자동으로 주입됩니다. 자세한 내용은 Application variables을 참고하세요. 비밀 애플리케이션 변수는 Front 컴포넌트에 절대 노출되지 않으므로, API 키 및 기타 민감한 로직은 Front 컴포넌트가 아니라 로직 함수 안에 유지해야 합니다.RestApiClient 레퍼런스
RestApiClient를 twenty-client-sdk/rest에서 import하세요. 이는 CoreApiClient 및 MetadataApiClient와 동일한 클라이언트 패밀리에 속하지만, GraphQL API 대신 앱의 HTTP 라우트를 대상으로 합니다.
| 방법 | 설명 |
|---|---|
get(path, options?) | GET 요청을 전송합니다. |
post(path, body?, options?) | POST 요청을 전송합니다. |
put(path, body?, options?) | PUT 요청을 전송합니다. |
patch(path, body?, options?) | PATCH 요청을 전송합니다. |
delete(path, options?) | DELETE 요청을 전송합니다. |
request(method, path, options?) | 임의의 HTTP 메서드를 사용하는 일반적인 요청입니다. |
options는 headers, query(쿼리 문자열 파라미터의 레코드이며, nullish 값은 건너뜁니다), 그리고 signal을 통한 AbortSignal을 받습니다. FormData가 아닌 객체 body는 자동으로 JSON 직렬화됩니다. 401이 발생하면 클라이언트는 호스트를 통해 한 번 액세스 토큰을 갱신한 뒤 요청을 재시도합니다.
기본 URL과 토큰은 기본적으로 환경에서 자동으로 결정됩니다. 테스트 등에서 필요할 때는 생성자에 override를 전달하세요. 예를 들면 다음과 같습니다:
status, statusText, url, 파싱된 body를 노출하는 RestApiClientError를 throw합니다:
런타임 컨텍스트에 접근하기
컴포넌트 내부에서, 현재 사용자, 레코드, 컴포넌트 인스턴스에 접근하려면 SDK 훅을 사용하세요:src/front-components/record-info.tsx
| 훅 | 반환값 | 설명 |
|---|---|---|
useUserId() | string 또는 null | 현재 사용자의 ID |
useSelectedRecordIds() | string[] | 선택된 모든 기록 ID(선택된 기록이 없으면 빈 배열) |
useRecordId() | string 또는 null | 사용 중단됨. 대신 useSelectedRecordIds()를 사용하세요 |
useFrontComponentId() | string | 이 컴포넌트 인스턴스의 ID |
useColorScheme() | 'light' 또는 'dark' | 호스트 UI의 활성 색 구성표 (System은 이미 결정됨) |
useFrontComponentExecutionContext(selector) | 항목에 따라 다름 | 셀렉터 함수를 사용해 전체 실행 컨텍스트에 접근 |
애플리케이션 변수
defineApplication()에서 isSecret: false로 정의된 애플리케이션 변수는 getApplicationVariable 유틸리티를 통해 프론트 컴포넌트 안에서 사용할 수 있습니다:
src/front-components/greeting.tsx
process.env를 통해 사용할 수 있습니다:
| 변수 | 설명 |
|---|---|
TWENTY_API_URL | Twenty API의 기본 URL |
TWENTY_APP_ACCESS_TOKEN | 앱의 역할 범위로 제한된 단기간 유효한 토큰 |
호스트 통신 API
프런트 컴포넌트는twenty-sdk의 함수를 사용해 내비게이션, 모달, 알림을 트리거할 수 있습니다:
| 함수 | 설명 |
|---|---|
navigate(to, params?, queryParams?, options?) | 앱 내 페이지로 이동 |
openSidePanelPage(params) | 사이드 패널 열기 |
closeSidePanel() | 사이드 패널을 닫습니다 |
openCommandConfirmationModal(params) | 확인 대화상자 표시 |
enqueueSnackbar(params) | 토스트 알림 표시 |
unmountFrontComponent() | 컴포넌트를 언마운트합니다 |
updateProgress(progress) | 진행률 표시기 업데이트 |
src/front-components/archive-record.tsx
여러 기록과의 작업
여러 개의 선택된 기록을 처리하려면useSelectedRecordIds()를 사용하세요. 이는 일괄 작업에 유용합니다:
src/front-components/bulk-export.tsx
퍼블릭 에셋
프런트 컴포넌트는getPublicAssetUrl을 사용해 앱의 public/ 디렉터리의 파일에 접근할 수 있습니다:
스타일링
프런트 컴포넌트는 여러 스타일링 방식을 지원합니다. 다음과 같은 방식을 사용할 수 있습니다:- 인라인 스타일 —
style={{ color: 'red' }} - Twenty UI 컴포넌트 —
twenty-sdk/ui에서 임포트(버튼, 태그, 상태, 칩, 아바타 등) - Emotion —
@emotion/react를 사용하는 CSS-in-JS - Styled-components —
styled.div패턴 - Tailwind CSS — 유틸리티 클래스
- React와 호환되는 모든 CSS-in-JS 라이브러리