A simple interface, rules that hold: building a mobile app for meeting up
A design retrospective on an iOS and Android mobile app that must guarantee a single seat, respect the server clock, survive network drops and have its privacy rules enforced by the API.
A simple interface, rules that hold
A public place. A chosen duration. Two participants. The app lets you propose or join an activity nearby, without scrolling through photos or biographies. Behind this deliberately reduced format, we are building a product that has to manage a single seat, schedules, interrupted connections and information that must not be visible to everyone.
The context
Having a coffee, going for a walk, visiting an exhibition: the starting point is a shared activity and a shared availability. One person proposes, another joins. They meet in person.
The product is designed and developed by Scopes, from Montpellier. The work covers the design of the user journey, the iOS and Android app, the business services, the administration tools and the presentation website. The constraint is to keep the experience legible while handling the less visible situations: two people book at the same instant, a network response arrives after a sign-out, a meeting expires while a request is waiting.
These situations shape the architecture as much as the screens do.
Model the journey before multiplying screens
The lifecycle of a proposal is described by explicit states and transitions: published, booked, arrived, cancelled, expired. The rules are gathered in a TypeScript module that is independent of the network and the database. It receives the identity of the actor and the time supplied by the server, then decides whether the action is possible.
This separation makes it possible to verify a rule to the millisecond without launching the app. It also prevents a screen, an HTTP route and an automated task from interpreting the same situation differently.
The API is built on Fastify and PostgreSQL. Choosing a modular monolith keeps business operations inside a single transaction and limits the number of services to operate. Validation contracts are shared with the clients. SQL access stays on the server side.
Guarantee the single seat
If two people tap "Join" at the same moment, only one of them must get the seat. The decision is taken inside a PostgreSQL transaction that locks the proposal concerned. The second request therefore reads a state that is already booked.
The time is checked after the lock is obtained: waiting for a transaction must not allow someone to join an activity whose start time has passed in the meantime.
Creation also handles network retries. Each request carries a key that identifies its repetition. If the first creation succeeded but its response was lost, the retry finds the same proposal. It does not publish a second activity. These behaviours are tested with concurrent transactions against a real PostgreSQL database.
Search nearby, on request
The app uses React Native and Expo, with a native map as the entry point. The person chooses an area, a search radius and constraints on time and duration. PostGIS performs the geographic search on the server, with distances expressed in metres.
Location is requested through an explicit action. An area can also be chosen by hand. Moving the map does not systematically trigger a new request: the user confirms the search within the area displayed. The journey has no need to track their movements in the background.
Have privacy enforced by the API
Sign-in relies on a phone number and a verification code. The journey requires no photo, biography or legal identity to be shown to other participants. That does not make the service anonymous: account and participation data remain necessary for it to work.
On site, each person can enter a sign of the moment, for instance "yellow backpack". Both signs are revealed once both arrivals have been declared. This rule is enforced in the server's responses: hiding a field on screen would not be enough. The list of activities does not contain this information.
Sessions can be revoked and their tokens are stored as fingerprints in the database. On the mobile side, asynchronous responses are tied to the session that requested them. An old request must not redisplay data after an account switch.
Plan for operations from the start
Support has an internal interface separate from the mobile app, with its own server, its own authentication and a dedicated SQL role. Requests can be tracked, assigned, resolved and then reopened when a user provides further information.
Sensitive actions are recorded. Case versions make it possible to detect an edit that has become stale, for instance when two operators are working on the same matter. Retries after a network drop are also taken into account.
Development proceeds by complete features: business rules, API, persistence, interface, then verification of the journey. Unit tests cover the decisions. Integration tests verify the database constraints. Interface tests put errors, retries and sign-outs to the test. Scenarios using simulated providers are kept distinct from tests against real services and devices.
What remains
The project has an implemented creation and participation journey, a geographic search, testable privacy rules and a support tool. The next stage of development covers notifications in particular, the qualification of external integrations and of journeys on physical devices, and the refinement of the interface before mobile distribution.
The product's presentation website is already public. It is generated as static HTML in the 24 official languages of the European Union. Its animation synchronises two phones to explain the journey. It is a representation of the product, not a capture of the native app. The site runs without advertising trackers or visitor-side analytics tools.
The mobile app is still in development at the time of writing. We therefore do not yet present usage results or a large-scale deployment. The work documents a more immediate requirement: making a gesture simple for the user without leaving its rules to the mercy of the network, the clock or the interface.
Technical summary
Technologies used: TypeScript, React Native, Expo, Fastify, PostgreSQL, PostGIS, React and Vite for the administration tools, Vitest and Docker. Static site in HTML, CSS and JavaScript, generated with Node.js and hosted on Railway.
Scope: product design, architecture, mobile and server development, administration tools, testing and multilingual website.
Status: a Scopes product, mobile app in development in 2026. The product name is withheld from this note and is shared on request.
Preparing a mobile app with business rules that must not depend on the network? Scopes designs and develops iOS and Android apps from Montpellier: see our page on mobile app development in Montpellier or describe your context.