Case study
- My role
- I designed and built the app and, on the backend, device registration and push delivery. I set up the tests, CI and automated builds with EAS.
- Duration
- Since April 2026, ongoing
The problem
Arenaways already had a website with booking and live trains. Passengers were missing something to keep in their pocket: an app with the same features, notices about their own line without checking the website, and the content the team publishes from the back office. Train data comes from RFI and changes minute by minute, the connection comes and goes on the train, and payment had to stay on Turnit's checkout, with no second booking engine to maintain.
What I did and why
- Tickets without a second booking engine: route, date and passengers are chosen in the app, then Turnit's checkout opens in the in-app browser, already filled in. Next to the purchase is the information on fares, passes and the BIP card.
- Live trains: search by number or by route on RFI data, with stops, times, delays, platforms, last reported position, replacement buses and cancellations. The line's routes and recent searches are one tap away, and a train or a route can be shared with a link.
- Cache yes, stale times no: news, pages and stations stay on the phone for 24 hours and can be read offline. Train data is never stored, so reopening the app never shows delays from hours before. When the connection comes back, requests resume on their own.
- Push notifications per line: users choose the lines they follow, and the backend sends a notice only to those devices, at most once every 15 minutes for the same notice, and removes tokens that are no longer valid. Preferences can only be changed with a per-device secret. Tapping a notification opens the right screen after its content is checked.
- One link, the same screen: website links to trains, routes, news and open positions open the app on the same page, on iOS and Android. Inside the app, links in the text to pages the app already has stay in the app instead of opening the browser.
- Content from the back office: news, offers, open positions and help pages are the website's, written once. The backend can also ask users to update the app when a version is too old.
- Repeatable releases: strict TypeScript, 283 Jest tests and CI on every pull request. Publishing a release on GitHub starts the EAS builds and the submission to TestFlight and Google Play. Errors and crashes reach Sentry.
Results
- iOS + Androidone codebase, on the App Store and Google Play
- 283automated tests, run on every pull request
- 15 minat most one notification per notice, only to those following the line
- 24 hof news and pages readable offline
- 0app versions needed to change news, offers and help pages
- 1 releaseon GitHub starts the builds and the submission to TestFlight and Google Play
Stack highlights
- Expo SDK 54
- React Native
- Expo Router
- TypeScript
- TanStack Query
- NativeWind
- expo-notifications + Expo Push
- EAS Build and Submit
- Jest
- Sentry
Travellers open the app, pick route, date and passengers and buy their ticket. They follow their train stop by stop, with delays, platforms and last reported position, and get a notification when there is a notice on the line they follow. News, offers, open positions and help pages come from the Arenaways back office and are the same content as the website: changing them does not need a new app version.
What I bring to an agency or a small business from this project
- A React Native app taken from the first build to the app stores and kept up with regular releases.
- Live data handled with care: the cache keeps the content, never the train times.
- Push notifications that do not turn into noise: only for the chosen lines, with a rate limit on the server.