← All work

Auction Deal-Analysis Platform · 2026

CarFlip

A deterministic profit-analysis platform for US salvage / auction cars — total investment, resale estimate, profit, ROI and a 0–100 Deal Score for any lot.

Links coming soon

Engineering snapshot

  • ~12.5k Lines of TypeScript
  • 12 Prisma Models
  • 9 Deal-Score Factors
  • 3 Business Engines
  • ~88% API Test Coverage
  • 17 Build Phases

Technologies

Monorepo
  • npm workspaces
  • packages/shared
  • packages/api
  • packages/web
Backend
  • NestJS 10
  • TypeScript
  • Prisma 5
  • PostgreSQL 16
  • JWT + Passport
  • argon2
  • Helmet
  • Per-IP rate limiting
Frontend
  • Next.js 14 (App Router)
  • React 18
  • Tailwind CSS
  • TanStack Query
  • Recharts
Engines
  • Framework-free TypeScript
  • Profit
  • Deal Score
  • Market Price
  • VIN decoder
Testing
  • Jest
  • Unit + e2e
  • Real PostgreSQL test DB
  • ~88% API coverage
Infrastructure
  • Docker (multi-stage)
  • Docker Compose
  • nginx / Caddy
  • Let's Encrypt
  • Hetzner VPS

Problem

A dealer spots a salvage car at a US auction — Copart, IAA — but can't tell whether buying it, shipping it, repairing it and reselling it will actually turn a profit.

Too many cost variables, unclear resale value, and risk that's hard to read from a title code and a damage photo. The decision usually comes down to gut feel.

Solution

CarFlip turns each auction lot into a clear yes / no.

For any lot it computes the total investment (bid + fees + shipping + repairs + extras), an estimated resale price from comparable sales, the projected profit and ROI, and a 0–100 Deal Score with a risk rating built from nine weighted factors — title type, damage type, mileage, age, market demand and more.

Every calculation is deterministic and explainable. The same input always produces the same output, and every number carries the reasoning behind it — no AI black box.

My role

I built CarFlip solo, from the monorepo layout to production.

That covered the NestJS API and its Prisma schema, the three framework-free business engines, the full Next.js frontend — landing, auth, filterable listings, the analysis detail page with Deal-Score visualisation and charts, the real-time what-if calculator, the dashboard, favourites and the admin panel — the seed dataset, the multi-stage Docker builds, two deploy stacks, and the deployment onto the shared Hetzner VPS.

Architecture

A TypeScript monorepo (npm workspaces) with three packages: shared, api and web.

The backend is NestJS 10 + Prisma 5 + PostgreSQL 16 — a global validation pipe with DTO whitelisting, a global exception filter, CORS, trust-proxy and body-size limits. All business logic lives in packages/shared as pure, framework-free TypeScript, so it is trivially testable and is reused by both the API and the standalone seed script.

Market-price analysis is expensive, so it is cached by input-hash + TTL and invalidated automatically when new comparable data is imported.

  1. Client
    Next.js 14 · App Router
  2. Transport
    REST /api/* · single origin
  3. Application
    NestJS 10 · 11 modules
  4. Engines
    ProfitDeal ScoreMarket Price
  5. Data
    PostgreSQL 16 · Prisma 5Hash + TTL cache
Market Price

Similarity-weighted median with outlier rejection

Resale price is estimated from comparable sales, not a single guess. Each comparable is weighted by how similar it is to the target vehicle; the estimate is the weighted median of that set.

Outliers are rejected using MAD (Median Absolute Deviation) before the median is taken, and every result carries a confidence level so the user knows how much to trust it.

  1. 01 Similarity-weighted median
  2. 02 MAD outlier rejection
  3. 03 5 confidence levels — VERY_LOW → VERY_HIGH
  4. 04 Cached by input-hash + TTL

558 market comparables in the seed dataset; the estimate degrades gracefully — fewer / weaker comparables lower the confidence, they don't break the number.

Deal Score

Nine weighted factors, 0–100

The Deal Score combines nine weighted factors — title type, damage type, mileage, vehicle age, market demand and others — into a single 0–100 score plus a rating.

It is a plain weighted sum, not a model. The contribution of every factor is visible, so a low score always comes with a reason.

Deterministic and explainable — the same lot always scores the same, and the score is never a black box.

Determinism

No AI in the core

Every price, score and profit figure is produced by a pure function. There is no ML model and no "it depends" — identical inputs give identical outputs, and each output ships with the inputs that produced it.

AI has a place in a workflow; the numbers a dealer bets money on are not it.

Engineering decisions

Single-origin deployment — no CORS at all

The browser only ever talks to one domain. /api/* is reverse-proxied to the NestJS backend behind the same origin as the Next.js frontend.

That removes CORS entirely — no preflight, no header juggling, no cookie-domain edge cases — and shrinks the surface that has to be secured.

Principle The simplest architecture is the one with the fewest moving parts to secure.

Business logic outside the framework

The profit, Deal-Score and market-price engines are plain TypeScript in packages/shared with zero NestJS imports. The API calls them; so does the seed script; so do the unit tests, directly.

Nothing about the rules is coupled to how a request happens to arrive.

Principle Keep the rules where the framework can't reach them.

Challenges

  1. 01

    One code path for live data and seed data

    The import pipelines are pure functions that take a PrismaClient. The API import endpoint and the standalone seed script call the identical logic, so there is no "works in the seeder, breaks in production" drift.

  2. 02

    Cache invalidation on import

    Market-price analysis is cached by input-hash + TTL because it is expensive. Importing new comparables automatically invalidates the entries it affects, so a stale estimate is never served after fresh data lands.

  3. 03

    No scraping

    Copart and IAA run aggressive anti-bot protection. Rather than fight that, CarFlip reads through a mock auction provider behind a provider interface — swapping in a real data source later is a contained change, not a rewrite.

  4. 04

    Trust through explanation

    A deterministic engine is only useful if the user believes it. Every score and price is shown with its inputs and its reasoning, not just a final figure — that is what makes the output actionable.

Result

CarFlip is a working full-stack product: a NestJS API, three tested business engines, and a Next.js frontend with a real-time what-if calculator and an admin panel, on PostgreSQL.

It is seeded with 152 vehicles, 558 market comparables and 120 mock auction imports, each auto-priced and auto-scored. Around 12,500 lines of TypeScript, built across 17 phases with dedicated engine docs (docs/market-price-engine.md, docs/auction-data.md).

Deployed to the shared Hetzner VPS behind the common reverse proxy as an isolated Docker stack — non-root container, healthchecks, migrate-on-boot and a seed that never drops a populated database.

End-to-end workflow
  1. Auction lot
  2. Cost breakdown
  3. Comparable sales
  4. Market price
  5. Deal Score
  6. Profit + ROI
  7. Buy / pass

Key features

Analysis
  • Total investment breakdown
  • Resale estimate from comparables
  • Profit & ROI
  • Deal Score (0–100)
  • Risk rating
  • Real-time what-if calculator
Vehicles
  • Filterable listing (URL-synced state)
  • Analysis detail page
  • Deal-Score visualisation
  • Charts (Recharts)
Auth & security
  • Register / login / profile
  • JWT + argon2
  • Role guards (USER / ADMIN)
  • Per-IP rate limiting
  • Helmet · DTO validation
Admin
  • Add vehicle
  • Auction import
  • Market-data management
User
  • Dashboard
  • Favourites
Engines (shared)
  • Profit engine
  • Deal Score engine
  • Market Price engine
  • VIN decoder

Overview

CarFlip is a profit-analysis platform for US salvage / auction cars (Copart / IAA style). For any auction lot it computes the total investment, an estimated resale price from comparable sales, projected profit and ROI, and a 0–100 Deal Score with a risk rating — all deterministic and explainable, no AI black box.

It is built as a TypeScript monorepo: a NestJS + Prisma + PostgreSQL backend, framework-free business engines with full unit-test coverage, and a Next.js 14 frontend with a real-time what-if calculator and an admin panel.

Want something like this built? Let's talk →