ebee7d71b9
Created by Github action <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22715?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: github-actions <github-actions@twenty.com>
145 lines
10 KiB
Plaintext
145 lines
10 KiB
Plaintext
---
|
|
title: 설치 훅
|
|
description: 설치 전에나 후에 로직을 실행하여 시드 데이터를 추가하고, 레코드를 백업하고, 업그레이드를 검증하세요.
|
|
icon: wrench
|
|
---
|
|
|
|
설치 훅은 설치 또는 업그레이드 라이프사이클 동안 실행되는 특수한 로직 함수입니다. 이들은 일반 [로직 함수](/l/ko/developers/extend/apps/logic/logic-functions)와 동일한 핸들러 런타임을 공유하고 `InstallPayload`를 받습니다(`{ previousVersion?: string; newVersion: string }` — 새로운 설치에서는 `previousVersion`이 `undefined`임). 하지만 자체 define 함수로 선언되며, 일반 트리거 모델(HTTP, cron, 데이터베이스 이벤트) 외부에서 동작합니다.
|
|
|
|
각 앱은 **최대 하나의 pre-install** 함수와 **최대 하나의 post-install** 함수만 정의할 수 있습니다. 둘 중 하나가 둘 이상 감지되면 매니페스트 빌드에서 오류가 발생합니다.
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ install flow │
|
|
│ │
|
|
│ upload package → [pre-install] → metadata migration → │
|
|
│ generate SDK → [post-install] │
|
|
│ │
|
|
│ old schema visible new schema visible │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## 한눈에 보기
|
|
|
|
| | `definePreInstallLogicFunction` | `definePostInstallLogicFunction` |
|
|
| ------- | ------------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
| 실행 | 메타데이터 마이그레이션 이전 — **이전** 스키마와 데이터는 그대로 유지됨 | 마이그레이션 및 SDK 생성 이후 — **새로운** 스키마가 적용됨 |
|
|
| 실행 | 항상 동기식; 설치를 차단함 | 기본적으로 비동기(대기열에 등록, 최대 3회 재시도); `shouldRunSynchronously: true`로 동기 실행을 선택할 수 있음 |
|
|
| 실패 시 | 스키마 변경 이전에 설치가 **중단**됨 | 비동기: 최대 3회까지 재시도됩니다. 동기: 호출자는 `POST_INSTALL_ERROR`를 받음(스키마 변경은 **롤백되지 않습니다**) |
|
|
| 일반적인 사용 | 마이그레이션으로 손실될 데이터를 백업하거나 수정함; 예외를 던져 위험한 업그레이드를 거부 | 기본 데이터 시딩, 워크스페이스 구성, 외부 리소스 등록 |
|
|
|
|
**기본 원칙:** 기본값은 post-install로 사용하세요. 마이그레이션 자체가 파괴적이며 이전 상태가 사라지기 전에 이를 가로채야 할 때에만 pre-install을 사용하세요.
|
|
|
|
| 원하는 작업... | 사용 |
|
|
| ------------------------------ | --------------------------------------------------- |
|
|
| 데이터 시딩, 워크스페이스 구성, 외부 리소스 등록 | `post-install` |
|
|
| 설치 응답을 차단해서는 안 되는 장시간 작업 | `post-install` (기본 비동기 모드, 워커 재시도 포함) |
|
|
| 설치가 반환된 직후 호출자가 즉시 의존하는 빠른 설정 | `shouldRunSynchronously: true`를 사용하는 `post-install` |
|
|
| 곧 진행될 마이그레이션으로 손실될 데이터를 읽거나 백업 | `pre-install` |
|
|
| 기존 데이터를 손상시킬 업그레이드를 거부 | `pre-install` (핸들러에서 예외를 던짐) |
|
|
| 모든 업그레이드 시 상태 조정 수행 | `shouldRunOnVersionUpgrade: true`가 설정된 어느 훅이든 사용 |
|
|
|
|
## 두 훅에 공통으로 적용되는 동작
|
|
|
|
* 구성은 트리거 설정을 제외한 `defineLogicFunction` 구성에 `shouldRunOnVersionUpgrade`가 추가된 형태입니다.
|
|
* **실행 시점**: 기본적으로 신규 설치에서만 실행됩니다. 업그레이드 시에도 실행하려면 `shouldRunOnVersionUpgrade: true`를 설정합니다. 업그레이드 경로에 따라 분기하기 위해 `previousVersion` / `newVersion`을 사용합니다.
|
|
* **멱등성이 중요합니다**: 비동기 post-install은 재시도될 수 있고, `shouldRunOnVersionUpgrade`가 켜져 있으면 두 훅 모두 업그레이드 시 다시 실행됩니다.
|
|
* 일반적인 로직 함수 환경(`APPLICATION_ID`, `APP_ACCESS_TOKEN`, `API_URL`)이 주입되므로, 앱의 토큰으로 Twenty API를 호출할 수 있습니다.
|
|
* 훅은 빌드 시 애플리케이션 매니페스트에 자동으로 연결됩니다(`preInstallLogicFunction` / `postInstallLogicFunction`) — [`defineApplication()`](/l/ko/developers/extend/apps/config/application)에서 참조할 것은 없습니다.
|
|
* 기본 `timeoutSeconds`는 데이터 시딩과 같은 더 긴 설정 작업을 허용하기 위해 300으로 설정되어 있습니다.
|
|
* **dev 모드에서는 실행되지 않음**: `yarn twenty dev`는 설치 플로우를 건너뛰고 파일을 직접 동기화하므로, 해당 환경에서는 훅이 전혀 실행되지 않습니다. 대신 수동으로 트리거하세요:
|
|
|
|
```bash filename="Terminal"
|
|
yarn twenty dev:function:exec --postInstall
|
|
yarn twenty dev:function:exec --preInstall
|
|
```
|
|
|
|
<AccordionGroup>
|
|
<Accordion title="definePostInstallLogicFunction" description="워크스페이스 메타데이터 마이그레이션이 적용된 후에 실행됩니다.">
|
|
|
|
앱 설치가 완료된 후 한 번 실행됩니다: 메타데이터 동기화 완료, SDK 클라이언트 생성, 새로운 스키마 쿼리 가능 상태. 예시 — 신규 설치에서 기본 레코드를 시딩하기:
|
|
|
|
```ts src/logic-functions/post-install.ts
|
|
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
|
|
import { CoreApiClient } from 'twenty-client-sdk/core';
|
|
|
|
const handler = async ({ previousVersion }: InstallPayload): Promise<void> => {
|
|
if (previousVersion) return; // fresh installs only
|
|
|
|
const client = new CoreApiClient();
|
|
await client.mutation({
|
|
createPostCard: {
|
|
__args: { data: { name: 'Welcome to Postcard', content: 'Your first card!' } },
|
|
id: true,
|
|
},
|
|
});
|
|
};
|
|
|
|
export default definePostInstallLogicFunction({
|
|
universalIdentifier: 'f7a2b9c1-3d4e-5678-abcd-ef9876543210',
|
|
name: 'post-install',
|
|
description: 'Seeds a welcome post card after install.',
|
|
timeoutSeconds: 300,
|
|
shouldRunOnVersionUpgrade: false,
|
|
shouldRunSynchronously: false,
|
|
handler,
|
|
});
|
|
```
|
|
|
|
`shouldRunSynchronously` 플래그가 실행 모델을 제어합니다:
|
|
|
|
* `false` *(기본값)* — 메시지 큐에 등록되고(`retryLimit: 3`), 워커에 의해 실행됩니다. 작업이 큐에 등록되면 설치 응답이 즉시 반환됩니다. **장시간 작업에 사용** — 대용량 데이터셋 시딩, 지연이 긴 서드파티 API 호출 등.
|
|
* `true` — 설치 플로우 중에 인라인으로 실행됩니다. 설치 요청은 핸들러가 종료될 때까지 블로킹되며, 예외가 발생하면 호출자에게 `POST_INSTALL_ERROR`로 전달됩니다(재시도 없음). **빠르고, 응답 전에 반드시 완료되어야 하는 작업에 사용하세요.** 이 시점에는 이미 마이그레이션이 적용되었으므로, 실패하더라도 스키마 변경은 롤백되지 않고 오류만 노출됩니다.
|
|
|
|
</Accordion>
|
|
<Accordion title="definePreInstallLogicFunction" description="워크스페이스 메타데이터 마이그레이션이 적용되기 전에 실행됩니다.">
|
|
|
|
메타데이터 마이그레이션 이전, **이전** 스키마를 대상으로 실행됩니다 — 마이그레이션으로 손실될 데이터를 백업하거나, 위험한 업그레이드를 거부하기에 적절한 위치입니다. 실행에 앞서, 서버는 순수 추가식의 "간소화된 동기화"를 수행하여 새 버전의 pre-install 함수만 등록하고, 나머지 — 이전 버전의 오브젝트, 필드, 데이터 — 는 핸들러가 실행될 때까지 변경하지 않습니다.
|
|
|
|
pre-install은 항상 **동기식**이며 설치를 차단합니다. 핸들러에서 예외를 던지면, 어떤 스키마 변경도 적용되기 전에 설치가 중단되며 — 워크스페이스는 일관된 상태로 이전 버전에 머무릅니다. 이는 의도된 동작입니다: pre-install은 위험한 업그레이드를 거부할 수 있는 마지막 기회입니다.
|
|
|
|
예시 — 마이그레이션이 기존 필드를 삭제하기 전에 해당 필드 값을 복사하기:
|
|
|
|
```ts src/logic-functions/pre-install.ts
|
|
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
|
|
import { CoreApiClient } from 'twenty-client-sdk/core';
|
|
|
|
const handler = async ({ previousVersion, newVersion }: InstallPayload): Promise<void> => {
|
|
// Only the 1.x → 2.x upgrade drops the legacy `notes` field.
|
|
if (!previousVersion?.startsWith('1.') || !newVersion.startsWith('2.')) {
|
|
return;
|
|
}
|
|
|
|
const client = new CoreApiClient();
|
|
const { postCards } = await client.query({
|
|
postCards: {
|
|
__args: { filter: { notes: { isNot: null } } },
|
|
edges: { node: { id: true, notes: true } },
|
|
},
|
|
});
|
|
|
|
// Copy legacy `notes` into `description` before the migration drops the
|
|
// column. If this fails, the upgrade aborts and the workspace stays on v1.
|
|
for (const { node } of postCards.edges) {
|
|
await client.mutation({
|
|
updatePostCard: {
|
|
__args: { id: node.id, data: { description: node.notes } },
|
|
id: true,
|
|
},
|
|
});
|
|
}
|
|
};
|
|
|
|
export default definePreInstallLogicFunction({
|
|
universalIdentifier: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
|
|
name: 'pre-install',
|
|
description: 'Backs up legacy notes into description before the v2 migration.',
|
|
timeoutSeconds: 300,
|
|
shouldRunOnVersionUpgrade: true,
|
|
handler,
|
|
});
|
|
```
|
|
|
|
</Accordion>
|
|
</AccordionGroup>
|