Pixeldev

Work/KIR

A test-drive platform where the car cannot leave until the paperwork is right.

A prestige used-car dealership in Melbourne was running test drives and loan cars through an off-the-shelf app that didn't fit how their floor actually works. They sent me a detailed brief: licence scanning, electronic agreements, loan tracking and live reporting. I built KIR, a multi-tenant platform with their dealership as the first tenant.

Client
A prestige used-car dealership, Melbourne
Industry
Automotive retail
Services
Product design, custom software, integrations
Stack
React, FastAPI, PostgreSQL, Redis
Timeline
Phase 1 from September 2026, three weeks to go-live
KIR Today screen: the day as a timeline of test drives and loans, a stat strip, a dark card flagging an overdue loan with a call button, and the cars currently out with progress bars.
Today, the manager's view: every drive on one timeline, the car that's late on the dark card, and how far through its time each car on the road is.
97API endpoints behind one typed client
1,564backend and front-end tests
9architecture decisions written down

The problem

A test drive at a prestige dealership is a few hundred thousand dollars of someone else's car leaving the lot with a stranger. Before it goes, a salesperson has to check the licence, record the odometer and condition, and get an agreement signed. Loan cars add expected returns, extensions and the awkward phone call when one doesn't come back. As their dealer principal put it, the old app made the salesperson fit the software, when it should have been the other way around.

Their brief asked for all of it in one place, on whatever device was in the salesperson's hand: phone, tablet or desktop. It also asked for privacy controls that most dealership software treats as an afterthought, because a driver licence is the most sensitive thing the system would hold.

What I built

KIR is an installable web app for the floor and a FastAPI backend behind it, built so native iOS and Android apps can sit on the same API later. Every screen opens on the day read as a sentence, 9 drives today, 1 loan overdue, with the numbers beside it.

  1. 1Stock imported from the dealership's website on a schedule, behind an interface a DMS connection can replace. Staff edits survive the next import until someone re-syncs that car.
  2. 2Licence scanning with the phone camera. Fields are extracted in our own process, the ones it wasn't sure about are highlighted for a human to check, and an expired licence stops the drive.
  3. 3Versioned test-drive and loan agreements, signed on the dealership's device or sent to the customer's phone as a secure link with a date-of-birth check. The signed PDF is attached to the customer, vehicle and booking.
  4. 4Bookings, a week calendar by vehicle, live tiles for what's out, overdue and due back, and notifications by email and SMS.
Two phones. Left: a salesperson checking licence fields read from a photo, with the licence number highlighted amber as unclear. Right: the customer's remote signing page with drive details, the excess that applies to them and a signature.
The two halves of a hand-over: the salesperson checks what the camera read, and the customer signs from their own phone.

The hard part

Double bookings had to be impossible, not just unlikely. Two salespeople at one counter can tap at the same moment, so overlap is a Postgres exclusion constraint on the vehicle and its time range, and creating or moving a booking takes an advisory lock on the vehicle so the cleaning buffer between drives holds under concurrency too. A walk-in loan has no booking at all, so every availability check reads bookings and cars that are physically out as one answer.

What was signed can never change. A manager can edit the agreement template, but the moment an agreement leaves draft its text, merge fields and excess tier are frozen onto it. The markdown renderer is built up from an allow-list, so a template can't smuggle in links, images or HTML, and unknown merge fields are refused at publish time rather than rendered as a blank in a legal document.

Licence data is treated as the liability it is under the Australian Privacy Principles. Each dealership's data is isolated with row-level security, licence images and fields are encrypted at rest, retention runs on two clocks, and reading a licence requires a manager role plus a fresh two-step verification on that session, with every view written to the audit log.

KIR vehicle list: stock synced from the dealership website twelve minutes ago, with rego, odometer, status and location columns, loan car tags and amber warnings on two cars whose registration is about to lapse.
Stock comes in from the dealership's website every hour. Rego about to lapse is flagged before it becomes a problem on the road.

How it went

The first three weeks produced 249 commits: the vehicle catalogue and website import, bookings and the calendar, licence scanning, the full agreement and remote-signing flow, staff invitations and two-step verification. Each decision with consequences is written up as an architecture record so the next developer, or the next phase, knows why it is the way it is. After their first week on it, the floor team's main feedback was that a hand-over now takes a couple of minutes at the car instead of ten at the desk.

Phase 2 brings a direct DMS connection, CRM integration and wider SMS automation; Phase 3 is native apps on the same API. Phase 1 went live with the dealership's sales floor in September 2026 and is rolling out stage by stage, starting with stock, bookings and licence scanning, with signed agreements and loan tracking following as each one is signed off.