gendesign/tradein-mvp/backend/app/api/v1
bot-backend 091befc9ff
Some checks failed
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Failing after 11s
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 8m0s
fix(tradein): идемпотентная отправка сообщения в поддержку (#3471)
Сеть Selectel -> api.telegram.org теряет заметную долю коротких запросов,
поэтому браузерный ретрай/двойной клик/переотправка по таймауту при отправке
в веб-чат поддержки создавали ВТОРУЮ строку в web_support_messages И второе
зеркало в support-топике Telegram, а не только дубль в БД.

Ключ идемпотентности (миграция 301, колонка idempotency_key +
partial unique индекс (thread_id, idempotency_key) WHERE direction='in'):
- явный заголовок Idempotency-Key от клиента, если он есть и валидной формы;
- иначе детерминированный fallback-отпечаток sha256(identity|текст|минутное
  окно) — старые клиенты без заголовка продолжают работать без изменений.

Pre-check резолвит тред по identity и ищет существующее inbound-сообщение с
этим ключом ДО похода в Telegram (не только до записи в БД) — иначе повтор
всё равно отправил бы второе зеркало, даже если бы вторая строка в БД не
создавалась. Гонку двух одновременных запросов с одним ключом закрывает
INSERT ... ON CONFLICT DO NOTHING на уникальном индексе в
web_support_storage.record_inbound (не read-then-write), а не сам pre-check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY6iWDnGDthdvsMWgK1BMG
2026-09-12 14:59:52 +03:00
..
__init__.py feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00
admin.py feat(tradein/geocoder): регион-параметризация геокодера — region_code в geocode()/known_city_hint, --region-code у скрипта сделок, region_code у admin geocode-missing (#3051) 2026-09-09 02:51:28 +03:00
audit.py fix(tradein/auth): отказ по насыщению — до выборки из БД и с агрегированным следом (#2715) (#2734) 2026-08-06 14:27:26 +00:00
auth.py feat(metrics): продуктовые счётчики Prometheus для Меры и Птицы + дашборд 2026-09-12 14:22:33 +03:00
brand.py feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00
buildings.py feat(tradein): второй % «за 45 дней» + zhkh-знаменатель slot (146) (#2071) 2026-06-28 17:51:38 +00:00
geocode.py feat(metrics): продуктовые счётчики Prometheus для Меры и Птицы + дашборд 2026-09-12 14:22:33 +03:00
glitchtip.py feat(glitchtip): фоновая ретрай-доставка алерта в Telegram при отказе синхронной попытки 2026-09-12 14:11:01 +03:00
lead.py feat(metrics): продуктовые счётчики Prometheus для Меры и Птицы + дашборд 2026-09-12 14:22:33 +03:00
me.py fix(tradein/auth): убрать устаревшее «Caddy basic_auth required» из 401 (#2573) (#2649) 2026-08-05 08:45:57 +00:00
payments.py fix(payments): обрыв соединения и Init без PaymentURL перестают запирать покупателя 2026-09-06 00:11:35 +05:00
privacy_admin.py Отмена по бюджету больше не оставляет сироту в сессии запроса (#3449) 2026-09-12 13:20:44 +05:00
search.py chore(format): нормализация под ruff 0.15.20 — 161 файл, только формат (#2864) (#3022) 2026-08-21 12:01:52 +00:00
support.py fix(tradein): идемпотентная отправка сообщения в поддержку (#3471) 2026-09-12 14:59:52 +03:00
team.py fix(tradein): резолвить роль из реестра, roles.yaml — только fallback (#3316) 2026-09-02 14:49:27 +05:00
trade_in.py feat(metrics): продуктовые счётчики Prometheus для Меры и Птицы + дашборд 2026-09-12 14:22:33 +03:00
version.py feat(tradein): версионирование продукта — единый источник, подвал, PDF, /versions (#2824) 2026-08-10 16:00:54 +00:00