Case · commercial product
Reho24 — Multi-Application Rental Platform
Search and booking, a mobile app, host operations tooling, owner reporting and a set of external integrations, all running on one API and one source of truth. This page walks through how it is put together and where the real difficulty sits in a system like this.
02Context
The product and where the difficulty is
Short-term rental is more than a catalogue of listings. Guests search and book. Hosts and owners manage properties and watch the money. An operations team handles check-ins, approvals and problem cases. Around all of that sit availability calendars, payments, booking channels and messaging.
The difficulty is not any single screen. It is that the same state, a booking, a payment, a calendar, is read and changed by many clients: the website, the mobile app, internal tools and external systems. If each client holds its own version of the truth, they will drift apart. So the architecture is built around one server-side core.
My role on the project was technical lead: architecture, code review and the release process.
03Architecture
One API hub, many clients, one source of truth
A generalised view of the ecosystem, without tying it to specific vendors.
At the centre is a Django core with a REST API on django-ninja and WebSocket channels on Django Channels. The web app, the mobile app and the internal tools all call it through one contract rather than talking to separate backends.
That gives the rules a single home: what counts as an available slot, how price is calculated, who may see what. A new client does not reinvent the business logic, it calls it.
Anything slow, unreliable or periodic is kept out of the request. Celery with Redis runs background jobs and schedules, and communication with outside systems goes through a dedicated integration layer.
04Backend
The server side
The core is split into business domains rather than one large pile of models.
Domain modules
Bookings, payments, listings, calendars, users and other areas live in modules with their own boundaries. There are dozens of them, which is one reason hundreds of versioned migrations need discipline.
A single REST contract
Web, mobile and internal tools use the same API. A contract change goes through review with every client in mind.
Realtime over WebSocket
Messages and state updates reach clients through Django Channels instead of constant polling.
Background jobs and schedules
Extensive background and scheduled processing in Celery covers syncs, reminders, recalculations and reports. Retries and schedules are described in code, not in someone’s memory.
Geo search
Searching listings by map area and distance is built on PostGIS, so geography is resolved in the database instead of filtered in application code.
Idempotent handling of external events
Callbacks from payment and booking systems arrive twice and out of order. Handlers are written so that a repeat cannot create a second payment or a second booking.
05Web
The Vue 3 web client
The public client is written in Vue 3 and TypeScript, built with Vite, with state in Pinia. It covers listing search, listing pages, the booking flow and the personal account: the path a guest takes from choosing a place to a confirmed booking.
Hosts and organisations get their own areas in the same application. The key decision is not to duplicate server rules on the client. The client shows state and sends intent, while the API decides whether an operation is allowed. That is why web and mobile behave consistently.
06Mobile
The Flutter mobile app
iOS and Android are built from one Flutter and Dart codebase. State is managed with BLoC and the network layer uses dio.
Search and map
Browsing listings on a map and in a list, filters, and the step into a listing and its booking. Maps are Yandex.
Bookings and trips
Guests see their bookings, check-in details and payment state, while hosts manage their properties.
Messages and push notifications
Messages arrive in real time, and important events reach the user by push even when the app is closed.
Secure sign-in
Biometric authentication on the device and Sign in with Apple, from the same Flutter codebase.
Deep links
Links open a specific listing or booking inside the app, so a jump from a message or an email does not end on the home screen.
One codebase, two stores
A single codebase reduces drift between platforms and simplifies releases.
07Internal tools
Internal tools
Team operations and owner reporting live in separate applications on React, Express and Vite rather than inside the public clients.
Host operations tool
An application for day-to-day work with guests and properties. It has its own workflows, dense tables and actions that have no place in a public interface.
Owner financial reporting
A separate reporting application: what was received and when, which charges apply, what is due for payout. The data comes from the same core.
Why separate apps
Internal users have different permissions, a different pace of change and different risks. Separate builds and deployments let them evolve without touching the public client, while both rely on the shared API.
08Integrations
External systems
Every outside system is unreliable in its own way, so integrations sit behind adapters and are kept apart from domain logic.
PMS and booking channels
Synchronising availability, prices and bookings with external property management systems.
Payments and acquiring
Accepting payments through providers, processing their notifications and reconciling statuses.
Messengers and email
Notifying guests and hosts on the channel where they are most likely to notice.
Push notifications
Delivering events to the mobile app.
Reports and storage
Exports, for example to Google Sheets, and file storage for documents and images.
Maps and geocoding
Turning addresses into coordinates and showing listings on a map.
09Reliability
Reliability and process
Tracing
OpenTelemetry follows a request through the API, the database and background jobs, so a slow spot is found by its trail rather than by guessing.
Metrics
Prometheus collects service and queue metrics, and alerts are built on top of them.
Background retries
A failing external system must not lose work. Tasks retry with delays, and failed ones stay visible.
Code review and releases
Changes go through review, and a release follows a defined procedure instead of depending on who happens to press the button.
Migration discipline
The schema changes on a live system, so migrations are versioned and checked for compatibility with the running code.
10Ownership
Why a single engineering owner matters
When the web app, the mobile app, the internal tools and the backend are driven by different people with no common owner, contracts drift: a field is named two ways, an error is handled differently, and a rule is implemented three times. Each of those gaps eventually becomes a bug.
Unified technical responsibility makes it possible to change the API knowing what will move in every client, and to keep review and releases in one process. This is not about one person doing everything. It is a way to reduce the number of places where the system can disagree with itself.
The result is a commercial product system in operation, not a demo.
11Stack
Technologies
Backend
Data
Web
Mobile
Internal
Operations
Building a similar multi-app product?
Tell us which clients and integrations you have and where state drifts today. We will walk through the architecture and say what is realistic.
Discuss your project13Contact
Tell us what
has to work.
Describe the problem, your current system and its constraints. If it’s a good fit, we’ll suggest a next step — usually a short call about data, integrations and timelines.
- Telegram@missuk2003
- Emailceo@closeflow.ru
- GitHubHusqvarnalox