
Redline — Contract Review
LiveAsk your contract questions, get cited markdown answers
Started: May 15, 2026 · ~5 hours, one evening
AI:
Claude Code
OpenAI
Stack:
HTML
JavaScript
n8n
Vercel
A contract-review prototype built as the Week 1 lab for Mahesh Yadav's AI PM Bootcamp. Upload a PDF, ask questions in chat, get cited markdown answers with confidence indicators and click-through citation pills that scroll the preview to the cited page. Architecture chosen for safety on a shared-password demo: the browser never sees the n8n webhook URL — a Vercel function proxies multipart uploads through with HMAC-signed HttpOnly session cookies and per-IP rate limiting in front of the AI agent. Live demo is gated behind a shared password.
// screens

1 / 3
// highlights
- Side-by-side PDF preview + chat composer — drag-and-drop upload, 4 MB cap, Enter to send, Shift+Enter for newline
- Assistant replies render full markdown (headings, lists, tables, blockquotes, inline code) with a per-message copy button for clean pasting
- Citation pills on each answer scroll the PDF preview to the cited page; confidence indicator dot per reply — green ≥85% / amber 65-84% / red <65% — with graceful fallback when the upstream omits structured fields
- Server-side auth via HMAC-signed HttpOnly · Secure · SameSite=Strict session cookies (7-day expiry) on Vercel Functions; per-IP rate limiting (chat 10/min, login 5/5min); webhook URL stays in env and never reaches the browser
- DOMPurify around marked v18 sanitizes LLM output against four common XSS vectors (<img onerror>, <script>, javascript: URI, <iframe data:>); CSP + HSTS + Permissions-Policy headers shipped via vercel.json
- n8n cloud workflow (Webhook → AI Agent → Respond) hosts the OpenAI call so the browser proxies through Vercel and never sees the model URL or credentials — CORS sidestepped entirely
- Single-evening build — 11 commits, 6 production deploys, 0 reverts; pre-ship QA score moved 82 → 92 after fixing the blank-flash-on-load bug
// takeaways
- marked v18 passes raw HTML through by design — DOMPurify is the standard mitigation for any LLM-driven markdown rendering. Two-line code change, ~16 KB gzipped, defends against the four common XSS vectors. Build this in from day one, not after a real incident.
- The HTML `hidden` attribute is fragile — class-level `display: flex` silently overrides it. The defensive base rule `[hidden] { display: none !important }` early in the stylesheet prevents the trap from recurring on every new component.
- `vercel env pull` is a `.gitignore` landmine — it writes `.env.local` with production secrets by default. Without `.env*` in `.gitignore`, one `git add .` exposes every secret. One-line fix, weeks of pain if missed.
- Vercel auto-deploy from GitHub honors `vercel.json` headers on every push — no CI wiring needed for CSP, HSTS, X-Frame-Options. The platform IS the deploy pipeline.
- For a prototype, the LLM provider's hard spend cap is the real safety net. Auth + rate limits are belt-and-suspenders; the spend cap is the seatbelt. Set it on the OpenAI account before anything else.