AI-powered used-car deal analyzer. Upload a CARFAX PDF and a few photos of a vehicle, and VinCritiq returns a structured deal report — pricing vs. market, depreciation curve, financing math, vehicle history flags, an interactive 3D model, and a Great / Good / Fair / Bad verdict.
🌐 Live site: vincritiq.com
- CARFAX + photo analysis — parse the report, classify title status, accident count, owner history, and service health.
- Pricing intelligence — compare against KBB and market averages; surface % over/under and a structured price story.
- Financing math — APR, term, down payment, monthly payment, total interest, total cost.
- Depreciation curve — projected 1/3/5-year residual values for the specific year/make/model.
- Verdict engine — heavy-flag rules (salvage, frame damage, 4+ owners, etc.) hard-cap the rating; price drives the base case otherwise.
- Interactive 3D model — generated once per year/make/model/trim from a vehicle photo via Tripo3D, cached in Cloudflare R2, then re-served instantly to every future user querying the same vehicle.
- Body-color swatches — repaint the 3D model in 8 preset colors via shader-injected per-pixel re-hueing.
- Frontend: React 18 (CRA), Tailwind, Three.js / @react-three/fiber / @react-three/drei
- Backend: Cloudflare Pages Functions (
/functions/api/*) - Storage: Cloudflare R2 (3D model cache), Firebase Storage (vehicle photos)
- Database & Auth: Firebase Firestore + Firebase Auth
- AI: Anthropic Claude Sonnet (streaming, multimodal, prompt caching)
- 3D pipeline: Tripo3D image-to-model API → R2 mirror for permanent URLs
- Hosting: Cloudflare Pages
- Node.js 18+ and npm
- Git
- A Firebase project (free Spark plan is fine for local dev; Blaze required for Storage)
- API keys for: Anthropic Claude, Tripo3D, optionally VinAudit and Vincario (VIN decode)
git clone https://github.com/<your-org>/vincritiq.git
cd vincritiq/carbot
npm installCreate carbot/.env (this file is gitignored). The dev proxy in src/setupProxy.js reads server-side secrets from this file and proxies them to the real upstream APIs so the browser never sees them.
# ── Server-side secrets (used by the dev proxy in src/setupProxy.js) ──
CLAUDE_API_KEY=sk-ant-…
TRIPO_KEY=tsk_…
VINAUDIT_KEY=… # optional — VIN-image lookups
VINCARIO_KEY=… # optional — VIN decode
VINCARIO_SECRET=… # optional — VIN decode
# ── Public Firebase web config (baked into the client bundle) ──
REACT_APP_FIREBASE_API_KEY=…
REACT_APP_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
REACT_APP_FIREBASE_PROJECT_ID=your-project
REACT_APP_FIREBASE_STORAGE_BUCKET=your-project.firebasestorage.app
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=…
REACT_APP_FIREBASE_APP_ID=1:…:web:…
REACT_APP_FIREBASE_MEASUREMENT_ID=G-…Get the Firebase web config from Firebase Console → Project Settings → General → Your apps → Web app → SDK setup.
In the Firebase Console:
-
Authentication → enable Email/Password and Google sign-in.
-
Firestore Database → create in production mode, then publish these rules (Rules tab):
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // Cross-user 3D model cache — slug-keyed, no per-user ownership. match /models3d/{slug} { allow read, create, update: if request.auth != null; } // Per-user chat sessions, messages, settings. match /users/{uid}/{document=**} { allow read, write: if request.auth != null && request.auth.uid == uid; } } }
-
Storage (requires Blaze plan) → publish
storage.rulesfrom this repo. -
(Optional) Storage lifecycle → apply
storage-lifecycle.jsonviagsutilto auto-delete user uploads after 90 days.
npm startOpens http://localhost:3000. The dev proxy starts automatically and prints a startup banner showing which API keys it loaded — if a key shows MISSING, double-check .env and restart.
This project deploys to Cloudflare Pages with a connected R2 bucket. Push to your fork, then in the Cloudflare dashboard:
- Pages → Create project → connect your repo, build command
npm run build, outputbuild/. - Settings → Environment variables → add the server-side secrets as encrypted Secrets (
CLAUDE_API_KEY,TRIPO_KEY, etc.). The FirebaseREACT_APP_*values are already inwrangler.toml. - R2 → create a bucket named
vincritiq-models. The binding is declared inwrangler.toml. - Settings → Custom domains → point your domain at the Pages project.
| Script | What it does |
|---|---|
npm start |
Run dev server with proxy on localhost:3000 |
npm run build |
Production build into build/ |
npm test |
CRA test runner (interactive watch) |
carbot/
├── src/
│ ├── components/ # ChatInterface, ReportModal, RightSidebar, …
│ ├── contexts/ # Auth + Chat React contexts
│ ├── utils/ # claudeApi, model3d, pricing, pdfParser, …
│ └── setupProxy.js # Dev-only API key proxy
├── functions/api/ # Cloudflare Pages Functions (production proxy)
│ ├── claude.js
│ ├── models/upload.js # Tripo → R2 mirror
│ ├── tripo/[[path]].js
│ └── vinaudit.js
├── public/
├── storage.rules # Firebase Storage rules
├── storage-lifecycle.json
├── wrangler.toml # Cloudflare Pages config + R2 binding
└── tailwind.config.js
auth/invalid-api-keyon load —REACT_APP_FIREBASE_API_KEYmissing/wrong; restartnpm startafter editing.env./api/claude500 — Claude key missing in.envor hit the per-request size limit (the app compresses photos but very large CARFAX PDFs can still tip it).- 3D model stuck "pending" — likely Firestore rules don't allow
updateonmodels3d/{slug}. Re-publish the rules above. - CORS errors loading GLB — in dev the Tripo URL is routed through
/dev-glb-proxy; in prod the GLB must be served from R2 (MODELS_PUBLIC_BASEenv var must be set in the Cloudflare dashboard). - "Client is offline" warning on first load — benign. Firestore's WebChannel is still connecting; the code retries automatically.
Private project — all rights reserved.