- pairing-сессия хранит poll_secret и confirm_code (lib/pairing), опрос ушёл
на POST: pair_session уезжал в query-параметре и оседал в access-логах, а
это половина ключа к JWT. Вторая половина в deep-link не уходит;
- на экране ожидания видно число, которое обязан назвать бот. По чужой ссылке
человек его не увидит — подтверждать нечего, токен не выдаётся;
- онбординг больше не просит вернуться и запросить код: Telegram подтверждает
номер шарингом контакта, приложение забирает токен опросом;
- суммы с копейками. formatMoney округлял до рубля, и «к оплате 350 ₽»
расходилось и со списанием банка, и с чеком (комиссия почти всегда даёт
копейки). Клавиша разделителя, нарисованная на клавиатуре, наконец работает;
- категорию долга выбирает водитель. Хардкод «Долг аренда» отправлял платёж
в аренду даже тем, у кого её нет; список приходит с сервера и там же
проверяется;
- ошибки бэкенда показываются словами (минимум СБП, потолок суммы) вместо
молчаливого «не удалось», статусы истории переведены полностью, возврат
денег отличим от отказа.
Тесты: 33 зелёных, tsc чист.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
window.location.href=deep_link navigated the whole PWA to t.me, destroying the
/tg-wait polling screen -> the authenticated token was never fetched. Prefetch
the pairing session and open Telegram via an <a href> (OS app-switch, PWA stays
mounted polling); add an Open-Telegram fallback link on the wait screen.
Co-Authored-By: claude-flow <ruv@ruv.net>