docs(log): auth/gps/chat фиксы — логины, 429-шторм, скачущий чат, упоминания

This commit is contained in:
2026-09-17 22:02:10 +03:00
parent 267af046a3
commit 5c308274f2

View File

@@ -581,3 +581,21 @@
- настройка «Строк в ячейке» (Авто / 1–8) в диалоге «Настройки реестра», хранится в `registry-rowlines-<formId>`; CSS `-webkit-line-clamp` на текстовых ячейках (титул, описание, исполнители, автор, текстовые поля; readView inline-редакторов — кламп только на read-view, редактор не затронут); оценка высоты виртуализатора 32 px в однострочном режиме.
- Как проверялось: `npm run check` (heap 6144), `npm run build`, `npx vitest run` (129/129), eslint 0 errors. Деплой через GitHub Actions — success, health 200.
- Подводные камни: (1) кламп не применяется к file/contract-number/составным полям — намеренно; (2) при `table-fixed` колонки без заданной ширины делят оставшееся место поровну (ожидаемо); (3) ширины/строки хранятся в localStorage — не мигрируют между устройствами (единообразно с прочими настройками реестра; серверный вариант — отдельная задача); (4) настройки реестра надо проверить на проде глазами: браузерная сессия WebBridge истекла, ручная проверка отложена за пользователем.
---
## [Авторизация + GPS + чат] Логины, 429-шторм, скачущий чат, упоминания
- Статус: ✅ done (коммиты `c1d5b1c` gps, `d011265` auth, `267af04` chat; деплой на iistwin.ru)
- Зачем: (1) пользователя периодически выкидывало на логин на том же устройстве; (2) «превышено количество запросов» и CRM переставал показывать формы; (3) сообщения в чате задачи «прыгали»; (4) жалоба на упоминания (@) в чате задачи.
- Расследование (3 explore-агента + логи прода через SSH):
- **429-шторм:** логи показали 8642 ответа 429 за 30 минут, почти все /api/gps/*. Цепочка: Traccar → POST /api/gps/ingest ~1/сек → SSE gps_asset_moved broadcast всем клиентам орг. на каждую точку (server/gps/geozone.service.ts) → useGpsLiveUpdates (client/src/hooks/useGps.ts) invalidateQueries без throttle → 2+ GET/сек → per-user бакет apiLimiter (1500/15мин) исчерпан → ВСЕ запросы устройства 429.
- **Логины:** (A) access-cookie 15 мин (TTL урезан 8 сентября, 06bfd2a), а refresh-retry был отключён для всех /api/auth/* (queryClient.ts:218) — холодный старт после 15 мин простоя = гарантированный логаут при живом 30-дневном refresh; (B) мёртвый grace-период ротации: markSessionReplaced не чистил refreshTokenHash → повтор старого токена шёл в isReplaced→deny, сервер стирал ОБА cookie общего cookie-jar → разлогинивались все вкладки/PWA устройства; гонки между refreshSession (singleton внутри вкладки), keep-alive useAuth и сырым fetch в useOfflineSync; (C) любой не-ok рефреша (429/500/сеть) трактовался как смерть сессии; refreshLimiter 120/15мин по IP без per-user ключа — офисный NAT делил бакет.
- **Чат:** автоскролл TaskChat без atBottom-гварда (любое новое сообщение дёргало чат вниз); картинки без размеров дёргали measureElement виртуализатора.
- **Упоминания:** код цел; UX-ловушки — голый @ не открывал список, текстовый триггер от 2 букв, мёртвый fallback-резолв (Response без .json()). Во время 429-шторма endpoint /api/mentions/search просто отдавал 429.
- Что изменено:
- GPS (c1d5b1c): server/gps/sse-throttle.ts — публикация gps_asset_moved не чаще 3 сек на asset (запись в БД не тронута); useGpsLiveUpdates — trailing throttle инвалидаций 60 сек; позиции polling 60 сек, статусы объектов 5 мин. Модель «точки пишутся в БД, карта читает по интервалу». +4 unit-теста.
- Auth (d011265): /api/auth/me при 401 → одна попытка refresh (единственное исключение из /api/auth/*); grace-окно ротации починено — повтор старого токена в пределах 5 мин выдаёт новую пару от successor, cookie НЕ стираются при stale-токенах, revoke family только при реальном reuse за пределами окна; refreshSession различает 401/403/400 (мёртвая сессия) vs 429/5xx/сеть (transient, без logout); единый refresh-путь (useAuth, useOfflineSync → refreshSession) + межвкладочная дедупликация BroadcastChannel('auth-refresh'); refreshLimiter per-user keyGenerator. +5 тестов в token-security.test.ts.
- Чат (267af04): atBottom-гвард автоскролла (как useChatController); картинки w-180 h-180 фиксировано; упоминания: голый @ открывает список, текстовый триггер от 3 букв, поиск по имени/отчеству/фамилии/email ILIKE, починен fallback-резолв; groupByDate/flatten в useMemo.
- Как проверялось: npm run check (heap 6144), build, vitest 138/138 (было 129: +4 троттл, +5 token-security, корректировки под новую логику), eslint 0 errors по изменённым файлам.
- Подводные камни: (1) каскад ротаций в grace-окне плодит строки user_sessions при шторме из N вкладок — безвредно, TTL-очистка сессий вне скоупа; (2) authService.refreshTokens() в client/src/services/auth.service.ts стал мёртвым — кандидат на чистку; (3) waiter BroadcastChannel по таймауту 8с отдаёт transient — вкладка повторит сама; (4) после деплоя мониторить логи на 429 (должно уйти к нулю при открытой GPS-странице).