Commit Graph

25 Commits

Author SHA1 Message Date
e4f9a1992a feat(automations): ctx.tasks.scheduleStatusChange — отложенная смена статуса (воркер 5с, отмена при ручном переходе) 2026-09-17 16:38:56 +03:00
0b2319b11d feat(automations): ctx.tasks.sendMessage — сообщение в чат задачи от Системы; userId в triggerData status_changed 2026-09-08 16:31:59 +03:00
667a321341 perf(sse+tasks): индекс SSE-соединений, getTaskTree на recursive CTE, батчи N+1
Шаги 1.4 и 1.5 плана production-готовности:
- SseConnectionIndex (byOrg/byUser), один heartbeat-таймер, протокол SSE не тронут
- getTaskTree/getTaskParentChain: WITH RECURSIVE CTE (было 1+2N запросов)
- sync initial/delta: Promise.all по формам
- embedding queue/reindex: батч-предзагрузки вместо поштучных запросов
- 8 новых тестов (96/96)
2026-09-07 23:29:21 +03:00
9528a8123a perf(directories): SQL-фильтрация/пагинация справочников, N+1, лимиты column-values
Шаги 1.1 и 1.2 плана production-готовности:
- getDataTableRowsPaged: фильтры/поиск/сортировка/пагинация в SQL (values->>N)
- getDataTablesWithAccess и list_directories без N+1
- /column-values: limit (дефолт 20, кап 1000), убраны debug-логи с горячего пути
- tree-режим и legacy-путь TableEditor сохранены 1:1
- 10 новых тестов (88/88)
2026-09-07 23:09:15 +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
cf6f937108 security(users): SafeUser — passwordHash/токены не уходят клиенту
Шаг 0.8 плана production-готовности:
- shared/schema.ts: тип SafeUser + safeUserColumns
- getUsersByOrganization, listUsers, searchUsers, getUsersByRole,
  getUsersByOrgRoleId, documents getUser — без чувствительных колонок
- sync (initial/delta), автоматизации ctx.users.list, MCP list_users — sanitized
2026-09-07 21:03:00 +03:00
0bde7764b1 MCP create_task: создание исполнителя в task_assignees при assigned_to
Раньше assigned_to писался только в legacy-колонку tasks.assigned_to, а запись
в task_assignees (модель исполнителей) не создавалась — из-за этого автоматизации,
читающие ctx.tasks.getAssignees (например «Ответственный в состав бригады»),
видели пустой список исполнителей для задач, созданных через MCP
2026-09-06 13:10:27 +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
005a51e367 fix: MCP update_task_status запускает автоматизации task.status_changed (раньше обходил executeTaskTransition) 2026-09-04 20:32:06 +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
667bddeac9 feat: замещение пользователей (substitution) — заместители по умолчанию и по формам, контур ознакомления, inbox reasons
- таблица user_delegations (миграция 0067) + колонки delegated_from_user_id/pending_review в task_assignees
- delegation.service: резолвер с цепочкой и защитой от циклов, bulk-до-назначение чанками, чистка истёкших замещений
- центральный хук в addTaskAssignee: заместитель добавляется при любом назначении (ручном, автопереходе, user-поле, MCP)
- контур ознакомления: после перехода отсутствующий остаётся в исполнителях с pending_review, снимается кнопкой «Ознакомлен»
- inbox reasons delegation/delegation_review + фильтр «Замещение» на главной
- блок «Замещение» в профиле пользователя, бейдж «за <имя>» и баннер ознакомления в карточке задачи
2026-08-05 10:44:55 +03:00
b4bded2ffb feat: триггер schedule для автоматизаций — ежедневный запуск по МСК
- планировщик 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 }
2026-07-24 13:52:03 +03:00
59079992dc Фикс предпросмотра файлов с абсолютными self-URL
- extractFileKey понимает абсолютные URL (по pathname) — превью работает для уже записанных файлов
- normalizeFileUrl: абсолютные self-URL нормализуются в относительные при записи file-полей (REST field-values, MCP update_task_fields/upload-инструменты, bot-api, create task)
2026-07-24 11:10:55 +03:00
b981614095 MCP: инструмент update_task_fields — обновление кастомных полей задачи
- Merge-семантика как POST /api/tasks/:id/field-values: upsert/delete, поля типа task пересоздают связи
- Аудит field.changed с актором ключа (бот + metadata.source='mcp'), side-эффекты: автопереходы, заголовок, кэши, SSE
- Доступен только в режиме full, как update_task
2026-07-23 16:31:45 +03:00
affbdeee1e Upload-тикеты: загрузка файлов через REST без знания API-ключа
- MCP create_upload_ticket → короткоживущий uploadUrl (10 мин, in-memory)
- POST /api/upload/ticket/:token — тот же пайплайн (processUploadRequest вынесен из /api/upload), авторизация тикетом, проверки скоупов
- get_api_guide: флоу без ключа — ticket → curl → привязка по fileUrl
2026-07-23 15:53:17 +03:00
af119d1cdc MCP: удалён base64-вариант загрузки файлов — только REST upload + привязка по fileUrl
- upload_file удалён; upload_task_file/upload_message_file/upload_directory_file/upload_table_row_file принимают только fileUrl (+fileName)
- descriptions указывают на REST POST /api/upload и get_api_guide
- server/services/file-upload.service.ts удалён (без base64 не используется)
2026-07-22 16:22:26 +03:00
8cfd49fd9f Атрибуция от бота в MCP/REST + REST API по ключу (этап 2)
- MCP: getActor (владелец ключа + бот), аудит changedByName=бот/label ключа, botId, metadata.source='mcp'; аудит для update_task/update_task_status
- sendTaskMessage: botId (messageType 'bot'), починен путь isBotToken без req.user
- authenticateTokenOrApiKey: JWT или X-Api-Key с белым списком endpoint'ов (/api/upload, messages, field-values, create task), проверки скоупов, аудит source='api'
- Лимиты файлов через env: UPLOAD_IMAGE_MAX_MB=25, UPLOAD_DOC_MAX_MB=100, UPLOAD_MAX_MB=100
- MCP upload-инструменты: параметр fileUrl для привязки уже загруженного файла; новый инструмент get_api_guide
2026-07-22 15:18:04 +03:00
936bce2ba9 MCP: загрузка файлов (base64) в file-поля, комментарии, справочники и таб-таблицы задач
- server/services/file-upload.service.ts: uploadFileFromBase64 (whitelist расширений, magic bytes, лимиты 10/50 МБ, S3/MinIO или локальный диск, запись file_uploads)
- Инструменты (write/full): upload_file, upload_task_file, upload_message_file, upload_directory_file, upload_table_row_file
- Проверки доступа isFormAllowed/isTableAllowed
2026-07-22 11:28:45 +03:00
25f84ee532 MCP: напоминания, уведомления, inbox, агрегации, update_form, дерево задач, поля пользователей, DaData — этап 3
- read: list_task_reminders, list_notifications, get_inbox, aggregate_tasks, get_task_tree, get_user_field_values, dadata_suggest
- write: set_task_reminder, send_notification, mark_notifications_read
- full: delete_task_reminder, update_form, set_user_field_value
2026-07-21 17:30:50 +03:00
05e09fa08b MCP: сообщения задач, исполнители, документы, файлы, аудит — этап 2
- list_task_messages, get_task_assignees, list_document_templates, get_task_file, get_task_audit_log (read)
- send_task_message, generate_document (write); set_task_assignees (full)
- Логика POST /api/tasks/:id/messages вынесена в server/services/task-message.service.ts (переиспользуется route и MCP)
- get_task_file: нативный S3 presigned URL или локальный путь с пояснением
2026-07-21 17:19:22 +03:00
002ce152be MCP: инструменты справочников (data tables) — этап 1
- 15 инструментов: list/get_directory, list_directory_rows (flat/tree), get_directory_row, get_directory_column_values (read); create/bulk_create_directory_row (write); create/update/delete_directory, update/delete/move_directory_row, link/unlink_directories (full)
- Объектные проверки isTableAllowed по scopes.tableIds
- Логика дерева строк вынесена в server/utils/data-table-tree.ts (переиспользуется REST-эндпоинтом и MCP)
- bulkCreateDataTableRows: поддержка parentId и position
2026-07-21 17:02:04 +03:00
a7733b4a03 Права доступа API-ключей: скоупы read/write/full и выборочный доступ к формам и справочникам
- organization_api_keys.scopes (jsonb, NULL = полный доступ для legacy-ключей)
- MCP: фильтрация инструментов по режиму и проверка formIds в handler'ах
- PATCH /api/mcp-keys/:id, валидация скоупов в server/utils/api-key.ts
- UI Settings: диалог создания/редактирования ключа с режимом и мультивыбором форм/справочников
2026-07-21 16:12:55 +03:00
70dfe07fa6 RAG: ночная пакетная индексация эмбеддингов, очередь embedding_queue, MCP get_organization_context, снижение OLLAMA_KEEP_ALIVE 2026-07-08 15:57:25 +03:00
1f5ecb6da4 fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric,
  чтобы браузер не округлял значения через input type=number
- пробелы при вставке в number-поля удаляются
- бэкенд нормализует значения number-полей в строку перед сохранением
- добавлен хелпер normalizeFieldValueForStorage

Closes: искажение расчётного счёта и других длинных числовых полей
2026-07-07 21:03:40 +03:00