The software that runs a bike rental shop, built from behind its counter.

Haven

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.

Book a bike at canazei.bike The public booking site. The staff apps are internal.

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.

01

Built from behind the counter

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

  • Reservations
  • Opening and closing rentals
  • Check-out and check-in by barcode
  • Repairs
  • Labels
  • Daily planning

It has carried five peak seasons, where a minute of downtime is a line of customers at the counter.

02

Four apps, one core

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

Public booking site

Customers pick dates, browse available bikes and sizes, and book. Their bookings land in the same system the counter uses.

customers

Embeddable widgets

Product and pricing pages that run inside the shop's existing Squarespace site and resize themselves to fit.

counter

Staff desktop app

The counter workstation: rentals, reservations, catalog, stats, labels and repairs.

floor

Staff mobile app

For the shop floor and the workshop, including the camera barcode scanner.

03

Face recognition at the counter

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.

  • Cold starts are hidden from staff. Loading the networks takes several seconds on a cold instance, so loading starts the moment a rental is opened. By the time the operator takes the ID photo, the instance is warm.
  • The ML stack doesn't break deploys. The native TensorFlow binary loads only on first real use, so deploy tooling that imports modules just to inspect them never needs it.
  • Each alert shows which photo matched. A watchlist entry can hold several reference photos; the alert puts the one that matched beside the captured ID with a similarity score, and staff are alerted at once.

Illustrative, not real data.

A threshold tuned on 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.

04

Cloud apps, counter hardware

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.

A phone becomes a wireless scanner

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.

Labels print from the cloud

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.

Split bills go to the register

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.

One scan opens the right thing

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.

05

Nearest-date suggestions

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.

06

Analytics and fleet maintenance

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.

booked in advance walk-in Illustrative shape, no real values.
07

Architecture

Customers, the cloud, and the physical shop. The interesting part is the bridge between the last two.

customers

Public booking siteIT · EN · DE
Squarespace widgetsembedded, self-resizing

cloud

FirebaseFirestore · Auth · Storage · Hosting
Cloud Functions20+
face recognition · TF.js email + PDF confirmations staff alerts scheduled analytics
Cloud message queuereal-time

the shop

Staff mobile appfloor and workshop · scanner
Counter agentlabel printer · keyboard input
Staff desktop appcounter workstation
POS / inventory systemsplit bills
08

Stack

Frontend
Svelte 5 and Svelte 4, SvelteKit, TypeScript, Vite, installable offline-capable PWAs for staff, ApexCharts
Backend
Firebase: Firestore, Cloud Functions v2 on Node 22, Auth, Storage, Hosting
Machine learning
TensorFlow.js (Node), face-api: SSD MobileNet v1 detector, 68-point landmarks, 128-d recognition network
Search
Algolia
Integrations
Socket.IO, Tailscale, Squarespace embeds, camera barcode detection
Documents
jsPDF, JsBarcode: multilingual reservation confirmations
Delivery
Vitest, Firebase Emulator Suite integration tests, GitHub Actions, pnpm monorepo
Languages
Italian, English, German

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.