예제
Descriptor 만들고 수정하기
Workshop Note의 typed 전자결재 binding과 문서 schema를 게시하고 도메인 양식에 나타난 결과를 확인합니다.
예제 유형 레시피
개요
Descriptor 만들고 수정하기 예제
이 예제는 같은 Workshop Note를 전자결재에 연결할 수 있도록
ApprovalFormBindingDescriptor와 ApprovalDocumentSchema를 추가합니다. 앞의
Contributor 만들기에서 workshop.note.publish 권한을
추가했다고 가정합니다.
이 예제가 다루는 범위
Descriptor는 여러 Core 런타임에 App 기능을 공개하는 공통 방식이지만, 이 예제는
그중 전자결재에 필요한 binding과 문서 schema만 다룹니다. 테넌트가 작성한
BPMN의 Service Task에서 App 업무 동작을 실행하려면 전자결재 descriptor를
재사용하지 않고 ProcessWorkActionDescriptor를 별도로 게시해야 합니다.
ProcessWorkActionDescriptor로 BPMN 선택기에 동작 공개
→ 서비스 프로바이더가 ProcessWorkActionRegistrar에 handler factory 등록
→ ProcessWorkActionHandler::handle()이 복원된 실행 문맥과 입력을 받음
→ ProcessWorkActionResult로 출력을 반환
Descriptor 선언은 catalog와 실행 계약을 공개할 뿐 App 업무 로직을 실행하지
않습니다. 실제 처리는 App 소유 handler가 담당합니다. Process 시작 binding,
사용자 태스크 폼, 가져올 수 있는 Process template도 각각
ProcessStartBindingDescriptor, ProcessUserTaskFormDescriptor,
ProcessTemplateDescriptor라는 별도 계약을 사용합니다. 실제 descriptor,
handler, 서비스 프로바이더 등록은 다음
업무 프로세스 기여하기에서 이어집니다.
BPMN 연동의 전체 선택 기준과 런타임 시그니처는
업무 프로세스와
업무 프로세스 계약을 보세요.
이 작업이 끝나면
| 생기는 것 | 확인 위치 |
|---|---|
workshop.note.submit binding | 전자결재 → 양식 관리 → 새 전자결재 양식 → 업무 양식 → 도메인 양식 |
| 이름·상태 snapshot schema | 양식 미리 보기와 결재 상세가 사용할 공개 문서 구조 |
| 새 메뉴 | 없음. 전자결재 메뉴는 Core가 소유함 |

위 화면이 작업 완료 후 실제로 추가되는 정보입니다. 도메인 양식 dialog에서
Workshop을 검색하면 노트 제출이 기타 앱 → Workshop 아래에 나타납니다.
이 단계는 관리자가 연결할 수 있는 선택지를 만든 것이며, 사용자용 작성 Widget은
다음 전자 결재에 기여하기에서 연결합니다.
어떤 계약을 구현하고 Core가 어떻게 받는가
WorkshopApprovalDescriptors도 Core 클래스를 상속하지 않습니다. App SDK의
AppDescriptorContribution을 구현하고 appDescriptors()에서 AppDescriptorSet을
반환합니다. ApprovalFormBindingDescriptor와 ApprovalDocumentSchema는 개발자가
상속하는 base class가 아니라, SDK가 제공하는 final descriptor 값 객체입니다.
WorkshopApprovalDescriptors implements AppDescriptorContribution
→ NexiaContributionRegistry가 구현 클래스를 발견
→ AppDescriptorCatalog가 appDescriptors()를 호출
→ descriptor type + key 중복을 검사하고 Workshop 소유권을 기록
├─ ApprovalBindingRegistry가 ApprovalFormBindingDescriptor를 소비
└─ ApprovalDocumentSchemaRegistry가 ApprovalDocumentSchema를 소비
(두 Registry 모두 현재 tenant의 App 설치 상태와 lifecycle을 다시 검사)
따라서 appDescriptors()에 객체를 넣는 행위는 UI를 직접 그리는 코드가 아닙니다.
Core의 전자결재 Registry가 이 정적 계약을 읽어 연결 가능한 도메인 양식과
동결할 문서 값의 구조로 해석합니다. ContributionOwner는 클래스가 발견된
Workshop namespace에서 정해지므로 App이 다른 App 소유인 것처럼 descriptor를
게시할 수도 없습니다.
1. Descriptor 추가
cp docs/developers/examples/descriptor/WorkshopApprovalDescriptors.php \
packages/workshop/src/Descriptors/WorkshopApprovalDescriptors.phpbinding의 핵심은 다음과 같습니다.
new ApprovalFormBindingDescriptor(
appKey: 'workshop',
resourceKey: 'note',
actionKey: 'submit',
labelKey: 'workshop.approval.note.submit.label',
entryModes: ['link'],
formWidgetKey: 'workshop.note.submit',
documentSchemaKey: 'workshop.note',
descriptionKey: 'workshop.approval.note.submit.description',
submitPermissionKey: 'workshop.note.publish',
)link는 이미 존재하는 Note를 연결한다는 뜻입니다. submit permission은 catalog
가시성을 제한하지만, 레코드별 backend Policy를 대신하지 않습니다.
같은 set에 binding이 참조하는 schema도 게시합니다.
new ApprovalDocumentSchema(
appKey: 'workshop',
resourceKey: 'note',
titleKey: 'workshop.approval.note.document.title',
sections: [[
'title_key' => 'workshop.approval.note.document.summary',
'fields' => [
['key' => 'name', 'label_key' => 'workshop.note.name.label', 'type' => 'string'],
['key' => 'status', 'label_key' => 'workshop.note.status.label', 'type' => 'string'],
],
]],
)Schema는 모델 column을 자동 반사하지 않습니다. App이 제출 시 동결할
documentValues의 공개 shape만 선언합니다.
2. locale 추가
Workshop이 지원하는 모든 locale에 같은 dotted key를 추가합니다.
{
"workshop.approval.note.submit.label": "노트 제출",
"workshop.approval.note.submit.description": "기존 노트를 전자결재에 연결합니다.",
"workshop.approval.note.document.title": "노트",
"workshop.approval.note.document.summary": "노트 내용"
}3. 발견과 화면 확인
sh docs/developers/examples/descriptor/verify.sh성공한 뒤 위 캡처의 경로에서 Workshop을 검색합니다. App 설치 상태,
submitPermissionKey, lifecycle, locale가 모두 맞아야 항목이 보입니다.
4. Descriptor 수정
표시 문구만 바꿀 때는 locale 값만 수정하고 identity와 version을 유지합니다. 호환 가능한 optional 계약을 추가한다면 consumer 호환성을 확인하고 version을 올립니다.
version: '1.1',action key, field type, requiredness처럼 기존 의미를 깨는 변경은 새 descriptor를 Active로 추가하고 기존 버전을 Deprecated로 전환합니다. 저장된 양식과 consumer가 이동한 뒤에만 Removed로 바꿉니다.
자주 발생하는 오류
| 증상 | 원인 | 해결 | 다시 확인 |
|---|---|---|---|
| validator는 성공하지만 도메인 양식 목록에 없음 | Workshop이 tenant에 설치되지 않았거나 사용자에게 submit 권한이 없거나 descriptor가 Active가 아님 | 설치 상태, workshop.note.publish 배정과 lifecycle을 확인 | 같은 tenant와 Legal Entity에서 Workshop 검색 시 노트 제출이 표시됨 |
| raw locale key가 보임 | Workshop이 지원하는 locale 중 하나에 동일한 dotted key가 없음 | 모든 resources/lang/{locale}.json에 네 key를 추가하고 runtime cache 갱신 | 선택기에 번역된 노트 제출과 설명이 표시됨 |
| 목록에는 있지만 작성 화면이 열리지 않음 | Descriptor는 정적 catalog만 게시했고 Slot Widget과 frontend registry가 아직 없음 | 다음 전자결재 contribution 레시피에서 네 workshop.note.submit identity를 연결 | 작성 화면이 Workshop Widget을 로드함 |
| schema를 찾지 못함 | binding의 documentSchemaKey와 schema의 appKey.resourceKey identity가 다름 | 둘을 정규 workshop.note identity로 맞춤 | verify.sh가 Descriptor contracts are valid.를 출력 |
포함된 파일
전자결재 Descriptor
docs/developers/examples/descriptor/WorkshopApprovalDescriptors.php<?php
declare(strict_types=1);
namespace Amuzcorp\Nexia\Workshop\Descriptors;
use Nexia\AppDescriptors\AppDescriptorSet;
use Nexia\AppDescriptors\ApprovalDocumentSchema;
use Nexia\AppDescriptors\ApprovalFormBindingDescriptor;
use Nexia\AppDescriptors\Contracts\AppDescriptorContribution;
final class WorkshopApprovalDescriptors implements AppDescriptorContribution
{
public static function appDescriptors(): AppDescriptorSet
{
return AppDescriptorSet::of(
new ApprovalFormBindingDescriptor(
appKey: 'workshop',
resourceKey: 'note',
actionKey: 'submit',
labelKey: 'workshop.approval.note.submit.label',
entryModes: ['link'],
formWidgetKey: 'workshop.note.submit',
documentSchemaKey: 'workshop.note',
descriptionKey: 'workshop.approval.note.submit.description',
submitPermissionKey: 'workshop.note.publish',
),
new ApprovalDocumentSchema(
appKey: 'workshop',
resourceKey: 'note',
titleKey: 'workshop.approval.note.document.title',
sections: [[
'title_key' => 'workshop.approval.note.document.summary',
'fields' => [
[
'key' => 'name',
'label_key' => 'workshop.note.name.label',
'type' => 'string',
],
[
'key' => 'status',
'label_key' => 'workshop.note.status.label',
'type' => 'string',
],
],
]],
),
);
}
}Descriptor 갱신과 검증
docs/developers/examples/descriptor/verify.sh#!/usr/bin/env sh
set -eu
test -f packages/workshop/src/Descriptors/WorkshopApprovalDescriptors.php
task artisan -- nexia-runtime:refresh-runtime-caches --if-route-cached --no-ansi
task artisan -- nexia-apps:validate-app-descriptors workshop --no-ansi
task artisan -- nexia-apps:doctor-package-app workshop --no-ansi
printf '%s\n' 'Descriptor contracts are valid. Confirm the new binding in the Electronic Approval domain-form catalog.'