설치 콘텐츠
테넌트 설치 라이프사이클과 초기화 상태, 그리고 테넌트 행을 만드는 콘텐츠 출처 셋입니다.
설치 콘텐츠
테넌트 데이터를 추가하기 전에 설치 필수 데이터, 선택 적용 콘텐츠, 폐기 가능한 데모 데이터를 구분하세요. 선택 콘텐츠의 CopyableTemplateContribution::templates()와 apply() 구현은 Copyable Template을 따르세요. 호스트 활성화와 테넌트 설치는 별도이며 dry-run은 데이터를 쓰지 않고 설치 계획을 보여 줍니다.
시그니처
다음 명령이 라이프사이클을 처리합니다. 호스트 활성화와 테넌트 설치는 별개 연산입니다.
task artisan -- nexia-apps:activate-package-app {package} [--build-assets] [--dry-run]
task artisan -- nexia-apps:install-tenant-app {app} [--dry-run] [--with-prerequisites]
task artisan -- nexia-apps:repair-tenant-app {app}
task artisan -- nexia-apps:install-dev-app {app} --tenant= [--dry-run] [--with-prerequisites]요청에 따라 테넌트 행을 만드는 명령이 둘 더 있습니다.
task artisan -- nexia-apps:apply-template {app} {template} --tenant= --actor= [--legal-entity=]
task artisan -- nexia-demo:seed-demo --tenant= [--force]최소 예시
호스트 활성화 후 tenants:list에서 대상 로컬 테넌트 ID를 확인합니다. 설치가 초기화 전에 미적용 App migration을 실행합니다. 개발 명령은 APP_ENV=local에서만 동작하며 게시 상태와 readiness는 바꾸지 않습니다.
task artisan -- tenants:list
nexia_tenant=REPLACE_WITH_TENANT_ID
task artisan -- nexia-apps:install-dev-app workshop --tenant="$nexia_tenant" --dry-run
task artisan -- nexia-apps:install-dev-app workshop --tenant="$nexia_tenant" --with-prerequisites--dry-run은 App과 그 전제 폐포 전체에 대한 정렬된 설치·재활성화·이미활성 계획을 출력하고 아무것도 쓰지 않습니다.
인자: 무엇이 테넌트 행을 만드는가
설치 콘텐츠는 아래 세 경로를 구분합니다. 가드가 있는 테넌트 migration이나 일반 App 명령도 행을 만들 수 있으며, 이 표의 콘텐츠 적용 경로와는 별개입니다.
| 출처 | 실행 시점 | 만드는 것 | 건너뛸 수 있는가 |
|---|---|---|---|
| App initializer | 테넌트 설치 중 | App이 동작하는 데 필요한 최소 행 | 아니오 |
| Copyable template | 행위자가 적용할 때 | 편집 가능한 테넌트 소유 사본 | 예 |
| 데모 데이터 | 명시적 nexia-demo:seed-demo | 버려도 되는 샘플 레코드 | 항상 |
다음 선언만으로 테넌트 업무 행이 생성되지는 않습니다.
| 개념 | 테넌트 행에 대한 효과 |
|---|---|
| Descriptor | 없음. 타입 있는 기능 메타데이터 |
| Registry | 없음. 런타임 조회 계층 |
| Catalog | 그 자체로는 없음 — 코드 소유 정의 |
| Process Template descriptor | 편집기 문서만 바꾸고, 저장·게시가 영속화 |
| Template 적용 원장 | 출처를 기록하고 결코 소스가 되지 않음 |
Catalog를 읽어 행을 만드는 별도 명령도 있습니다. 예를 들어 nexia-access:sync-permissions는 코드의 Permission Catalog를 테넌트 Permission 행으로 동기화합니다. 이는 Catalog 선언 자체가 아니라 명령 실행의 효과입니다.
결과 또는 반환: 설치 라이프사이클
nexia-apps:install-tenant-app은 App마다 행 하나를 tenant_app_installations에 쓰고, 운영 상태와 초기화 상태를 함께 담습니다.
| 초기화 상태 | 의미 |
|---|---|
pending | 행은 쓰였고 initializer는 아직 완료되지 않음 |
initialized | Initializer가 성공적으로 완료됨 |
failed | Initializer가 실패하고, 행이 오류 메시지를 담고 있음 |
명령의 순서는 고정돼 있습니다.
- 전제 폐포와 Central 게시 상태, private 테넌트 허용을 검증하고 계획을 출력합니다.
- 선행 App부터 폐포의 미적용 migration을 실행합니다.
pending설치 행을 씁니다.- 테넌트의 Permission 카탈로그와 기준 Core Role을 동기화합니다.
- App마다 initializer를 각각 자기 트랜잭션에서 실행합니다.
- 계획을
initialized로 표시합니다.
Initializer마다 자기 트랜잭션에서 돌기 때문에 이미 커밋된 작업은 되돌려지지 않습니다. 다만 순서는 실패 지점에서 멈추고, 실패한 항목과 그 계획에서 아직 대기 중인 모든 항목이 같은 오류로 failed 표시됩니다.
InstalledAppResolver는 설치가 활성이고 초기화가 완료되고 모든 전제도 operational일 때만 App을 노출합니다.
app.installed:{app_key}가 닫힘 방향으로 실패하는 이유가 그 규칙입니다. pending이나 failed인 App은 테넌트 런타임에서 사용할 수 없습니다. PHP 경로가 등록되어 있더라도 app.installed가 요청을 거부합니다.
nexia-apps:repair-tenant-app {app}이 실패하거나 낡은 App에 대해 설치 계획을 다시 실행합니다. 손으로 행을 편집하는 것이 아니라 이것이 지원되는 복구 경로입니다.
일반 HTTP·CLI·가입 설치는 같은 배포 게이트를 통과합니다. 로컬 콘솔 개발 명령만 게시·테넌트 허용·preview 제한을 건너뛰며 선행 App, descriptor, migration, 초기화, 사용자 권한 검사는 유지합니다. 미게시 로컬 App의 복구·재활성화에도 개발 명령을 다시 사용합니다. 허용이 철회되거나 게시가 중단된 App도 기존 설치가 활성인 동안에는 계속 동작하지만 새 설치와 재활성화는 거부됩니다. 따라서 Central의 일시 장애가 평상시 App 요청을 중단시키지 않으면서 라이프사이클 쓰기가 열린 방향으로 실패하지 않습니다.
4단계는 권한 정의를 동기화합니다. User 자격을 바꾸지 않습니다. 보호된 App 연산에는 적용 가능한 Access Grant가 필요하며 설치만으로는 부여되지 않습니다.
App initializer
이 인터페이스는 호스트 전용입니다. App Package가 import할 수 없는
App\*아래에 있습니다. 새 패키지는 대신 가드 있는 테넌트 마이그레이션으로 필수 행을 배포합니다. 필수 설치 콘텐츠를 따르세요.
namespace App\AppRuntime;
interface TenantAppInitializerContribution
{
public const DEFAULT_VERSION = '1';
public function appKey(): string;
public function initialize(TenantAppInitializationContext $context): void;
}
interface VersionedTenantAppInitializerContribution extends TenantAppInitializerContribution
{
public function version(): string;
}| 요건 | 이유 |
|---|---|
| 멱등 | nexia-apps:repair-tenant-app이 다시 실행함 |
| 최소 운영 기본값만 생성 | 데이터 로딩 장치가 아님 |
| 운영자가 편집한 콘텐츠를 덮어쓰지 않음 | 재실행이 의도적인 변경을 파괴함 |
| 데모 레코드를 만들지 않음 | 그것은 데모 데이터의 몫 |
| 복사된 Template을 덮어쓰지 않음 | 그것은 테넌트 소유 |
호스트가 관리하는 initializer는 기본값 구조가 바뀔 때 버전이 있는 인터페이스로 구분합니다. 기본 버전은 '1'입니다.
Copyable template
CopyableTemplateContributionRegistry가 코드로 정의된 출처를 발견합니다. 데이터베이스 카탈로그가 아닙니다. CopyableTemplateFacade가 그것들을 현재 ApprovalFormPresetCatalog 어댑터와 결합합니다.
하나를 적용하면 테넌트 안 template_applications 원장에 출처가 기록됩니다.
| 원장 필드 | 내용 |
|---|---|
| App key | 소유 App |
| Template 키와 버전 | 불변 소스 정체성 |
| 범위 | tenant 또는 legal_entity |
| Legal Entity | null 가능 |
| 행위자 | 적용한 사람 |
| 결과 상태 | 성공 또는 실패 |
| 실패 이유 | 실패 시 |
| 생성된 Resource 참조 | 사본이 만들어낸 것 |
원장은 출처 기록일 뿐입니다. 결코 Template 소스 카탈로그가 되지 않고, 사본에 대한 이후 편집을 추적하지도 않습니다.
이것을 전제로 계획을 세우기 전에 알아둘 현재 제약이 둘 있습니다.
- Approval form preset은 테넌트 범위이므로,
nexia-apps:apply-template에--legal-entity를 넘기면 그것들에 대해 실패합니다. - Process Template은 이 경로를 아예 거치지 않습니다. 하나를 선택하면 저장되지 않은 BPMN 편집기 문서가 바뀌고, 평범한 정의 저장과 게시가 영속화와 짝 결정 배포를 소유합니다.
App은 Nexia\Templates\Contracts\CopyableTemplateContribution으로 Template을 공개합니다. templates()가 소스를 선언하고 apply()는 행위자와 선택적 Legal Entity를 담은 TemplateApplicationContext를 받습니다. 발견과 실행, 출처 원장은 호스트가 소유합니다.
데모 데이터
데모 데이터는 Core가 App 소유 Nexia\Fixture\Contracts\FixtureContribution 구현을 조합하는 명시적 픽스처 세트입니다. Core는 FixtureContext로 호스트 식별자의 스칼라 값만 제공하고, App은 자기 행만 쓰며 다른 App 모델을 import하지 않고 안정된 Resource Reference를 교환할 수 있습니다. 데모 데이터는 계속 폐기 가능한 샘플이며 설치 전제 조건이 아닙니다.
task artisan -- nexia-demo:seed-demo --tenant="$nexia_tenant"| 속성 | 동작 |
|---|---|
| 프로덕션 실행 | --force를 넘기지 않으면 거부 |
| 순서 | 프로덕션 기준선 먼저, 그다음 Core 데모 픽스처 |
| App 설치 상태 | 그대로 유지 — 시딩은 아무것도 설치하거나 활성화하지 않음 |
| 테넌트 프로비저닝 | 결코 호출하지 않음 |
| 설치 | 결코 의존하지 않음 |
| App 누락 또는 비활성 | 해당 App contribution만 건너뛰고 다른 operational App은 계속 실행 |
어떤 기능이 데모 시딩 뒤에만 동작한다면, 그 필수 행은 데모 데이터가 아니라 설치에 속합니다.
오류
| 증상 | 원인 | 해결 |
|---|---|---|
app.installed:{key}가 요청을 거부 | 설치가 pending이나 failed, 또는 전제가 operational이 아님 | nexia-apps:doctor-package-app 후 nexia-apps:repair-tenant-app |
| 행을 쓰기 전에 설치가 멈춤 | 전제 누락, 키 중복, 순환 | 전제 그래프 수정, 비대화형 설치에는 --with-prerequisites |
| 활성화가 데이터베이스 연결에서 실패 | Manifest 동기화가 엄격함 | PostgreSQL에 닿는 컨테이너 안에서 실행 |
| App이 설치됐는데 사용자에게 안 보임 | 그 권한을 담은 Role이 없음 | 관리자가 App Role을 만들고 배정 |
nexia-apps:apply-template에서 --legal-entity 거부 | Template이 테넌트 범위 | 옵션 생략 |
| 신규 테넌트에서 기능이 깨지고 데모 테넌트에서는 괜찮음 | 필수 행이 데모 데이터에 있음 | 설치로 옮기기 |
실제 사용
선택 콘텐츠는 App의 CopyableTemplateContribution에서 확인하세요. 선언은 사용할 양식을 나열하고 apply()는 전달받은 문맥에서 편집 가능한 테넌트 사본을 만듭니다.
packages/payroll과 packages/talent는 Nexia\Templates\Contracts\CopyableTemplateContribution을 직접 구현합니다. 두 패키지의 templates() 선언과 멱등적인 apply()가 현재 App 쪽 실제 예시입니다.
관련 문서
- Copyable Template — 출처 셋 중에서 고르기
- Artisan 명령어 — 위 모든 명령의 시그니처와 범위
- App 라이프사이클 — 설치가 런타임에서 놓이는 자리
- 설치 오류 해결 — 실패한 설치 진단