О проекте
Jepta — гиперлокальная социальная сеть, построенная вокруг места, где вы живёте. Вместо глобального графа подписок она организует людей по близости: чаты, привязанные к адресу или дому, групповые чаты для тех, кто живёт по одному адресу, и каналы, которые ведут пекарня, мастерская или клуб в паре сотен метров от вас. Всё в приложении — предлагаемые чаты, каналы в ленте, посты, которые вы видите первыми, — ранжируется по расстоянию от текущей геопозиции.
Компания Netgineers GmbH обратилась к нам, когда продукт был уже определён, а бэкенд — в работе. Требовалась мобильная часть: одна кодовая база на Flutter для iOS и Android — для продукта с необычно широкой для первого релиза поверхностью.

Онбординг

Запрос геопозиции

Список чатов

Лента канала

Информация о канале

Чат с каналом

Новый пост
Задача
Две вещи делали этот проект сложнее обычной разработки.
Масштаб поверхности экранов
Jepta — это не одна функция с настройками вокруг неё. Личные чаты, групповые чаты, чаты по адресу, лента каналов, профили каналов с часами работы и галереями фотографий, переписка канала с пользователем, редактор постов с настройкой комментариев для каждого поста, вкладка активности, вкладка профиля, поиск, добавление контактов по QR-коду, работа с геопозицией и разрешениями — всё это в первом релизе и в шестимесячном окне. При таком количестве экраны перестают быть независимыми единицами работы: без общего скелета каждый новый тянет за собой свои особенности навигации, свои состояния загрузки и пустого экрана, свою копию одного и того же списка.
Реальное время везде
Чат — очевидное место, где появляются WebSocket-соединения, но в Jepta они им не ограничены. Пришедший пост в канале, изменившийся счётчик комментариев, бейдж непрочитанного на вкладке чатов, отметка о прочтении — всё это работает через одно и то же постоянное соединение, в том числе на экранах, на которые пользователь сейчас не смотрит. Решать это отдельно на каждом экране означало бы по соединению на экран и состояние, которое расходится с самим собой при первом же переключении вкладки.
Наш подход
Мы рассматривали обе проблемы как одну: сначала построить общие части, а экраны сделать тонкими.
Один слой реального времени и много потребителей
WebSocket-соединение живёт под интерфейсом как единый клиент, который сам управляет своим жизненным циклом: подключение, аутентификация, heartbeat, переподключение с backoff, повторная подписка. Экраны не открывают сокеты — они подписываются на типизированные потоки событий и получают обновления. Сообщения, отправленные при отсутствии связи, ставятся в очередь и досылаются при переподключении, а не теряются; статус доставки (отправлено, доставлено, прочитано) — часть модели сообщения, а не догадка на основе того, что успело прийти. Поскольку слой общий, сообщение в открытом чате и увеличение бейджа на вкладке, куда пользователь не смотрит, — это одно и то же событие, обработанное один раз.
Скелет экрана вместо ручной сборки каждого
При таком количестве поверхностей выигрыш давало их единообразие: один навигационный граф с типизированными маршрутами, один подход к Управление состоянием, применённый одинаково в каждой фиче, и общий набор состояний: список, загрузка, пустой экран, ошибка. Новые экраны в основном собирались из готового — именно это сделало объём выполнимым в срок и сохранило приложение цельным, а не похожим на двадцать экранов от разных рук.
Геопозиция как полноценные входные данные
Близость — не фильтр, прикрученный к ленте, а организующий принцип продукта, поэтому слой геопозиции должен был быть надёжным: сценарии выдачи разрешений, корректно работающие при отказе, закешированные координаты, чтобы лента не была пустой, пока определяется местоположение, и расстояние, показанное рядом с самим контентом («в 5 км от вас» в шапке канала), чтобы ранжирование читалось, а не выглядело загадкой.
Результат
Jepta вышла на iOS и Android из одной кодовой базы на Flutter в отведённые шесть месяцев и с полным набором функций: чаты, каналы, посты, комментарии и лента с учётом геопозиции — в первом релизе, а не по частям в нескольких.
Дольше дедлайна прожила архитектура. Поскольку слой реального времени, навигационный граф и подход к состоянию были построены один раз и переиспользовались, добавление экрана после релиза осталось небольшим изменением, а не новой интеграцией с сокетом, роутером и кешем. Для продукта, чей роадмап — «больше поверхностей», именно эта разница накапливается.
Больше всего меня беспокоили шесть месяцев на приложение такого охвата. Jepta — это соседские чаты, каналы бизнеса, посты, комментарии и лента, которая перестраивается вокруг того места, где вы сейчас находитесь: длинный список экранов, фиксированная дата и трезвое ожидание, что половина уедет во второй релиз.
Команда Nerdy Production сначала построила общий фундамент — один слой реального времени, одну модель навигации, — и после этого каждый новый экран стал дешёвым. Мы вышли на iOS и Android с полным набором функций, чат надёжно работает с первого дня, а дорабатывать приложение с тех пор — небольшая задача, а не проект. Мы получили тот продукт, который заказывали, и к той дате, к которой заказывали.

FAQ
Jepta сделана в рамках нашей услуги разработки приложений на Flutter — той же практики, что стоит за другими нашими проектами с реальным временем.
