메인 콘텐츠로 건너뛰기
로직 함수는 Twenty 플랫폼에서 실행되는 서버 측 TypeScript 함수입니다. 이 함수들은 HTTP 요청, cron 스케줄 또는 데이터베이스 이벤트에 의해 트리거될 수 있으며 — AI 에이전트를 위한 도구로도 제공할 수 있습니다.
각 함수 파일은 defineLogicFunction()을 사용해 핸들러와 선택적 트리거가 포함된 구성을 내보냅니다.
src/logic-functions/createPostCard.logic-function.ts
사용 가능한 트리거 유형:
  • httpRoute: HTTP 경로와 메서드로 함수를 노출합니다. 앱 코드에서 RestApiClient를 사용할 때는 라우트 경로 앞에 /s/를 접두사로 붙이십시오. 배포된 URL은 주입된 TWENTY_FUNCTIONS_URL 기본 URL(설정되지 않은 경우 \<server-url>/s)을 사용합니다.
(헤드리스) 프런트 컴포넌트에서 라우트로 트리거되는 로직 함수를 호출하려면 로직 함수 호출하기를 참고하세요.
  • cron: CRON 식을 사용하여 예약된 일정으로 함수를 실행합니다.
  • databaseEvent: 워크스페이스 객체 라이프사이클 이벤트에서 실행됩니다. 이벤트 작업이 updated인 경우, 수신할 특정 필드를 updatedFields 배열에 지정할 수 있습니다. 정의하지 않거나 비워두면, 어떤 업데이트든 함수가 트리거됩니다.
예: person.updated, *.created, company.*
  • serverRoute: 단일 등록 범위 HTTP 라우트를 노출합니다. serverRouteTriggerSettings로 선언된 resolver 함수는 소유자 워크스페이스에서 실행되며, 디스패치할 대상 워크스페이스와 대상 로직 함수를 반환합니다. 그런 다음 플랫폼은 해당 target 함수를 실행하고 그 응답을 반환합니다. 서버 라우트 트리거를 참고하세요.
CLI를 사용해 함수를 수동으로 실행할 수도 있습니다:
다음으로 로그를 확인할 수 있습니다:

라우트 트리거 페이로드

라우트 트리거가 로직 함수를 호출하면, 함수는 AWS HTTP API v2 형식을 따르는 RoutePayload 객체를 받습니다. twenty-sdk/logic-function에서 RoutePayload 타입을 임포트하세요:
RoutePayload 타입은 다음과 같은 구조입니다:

forwardedRequestHeaders

기본적으로 보안상의 이유로 들어오는 요청의 HTTP 헤더는 로직 함수로 전달되지 않습니다. 특정 헤더에 접근하려면 forwardedRequestHeaders 배열에 나열하세요:
핸들러에서, 전달된 헤더에 다음과 같이 접근합니다:
헤더 이름은 소문자로 정규화됩니다. 소문자 키를 사용해 접근하세요(예: event.headers['content-type']).

사용자 정의 HTTP 응답

기본적으로, 핸들러에서 일반 값을 반환하면 해당 값이 200 응답으로 전송됩니다(객체는 JSON, 문자열은 text/plain). 상태 코드와 응답 헤더를 제어하려면 twenty-sdk/logic-function에서 Response를 반환하세요:
보안상의 이유로, 응답 헤더는 허용 목록으로 제한됩니다. 목록에 없는 헤더(예: Set-Cookie, Access-Control-Allow-Origin과 같은 CORS 헤더, 또는 사용자 정의 X-* 헤더)는 응답이 전송되기 전에 조용히 제거됩니다. 허용되는 응답 헤더는 다음과 같습니다:
  • content-type
  • content-language
  • content-disposition
  • cache-control
  • retry-after
상태 코드는 유효한 HTTP 상태 코드(100에서 599 사이)여야 합니다. 응답 헤더 이름은 대소문자를 구분하지 않습니다.

서버 라우트 트리거

httpRouteTriggerSettings/s/ 아래에 함수를 노출하고 요청 호스트에서 워크스페이스를 해석합니다. 이는 각 워크스페이스가 자체 도메인을 가질 때 동작합니다. 그러나 타사 공급자는 모든 테넌트의 이벤트를 하나의 URL로 전달합니다. 그 경우에는 serverRouteTriggerSettings를 사용하세요.트리거는 두 부분으로 구성됩니다:
  1. resolver 로직 함수 — serverRouteTriggerSettings로 선언되는 — 는 소유자 워크스페이스(애플리케이션 등록을 소유한 워크스페이스)에서 실행됩니다. 이 함수는 들어오는 요청을 검사하고 { workspaceId, targetLogicFunctionUniversalIdentifier, payload? }를 반환하여, 대상 워크스페이스와 대상 함수를 둘 다 선택합니다. resolver는 단일 인가 지점입니다 — URL에는 resolver의 식별자만 포함됩니다. 요청 서명을 검증하기에 가장 적합한 위치입니다. resolver는 어떤 부수 효과가 발생하기 전에 실행되며, 원본 rawBody와 전달된 헤더에 접근할 수 있고, 대상에 전혀 접근하지 않고도 요청을 거부할 수 있습니다.
  2. 그 다음 target 로직 함수 — 일반적인 워크스페이스별 로직 함수 — 가 resolver가 반환한 payload(또는 resolver가 변환하지 않았다면 원본 요청 payload)를 가지고 결정된 워크스페이스에서 실행됩니다. 해당 함수의 반환 값이 HTTP 응답이 됩니다.
src/logic-functions/resolve-server-route.logic-function.ts
src/logic-functions/handle-invoice-paid.logic-function.ts
엔드포인트는 다음 위치에서 접근할 수 있습니다:
이 식별자는 manifest에 있는 resolver의 universalIdentifier입니다. 해당 URL을 공급자에 등록하세요.
애플리케이션은 소유자 워크스페이스가 지정되어 해당 워크스페이스에 설치되어 있어야 합니다. 리졸버는 소유자 워크스페이스(애플리케이션 등록을 소유한 워크스페이스)에서 실행되므로, 서버 라우트 트리거는 애플리케이션에 소유자 워크스페이스가 지정되고 — 즉, 소유자 워크스페이스가 있고 — 그리고 그 애플리케이션이 소유자 워크스페이스에 설치된 때에만 동작합니다. 이 두 조건이 모두 충족되기 전에는 리졸버가 실행될 위치가 없으므로, 라우트를 디스패치할 수 없습니다. 따라서 serverRouteTriggerSettings 로직 함수를 노출하는 애플리케이션은 소유자 워크스페이스가 지정되어 그 워크스페이스에 설치되기 전까지는 마켓플레이스에 등록될 수 없습니다.
Resolver 계약. SDK의 LogicFunctionConfig 타입은 컴파일 타임에 이를 강제합니다. serverRouteTriggerSettings를 설정하는 즉시, 핸들러는 { workspaceId: string; targetLogicFunctionUniversalIdentifier: string; payload?: object }(또는 이 값을 반환하는 Promise)를 반환하도록 제한됩니다. workspaceId는 대상 함수가 설치된 워크스페이스여야 하며, 그렇지 않으면 요청은 404로 거부됩니다.
서명 검증은 사용자 책임입니다 — resolver에서 검증하세요. 플랫폼은 요청 서명을 검증하지 않습니다. resolver는 이를 수행하기에 권장되는 위치입니다. 가장 먼저 실행되며, event.rawBodyforwardedRequestHeaders에 나열한 헤더에 접근할 수 있고, 오류를 발생시키거나 일치하지 않는 workspaceId를 반환하면 대상이 호출되기 전에 디스패치를 중단합니다. 검증을 대신 대상 쪽으로 미루는 경우, 대상은 rawBody와 헤더를 잃지 않도록 주의해야 합니다. 즉, resolver가 payload를 반환해서는 안 됩니다. 항상 어떤 부수 효과가 발생하기 이전에 검증을 수행하고, 상수 시간 비교를 사용하세요.
요청 서명의 경우 대부분의 공급자는 HMAC-SHA256으로 서명합니다. 서로 다른 부분은 헤더 이름, 다이제스트 인코딩, 그리고 서명 대상 페이로드 문자열입니다. 몇 가지 예시는 다음과 같습니다:위의 resolver 예제는 이미 GitHub HMAC-SHA256 플로우를 보여 줍니다. 통합하려는 공급자에 따라 헤더 이름, 다이제스트 인코딩, 그리고 서명 대상 페이로드 문자열을 조정하세요.
대상 함수는 동기적으로 실행되며, 반환한 값이 HTTP 응답이 되므로, 호출자는 상태 코드를 확인하고 2xx가 아닐 경우 재시도할 수 있습니다. 두 핸들러 모두 빠르게 유지하세요. 일부 공급자(예: Slack)는 몇 초 안에 타임아웃됩니다. resolver는 public endpoint로 접근 가능하므로, 엣지에서 rate limiting으로 보호하세요.

데이터베이스 이벤트 트리거 페이로드

데이터베이스 이벤트 트리거가 로직 함수를 호출하면, 변경된 각 레코드마다 하나의 DatabaseEventPayload를 받습니다. 이 페이로드는 소스 워크스페이스와 오브젝트에 대한 메타데이터를 레코드 수준 이벤트와 결합합니다.
페이로드에는 다음이 포함됩니다:소프트 삭제의 경우, 레코드의 deletedAt 필드가 변경되므로 .deleted는 업데이트 스타일 구조를 따릅니다. 영구 삭제의 경우 .destroyed를 사용하세요.
databaseEventTriggerSettings.updatedFields는 어떤 업데이트 이벤트가 함수를 트리거할지 필터링합니다. event.properties.updatedFields는 현재 이벤트에서 실제로 어떤 필드가 변경되었는지 알려줍니다.
생성 이벤트 예시:
업데이트 이벤트 예시:
이메일 업데이트에만 트리거되도록:
삭제 이벤트 예시:

함수를 AI 도구 또는 워크플로 작업으로 노출하기

로직 함수는 두 가지 영역에서 노출될 수 있으며, 각 영역마다 자체 트리거가 있습니다:
  • toolTriggerSettings — 이 설정을 사용하면 함수가 Twenty의 AI 기능(채팅, MCP, 함수 호출)에서 검색 가능해집니다. 표준 JSON 스키마(LLM이 기본적으로 이해하는 형식)를 사용합니다.
  • workflowActionTriggerSettings — 시각적 워크플로 빌더에서 함수를 단계로 나타나게 합니다. 빌더가 적절한 필드 에디터, 변수 선택기, 레이블을 렌더링할 수 있도록 Twenty의 풍부한 InputSchema를 사용합니다.
함수는 둘 중 하나만 또는 둘 다 선택할 수 있습니다. 이들 설정은 cronTriggerSettings, databaseEventTriggerSettings, httpRouteTriggerSettings와 나란히 위치하며 — 패턴도 형태도 동일합니다.
워크플로 Code 액션과의 관계. 워크플로 빌더에 내장된 Code 액션 자체가 하나의 로직 함수입니다. Twenty는 Code 단계마다 하나씩 생성하고, 해당 편집기를 인라인으로 노출합니다. workflowActionTriggerSettings는 그러한 일회성 인라인 코드를 재사용 가능한 액션으로 전환하는 방법입니다. 앱에서 함수를 한 번만 정의하면, 각 Code 단계에 코드를 복사·붙여넣기 하는 대신 모든 워크플로에서 선택할 수 있게 됩니다. 엔드유저 관점에 대해서는 사용자 가이드의 Code 액션을 참고하세요.
src/logic-functions/enrich-company.logic-function.ts
핵심 요점:
  • 함수는 노출 방식을 혼합할 수 있습니다 — toolTriggerSettingsworkflowActionTriggerSettings를 모두 선언하여 채팅과 워크플로 빌더 모두에 노출할 수 있습니다.
  • toolTriggerSettings.inputSchemaworkflowActionTriggerSettings.inputSchema는 모두 선택 사항입니다. 생략되면 매니페스트 빌더가 핸들러 소스 코드에서 이를 추론합니다(AI 도구의 경우 JSON 스키마, 워크플로 작업의 경우 Twenty의 InputSchema). 더 풍부한 타입 지정을 원한다면 명시적으로 제공하세요 — 예를 들어 워크플로 빌더를 위해 CURRENCY 또는 RELATION처럼 FieldMetadataType을 인지하는 필드를 사용하거나, AI 에이전트가 읽을 수 있는 description 필드를 포함하려는 경우:
매개 변수를 한 번만 선언하고 두 환경 모두에서 사용하려면, 단일 JSON Schema(InputJsonSchema)를 정의한 후 twenty-sdk/logic-functionjsonSchemaToInputSchema를 사용해 워크플로 작업용으로 변환하세요. toolTriggerSettings.inputSchema는 JSON Schema를 그대로 사용하지만, workflowActionTriggerSettings.inputSchema는 Twenty의 InputSchema를 요구합니다:
완전한 워크플로 액션 예제
workflowActionTriggerSettings는 네 가지 필드를 받습니다:이 모든 것을 하나로 — 선언된 출력을 통해 이후 단계에서 taskId를 참조할 수 있는, 워크플로 액션으로 노출된 함수 예시는 다음과 같습니다:
src/logic-functions/enrich-company.logic-function.ts
앱이 설치되면 Enrich Company가 워크플로 빌더의 액션 선택기에 나타납니다. 빌더는 companyNamedomain을 입력 필드로 렌더링하며(각각 이전 단계에서 값을 가져올 수 있음), 이후 단계에서는 해당 단계의 taskIdenriched 출력 값을 참조할 수 있습니다.
좋은 description을 작성하세요. AI 에이전트는 도구를 언제 사용할지 결정하기 위해 함수의 description 필드에 의존합니다. 도구가 무엇을 하는지와 언제 호출해야 하는지 구체적으로 작성하세요.
런타임 헬퍼. twenty-sdk/utils는 작은 런타임 헬퍼를 다시 export하여 핸들러가 twenty-shared를 직접 import하지 않도록 합니다. 예를 들어 isDefined(value)nullundefined 모두에 대해 false를 반환합니다. 이를 사용하면 선택적 핸들러 입력을 안전하게 좁힐 수 있습니다. 이러한 입력은 타입이 T | undefined로 지정되어 있더라도 런타임에는 null로 전달될 수 있습니다:
설치 훅 — 사전 설치 및 사후 설치 핸들러 — 는 이 런타임을 공유하지만, 각각의 define 함수로 선언되며 트리거 설정을 받지 않습니다. definePreInstallLogicFunctiondefinePostInstallLogicFunction 에 대해서는 설치 훅을 참고하세요.

타입이 지정된 API 클라이언트(twenty-client-sdk)

twenty-client-sdk 패키지는 로직 함수와 프런트 컴포넌트에서 Twenty API와 상호작용하기 위한 타입이 지정된 두 가지 GraphQL 클라이언트를 제공합니다.
CoreApiClient는 워크스페이스 데이터를 조회하고 변경하는 데 사용하는 기본 클라이언트입니다. yarn twenty dev 또는 yarn twenty dev:build 중에 워크스페이스 스키마로부터 생성되므로, 객체와 필드에 정확히 맞는 완전한 타입 정보를 제공합니다.
이 클라이언트는 선택 집합 구문을 사용합니다: 필드를 포함하려면 true를 전달하고, 인수에는 __args를 사용하며, 관계는 객체를 중첩합니다. 워크스페이스 스키마를 기반으로 완전한 자동 완성과 타입 검사를 제공합니다.
CoreApiClient는 개발/빌드 시점에 생성됩니다. 먼저 yarn twenty dev 또는 yarn twenty dev:build를 실행하지 않고 사용하면 오류가 발생합니다. 생성은 자동으로 이루어지며 — CLI가 워크스페이스의 GraphQL 스키마를 분석하고 @genql/cli를 사용해 타입이 지정된 클라이언트를 생성합니다.

타입 주석을 위한 CoreSchema 사용

CoreSchema는 워크스페이스 객체에 맞는 TypeScript 타입을 제공하며, 컴포넌트 상태나 함수 매개변수에 타입을 지정할 때 유용합니다:
MetadataApiClient는 SDK와 함께 사전 빌드된 상태로 제공됩니다(생성 필요 없음). 워크스페이스 구성, 애플리케이션 및 파일 업로드를 위해 /metadata 엔드포인트를 조회합니다.

파일 업로드

MetadataApiClient에는 파일 유형 필드에 파일을 첨부하기 위한 uploadFile 메서드가 포함되어 있습니다:
핵심 요점:
  • 필드의 universalIdentifier(워크스페이스별 ID가 아님)를 사용하므로, 앱이 설치된 모든 워크스페이스에서 업로드 코드가 동작합니다.
  • 반환된 url은 업로드된 파일에 액세스하는 데 사용할 수 있는 서명된 URL입니다.
코드가 Twenty에서 실행될 때(로직 함수 또는 프런트 컴포넌트), 플랫폼이 자격 증명을 환경 변수로 주입합니다:
  • TWENTY_API_URL — Twenty API의 기본 URL
  • TWENTY_APP_ACCESS_TOKEN — 애플리케이션의 기본 함수 역할 범위로 제한된 단기 키
클라이언트에 이를 전달할 필요가 없습니다 — 자동으로 process.env에서 읽습니다. API 키의 권한은 defineApplicationRole()으로 선언된 역할(또는 application-config.tsdefaultRoleUniversalIdentifier를 통해 참조된 역할)에 의해 결정됩니다.