Portfolio showcase project. BrightClause is a demonstration of full-stack delivery, not a commercial product and not a maintained service. The live demo at brightclause.com runs on real contract data - three public filings - and is free to explore, no sign-up. The code is MIT licensed: fork it, adapt it, self-host it. Issues and PRs are welcome but may not get a response. See Known Issues before building on it.
BrightClause transforms contract review from weeks to minutes. Upload PDFs, extract key clauses with AI, assess risk levels, compare documents side-by-side, and explore entity relationships through an interactive knowledge graph. Enhanced reading and analysis for any commercial contract.
| Feature | Description |
|---|---|
| 4-Tier OCR | PyMuPDF, Tesseract, PaddleOCR, Vision LLM fallback |
| Clause Extraction | 16 clause types with AI-powered risk scoring |
| BYOK Extraction | Bring Your Own Anthropic API key — upload any document and extract clauses on demand |
| Contract Q&A Chat | RAG-powered chat — ask questions about any document in natural language |
| Plain-English Translator | One-click clause explanation in simple, non-legal language |
| Executive Reports | AI-generated executive summaries with risk overview and recommendations |
| Timeline Extraction | Automatic extraction and visualization of key contract dates |
| Cross-Document Entities | Entity resolution across your entire document portfolio |
| Obligation Tracker | AI extracts obligations, parties, and deadlines with status tracking |
| Deal Grouping | Group contracts into deals for aggregate risk analysis |
| Knowledge Graph | Entity extraction with interactive relationship visualization |
| Hybrid Search | Semantic + keyword search with configurable weights |
| Risk Assessment | 4-level scoring (Critical, High, Medium, Low) |
| Document Comparison | Side-by-side risk and clause comparison matrix |
| PDF Viewer | In-app PDF display with clause navigation sidebar |
| Dark/Light Mode | Full theme toggle with localStorage persistence |
| Activity Feed | Audit log tracking uploads, analysis, chat, and exports |
| Multi-Format Export | Excel, Word, PDF, CSV, JSON |
Recorded against the running application with real contract data - three public filings (an NDA, a SaaS licence, and a business acquisition agreement).
Select any contract to get an instant risk breakdown: severity counts across four tiers, plus the specific clauses flagged for attention.
A risk heatmap across clause type and document, a portfolio health score, and clause distribution over the whole corpus.
Per-document risk assessment, an extracted contract timeline, and clause filtering by type - each clause with a plain-English summary and a risk badge.
Entities and relationships extracted from a single contract, laid out as an interactive force-directed graph and colour-coded by entity type.
%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#0f172a', 'primaryTextColor': '#e2e8f0', 'primaryBorderColor': '#c9a227', 'lineColor': '#c9a227', 'secondaryColor': '#1e293b', 'tertiaryColor': '#0f1f2e'}}}%%
flowchart TD
classDef fe fill:#0f1f3d,stroke:#60a5fa,color:#93c5fd
classDef be fill:#0a2520,stroke:#34d399,color:#6ee7b7
classDef store fill:#1c1400,stroke:#c9a227,color:#fcd34d
classDef ai fill:#2d1200,stroke:#f97316,color:#fdba74
classDef task fill:#1a0f2e,stroke:#a78bfa,color:#c4b5fd
subgraph FE["🖥 Next.js 14 · TypeScript · TailwindCSS"]
direction LR
Dashboard["Dashboard"]:::fe
DocDetail["Document\nAnalysis"]:::fe
Compare["Compare\nMatrix"]:::fe
Analytics["Portfolio\nAnalytics"]:::fe
Search["Hybrid\nSearch"]:::fe
Deals["Deals"]:::fe
Obligations["Obligations"]:::fe
KG["Knowledge\nGraph"]:::fe
end
Dashboard & DocDetail & Compare & Analytics & Search & Deals & Obligations & KG -->|"Next.js /api/* proxy"| BE
subgraph BE["⚡ FastAPI · Python · SQLAlchemy 2.0 · Celery"]
direction LR
DocsAPI["Documents"]:::be
AnalysisAPI["Analysis\n+ BYOK"]:::be
SearchAPI["Search"]:::be
ChatAPI["RAG Chat"]:::be
GraphAPI["Graph"]:::be
DealsAPI["Deals"]:::be
end
DocsAPI & AnalysisAPI & SearchAPI & ChatAPI & GraphAPI & DealsAPI --> PG[("🗄 PostgreSQL\n+ pgvector")]:::store
DocsAPI --> MinIO[("📦 MinIO\nS3 Storage")]:::store
AnalysisAPI & ChatAPI --> OllamaNode(["🤖 Ollama\nllama3.2"]):::ai
AnalysisAPI & ChatAPI --> ClaudeNode(["✨ Claude API\nBYOK · Haiku"]):::ai
PG --> Redis[("⚡ Redis")]:::task
Redis --> CeleryNode["⚙ Celery\nWorkers"]:::task
%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#0f172a', 'primaryTextColor': '#e2e8f0', 'primaryBorderColor': '#c9a227', 'lineColor': '#94a3b8'}}}%%
flowchart TD
classDef upload fill:#0f1f3d,stroke:#60a5fa,color:#93c5fd,font-weight:bold
classDef ocr fill:#0a2520,stroke:#34d399,color:#6ee7b7
classDef embed fill:#1c1400,stroke:#c9a227,color:#fcd34d,font-weight:bold
classDef clause fill:#2d1200,stroke:#f97316,color:#fdba74,font-weight:bold
classDef entity fill:#1a0f2e,stroke:#a78bfa,color:#c4b5fd,font-weight:bold
classDef risk fill:#2d0f0f,stroke:#ef4444,color:#fca5a5,font-weight:bold
classDef kg fill:#0a2520,stroke:#10b981,color:#6ee7b7,font-weight:bold
Upload(["📄 Upload PDF"]):::upload --> OCR
subgraph OCR["4-Tier OCR Pipeline - confidence-threshold fallback"]
T0["Tier 0 PyMuPDF\nnative PDF text"]:::ocr
T1["Tier 1 Tesseract\nclean scans"]:::ocr
T2["Tier 2 PaddleOCR\ncomplex layouts"]:::ocr
T3["Tier 3 Vision LLM\nhandwriting / damaged"]:::ocr
T0 -.->|fallback| T1 -.->|fallback| T2 -.->|fallback| T3
end
OCR --> Chunk["✂ Chunking\n6 000 chars · 600 overlap\nSemantic boundary preservation"]:::embed
Chunk --> Embed["🔢 Vector Embeddings\nnomic-embed-text · 768 dims · IVFFlat"]:::embed
Embed --> Clauses["📋 Clause Extraction\n16 types via LLM"]:::clause
Embed --> Entities["🔗 Entity Extraction\nparties · dates · amounts · locations"]:::entity
Clauses --> Risk["⚠ Risk Assessment\nCritical · High · Medium · Low"]:::risk
Entities --> KGraph["🕸 Knowledge Graph\ninteractive relationship visualization"]:::kg
| Technology | Purpose |
|---|---|
| FastAPI | Async Python web framework |
| PostgreSQL + pgvector | Vector database for semantic search |
| SQLAlchemy 2.0 | Async ORM with eager loading |
| Celery + Redis | Background task processing |
| MinIO | S3-compatible object storage |
| Ollama | Local LLM inference (llama3.2, nomic-embed-text) |
| Claude API (BYOK) | Per-request Anthropic API key for cloud-quality extraction without server-side cost |
| Technology | Purpose |
|---|---|
| Next.js 14 | React framework with App Router |
| TypeScript | Type safety |
| TailwindCSS | Utility-first styling on the v3 design-token system (dark + light) |
| Framer Motion | Page transitions & entrance animations |
| Playwright | Cross-browser E2E testing (Chrome, Firefox, WebKit) |
- Hybrid search is broken.
POST /api/searchfails for every query in all three modes (hybrid, semantic, keyword). The raw SQL in the search service hitsasyncpg.exceptions.PostgresSyntaxError: syntax error at or near ":"- a::vectorcast being parsed as a SQLAlchemy named bind parameter. The UI reports this as "No Results Found" rather than surfacing the error, so it looks empty rather than broken. Everything else in the feature table works; this one needs the cast escaped or the query moved to bound parameters.
- Docker & Docker Compose
- Node.js 18+
- 8GB RAM minimum (for Ollama)
git clone https://github.com/m4cd4r4/BrightClause.git
cd BrightClause
# Start all backend services
docker-compose up -d
# Pull required Ollama models
docker exec brightclause-ollama ollama pull llama3.2
docker exec brightclause-ollama ollama pull nomic-embed-textcd frontend
npm install
npm run dev| Service | URL |
|---|---|
| Frontend (local) | http://localhost:3000 |
| Frontend (prod) | https://brightclause.com |
| API Docs (local) | http://localhost:8002/docs |
| API (self-hosted) | http://localhost:8002 |
| MinIO Console | http://localhost:9001 |
| Method | Endpoint | Description |
|---|---|---|
POST |
/documents/upload |
Upload PDF contract |
GET |
/documents |
List all documents |
GET |
/documents/{id} |
Get document details |
GET |
/documents/{id}/download-url |
Presigned PDF download URL |
PATCH |
/documents/{id} |
Rename document |
DELETE |
/documents/{id} |
Delete document |
GET |
/documents/{id}/chunks |
Get text chunks |
| Method | Endpoint | Description |
|---|---|---|
POST |
/chat/{id} |
Ask a question about a document |
Accepts question and history array. Returns AI answer with source chunk citations.
| Method | Endpoint | Description |
|---|---|---|
GET |
/search?q={query} |
Hybrid semantic + keyword search |
GET |
/search/stats |
Index statistics |
Parameters: limit, mode (hybrid/semantic/keyword), document_id, semantic_weight
| Method | Endpoint | Description |
|---|---|---|
POST |
/analysis/{id}/extract |
Trigger clause extraction (optional body: {"claude_api_key": "sk-ant-..."}) |
POST |
/analysis/{id}/report |
Generate AI executive summary |
POST |
/analysis/{id}/clauses/{clause_id}/explain |
Plain-English clause explanation |
POST |
/analysis/{id}/obligations/extract |
AI obligation extraction |
GET |
/analysis/{id}/obligations |
List obligations for document |
GET |
/analysis/obligations/all |
Cross-document obligation list |
GET |
/analysis/{id}/summary |
Get risk summary |
GET |
/analysis/{id}/clauses |
Get extracted clauses (with page numbers) |
GET |
/analysis/clause-types |
List clause types |
BYOK Extraction: Pass claude_api_key in the request body to use Claude (Haiku) instead of the local Ollama model. The key is never stored server-side — it is used only for the duration of the request.
curl -X POST http://localhost:8002/analysis/{id}/extract \
-H "Content-Type: application/json" \
-d '{"claude_api_key": "sk-ant-api03-..."}'| Method | Endpoint | Description |
|---|---|---|
POST |
/graph/{id}/extract |
Trigger entity extraction |
GET |
/graph/{id} |
Get graph nodes & edges |
GET |
/graph/{id}/entities |
Get entities by type |
GET |
/graph/{id}/timeline |
Extract timeline events |
GET |
/graph/cross-reference |
Cross-document entity resolution |
GET |
/graph/stats |
Graph statistics |
GET |
/graph/types |
Entity & relationship types |
| Method | Endpoint | Description |
|---|---|---|
POST |
/deals |
Create a deal |
GET |
/deals |
List all deals |
GET |
/deals/{id} |
Deal detail with aggregate risk |
POST |
/deals/{id}/documents |
Add documents to deal |
DELETE |
/deals/{id}/documents/{doc_id} |
Remove document from deal |
POST |
/deals/{id}/upload |
Batch upload to deal |
DELETE |
/deals/{id} |
Delete deal |
| Method | Endpoint | Description |
|---|---|---|
GET |
/activity |
Recent activity feed (audit log) |
| Category | Types |
|---|---|
| Deal Terms | Change of Control, Assignment, Exclusivity |
| IP & Data | IP Ownership, Confidentiality, Data Privacy |
| Liability | Indemnification, Limitation of Liability, Warranty |
| Term | Termination, Renewal, Notice Periods |
| Competition | Non-Compete, Non-Solicitation |
| Financial | Payment Terms, Audit Rights, Insurance |
| Compliance | Governing Law, Dispute Resolution, Force Majeure |
| Level | Color | Trigger Examples |
|---|---|---|
| Critical | Red | Automatic termination, uncapped liability, IP transfer |
| High | Orange | Consent required, gross negligence, material restrictions |
| Medium | Amber | 30-day notice, standard indemnification |
| Low | Green | Market-standard terms, reasonable limitations |
BrightClause/
├── backend/
│ ├── app/
│ │ ├── api/ # Route handlers
│ │ │ ├── documents.py # Upload, list, download, delete
│ │ │ ├── search.py # Hybrid vector search
│ │ │ ├── analysis.py # Extraction, reports, obligations
│ │ │ ├── graph.py # Knowledge graph, timeline, cross-ref
│ │ │ ├── chat.py # RAG Q&A
│ │ │ ├── deals.py # Deal management
│ │ │ ├── activity.py # Audit log
│ │ │ └── health.py
│ │ ├── core/ # Config, database, auth
│ │ ├── models/ # SQLAlchemy models
│ │ │ ├── document.py # Document, Chunk, Clause, Obligation, Deal
│ │ │ ├── knowledge_graph.py # Entity, Relationship
│ │ │ └── activity.py # Activity audit log
│ │ ├── services/ # Business logic
│ │ │ ├── ocr_pipeline.py # 4-tier OCR
│ │ │ ├── pdf_extractor.py # PDF text extraction
│ │ │ ├── chunking.py # Semantic chunking
│ │ │ ├── embeddings.py # Vector embeddings
│ │ │ ├── clause_extraction.py
│ │ │ ├── entity_extraction.py
│ │ │ ├── hybrid_search.py # Semantic + keyword
│ │ │ └── storage.py # MinIO file storage
│ │ ├── tasks/ # Celery async tasks
│ │ ├── main.py # FastAPI entry point
│ │ └── worker.py # Celery worker
│ └── Dockerfile
├── frontend/
│ ├── src/
│ │ ├── app/
│ │ │ ├── page.tsx # Landing page
│ │ │ ├── hero-visual.tsx # Animated product mockup
│ │ │ ├── layout.tsx # Root layout + ThemeProvider
│ │ │ ├── providers.tsx # Context providers
│ │ │ ├── error.tsx # Error boundary
│ │ │ ├── dashboard/page.tsx # Document management + activity feed
│ │ │ ├── search/page.tsx # Hybrid search
│ │ │ ├── compare/page.tsx # Side-by-side comparison
│ │ │ ├── analytics/page.tsx # Portfolio analytics + cross-ref
│ │ │ ├── obligations/page.tsx # Obligation & deadline tracker
│ │ │ ├── deals/page.tsx # Deal list
│ │ │ ├── deals/[id]/page.tsx # Deal detail + aggregate risk
│ │ │ ├── documents/[id]/page.tsx # Document detail + clauses
│ │ │ ├── documents/[id]/chat-panel.tsx # RAG Q&A sidebar
│ │ │ ├── documents/[id]/pdf-viewer.tsx # PDF viewer + clause nav
│ │ │ ├── documents/[id]/timeline.tsx # Timeline visualization
│ │ │ ├── documents/[id]/graph/page.tsx # Knowledge graph
│ │ │ └── api/[...path]/route.ts # Backend proxy
│ │ └── lib/
│ │ ├── api.ts # Typed API client
│ │ ├── risk.ts # Centralized risk utilities
│ │ ├── toast.tsx # Toast notification system
│ │ ├── navigation.tsx # Shared navigation (7 routes)
│ │ ├── theme.tsx # Dark/light mode provider
│ │ ├── walkthrough.tsx # Guided onboarding
│ │ ├── export.ts # Export (Excel/Word/PDF/CSV/JSON)
│ │ └── export-lazy.ts # Lazy-loaded export deps
│ ├── tests/
│ │ ├── dashboard.spec.ts
│ │ ├── document-detail.spec.ts
│ │ └── knowledge-graph.spec.ts
│ └── next.config.js
├── docker-compose.yml
├── docs/
│ └── DEMO.md
└── README.md
v3 design tokens (dark is the default; a light theme ships via the html.light toggle).
| Token | Value | Usage |
|---|---|---|
--v3-canvas |
#0a0a0c |
Page background |
--v3-panel |
#111114 |
Sidebar / section surfaces |
--v3-card |
#16161a |
Cards, rows |
--v3-accent |
#d4a82d |
Legal gold (primary actions only) |
--v3-risk-critical |
#ef4444 |
Critical risk |
--v3-risk-high |
#f97316 |
High risk |
--v3-risk-medium |
#eab308 |
Medium risk |
--v3-risk-low |
#10b981 |
Low risk |
| Font | Usage |
|---|---|
| Geist Sans | Display & body text |
| Geist Mono | Code, data labels, clause references |
No serif anywhere; two-tier elevation, no glassmorphism.
cd frontend
# Run all E2E tests
npx playwright test
# With Playwright UI
npx playwright test --ui
# Headed mode (visible browser)
npx playwright test --headed# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/brightclause
# Redis
REDIS_URL=redis://localhost:6379/0
# MinIO
MINIO_ENDPOINT=localhost:9000
MINIO_ACCESS_KEY=brightclause
MINIO_SECRET_KEY=brightclause_dev
# Ollama
OLLAMA_URL=http://localhost:11434
LLM_MODEL=llama3.2
EMBEDDING_MODEL=nomic-embed-text
# Processing
CHUNK_SIZE=6000
CHUNK_OVERLAP=600
MAX_FILE_SIZE=52428800
# Optional: Anthropic Claude API (for server-side extraction without BYOK)
# Leave blank to use Ollama for all LLM inference (free, self-hosted)
ANTHROPIC_API_KEY=Public contract datasets for testing:
- CUAD Dataset - 13K labeled clauses
- SEC EDGAR - Public commercial filings
- MAUD Dataset - 152 labeled agreements
- PDF upload with 4-tier OCR pipeline
- Clause extraction with risk scoring (16 clause types)
- Knowledge graph visualization (interactive canvas with zoom/pan/filters)
- Hybrid semantic + keyword search
- E2E test suite with Playwright (Chrome, Firefox, WebKit)
- Production deployment (Vercel frontend + VPS backend)
- Celery async job processing for extraction
- Export to Excel, Word, PDF, CSV, JSON
- Document comparison matrix (side-by-side risk & clause diff)
- Portfolio analytics dashboard
- API proxy layer (hidden backend, server-side API key)
- Animated hero visual with product mockup
- Guided walkthrough & onboarding
- Drag-and-drop upload with inline rename
- Centralized risk utilities & toast notifications
- Clause source tracking (page number & chunk index)
- Contract Q&A Chat (RAG with source citations)
- Plain-English clause translator
- AI executive summary report generation
- Timeline extraction and visualization
- Cross-document entity resolution
- Dark/light mode with theme toggle
- Activity feed / audit log
- Obligation & deadline tracker
- Deal grouping with aggregate risk analysis
- In-app PDF viewer with clause navigation
- BYOK (Bring Your Own Key) — Claude API extraction per-request, key stored in sessionStorage only
- v3 design-system reskin across every surface (Geist, four-tier dark + light theme)
- Mobile-responsive app shell (off-canvas drawer) and per-page reflow incl. an accordion analytics heatmap
- Overlay accessibility — focus-trapped drawer/command-palette/cinema, background
inert, reduced-motion respected
- Browser-only privacy mode (pdf.js + WebLLM, no server required)
- Custom extraction templates
- Playbook compliance checking
- Multi-user auth & role-based access
MIT License - See LICENSE for details.
Macdara — GitHub
Built with enterprise-grade engineering practices to demonstrate production AI/ML systems.





