Close out the signing lifecycle — notices, routing, guards, expiry

FixESigService
Ya
7 Agosti 2026, 06:51 UTC
Mwandishi
Kamo
Ahadi ya
d8bc8c4

Everything after a signer presses Finish was incomplete. Notices: an envelope's last signature produced a flattened PDF in MinIO that only the final signer ever saw a link to, for the four hours their session lived. Earlier signers and the sender learned nothing, while the signer app told every one of them a signed copy would be emailed. Adds EsignNotificationService: each party's executed copy (re-minting their access token and extending it to a stated 90-day window), the sender's completion notice, and the decoder / void / expiry notices. Every send is deferred to afterCommit — mail cannot be recalled if the signing transaction rolls back. Routing order: SigningSession reported SEQUENTIAL whenever the roster carried distinct routing orders, and nothing enforced it — every recipient was emailed at once and any of them could sign at any time. EsignRouting now decides the open tier; the initial send invites only that tier, a signature that moves it invites the next, and an out-of-turn submit is a 409. Guards: a DELEGATED recipient could still sign the slot they had just reassigned; decoder() had no terminal-state check at all, so a party who had already signed could flip themselves to DEcoderD on an executed envelope; delegate() could add a live recipient to a closed one. A decoder now closes the envelope rather than leaving the remaining parties signing something envelopeComplete can never call complete. Expiry: EsignEnvelopeStatus.EXPIRED existed, had a UI chip, and was never written by any code path. Adds EsignExpirySweeper (+ @EnableScheduling). Also: the step-up OTP was six digits with unlimited attempts against a four-hour session — now attempt-capped and compared in constant time; a failed resend answered 200 ("Invite resent" for mail that never left); the sender's covering message was never persisted, so a resend and every tier-advance invitation dropped it and session.message was always null; **************** pointed inside the signer app's own BFF where no sender-side consumer could call it; a template with no fields at all could be sent and "signed"; and ResponseStatusException reasons never reached the client, so every carefully worded refusal arrived as a bare status code. 103 -> 140 tests, 0 failures.

Mabadiliko yote

Je, unaona nini kuhusu usafiri?

Kila moja ya hizi updates ardhi katika nafasi yako ya kazi moja kwa moja. Kuanza bure na kuangalia kukua wiki baada ya wiki.

Kuwa Huru MileleMtazamo wa bei