Audience: Admins, Authors, Reviewers, Compliance
Outcomes: Policy-compliant counterparties; auditable collaboration
Parties & counterparties
type BuyerRef = | { kind: "internal"; id: number } | { kind: "external"; email: string; name?: string }; function getBuyerRef(body: any): BuyerRef { if (body.buyerId) return { kind: "internal", id: Number(body.buyerId) }; if (body.buyerEmail) return { kind: "external", email: String(body.buyerEmail), name: body.buyerName || undefined }; throw new Error("buyerId or buyerEmail is required"); }
Internal buyer in another org requires a partner link; missing ⇒
403
Assign authorized signers per party; optional signing order
Anti-patterns
Group inbox as legal signer
Missing authorization chain
Review workflow
# Send for review curl -X POST $API_BASE/api/contracts/draft/send-for-review -b cookies.txt \ -H 'Content-Type: application/json' \ -d '{ "title":"Design SOW","currency":"USD","value":"1500.00","parties":["[email protected]","[email protected]"] }' # Approve / Reject with notes curl -X POST $API_BASE/api/contracts/draft/draft_123/respond -b cookies.txt \ -H 'Content-Type: application/json' -d '{"action":"approve","message":"Looks good"}'
Status:
pending_review
→approved
orrejected
Features: inline comments, change requests (blocking/non-blocking), deadlines & reminders
Approvals & policy engine
Typical rules:
Amount > X ⇒ Owner approval
New counterparty ⇒ extra review
KYC verified for initiator
Mandatory clauses present (IP, liability, confidentiality)
Middleware chain
app.post('/api/contracts/blockchain', sessionAuth, enforceKyc('contract_creation'), enforceApprovalMatrix(), // thresholds, roles verifyMandatoryClauses(), // must-have clauses async (req, res) => { /* create + return signatureRequest */ } );
QA checklist
Missing partner link ⇒
403
with guidance to invite partnerReviewer cannot edit mandatory clauses
Approval matrix blocks activation when thresholds unmet
Runbook: “Review stuck; no responses”
Nudge via reminders; reassign reviewer; set hard deadline with auto-reject