Developer tutorial. Requires Node.js, React, TypeScript, and command-line experience.

What you’ll build
A drag-and-drop webapp where a user pastes their API key, uploads a PDF contract, and sees a heatmap of risks sorted by severity. Each risk includes a clause reference, category, and suggested redline. The whole thing runs on two API calls: one to upload the file, one to analyze it.API endpoints
Want to skip ahead? View on GitHub or run on Replit.
Prerequisites
- A GC AI API key (get one from Settings > API in the app)
- Node.js 18+
Build the app
1
Scaffold the project
Create a new Vite + React + TypeScript project and install Tailwind CSS:Open The proxy forwards Replace Create two empty files. These are the only two source files we’ll write:Run
vite.config.ts and add the Tailwind plugin plus an API proxy for development:vite.config.ts
/api requests to GC AI during development so you don’t hit CORS issues from localhost.Now clear out the starter code. We’ll write everything from scratch:src/index.css with the Tailwind import and a minimal color theme:src/index.css
npm run dev to confirm the scaffold works before we start building.2
Build the API client
The API client goes in Next, a small helper that attaches the API key to every request and throws on non-2xx responses:Key validation. A lightweight File upload. Contract analysis. That’s the whole API layer. Three exported functions:
src/api.ts. It wraps the GC AI endpoints into three functions: validateApiKey, uploadFile, and analyzeContract.Start with the types. ContractRisk is the shape we’ll ask the model to return:src/api.ts
src/api.ts
GET /folders?limit=1 call checks whether the API key is valid without creating any resources:src/api.ts
uploadFile posts the file, then polls GET /files/:id every 2 seconds until the status is ready. The caller just awaits the result:src/api.ts
analyzeContract sends a chat completion with wait=0, which returns a job ID immediately instead of blocking. It polls the job until the model finishes, then parses the structured JSON out of the response:src/api.ts
validateApiKey(key), uploadFile(key, file), and analyzeContract(key, fileId).3
App shell: header and footer
Now we start building The key validates on blur and on page load (if one was saved to 
src/App.tsx. This first pass just sets up the header (with the API key input), an empty main area, and a footer:src/App.tsx
localStorage from a previous session). A green checkmark or red X shows up inline so you know right away whether the key is good.
4
File upload
Add a
FileUpload component above the App function. It supports both drag-and-drop and click-to-browse:src/App.tsx (above App)
5
Document preview
Add a This renders from the browser’s local
DocumentPreview component that renders the uploaded PDF using react-pdf. We use this instead of a native iframe embed so the preview works in sandboxed environments like Replit:src/App.tsx (above App)
File object, not from anything returned by the API. The preview shows up the moment the user drops a file, even while the upload is still running.6
Risk heatmap
Add the Risks are sorted high to low. The
RiskHeatmap component that renders the analysis results. Each risk gets a card with a colored left border for severity, a category badge, a clause reference, and a suggested redline:src/App.tsx (above App)
SeveritySummary at the top acts as a legend, with colored count badges that match the left-border colors on the cards below.7
Wire it up
The last piece is the state machine and the conditional rendering that wires everything together.Define the status type and status messages above the Each variant of Finally, fill in the The UI shows one thing at a time based on the current status: a prompt to enter a key, the file upload zone, a spinner, or the results. The 

App function:src/App.tsx (above App)
Status carries only the data the UI needs for that state. TypeScript narrows the type in each rendering branch, so you can’t accidentally access risks while still uploading.Add the state and handler inside App:<main> element:DocumentPreview stays mounted across the uploading/analyzing/done transitions so it doesn’t flash.Run npm run dev, paste your API key, and drop a contract PDF. You should see the risk heatmap appear after about 30-60 seconds.

Source code
GitHub
Clone the repo and run locally
Replit
Run it in the browser