Системная аналитика
Спроектировать мобильное приложение для покупки авиабилета
Необходимо описать:
- Бизнес-логику мобильного приложения (использовать любую удобную нотацию моделирования бизнес-процессов).
- Основные функции данного приложения (список должен быть составлен в порядке убывания важности функций для пользователя).
- Процесс синхронизации данных между клиентом и сервером (добавление и удаление списка избранного/любимых направлений, поиск/бронирование/оплата). Представить все в диаграммах, API методах и других представлениях.
- Подготовить прототип одного из экранов мобильного приложения и описать пользовательский интерфейс для данного экрана (например, покупка авиабилета).
- Подготовить подробное описание функции покупки авиабилета, которую можно было бы использовать в качестве постановки задачи для разработки (помимо текстового описания использовать UML диаграммы, указать используемые API методы, передаваемые и получаемые параметры, описать процесс хранения информации о заказах пользователя).
- Основные, на ваш взгляд, сложности разработки такого приложения. Вопросы, возникшие при выполнении тестового задания, которые вы бы задали заказчику.
Можно выбрать любой пункт и детализировать
выбранные пункты:
4. Подготовить прототип одного из экранов мобильного приложения и описать пользовательский интерфейс для данного экрана (например, покупка авиабилета).
5. Подготовить подробное описание функции покупки авиабилета, которую можно было бы использовать в качестве постановки задачи для разработки (помимо текстового описания использовать UML диаграммы, указать используемые API методы, передаваемые и получаемые параметры, описать процесс хранения информации о заказах пользователя).
Прототип экранов мобильного приложения
Типовой экран
Экраны подсистемы покупки билетов будут построены по типовой схеме. Выделим три элемента, определим функции:
- Верхняя панель инструментов (тулбар)
- Заголовок страницы
- Если конкретный экран является частью визарда, могут располагаться кнопки перехода на предыдущий этап
- Контекстные кнопки. Например - отправить ссылку
- Нижняя панель инструментов
- Кнопка - перейти на следующий экран
- Статистика с итогами заполнения формы текущего этапа. Например общая стоимость перелета и дополнительных услуг
- Основной контейнер для приложения
Требования:
- Верхняя панель инструментов прикреплена к верхней части экрана
- Нижняя панель инструментов прикреплена к нижней части экрана
- Контент панелей инструментов формируется таким образом, чтобы в данных контейнерах не было ни вертикального ни горизонтального скролла
- Контент основной части экрана с содержимым визарда покупки билетов может иметь вертикальный скролл в зависимости от наполнения. Горизонтального скролла быть не должно.
Экран выбора тарифа для перелета
Открывается со списка вариантов перелета
Верхний тулбар
- Кнопка "Назад" - возвращает на список вариантов перелета
- Заголовок экрана - статический текст "Доступные тарифы"
Основное рабочее пространство
- Виджет "Информация о перелете"
- Статический текст. Дата и маршрут
- Названия месяцев сокращаются по такому правилу
янв., февр., апр., авг., сент., окт., нояб., дек. Такие названия месяцев, как март, май, июнь, июль, сокращений не имеют.
- Виджеты с доступными тарифами
- отрисовываются все объекты, которые вернул backend
- Доступные тарифы отсортированы по цене в порядке возрастания
- По умолчанию выбирается самый дешевый тариф - первый в списке
- Виджет тарифа
- Название - статический текст
- Стоимость - показывается для всех не выбранных тарифов в виде разницы в стоимости тарифов относительно выбранного
- Основные параметры тарифа - отрисовываются первые 4 опции тарифа из ответа бэкенда
- Кнопка "Подробнее" - открывает попап в котором показаны все параметры тарифа, которые вернул бэкенд
- Радиокнопка - индикатор выбора конкретного тарифа
Нижний тулбар
- Стоимость выбранной опции . Формат
<Итого: > {price}
- Кнопка "Продолжить" - навигирует на Экран оформления заказа
Экран оформления заказа
Верхний тулбар
- Кнопка "Назад" - возвращает экран выбора тарифа
- Заголовок экрана - статический текст "Оформление заказа"
Основное рабочее пространство
-
Виджет информация о перелете
- Статический текст. Дата и маршрут
- Названия месяцев сокращаются по такому же правилу, что и в описании на экране выбора тарифов для перелета
- Названия дней недели сокращаются как:
Пн, Вт, Ср, Чт, Пт, Сб, Вс
- Подробный билет - открывает попап с полными деталями выбранного варианта перелета и правилами тарифа
- Статический текст. Дата и маршрут
-
Секция "информация о покупателе"
- Для пользователей, которые не вошли в приложение
- Предложение войти в приложение
- Поле ввода электронного адреса
- Валидация корректности ввода адреса
- Поле ввода номера телефонов
- Подключается библиотека для валидации правильности ввода в зависимости от выбранной страны
- Для пользователей которые вошли в приложение
- В рамках публичной статьи проработка не предполагается
- Для пользователей, которые не вошли в приложение
-
Секция "Информация о пассажире"
- Счетчик числа выбранных пассажиров и статическое число предполагаемых к покупке билетов
- Карточка пассажира
- ФИО
- Пол
- дата рождения
- номер паспорта
- Кнопка "Новый пассажир" - инициирует сценарий добавления пассажира на форму оформления билета
Нижний тулбар
- Кнопка "Продолжить"
- Активна, если на форму добавлено необходимое число пассажиров
- Навигирует на "Экран оформления заказа"
Описание функции покупки авиабилета
Основная задача раздела - показать артефакты системного аналитика - UML диаграммы, методы api, open-api спецификации, диаграмма последовательности хранения информации о заказах пользователя.
Предполагаемая системная архитектура
Показанная выше системная архитектура для данного сценария использования не идеальная. Но достаточна для основной задачи статьи - показать артефакты аналитика.
Код диаграммы в нотации plunt uml C4
@startuml
!include C4_Container.puml
!define DEVICONS https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons
!include DEVICONS/go.puml
!include DEVICONS/react.puml
!include DEVICONS/mongodb.puml
'LAYOUT_TOP_DOWN()
'LAYOUT_AS_SKETCH()
LAYOUT_WITH_LEGEND()
title Пример подсистемы покупки билетов
Person(user_app, "Пользователь мобильного приложения", "бронирует авиабилеты")
Person(user_web, "Пользователь браузерной версии", "бронирует авиабилеты")
Boundary(booking_system, "Система бронирования билетов") {
'Микросервисы
Container(airtickets_frontend,"airtickets-frontend","react","Микрофронтенд для приложения Perfomance Management", $sprite="react")
Container(airticket_bff,"airtickets-bff","go","Взаимодействие с мобильным приложением и браузером пользователся", $sprite="go")
Container(airtickets_order_manager,"pm-integration-api","go","Интеграционный слой для взаимодействия с внешними системами", $sprite="go")
Container(ext_gds_amadeus_api,"ext-gds-amadeus-api", "go", "Взаимодействие с Amadeus GDS", $sprite="go")
'Базы данных
ContainerDb(airtickets_order_manager_db,"airtickets-order-manager-db","MongoDB","", $sprite="mongodb")
ContainerDb(ext_gds_amadeus_api_db,"ext-gds-amadeus-api-db","MongoDB","", $sprite="mongodb")
}
System_Ext(gds_amadeus, "Amadeus GDS", "Глобальная дистрибьюторская система")
System_Ext(platform_payment, "User payment", "Управление расчетами с пользователями и поставщиками")
'Взаимодействие пользователя и системы
Rel(user_web, airtickets_frontend,"забирает js, css файлы для сборки UI в браузере")
Rel(user_web, airticket_bff,"браузер забирает данные для последующей отрисовки в UI")
Rel(user_app, airticket_bff,"мобильное приложение забирает данные для последующей отрисовки в UI")
'взаимодействие между микросервисами внутри приложения
Rel(airtickets_order_manager, ext_gds_amadeus_api, "запросы цен и заказы", "gRPC")
'Взаимодействие api c базами данных
Rel(airtickets_order_manager, airtickets_order_manager_db, "Заказы пользователей")
Rel(ext_gds_amadeus_api, ext_gds_amadeus_api_db, "интеграционный вызовы во внешнюю систему")
'Внешние интеграции
Rel_L(ext_gds_amadeus_api, gds_amadeus, "Бронирование билетов", "http")
Rel_L(airtickets_order_manager, platform_payment, "Прием оплаты за заказы", "gRPC")
'bff
Rel(airticket_bff, airtickets_order_manager, "управление заказами", "gRPC")
'skinparam nodesep 100
'skinparam Linetype ortho
@enduml
Микросервисы и базы данных домена покупки билетов
- airtickets-frontend : Микрофронтенд на react для web версии. Предоставляет js,css файлы для сборки страницы в браузере.
- airtickets-bff : bff слой для организации взаимодействия с мобильными приложениями разных платформ и web браузерами. Пишет аудитные логи, взаимодействует с платформенным сервисом IAM для проверки прав пользователя на доступ к ресурсам.
- airtickets-order-manager : сервис хранения заказов и оркестрации исполнения заказов. Имеет свою базу данных
airtickets_order_manager_db
а также встроенный движок управления процессами - ext-gds-amadeus-api : микросервис интеграции с конкретной GDS у которой может быть своя специфика обработки интеграционных вызовов
Внешние системы
- Amadeus GDS : Система бронирования билетов
- User payment : Платформенный сервис приема оплат. Считаем внешним, так как разрабатывается другой командой
Use-case
Наименование: Покупка авиабилета
Описание: Пользователь выбрал нужный авиабилет в результатах поиска и совершил покупку
Акторы : Пользователь
Другие участники : мобильное приложение пользователя; микросервисы подсистемы покупки билетов; шлюз оплаты; внешняя система бронирования Amadeus
Предусловия : Пользователь не авторизован в системе. Пользователь нашел в результатах поиска подходящий маршрут. Маршрут в поиске был предоставлен провайдером GDS Amadeus
Постусловия : пользователь купил билет; получен платеж от пользователя; билет направлен на электронный адрес покупателя; заведена задача на оплату заказа для системы бронирования
Основной сценарий
- Пользователь кликает на карточку маршрута в результатах поиска
- Мобильное приложение параллельно отправляет 3 запроса: 1 проверка наличия мест и стоимости
/ConfirmFare
; 2 запрос условий перевозки/GetConditionData
; 3 запрос списка дополнительных сервисов/GetServicesAvailability
. И показывает заглушку - ожидание ответа от бэкенда - Микросервис
airtickets-bff
валидирует запросы и перенаправляет на микросервисairtickets-order-manager
airtickets-order-manager
регистрирует у себя 1 заказ, определяет поставщика маршрута и перенаправляет входящие запросы на интеграционный сервисext-gds-amadeus-api
ext-gds-amadeus-api
логирует полученные запросы в своей базе данных и перенаправляет во внешнюю систему вызов/shopping/flight-offers/pricing
- Полученный ответ перенаправляется в
airtickets-order-manager
airtickets-order-manager
пишет ответ в свою базу и отвечает на исходные запросы мобильного приложения- Мобильное приложение отрисовывает "экран выбора тарифа для перелета"
- Пользователь выбирает опцию и нажимает кнопку "Продолжить" в нижнем тулбаре мобильного приложения
- Мобильное приложение открывает экран оформления заказа
- Пользователь заполняет данные на форме
- email покупателя
- данные пассажиров - ФИО, пол, дата рождения, номер паспорта
- дополнительные сервисы
- Пользователь нажимает кнопку "Продолжить" в нижнем тулбаре мобильного приложения
- Мобильное приложение навигирует на экран подтвержения заказа и оплаты
- Пользователь вводит информацию об оплате в виджет платежного терминала и нажимает оплатить
- Мобильное приложение оправляет факт оплаты в бэкенд подсистемы покупки билетов и шлюза оплаты
- После подтверждения оплаты мобильное приложение сообщает о необходимости немного подождать выпуска билетов
airtickets-order-manager
переводит заказ в статус - ожидание оплаты- Платежная система отправляет нотификацию о факте оплаты
airtickets-order-manager
airtickets-order-manager
переводит заказ в статус оплачено и производит заказ в GDS Amadeus- После подтверждения заказа и получения билетов
airtickets-order-manager
меняюет статус заказа на выполнено и перенаправляет билеты через платформенный сервис нотификаций
Диаграмма последовательности
Описание методов API
Показаны два примера: текстовый формат описания и описание в виде open api спецификации
Текстовый формат
запрос на подтверждение стоимости перевозки
Метод: Get /ConfirmFare2
Path parameters: не используются
Query parameters:
- id (number) : ключ идемпотентности
- supplier (text) : идентификатор поставщика
- route_id (text) : id маршрута
- timestamp (number) : unix timestamp запроса
- currency (text) : кода валюты
Status Codes:
- 200 OK : A successful response.
Response JSON Object:
- .TripTimeChanged (boolean) : проставляется статус если время изменено относительно исходного запроса
- .NotConfirmedSegmentNumbers (object) : список не подтвержденных сегментов
- .TripsWithChangedTime (string) : список сегментов с измененным временем
- .RequestId (number) : идентификатор запроса
- .Price (string) : конкатенация кода валюты и стоимости маршрута
- .FareId (number) : идентификатор маршрута
- .Segments (string) : список сегментов
- .Error (string) : код и текст ошибки
- .Sign (string) : токен подписи запроса
- .Confirmed (boolean) : факт подтверждения маршрута
- .CheckMinConnectionTimeResult
- .CheckMinConnectionTimeResult.NextDirectionIndex
- .CheckMinConnectionTimeResult.ExpectedMinConnectionTime
- .CheckMinConnectionTimeResult.ActualConnectionTime
- .CheckMinConnectionTimeResult.Error
- .CheckMinConnectionTimeResult.PreviousDirectionIndex
- .PriceChangeInfo (string)
Пример ответа:
{
"Confirmed": true,
"FareId": "4305",
"Price": "RUB12012",
"RequestId": "75055675067185",
"Segments": "SVO0915N35042011E1305AER-AER0845D335P6950E1220SVO",
"Sign": "EF09ED35DB3D2E94DE244A024BD1516360CC9E1B1F6189399A0004C0FC10DDA9",
"PriceChangeInfo": null,
"NotConfirmedSegmentNumbers": [],
"TripTimeChanged": false,
"TripsWithChangedTime": null,
"CheckMinConnectionTimeResult": {
"Error": null,
"ExpectedMinConnectionTime": null,
"ActualConnectionTime": null,
"PreviousDirectionIndex": 0,
"NextDirectionIndex": 0
},
"Error": null
}