Справочная информация о приложении. Это иллюстративная архитектура и контрольный список объёма работ, а не проверенный проект клиента или результат измеренного внедрения. Технологии, объём интеграции и результаты поставки согласовываются для конкретного технического задания.
Сценарий и ограничения
Сервисный продукт, в котором iOS и Android используют одинаковые рабочие процессы, а небольшой команде необходимо поддерживать обе платформы. Архитектуру определяют три ограничения: ненадёжные мобильные сети, циклы проверки в магазинах приложений, из-за которых выпуск срочных исправлений занимает много времени, и необходимость изменять бизнес-правила без выпуска новой сборки.
Архитектура
Слои и зоны ответственности
| Слой | Технология | Зона ответственности |
|---|---|---|
| Приложение | Flutter (Dart), разделённый на UI / состояние / репозиторий | Экраны и взаимодействие. Слой репозитория — единственный компонент, который знает, поступили ли данные из сети или из локального кэша, поэтому обработка автономной работы не попадает в код UI. |
| Локальное хранилище | SQLite (drift) + защищённое хранилище платформы | Кэшированные сущности, очередь ожидающих записи операций и токены в защищённом хранилище вместо shared preferences. |
| API | Go + Gin, версионируемые маршруты | Бизнес-правила, валидация, авторизация. Версионирование с первого дня необходимо, поскольку старые сборки приложения остаются у пользователей ещё долго после выпуска. |
| Хранилище | PostgreSQL | Транзакционные данные; JSONB используется для действительно переменных атрибутов вместо бесконечного расширения таблиц. |
| Кэш / очередь | Redis | Сессии, ограничение частоты запросов, ключи идемпотентности и очередь фоновых заданий. |
| Push-уведомления | FCM и APNs за единым сервисом уведомлений | Единый внутренний API для уведомлений; различия между платформами обрабатываются на сервере, а не в приложении. |
| Администрирование | Панель администрирования на Vue | Управление пользователями, контентом и заказами, а также значениями удалённой конфигурации, которые меняют поведение приложения без выпуска новой версии. |
Модель данных
Приведённые ниже таблицы содержат правила, от которых зависит всё остальное. Ошибки в них превращают работающий демонстрационный прототип в систему, которую невозможно расширять.
Основные сущности
| Сущность | Ключевые поля, связи и правила |
|---|---|
| user / auth_identity | Один пользователь может иметь несколько идентификаторов (телефон, Apple, Google, WeChat). Разделение идентификатора и пользователя позволяет добавлять способ входа позднее без миграции. |
| device | Push-токен, платформа, версия приложения и локаль для каждого устройства. Отсюда берутся данные для адресной доставки уведомлений и поэтапного выпуска. |
| order / booking | Доменная сущность с явным столбцом состояния и журналом переходов, поэтому служба поддержки может ответить на вопрос «как объект достиг этого состояния». |
| outbox (на стороне клиента) | Поставленные в очередь локальные записи с UUID, созданным клиентом. Этот UUID становится ключом идемпотентности на сервере, благодаря чему повторная попытка после тайм-аута безопасна. |
| sync_cursor | Метка времени updated_at для каждого пользователя, управляющая инкрементальной синхронизацией: приложение загружает изменения, а не запрашивает заново целые коллекции. |
| remote_config | Конфигурация «ключ-значение» с привязкой к версии приложения и платформе, позволяющая менять правила и флаги функций без отправки приложения на проверку в магазин. |
Ключевые интерфейсы
Конечные точки, содержащие бизнес-правила
| Конечная точка | Назначение и примечания по конкурентному доступу |
|---|---|
| POST /api/v1/auth/token | Выдаёт краткоживущий токен доступа и токен обновления с ротацией. Ротация токена обновления ограничивает ущерб от украденного токена на устройстве, к которому нет доступа. |
| GET /api/v1/sync?since= | Инкрементальная загрузка записей, изменённых после указанного курсора, с постраничной выдачей и ограничением размера, чтобы пользователь, вернувшийся после нескольких недель автономной работы, не мог получить неограниченный ответ. |
| POST /api/v1/orders | Принимает UUID клиента в качестве ключа идемпотентности; повторный запрос после тайм-аута сети возвращает исходный заказ, а не создаёт дубликат. |
| POST /api/v1/devices | Регистрирует или обновляет push-токен, связанный с пользователем и версией приложения для адресных и поэтапных уведомлений. |
| GET /api/v1/config | Возвращает удалённую конфигурацию для запрашивающей версии приложения — механизм, позволяющий не выпускать новую сборку для изменения правила. |
Технические решения
- Flutter вместо двух нативных кодовых баз. Рабочие процессы общие, а команда небольшая, поэтому общий код приложения может сократить дублирование обслуживания там, где рабочие процессы совпадают; платформенные интеграции, проверки устройств и выпуски всё равно требуют отдельных работ. Там, где платформы действительно различаются — платежи, push-уведомления, биометрия, — различие изолируется за платформенным каналом и не проникает в общий код.
- Устойчивость к автономной работе, но не автономная работа как основа архитектуры. Чтение выполняется из кэша, а записи помещаются в клиентскую очередь outbox, но авторитетным источником остаётся сервер. Полноценная автономная работа с разрешением конфликтов обходится значительно дороже и оправдана только тогда, когда пользователи действительно работают без подключения в течение длительных периодов.
- UUID, созданные клиентом, как ключи идемпотентности. В мобильных сетях регулярны тайм-ауты в середине запроса. Без этого повторные попытки после тайм-аута могут привести к риску создания дубликатов заказов, который необходимо тестировать.
- Версионирование API с первого выпуска. Пользователи откладывают обновления, поэтому сервер должен продолжать обслуживать старые сборки. Добавление версионирования после запуска обходится значительно дороже, чем его внедрение с самого начала.
- Удалённая конфигурация для бизнес-правил. Выпуски клиента зависят от проверки платформами и принятия обновления пользователями. Поддерживаемые пороги, тексты и флаги функций могут управляться на стороне сервера там, где это допускают правила платформ; изменения, требующие новой сборки приложения, сохраняют эту зависимость.
Гипотетические целевые показатели
Приведённые ниже значения являются гипотетическими примерами для планирования ёмкости, а не измеренными результатами клиента, проверенной рекомендацией по оценке ёмкости или соглашением об уровне обслуживания. Установите целевые показатели приёмки для конкретного проекта после определения нагрузки, устройств, данных, оборудования и зависимостей от сторонних систем; проверьте их с помощью пилотного запуска и нагрузочных тестов до фиксации производственной цели.
Цели по ёмкости и производительности
| Цель | Значение и допущение |
|---|---|
| Холодный запуск до первого содержательного экрана | Менее 2 секунд на Android-устройстве среднего уровня при условии, что кэшированные данные отображаются, пока в фоне выполняется обновление по сети. |
| Инкрементальная синхронизация | Размер пакета изменений менее 200 KB для типичного вернувшегося пользователя; размер страницы ограничен, поэтому система должна работать с ухудшением характеристик для пользователя, отсутствовавшего долгое время, а не завершаться по тайм-ауту. |
| Задержка API | p95 менее 300 мс для стандартных операций чтения, без учёта сторонних вызовов, задержку которых мы не контролируем. |
| Доставка push-уведомлений | Определите и измеряйте время постановки уведомления в очередь приложением и подтверждения со стороны провайдера. Итоговое время доставки зависит от платформы и не гарантируется этим примером. |
Что входит в поставку
- Исходный код приложения Flutter, исходный код бэкенда Go и исходный код администраторской панели Vue в вашем репозитории
- Конфигурация сборки и подписи для обеих платформ, а также подготовка карточек в магазинах
- Документация API, схема базы данных и история миграций
- Инструкции по развёртыванию, мониторинг и доступ к журналам, процедура резервного копирования и восстановления
- Поддержка отправки в App Store и Google Play; результат и сроки проверки остаются в зоне ответственности Apple и Google
Планирование для вашего бизнеса
Описанные выше модули — отправная точка, а не фиксированный пакет. Обычно мы ограничиваем первый выпуск одним основным рабочим процессом и одним административным рабочим процессом, а затем расширяем решение, когда реальные данные использования показывают, где фактически находятся нагрузка и нестандартные случаи. Отправьте техническое задание с определённым объёмом, и мы сопоставим его с этой архитектурой и сообщим, какие её части пока не нужны.

