The capstone task — signer decline, end to end
Fifteen lessons, one real deployed application. SignFlow went from an empty main to a document-signing workflow with authentication, an audit trail, and a live URL. This capstone asks you to extend it yourself — to prove the patterns are yours, not just read.
The task: signer decline. Right now a signer can sign. Add the ability to decline — to formally refuse to sign, with a reason — and make a declined document a terminal state, exactly the way a completed one is. This is deliberately symmetric with signing: you already have the perfect template one file over. If you can build decline by applying what sign taught you, you have internalised the track.
What it must do, end to end:
-
A migration. A signer can be
pending,signed, or nowdeclined; a document can bedraft,sent,completed, or nowdeclined. Extend theCHECKconstraints. Add adecline_reason TEXTto the signer (nullable — only declines have one). (ACHECKconstraint can't be altered in place; drop and re-add it in the migration — finding the syntax is part of the exercise.) -
A query.
DeclineSigner, guarded exactly likeSignSigner:UPDATE ... SET status='declined', decline_reason=$2 WHERE id=$1 AND status='pending'(:execrows). Single-use, for the same reason signing is — a spent token declines zero rows. -
A handler, in a transaction. On decline: flip the signer to
declined, flip the document todeclined(one decline ends the whole request — decide and defend that rule), and write an audit event (document.declined,actorSigner) in the same transaction. The document's status transition and the audit row commit together or not at all — the L10–12 pattern exactly. -
A template. A Decline button and a reason field on the signing page, next to Sign. A declined signer sees their declined state on return (idempotent, like signed). The owner's roster and audit trail show the decline and its reason.
-
The constraints honored. The token is still the whole authorization (no document id in the decline request). The audit row is FK-free and survives. The signature caveat still frames what a decline is: evidence that this person refused these exact bytes, nothing more.
Author it from your own verified code — the same discipline the whole track used: write it, compile it, run it, exercise it. When a signer declines, watch the document go declined, the audit trail record it with the reason, and the roster reflect it. That is the capstone: not new concepts, but your hands applying every one of them to a feature that wasn't handed to you.