- useOfflineSync: tryUploadFile/trySendAttachmentMessage бросали ошибку без
кода статуса — постоянная 400 не распознавалась regex \b400\b и вложение
ретраилось бесконечно (спам POST /api/upload каждые ~30 сек).
- validateFilename: разрешены скобки () в именах (типично для фото с
телефонов; сохраняемое имя всё равно генерируется), в текст 400 добавлено
само имя файла для диагностики.
- BatchCreateDialog: тост ошибки показывает текст сервера (из BadRequestError
или JSON в message 5xx) вместо общего «Ошибка создания задач».
B: BatchCreateDialog режет список на чанки ≤100 (лимит сервера), каждый
чанк со своим idempotency-key (requestId-N) — повтор после ошибки не
создаёт дублей; 10-минутный лок армируется только при полном успехе,
а не до запроса (раньше блокировал даже после 400).
D: таблица error_logs (миграция 0066), захват ответов >=400 в request
middleware (без 401/health/events, дедуп 60с), admin API GET/DELETE
/api/error-logs и вкладка «Журнал ошибок» в Настройках.
searchTasksByKeyword теперь возвращает isCompleted и через leftJoin
formStatuses — statusName/statusColor/statusIsFinal. В HomeGlobalSearch
закрытые задачи (isCompleted || statusIsFinal) зачёркнуты и приглушены,
у каждой задачи цветной бейдж текущего статуса.
assigneeUserId/assigneeConditions перехода раньше и давали право нажать
кнопку, и молча переназначали задачу на согласующего; кликнувший также
всегда добавлялся в task_assignees (список «Ответственный»).
Теперь ответственный при переходе всегда сохраняется, кликнувший в
ответственные не добавляется (доступ трекается через recordTransitionAccess).
В FormEditor добавлена подсказка о семантике блока «Согласующие».
- планировщик server/workers/automation-scheduler.ts (тик 60 сек, все организации)
- защита от дублей: automations.last_scheduled_run_at (миграция 0065), catch-up в пределах суток
- UI: выбор триггера 'По расписанию' и времени запуска в Automations.tsx
- MCP: create_automation/update_automation принимают trigger 'schedule'
- triggerData: { trigger: 'schedule', scheduledAt }
- extractFileKey понимает абсолютные URL (по pathname) — превью работает для уже записанных файлов
- normalizeFileUrl: абсолютные self-URL нормализуются в относительные при записи file-полей (REST field-values, MCP update_task_fields/upload-инструменты, bot-api, create task)
- ApiScopesEditor — общий редактор скоупов (режим + формы/справочники)
- Bots.tsx: секция «Доступ к API и MCP» при создании и в настройках бота, показ ключа один раз, перевыпуск с подтверждением
- Settings.tsx: управление ключами убрано, read-only список legacy-ключей
- TaskHistory/TaskDetail: иконка бота + бейдж канала MCP/API у записей аудита
- GET /api/bots/:id возвращает apiKey
- organization_api_keys.scopes (jsonb, NULL = полный доступ для legacy-ключей)
- MCP: фильтрация инструментов по режиму и проверка formIds в handler'ах
- PATCH /api/mcp-keys/:id, валидация скоупов в server/utils/api-key.ts
- UI Settings: диалог создания/редактирования ключа с режимом и мультивыбором форм/справочников
- в режиме редактирования карточки задачи редакторы geo (~90px) и contact
(~300px) переполняли inset-0 оверлей поверх однострочного read-view (~28px)
и наезжали на соседние поля (форма «Объект», «Наши Юрики»)
- теперь для типов geo/contact редактор рендерится в потоке, строка растёт
до высоты редактора; остальные типы — без изменений
- validateTelemostRoom: таймаут 3 сек + кэш 10 мин
- createVpnTask: транзакция + batch insert field values
- prepareVpnSubscription: валидация и создание подписки в фоне при получении ссылки
- sendVpnBotMessage: кэш botId, Promise.all для enrich/members/orgMap
- processPlatformSelection: одно сообщение с файлом и подпиской вместо двух
- Chat.tsx: нажатая кнопка становится зелёной галочкой, остальные disabled
- Добавлены active_chat_* поля в user_presence и endpoint /api/devices/active-chat
- Сервер не шлёт Web Push/Pushy, если получатель смотрит в тот же чат на видимой вкладке
- Клиент сообщает серверу и Service Worker об активном чате из Chat.tsx и TaskChat.tsx
- TaskChat: входящие сообщения автоматически отмечаются прочитанными при видимой вкладке
- SW: подавляет foreground/system push, если активный чат совпадает
- Убран локальный useState mode; режим всегда берется из value.
- Добавлена синхронизация customerInput с внешним value.
- При переключении на 'Мой номер' value сбрасывается для генерации номера.
- При переключении на 'Номер заказчика' используется локальный шифр.
- Убрано локальное состояние customerValue, теперь значение берётся напрямую из parsed.value
- Убран лишний useEffect, который мог сбрасывать ввод при глобальном редактировании
- Состояние mode продолжает синхронизироваться с value prop
- inputClass: w-full → w-auto (prevents input from wrapping below label)
- textareaClass: flex-1 → w-auto min-w-[200px]
- Increases max-w from 280px to 320px for longer values
- Fixes text/select inputs appearing on new line instead of inline with label
- catch block: use parsed.value as fallback instead of empty string
- remove error display in UI — show current value instead
- add parsed.value as fallback before 'Select legal entity' message
- fixes 'Не удалось загрузить номер' on first edit
- Revert NotionFieldRow grid layout back to original flex layout
- Keep StickyActionBar at bottom (not top)
- Add pencil icon on hover in left column
- Keep all original overlay logic (wide overlay for contract-number, date+prolongation)
- Preserve inline horizontal layout for extra elements (checkbox, calendar icon)
Fixes: vertical stacking of extra elements, misaligned fields
- ContractNumberField: mode и customerValue теперь синхронизируются с value prop через useEffect
- TaskDetail: date/datetime input используют w-auto, чтобы чекбокс автопролонгации шёл в одну строку
- FieldOverlay: при fitOverlay=false добавлен w-max, чтобы оверлей растягивался по ширине редактора, а не обрезался по read-view
- TaskDetail: date/datetime с автопролонгацией используют fitOverlay=false и overlayMinWidth=280
- ContractNumberField compact: переключатель, select юрлица и input/preview в одну строку
- TaskDetail: date/datetime с автопролонгацией — input и чекбокс в одну строку
- Увеличена max-width обёртки contract-number до 640px
- FieldOverlay: border-input, shadow-sm, убран overflow-hidden по умолчанию
- TaskDetail: input-редакторы h-7 leading-6, для contract-number fitOverlay=false
- ContractNumberField: добавлен compact-режим, подполя не обрезаются
- Создание задачи оставлено с вертикальным layout