Public booking site
Customers pick dates, browse available bikes and sizes, and book. Their bookings land in the same system the counter uses.
The software that runs a bike rental shop, built from behind its counter.
Haven is the operations platform behind a bike rental shop in the Italian Alps: online booking, counter operations, fleet maintenance and analytics. I designed, built and run it on my own, and it has been in production for five seasons.
5 seasons in production, 2022 to 2026. Close to 20k rentals over a fleet of 100+ bikes, with rental volume up about 45% since the first season.
I built Haven while working at the shop it was built for. During the season I served customers, handed out bikes and handled returns, then wrote the software that ran those same operations. Every feature started as a problem I ran into at the counter, and the next day I watched it get used.
Most software for small businesses is written by people who have never worked a shift in one. Here the engineer was also the user.
The fleet is high-end Specialized bikes, with top models around €15,000 each: e-MTB, gravel, road, city and kids' bikes, plus trailers, child seats and protective gear, 100+ bikes across about 25 models. Summer is the season and August is by far its busiest month; peak months reach roughly 2,000 rentals. About two thirds are booked in advance and the rest walk in. The clientele is international, so the customer-facing site speaks Italian, English and German.
A day at the counter runs on it
It has carried five peak seasons, where a minute of downtime is a line of customers at the counter.
All four share one TypeScript core: the models, availability logic and pricing are written once. Behind them, 20+ Cloud Functions run the booking API, scheduled analytics, confirmation emails with generated PDFs and barcodes, staff notifications and face recognition. Every app has separate beta and production channels with automated test and deploy pipelines.
Customers pick dates, browse available bikes and sizes, and book. Their bookings land in the same system the counter uses.
Product and pricing pages that run inside the shop's existing Squarespace site and resize themselves to fit.
The counter workstation: rentals, reservations, catalog, stats, labels and repairs.
For the shop floor and the workshop, including the camera barcode scanner.
Staff photograph each renter's ID while the rental is open, and Haven checks it against a watchlist in real time. The model runs on the platform itself, not through a third-party vision API: face detection, 68-point landmarks and 128-dimensional embeddings run inside a Cloud Function with TensorFlow.js and face-api, and a match is a Euclidean distance between embeddings.
Illustrative, not real data.
Staff photograph a printed ID document, not the person, and re-photographing a printed face pulls everyone's embeddings closer together. face-api's default threshold of 0.6 produced false positives. On real matches, genuine pairs came in at a distance of 0.39 or less, and a confirmed false match between two different people at 0.51, so I set the threshold at 0.45.
The staff apps are cloud web apps, but a rental counter is hardware: scanners, a label printer, a register. I connected them so that staff kept working the way they already did.
Illustrative, not real data.
The mobile app reads barcodes with the camera and sends them through a real-time cloud queue to a small agent on a counter computer, which types the code as keyboard input. Any program on that machine receives the scan, not just Haven.
Staff print bike and reservation labels from any device. Each job goes into a queue tied to a specific station, and that station's agent prints it.
When a group splits payment, the selected items and their discounts go over a WebSocket bridge, across a private Tailscale network, into the shop's separate POS and inventory system.
Codes carry a type prefix. A reservation code opens the booking, a rental code opens the rental, and a bike's code finds the open rental it is on. Staff barely type.
When a model is sold out for the requested dates, the booking site doesn't stop at "unavailable". It suggests the closest dates when that model is free for the same rental length, so the customer picks a different day instead of a different shop.
Scheduled jobs build daily and monthly statistics broken down by booking channel (online, phone, WhatsApp, email, walk-in) and by bike category, with year-over-year charts. The business plans its seasons on them.
Every bike keeps a repair history by part type (brake pads, tubes, tires, spokes), which shows which bikes and models cost the most to keep on the road.
Customers, the cloud, and the physical shop. The interesting part is the bridge between the last two.
customers
cloud
the shop
Haven taught me to build for people I work alongside every day, where a bad screen gets reported in person the next morning, and to keep a system running through August as its only engineer.