All work

Buy / sell/ tradeCRM

A used-bike resale business was running on spreadsheets, a shared inbox and somebody's memory. I replaced all of it with one platform that carries a bike from the seller's first photo to the day it sells.

Role
Sole developer
Surface
Internal web app + public intake
Stack
Next.js · Supabase · Shopify
Status
In daily production use
Deals pipeline — sample data
Pipeline
Deals
Projected revenue $630,653+ New deal
Board 200History 99
Name, customer, #, contact…
Owner: All
Payout: All
Needs pricing
Stage value
$62,055 8 deals
08202026-1205Credit
Titan V3 road frameset
M. Whitfield
Credit$3,395
08192026-1414
Carbon wheelset 50mm
D. Halloran
Credit$882
Review
Stage value
$62,700 11 deals
08182026-1527Trade
Aero disc frameset trade-in
J. Okafor
Cash$2,783
Credit$3,200
Offer sent
Stage value
$106,950 42 deals
08192026-0856
Trail full-suspension M
R. Castellanos
Credit$4,700
Accepted
Stage value
$33,270 5 deals
08072026-0940
Endurance road 54cm
N. Glavac
Credit$4,000
6d in Accepted
Needs label
Stage value
$2,980 2 deals
07302026-1346
Groupset parts lot
P. Ndiaye
UPS · awaiting first scan

Interface rebuilt with sample data — no real seller or pricing information shown.

One bike, seven stages, one system.

Every stage used to live somewhere else — a form, a spreadsheet, an inbox, a notebook on the workbench. Each handoff was a chance to lose a bike, misprice it, or forget a seller was waiting on an answer.

A public intake form takes photos and specs with no account required. The bike is valued against a model library and cached MSRP, then offered as cash, store credit or both, which the seller accepts by link. Once it arrives, tune-up steps and condition grading get logged per item, so listing copy composes from what the mechanic actually recorded. The deal closes out in the P&L against what it cost to buy and fix.

The parts that were hard.

A catalog nobody agrees on

Bikes don't have clean SKUs. The same frame ships under different names by year, region and build kit. The model and variant tables exist so a mechanic can find the thing in front of them without knowing what marketing called it.

Money that splits two ways

Sellers get paid in cash, store credit, or both, and the split changes what the deal is worth to the business. Every stage total on the board carries both numbers, because a credit dollar and a cash dollar are not the same dollar.

Listings that stay in sync

The storefront needs structured metafields, not prose. Condition copy, tune-up notes and spec fields compose into a listing payload so the same bike reads consistently everywhere it appears.

Next case study
Six Sisters' Meal Planner
Read it