← Все работы

Платформа анализа аукционных сделок · 2026

CarFlip

Детерминированная платформа анализа прибыли для авто с аукционов salvage / auction в США — полная стоимость, оценка перепродажи, прибыль, ROI и Deal Score от 0 до 100 для любого лота.

Ссылки скоро

Инженерный обзор

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

Технологии

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

Задача

Дилер видит битую машину на аукционе в США — Copart, IAA — но не может понять, принесёт ли прибыль её покупка, доставка, ремонт и перепродажа.

Слишком много переменных затрат, неясная цена перепродажи, а риск трудно прочитать по коду тайтла и фото повреждений. Решение обычно принимается по интуиции.

Решение

CarFlip превращает каждый аукционный лот в понятное «да / нет».

Для любого лота он считает полную стоимость вложений (ставка + сборы + доставка + ремонт + дополнительно), оценку цены перепродажи по похожим продажам, прогноз прибыли и ROI, а также Deal Score от 0 до 100 с рейтингом риска из девяти взвешенных факторов — тип тайтла, тип повреждений, пробег, возраст, спрос на рынке и другие.

Каждый расчёт детерминирован и объясним. Одинаковый вход всегда даёт одинаковый результат, и за каждым числом стоит его обоснование — без чёрного ящика AI.

Моя роль

Я построил CarFlip в одиночку — от структуры монорепозитория до продакшена.

Это включало NestJS API и его схему Prisma, три свободных от фреймворка бизнес-движка, полный фронтенд на Next.js — лендинг, аутентификацию, фильтруемые списки, страницу анализа с визуализацией Deal Score и графиками, калькулятор what-if в реальном времени, дашборд, избранное и админ-панель — сид-данные, многоэтапные Docker-сборки, два деплой-стека и развёртывание на общий Hetzner VPS.

Архитектура

Монорепозиторий на TypeScript (npm workspaces) с тремя пакетами: shared, api и web.

Backend — NestJS 10 + Prisma 5 + PostgreSQL 16: глобальный validation pipe с белым списком DTO, глобальный exception filter, CORS, trust-proxy и лимиты размера тела. Вся бизнес-логика живёт в packages/shared как чистый, свободный от фреймворка TypeScript — легко тестируется и переиспользуется и API, и отдельным сид-скриптом.

Анализ рыночной цены дорогой, поэтому он кэшируется по хешу входа + TTL и инвалидируется автоматически при импорте новых похожих данных.

  1. Клиент
    Next.js 14 · App Router
  2. Транспорт
    REST /api/* · один origin
  3. Приложение
    NestJS 10 · 11 модулей
  4. Движки
    ProfitDeal ScoreMarket Price
  5. Данные
    PostgreSQL 16 · Prisma 5Кэш hash + TTL
Рыночная цена

Медиана со взвешиванием по похожести и отсевом выбросов

Цена перепродажи оценивается по похожим продажам, а не одной догадкой. Каждый comparable взвешивается по тому, насколько он похож на целевую машину; оценка — взвешенная медиана этого набора.

Выбросы отсеиваются через MAD (Median Absolute Deviation) до взятия медианы, и каждый результат несёт уровень уверенности — пользователь знает, насколько ему доверять.

  1. 01 Медиана со взвешиванием по похожести
  2. 02 Отсев выбросов через MAD
  3. 03 5 уровней уверенности — VERY_LOW → VERY_HIGH
  4. 04 Кэш по хешу входа + TTL

В сид-данных 558 рыночных comparable; оценка деградирует плавно — меньше / слабее comparable снижают уверенность, а не ломают число.

Deal Score

Девять взвешенных факторов, 0–100

Deal Score объединяет девять взвешенных факторов — тип тайтла, тип повреждений, пробег, возраст машины, спрос на рынке и другие — в единый балл от 0 до 100 плюс рейтинг.

Это простая взвешенная сумма, а не модель. Вклад каждого фактора виден — низкий балл всегда приходит с причиной.

Детерминированный и объяснимый — один и тот же лот всегда получает один балл, и балл никогда не чёрный ящик.

Детерминизм

В ядре нет AI

Каждая цена, балл и цифра прибыли выдаётся чистой функцией. Нет ML-модели и нет «зависит» — одинаковый вход даёт одинаковый выход, и каждый выход идёт с входами, которые его породили.

У AI есть место в рабочем процессе; числа, на которые дилер ставит деньги — не оно.

Инженерные решения

Деплой на один origin — вообще без CORS

Браузер общается только с одним доменом. /api/* реверс-проксируется на NestJS-backend за тем же origin, что и фронтенд на Next.js.

Это полностью убирает CORS — нет preflight, нет жонглирования заголовками, нет краевых случаев с доменом cookie — и сокращает поверхность, которую нужно защищать.

Принцип Самая простая архитектура — та, в которой меньше всего частей, которые нужно защищать.

Бизнес-логика вне фреймворка

Движки profit, Deal-Score и рыночной цены — это обычный TypeScript в packages/shared без единого импорта NestJS. Их вызывает API; вызывает сид-скрипт; вызывают напрямую и юнит-тесты.

В правилах нет ничего, привязанного к тому, как именно пришёл запрос.

Принцип Держи правила там, куда фреймворк не дотянется.

Сложности

  1. 01

    Один путь кода для живых и сид-данных

    Пайплайны импорта — чистые функции, принимающие PrismaClient. Эндпоинт импорта API и отдельный сид-скрипт вызывают идентичную логику, поэтому нет расхождения «работает в сидере, ломается в продакшене».

  2. 02

    Инвалидация кэша при импорте

    Анализ рыночной цены кэшируется по хешу входа + TTL, потому что он дорогой. Импорт новых comparable автоматически инвалидирует затронутые записи — устаревшая оценка после свежих данных не отдаётся никогда.

  3. 03

    Без скрейпинга

    У Copart и IAA агрессивная анти-бот-защита. Вместо борьбы с ней CarFlip читает через mock-провайдер аукциона за интерфейсом провайдера — подключить реальный источник данных позже это ограниченное изменение, а не переписывание.

  4. 04

    Доверие через объяснение

    Детерминированный движок полезен, только если пользователь ему верит. Каждый балл и цена показываются с их входами и обоснованием, а не только итоговой цифрой — именно это делает результат применимым.

Результат

CarFlip — работающий full-stack продукт: NestJS API, три протестированных бизнес-движка и фронтенд на Next.js с калькулятором what-if в реальном времени и админ-панелью, на PostgreSQL.

Он заполнен 152 машинами, 558 рыночными comparable и 120 mock-импортами аукциона — каждый автоматически оценён по цене и по Deal Score. Около 12 500 строк TypeScript, за 17 фаз, с отдельной документацией движков (docs/market-price-engine.md, docs/auction-data.md).

Развёрнут на общий Hetzner VPS за общим реверс-прокси как изолированный Docker-стек — non-root контейнер, healthcheck-и, миграция при загрузке и сид, который никогда не удаляет заполненную базу.

Сквозной процесс
  1. Аукционный лот
  2. Разбивка затрат
  3. Похожие продажи
  4. Рыночная цена
  5. Deal Score
  6. Прибыль + ROI
  7. Купить / пропустить

Ключевые функции

Анализ
  • Разбивка полных вложений
  • Оценка перепродажи по comparable
  • Прибыль и ROI
  • Deal Score (0–100)
  • Рейтинг риска
  • Калькулятор what-if в реальном времени
Машины
  • Фильтруемый список (состояние в URL)
  • Страница анализа
  • Визуализация Deal Score
  • Графики (Recharts)
Аутентификация и безопасность
  • Регистрация / вход / профиль
  • JWT + argon2
  • Ролевые guard-ы (USER / ADMIN)
  • Rate limiting по IP
  • Helmet · валидация DTO
Админ
  • Добавление машины
  • Импорт аукциона
  • Управление рыночными данными
Пользователь
  • Дашборд
  • Избранное
Движки (shared)
  • Движок Profit
  • Движок Deal Score
  • Движок Market Price
  • VIN-декодер

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.

Хотите, чтобы вам собрали что-то подобное? Обсудить →