업무 프로세스 계약
업무 프로세스 시작과 work action, user task 폼, 템플릿, 결정 결과 SDK 계약과 라이프사이클 규칙입니다.
업무 프로세스 계약
Process에 필요한 Descriptor를 게시하고 실행할 Work Action의 런타임 handler를 등록하세요. 아래 최소 선언은 액션을 탐색할 수 있게 할 뿐 handler를 설치하지 않습니다. 실행 전 런타임 등록 절을 적용하고 영속 메시지의 정확한 correlation 식별자를 유지하세요.
시그니처
하나의 정적 descriptor contribution이 App을 Process 런타임에 노출합니다. 불변 set을 반환하고 Core가 필요한 typed Process descriptor를 고릅니다.
use Nexia\AppDescriptors\Contracts\AppDescriptorContribution;
use Nexia\AppDescriptors\AppDescriptorSet;
use Nexia\AppDescriptors\ProcessWorkActionDescriptor;appDescriptors()는 tenant나 actor가 생기기 전 catalog 조립 중에 평가됩니다.
set에는 ProcessStartBindingDescriptor, ProcessWorkActionDescriptor,
ProcessUserTaskFormDescriptor, ProcessTemplateDescriptor,
DecisionResultTemplateDescriptor와 Approval·Signature descriptor를 함께 넣을 수 있습니다.
최소 예시
설명용 Quality key를 사용하는 생성자 유효 선언 예시입니다. 해당 Quality 업무 Resource가 체크아웃에 있다는 전제는 아닙니다. 실제로 등록한 Resource와 아래 런타임 연동 계약을 함께 사용하세요.
<?php
declare(strict_types=1);
namespace Amuzcorp\Nexia\Quality\Descriptors;
use Nexia\AppDescriptors\Contracts\AppDescriptorContribution;
use Nexia\AppDescriptors\AppDescriptorSet;
use Nexia\AppDescriptors\ProcessWorkActionDescriptor;
final class QualityProcessActions implements AppDescriptorContribution
{
public static function appDescriptors(): AppDescriptorSet
{
return AppDescriptorSet::of(
new ProcessWorkActionDescriptor(
kind: 'serviceTask',
appKey: 'quality',
actionKey: 'inspection_request.finalize',
labelKey: 'quality.process.inspection_request.finalize.label',
topic: 'quality.inspection_request.finalize',
),
);
}
}인자: ProcessWorkActionDescriptor
| 인자 | 타입 | 기본값 | 동작 |
|---|---|---|---|
kind | string | — | serviceTask, sendTask, receiveTask |
appKey | string | — | 소유 App, 비어 있으면 안 됨 |
actionKey | string | — | App 안에서 안정적인 식별자, 예를 들어 leave_request.finalize |
labelKey | string | — | BPMN 요소 선택기에 보이는 라벨 |
topic | string | — | serviceTask의 워커 topic, sendTask / receiveTask의 메시지 topic |
version | string | 1.0 | Descriptor 개정 |
payloadSchema | array | [] | 키별 검증·작성 맵 |
allowedBindingSources | array | [] | 프로세스 작성자가 각 입력을 어디서 바인딩할 수 있는지 |
inputContract | array | [] | 선언된 입력 |
approvalTask | ProcessApprovalTaskConfiguration, null | null | 하나의 serviceTask를 결재 상신과 대기를 결합한 작업으로 표시 |
outputContract | array | [] | Activity IO로 사용할 수 있는 안정적인 작업 출력 |
status | DescriptorStatus | Active | Active, Deprecated, Removed |
kind는 닫힌 집합에 대해 검증됩니다.
ProcessWorkActionDescriptor [quality.inspection.finalize] kind [userTask] must be one of: serviceTask, sendTask, receiveTask
ProcessWorkActionDescriptor app_key must be a non-empty string.
userTask는 의도적으로 빠져 있습니다. 사람 태스크는 ProcessUserTaskFormDescriptor입니다.
kind는 상호작용 모양으로 고르세요.
| Kind | 의미 | topic이 가리키는 것 |
|---|---|---|
serviceTask | 프로세스가 여러분 App을 호출하고 기다림 | App이 소비하는 워커 topic |
sendTask | 프로세스가 메시지를 내보냄 | 메시지 topic |
receiveTask | 프로세스가 메시지를 기다림 | 메시지 topic |
ProcessStartBindingDescriptor
| 인자 | 타입 | 기본값 | 동작 |
|---|---|---|---|
appKey | string | — | 소유 App |
bindingKey | string | — | App 안의 안정 업무 의도 |
definitionKey | string | — | App 소유 Process 정의 키 |
processId | string | — | 정의 안의 BPMN process id |
resourceKey | string | — | Process 시작을 허용할 App 소유 Resource |
startPermissionKey | string | — | Core가 다시 확인할 App 소유 Permission |
labelKey | string | — | Binding 라벨 |
version | string | 1.0 | Descriptor 개정 |
status | DescriptorStatus | Active | 라이프사이클 |
생성자는 빈 필드를 거부하고 definitionKey, resourceKey,
startPermissionKey가 appKey.로 시작하도록 요구합니다. 실제 조회 키는
appKey.bindingKey입니다.
이 descriptor는 여전히 start intent의 정식 선언입니다. Core는
Nexia\Process\Contracts\ProcessStarter를 구현해 bound request를 시작하며,
discovery를 AppDescriptorSet으로 옮겨도 이 실행 경계는 제거되거나 약해지지 않습니다.
Work Action 런타임 등록
AppDescriptorContribution::appDescriptors()가 catalog 항목을 공개합니다. serviceTask
구현은 Nexia\Process\Contracts\ProcessWorkActionRegistrar를 통해 별도로
등록합니다.
use Nexia\Process\Contracts\ProcessWorkActionHandler;
use Nexia\Process\Contracts\ProcessWorkActionRegistrar;
use Amuzcorp\Nexia\Quality\Process\FinalizeInspectionRequest;
$registrar = app(ProcessWorkActionRegistrar::class);
$registrar->register(
'quality',
'inspection_request.finalize',
static fn (): ProcessWorkActionHandler => app(FinalizeInspectionRequest::class),
);App 내부 경로에 FinalizeInspectionRequest를 구현한 뒤 service provider의 boot()에서 등록하세요. 이 클래스는 ProcessWorkActionHandler::handle(ProcessWorkActionInvocation): ProcessWorkActionResult를 구현해야 합니다. 위 이름은 설명용이며 Quality가 제공하는 handler가 아닙니다. 전체 실행 절차는 업무 프로세스에서 이어집니다.
handler는 고정된 descriptor 버전, Process·외부 태스크 id, idempotency key,
복원된 Legal Entity와 행위자, 정규 ResourceRef, 실제 Token의 elementId, 입력을 담은
ProcessWorkActionInvocation을 받습니다. ProcessWorkActionResult를
반환합니다. ProcessWorkActionException의 안정 오류 코드는 Core 소유
retry·incident 상태로 전달됩니다. elementId는 불변 상신 증거와 정확한 Approval Case
참조에 함께 저장한 뒤 ProcessMessageDelivery에 사용하세요. 액션 이름으로 추측하지
않습니다. 이전 SDK 호출자는 생략할 수 있어 기본값은 null이며, 갱신된 Core는 항상 전달합니다.
Approval Task 메타데이터
Approval Task는 serviceTask 하나를 사용합니다. “상신”과 “대기” 동작을
따로 기여하지 마세요. approvalTask가 App 바인딩, 영속 결과 topic,
결과 값, 테넌트 설정을 저장할 payload 키 둘을 선언합니다. 작성 시점
미리보기 대상은 선언하지 않습니다.
ProcessApprovalTaskConfiguration 인자 | 타입 | 기본값 | 동작 |
|---|---|---|---|
bindingKey | string | — | App 소유 Approval binding. 정규화되고 비어 있지 않아야 함 |
outcomeTopic | string | — | 영속 메시지 topic. 정규화되고 비어 있지 않아야 함 |
outcomes | string 목록 | approved, rejected, recalled, cancelled | 비어 있지 않고 중복 없는 정규화 결과 값 |
templatePayloadKey | string | template_key | 선택한 실제 business template key를 저장할 payload 필드 |
routePolicyPayloadKey | string | approval_route_policy_key | 선택한 실제 route policy key를 저장할 payload 필드 |
businessTemplatePresetKey | string, null | null | 작성 시 사용할 App 선언 Approval business-template preset 기본값 |
routePolicyPresetKey | string, null | null | 작성 시 사용할 App 선언 Approval route-policy preset 기본값 |
supportsLinePreparation | bool | false | 같은 대기 태스크에서 사람이 결재선을 정하도록 허용. handler가 준비된 결재선을 사용해야 함 |
선택적 preset 키 둘은 tenant에 실제 Approval 설정이 아직 없을 때 App이 의도한 recipe를 선택합니다. Core가 catalog 순서로 App 업무 정책을 추론하지 않게 하는 장치입니다. 편집기는 선택한 preset을 Legal Entity 소유의 published template과 active policy로 materialize할 수 있습니다. BPMN payload에는 preset 키가 아니라 그 결과인 실제 설정 키를 기록합니다. null인 preset 필드는 직렬화 결과에서 빠집니다.
대응하는 payloadSchema 항목은 Core 카탈로그를 사용해야 합니다.
'template_key' => [
'type' => 'string',
'required' => true,
'catalog_ref' => 'approval.business_template',
'filter' => ['binding_key' => 'quality.inspection_request.submit'],
],
'approval_route_policy_key' => [
'type' => 'string',
'required' => true,
'catalog_ref' => 'approval.route_policy',
'filter' => ['status' => 'active'],
],위 예시는 활성 결재 정책을 명시적으로 요구합니다. 양식에 설정한 결재선이나 사람이 선택한 결재선을 지원하는 액션은 route payload를 선택 사항으로 두고 supportsLinePreparation: true를 선언합니다. 편집기는 게시된 업무 양식을 선택하며 양식에 정책이 있으면 이를 사용합니다. 없으면 실행 시 기존 준비 Task에서 결재선을 받습니다. 명시적으로 선택한 정책은 실제로 존재하고 활성 상태여야 합니다. 게시 시 양식·바인딩·범위와 선택된 정책을 검증하며 작성자를 기준으로 결재자를 미리 결정하지 않습니다.
이 확인은 설정 사용 가능 여부만 보고하며 결재선을 계산하지 않습니다.
런타임 상신자는 프로세스 인스턴스를 시작한 행위자이고, 작성 시점의 어떤
입력으로도 결정되지 않습니다 — 수동 시작 프로세스는 권한 있는 누구나
시작할 수 있고, 이벤트 시작 프로세스는 그 이벤트를 유발한 사람이
시작합니다. 그래서 편집기는 작성자를 상신자 대신 세우지도, 예시 대상을
요구하지도 않습니다. 조직 데이터 공백은 실패로 닫히는 상신 시점과
인스턴스 incident 기록에서 드러납니다. 직접 배치한 Approval
ServiceTask와 템플릿에서 가져온 태스크 모두 선언된 approval_outcome을
dataOutputAssociation으로 매핑해 뒤따르는 exclusive Gateway에 공급해야
합니다. App 패키지 테스트에서는
Nexia\Testing\ApprovalProcessConformance::assert()로 이 전체 형태를
검사할 수 있습니다.
구조 검사는 첫 번째 게이트일 뿐입니다. App handler는 Approval Case에
연결된 App 소유 동결 제출 증거도 만들어야 하고, 전체 Inbox consumer는
ProcessRuntime::deliverMessage()를 호출하기 전에 그 증거를 App 상태에
적용해야 합니다. 이 실제 배선은
Nexia\Testing\ApprovalProcessBridgeConformance::assert()로 검사합니다.
Rejected, AlreadyConsumed, Pending 전달 상태 게이트는 별도로
ApprovalOutcomeConsumerConformance::assert()를 유지합니다.
receiveTask에는 descriptor, BPMN 구조, 요소 id, 필수 수신 키, App의 실제
이벤트 correlator를 넘겨
Nexia\Testing\ReceiveTaskCorrelationConformance::assert()를 사용합니다.
이 검사는 Activity IO 매핑과 정확한 요소·topic으로 실제 전송된 메시지를
함께 확인합니다. 사용자가 내부 식별자를 입력하지 않고도 권한 있는 제품
동작이나 connector가 그 메시지를 보낼 수 있어야 게시된 대기가 완성됩니다.
ProcessUserTaskFormDescriptor
| 인자 | 타입 | 기본값 | 동작 |
|---|---|---|---|
key | string | — | 안정적인 폼 정체성 |
appKey | string | — | 소유 App |
labelKey | string | — | 태스크 폼 선택기의 라벨 |
rendering | array | ['mode' => 'core_schema'] | 폼이 렌더링되는 방식 |
schema | array | ['fields' => []] | 입력 필드 스키마 |
outputSchema | array | [] | 폼이 프로세스로 돌려주는 값 |
allowedResourceActions | array | [] | 폼이 호출할 수 있는 Resource 동작 |
version | string | 1.0 | Descriptor 개정 |
status | DescriptorStatus | Active | 라이프사이클 |
rendering 기본 모드 core_schema는 플랫폼이 schema에서 폼을 렌더링한다는 뜻이므로, 간단한 폼은 App 프런트엔드 컴포넌트가 아예 필요 없습니다. schema.fields를 채우고 필요한 출력과 BPMN Activity IO를 연결하세요.
allowedResourceActions는 문서가 아니라 화이트리스트입니다. 폼은 자기가 나열한 동작만 호출할 수 있고, 각각은 여전히 평범하게 권한 확인을 받습니다.
outputSchema 항목은 type과 선택적인 variable, required, nullable을
가집니다. 필수이고 null이 아닌 string/enum 결과에는 비어 있지 않고 중복 없는
enum, label_key, 각 값의 enum_labels 번역 키를 추가합니다. 그러면 BPMN
편집기가 이 결과를 현지화된 Gateway 선택지로 제공하고 UserTask의 Activity IO
대상을 따라갑니다. 작성자는 내부 경로나 원시 enum 값을 입력하지 않습니다.
ProcessTemplateDescriptor
| 인자 | 타입 | 기본값 | 동작 |
|---|---|---|---|
key | string | — | 안정적인 템플릿 정체성, 비어 있으면 안 됨 |
version | string | — | 필수, 비어 있으면 안 됨 |
appKey | string, null | — | 소유 App. 제공하면 비어 있으면 안 되고 key의 첫 segment와 같아야 하며, 플랫폼 템플릿이면 null |
labelKey | string | — | 템플릿 선택기의 라벨 |
category | string | — | 선택기 안 묶음 |
structure | array | — | BPMN 구조 |
decisions | array | [] | 레거시 권장 메타데이터. 자동 영속화하지 않음 |
dependencies | array | [] | 템플릿이 요구하는 다른 산출물 |
status | DescriptorStatus | Active | 라이프사이클 |
descriptionKey | string, null | null | 더 긴 설명 |
nameKeys | array | [] | 만들어진 정의의 로케일별 이름 |
ProcessTemplateDescriptor key must be a non-empty string.
DecisionResultTemplateDescriptor
| 인자 | 타입 | 기본값 | 동작 |
|---|---|---|---|
key | string | — | 안정적인 정체성 |
version | string | — | 필수 |
labelKey | string | — | 라벨 |
fields | array | — | 결과 필드, DecisionResultFieldDescriptor 항목으로 |
status | DescriptorStatus | Active | 라이프사이클 |
descriptionKey | string, null | null | 카탈로그 설명 |
decisionTable | array, null | null | 선택적인 완전한 편집 가능 authoring seed |
hitPolicy | string, null | null | 완전한 seed가 있을 때 필요한 지원 정책 |
선택적인 DMN authoring 시작점을 선언합니다. 완전한 seed는 비어 있지 않은
list 형태의 inputs, outputs, rules와 정확히 하나의 input을 요구합니다.
guided editor가 input 열 하나만 seed하기 때문입니다. 그 input에는 비어 있지
않은 id가 필요합니다. source를 선언한다면 kind는 event_payload 또는
process_variable뿐입니다. Event source는 event_name과 payload_key가
필요하고 expression은 event_payload.{payload_key}여야 합니다. Process
variable expression은 input id와 같아야 합니다. 선언한 모든 결과 필드는
output에 있어야 합니다. 선택은 평범한 편집기에 값을 복사할 뿐이며, Decision
Definition을 만들거나 영속 키를 고르거나 런타임 의존성이 되지 않습니다.
직접 배치한 BusinessRuleTask와 Process 템플릿에서 복사한 태스크는 같은 생성 흐름을 씁니다. 불완전한 BPMN 초안을 저장하고 별도 작업 탭에서 DMN을 열어 명시적으로 저장한 뒤, 연결해 저장된 BPMN 초안으로 돌아옵니다. DMN을 먼저 게시하고 BPMN을 게시합니다.
버전 고정
버전 동작은 어느 내구 객체가 그것을 저장하는지에 따라 달라집니다. 기본 설치 또는
source_template_keys로 준비한 템플릿과 정의 키가 일치하는 저장에서는
source_template_key·source_template_version을 기록하고 후속 버전에도 보존합니다.
선택만으로 저장되지는 않습니다. 출처 기록이 있어도 새 템플릿이 저장된 정의나
실행 중인 인스턴스를 자동 교체하지 않습니다. 정의의 Work Action은 {app, action_key}로 해석합니다. 하지만
Core가 외부 태스크를 만들 때 해석된 App, action, version, topic을 고정하고,
실행 시점의 활성 descriptor가 그 tuple과 더 이상 일치하지 않으면 거부합니다.
결과입니다.
| 하는 일 | 실행 중 프로세스에 대한 영향 |
|---|---|
| 같은 버전에서 descriptor 동작 변경 | 실행 중 정의가 어긋날 수 있음 — 하지 마세요 |
| 새 Work Action 버전 게시 | 이후 태스크는 새 descriptor를 해석합니다. 기존 외부 태스크는 고정 tuple을 유지하고 더 이상 일치하지 않으면 fail closed합니다 |
status: Deprecated 설정 | 새 선택 없음, 기존 정의는 계속 해석됨 |
status: Removed 설정 | 해석이 멈추고 참조하는 정의가 깨짐 |
| Descriptor 삭제 | Removed와 같지만 감사 흔적이 없음 |
게시된 버전은 불변으로 취급하세요. 동작 변경에는 새 버전을 주세요.
해석 관문
Descriptor가 작성 중에 선택 가능하고 실행 시점에 해석 가능한 것은 이 조건이 모두 성립할 때뿐입니다.
| 관문 | 요구 사항 |
|---|---|
| 발견 | 클래스가 선언된 contribution 위치 안에 있고 인터페이스를 구현함 |
| 설치 | 소유 App이 테넌트에 대해 설치되고 활성이고 초기화됨 |
| 라이프사이클 | status가 선택을 허용함 |
| 권한 | Core가 시작 binding의 startPermissionKey를 다시 확인합니다. Work Action은 시작 행위자를 복원하고 handler가 수행하는 각 보호 동작을 인가합니다 |
결과 또는 반환: Process 런타임 접근
App에 묶인 Process를 시작하려면 Nexia\Process\Contracts\ProcessStarter를
해석해 start(BoundProcessStart)를 호출합니다. 요청은 전체 binding key,
Legal Entity, 행위자, 정규 ResourceRef, 변수, idempotency key를 담습니다.
Core는 권한을 다시 해석하고 읽기 전용 ProcessInstanceSnapshot을 반환합니다.
정확한 재시도는 같은 snapshot을 돌려주고 같은 키 아래 바뀐 payload는 거부합니다.
App이 실행 중인 Process를 관찰하거나 correlation해야 하면 Nexia\Process\Contracts\ProcessRuntime을 해석합니다.
| 메서드 | 계약 |
|---|---|
hasPublishedEventStart($legalEntityKey, $eventName) | 해당 Legal Entity에서 지금 실행 가능한 게시 정의가 그 이벤트 시작을 제공하는지 반환 |
findInstance($publicId) | 읽기 전용 ProcessInstanceSnapshot 또는 null 반환 |
correlateReceiveTask($correlation) | 정확한 receive task 하나를 correlation하고 일치 여부 반환 |
deliverMessage($delivery) | 멱등 메시지 하나를 영속 기록하고 정확한 대기 Activity에 correlation |
Snapshot은 publicId, legalEntityKey, 상태, 선택 businessKey, 선택 정규 ResourceRef만 노출합니다. ReceiveTaskCorrelation에는 Legal Entity key, 인스턴스 public id, 선택 business key, 정규 Resource reference, BPMN element id, topic, payload, 선택 필수 인스턴스 상태가 필요합니다. 식별자는 비어 있지 않고 이미 정규화돼 있어야 합니다.
ProcessMessageDelivery는 안정적인 메시지 정체성과 Approval Case id 같은
선택 외부 참조도 운반합니다. 새 identity는 모두
ProcessMessageIdentity::forEvent($appKey, $consumerKey, $eventIdentity)로
만드세요. wire 형태는 app.consumer:event-identity이고 전체 길이는 190
byte로 제한됩니다. 일치하는 전달은 한 번 소비되고, 일찍 온 전달은 대기하며,
중복은 AlreadyConsumed를 돌려주고, 불일치 correlation은 token을 전진시키지
않고 거절됩니다. rejected 메시지는 불변 증거로 남습니다. 연결 상태를 고친 뒤
그 저장 메시지를 다시 검증하거나, 증거 자체가 틀렸다면 새 정정 이벤트를
발행하세요.
라이프사이클 이벤트 시작의 businessKey를 추측하지 마세요. Core의 이벤트
시작 key 파생은 비공개 런타임 동작입니다. App이 인스턴스를 시작하고 자기가
공급한 key를 저장한 경우에만 정확한 값을 보내고, 그 외에는 SDK 결과가
권위 있는 값을 주지 않았다면 null을 보냅니다.
자동 라이프사이클 시작에는 공개 Resource 라이프사이클 이벤트를 선언하고,
BPMN StartEvent에서 그 이벤트를 선택한 다음, App 상태 변경과 같은 트랜잭션에서
EventPublisher로 이벤트를 발행하세요. EventDraft 호출 예시는 이벤트와 비동기 작업 처리하기을 따릅니다. Core가 이벤트를 소비해 인스턴스를 만듭니다.
한 번만 가능한 상태 전이 전에는 hasPublishedEventStart()를 상태를 바꾸지 않는
가용성 관문으로 사용해, 소비할 게시 프로세스가 없는데 상태만 확정되는 일을 막을
수 있습니다. 이 메서드 자체는 이벤트를 게시하거나 인스턴스를 시작하지 않습니다.
App 의도에 바인딩된 Process를 시작하려면
Nexia\Process\Contracts\ProcessStarter를 해석하고 BoundProcessStart를
전달합니다. 바인딩 키, Legal Entity, 행위자, 정규 ResourceRef, 변수,
정규화된 멱등 키를 공급하세요. Core가 게시된 정의를 고르며 App은 Core
정의나 인스턴스 모델을 import하지 않습니다. 이것은 명시적인 App 명령
capability이지 별도의 BPMN StartEvent 모드가 아닙니다. 라이프사이클 자동화는
앞에서 설명한 Event 시작을 사용합니다.
등록된 App 워커는 ProcessWorkActionResult를 반환합니다. 제출된 Approval이
아직 종결 결과에 이르지 않았다면
ProcessWorkActionResult::waitingForApproval(...)을 반환하세요. Core는 외부
태스크를 완료하지만 같은 BPMN token을 awaiting_approval로 주차합니다.
인스턴스 상세에는 “상신 완료 · 결재 대기”, 상신 시각, 결재 바로가기가
표시됩니다.
영속 결과를 소비한 뒤에도 완료 단계에는 같은 바로가기가 남고, 현지화된
결과와 처리 시각이 표시됩니다. 공통 상세 화면은 worker payload, catalog key,
message identity, topic, broker envelope을 표시하지 않습니다.
종결 메시지 payload는 같은 태스크의 Activity IO를 통해서만 변수로
materialize됩니다. 닫힌 집합이며 현지화된 approval_outcome을 선언하고
dataOutputAssociation으로 프로세스 변수에 매핑한 뒤, 다음 Gateway가 그
target을 읽게 하세요. 승인 경로와 기본 반려·비승인 경로가 각각 최종 노드에
도달하는지 검사해야 합니다. 상신 성공만으로는 Approval E2E 검증이 아닙니다.
Process 영속화와 잠금, BPMN 검증, 영속 메시지 저장, token 전진은 호스트가 소유합니다. App은 정확한 증거를 공급할 뿐 호스트 Process 모델을 갱신하거나 token을 직접 전진시키지 않습니다.
Approval 설정 Preset
App은 AppDescriptorSet에 ApprovalBusinessTemplatePresetDescriptor와
ApprovalRoutePolicyPresetDescriptor를 넣어 편집 가능한 시작점을
제공할 수 있습니다. Preset은 소스 descriptor이지 실제 테넌트 설정이
아닙니다. 권한 있는 Process 작성자가 선택한 조합을 실체화하면 Core가
Legal Entity 소유 레코드를 멱등하게 생성하고 게시·활성화합니다. 행위자는
Approval 템플릿 생성/게시와 결재 정책 생성/활성화 권한을 각각 가져야
합니다. Process 정의 권한은 Approval 관리 권한을 뜻하지 않습니다.
오류
| 메시지 또는 증상 | 원인 | 해결 |
|---|---|---|
kind [X] must be one of: serviceTask, sendTask, receiveTask | 잘못된 kind | 지원되는 kind나 user task 폼 계열 쓰기 |
app_key must be a non-empty string. | 빈 appKey | App key 공급 |
ProcessStartBindingDescriptor X must be non-empty. | 빈 binding 필드 | 모든 안정 binding 식별자 공급 |
Process start binding resource_key must be owned by app_key. | App을 가로지르는 Resource binding | 기여 App이 소유한 Resource만 binding |
start_permission_denied | 현재 행위자에게 binding Permission이 없음 | 현재 Legal Entity에서 정확한 App 소유 Permission 부여 |
ProcessTemplateDescriptor key must be a non-empty string. | 빈 key | 안정적인 키 공급 |
| BPMN 선택기에 동작이 없음 | 발견, 설치, 라이프사이클 관문 | nexia-apps:doctor-package-app 실행 후 설치 상태와 status 확인 |
| 게시된 프로세스가 어떤 태스크에서 실패 | Descriptor가 Removed이거나 App이 비활성화됨 | Descriptor 복원 또는 App 재활성화 |
| 라벨이 일반 업무 용어로만 보임 | 로케일 항목 누락 | resources/lang/{locale}.json에 키 추가. 내부 키는 의도적으로 숨김 |
Process message identity must use the namespaced form… | raw 또는 namespace 없는 이벤트 id | ProcessMessageIdentity::forEvent()로 생성 |
Receive-task correlation identifiers must be non-blank and normalized. | Instance·element·topic·business key가 비었거나 공백으로 둘러싸임 | 정확히 정규화된 routing 식별자 전달 |
실제 사용
packages/people/src/Descriptors/PeopleOnboardingProcessDescriptors.php는 실제
시작 binding, Process template, user-task form, Work Action을 기여합니다.
packages/people/src/PeopleCoreServiceProvider.php는
ProcessWorkActionRegistrar를 통해 service-action handler를 등록합니다.
People은 onboarding에 ProcessStarter를 해석하고 Grants와 PSA는
ProcessRuntime을 해석해 현재 인스턴스를 검사하며 Approval 결과를 정확히
대기 중인 receive task에 correlation합니다. 어느 패키지도 호스트 Process
모델을 import하거나 갱신하지 않습니다.
리소스 대상과 사용자 입력
업무 액션의 resourceInputs에 허용할 리소스 키·역할·필수 여부·단일 또는 복수 참조를 선언합니다. targetResourceInput은 단일 참조를 업무 대상으로 선택합니다. Core는 실행 시 현재 범위·App 사용 가능 여부·실행자 권한을 검사합니다. 참조 자체는 권한이 아닙니다. 호출에는 최초 업무 대상도 별도로 유지되므로 후속 대상이 바뀌어도 Process의 원래 상관관계는 보존됩니다.
기존 Activity IO 매핑으로 결과 참조를 다음 업무에 연결합니다. 사용자 입력 폼은 매핑된 값을 초기값으로 받습니다. nexia:userTaskForm.editableFields로 수정 가능한 스키마 필드를 제한할 수 있으며, 생략하면 모두 수정 가능합니다. 실행 시 고정 필드 변경을 거부하고 필수 입력도 검사합니다. 에디터는 업무 앞에 순수 입력 폼을 삽입할 수 있습니다. 폼의 제출 자체가 업무를 실행하는 경우 별도의 실행 Task를 중복 추가하지 않습니다.
installByDefault를 명시한 템플릿은 기존 배포 수명주기로 사용 가능한 법인에 설치됩니다. 반복 설치는 중복을 만들지 않고 원본 버전과 회사 수정본을 보존하며, 회사가 중단한 기본 프로세스를 다시 활성화하지 않습니다. 목록은 의존성·설정 부족과 활성·중단 상태를 구분합니다. 프로비저닝 시 담당자나 결재 구성을 임의로 만들지 않습니다. 새 기본 템플릿은 적용 가능한 업데이트로 표시하며 기존 실행 정의를 자동 교체하지 않습니다.
관련 문서
- 업무 프로세스 — 이 계열들 사이에서 고르기
- 전자 결재 계약 — Approval 바인딩 계열
- 확장 모델 — 개념으로서의 descriptor 라이프사이클
- 업무 프로세스·전자 결재 문제 해결 — 사용할 수 없는 descriptor 진단
Payload schema의 deprecated: true 필드는 기존 정의에서 계속 검증하지만 새 작성용 카탈로그에는 노출하지 않습니다. 기존 값을 보존해야 하는 폐기 설정에 사용하며, 실행 중인 정의를 이전하기 전에 해당 값의 실행 처리를 제거하지 않습니다.