контекст
Telegram-платформа с инкентивизированными заданиями: пользователи сабмитят выполнение шагов в партнёрских проектах, модераторы валидируют через admin-handlers, раз в месяц система распределяет бюджет по pool-based схеме на основе review-points. Бот отвечает за расчёт распределения, хранение wallet-адресов и broadcast результатов; on-chain settlement выполняется отдельно по результатам PLpgSQL-расчёта. За 7 месяцев — рост с 25k до 63k MAU, более 1M ручных проверок задач.
компромиссы
- Скоринг в PLpgSQL stored procedures vs application-level: вынес в БД — атомарность с записью лидерборда, минус сетевой round-trip и невозможно случайно посчитать половину; цена — сложнее юнит-тестировать, выигрыш — простая аудитируемая SQL-логика, которую можно git-tracking.
- Pool-based распределение (winner_flag + price_if_last) vs flat per-task: pool-схема исключает доминирование одного юзера и держит распределение справедливым на длинном хвосте, требует window-функций SQL.
- Mozilla Fluent через fluentogram vs gettext: Fluent даёт inline pluralization и DSL для биз-фраз; fluentogram даёт async-интеграцию с aiogram. .ftl-локали в репо — текстовый source of truth.
- Jupyter-ноутбук для калибровки месячного бюджета вместо real-time дашборда: дешевле в поддержке (1 ноутбук vs Grafana stack), быстрее итерации формул на исторических данных перед каждым раундом распределения.
- docker-compose вместо k8s: компактный набор сервисов на одном host — k8s overhead не оправдан.
архитектура
Telegram webhook бьёт в bot service на aiogram (с Mozilla Fluent через fluentogram для i18n, ru/en .ftl-локали). Submission/review workflow: пользователь сабмитит выполнение через FSM на Redis, модератор валидирует через admin-handlers. Расчёт выплат полностью в Postgres: набор PLpgSQL stored procedures (compile_leaderboard, compile_monthly_rewards, compile_weekly_results, compile_referred_rewards) применяет pool-based алгоритм (winner_flag + price_if_last поверх review-points) к данным review/submission. Wallet-адреса пользователей хранятся в Postgres; on-chain settlement выполняется отдельным процессом по результатам SQL-расчёта, бот шлёт broadcast с уведомлением о выплате. Audit-модуль логирует операции над балансом. FastAPI/uvicorn под webhook-runner и админскую часть.
результаты
- $138k+ обработано системой выплат за 7 месяцев на 63k+ MAU.
- pool-based reward distribution полностью в SQL — атомарный расчёт, аудитируемая формула.
- >1M ручных проверок задач модераторами через bot-flow.
- i18n: ru/en через Fluent + fluentogram, .ftl-локали как источник правды.
- компактный stack в docker-compose; bot + admin + webhook-runner на одном host.
что вынес
- PLpgSQL stored procedures для финансового скоринга оправданы, когда формула меняется ежемесячно — git-tracked миграции дают чёткую history без application redeploy и атомарность на уровне транзакции.
- Window-функции в SQL (FIRST_VALUE OVER PARTITION, ROWS UNBOUNDED PRECEDING) делают сложные распределения декларативными — то, что в application-коде превратилось бы в imperative loop с ручной агрегацией.
- Fluent + fluentogram ставит DSL-планку для i18n в продуктах с многоязычной аудиторией — pluralization и contextual variants нативно, минус целый класс багов с ручным форматированием.