Scope Designed, built, and operated end to end by Hallitse Oy
Status Live in production, taking real bookings and real money
Surfaces Customer booking sites, operator, driver and admin portals, native iOS and Android apps
Scale 198 tables, 429 append-only migrations, row-level security on every tenant table

The problem

Valet storage is a small-operator business. One van, often one person. The software needed to run it properly is not small: taking a booking, holding capacity, routing a driver, getting the VAT right, issuing a compliant invoice, chasing it when it goes unpaid, and satisfying consumer law in whichever country the customer sat in when they clicked pay.

That software is normally enterprise-shaped and enterprise-priced, so operators run on a spreadsheet and a phone number instead - and then cannot grow past what one person can hold in their head. The platform exists to close that gap: the operational depth of a large system, set up by an operator who has never spoken to us.

What we built

1Isolation the database enforces

Every operator's data is separated by row-level security in PostgreSQL, not by remembering to write the right filter. One operator cannot see another's customers even if the application code asks wrongly.

2The whole commercial spine

Booking, capacity, card and invoice payment, contracts, invoices and credit notes as real PDFs, and an automatic chase when payment fails. Not a booking form with a spreadsheet behind it.

3Country-aware, not country-blind

VAT resolved per product type per country, and EU consumer withdrawal rights disclosed and consented to in the language the customer actually read - because binding someone to terms they cannot read is not consent.

4Every surface on one core

The customer booking site, the operator and driver portals, the platform admin, and the native phone apps are all clients of the same API - which is why a second business took weeks rather than a rebuild.

Design and detail

The rules live in the database wherever they can be expressed there - constraints, triggers, row-level security - rather than in application code. It costs more to write, and it means a new screen or a new endpoint cannot quietly step around a rule that already exists. Every business table keeps its own append-only history, so what changed and who changed it is answerable years later.

The constraint we hold every feature to is a one-person operator in a country we have never spoken to, finding us through a search result and signing up without help. It is a demanding test, and it is the reason there is no setup call and no configuration consultancy: anything that needs us in the room is not finished.

Built on

A deliberately plain stack, chosen to still be maintainable in year three.

.NET 10 PostgreSQL Dapper React 19 TypeScript Tailwind React Native Expo Paytrail AWS