Commit Graph

152 Commits

Author SHA1 Message Date
113ed458b6 feat(ui): фаза 4 — скелетоны PageSkeleton/ListSkeleton/CardSkeleton/FormSkeleton (мигрированы ~19 страниц вместо спиннеров), PageTransition на framer-motion (fade 150ms, MotionConfig reducedMotion=user, гейт skinComponents.motion.enabled), StaggerList для списков задач/диалогов/справочников 2026-09-08 21:10:08 +03:00
c4fdfe4eab refactor(ui): фаза 3 — единый AppShell (Sidebar не размонтируется при навигации), Layout стал тонким контейнером, SPA-навигация вместо location.href (уведомления, тосты, TableEditor), scroll restoration, плавное появление биллинг-оверлея 2026-09-08 20:48:28 +03:00
5d219ac794 fix(ui): фаза 2 — стабилизация данных: throttle+invalidate вместо refetch-пачек на SSE, единый useUnreadBadges (polling только при обрыве SSE), TaskChat polling только при потере SSE, one-shot guard в safeLazy, плавная смена скина (transition цветов) 2026-09-08 20:38:01 +03:00
7a98bf7bf3 feat(ui): фаза 1 — шкалы motion/z-index в токенах, boot-скрипт темы в index.html, рецепты компонентов (design-system/recipes.ts) для button/input/badge/card/table, layout.taskDetail в скине, удалён мёртвый CSS (.btn-compact и др.) и зависимость tw-animate-css 2026-09-08 20:26:14 +03:00
c8d7f9b336 fix(auth-ui): тихий фейл 400 при смене пароля, валидация, пароль при создании
PLAN-user-password-fixes.md (инцидент 2026-09-07, user 55/56):
- toServiceError в client auth.service: BadRequestError → {success:false, error}
- полная клиентская валидация пароля в ProfilePasswordRow
- опциональный пароль при создании пользователя (UserModal + POST /api/users)
- onError с toast в PollCard/ReactionBar (этап 4)
- 11 новых тестов (129/129)
2026-09-08 16:42:59 +03:00
0b2319b11d feat(automations): ctx.tasks.sendMessage — сообщение в чат задачи от Системы; userId в triggerData status_changed 2026-09-08 16:31:59 +03:00
42e5ace655 feat(notifications+a11y): центр уведомлений /notifications, skip-link, axe smoke
Шаг 2.5 плана production-готовности:
- страница уведомлений (фильтр, догрузка, прочтение) + ссылки из dropdown/мобильного меню
- общие хелперы notification-utils (дедупликация dropdown)
- skip-link + id=content на main
- axe smoke-тесты (0 critical/serious), исправлены 2 нарушения в новой странице
- 3 новых теста (107/107), i18n отложен по решению пользователя
2026-09-08 09:32:36 +03:00
6e7270d2ee refactor(form-editor): разбиение FormEditor.tsx (4975→337) — шаг 2.2 завершён
Шаг 2.2 (часть 4) плана production-готовности:
- 14 файлов в components/form-editor/ (контроллер, FieldCard, вкладки, диалоги)
- сверка 13/15 блоков байт-в-байт, расхождения объяснены
- warnings 566→542, check/build чисто, vitest 104/104

Итог 2.2: Chat 2696→639, TaskDetail 3278→804, Bots 3928→163, FormEditor 4975→337
2026-09-08 08:57:55 +03:00
95d03aeeff refactor(bots): разбиение Bots.tsx (3928→163) — механическая экстракция
Шаг 2.2 (часть 3) плана production-готовности:
- 16 файлов в components/bots/ (типы, контроллер, диалоги, вкладки, секции)
- сверка 28/28 сегментов дословно, порядок хуков 1:1
- check/lint/build чисто, vitest 104/104
2026-09-08 08:12:35 +03:00
52b583c671 refactor(task-detail): разбиение TaskDetail.tsx (3278→804) — механическая экстракция
Шаг 2.2 (часть 2) плана production-готовности:
- 14 файлов в components/task-detail/ (типы, вкладки, диалоги, шапка, таб-бар,
  мобильный accordion, хук условий полей)
- посимвольная сверка: все несовпадения объяснены (export-префиксы/импорты/пропсы)
- check/lint/build чисто, vitest 104/104
2026-09-08 06:53:25 +03:00
6bbedad291 refactor(chat): разбиение Chat.tsx (2696→639) — механическая экстракция без смены поведения
Шаг 2.2 (часть 1) плана production-готовности:
- 8 файлов в components/chat/: типы, утилиты, MessageBubble, диалоги,
  TypingIndicator, useChatController (логика перенесена дословно)
- неизменность доказана посимвольной сверкой с оригиналом
- check/lint/build чисто, vitest 104/104
2026-09-08 01:29:37 +03:00
75ec0f25bb chore(repo): дедуп formatAmount, пины образов, дефолты MinIO, доля any
Шаги 2.3 и 2.4 плана production-готовности:
- lib/format.ts formatAmount вместо 2 локальных копий
- пины тегов minio/rclone/ollama/traccar/pgvector + osrm по digest
- minioadmin без дефолта (env required, dev-подсказки в .env.example)
- 28 any в auto-transitions/shared типизированы из @shared/schema
- удалён _tablefield_orig.txt
- check/lint/build чисто, vitest 104/104
2026-09-08 01:07:55 +03:00
5750a3106f security(auth): anti-enumeration, returnTo-валидация, лимит попыток логина
Шаг 2.1 плана production-готовности:
- единый 401 при любом отказе логина + constant-time bcrypt
- forgot-password: идентичный ответ независимо от существования email
- sanitizeReturnTo (open redirect fix в /api/documents/generate-link)
- 10 неудачных попыток → блок 15 мин (in-memory, аудит)
- DATABASE_SSL_REJECT_UNAUTHORIZED env (дефолт true)
- доделка 0.7: статичные тексты в llm-providers/rag/finance-di2
- 8 новых тестов (104/104)
2026-09-08 00:46:57 +03:00
b1a3461c33 feat(onboarding+modules): чеклист новой org, MedSchedule за флагом, удаление Capacitor
Шаги 1.9 и 1.10 плана production-готовности:
- OnboardingChecklist (форма→коллеги→задача) на главной, фикс EmptyState в Tasks
- organizations.medschedule_enabled (миграция 0081), гейт модуля по флагу
- Capacitor-стек удалён (5 зависимостей, push-notifications.ts, capacitor.config)
- check/lint/build чисто, vitest 96/96
2026-09-08 00:27:17 +03:00
abd5d4b65f chore(ci+logs): eslint в CI, npm audit, logger с уровнями, retention error_logs
Шаги 1.6 и 1.7 плана production-готовности:
- eslint flat-config (баг-ловушки, легаси warn), lint блокирующий в pr-check
- npm audit --audit-level=high в CI (отчёт)
- фикс реального бага: условный useRef в TaskTitleInline
- server/utils/logger.ts (LOG_LEVEL/LOG_FORMAT) в 5 горячих местах
- error_logs retention 30 дней (worker), redactSensitive в captureErrorLog
- 0 errors lint, vitest 96/96
2026-09-08 00:11:38 +03:00
6eaca79cc6 perf(ui): виртуализация реестра задач и чата (@tanstack/react-virtual)
Шаг 1.3 плана production-готовности:
- TaskRegistry: виртуальные строки с динамической высотой, порог 30
- TaskChat: виртуальные сообщения, порог 100, автоскролл/scrollToMessage
- выделение/сортировка/поиск/inline-редакторы работают по полному массиву
- check/build чисто, vitest 96/96
2026-09-07 23:46:42 +03:00
701af06290 feat(billing): PaymentProvider + Mock, self-service пополнение баланса
Шаг 0.13 плана production-готовности:
- интерфейс PaymentProvider (createPayment/verifyWebhook/getPaymentStatus)
- MockPaymentProvider с настоящим webhook (sha256-подпись, идемпотентность)
- applySucceededPayment: транзакция с guard, credit, авто-снятие billingBlocked
- роуты payments + confirm-test (только mock) + публичный webhook
- Billing.tsx: Пополнить/Подтвердить (тест), фикс setLocation в рендере
- миграция 0080 billing_payments, 13 новых тестов (78/78)
2026-09-07 22:45:30 +03:00
a27766a38b perf(tasks): лимиты/пагинация /api/tasks и дельта-синк в SQL
Шаги 0.10 и 0.9 плана production-готовности:
- дефолт limit 50, кап 200; списковые ответы без description
- курсорная пагинация (updated_at, id) + nextCursor
- since-фильтр дельта-синка перенесён в SQL (updated_at >= since)
- embedding pre-count через COUNT(*) вместо выгрузки миллиона строк
- 11 новых юнит-тестов (56/56 зелёные)

Инвариант поиска сохранён: search-ветка /api/tasks?search= не изменена
2026-09-07 22:01:25 +03:00
a2b231d876 fix(history): московское время и ФИО вместо user ID в истории задачи 2026-09-07 16:55:51 +03:00
66f4e5ef53 DI2: удаление старого модуля финансов — пул БД и аудит перенесены в finance-di2
- server/finance/ (19 файлов) удалён: пул финансовой БД перенесён в server/finance-di2/db-core.ts, db-client.ts теперь реэкспортирует из ./db-core
- Шедулер аудита перенесён в server/finance-di2/audit-scheduler.ts (03:00 МСК, setInterval, без node-cron), запуск из registerDi2Routes с защитой от повторного старта
- История аудита DI2 теперь персистентна: загрузка/запись data/finance-audit-history.json в audit-agent.ts (порт из удалённого server/finance/audit.ts)
- registerFinanceRoutes убран из server/routes/index.ts, registerDi2Routes остался на его месте
- Клиент: удалены pages/finance/, components/finance/, hooks/useFinance.ts, hooks/useColumnLabels.ts, lib/format.ts, pages/salary.tsx; роуты /finance*, /income*, /expenses*, /salary и lazy-импорты убраны из App.tsx
- Навигация: «Финансы» в Sidebar и MobileBottomNav ведёт на субапп /di2 (внешняя ссылка), гейт moduleAccess.finance + finance.view сохранён
- index.css: удалён блок .hover-elevate/.hover-elevate-2/.active-elevate (использовался только старым модульным DataTable)
- FinanceBottomNav.tsx сохранён как референс для этапа 3 (.superpowers/sdd/di2-restyle/FinanceBottomNav.reference.tsx)
- Не тронуто: client-di2/, сиды прав finance.view/manage, finance_access (module-access)
2026-09-06 21:53:47 +03:00
23ed1ecf3d DI2 внедрение, таск 2: клиентский субапп Data-Insight2 (client-di2)
- client-di2/: копия фронтенда DI2 + shared/schema.ts, main.tsx обёрнут в wouter Router base=/di2, favicon относительный
- client-di2/tailwind.config.ts (свои токены DI2) подключён через @config в index.css — иначе postcss взял бы корневой конфиг iistwin
- vite.config.di2.ts: base /di2/, root client-di2, outDir dist/public-di2
- package.json: build/check через && включают сборку и typecheck di2 (build:di2, check:di2), новых зависимостей нет
- Навигация финансов: ссылка «Data-Insight (полная версия)» → /di2 (target=_blank) в FinanceSidebar и FinanceBottomNav
- Типовые фиксы предсуществующих ошибок DI2 (casts, ruleLogic в mutation-типах, Set<string>)
2026-09-06 19:46:28 +03:00
a60a75eda0 feat(profile): read-first редизайн страницы пользователя, per-field как в задачах
- Раскладка: шапка-профиль → Основное/Контакты → Роль и доступ/Поля+Замещение → вторичные разделы чипами
- ProfileFieldRow: двойной клик/карандаш, редактор в слоте, Esc, optimistic-кэш, все типы полей
- Замещение: надпись + ⊕ popover, список под строкой
- Удалены RHF-форма, zod-схема и кнопки «Сохранить»
- server: PATCH /api/users/:id (частичное обновление, admin-градация, аудит)
- server: history-number в REST PATCH пишет историю + пересчёт средней
2026-09-06 18:47:05 +03:00
ddc2bd9491 Поля профиля с options.readOnly: запрет редактирования «Оценки» и «Средней оценки»
- UI: read-only поля отображаются текстом (у history-number остаётся кнопка графика),
  исключены из сохранения; кнопка «Сохранить» скрыта, если все поля вкладки read-only
- Сервер: POST/PATCH field-values профиля отклоняют запись в поле с options.readOnly (400);
  автоматизации пишут через storage напрямую и не затрагиваются
- Данные: options.readOnly=true у полей «Оценка» и «Средняя оценка»
2026-09-06 15:08:23 +03:00
ec86fa4c11 Рейтинг сотрудников: history-number поле = последняя оценка, среднее за месяц — в поле options.avgFieldCode
- setUserProfileFieldValueFromAutomation: для history-number значением поля становится переданное число (последняя оценка), а не среднее
- recomputeUserFieldMonthlyAverage: среднее за текущий месяц пишется в поле, указанное в options.avgFieldCode history-number поля (если не задано — в само поле, обратная совместимость)
- Автоматизация «Оценка сотрудникам» (форма 11): сумма трёх числовых полей «Оценка 1/2/3» вместо одного select-поля
- Документация sandbox обновлена во всех четырёх местах (UI, MCP, Obsidian, AGENTS.md)
2026-09-06 11:55:15 +03:00
a7a14d947a Финансы: деревья категорий как в Data-Insight2 — группировка авто/ручные, свёрнуто по умолчанию, полосы сумм, нераспределённые 2026-09-06 09:53:45 +03:00
4b34a4bea5 Финансы: мобильная нижняя навигация (Обзор / Разделы / Настройки) вместо боковой панели на телефоне 2026-09-05 17:59:34 +03:00
7a8db03163 Финансы: дебиторка (vw_debt_active), расчёты НДС/налога на прибыль, аудит целостности с автопланировщиком, синхронизация зарплат из Google Sheets, миграция настроек Data-Insight2 2026-09-05 15:07:36 +03:00
d2c993b613 fix: мультивыбор user/роль — мгновенное обновление выбора (галки/чипы) в карточке задачи 2026-09-05 12:33:14 +03:00
ba723aa0b7 feat: ctx.users.recalcFieldAverage + документация автопересчёта среднего history-number 2026-09-04 20:14:51 +03:00
4d65049e02 feat: рейтинговые автоматизации, мультивыбор user/role-полей, график history-number
Инфраструктура автоматизаций:
- триггер task.status_changed оживлён: вызов из executeTaskTransition (fire-and-forget) + фильтр triggerConfig.statusId
- ctx.users.setFieldValue(userId, fieldCodeOrId, value): запись user_profile_field_values с аудитом; для history-number — append в user_field_history (миграция 0078)
- документация sandbox обновлена (Automations.tsx, mcp.ts, AGENTS.md) по критическому правилу 2

Мультивыбор пользователей и ролей в user-поле:
- чекбокс «Множественный выбор (пользователи и роли)» в настройках поля (form_fields.allow_multiple)
- значение — массив ['user:ID','role:ID'], обратная совместимость с одиночными/legacy значениями
- UserRoleMultiSelect в карточке задачи, реестре и диалоге создания (роли добавлены и в одиночный сценарий создания)
- синк в task_assignees итерирует массив; role:ID раскрывается в членов роли; PATCH single — diff старого/нового значений
- отображение массивов: реестр, title-шаблоны, условия полей, MCP update_task_fields
- список орг-ролей (/api/roles) загружается всем пользователям (сервер и так был открыт) — роли доступны не только админам

График history-number в профиле:
- GET /api/users/:id/field-history/:fieldId?period=week|month|quarter|year (агрегация AVG по бакетам)
- диалог с LineChart (recharts) и переключателем периодов по клику на иконку у поля
2026-09-04 19:39:10 +03:00
013e97c8d3 fix(ui): bulk-панель выделения заменяет тулбар на месте — список больше не сдвигается
- Home: панель действий рендерится вместо строки поиска (те же метрики: py-1, h-8 md:h-6)
- Реестр: панель «N выбрано / Удалить» внутри тулбара TaskRegistry (swap содержимого строки)
2026-09-04 14:42:53 +03:00
49209ddacd fix(chat): убрана длинная подсказка из placeholder поля сообщения в чате задачи 2026-09-04 11:43:23 +03:00
9a1a6f45e0 feat(themes): Тема 2.0 — spacing/density/компоненты в скинах, пресеты layout форм, скин pyrus
- tokens: spacing (fieldGap/controlPadding/sectionGap/pageGutter), density (пресеты compact/comfortable/spacious + высоты), components (control.variant, label, form.columns, dialog, table, button, motion)
- componentsToCssVars: варианты → CSS-переменные; контролы/таблицы/диалоги/кнопки читают var-ы с fallback'ами (обратная совместимость)
- useSkinComponents() для структурных вариантов
- AppearanceSettings: секция «Компоненты и отступы» + экспорт/импорт темы JSON
- layouts/: пресеты compact/vertical/pyrus представления карточки, выбор в FormEditor без кода (@preset:<id>), предпросмотр
- FieldValueRow вынесен в components/task-fields/ (пресеты с per-field редактированием)
- ctx.libs: +TaskChat, extraCtx: +transitions/assignees
- skins/pyrus: dark-first по мотивам Pyrus, compact density, filled-контролы, WCAG-контрасты
2026-09-04 09:31:43 +03:00
67dbf90d65 feat(gps): мосты-предположения по дорогам между GPS-якорями на LBS-участках (OSRM route, пунктир) 2026-08-31 21:30:17 +03:00
0ad9bb8715 fix(gps): убран слой детекции LBS по stale re-send (помечал ~100% точек); is_lbs только по протокольному флагу valid=false + физика 2026-08-31 17:02:56 +03:00
bec3cc054d feat(gps): траекторный фильтр трека (медианный якорь из 10 точек + lookahead-подтверждение переезда); скорость у выживших LBS-точек с «~» 2026-08-30 20:26:36 +03:00
0386005463 fix(gps): LBS-точки без линий (конец «мяча»), честные поездки без фейковых разрывов, тост OSRM только при реальной недоступности 2026-08-30 12:49:00 +03:00
3ff74d0d17 fix(gps): zIndex точек трека над полилиниями + capture-клики; offroad-фильтр LBS при выдаче трека (чистит старый «мяч») 2026-08-29 21:36:55 +03:00
a302f0c0ea feat(gps): фильтр «далеко от дороги» в LBS-режиме (offRoadMeters, OSRM nearest); пробег «точно + примерно (по вышкам)» в Маршрутах 2026-08-29 21:12:09 +03:00
9eaff65500 fix(gps): подписи Старт/Финиш не обрезаются; data-gps-marker-id на маркерах — надёжная доставка кликов (панель точки, плейхед) 2026-08-29 20:58:08 +03:00
60bd52b75a feat(gps): режим «потерян GPS» — LBS-точки помечаются (is_lbs), примерная позиция на карте, пунктир в треке; OSRM map matching трека (matched endpoint + переключатель «По дорогам») 2026-08-28 17:22:57 +03:00
5d45084af1 feat(gps): автообновление списка объектов каждые 30 сек (бейдж «Нет GPS» гаснет сам) 2026-08-28 16:09:14 +03:00
6688b49d4b fix(gps): непрозрачная инфо-панель точки трека (bg-card вместо bg-background/95) 2026-08-28 15:13:03 +03:00
1df7b06630 fix(gps): инфо-панель точки трека вместо balloon провайдера (время/скорость/направление + плейхед) 2026-08-28 13:29:11 +03:00
3ea0f8c187 feat(gps): фронт индикатора потери GPS — бейдж «Нет GPS» в объектах, настройка порога в часах 2026-08-28 10:53:34 +03:00
96e088c890 fix(gps): фильтр несогласованности скоростей против LBS-телепортов; fix: плейхед не закрывает balloon точек трека 2026-08-28 10:33:45 +03:00
ac4f89d42e feat(gps): фильтры heartbeat-эхо/valid=false/spike; доступ к GPS и Финансам — матрица на /users (пользователи+роли) 2026-08-26 17:13:49 +03:00
2fb7ad6606 fix(pwa): добавлен interactive-widget=resizes-content в viewport
Без этого на Android при открытии клавиатуры viewport не уменьшался,
и поле ввода сообщения в чате/задаче перекрывалось клавиатурой
или «убегало» вверх вместе с контентом.
2026-08-26 15:10:09 +03:00
5e8103a6da fix(push): bump SW to v12, улучшен openOrFocusChat и notificationclick
- openOrFocusChat: includeUncontrolled=true, логирование, try/catch, fallback на clients.openWindow.
- notificationclick: логирование data, fallback построения URL из вложенного data.data.
- markNotificationRead: поддержка type/messageId/conversationId на верхнем уровне и во вложенном data.
- Bump CACHE_NAME до v12 для принудительного обновления SW.
2026-08-26 14:54:37 +03:00
8a649541fb feat(button): связь parent/child и копирование полей для кнопки создания задачи
- В настройках кнопки «Создать задачу по форме» добавлен выбор связи: новая задача — родительская или дочерняя (task_relations).
- Добавлено копирование значений полей из текущей задачи в новую через визуальный маппинг в отдельном диалоге (ButtonCopyFieldsDialog).
- Маппинг хранится в form_fields.options.copyFields, связь — в options.relationType.
- CreateTaskDialog/CreateTaskFormContent поддерживают initialValues (объектные значения) и parentTaskId.
2026-08-26 11:24:56 +03:00