Ограничение, которое определило всё
У RYTA была старая версия на .NET с живыми пользователями и объявлениями. Новую нужно было выпустить быстро, менять ежедневно в недели запуска и довести до людей на Android, в вебе и внутри мессенджера MAX — не дожидаясь проверки в сторе каждый раз, когда сдвинулась кнопка. Это исключает классическое нативное приложение. И исключает инструменты в духе Capacitor с чужим сервисом обновлений: путь обновления должен был быть нашим.
Один бандл, три оболочки
Приложение — PWA на чистом JavaScript с картой MapLibre GL на PMTiles из нашего собственного гео-стека. Один и тот же бандл:
- зашит в Android APK как ресурс и запускается в тонкой оболочке Kotlin WebView,
- раздаётся как PWA на web.ryta.online,
- зеркалится ботом и мини-приложением в мессенджере MAX — в продакшене с 27 августа 2026.
Код приложения живёт по модели core template: прикладной код никогда не правит файлы ядра, улучшения ядра подтягиваются скриптом по манифесту, так что оболочка и движок обновлений общие с другими приложениями на том же шаблоне.
Движок OTA
При старте оболочка спрашивает бэкенд о более новом бандле в своём канале, скачивает, проверяет SHA-256 и атомарно подменяет с откатом, если новый бандл не запускается. Каналы дают поэтапную раскатку; порог минимальной версии нативной оболочки не даёт бандлу запуститься там, где нет нужной возможности. Так выпущено больше 300 бандлов.
Личность без паролей
Пользователь подтверждает номер телефона звонком на номер 8-800. Виртуальная АТС Ростелекома шлёт на бэкенд вебхук с HMAC-подписью, бэкенд сопоставляет звонящего с ожидающим запросом. Ни SMS-кодов, ни паролей; у одного человека может быть много устройств. Подписки привязаны к подтверждённому телефону.
Бэкенд и деньги
FastAPI с SQLAlchemy на PostgreSQL, MinIO для фотографий, нативно собранные push-сообщения FCM только для личных сообщений — чтобы не было веерных рассылок, тематические чаты и личные диалоги. Платные услуги идут через эквайринг Т-Банка (Init плюс подписанный вебхук уведомлений) по прайс-листу из админки. Админка на SvelteKit: пользователи, объявления, биллинг, пуши, ошибки клиентов, темы, справочники и свой выбор иконок с конвертацией Android vector XML в SVG.
Клиентский журнал диагностики выгружает ошибки прямо в админку; скрипты релиза ловят расхождение окружений; контейнер redroid даёт виртуальное Android-устройство для тестов; скрипт генерирует скриншоты, подписи и графику для Play Store.
Цифры
Около 36 600 строк в 116 файлах: бэкенд, PWA, Android-оболочка, админка и MAX-бот; пользователи и объявления перенесены из .NET-системы; хостинг — свой Docker/Caddy с приватным реестром.
Что сделал бы иначе
Сделал бы журнал диагностики до первой беты, а не после первого сообщения об ошибке с телефона, которого я не видел. И определил бы политику каналов (кому какой бандл) заранее: натягивать её на пользователей, которые уже в поле, неудобно.