dbp / relay-portfolio-bundle
A template bundle for the Relay API gateway
Package info
github.com/digital-blueprint/relay-portfolio-bundle
Type:symfony-bundle
pkg:composer/dbp/relay-portfolio-bundle
Requires
- php: >=8.2
- ext-json: *
- api-platform/metadata: ^4.2 || ^5.0
- api-platform/openapi: ^4.2 || ^5.0
- dbp/relay-base-person-bundle: ^0.2.44
- dbp/relay-blob-library: ^0.3.11
- dbp/relay-core-bundle: ^0.1.253
- doctrine/collections: ^2.6
- doctrine/dbal: ^3.8 || ^4.0
- doctrine/doctrine-bundle: ^2.12
- doctrine/doctrine-migrations-bundle: ^3.3
- doctrine/migrations: ^3.5
- doctrine/orm: ^2.18 || ^3.2
- psr/log: ^3.0
- symfony/config: ^7.4
- symfony/console: ^7.4
- symfony/dependency-injection: ^7.4
- symfony/framework-bundle: ^7.4
- symfony/http-foundation: ^7.4
- symfony/http-kernel: ^7.4
- symfony/routing: ^7.4
- symfony/serializer: ^7.4
- symfony/translation: ^7.4
- symfony/uid: ^7.4
- twig/twig: ^3.8
Requires (Dev)
- dbp/relay-blob-bundle: ^0.2.16
- friendsofphp/php-cs-fixer: ^3.50
- phpstan/phpstan: ^2.1.17
- phpstan/phpstan-phpunit: ^2.0.6
- phpstan/phpstan-symfony: ^2.0.6
- phpunit/phpunit: ^11.1
- symfony/phpunit-bridge: ^7.0.4
- symfony/runtime: ^7.4
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Signing workflow state
The internal signing state uses schema version 1. Compatibility with earlier internal state layouts is not supported yet. The external signing API's field names are unchanged.
The snapshot has two parts:
jobis the immutable, normalized job definition:signingProcessId, constituent, metadata, original document, attachments, and iteration definitions.statecontains mutable execution results and lifecycle facts: iteration task references and signed documents, cancellation, expiration, and retrieval.
Iteration definitions in job.iterations contain number, kind, and
one participant. Exactly two ordered steps are supported: step 0 is an
internal_approval by an internal person; step 1 is external_signing by an
external person. These internal kinds are translated into API categories only
by SignService. Multiple participants within a step are not supported.
Each state.iterations record has the matching number, one generated taskId,
and its participant's signedDocument. Task IDs must be non-empty and unique
within the workflow. Results are matched by iteration number, not by array
position. Both steps must complete before signing is complete.
Documents consistently use {fileId, filename} references:
job.originalDocumentis the original uploaded PDF.job.attachmentscontains unsigned supporting documents.- Each execution iteration's
signedDocumentisnulluntil completed, then contains its output PDF reference. The current document is derived from completed iterations.
Identity fields have the following meanings:
job.constituentis the requester, not necessarily a signer. Its email, internal person ID and display name are captured at creation in an identity object containingemail,userId, anddisplayName.state.cancelledByuses the same identity object, captured on cancellation, and isnullbefore cancellation. Neither identity carries participant task IDs or locale.- A participant's
userIdis its resolved internal person ID;nullexplicitly denotes an external signer, never an unresolved internal user. - Email and display name are creation-time snapshots.
localeis an optional external signer preference, not an identity attribute.
Signing status is derived, not stored. Cancellation (cancelledAt) takes
precedence over recorded expiration (expiredAt); otherwise, all iterations
having a signedDocument means completion. Remaining jobs are active. The
handler prevents terminal transitions from overwriting each other, and only
SignService translates these facts into signing API status values.
An elapsed job.expirationDate blocks signing immediately but does not itself change
the recorded status. The timeout check records expiredAt and closes the workflow
in one transaction. Successful jobs remain open until their final document is
retrieved. cancelledAt records the first cancellation in UTC and stays unchanged
on retries, together with the cancellation actor. lastRetrievedAt records the
most recent final-document retrieval. Existing database completion timestamps
are not duplicated in this state.
Actions and timeout checks reload workflow state under a database write lock inside their transaction. Duplicate signature actions are rejected without uploading another document; cancellation is idempotent and retrieval is repeatable. Signing after the deadline is rejected even before a timeout check runs, and expiration cannot overwrite a final signing status. The manual expire action records expiration without changing the original job deadline.