AI Contract Diligence, Negotiation & Compliance Workspace — built for the Republic of Azerbaijan.
Upload a draft, watch AI extract typed clauses, rule-based + AI-scored risks, redline counter-proposals against your firm's clause library, negotiate per clause with a counterparty, e-sign with an HMAC-chained audit cert that's verifiable by replay. Every citation pins to the actual article of AR Mülki / Vergi / Əmək Məcəlləsi or AR AML/CFT / Personal Data / Copyright law.
Contract draft (PDF/DOCX/text)
↓
Text extraction (pdf-parse / mammoth)
↓
AI clause extractor → Typed clauses (20+ categories)
↓
Rule scanner + AI risk scorer
(regexes) (per-clause)
↓
Risks (severity · category · suggested fix · AR-law citation)
↓
Redline counter (uses firm's clause library)
↓
Per-clause negotiation threads (SSE realtime)
↓
E-signature → HMAC-chained audit log → Verifiable cert
| Layer | What it does |
|---|---|
app/ |
Next.js 15 App Router · React 19 RC · Tailwind ("Chambers" — deep ink navy + ivory + dark teal + oxblood redline + warm gold seal). Light + dark themes. Source Serif 4 for headings + contract body; Inter for UI; JetBrains Mono for citations. |
lib/db.ts |
SQLite (better-sqlite3) WAL + FK + numbered migrations. Multi-tenant by workspace_id. 7 roles. |
lib/auth.ts |
bcrypt + jose JWT 7d cookie. Per-route role gating. Counterparty signing tokens (bcrypt-hashed, 30-day default). |
lib/crypto.ts |
AES-256-GCM via HKDF-derived key (from JWT_SECRET) for AI provider keys + integration secrets. |
lib/legal.ts |
Trilingual AR legal corpus — Civil Code arts. 386, 390-3, 399, 417, 422, 440, 447, 491, 525, 726, 790; Tax Code arts. 101, 105, 125, 159; Labor Code arts. 43, 44, 88, 154; AML/CFT, IP, Personal Data, Anti-Corruption, E-Signature Law. |
lib/clauses.ts |
22-category clause taxonomy. |
lib/risks.ts |
Deterministic rule scanner — unlimited liability, uncapped indemnity, auto-renewal w/o notice, foreign governing law, offshore arbitration, PII without DPA, VAT silence, excessive penalty, broad non-compete, missing force-majeure. |
lib/compliance.ts |
AR rule presets seeded into DB. runComplianceCheck produces deterministic pass/fail findings. |
lib/diff.ts |
LCS-based line diff for redline rendering (<ins> / <del>). |
lib/signature.ts |
HMAC-SHA-256 chained audit log (prev_hash + canonical payload → this_hash). Tampering is detectable via verifyChain(). |
lib/ai/ |
OpenAI + Anthropic SDKs (user-managed keys via Settings UI), unified complete() + streamChat(), seven prompt builders in prompts.ts. |
cp .env.example .env.local # set JWT_SECRET (≥16 chars)
npm install
npm run seed # creates data/praesidio.db with demo data
npm run dev # http://localhost:4949Login: admin@praesidio.az / admin1234 (super_admin).
| Spec area | Where it lives |
|---|---|
| Identity + RBAC (7 roles) | lib/auth.ts · app/api/auth/* · app/login · app/register |
| Multi-tenancy by workspace | workspaces table; every domain table FK'd to it |
| Clients, matters, contracts | app/(app)/clients · /matters · /contracts (8-tab detail) |
| Document ingestion + extraction | app/api/documents · lib/documents.ts (pdf-parse + mammoth) |
| Clause taxonomy + extractor | lib/clauses.ts + app/api/ai/extract-clauses |
| Rule + AI risk scoring | lib/risks.ts + app/api/ai/score-risks |
| Versioning + redline diff | app/api/contracts/[id]/versions · lib/diff.ts |
| Per-clause negotiation threads | app/api/contracts/[id]/threads + /threads/[id]/comments (SSE-broadcast) |
| Obligations + calendar | app/api/contracts/[id]/obligations |
| E-signature + HMAC audit chain | app/api/contracts/[id]/signatures · app/api/signatures/[id]/events · app/api/sign/[token] (public) · lib/signature.ts |
| Compliance engine + report | lib/compliance.ts · app/api/contracts/[id]/compliance · app/api/ai/compliance |
| Clause library | app/(app)/library · app/api/library/* |
| Iuris AI assistant (slide-over) | components/IurisPanel.tsx · app/api/ai/iuris (SSE) |
| Endpoint | What it does |
|---|---|
POST /api/ai/extract-clauses |
AI parses current version → typed clauses + rule-based risks |
POST /api/ai/score-risks |
AI rescores per-clause for nuance beyond the rule scanner |
POST /api/ai/summarize |
One-page executive summary |
POST /api/ai/redline |
Counter-proposal text addressing open risks, using clause library |
POST /api/ai/compliance |
AR-law compliance verdict + citations + accept/sign-with-amendments/don't-sign |
POST /api/ai/qa |
Strict per-contract Q&A — answers only from the contract body |
POST /api/ai/amendment |
Drafts a standalone amendment document |
POST /api/ai/iuris (SSE) |
Streaming workspace assistant — knows the platform + the contract |
All routed through unified complete() / streamChat(). OpenAI default; Anthropic alternative; env-key fallback; dry-run stub when nothing configured.
When a signature request is created:
seq=1 created prev_hash="0" this_hash=HMAC(secret, "0|{…canonical…}")
seq=2 viewed prev_hash=<seq1.this_hash> this_hash=HMAC(secret, prev|"{…}")
seq=3 signed prev_hash=<seq2.this_hash> this_hash=HMAC(secret, prev|"{…}")
seq=N executed prev_hash=<seqN-1.this_hash> this_hash=… ← becomes the cert
verifyChain(signature_id) replays the chain — if anyone tampers with seq=2's payload, seq=3's this_hash won't match the recomputed value, and the chain is flagged invalid at the first bad seq.
- You issue a signature request →
POST /api/contracts/{id}/signatureswithsigners[] - Server mints a
signing_tokenper signer (bcrypt-hashed at rest, 12-char prefix) - You send each signer their URL:
https://your-host/sign/{token} - Signer opens the URL — sees the contract, signs with full-name typed confirmation, both events landing in the HMAC chain
- When the last signer signs → status
executed,cert_hash= final chain hash
- Next.js 15 (App Router) · React 19 RC · TypeScript strict · Tailwind
- better-sqlite3 (WAL + FK) · jose · bcryptjs · pdf-parse · mammoth
- OpenAI SDK + Anthropic SDK · user-managed AES-256-GCM-encrypted keys
- Web:
4949 - DB:
data/praesidio.db(configurable viaPRAESIDIO_DB)
- All code, docs and committed strings in English
- No
window.confirm()—<ConfirmModal>only - No
window.prompt()—<PromptModal>only - AI dual-provider: OpenAI default + Anthropic alternative; keys editable from Settings UI
- Distinct aesthetic per project — Chambers (modern law firm) is unique to Praesidio Lex