본문으로 건너뛰기

예제

전자 서명에 기여하기

Workshop Note 이름을 전자 서명 Template 편집기에 나타나는 App 소유 데이터 소스로 게시합니다.

예제 유형 레시피

개요

전자 서명에 기여하기 예제

이 예제는 같은 Workshop Note의 이름을 전자 서명 문서에 자동 입력할 수 있는 App 데이터 필드로 게시합니다. 다른 App의 근로계약이나 자산을 끌어오지 않고, first-app → resource-generator → contributor → descriptor에서 만든 Workshop 흐름을 그대로 이어갑니다.

이 작업이 끝나면

생기는 것확인 위치
NoteFieldsV1SignatureDocumentDataSourceWorkshop의 정적 서명 데이터 계약
fail-closed Provider skeleton실제 Note 값을 재인가·조회할 App 구현 위치
노트 이름 자동 입력 필드전자 서명 → 전자 서명 양식 → 양식 만들기 → 서명자 → 필드 추가

Workshop 노트 이름 App 데이터 필드

위 화면은 생성된 descriptor와 locale를 적용한 실제 결과입니다. 필드 추가에서 App: Workshop, 리소스: Workshop 노트, 필드: 노트 이름을 선택할 수 있습니다. Example NoteFieldsV1 value는 양식 작성 중에만 쓰는 synthetic sample입니다.

어떤 계약을 구현하고 Core가 어떻게 받는가

Generator는 상속용 Core 클래스를 만들지 않고 서로 역할이 다른 두 SDK 계약을 구현합니다.

생성 클래스구현하는 SDK 계약역할
NoteFieldsV1SignatureDocumentDataSourceSignatureDocumentDataSourceContribution정적 descriptor와 runtime Provider를 한 소유자로 게시
NoteFieldsV1SignatureDocumentDataSourceProviderSignatureDocumentDataSourceProvideractor·subject가 포함된 query를 받아 실제 Note 값을 재인가·조회

SignatureDocumentDataSourceContribution은 AppDescriptorContribution을 확장하므로 생성 클래스는 appDescriptors()와 signatureDocumentDataSourceProviders()를 모두 제공합니다. Core는 container로 contribution을 만들기 때문에 생성자에 주입된 Provider도 받을 수 있습니다.

NexiaContributionRegistry가 SignatureDocumentDataSourceContribution 발견
  ├─ AppDescriptorCatalog가 appDescriptors()의 정적 source/field 계약 수집
  └─ SignatureDocumentDataSourceRegistry가 Provider 목록 수집
       → appKey + sourceKey + sourceVersion과 기여 소유권이 정확히 같은지 pairing
       ├─ 양식 작성: CatalogController가 정적 descriptor와 synthetic sample 전달
       └─ 요청 준비: RuntimeExecutor가 tenant context와 계약을 검사한 뒤
                    Provider::resolve(query)를 제한 시간 안에 호출하고 결과를 검증

따라서 필드가 화면에 보이는 것과 실제 Note 값이 채워지는 것은 다른 단계입니다. 정적 descriptor만으로 authoring 선택지는 만들 수 있지만, runtime Provider가 fail-closed 상태라면 실제 요청 준비에서는 값을 내보내지 않습니다.

1. 생성 결과 미리 보기

포함된 스크립트는 기본적으로 dry run입니다.

코드 예시
Shell
sh docs/developers/examples/electronic-signature-contribution/commands.sh

두 파일의 WOULD CREATE가 보여야 합니다.

packages/workshop/src/Descriptors/NoteFieldsV1SignatureDocumentDataSource.php
packages/workshop/src/Signature/NoteFieldsV1SignatureDocumentDataSourceProvider.php

검토한 뒤에만 실제 파일을 생성합니다.

코드 예시
Shell
WRITE=1 sh docs/developers/examples/electronic-signature-contribution/commands.sh

이 명령은 subject와 source를 모두 workshop.note로 지정하고, direct-subject lookup으로 하나의 name 문자열을 제공하는 계약을 만듭니다. Generator는 모델이나 DB column을 추론하지 않습니다.

2. locale 추가

Workshop이 소유한 모든 locale에 같은 key를 추가합니다.

코드 예시
JSON
{
  "workshop.signature_document_data.fields.name": "노트 이름",
  "workshop.signature_document_data.note_fields_v1.label": "Workshop 노트",
  "workshop.signature_document_data.note_fields_v1.description": "전자 서명 문서에 연결된 노트 정보를 제공합니다."
}

Descriptor의 syntheticSample은 정적 catalog 미리 보기용입니다. 여기에는 실데이터나 민감정보를 넣지 않습니다.

3. Provider 구현

생성된 Provider는 의도적으로 Unavailable을 반환합니다. 파일 생성만으로 실제 Note 값이 노출되어서는 안 됩니다. 다음을 모두 구현한 뒤 활성화합니다.

  • Core가 복원한 현재 tenant, Legal Entity, actor 확인
  • 요청의 workshop.note subject ResourceRef 재인가
  • workshop.note.read 권한과 레코드별 Policy 확인
  • 요청 field allowlist와 asOf 적용
  • bounded lookup과 timeout
  • 결과 provenance 및 진단에서 값 제거

Provider는 Note 모델을 App 안에서 조회할 수 있지만, Core 모델이나 다른 App 모델을 import하지 않습니다.

4. 화면과 runtime 차이

필드 추가 dialog는 정적 descriptor와 synthetic sample만 읽으므로 Provider가 아직 fail-closed여도 위 선택지는 보입니다. 실제 값 조회는 전자 서명 요청을 준비할 때 subject와 actor를 복원한 뒤에만 실행됩니다.

양식 작성 시                         요청 준비 시
정적 Descriptor catalog             Runtime Provider
└─ Workshop 노트                     └─ actor·subject 재인가
   └─ 노트 이름 · 예제 값               └─ 허용된 Note 이름 반환

5. 갱신과 확인

코드 예시
Shell
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

Doctor에서 paired Signature document data source가 확인되면 위 캡처 경로에서 필드 추가를 열어 Workshop을 선택합니다.

자주 발생하는 오류

증상원인해결다시 확인
명령이 WOULD CREATE만 출력하고 파일이 생기지 않음Generator와 예제 스크립트의 기본 동작은 dry run임출력을 검토한 뒤 WRITE=1 sh docs/developers/examples/electronic-signature-contribution/commands.sh 실행두 대상 파일이 packages/workshop/src/ 아래에 존재
validator가 locale catalog 누락을 보고함생성된 descriptor의 label·description·field key를 Workshop locale에 추가하지 않음모든 resources/lang/{locale}.json에 세 key 추가validator가 locale finding 없이 완료
필드 추가에는 보이지만 요청 준비에서 값이 나오지 않음생성된 Provider가 의도적으로 Unavailable을 반환하는 fail-closed skeleton임actor·subject 재인가, field allowlist, bounded lookup과 provenance를 구현요청 준비에서 허용된 Note 이름과 provenance가 반환됨
Doctor가 paired data source를 찾지 못함정적 descriptor와 Provider의 app key, source key 또는 version이 다름양쪽 identity를 같은 workshop source key와 version으로 맞추고 cache 갱신Doctor가 paired Signature document data source를 보고

수정 규칙

변경처리
표시 문구locale 값만 수정하고 version 유지
optional field 추가consumer 호환성을 확인하고 version 검토
type, requiredness, lookup 의미 변경새 source version 게시 후 consumer 이동
source 제거참조 중인 양식·요청을 확인한 뒤 lifecycle 전환

포함된 파일

코드 예시
Shell
#!/usr/bin/env sh
set -eu

task artisan -- nexia-apps:make-package-signature-data-source workshop NoteFieldsV1 \
  --subject-resource-key=workshop.note \
  --source-resource-key=workshop.note \
  --lookup-mode=direct_subject \
  --cardinality=one \
  --min-items=1 \
  --max-items=1 \
  --field-key=name \
  --field-type=string \
  --field-classification=internal \
  --field-formatter=plain

if [ "${WRITE:-0}" != '1' ]; then
  printf '%s\n' 'Dry run complete. Rerun with WRITE=1 to create the two fail-closed skeletons.'
  exit 0
fi

task artisan -- nexia-apps:make-package-signature-data-source workshop NoteFieldsV1 \
  --subject-resource-key=workshop.note \
  --source-resource-key=workshop.note \
  --lookup-mode=direct_subject \
  --cardinality=one \
  --min-items=1 \
  --max-items=1 \
  --field-key=name \
  --field-type=string \
  --field-classification=internal \
  --field-formatter=plain \
  --write

printf '%s\n' 'Skeletons created. Add locale labels and implement authorization and provenance before validation.'