Case Study
Qber: A Keyless Car Rental Platform on One Firebase Project and Three Apps
For NordiQ Solutions we built the whole product around a telematics device in the car: a Flutter app for owners, a Next.js admin for staff, and an account-less web portal for renters, all on one Firebase project. This is how the pieces were split, why we audited our own work early, and what is still open.
TL;DR
- —Qber puts a telematics tracker into a car so the owner can see it, lock it and unlock it from a phone, and rent it out without meeting the renter.
- —We built three front doors onto one backend: a Flutter owner app, a Next.js staff admin and a public renter portal, each owning its own Firestore collections.
- —Telemetry and commands go through the Flespi platform and Cloud Functions; there is no custom server to run.
- —We audited our own early work before building the back office, and let the findings shape its architecture, not just its backlog.
- —Renters never create an account: a QR sticker and a short rental code get them through photos and contract acceptance, with a hash of what they accepted stored as evidence.
The product: a tracker in the car, an app in the owner's pocket
Qber, by NordiQ Solutions, is a peer-to-peer car rental platform with remote handover. The owner orders a Qber Remote device from the webshop with a monthly or yearly subscription, a technician installs it, and from then on the car reports its position and telemetry and accepts lock and unlock commands from the owner's phone.
The hardware is a Teltonika tracker with a CAN adapter, reached through the Flespi telematics platform. Depending on the car, a door command is either a relay output or a CAN-bus instruction; the app does not need to know which. The rental itself hangs off those commands: an unlock opens a rental, a lock closes it, and the kilometres and fuel at both ends are read from telemetry on the server.
One backend, three front doors
Three kinds of people touch the system, and they need very different things. Owners want a mobile app that shows the car and starts a rental. NordiQ staff want a back office for customers, subscriptions, devices, SIM cards, QR stickers, tickets and notifications. Renters want to get into a car they do not own, with the least friction possible and no app to install.
So there are three apps on one Firebase project, with ownership drawn explicitly. The Flutter owner app and its Cloud Functions own users, vehicles, rentals, tickets and notifications. The Next.js admin owns customers, subscriptions, devices, SIMs, QR codes and the audit log. The renter portal owns handovers. Each app reads what the others own but writes only its own, and back-office data is never readable from a client at all.
Telematics without a server to babysit
Flespi streams device messages into a Cloud Function webhook, which writes the latest telemetry to Firestore; the app subscribes to that document. Commands go the other way: a callable function checks that the caller owns the car, sends the relay or CAN command through Flespi, logs it, and opens or closes the rental. Telemetry cards, service intervals and warnings come from the same stream, mapped from a spreadsheet the client filled in; fault codes are queried on demand.
One decision looks trivial and was not. Flespi streams carry messages, never connection state, so the first version's online indicator was always true. We considered a platform webhook on connection events and dropped it as not worth the moving parts; a car is now online if its last message is younger than ten minutes. It is the kind of choice that keeps a small system small.
Audit first, then build the back office
Before starting the admin we ran a full audit of the mobile app and its Cloud Functions, the same review we would run on a codebase we take over. It found the shortcuts a fast first version accumulates, and its main lesson was that patterns acceptable for a single-user mobile app are not a foundation for a staff back office with access to every customer.
So the admin was built on a different model rather than patched: all data and third-party access happens on the server, staff access is role-based and re-checked on every request, every change is validated and written to an audit log, and the browser holds nothing worth stealing. The audit's remaining items went into a tracked list with a fixed, partial or open status, which we prefer to a vague promise of hardening later.
Renters without accounts
A renter meets Qber once, at a windscreen. The portal is built for exactly that: no registration, no password. The renter scans the QR sticker, enters the short rental code from the owner, and gets a session for that one handover. From there a status-driven page walks them through five check-in photos in fixed slots, their details, and the rental contract; at return, six more photos.
The contract is accepted, not signed. The renter reads the full Hungarian contract, the same template and values as the PDF that will be emailed, and presses accept. The portal stores when it happened, which template version was shown, and a hash of the exact text, which equals the document hash on the generated PDF. We had built drawn signatures and an owner signing page first; both were retired the same day, because starting the rental in the app is the owner's approval and a hash proves more than a scribble.
The owner's app never writes a handover. It asks the portal's API to create or cancel one, reads its own handovers from Firestore, and asks for confirmation before unlocking if the renter has not yet accepted. Unlock moves the handover to active and lock closes it; the contract PDF goes to both parties by email.
Boring choices that keep the pace
Nothing in the stack is exotic. The owner app is Flutter with hand-written Riverpod providers and go_router; the admin and portal are Next.js 16 with Server Actions, shadcn/ui, Zod and next-intl, deployed to Vercel with cron jobs for the daily Firestore backup and the integration sync. Everything is bilingual with Hungarian as the default, in all three apps, from the first screen.
The admin has a proper Vitest suite around schemas, mappers, actions and request validation; the portal has focused tests on the renter session, contract rendering and codes. The mobile app has no real automated tests yet, and we say so; the next investment there should be widget tests against a Firebase emulator rather than another feature.
Where it stands
The platform is early. Onboarding is set up to run through the admin's Kanban from paid order to active subscription, the staff back office and the renter portal are deployed, and the owner app has been through sixteen builds. Some things are still open and listed as such: the contract wording awaits legal review, crash reporting and store release signing are not done, and a retention job for licence photos is a to-do.
We publish no customer or vehicle numbers because the product is early and the client's. What we can show is the shape: a hardware-backed rental platform delivered as three small apps on one backend, over roughly three months, with the back office designed around what an early audit taught us.
What we learned building Qber
- ✓Draw data ownership between apps explicitly, in rules and in docs; shared backends stay sane only when each app writes its own collections.
- ✓Audit early and let the findings change the architecture, not just the backlog.
- ✓A back office needs its own security model; do not inherit the shortcuts of the mobile app it serves.
- ✓The least friction for an occasional user is no account at all, if the evidence trail is stronger than a login would be.
- ✓Prefer the definition that removes a moving part, like online means a message in the last ten minutes.
Building a product with hardware in the loop?
We design and build connected products end to end: the device integration, the mobile app, the back office and the customer-facing web, on a backend you do not have to run.
Get a free estimate