@excelium-tech/contract-approval
v0.2.15
Published
AI contract review and role-enforced approval workflow for Twenty Opportunities
Readme
Contract Approval
AI contract review plus a role-enforced approval workflow for Twenty Opportunities.
A salesperson creates a Contract linked to an Opportunity, attaches the contract PDF, and submits it for review. An AI review reads the PDF and flags risky or inconsistent clauses — notably a customer-vs-supplier payment-terms mismatch (e.g. the customer pays monthly while the supplier must be paid in a single upfront installment). Managers/partners (Gerente/Sócio) then approve or reject, and only that role can approve.
What it installs
- Contract (custom object, related to Opportunity): payment terms (customer/supplier), lifecycle
status, AI review summary, structured AI findings,aiPaymentMismatch, approver, submitter, and timestamps. The contract PDF attaches to the Contract via the native Attachment relation. - Approval Decision (custom object, child of Contract): the append-only audit of who decided what, when, and why (
decidedBy,decision,comment,decidedAt). - Gerente/Sócio role: assignable to users; the record-decision function checks this role before accepting an approval. A declarative field-permission on
Contract.statusis shipped as defense-in-depth. - Logic functions:
ai-review,submit-for-review, andrecord-decision(all route-auth'd), plus a no-oppost-install. - Front-component actions on a Contract: Submit for review, Approve, Reject.
- Pending approvals view: contracts with
status = pending_manager_approval— the manager's work queue.
How it works
- Submit for review sets
status = pending_ai_review, records the submitter, then runs the AI review directly (no workflow required). - AI review fetches the Contract's most-recent PDF attachment (signed URL), sends it to the Anthropic Messages API as a
documentblock with a broad clause-review prompt, writes backaiReviewSummary/aiFindings/aiPaymentMismatch, and advancesstatus = pending_manager_approval. - Approve / Reject calls the route-auth'd
record-decisionfunction, which resolves the invoking user and verifies they hold the Gerente/Sócio role before writing an Approval Decision (decidedBy= the actor) and updating the contract. A non-manager attempt is refused with a clear message and nothing is written.
Setup
- Install the app.
- In Settings → Apps, set
ANTHROPIC_API_KEY(required for AI review). Optionally setLLM_MODEL(defaults to a multimodal Claude model). Without the key, the AI step degrades gracefully: it writes a "not configured" summary and the contract awaits manual manager review. - Assign the Gerente/Sócio role to the members who may approve.
Graceful degradation
- No LLM key → AI review writes a "not configured" summary and leaves the status for manual review.
- No downloadable PDF → the AI review falls back to the structured payment-terms fields.
Development
yarn install
yarn twenty dev:build
yarn typecheck
yarn lint
yarn test # unit tests (offline, fixtures/mocks)Regenerate all universal identifiers:
node scripts/generate-universal-identifiers.mjsNotes / out of scope
- Live-instance validation (real PDF → LLM round trip, front-component→route end-user auth, install-time workflow seeding) is deferred; unit tests use mocks.
- Email notifications require a connected account and are not install-seedable; the pending-approvals view is the notification surface.
