Build in Public, часть 2: драники на сервере, таймауты Telegram и как я пилю свой «Кошелёк» на React Native

Привет, DTF! Под прошлым постом про то, как я в одиночку запилил SaaS-сервис карт лояльности для 1С, в комментариях мне скинули топовый рецепт драников. Докладываю: драники пожарены, транзакции SELECT ... FOR UPDATE в PostgreSQL после них реально полетели быстрее, так что продолжаю рассказывать, что происходит с проектом дальше и какие грабли прилетели в продакшене.

Грабли №1: «Telegram не ответил за 15 секунд — ушло без картинки»

Как только реальные магазины начинают делать утренние рассылки по базе с картинками акций одновременно в MAX и Telegram, всплывает классическая сетевая боль. Текстовый JSON пролетает со свистом, а вот загрузка бинарника картинки через релей-воркер на Cloudflare (workers.dev) периодически упирается в жесткий 15-секундный таймаут из-за троттлинга и ограничений сети.

Хорошо, что еще на этапе проектирования воркеров на BullMQ я заложил Graceful Degradation (мягкую деградацию): если отправка медиафайла отваливается по таймауту, воркер не роняет джобу в ошибку и не спамит ретраями, а автоматически перехватывает фолбэк и доставляет клиенту текстовое уведомление без картинки, честно помечая в логах кабинета: «Доставлено: 2 (без картинки 1) — Telegram не ответил за 15 с».

Чтобы добить эту проблему окончательно, перевел повторные отправки одного и того же баннера на кэширование внутреннего file_id от серверов Telegram: первый запрос загружает сжатый файл, забирает file_id в Redis, а остальные 999 сообщений в очереди уходят легкими текстовыми запросами со ссылкой на этот ID за доли секунды.

Грабли №2: Запрет рекламы в ТГ с 2027 года и рождение «Безопасного контейнера»

Вторая головная боль прилетела со стороны законодательства: с 2027 года в Telegram вводят запрет на рекламные интеграции. И тут оказалось, что решение проблемы с тяжелыми картинками и защита от штрафов ФАС — это одна и та же фича.

Мы добавили механику, при которой бот вообще не шлет рекламные простыни и тяжелые картинки в чат Telegram. В чат падает чисто сервисное банковское пуш-уведомление: «По вашей карте начислено 200 подарочных баллов / открыт новый купон». Клиент жмет кнопку, проваливается в Mini App (который юридически является нашим веб-сайтом на российских серверах, а не Telegram), и уже там смотрит витрину купонов и обменивает баллы на промокоды.

Что дальше: от отдельных ботов к супераппу-кошельку на React Native

Пока пилил купоны с префиксами LC и крутил демо-режим (кстати, внутри демки на chat-card.ru прикрутил мини-квест: даю 500 демо-баллов, которые можно потратить на купон со скидкой 20%), понял, что останавливаться на отдельных Mini App для каждого магазина скучно.

Сейчас проектирую поверх существующего бэкенда на Fastify единое приложение-агрегатор в стиле классического «Кошелька» на React Native:

· Авторизация за 0 рублей: Никаких SMS-шлюзов при входе — бесшовный Deep Link в Telegram или MAX подтягивает верифицированный номер за секунду.

· Свои + чужие карты в одном месте: Сетка «Часто используете» объединяет нативные бонусные карты нашей системы (с 60-секундными QR-кодами и балансом из 1С) и обычные пластиковые карты любых супермаркетов, которые юзер может отсканировать камерой и закэшировать локально в MMKV для офлайн-работы на кассах в подвалах без сети.

· Геймификация вместо платной подписки: Хочешь отключить баннеры внутри приложения на 3 месяца бесплатно? Выпусти в 1 клик 3 карты локальных магазинов своего города из каталога. Пользователю — чистый интерфейс без рекламы, магазинам — лиды в 1С, проекту — CPA-монетизация.

Вот такой путь от простого кассового скрипта для 1С до собственного маркетплейса карт. Кто работал с React Native + офлайн-рендером штрих-кодов (EAN-13 / Code128) с автовыкручиванием яркости экрана на максимум при открытии карты — какие библиотеки сейчас самые стабильные под новую архитектуру RN? Делитесь в комментах (рецепты блюд из белорусской кухни тоже приветствуются)!

Build in Public, часть 2: драники на сервере, таймауты Telegram и как я пилю свой «Кошелёк» на React Native