Examples
Contribute to Electronic Signature
Publish the Workshop Note name as an App-owned data source in the Signature template editor.
Example type Recipe
Overview
Contribute to Electronic Signature
This recipe publishes the same Workshop Note name as an App-data field
that Electronic Signature documents can fill automatically. It continues the
Workshop story from the earlier recipes.
What appears when you finish
| Result | Where to see it |
|---|---|
NoteFieldsV1SignatureDocumentDataSource | Workshop's static Signature data contract |
| Fail-closed Provider skeleton | App-owned location for authorized Note resolution |
| Note Name automatic field | E-Signature → E-Signature Templates → Create template → Signer → Add field |

This is the actual editor after applying the generated descriptor and locale
entries. Add field offers App: Workshop, Resource: Workshop Note, and
Field: Note Name. Example NoteFieldsV1 value is a synthetic authoring
sample, not tenant data.
Which contracts it implements and how Core receives them
The generator does not create a subclass of a Core class. It creates two classes that implement separate App SDK contracts.
| Generated class | SDK contract | Responsibility |
|---|---|---|
NoteFieldsV1SignatureDocumentDataSource | SignatureDocumentDataSourceContribution | Publishes the static descriptor and runtime Provider under one owner |
NoteFieldsV1SignatureDocumentDataSourceProvider | SignatureDocumentDataSourceProvider | Receives a query containing actor and subject context, then reauthorizes and resolves the real Note value |
SignatureDocumentDataSourceContribution extends
AppDescriptorContribution, so the generated contribution provides both
appDescriptors() and signatureDocumentDataSourceProviders(). Core resolves
the contribution through its container, allowing it to receive the generated
Provider through constructor injection.
NexiaContributionRegistry discovers SignatureDocumentDataSourceContribution
├─ AppDescriptorCatalog collects the static source and field contract
└─ SignatureDocumentDataSourceRegistry collects Providers
→ pairs exact appKey + sourceKey + sourceVersion and contribution ownership
├─ Template authoring: CatalogController returns descriptor + synthetic sample
└─ Request preparation: RuntimeExecutor checks tenant context and contract,
invokes Provider::resolve(query) within a deadline,
then validates the returned result
The field appearing in the editor and a real Note value being filled are therefore separate stages. A static descriptor can create the authoring choice, but a fail-closed runtime Provider returns no value during request preparation.
1. Preview generation
The included script is a dry run by default:
sh docs/developers/examples/electronic-signature-contribution/commands.shExpect two WOULD CREATE targets:
packages/workshop/src/Descriptors/NoteFieldsV1SignatureDocumentDataSource.php
packages/workshop/src/Signature/NoteFieldsV1SignatureDocumentDataSourceProvider.php
Write them only after reviewing the preview:
WRITE=1 sh docs/developers/examples/electronic-signature-contribution/commands.shThe command uses workshop.note as both subject and source, direct-subject
lookup, cardinality one, and a string name field. The generator never infers
a model or database column.
2. Add locale entries
Add the exact same keys to every locale owned by Workshop:
{
"workshop.signature_document_data.fields.name": "Note name",
"workshop.signature_document_data.note_fields_v1.label": "Workshop Note",
"workshop.signature_document_data.note_fields_v1.description": "Provides the linked Note to an Electronic Signature document."
}The descriptor's syntheticSample is only for the static authoring catalog.
Never put real or sensitive data there.
3. Implement the Provider
The generated Provider intentionally returns Unavailable. Generating files
must not expose real Note values. Before activation, implement all of these:
- verify the Core-restored tenant, Legal Entity, and actor;
- reauthorize the requested
workshop.notesubjectResourceRef; - check
workshop.note.readand record-level Policy; - enforce the requested-field allowlist and
asOfinstant; - bound the lookup and timeout;
- return provenance and keep values out of diagnostics.
The Provider may query the Note model inside Workshop. It must not import a Core model or another App model.
4. Understand authoring versus runtime
The Add field dialog reads only the static descriptor and synthetic sample, so the choice appears while the generated Provider still fails closed. Real values resolve only during request preparation after Core restores subject and actor context.
Template authoring Request preparation
Static Descriptor catalog Runtime Provider
└─ Workshop Note └─ reauthorize actor and subject
└─ Note Name · sample └─ return the allowed Note name
5. Refresh and inspect
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-ansiAfter Doctor reports a paired Signature document data source, open Add field at the screenshot path and select Workshop.
Common errors
| Symptom | Cause | Fix | Confirm |
|---|---|---|---|
The command prints only WOULD CREATE and no files appear | Dry run is the default for both the generator and the example script | Review the preview, then run WRITE=1 sh docs/developers/examples/electronic-signature-contribution/commands.sh | Both target files exist under packages/workshop/src/ |
| Validation reports missing locale catalog entries | The generated descriptor label, description, and field keys were not added to every Workshop locale | Add all three keys to every resources/lang/{locale}.json | Validation completes without a locale finding |
| Add field shows the choice but request preparation returns no value | The generated Provider is a fail-closed skeleton that intentionally returns Unavailable | Implement actor and subject reauthorization, the field allowlist, bounded lookup, and provenance | Request preparation returns the allowed Note name with provenance |
| Doctor does not report a paired data source | The static descriptor and Provider differ in app key, source key, or version | Match both identities to the same workshop source key and version, then refresh caches | Doctor reports a paired Signature document data source |
Revision rules
| Change | Treatment |
|---|---|
| Label wording | Change locale values and keep the version |
| Compatible optional field | Confirm consumer compatibility and review the version |
| Type, requiredness, or lookup meaning | Publish a new source version and migrate consumers |
| Remove the source | Review referencing templates and requests before lifecycle transition |
Included files
#!/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.'