AI-Powered Legal Document Auditor built with Django, Django REST Framework, Django Channels, React, Vite, Redis, PostgreSQL, and Docker Compose.
LawPulse is a LegalTech web application for uploading PDF contracts, extracting risky clauses, and reviewing them in a side-by-side interface. The backend parses uploaded PDF files, stores page-level text, extracts potentially risky clauses using a LangChain-backed service with a heuristic fallback, and streams live progress updates over WebSockets. The frontend provides a contract viewer, extracted text panel, clause list, and review form.
This repository follows a strict Windows-first execution path for local development at:
D:\Projects\LawPulse
LawPulse is designed as both a portfolio-grade demonstration of full-stack engineering and a production-oriented reference for document-processing workflows. It showcases:
- backend API design with Django REST Framework
- real-time progress delivery with Django Channels and Redis
- contract-aware frontend behavior with React and TypeScript
- PDF processing and clause extraction workflows
- Docker-based reproducibility across application services
- observable request handling through custom latency headers
- OpenAPI-first documentation through drf-spectacular
This repository demonstrates the following engineering themes:
- API-first backend design with documented endpoints and a root health response
- real-time system behavior through WebSocket status updates during audit execution
- frontend-backend contract awareness through strict TypeScript usage and explicit base URL handling
- operational reproducibility with Docker Compose for frontend, backend, PostgreSQL, and Redis
- development discipline through clear setup instructions and validation checkpoints
- portfolio readiness through screenshot evidence, admin coverage, Swagger visibility, and clean repository structure
Use these versions as the project baseline:
- Python 3.13.12
- Django 5.2
- Node.js 24 LTS
- Redis 7
- PostgreSQL 17
This project includes three critical execution corrections:
-
Python version is fixed to 3.13.12
- Do not use Python 3.12 for this project.
-
Frontend PDF loading uses absolute backend media URLs
- The frontend converts Django media URLs into absolute backend URLs so
react-pdfloads from: http://127.0.0.1:8000/...- instead of incorrectly attempting:
http://127.0.0.1:5173/...
- The frontend converts Django media URLs into absolute backend URLs so
-
A root health endpoint exists at
/http://127.0.0.1:8000/loads successfully and returns a backend health response.
- Django 5.2
- Django REST Framework
- drf-spectacular Swagger / OpenAPI
- Django Channels
- Redis
- React
- Vite
- TypeScript (strict mode)
- PostgreSQL
- LangChain
react-pdf- Docker Compose
- Upload PDF contracts
- Parse contract pages into stored page text
- Extract risky clauses with LangChain-backed logic and heuristic fallback
- Stream live processing updates via WebSockets
- Side-by-side contract viewer and clause review interface
- Review extracted clauses with a structured form
- Custom request latency middleware with
X-Request-Latency-Ms - Swagger / OpenAPI documentation
- Django admin for jobs, pages, and clauses
- Local Windows development workflow
- Full Dockerized stack for frontend, backend, PostgreSQL, and Redis
The Django backend is responsible for:
- receiving uploaded PDF contracts
- extracting and persisting page-level text
- generating audit jobs and risky clause outputs
- exposing REST endpoints for job creation and retrieval
- broadcasting live progress messages over WebSockets
- exposing admin and OpenAPI documentation surfaces
- adding request timing metadata through custom middleware
The React frontend is responsible for:
- uploading source PDF files
- rendering contract pages via
react-pdf - displaying extracted text and risky clause lists
- presenting a review workflow for extracted clauses
- tracking live progress from the WebSocket channel
- handling corrected backend-origin media URLs for PDF rendering
Redis and PostgreSQL support the runtime model:
- Redis supports Channels-backed real-time communication
- PostgreSQL supports containerized relational persistence
- Docker Compose orchestrates the full local stack
D:\Projects\LawPulse
├── .gitignore
├── README.md
├── LICENSE
├── docker-compose.yml
├── docs
│ └── screenshots
│ ├── backend-admin.png
│ ├── backend-response-headers.png
│ ├── backend-swagger-ui.png
│ ├── frontend-completed-view.png
│ ├── frontend-empty-state.png
│ ├── frontend-processing.png
│ └── frontend-selected-clause.png
├── backend
│ ├── .env
│ ├── .env.example
│ ├── Dockerfile
│ ├── manage.py
│ ├── requirements.txt
│ ├── auditor
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── consumers.py
│ │ ├── models.py
│ │ ├── routing.py
│ │ ├── serializers.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ └── services
│ │ ├── __init__.py
│ │ ├── llm.py
│ │ └── pdf_audit.py
│ └── config
│ ├── asgi.py
│ ├── middleware.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── frontend
├── .env
├── Dockerfile
├── package.json
├── tsconfig.app.json
├── vite.config.ts
└── src
├── api.ts
├── App.css
├── App.tsx
├── index.css
├── main.tsx
├── types.ts
└── components
├── PdfViewerPane.tsx
├── RiskForm.tsx
└── RiskList.tsx
For the fastest path, use either the local Windows workflow or the full Docker workflow.
Backend terminal:
cd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
python manage.py runserverFrontend terminal:
cd D:\Projects\LawPulse\frontend
npm run devRedis terminal:
docker start lawpulse-redis-localcd D:\Projects\LawPulse
docker compose up --buildcd D:\Projects\LawPulse
docker compose downIf a terminal command hangs or needs to be interrupted, press:
CTRL + C
Install the following on Windows before starting:
- Python 3.13.12 (64-bit)
- Node.js 24 LTS
- Git for Windows
- Docker Desktop
- Visual Studio Code
Verify tools in PowerShell:
where.exe python
python --version
py -3.13 --version
py --list
node --version
npm --version
git --version
docker --version
docker compose versionSuccess means:
- every command prints a version
py -3.13 --versionworks- Docker Desktop is running
- Python 3.13.12 is visible and usable
- Python 3.12 is not used for this project
Create the project folders:
cd D:\Projects
mkdir LawPulse
cd D:\Projects\LawPulse
mkdir backend
mkdir frontend
mkdir docs
mkdir docs\screenshotsExpected structure:
D:\Projects\LawPulse
├── backend
├── frontend
└── docs
└── screenshots
Initialize the repository:
cd D:\Projects\LawPulse
git init
git branch -M mainCreate root .gitignore:
# OS
.DS_Store
Thumbs.db
# Python
backend/.venv/
backend/__pycache__/
backend/**/__pycache__/
backend/*.sqlite3
backend/db.sqlite3
backend/.pytest_cache/
backend/.mypy_cache/
backend/.ruff_cache/
backend/media/
backend/staticfiles/
# Python env files
backend/.env
# Node
frontend/node_modules/
frontend/dist/
# Frontend env
frontend/.env.local
frontend/.env.*.local
# Root / generic env
.env
.env.*
# VS Code
.vscode/
# Logs
*.log
# Screenshots temp exports
*.tmp.pngcd D:\Projects\LawPulse\backend
py -3.13 -m venv .venv
.\.venv\Scripts\Activate.ps1If PowerShell blocks activation:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
.\.venv\Scripts\Activate.ps1Successful activation shows the prompt prefixed with:
(.venv)
To leave the virtual environment later, run:
deactivateCreate D:\Projects\LawPulse\backend\requirements.txt:
Django>=5.2,<5.3
djangorestframework>=3.16,<3.17
drf-spectacular>=0.28,<0.29
channels>=4.3,<4.4
channels_redis>=4.3,<4.4
daphne>=4.2,<4.3
django-cors-headers>=4.7,<4.8
dj-database-url>=3.0,<3.1
psycopg[binary]>=3.2,<3.3
python-dotenv>=1.1,<1.2
pypdf>=5.4,<5.6
langchain>=0.3,<0.4
langchain-openai>=0.3,<0.4
pydantic>=2.11,<2.12
Install dependencies:
cd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txtValidate the environment:
python -m pip list
python -c "import django; print(django.get_version())"cd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
django-admin startproject config .
python manage.py startapp auditor
mkdir auditor\services
New-Item auditor\services\__init__.py -ItemType Filecd D:\Projects\LawPulse\frontend
npm create vite@latest . -- --template react-ts
npm install
npm install react-pdf pdfjs-dist react-hook-form zod @hookform/resolversConfirm strict TypeScript in frontend\tsconfig.app.json:
"strict": trueOptional validation:
cd D:\Projects\LawPulse\frontend
npm run buildCreate backend\.env.example:
DEBUG=True
SECRET_KEY=django-insecure-change-me
ALLOWED_HOSTS=127.0.0.1,localhost
CORS_ALLOWED_ORIGINS=http://127.0.0.1:5173,http://localhost:5173
DATABASE_URL=sqlite:///D:/Projects/LawPulse/backend/db.sqlite3
REDIS_URL=redis://127.0.0.1:6379/0
LLM_MODEL=gpt-4o-mini
OPENAI_API_KEY=
OPENAI_BASE_URL=Create backend\.env:
DEBUG=True
SECRET_KEY=django-insecure-change-me-now
ALLOWED_HOSTS=127.0.0.1,localhost
CORS_ALLOWED_ORIGINS=http://127.0.0.1:5173,http://localhost:5173
DATABASE_URL=sqlite:///D:/Projects/LawPulse/backend/db.sqlite3
REDIS_URL=redis://127.0.0.1:6379/0
LLM_MODEL=gpt-4o-mini
OPENAI_API_KEY=
OPENAI_BASE_URL=Key backend behavior in the final build:
config/settings.pyloads environment variables from.env- the root endpoint
/returns a JSON health response - media is served in development when
DEBUG=True - Channels is configured to use Redis
- custom request latency middleware adds
X-Request-Latency-Ms - DRF schema generation is exposed through drf-spectacular
When the backend is running, this endpoint should work:
http://127.0.0.1:8000/
Expected response shape:
{
"name": "LawPulse API",
"status": "ok",
"docs": "/api/docs/",
"schema": "/api/schema/",
"admin": "/admin/"
}Use these commands after wiring configuration:
cd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
python manage.py check
python manage.py showmigrationsRun migrations and create an admin user:
cd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
python manage.py makemigrations
python manage.py migrate
python manage.py check
python manage.py createsuperuserSuccess means:
- migrations complete without errors
python manage.py checkreports no issues- superuser is created successfully
Start a local Redis helper container:
docker run --name lawpulse-redis-local -p 6379:6379 -d redis:7If it already exists:
docker start lawpulse-redis-localVerify:
docker psTo stop the local Redis helper when needed:
docker stop lawpulse-redis-localcd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
python manage.py runserverThese pages should load:
http://127.0.0.1:8000/http://127.0.0.1:8000/api/docs/http://127.0.0.1:8000/admin/
Create frontend\.env:
VITE_API_BASE_URL=http://127.0.0.1:8000
VITE_WS_BASE_URL=ws://127.0.0.1:8000The frontend must use the corrected src/api.ts that converts media URLs into absolute backend URLs before react-pdf receives them.
This is required so PDF files load from the backend server rather than the Vite dev server origin.
Run these checks before normal development use:
cd D:\Projects\LawPulse\frontend
npm install
npm run buildA successful build is a strong signal that the TypeScript and Vite setup is healthy.
cd D:\Projects\LawPulse\frontend
npm install
npm run devOpen:
http://127.0.0.1:5173
Verify the following:
- upload a PDF contract
- live status updates appear
- the PDF renders
- the risky clauses list populates
- clicking a clause updates the form
- extracted text highlighting updates
- the PDF loads from the backend media URL correctly
http://127.0.0.1:8000/api/docs/
http://127.0.0.1:8000/api/schema/
http://127.0.0.1:8000/
GET /api/audit-jobs/POST /api/audit-jobs/GET /api/audit-jobs/{id}/
ws://127.0.0.1:8000/ws/audit-jobs/{id}/
The repository includes observable signals useful for engineering review:
- root health response at
/ - OpenAPI documentation at
/api/docs/ - schema visibility at
/api/schema/ - request timing header through
X-Request-Latency-Ms
This repository is intentionally opinionated:
- Windows-first local pathing is the primary documented workflow
- Python 3.13.12 is treated as mandatory
- frontend and backend ports are fixed for consistency
- Redis is required for the real-time flow
.env.exampleis the safe configuration reference.envmust remain local and uncommitted
This repository is positioned as a full-stack engineering showcase and local reproducibility reference. It is not presented as a finished legal-risk classifier or legal advice system.
Create backend\Dockerfile:
FROM python:3.13-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
RUN apt-get update && apt-get install -y build-essential libpq-dev && rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["sh", "-c", "python manage.py migrate && daphne -b 0.0.0.0 -p 8000 config.asgi:application"]Create frontend\Dockerfile:
FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5173
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]Create docker-compose.yml in the project root:
services:
db:
image: postgres:17
container_name: lawpulse-db
environment:
POSTGRES_DB: lawpulse
POSTGRES_USER: lawpulse
POSTGRES_PASSWORD: lawpulse
ports:
- "5432:5432"
volumes:
- lawpulse_postgres_data:/var/lib/postgresql/data
redis:
image: redis:7
container_name: lawpulse-redis
ports:
- "6379:6379"
backend:
build:
context: ./backend
container_name: lawpulse-backend
command: sh -c "python manage.py migrate && daphne -b 0.0.0.0 -p 8000 config.asgi:application"
environment:
DEBUG: "True"
SECRET_KEY: docker-secret-key-change-me
ALLOWED_HOSTS: 127.0.0.1,localhost,backend
CORS_ALLOWED_ORIGINS: http://127.0.0.1:5173,http://localhost:5173
DATABASE_URL: postgres://lawpulse:lawpulse@db:5432/lawpulse
REDIS_URL: redis://redis:6379/0
LLM_MODEL: gpt-4o-mini
OPENAI_API_KEY: ""
OPENAI_BASE_URL: ""
volumes:
- ./backend:/app
ports:
- "8000:8000"
depends_on:
- db
- redis
frontend:
build:
context: ./frontend
container_name: lawpulse-frontend
environment:
VITE_API_BASE_URL: http://127.0.0.1:8000
VITE_WS_BASE_URL: ws://127.0.0.1:8000
volumes:
- ./frontend:/app
- /app/node_modules
ports:
- "5173:5173"
depends_on:
- backend
volumes:
lawpulse_postgres_data:Stop local processes and the local Redis helper first:
docker stop lawpulse-redis-localThen run:
cd D:\Projects\LawPulse
docker compose up --buildSuccess means:
- frontend runs on
http://127.0.0.1:5173 - backend runs on
http://127.0.0.1:8000 - Swagger runs on
http://127.0.0.1:8000/api/docs/
Save the following files into:
D:\Projects\LawPulse\docs\screenshots
-
backend-swagger-ui.png- page:
http://127.0.0.1:8000/api/docs/ - include visible Swagger title
- include visible
GET /api/audit-jobs/ - include visible
POST /api/audit-jobs/
- page:
-
backend-admin.png- page:
http://127.0.0.1:8000/admin/ - log in
- include visible Audit Jobs, Audit Pages, Risk Clauses
- page:
-
backend-response-headers.png- open browser developer tools
- make a backend request
- capture response headers
- include
X-Request-Latency-Ms
-
frontend-empty-state.png- app before upload
-
frontend-processing.png- while PDF is processing
- include visible progress or status
-
frontend-completed-view.png- after processing
- include left PDF pane
- include extracted text
- include risk list
- include form on the right
-
frontend-selected-clause.png- after clicking a clause
- include selected list item
- include updated form
- include extracted text highlight
Stage screenshots:
cd D:\Projects\LawPulse
git add docs\screenshots
git statusFor a stronger GitHub presentation, configure the repository with:
- repository name:
lawpulse - description:
AI-powered legal document auditor with Django, DRF, Channels, React, Redis, PostgreSQL, and Docker Compose - topics:
django,djangorestframework,django-channels,react,typescript,vite,redis,postgresql,docker-compose,openapi,legaltech,pdf-processing,websockets
cd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
python manage.py makemigrations
python manage.py migrate
python manage.py runservercd D:\Projects\LawPulse\frontend
npm install
npm run devdocker start lawpulse-redis-localcd D:\Projects\LawPulse
docker compose up --buildcd D:\Projects\LawPulse
docker compose downcd D:\Projects\LawPulse
git status
git add .
git commit -m "feat: describe one focused change"
git pushConfirm all are true:
http://127.0.0.1:8000/api/docs/loadsPOST /api/audit-jobs/existsGET /api/audit-jobs/worksGET /api/audit-jobs/{id}/returns nested pages and clausesX-Request-Latency-Msexists in response headers
Confirm all are true:
- browser connects to
ws://127.0.0.1:8000/ws/audit-jobs/{id}/ - progress messages arrive during processing
Confirm all are true:
- Vite app runs
- PDF uploads
- risky clauses populate
- selecting a clause updates the form
- selected text highlights in extracted text panel
- PDF renders from backend media URL correctly
Confirm all are true:
docker compose up --buildstarts db, redis, backend, and frontend- frontend communicates with backend successfully
Confirm all are true:
- repository is on GitHub
- no secrets are committed
- screenshots render in the README
Backend terminal:
cd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
python manage.py runserverFrontend terminal:
cd D:\Projects\LawPulse\frontend
npm run devRedis terminal:
docker start lawpulse-redis-localcd D:\Projects\LawPulse
docker compose up --build-
Use Python 3.13.12
-
Use Django 5.2
-
Use Node.js 24 LTS
-
Use Redis 7
-
Use PostgreSQL 17
-
Keep local development ports fixed as:
- backend:
8000 - frontend:
5173 - Redis:
6379
- backend:
-
Keep the corrected
frontend\src\api.tsabsolute URL handling for media files -
Keep the root endpoint
/in the backend so health verification works cleanly
cd D:\Projects\LawPulse\backend
.\.venv\Scripts\Activate.ps1
python manage.py migrate
python manage.py runservercd D:\Projects\LawPulse\frontend
npm install
npm run devdocker start lawpulse-redis-localcd D:\Projects\LawPulse
docker compose up --buildDo not commit:
backend\.env- any real API keys
- any personal credentials
The repository should include backend\.env.example as the safe template and keep backend\.env ignored by Git.
LawPulse is the complete single-path build for an AI-powered legal document auditor with:
- Django backend APIs
- WebSocket progress updates
- PDF upload and parsing
- clause extraction and review
- React side-by-side viewer UI
- Redis-backed Channels support
- PostgreSQL-ready Docker deployment
- documented Windows-first local workflow
This project is licensed under the MIT License.
Copyright (c) 2026 Cherry Augusta
See the LICENSE file for full details.






