All work
Marketplace
Automotive retail
In active development
Confidential client

Vintage Cars

Classic-car showroom and inventory platform

Platform guide

A Flutter showroom app over a hardened Express API — browse and filter classic stock on mobile, manage inventory, brands and categories from the dealer dashboard. Zod validates every request boundary and a Sharp pipeline normalises listing photography, so provenance and condition read the way the stock deserves.

The problem

Classic-car dealers sell on photography and provenance, and general-purpose listing sites flatten both. Stock also changes slowly but matters enormously per unit, so inventory accuracy and image quality outrank catalogue scale. A single missing service record can move an asking price by five figures.

Our approach

A Flutter client gives the showroom a native feel on mobile from the same codebase that powers the dealer dashboard. The API takes hardening seriously for a public-facing surface: Zod schemas validate every request, uploads run through a Sharp pipeline that normalises and resizes listing photography, and rate limiting sits in front of the auth routes. Provenance is modelled as an append-only event log rather than a free-text notes field.

The outcome

A showroom where listings look the way the stock deserves, and a dashboard where a dealer can maintain taxonomy and inventory without touching a spreadsheet.

What is inside

Flutter client with showroom browsing, dealer dashboard and authentication

Brand and category taxonomy layered over the car inventory model

Zod schema validation on every API boundary

Sharp image pipeline normalising and resizing listing photography on upload

Rate limiting and JWT auth protecting public endpoints

Aggregate stats endpoint powering the dashboard overview

Original React + Ant Design web build retained as a legacy client


Engineering notes · 4 min read

Provenance is an event log, not a notes field

Small

Catalogue size

value per unit is huge

Append-only

Provenance

never edited

Sharp

Image pipeline

normalised on upload

A classic car is worth what its history can prove. Owners, service intervals, restoration work, one documented accident — each of those is a dated fact that changes the asking price, and none of them should be editable after the fact.

So provenance is stored as an append-only sequence of events rather than a free-text notes field. A correction is a new event that supersedes an old one, which means the record of what the dealer believed last year survives.

Hardening a public surface

Everything a browsing visitor touches is unauthenticated, which makes the API the attack surface. Zod schemas validate every request boundary rather than trusting a route handler to check the shapes it needs, and rate limiting sits in front of the auth routes.

Uploads get the most attention, because that is where a public endpoint accepts arbitrary bytes. Every image goes through a Sharp pipeline that re-encodes and resizes it, which normalises listing photography and, as a side effect, discards anything that was not actually an image.

  • Zod validation on every boundary, not just the ones that felt risky
  • Sharp re-encode on upload — normalises presentation and strips non-image payloads
  • Rate limiting in front of auth, because credential stuffing is the cheapest attack
  • One aggregate stats endpoint for the dashboard, rather than six chatty ones
  • The original React + Ant Design web client kept as a legacy surface during the Flutter transition
Why the demo is marked desktop-first
ScreenAt 375pxDecision
Stock listStacks into cards cleanlyMobile-ready
Listing detailWorks, images reflowMobile-ready
Provenance timelineNeeds horizontal room to read as a sequenceDesktop advised in the modal
Technology

Client

Flutter
Dart

Back end

Express
Node.js
Mongoose
Zod
Sharp
JWT
Multer
Morgan

Data

MongoDB

Legacy

React
Ant Design

Platforms

iOS · Android · Web

Discuss a similar build

Need a platform like Vintage Cars?

We can walk you through how this was built, what it cost to run, and what the equivalent looks like for your business.

Or email us directly at [email protected]