Paolo Gianfelici
All work
Off the stores · recorded on sample contentCase study

Criluma Viaggi

A travel agency in the pocket: its offers, a holiday search, booking and payment, and a meeting with a consultant.

Role
Main Flutter developer: payments, sign-in with Google, Facebook and Apple, appointments, push notifications, the null-safety migration and the 2.0 release
Client
Criluma Viaggi, travel agency
Period
2018–2022 (last release 2.0.1, November 2021)
Platforms
iOS and Android from one Flutter codebase
  • Flutter
  • Dart
  • BLoC
  • RxDart
  • Firebase Auth
  • Cloud Messaging
  • Google Sign-In
  • Facebook Login
  • Sign in with Apple
  • Stripe
  • Nexi
  • MyBank

The product

Criluma Viaggi is a travel agency in the Marche region, and its app put the agency in the customer's pocket: the offers of the moment, a search over the holidays its booking system sells (flight and hotel, or the hotel alone) and a booking made on the phone, from the quote to the travellers' details, the insurance and the payment.

Customers could also book a meeting with one of the agency's travel consultants, at the agency or on a video call. I was the app's main developer, on iOS and Android from one Flutter codebase, until version 2.0.1 in November 2021.

183
of the 222 commits in the app's repository are mine
18k
lines of Dart in the last release
3
payment integrations over the years: Stripe, Nexi and MyBank
4
ways to sign in: the agency's account, Google, Facebook and Apple

Walkthrough

The app, in motion

Pick a recording, or jump straight to a chapter.

Searching for a holiday, first frame
0:00 / 1:17

Recorded from the app's last release at phone size, with the search and in-app booking switched back on as they were in version 1.6. Hotels, prices and banks are invented; the bank's pages are drawn by the demo.

What it does

From an offer in the window to a paid holiday

01

The offers in the window

The home page is the agency's shop window: a carousel of offers, each with the destination, the hotel and its stars, the dates and the price. An offer opens with its pictures, what is included and a form that sends the agency a question about it.

02

A search that follows what is on sale

Flight and hotel, the hotel alone, or a free search. Destination, month and departure airport narrow each other: after every choice the server answers with the countries, regions, months and airports that still have departures.

03

Hotel, flights and rooms

Results sort by price, category or type. A hotel opens with its pictures, the tour operator, the outbound and return flights and the rooms available for the party; rooms can be added and the flights and dates changed, and the total follows.

04

From the quote to the booking

The quote puts the flights, the stay and the insurance on one page. Confirming it asks for each traveller of each room (title, name, phone, date of birth and tax code), then the optional insurance, the terms, and a summary with the consents the contract requires.

05

Paying with MyBank

The checkout in the last release's code pays by MyBank transfer: the app opens the agency's payment page, the customer picks their bank, signs in and authorises the transfer there, and comes back to the app with the holiday paid. Earlier versions took cards through Stripe, and I built a Nexi card checkout too.

06

A consultant, at the agency or on video

A signed-in customer finds their details already filled in: they pick a day, a time and what the meeting is about, and a consultant to meet at the agency or on a video call. Sign-in uses the agency's CriluMy account, or Google, Facebook and Apple.

Under the hood

How it was built

Talking to a travel booking system

Everything comes from the agency's booking server, an ASP.NET web service whose requests wrap their fields in a JSON string inside JSON, and whose answers do the same. The app turns them into typed models and BLoCs on RxDart streams: the search keeps destinations, months and airports in step, and the booking carries the party, rooms, flights and quote from screen to screen.

Payments, and a plugin

For Nexi's card payments I wrote nexi_payment, a Flutter plugin over Nexi's Android and iOS SDKs, published on pub.dev in June 2020; I still maintain it. In the app, cards through Stripe came first and Nexi next, then MyBank through GestPay (2020–2021), with the app opening the agency's payment page in a web view and reading the outcome from the address it returns to.

Accounts, and keeping up with Flutter

A CriluMy sign-in is checked by the agency's server and mirrored in Firebase Auth; Google, Facebook and Apple go through Firebase and are matched to the customer's CriluMy account by user name or e-mail, or open one. The project started on a Flutter beta in 2018 and followed Flutter to 2.x: the new Android embedding in 2020, sound null safety for 2.0 in 2021.

Recording an app that has left the stores

The app is real. The holidays are invented.

The app is off the stores, but the agency is in business, and its booking system, offers and customers are its own. So the recordings use a copy of the last release that runs on its own, with a stand-in for everything behind it.

  1. 1

    The last release, built for the browser

    Version 2.0.1, built for the web with Flutter 2.10, a few months younger than the app, and told it runs on an iPhone. The search and in-app booking are switched back on as they were in 1.6, with the few null-safety slips in those screens fixed.

  2. 2

    A booking server inside the page

    Every request the app makes is answered in the page by a stand-in that speaks the web service's format, from an invented catalogue: nine hotels from Sardinia to the Maldives, two tour operators, flights from five airports, rooms and quotes. Sign-in runs on the in-memory Firebase used in tests.

  3. 3

    Drawn pictures, invented people

    The suppliers' photographs stay out: a script draws every beach, pool and room, the consultants' portraits and the operators' logos. The consultants, the customer and the banks are invented, and the bank's pages are drawn by the demo.

  4. 4

    Recorded offline

    The recorder refuses any request that leaves the machine, so a take cannot reach the agency's systems.

The logo, the interface and its icons are the app's own. The offers, hotels, prices, flights, consultants, customer, banks and pictures are sample content made for this portfolio.

Hotel

No demo to try here: the agency is in business, so this page shows recordings on sample content.

Every screen

The full set of screenshots

  • OffersA carousel of offers with price, hotel and dates.
  • OfferPictures, price per person, board, departure airport and dates.
  • Hotel and servicesThe hotel, its stars and what the offer includes.
  • Ask the agencyA request about the offer, sent to the agency.
  • SearchFlight + stay, stay only or free search.
  • DestinationsCountries first, then regions.
  • DepartureThe months with departures.
  • ResultsHotels with dates and price, sorted by price, category or type.
  • HotelPictures, the tour operator, stars and dates.
  • Flights and roomsOutbound and return flights, the rooms and their board.
  • QuoteFlights, stay and insurance, before booking.
  • TravellersEach traveller of each room: title, name, phone, date of birth and tax code.
  • Date of birthPicked from a calendar.
  • Insurance and termsThe optional insurance and the contract terms.
  • CheckoutThe booking summary, the consents and the total.
  • MyBankThe customer chooses their bank (drawn by the demo).
  • PaidBack in the app: paid, with a confirmation by e-mail to follow.
  • AppointmentThe customer's details, already filled in, and the day and time.
  • ConsultantsAt the agency or on video (invented consultants).
  • Sign-inThe agency's CriluMy account.
  • RegistrationName, e-mail, a user name and a password.

Next case study

TEPY →