From b3915a851cc560e4724220cc7f93f827db9ad4c4 Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Tue, 12 May 2026 12:50:52 +0300 Subject: [PATCH] SECURITY - LAUNCHER: harden storage and access lifecycle --- .env.example | 1 + .gitignore | 5 + public/storage/launcher-data.json | 4241 ----------------- scripts/seed-live-control-plane.mjs | 25 +- server/control-plane-store.mjs | 36 +- server/dev-server.mjs | 340 +- server/storage/.gitkeep | 0 src/app/LauncherApp.tsx | 58 +- src/shared/api/authApi.ts | 2 +- src/shared/api/mockApi.ts | 4 +- src/shared/api/storageApi.ts | 6 +- .../ProfileSettingsPanel.tsx | 67 +- 12 files changed, 459 insertions(+), 4326 deletions(-) delete mode 100644 public/storage/launcher-data.json create mode 100644 server/storage/.gitkeep diff --git a/.env.example b/.env.example index b7013b1..2fe8de7 100644 --- a/.env.example +++ b/.env.example @@ -6,3 +6,4 @@ NODEDC_PLATFORM_ENV=../../NODEDC/platform/infra/.env PORT=5173 LAUNCHER_BASE_URL=http://launcher.local.nodedc TASK_BASE_URL=http://task.local.nodedc +NODEDC_INTERNAL_ACCESS_TOKEN=change-me-generate-with-platform-init-dev-env diff --git a/.gitignore b/.gitignore index 8a3adc5..6de55c0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,9 @@ yarn-debug.log* yarn-error.log* pnpm-debug.log* *.tsbuildinfo +server/storage/* +!server/storage/.gitkeep +public/storage/launcher-data.json +dist/storage/launcher-data.json +public/storage/uploads/ public/storage/backups/ diff --git a/public/storage/launcher-data.json b/public/storage/launcher-data.json deleted file mode 100644 index ceb11da..0000000 --- a/public/storage/launcher-data.json +++ /dev/null @@ -1,4241 +0,0 @@ -{ - "clients": [ - { - "id": "client_romashka", - "type": "company", - "name": "DCTOUCH", - "legalName": "ООО ДИСИТАЧ", - "status": "active", - "contractStartsAt": "2026-05-04T00:00:00.000Z", - "contractEndsAt": null, - "paidUntil": null, - "demoEndsAt": null, - "contactName": "DC", - "contactEmail": "dcctouch@gmail.com", - "notes": "Live-клиент NODE.DC для первичной проверки control-plane, SSO и доступа к сервисам.", - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-08T16:19:24.425Z", - "integrations": { - "taskManager": { - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "workspaces": [ - { - "slug": "nodedc", - "name": "NODE DC", - "isPrimary": true, - "managedBy": "launcher" - }, - { - "slug": "dcabramov", - "name": "DCABRAMOV", - "isPrimary": false, - "managedBy": "launcher" - } - ] - } - }, - "inn": null, - "avatarUrl": "/storage/uploads/1778257160251-eba1370a-2025-05-14-23.46.35.jpg" - } - ], - "users": [ - { - "id": "user_root", - "authentikUserId": "85f83274-6942-4375-b64d-601716d3ae29", - "name": "DC SUDO", - "email": "dcctouch@gmail.com", - "phone": null, - "position": "NODE.DC Super Admin", - "notes": "Главный супер-администратор NODE.DC. Authentik-пользователь уже создан в dev-контуре.", - "avatarUrl": "/storage/uploads/1777901580306-658d5b6b-2026-03-02-19.34.33.png", - "globalStatus": "active", - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-04T13:45:07.613Z" - }, - { - "id": "user_silver_psih", - "authentikUserId": "748490e7-a24b-426a-bf97-b348a2db44b4", - "name": "DC SILVER", - "email": "silver_psih@yahoo.com", - "phone": null, - "position": "Manager", - "notes": "Живой пользователь из Plane. Требует создания/синхронизации в Authentik через Launcher flow.", - "avatarUrl": "/storage/uploads/1777901476392-03f10a36-2022-10-13-20-52-47-0287-2037248814-scale20.00-k_euler_a-0287.jpg", - "globalStatus": "active", - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-10T13:30:31.884Z" - }, - { - "id": "user_constr_dc_yahoo_com", - "authentikUserId": "25686308-f513-428d-b5fc-771b73414a57", - "name": "DC CONSTR", - "email": "constr_dc@yahoo.com", - "phone": null, - "position": null, - "notes": "Создан через публичную регистрацию по инвайту клиента DCTOUCH.", - "avatarUrl": "/storage/uploads/1777992885416-502c0a5d-94-944112_unicorn-clipart-mystical-unicorn-web-server.png", - "globalStatus": "active", - "createdAt": "2026-05-05T14:53:26.607Z", - "updatedAt": "2026-05-07T09:41:41.158Z" - }, - { - "id": "user_support_dctouch_ru", - "authentikUserId": "e3896e96-b9b4-49f7-b591-47b72ca25dc8", - "name": "DC SUPPORT", - "email": "support@dctouch.ru", - "phone": null, - "position": null, - "notes": "Создан через публичную регистрацию по инвайту клиента DCTOUCH.", - "avatarUrl": "/storage/uploads/1778266785899-aa393f19-2025-05-14-23.46.35.jpg", - "globalStatus": "active", - "createdAt": "2026-05-05T16:02:43.235Z", - "updatedAt": "2026-05-08T19:00:01.647Z" - }, - { - "id": "user_silverpsih007_gmail_com", - "authentikUserId": "43b3f644-2a99-4e3e-948f-f199660cc08e", - "name": "DC SILVER007", - "email": "silverpsih007@gmail.com", - "phone": null, - "position": null, - "notes": "Создан через публичную регистрацию по инвайту клиента DCTOUCH.", - "avatarUrl": null, - "globalStatus": "active", - "createdAt": "2026-05-05T17:26:50.184Z", - "updatedAt": "2026-05-07T11:39:41.562Z" - }, - { - "id": "user_abramov_dcconstructions_ru", - "authentikUserId": "58f6fb15-198d-4f6a-b93c-6e08f80deae1", - "name": "DC ABRAMOV", - "email": "abramov@dcconstructions.ru", - "phone": null, - "position": null, - "notes": "Создан через публичную регистрацию по инвайту клиента DCTOUCH.", - "avatarUrl": null, - "globalStatus": "active", - "createdAt": "2026-05-05T22:43:07.620Z", - "updatedAt": "2026-05-05T22:43:22.734Z" - }, - { - "id": "user_support_dcconstructions_ru", - "authentikUserId": "73e3c792-be23-4833-9355-fbfc38310f56", - "name": "DC CONSTRICTIONS", - "email": "support@dcconstructions.ru", - "phone": null, - "position": null, - "notes": "Создан через публичную регистрацию по инвайту клиента DCTOUCH.", - "avatarUrl": null, - "globalStatus": "active", - "createdAt": "2026-05-06T01:06:48.113Z", - "updatedAt": "2026-05-06T01:28:06.887Z" - }, - { - "id": "user_ayo_ayo_ae_gmail_com", - "authentikUserId": "529588a1-48fa-44f7-a2a7-dc24f9b6626b", - "name": "Anna Ayo", - "email": "ayo.ayo.ae@gmail.com", - "phone": null, - "position": null, - "notes": "Создан через публичную регистрацию по инвайту клиента Открытый контур.", - "avatarUrl": "/storage/uploads/1778326544251-ddfabfce-31e1669e-28da-428a-9e2a-d51a781f041f.jpg", - "globalStatus": "active", - "createdAt": "2026-05-09T11:33:58.892Z", - "updatedAt": "2026-05-09T12:34:39.358Z" - }, - { - "id": "user_pupa_mail_ru", - "authentikUserId": "a2a1b489-f492-45a0-a5bd-04f6c1ede80d", - "name": "PUPA", - "email": "pupa@mail.ru", - "phone": null, - "position": null, - "notes": "Создан через публичную регистрацию по инвайту клиента Открытый контур.", - "avatarUrl": null, - "globalStatus": "active", - "createdAt": "2026-05-09T19:37:43.521Z", - "updatedAt": "2026-05-09T19:37:43.533Z" - }, - { - "id": "user_realla_mail_ru", - "authentikUserId": "95b13198-08d8-4674-afb9-03bf45b5f6da", - "name": "АВ", - "email": "realla@mail.ru", - "phone": null, - "position": null, - "notes": "Создан через публичную регистрацию по инвайту клиента Открытый контур.", - "avatarUrl": null, - "globalStatus": "active", - "createdAt": "2026-05-11T09:16:35.282Z", - "updatedAt": "2026-05-11T09:16:35.291Z" - } - ], - "memberships": [ - { - "id": "mem_dc_touch_dctouch", - "clientId": "client_romashka", - "userId": "user_root", - "role": "client_owner", - "status": "active", - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-04T12:55:13.842Z" - }, - { - "id": "mem_silver_psih_dctouch", - "clientId": "client_romashka", - "userId": "user_silver_psih", - "role": "client_admin", - "status": "active", - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-07T11:04:47.173Z" - }, - { - "id": "mem_client_romashka_constr_dc_yahoo_com", - "clientId": "client_romashka", - "userId": "user_constr_dc_yahoo_com", - "role": "client_admin", - "status": "active", - "createdAt": "2026-05-05T14:53:26.607Z", - "updatedAt": "2026-05-07T09:41:39.935Z" - }, - { - "id": "mem_client_romashka_support_dctouch_ru", - "clientId": "client_romashka", - "userId": "user_support_dctouch_ru", - "role": "client_admin", - "status": "active", - "createdAt": "2026-05-05T16:02:43.235Z", - "updatedAt": "2026-05-08T11:44:24.773Z" - }, - { - "id": "mem_client_romashka_silverpsih007_gmail_com", - "clientId": "client_romashka", - "userId": "user_silverpsih007_gmail_com", - "role": "client_admin", - "status": "active", - "createdAt": "2026-05-05T17:26:50.184Z", - "updatedAt": "2026-05-07T11:39:39.407Z" - }, - { - "id": "mem_client_romashka_abramov_dcconstructions_ru", - "clientId": "client_romashka", - "userId": "user_abramov_dcconstructions_ru", - "role": "member", - "status": "active", - "createdAt": "2026-05-05T22:43:07.620Z", - "updatedAt": "2026-05-05T22:43:07.620Z" - }, - { - "id": "mem_client_romashka_support_dcconstructions_ru", - "clientId": "client_romashka", - "userId": "user_support_dcconstructions_ru", - "role": "member", - "status": "active", - "createdAt": "2026-05-06T01:06:48.113Z", - "updatedAt": "2026-05-06T01:06:48.113Z" - }, - { - "id": "mem_client_public_pool_ayo_ayo_ae_gmail_com", - "clientId": "client_public_pool", - "userId": "user_ayo_ayo_ae_gmail_com", - "role": "member", - "status": "active", - "createdAt": "2026-05-09T11:33:58.892Z", - "updatedAt": "2026-05-09T11:33:58.892Z" - }, - { - "id": "mem_client_public_pool_pupa_mail_ru", - "clientId": "client_public_pool", - "userId": "user_pupa_mail_ru", - "role": "member", - "status": "active", - "invitedByUserId": "user_ayo_ayo_ae_gmail_com", - "inviteId": "invite_ayoyoyo_pupa_mail_ru", - "source": "tasker_workspace_invite", - "sourceTaskerInviteRequestId": "tasker_invite_request_ayoyoyo_pupa_mail_ru", - "createdAt": "2026-05-09T19:37:43.521Z", - "updatedAt": "2026-05-09T19:37:43.521Z" - }, - { - "id": "mem_client_public_pool_realla_mail_ru", - "clientId": "client_public_pool", - "userId": "user_realla_mail_ru", - "role": "member", - "status": "active", - "invitedByUserId": "user_root", - "inviteId": "invite_realla_mail_ru", - "source": "access_request", - "sourceTaskerInviteRequestId": null, - "createdAt": "2026-05-11T09:16:35.282Z", - "updatedAt": "2026-05-11T09:16:35.282Z" - } - ], - "groups": [ - { - "id": "group_dctouch_admins", - "clientId": "client_romashka", - "name": "Администраторы", - "description": "Администраторы клиента и владельцы платформенного доступа.", - "memberIds": [ - "user_root" - ], - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-04T12:55:13.842Z" - }, - { - "id": "group_dctouch_managers", - "clientId": "client_romashka", - "name": "Менеджеры", - "description": "Рабочая группа менеджеров с доступом к операционному контуру.", - "memberIds": [ - "user_silver_psih" - ], - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-04T12:55:13.842Z" - } - ], - "services": [ - { - "id": "service_nodedc", - "slug": "nodedc", - "title": "AGENT CORE", - "subtitle": "Агентная платформа", - "description": "Сборка, запуск и мониторинг агентных workflow.", - "fullDescription": "Среда для сборки и управления AI-агентами: сценарии, интеграции, ключи, запуск процессов и runtime-мониторинг в одном контуре. Агентные результаты можно передавать в операционный модуль, CRM, рабочие группы и другие системы.", - "url": "https://nodedc.ru/", - "launchUrl": "https://nodedc.ru/", - "accentColor": "#B5FF5A", - "fallbackGradient": "linear-gradient(128deg, rgba(181, 255, 90, 0.84), rgba(37, 58, 36, 0.86) 42%, #0A0D10 82%)", - "status": "active", - "order": 10, - "authentikApplicationSlug": "nodedc", - "authentikGroupName": "service-nodedc", - "createdAt": "2026-04-01T10:00:00Z", - "updatedAt": "2026-05-02T11:52:29.667Z", - "coverImageUrl": "/storage/uploads/1777649382309-49d8c393-2026-05-01-17.31.21.jpg", - "coverMediaKind": "image", - "coverMediaSource": "file", - "coverMediaFileName": "1777649382309-49d8c393-2026-05-01-17.31.21.jpg", - "ambientVideoUrl": "/storage/uploads/1777649395844-a878de95-090aff247929335.69e6521716ea9.gif", - "ambientMediaKind": "gif", - "ambientMediaSource": "file", - "ambientMediaFileName": "1777649395844-a878de95-090aff247929335.69e6521716ea9.gif" - }, - { - "id": "service_task_manager", - "slug": "task-manager", - "title": "OPERATIONAL CORE", - "subtitle": "Операционный слой", - "description": "Задачи, контуры предприятия, процессы и AI-функции поверх задачника.", - "fullDescription": "Операционный контур для совместной работы людей и AI-агентов. Задачи, поручения, согласования и результаты агентных запусков собираются в единую рабочую среду для управления процессами.", - "url": "https://tasks.handhdc.ru/sso/launch", - "launchUrl": "https://tasks.handhdc.ru/sso/launch", - "accentColor": "#D7C8FF", - "fallbackGradient": "linear-gradient(132deg, rgba(215, 200, 255, 0.82), rgba(51, 41, 79, 0.9) 46%, #0B0D10 84%)", - "status": "active", - "order": 20, - "authentikApplicationSlug": "task-manager", - "authentikGroupName": "service-task-manager", - "createdAt": "2026-04-01T10:00:00Z", - "updatedAt": "2026-05-02T11:52:46.023Z", - "coverImageUrl": "/storage/uploads/1777652545129-cf547e17-NODEDC_TASK.png", - "coverMediaKind": "image", - "coverMediaSource": "file", - "coverMediaFileName": "1777652545129-cf547e17-NODEDC_TASK.png" - }, - { - "id": "service_1c", - "slug": "1c-assistant", - "title": "1C AI ASSISTANT", - "subtitle": "Бухгалтерский ассистент", - "description": "Вопросы к 1С, точные выборки и доказательная навигация по данным.", - "fullDescription": "Ассистент для работы с данными 1С через естественный язык: операции, остатки, задолженности, документы, налоги, контрагенты и бухгалтерские показатели доступны в формате точных запросов и проверяемых ответов.", - "url": "https://1c.handhdc.ru/sso/launch", - "launchUrl": "https://1c.handhdc.ru/sso/launch", - "accentColor": "#8FD7FF", - "fallbackGradient": "linear-gradient(126deg, rgba(143, 215, 255, 0.8), rgba(32, 61, 80, 0.9) 44%, #080B0F 84%)", - "status": "maintenance", - "order": 40, - "authentikApplicationSlug": "1c-assistant", - "authentikGroupName": "service-1c-assistant", - "createdAt": "2026-04-01T10:00:00Z", - "updatedAt": "2026-05-02T11:53:29.406Z", - "coverImageUrl": "/storage/uploads/1777657277366-a9886413-LLM_MANAGER.png", - "coverMediaKind": "image", - "coverMediaSource": "file", - "coverMediaFileName": "1777657277366-a9886413-LLM_MANAGER.png" - }, - { - "id": "service_tender", - "slug": "tender-agent", - "title": "TENDER AI AGENT", - "subtitle": "Госзакупки и тендеры", - "description": "Поиск, анализ и подготовка тендерных решений.", - "fullDescription": "Агент для поиска, отбора и анализа тендеров: собирает данные с площадок, разбирает документы, оценивает риски, участников и условия закупки, после чего передаёт результат в рабочий контур для дальнейшей обработки.", - "url": "https://tender.handhdc.ru/sso/launch", - "launchUrl": "https://tender.handhdc.ru/sso/launch", - "accentColor": "#FFD166", - "fallbackGradient": "linear-gradient(135deg, rgba(255, 209, 102, 0.84), rgba(74, 53, 19, 0.92) 42%, #0B0D10 86%)", - "status": "active", - "order": 30, - "authentikApplicationSlug": "tender-agent", - "authentikGroupName": "service-tender-agent", - "createdAt": "2026-04-03T10:00:00Z", - "updatedAt": "2026-05-02T11:53:12.714Z", - "coverImageUrl": "/storage/uploads/1777652810531-1f17b7ed-LAP_PURP4k.jpg", - "coverMediaKind": "image", - "coverMediaSource": "file", - "coverMediaFileName": "1777652810531-1f17b7ed-LAP_PURP4k.jpg", - "ambientVideoUrl": "/storage/uploads/1777652817155-199c5e6c-090aff247929335.69e6521716ea9.gif", - "ambientMediaKind": "gif", - "ambientMediaSource": "file", - "ambientMediaFileName": "1777652817155-199c5e6c-090aff247929335.69e6521716ea9.gif" - }, - { - "id": "service_digital_twin", - "slug": "digital-twin", - "title": "DIGITAL TWIN MOSCOW", - "subtitle": "3D и пространственные данные", - "description": "Просмотр цифровых двойников, карт и объектных сцен.", - "fullDescription": "Городская цифровая витрина на базе отсканированных пространств Москвы: 3D-сцены, объекты, слои, инфраструктура, статусы и телеметрия объединяются в интерактивную среду для просмотра, анализа и мониторинга.", - "url": "https://launch.dcserve.ru/", - "launchUrl": "https://launch.dcserve.ru/", - "accentColor": "#76E4F7", - "fallbackGradient": "linear-gradient(140deg, rgba(118, 228, 247, 0.82), rgba(23, 69, 87, 0.92) 47%, #080B0F 86%)", - "status": "active", - "order": 50, - "authentikApplicationSlug": "digital-twin", - "authentikGroupName": "service-digital-twin", - "createdAt": "2026-04-05T10:00:00Z", - "updatedAt": "2026-05-02T11:53:43.705Z", - "coverImageUrl": "/storage/uploads/1777711943125-691830c2-NODEDC_DT_MMAP.png", - "coverMediaKind": "image", - "coverMediaSource": "file", - "coverMediaFileName": "1777711943125-691830c2-NODEDC_DT_MMAP.png" - } - ], - "grants": [ - { - "id": "grant_dctouch_task_admins", - "serviceId": "service_task_manager", - "targetType": "group", - "targetId": "group_dctouch_admins", - "appRole": "admin", - "status": "active", - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-04T12:55:13.842Z" - }, - { - "id": "grant_dctouch_task_managers", - "serviceId": "service_task_manager", - "targetType": "group", - "targetId": "group_dctouch_managers", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-04T12:55:13.842Z" - }, - { - "id": "grant_dctouch_nodedc_admins", - "serviceId": "service_nodedc", - "targetType": "group", - "targetId": "group_dctouch_admins", - "appRole": "admin", - "status": "active", - "createdAt": "2026-05-04T00:00:00.000Z", - "updatedAt": "2026-05-04T12:55:13.842Z" - }, - { - "id": "grant_digital_twin_user_silver_psih_yahoo_com", - "serviceId": "service_digital_twin", - "targetType": "user", - "targetId": "user_silver_psih", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-04T13:33:42.062Z", - "updatedAt": "2026-05-04T13:33:42.062Z" - }, - { - "id": "grant_task_manager_user_constr_dc_yahoo_com", - "serviceId": "service_task_manager", - "targetType": "user", - "targetId": "user_constr_dc_yahoo_com", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-05T14:57:13.249Z", - "updatedAt": "2026-05-05T14:57:13.249Z" - }, - { - "id": "grant_task_manager_user_silverpsih007_gmail_com", - "serviceId": "service_task_manager", - "targetType": "user", - "targetId": "user_silverpsih007_gmail_com", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-05T17:27:40.540Z", - "updatedAt": "2026-05-05T17:27:40.540Z" - }, - { - "id": "grant_task_manager_user_abramov_dcconstructions_ru", - "serviceId": "service_task_manager", - "targetType": "user", - "targetId": "user_abramov_dcconstructions_ru", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-05T22:43:22.308Z", - "updatedAt": "2026-05-05T22:43:22.308Z" - }, - { - "id": "grant_task_manager_user_support_dcconstructions_ru", - "serviceId": "service_task_manager", - "targetType": "user", - "targetId": "user_support_dcconstructions_ru", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-06T01:28:06.515Z", - "updatedAt": "2026-05-06T01:28:06.515Z" - }, - { - "id": "grant_task_manager_user_support_dctouch_ru", - "serviceId": "service_task_manager", - "targetType": "user", - "targetId": "user_support_dctouch_ru", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-05T16:04:52.709Z", - "updatedAt": "2026-05-08T10:14:37.303Z" - }, - { - "id": "grant_task_manager_user_ayo_ayo_ae_gmail_com", - "serviceId": "service_task_manager", - "targetType": "user", - "targetId": "user_ayo_ayo_ae_gmail_com", - "appRole": "admin", - "status": "active", - "createdAt": "2026-05-09T12:34:38.766Z", - "updatedAt": "2026-05-09T12:34:38.766Z" - }, - { - "id": "grant_task_manager_user_pupa_mail_ru", - "serviceId": "service_task_manager", - "targetType": "user", - "targetId": "user_pupa_mail_ru", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-09T19:37:43.521Z", - "updatedAt": "2026-05-09T19:37:43.521Z" - }, - { - "id": "grant_task_manager_user_silver_psih_yahoo_com", - "serviceId": "service_task_manager", - "targetType": "user", - "targetId": "user_silver_psih", - "appRole": "member", - "status": "active", - "createdAt": "2026-05-04T15:26:07.830Z", - "updatedAt": "2026-05-10T13:30:31.081Z" - } - ], - "exceptions": [], - "invites": [ - { - "id": "invite_constr_dc_yahoo_com", - "clientId": "client_romashka", - "email": "constr_dc@yahoo.com", - "role": "member", - "invitedByUserId": "user_root", - "token": "856d7ef7-f0e0-4f53-8fac-27ed89e67ea0", - "expiresAt": "2026-05-12T13:38:27.256Z", - "status": "accepted", - "createdAt": "2026-05-05T13:38:27.256Z", - "updatedAt": "2026-05-05T14:53:26.607Z" - }, - { - "id": "invite_support_dctouch_ru", - "clientId": "client_romashka", - "email": "support@dctouch.ru", - "role": "member", - "invitedByUserId": "user_root", - "token": "2b8c2c1f-384d-4514-b566-b788b771fe7b", - "expiresAt": "2026-05-12T16:01:01.781Z", - "status": "accepted", - "createdAt": "2026-05-05T16:01:01.781Z", - "updatedAt": "2026-05-05T16:02:43.235Z" - }, - { - "id": "invite_silverpsih007_gmail_com", - "clientId": "client_romashka", - "email": "silverpsih007@gmail.com", - "role": "member", - "invitedByUserId": "user_root", - "token": "fed64a57-bcf5-4e12-b6c9-dbb48725cad6", - "expiresAt": "2026-05-12T17:25:29.607Z", - "status": "accepted", - "createdAt": "2026-05-05T17:25:29.607Z", - "updatedAt": "2026-05-05T17:26:50.184Z" - }, - { - "id": "invite_abramov_dcconstructions_ru", - "clientId": "client_romashka", - "email": "abramov@dcconstructions.ru", - "role": "member", - "invitedByUserId": "user_root", - "token": "fca2b781-8e42-4c14-beac-3f67a58e28bd", - "expiresAt": "2026-05-12T22:41:52.296Z", - "status": "accepted", - "createdAt": "2026-05-05T22:41:52.296Z", - "updatedAt": "2026-05-05T22:43:07.620Z" - }, - { - "id": "invite_support_dcconstructions_ru", - "clientId": "client_romashka", - "email": "support@dcconstructions.ru", - "role": "member", - "invitedByUserId": "user_root", - "token": "3f5293a4-ed05-455b-ae65-1c91d9496519", - "expiresAt": "2026-05-13T01:04:54.007Z", - "status": "accepted", - "createdAt": "2026-05-06T01:04:54.007Z", - "updatedAt": "2026-05-06T01:06:48.113Z" - }, - { - "id": "invite_ayo_ayo_ae_gmail_com", - "clientId": "client_public_pool", - "email": "ayo.ayo.ae@gmail.com", - "role": "member", - "invitedByUserId": "user_root", - "token": "2555c4e6-6a84-429c-8f21-bb41a5e51c28", - "expiresAt": "2026-05-16T11:32:40.371Z", - "status": "accepted", - "createdAt": "2026-05-09T11:32:40.370Z", - "updatedAt": "2026-05-09T11:33:58.892Z" - }, - { - "id": "invite_ayoyoyo_pupa_mail_ru", - "clientId": "client_public_pool", - "email": "pupa@mail.ru", - "role": "member", - "invitedByUserId": "user_ayo_ayo_ae_gmail_com", - "source": "tasker_workspace_invite", - "sourceTaskerInviteRequestId": "tasker_invite_request_ayoyoyo_pupa_mail_ru", - "sourceTaskerInviteId": "9b470198-5685-4ebf-b330-75b357363e97", - "sourceWorkspaceSlug": "ayoyoyo", - "sourceWorkspaceName": "AYOYOYO", - "sourceTaskerInviteLink": "http://task.local.nodedc/workspace-invitations/?invitation_id=9b470198-5685-4ebf-b330-75b357363e97&slug=ayoyoyo&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6eyJlbWFpbCI6InB1cGFAbWFpbC5ydSIsInJvbGUiOjE1fSwidGltZXN0YW1wIjoxNzc4MzU1Mzc5LjI4MDg0MX0.q9fLuUBLXNYK9XZk0y02zjc55uixPfKTMiS92oOfEoU", - "token": "dee0814c-917a-456c-be5d-f8da468136c9", - "expiresAt": "2026-05-16T19:36:41.118Z", - "status": "accepted", - "createdAt": "2026-05-09T19:36:41.118Z", - "updatedAt": "2026-05-09T19:37:43.521Z" - }, - { - "id": "invite_realla_mail_ru", - "clientId": "client_public_pool", - "email": "realla@mail.ru", - "role": "member", - "invitedByUserId": "user_root", - "source": "access_request", - "sourceTaskerInviteRequestId": null, - "sourceTaskerInviteId": null, - "sourceWorkspaceSlug": null, - "sourceWorkspaceName": null, - "token": "02bbfc59-0bc4-4eb0-8128-46eabee23a46", - "expiresAt": "2026-05-17T13:18:41.837Z", - "status": "accepted", - "createdAt": "2026-05-10T13:18:41.837Z", - "updatedAt": "2026-05-11T09:16:35.282Z" - } - ], - "syncStatuses": [ - { - "id": "sync_dctouch_client_authentik", - "objectId": "client_romashka", - "objectName": "DCTOUCH", - "objectType": "client", - "target": "authentik", - "state": "pending", - "lastSyncAt": "2026-05-04T12:55:13.842Z", - "error": null, - "updatedAt": "2026-05-08T16:19:24.425Z" - }, - { - "id": "sync_dc_touch_authentik", - "objectId": "user_root", - "objectName": "dcctouch@gmail.com", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-04T13:45:07.613Z", - "error": null, - "updatedAt": "2026-05-04T13:45:07.613Z" - }, - { - "id": "sync_silver_psih_authentik", - "objectId": "user_silver_psih", - "objectName": "silver_psih@yahoo.com", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-10T13:30:31.884Z", - "error": null, - "updatedAt": "2026-05-10T13:30:31.884Z" - }, - { - "id": "sync_dctouch_groups_authentik", - "objectId": "client_romashka:groups", - "objectName": "DCTOUCH groups", - "objectType": "group", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-04T12:55:13.842Z" - }, - { - "id": "sync_task_manager_authentik", - "objectId": "service_task_manager", - "objectName": "OPERATIONAL CORE", - "objectType": "service", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-04T12:55:13.842Z", - "error": null, - "updatedAt": "2026-05-04T12:55:13.842Z" - }, - { - "id": "sync_grant_service_digital_twin_user_silver_psih", - "objectId": "service_digital_twin:user_silver_psih", - "objectName": "digital-twin:silver_psih@yahoo.com", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-04T13:33:42.062Z" - }, - { - "id": "sync_grant_service_task_manager_user_silver_psih", - "objectId": "service_task_manager:user_silver_psih", - "objectName": "task-manager:silver_psih@yahoo.com", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-10T13:30:31.081Z" - }, - { - "id": "sync_invite_invite_constr_dc_yahoo_com", - "objectId": "invite_constr_dc_yahoo_com", - "objectName": "constr_dc@yahoo.com", - "objectType": "invite", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-05T13:38:28.642Z" - }, - { - "id": "sync_user_user_constr_dc_yahoo_com", - "objectId": "user_constr_dc_yahoo_com", - "objectName": "constr_dc@yahoo.com", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-07T09:41:41.158Z", - "error": null, - "updatedAt": "2026-05-07T09:41:41.158Z" - }, - { - "id": "sync_grant_service_task_manager_user_constr_dc_yahoo_com", - "objectId": "service_task_manager:user_constr_dc_yahoo_com", - "objectName": "task-manager:constr_dc@yahoo.com", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-05T14:57:13.253Z" - }, - { - "id": "sync_invite_invite_support_dctouch_ru", - "objectId": "invite_support_dctouch_ru", - "objectName": "support@dctouch.ru", - "objectType": "invite", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-05T16:01:06.477Z" - }, - { - "id": "sync_user_user_support_dctouch_ru", - "objectId": "user_support_dctouch_ru", - "objectName": "support@dctouch.ru", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-08T19:00:01.647Z", - "error": null, - "updatedAt": "2026-05-08T19:00:01.647Z" - }, - { - "id": "sync_grant_service_task_manager_user_support_dctouch_ru", - "objectId": "service_task_manager:user_support_dctouch_ru", - "objectName": "task-manager:support@dctouch.ru", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-08T10:14:37.305Z" - }, - { - "id": "sync_invite_invite_silverpsih007_gmail_com", - "objectId": "invite_silverpsih007_gmail_com", - "objectName": "silverpsih007@gmail.com", - "objectType": "invite", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-05T17:25:31.407Z" - }, - { - "id": "sync_user_user_silverpsih007_gmail_com", - "objectId": "user_silverpsih007_gmail_com", - "objectName": "silverpsih007@gmail.com", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-07T11:39:41.562Z", - "error": null, - "updatedAt": "2026-05-07T11:39:41.562Z" - }, - { - "id": "sync_grant_service_task_manager_user_silverpsih007_gmail_com", - "objectId": "service_task_manager:user_silverpsih007_gmail_com", - "objectName": "task-manager:silverpsih007@gmail.com", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-05T17:27:40.543Z" - }, - { - "id": "sync_invite_invite_abramov_dcconstructions_ru", - "objectId": "invite_abramov_dcconstructions_ru", - "objectName": "abramov@dcconstructions.ru", - "objectType": "invite", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-05T22:41:56.561Z" - }, - { - "id": "sync_user_user_abramov_dcconstructions_ru", - "objectId": "user_abramov_dcconstructions_ru", - "objectName": "abramov@dcconstructions.ru", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-05T22:43:22.734Z", - "error": null, - "updatedAt": "2026-05-05T22:43:22.734Z" - }, - { - "id": "sync_grant_service_task_manager_user_abramov_dcconstructions_ru", - "objectId": "service_task_manager:user_abramov_dcconstructions_ru", - "objectName": "task-manager:abramov@dcconstructions.ru", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-05T22:43:22.308Z" - }, - { - "id": "sync_invite_invite_support_dcconstructions_ru", - "objectId": "invite_support_dcconstructions_ru", - "objectName": "support@dcconstructions.ru", - "objectType": "invite", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-06T01:04:56.745Z" - }, - { - "id": "sync_user_user_support_dcconstructions_ru", - "objectId": "user_support_dcconstructions_ru", - "objectName": "support@dcconstructions.ru", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-06T01:28:06.887Z", - "error": null, - "updatedAt": "2026-05-06T01:28:06.887Z" - }, - { - "id": "sync_grant_service_task_manager_user_support_dcconstructions_ru", - "objectId": "service_task_manager:user_support_dcconstructions_ru", - "objectName": "task-manager:support@dcconstructions.ru", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-06T01:28:06.516Z" - }, - { - "id": "sync_invite_invite_ayo_ayo_ae_gmail_com", - "objectId": "invite_ayo_ayo_ae_gmail_com", - "objectName": "ayo.ayo.ae@gmail.com", - "objectType": "invite", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-09T11:32:51.152Z" - }, - { - "id": "sync_user_user_ayo_ayo_ae_gmail_com", - "objectId": "user_ayo_ayo_ae_gmail_com", - "objectName": "ayo.ayo.ae@gmail.com", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-09T12:34:39.358Z", - "error": null, - "updatedAt": "2026-05-09T12:34:39.358Z" - }, - { - "id": "sync_grant_service_task_manager_user_ayo_ayo_ae_gmail_com", - "objectId": "service_task_manager:user_ayo_ayo_ae_gmail_com", - "objectName": "task-manager:ayo.ayo.ae@gmail.com", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-09T12:34:38.766Z" - }, - { - "id": "sync_grant_service_task_manager_user_alah_gmail_com", - "objectId": "service_task_manager:user_alah_gmail_com", - "objectName": "task-manager:alah@gmail.com", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-09T18:58:27.834Z" - }, - { - "id": "sync_grant_service_task_manager_user_pupa_mail_ru", - "objectId": "service_task_manager:user_pupa_mail_ru", - "objectName": "task-manager:pupa@mail.ru", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-09T19:37:43.521Z" - }, - { - "id": "sync_user_user_pupa_mail_ru", - "objectId": "user_pupa_mail_ru", - "objectName": "pupa@mail.ru", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-09T19:37:43.533Z", - "error": null, - "updatedAt": "2026-05-09T19:37:43.533Z" - }, - { - "id": "sync_invite_invite_realla_mail_ru", - "objectId": "invite_realla_mail_ru", - "objectName": "realla@mail.ru", - "objectType": "invite", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-11T09:11:46.244Z" - }, - { - "id": "sync_grant_service_task_manager_user_alla_mail_ru", - "objectId": "service_task_manager:user_alla_mail_ru", - "objectName": "task-manager:alla@mail.ru", - "objectType": "grant", - "target": "authentik", - "state": "pending", - "lastSyncAt": null, - "error": null, - "updatedAt": "2026-05-10T18:48:11.279Z" - }, - { - "id": "sync_user_user_realla_mail_ru", - "objectId": "user_realla_mail_ru", - "objectName": "realla@mail.ru", - "objectType": "user", - "target": "authentik", - "state": "synced", - "lastSyncAt": "2026-05-11T09:16:35.291Z", - "error": null, - "updatedAt": "2026-05-11T09:16:35.291Z" - } - ], - "auditEvents": [ - { - "id": "audit_1778336274475_tasker_invite_cancelled", - "createdAt": "2026-05-09T14:17:54.470Z", - "actorUserId": null, - "actorName": "Operational Core", - "action": "Отозвана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@mail.ru", - "result": "warning", - "details": "Отозвано в Operational Core" - }, - { - "id": "audit_live_seed_control_plane", - "at": "2026-05-04T12:55:13.842Z", - "actorUserId": "system", - "actorName": "NODE.DC seed", - "action": "Применён live seed control-plane", - "objectType": "control_plane", - "objectName": "Launcher users and access", - "clientId": "client_romashka", - "result": "success", - "details": "Demo-участники удалены из runtime storage. Оставлены dcctouch@gmail.com и silver_psih@yahoo.com." - }, - { - "id": "audit_silver_psih_yahoo_com", - "at": "2026-05-04T13:31:18.416Z", - "actorUserId": "user_silver_psih", - "actorName": "Silver Psy", - "action": "Обновлён профиль пользователя", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": null - }, - { - "id": "audit_silver_psih_yahoo_com_2", - "at": "2026-05-04T13:31:18.693Z", - "actorUserId": "user_silver_psih", - "actorName": "DC SILVER", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_dcctouch_gmail_com", - "at": "2026-05-04T13:33:03.295Z", - "actorUserId": "user_root", - "actorName": "DC Touch", - "action": "Обновлён профиль пользователя", - "objectType": "user", - "objectName": "dcctouch@gmail.com", - "clientId": null, - "result": "success", - "details": null - }, - { - "id": "audit_dcctouch_gmail_com_2", - "at": "2026-05-04T13:33:03.579Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "dcctouch@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:superadmin, nodedc:launcher:admin, nodedc:taskmanager:admin, nodedc:taskmanager:user" - }, - { - "id": "audit_silver_psih_yahoo_com_digital_twin", - "at": "2026-05-04T13:33:42.062Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / digital-twin", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager", - "at": "2026-05-04T13:34:41.114Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_dcctouch_gmail_com_3", - "at": "2026-05-04T13:45:07.614Z", - "actorUserId": "system", - "actorName": "Codex access sync", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "dcctouch@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:superadmin, nodedc:launcher:admin, nodedc:taskmanager:admin, nodedc:taskmanager:user" - }, - { - "id": "audit_silver_psih_yahoo_com_3", - "at": "2026-05-04T13:45:07.954Z", - "actorUserId": "system", - "actorName": "Codex access sync", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_2", - "at": "2026-05-04T13:50:03.850Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_4", - "at": "2026-05-04T13:50:04.107Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_5", - "at": "2026-05-04T14:00:23.198Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_3", - "at": "2026-05-04T14:00:25.625Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_silver_psih_yahoo_com_6", - "at": "2026-05-04T14:00:25.848Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_7", - "at": "2026-05-04T14:00:35.727Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_8", - "at": "2026-05-04T14:00:43.300Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_4", - "at": "2026-05-04T14:00:46.785Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_9", - "at": "2026-05-04T14:00:47.011Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_10", - "at": "2026-05-04T14:01:28.244Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_11", - "at": "2026-05-04T14:01:31.878Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_12", - "at": "2026-05-04T14:01:33.920Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_5", - "at": "2026-05-04T14:01:35.987Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_silver_psih_yahoo_com_13", - "at": "2026-05-04T14:01:36.184Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_14", - "at": "2026-05-04T14:01:44.613Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_15", - "at": "2026-05-04T14:01:46.978Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_16", - "at": "2026-05-04T14:01:48.992Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_17", - "at": "2026-05-04T14:01:51.455Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_6", - "at": "2026-05-04T14:01:53.407Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_18", - "at": "2026-05-04T14:01:53.622Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_7", - "at": "2026-05-04T14:09:21.076Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_silver_psih_yahoo_com_19", - "at": "2026-05-04T14:09:21.315Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_8", - "at": "2026-05-04T14:09:27.239Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_20", - "at": "2026-05-04T14:09:27.516Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_21", - "at": "2026-05-04T14:09:39.517Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_22", - "at": "2026-05-04T14:09:44.175Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_9", - "at": "2026-05-04T14:09:47.316Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_silver_psih_yahoo_com_23", - "at": "2026-05-04T14:09:47.519Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_24", - "at": "2026-05-04T14:09:54.512Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_25", - "at": "2026-05-04T14:09:56.599Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_26", - "at": "2026-05-04T14:10:10.975Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_27", - "at": "2026-05-04T14:10:13.786Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_28", - "at": "2026-05-04T14:10:36.419Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_10", - "at": "2026-05-04T14:10:43.069Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_29", - "at": "2026-05-04T14:10:43.376Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_11", - "at": "2026-05-04T14:10:48.109Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_silver_psih_yahoo_com_30", - "at": "2026-05-04T14:10:48.333Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_31", - "at": "2026-05-04T14:10:50.741Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_32", - "at": "2026-05-04T14:10:52.704Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_33", - "at": "2026-05-04T14:10:54.283Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_34", - "at": "2026-05-04T14:11:00.944Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_35", - "at": "2026-05-04T14:11:06.473Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_12", - "at": "2026-05-04T14:14:56.539Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_36", - "at": "2026-05-04T14:14:56.867Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_13", - "at": "2026-05-04T14:14:59.525Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_silver_psih_yahoo_com_37", - "at": "2026-05-04T14:14:59.762Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_14", - "at": "2026-05-04T14:15:10.297Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_38", - "at": "2026-05-04T14:15:10.555Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_15", - "at": "2026-05-04T14:50:51.260Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_silver_psih_yahoo_com_39", - "at": "2026-05-04T14:50:51.574Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_16", - "at": "2026-05-04T14:51:46.812Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_40", - "at": "2026-05-04T14:51:47.092Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_17", - "at": "2026-05-04T15:25:51.639Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_silver_psih_yahoo_com_41", - "at": "2026-05-04T15:25:51.952Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, service-digital-twin" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_18", - "at": "2026-05-04T15:26:07.830Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_42", - "at": "2026-05-04T15:26:08.500Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_digital_modules", - "at": "2026-05-04T19:15:22.791Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Удалён сервис", - "objectType": "service", - "objectName": "Digital Modules", - "clientId": null, - "result": "warning", - "details": null - }, - { - "id": "audit_brand_settings", - "at": "2026-05-05T10:04:34.052Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлены системные настройки", - "objectType": "settings", - "objectName": "Brand settings", - "clientId": null, - "result": "success", - "details": "Logo link: http://launcher.local.nodedc/" - }, - { - "id": "audit_constr_dc_yahoo_com", - "at": "2026-05-05T13:09:04.396Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан инвайт", - "objectType": "invite", - "objectName": "constr_dc@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": "Роль: member" - }, - { - "id": "audit_constr_dc_yahoo_com_2", - "at": "2026-05-05T13:09:11.185Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "constr_dc@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_constr_dc_yahoo_com_3", - "at": "2026-05-05T13:38:19.890Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Удалён инвайт", - "objectType": "invite", - "objectName": "constr_dc@yahoo.com", - "clientId": "client_romashka", - "result": "warning", - "details": null - }, - { - "id": "audit_constr_dc_yahoo_com_4", - "at": "2026-05-05T13:38:27.257Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан инвайт", - "objectType": "invite", - "objectName": "constr_dc@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": "Роль: member" - }, - { - "id": "audit_constr_dc_yahoo_com_5", - "at": "2026-05-05T13:38:28.642Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "constr_dc@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_constr_dc_yahoo_com_6", - "at": "2026-05-05T14:53:26.608Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "constr_dc@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_constr_dc_yahoo_com_7", - "at": "2026-05-05T14:53:26.613Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "constr_dc@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_constr_dc_yahoo_com_8", - "at": "2026-05-05T14:54:46.980Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Обновлён профиль пользователя", - "objectType": "user", - "objectName": "constr_dc@yahoo.com", - "clientId": null, - "result": "success", - "details": null - }, - { - "id": "audit_constr_dc_yahoo_com_9", - "at": "2026-05-05T14:54:47.242Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "constr_dc@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_constr_dc_yahoo_com_task_manager", - "at": "2026-05-05T14:57:13.253Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "constr_dc@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_constr_dc_yahoo_com_10", - "at": "2026-05-05T14:57:13.515Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "constr_dc@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_support_dctouch_ru", - "at": "2026-05-05T16:01:01.784Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан инвайт", - "objectType": "invite", - "objectName": "support@dctouch.ru", - "clientId": "client_romashka", - "result": "success", - "details": "Роль: member" - }, - { - "id": "audit_support_dctouch_ru_2", - "at": "2026-05-05T16:01:06.477Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "support@dctouch.ru", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_support_dctouch_ru_3", - "at": "2026-05-05T16:02:43.235Z", - "actorUserId": "user_support_dctouch_ru", - "actorName": "DC SUPPORT", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "support@dctouch.ru", - "clientId": "client_romashka", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_support_dctouch_ru_4", - "at": "2026-05-05T16:02:43.242Z", - "actorUserId": "user_support_dctouch_ru", - "actorName": "DC SUPPORT", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "support@dctouch.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_support_dctouch_ru_task_manager", - "at": "2026-05-05T16:04:52.709Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "support@dctouch.ru / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_support_dctouch_ru_5", - "at": "2026-05-05T16:04:53.004Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "support@dctouch.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_silverpsih007_gmail_com", - "at": "2026-05-05T17:25:29.608Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан инвайт", - "objectType": "invite", - "objectName": "silverpsih007@gmail.com", - "clientId": "client_romashka", - "result": "success", - "details": "Роль: member" - }, - { - "id": "audit_silverpsih007_gmail_com_2", - "at": "2026-05-05T17:25:31.407Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "silverpsih007@gmail.com", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_silverpsih007_gmail_com_3", - "at": "2026-05-05T17:26:50.184Z", - "actorUserId": "user_silverpsih007_gmail_com", - "actorName": "DC SILVER007", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "silverpsih007@gmail.com", - "clientId": "client_romashka", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_silverpsih007_gmail_com_4", - "at": "2026-05-05T17:26:50.188Z", - "actorUserId": "user_silverpsih007_gmail_com", - "actorName": "DC SILVER007", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silverpsih007@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_silverpsih007_gmail_com_task_manager", - "at": "2026-05-05T17:27:40.543Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silverpsih007@gmail.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silverpsih007_gmail_com_5", - "at": "2026-05-05T17:27:40.754Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silverpsih007@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_abramov_dcconstructions_ru", - "at": "2026-05-05T22:41:52.301Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан инвайт", - "objectType": "invite", - "objectName": "abramov@dcconstructions.ru", - "clientId": "client_romashka", - "result": "success", - "details": "Роль: member" - }, - { - "id": "audit_abramov_dcconstructions_ru_2", - "at": "2026-05-05T22:41:56.561Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "abramov@dcconstructions.ru", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_abramov_dcconstructions_ru_3", - "at": "2026-05-05T22:43:07.620Z", - "actorUserId": "user_abramov_dcconstructions_ru", - "actorName": "DC ABRAMOV", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "abramov@dcconstructions.ru", - "clientId": "client_romashka", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_abramov_dcconstructions_ru_4", - "at": "2026-05-05T22:43:07.624Z", - "actorUserId": "user_abramov_dcconstructions_ru", - "actorName": "DC ABRAMOV", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "abramov@dcconstructions.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_abramov_dcconstructions_ru_task_manager", - "at": "2026-05-05T22:43:22.308Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "abramov@dcconstructions.ru / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_abramov_dcconstructions_ru_5", - "at": "2026-05-05T22:43:22.734Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "abramov@dcconstructions.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_support_dcconstructions_ru", - "at": "2026-05-06T01:04:54.018Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан инвайт", - "objectType": "invite", - "objectName": "support@dcconstructions.ru", - "clientId": "client_romashka", - "result": "success", - "details": "Роль: member" - }, - { - "id": "audit_support_dcconstructions_ru_2", - "at": "2026-05-06T01:04:56.745Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "support@dcconstructions.ru", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_support_dcconstructions_ru_3", - "at": "2026-05-06T01:06:48.113Z", - "actorUserId": "user_support_dcconstructions_ru", - "actorName": "DC CONSTRICTIONS", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "support@dcconstructions.ru", - "clientId": "client_romashka", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_support_dcconstructions_ru_4", - "at": "2026-05-06T01:06:48.121Z", - "actorUserId": "user_support_dcconstructions_ru", - "actorName": "DC CONSTRICTIONS", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "support@dcconstructions.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_support_dcconstructions_ru_task_manager", - "at": "2026-05-06T01:28:06.516Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "support@dcconstructions.ru / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_support_dcconstructions_ru_5", - "at": "2026-05-06T01:28:06.887Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "support@dcconstructions.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_brand_settings_2", - "at": "2026-05-06T06:52:46.025Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлены системные настройки", - "objectType": "settings", - "objectName": "Brand settings", - "clientId": null, - "result": "success", - "details": "Logo link: http://launcher.local.nodedc/; Tasker workspace policy: task_admins_only" - }, - { - "id": "audit_dctouch", - "at": "2026-05-06T08:44:44.887Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dc_constr", - "at": "2026-05-06T09:02:42.183Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC CONSTR", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: 15" - }, - { - "id": "audit_dc_constr_2", - "at": "2026-05-06T09:02:45.197Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC CONSTR", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: 15" - }, - { - "id": "audit_dc_constr_3", - "at": "2026-05-06T09:02:57.971Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC CONSTR", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: 15" - }, - { - "id": "audit_dc_constr_4", - "at": "2026-05-06T09:02:59.293Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC CONSTR", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: 15" - }, - { - "id": "audit_dc_constr_5", - "at": "2026-05-06T09:09:09.389Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC CONSTR", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: 15" - }, - { - "id": "audit_dc_silver", - "at": "2026-05-06T09:46:34.612Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SILVER", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: admin" - }, - { - "id": "audit_dc_constr_6", - "at": "2026-05-06T09:46:41.427Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC CONSTR", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: member" - }, - { - "id": "audit_dc_sudo", - "at": "2026-05-06T10:17:58.710Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SUDO", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: admin" - }, - { - "id": "audit_dc_sudo_2", - "at": "2026-05-06T10:21:44.717Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Снят Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SUDO", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: nodedc" - }, - { - "id": "audit_dc_support", - "at": "2026-05-06T10:38:27.410Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SUPPORT", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: member" - }, - { - "id": "audit_dc_silver_2", - "at": "2026-05-06T10:51:20.914Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SILVER", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: member" - }, - { - "id": "audit_dc_sudo_3", - "at": "2026-05-06T10:54:33.543Z", - "actorUserId": "system", - "actorName": "NODE.DC System", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SUDO", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: admin" - }, - { - "id": "audit_dc_silver007", - "at": "2026-05-06T11:20:45.826Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SILVER007", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: member" - }, - { - "id": "audit_dc_abramov", - "at": "2026-05-06T11:20:47.255Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC ABRAMOV", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: member" - }, - { - "id": "audit_dc_constrictions", - "at": "2026-05-06T11:20:48.841Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC CONSTRICTIONS", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: member" - }, - { - "id": "audit_constr_dc_yahoo_com_11", - "at": "2026-05-07T09:41:39.942Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлено членство", - "objectType": "user", - "objectName": "constr_dc@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": "Role: client_admin; status: active" - }, - { - "id": "audit_constr_dc_yahoo_com_12", - "at": "2026-05-07T09:41:41.158Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "constr_dc@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_dc_constr_7", - "at": "2026-05-07T09:41:45.137Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC CONSTR", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: admin" - }, - { - "id": "audit_silver_psih_yahoo_com_43", - "at": "2026-05-07T11:04:26.162Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Обновлено членство", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": "Role: client_admin; status: active" - }, - { - "id": "audit_silver_psih_yahoo_com_44", - "at": "2026-05-07T11:04:26.890Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_dc_silver_3", - "at": "2026-05-07T11:04:32.210Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SILVER", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: admin" - }, - { - "id": "audit_dc_silver_4", - "at": "2026-05-07T11:04:34.414Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SILVER", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: member" - }, - { - "id": "audit_dc_silver_5", - "at": "2026-05-07T11:04:40.683Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SILVER", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: admin" - }, - { - "id": "audit_dc_silver_6", - "at": "2026-05-07T11:04:42.616Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SILVER", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Role: member" - }, - { - "id": "audit_silver_psih_yahoo_com_45", - "at": "2026-05-07T11:04:45.081Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Обновлено членство", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": "Role: client_admin; status: disabled" - }, - { - "id": "audit_silver_psih_yahoo_com_46", - "at": "2026-05-07T11:04:45.343Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_silver_psih_yahoo_com_47", - "at": "2026-05-07T11:04:47.173Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Обновлено членство", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": "client_romashka", - "result": "success", - "details": "Role: client_admin; status: active" - }, - { - "id": "audit_silver_psih_yahoo_com_48", - "at": "2026-05-07T11:04:47.399Z", - "actorUserId": "user_constr_dc_yahoo_com", - "actorName": "DC CONSTR", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_silverpsih007_gmail_com_6", - "at": "2026-05-07T11:39:37.305Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлено членство", - "objectType": "user", - "objectName": "silverpsih007@gmail.com", - "clientId": "client_romashka", - "result": "success", - "details": "Role: client_admin; status: active" - }, - { - "id": "audit_silverpsih007_gmail_com_7", - "at": "2026-05-07T11:39:39.407Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлено членство", - "objectType": "user", - "objectName": "silverpsih007@gmail.com", - "clientId": "client_romashka", - "result": "success", - "details": "Role: client_admin; status: active" - }, - { - "id": "audit_silverpsih007_gmail_com_8", - "at": "2026-05-07T11:39:40.076Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silverpsih007@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_silverpsih007_gmail_com_9", - "at": "2026-05-07T11:39:41.562Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silverpsih007@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_dc_support_2", - "at": "2026-05-08T10:08:56.801Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker project", - "objectType": "task-manager-project-membership", - "objectName": "DC SUPPORT", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Project: DCTM-WT-CODEX; Role: member" - }, - { - "id": "audit_dctouch_2", - "at": "2026-05-08T10:10:17.084Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_3", - "at": "2026-05-08T10:11:08.178Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_4", - "at": "2026-05-08T10:14:10.729Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_support_dctouch_ru_task_manager_2", - "at": "2026-05-08T10:14:37.304Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "support@dctouch.ru / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_dc_support_3", - "at": "2026-05-08T10:14:37.448Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker workspace", - "objectType": "task-manager-membership", - "objectName": "DC SUPPORT", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: DCABRAMOV; Role: member" - }, - { - "id": "audit_support_dctouch_ru_6", - "at": "2026-05-08T10:14:38.013Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "support@dctouch.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_support_dctouch_ru_7", - "at": "2026-05-08T11:44:24.774Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлено членство", - "objectType": "user", - "objectName": "support@dctouch.ru", - "clientId": "client_romashka", - "result": "success", - "details": "Role: client_admin; status: active" - }, - { - "id": "audit_support_dctouch_ru_8", - "at": "2026-05-08T11:44:25.215Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "support@dctouch.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_dc_constrictions_2", - "at": "2026-05-08T11:52:50.107Z", - "actorUserId": "user_support_dctouch_ru", - "actorName": "DC SUPPORT", - "action": "Назначен Tasker project", - "objectType": "task-manager-project-membership", - "objectName": "DC CONSTRICTIONS", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Project: Менеджмент; Role: member" - }, - { - "id": "audit_dctouch_5", - "at": "2026-05-08T15:25:23.301Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_6", - "at": "2026-05-08T15:33:22.866Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_7", - "at": "2026-05-08T15:37:09.487Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_8", - "at": "2026-05-08T15:37:18.628Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_9", - "at": "2026-05-08T15:47:50.379Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_10", - "at": "2026-05-08T15:54:49.291Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_11", - "at": "2026-05-08T16:05:21.237Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_dctouch_12", - "at": "2026-05-08T16:19:24.425Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCTOUCH", - "clientId": "client_romashka", - "result": "success", - "details": null - }, - { - "id": "audit_support_dctouch_ru_9", - "at": "2026-05-08T19:00:00.983Z", - "actorUserId": "user_support_dctouch_ru", - "actorName": "DC SUPPORT", - "action": "Обновлён профиль пользователя", - "objectType": "user", - "objectName": "support@dctouch.ru", - "clientId": null, - "result": "success", - "details": null - }, - { - "id": "audit_support_dctouch_ru_10", - "at": "2026-05-08T19:00:01.647Z", - "actorUserId": "user_support_dctouch_ru", - "actorName": "DC SUPPORT", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "support@dctouch.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_2", - "at": "2026-05-08T19:23:23.147Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан клиент", - "objectType": "client", - "objectName": "Новый клиент 2", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_c", - "at": "2026-05-08T19:23:28.685Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "C", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_cf", - "at": "2026-05-08T19:23:28.889Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "CF", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_cfd", - "at": "2026-05-08T19:23:29.195Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "CFD", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_cfdd", - "at": "2026-05-08T19:23:29.377Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "CFDD", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_cfd_2", - "at": "2026-05-08T19:23:30.422Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "CFD", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_cf_2", - "at": "2026-05-08T19:23:30.458Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "CF", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_c_2", - "at": "2026-05-08T19:23:30.641Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "C", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_c_3", - "at": "2026-05-08T19:23:30.910Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "C", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_c_4", - "at": "2026-05-08T19:23:31.935Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "C", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_c_5", - "at": "2026-05-08T19:23:33.248Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "C", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_c_6", - "at": "2026-05-08T19:23:34.631Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "C", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_cd", - "at": "2026-05-08T19:23:35.652Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "CD", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_c_7", - "at": "2026-05-08T19:23:36.037Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "C", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_c_8", - "at": "2026-05-08T19:23:36.329Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "C", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_dc", - "at": "2026-05-08T19:23:37.781Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DC", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_dcc", - "at": "2026-05-08T19:23:40.903Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCC", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_dcco", - "at": "2026-05-08T19:23:41.023Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCCO", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_dccon", - "at": "2026-05-08T19:23:41.359Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCCON", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_dccons", - "at": "2026-05-08T19:23:41.534Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCCONS", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_dcconst", - "at": "2026-05-08T19:23:41.821Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCCONST", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_dcconstr", - "at": "2026-05-08T19:23:42.018Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён клиент", - "objectType": "client", - "objectName": "DCCONSTR", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_dcconstr_2", - "at": "2026-05-08T19:37:53.961Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Удалён клиент", - "objectType": "client", - "objectName": "DCCONSTR", - "clientId": "client_2", - "result": "warning", - "details": null - }, - { - "id": "audit_2_2", - "at": "2026-05-08T19:38:15.835Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан клиент", - "objectType": "client", - "objectName": "Новый клиент 2", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_2_3", - "at": "2026-05-08T19:38:36.383Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Удалён клиент", - "objectType": "client", - "objectName": "Новый клиент 2", - "clientId": "client_2", - "result": "warning", - "details": null - }, - { - "id": "audit_ayo_ayo_ae_gmail_com", - "at": "2026-05-09T11:01:08.503Z", - "actorUserId": "public", - "actorName": "DC", - "action": "Создана публичная заявка", - "objectType": "access_request", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": null, - "result": "success", - "details": "DC" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_2", - "at": "2026-05-09T11:32:40.371Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Подтверждена публичная заявка", - "objectType": "access_request", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": null, - "result": "success", - "details": "Invite: invite_ayo_ayo_ae_gmail_com; target: Открытый контур; role: member" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_3", - "at": "2026-05-09T11:32:51.152Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": "client_public_pool", - "result": "success", - "details": null - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_4", - "at": "2026-05-09T11:33:58.892Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": "client_public_pool", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_5", - "at": "2026-05-09T11:33:58.934Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_6", - "at": "2026-05-09T11:35:48.963Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Обновлён профиль пользователя", - "objectType": "user", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": null, - "result": "success", - "details": null - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_7", - "at": "2026-05-09T11:35:49.157Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_task_manager", - "at": "2026-05-09T12:23:47.333Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "ayo.ayo.ae@gmail.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: admin" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_8", - "at": "2026-05-09T12:23:50.206Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, nodedc:taskmanager:admin" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_task_manager_2", - "at": "2026-05-09T12:24:41.929Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "ayo.ayo.ae@gmail.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: deny" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_9", - "at": "2026-05-09T12:24:42.117Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_task_manager_3", - "at": "2026-05-09T12:34:38.766Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "ayo.ayo.ae@gmail.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: admin" - }, - { - "id": "audit_ayo_ayo_ae_gmail_com_10", - "at": "2026-05-09T12:34:39.358Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "ayo.ayo.ae@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, nodedc:taskmanager:admin" - }, - { - "id": "audit_ayoyoyo_alah_mail_ru", - "at": "2026-05-09T13:43:17.849Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Создана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@mail.ru", - "clientId": null, - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_ayoyoyo_alah_mail_ru_2", - "at": "2026-05-09T13:43:47.185Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Подтверждена заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@mail.ru", - "clientId": null, - "result": "success", - "details": "http://task.local.nodedc/workspace-invitations/?invitation_id=af8c6a1c-9ac2-44c8-9023-f27bc93d76d8&slug=ayoyoyo&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6eyJlbWFpbCI6ImFsYWhAbWFpbC5ydSIsInJvbGUiOjE1fSwidGltZXN0YW1wIjoxNzc4MzM0MTk3Ljc4NjAyMX0.iup2nsWz2r0LCbOv8vH6INI0fo7dWdLfN2Jtxz76E-I" - }, - { - "id": "audit_ayoyoyo_alah_mail_ru_3", - "at": "2026-05-09T14:24:31.257Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Создана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@mail.ru", - "clientId": null, - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_ayoyoyo_alah_mail_ru_4", - "at": "2026-05-09T14:24:41.276Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Подтверждена заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@mail.ru", - "clientId": null, - "result": "success", - "details": "http://task.local.nodedc/workspace-invitations/?invitation_id=bcb82953-f277-4f0c-a61a-1b0791a8a381&slug=ayoyoyo&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6eyJlbWFpbCI6ImFsYWhAbWFpbC5ydSIsInJvbGUiOjE1fSwidGltZXN0YW1wIjoxNzc4MzM2NjcxLjIzNTc3fQ.wyKAbnfPd2NasrAEbmg8KaYo-nOGFKHgC0nERaekuys" - }, - { - "id": "audit_alah_mail_ru", - "at": "2026-05-09T17:08:10.887Z", - "actorUserId": "system", - "actorName": "NODE.DC Root", - "action": "Создан platform-инвайт для workspace-инвайта", - "objectType": "invite", - "objectName": "alah@mail.ru", - "clientId": "client_public_pool", - "result": "success", - "details": "ayoyoyo; inviter: ayo.ayo.ae@gmail.com" - }, - { - "id": "audit_ayoyoyo_alah_mail_ru_5", - "at": "2026-05-09T17:25:17.781Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Отозвана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@mail.ru", - "clientId": null, - "result": "warning", - "details": "Отозвано в Operational Core" - }, - { - "id": "audit_ayoyoyo_alah_gmail_com", - "at": "2026-05-09T17:25:54.406Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Создана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@gmail.com", - "clientId": null, - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_alah_gmail_com", - "at": "2026-05-09T17:26:04.674Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан platform-инвайт для workspace-инвайта", - "objectType": "invite", - "objectName": "alah@gmail.com", - "clientId": "client_public_pool", - "result": "success", - "details": "ayoyoyo; inviter: ayo.ayo.ae@gmail.com" - }, - { - "id": "audit_ayoyoyo_alah_gmail_com_2", - "at": "2026-05-09T17:26:04.726Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Подтверждена заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@gmail.com", - "clientId": null, - "result": "success", - "details": "http://task.local.nodedc/workspace-invitations/?invitation_id=359913f5-80e6-4772-82f9-19e653cf1147&slug=ayoyoyo&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6eyJlbWFpbCI6ImFsYWhAZ21haWwuY29tIiwicm9sZSI6MTV9LCJ0aW1lc3RhbXAiOjE3NzgzNDc1NTQuMzg3MTV9.ECLpdg1RAaCll_GfNZEx1OTI3sf3bfuRxmJShpEZruM" - }, - { - "id": "audit_alah_gmail_com_2", - "at": "2026-05-09T17:26:58.823Z", - "actorUserId": "user_alah_gmail_com", - "actorName": "ALAH", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "alah@gmail.com", - "clientId": "client_public_pool", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_alah_gmail_com_3", - "at": "2026-05-09T17:26:58.829Z", - "actorUserId": "user_alah_gmail_com", - "actorName": "ALAH", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "alah@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_ayoyoyo_alah_gmail_com_3", - "at": "2026-05-09T18:01:41.568Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Отозвана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@gmail.com", - "clientId": null, - "result": "warning", - "details": "Отозвано в Operational Core" - }, - { - "id": "audit_alah_gmail_com_task_manager", - "at": "2026-05-09T18:22:48.238Z", - "actorUserId": "user_alah_gmail_com", - "actorName": "ALAH", - "action": "Снят доступ Operational Core по workspace-инвайту", - "objectType": "grant", - "objectName": "alah@gmail.com / task-manager", - "clientId": null, - "result": "warning", - "details": "Workspace invite: ayoyoyo; cancelled at: 2026-05-09T18:22:48.238Z" - }, - { - "id": "audit_ayoyoyo_alah_gmail_com_4", - "at": "2026-05-09T18:22:48.238Z", - "actorUserId": "system", - "actorName": "NODE.DC cleanup", - "action": "Отозвана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@gmail.com", - "clientId": null, - "result": "warning", - "details": "Пользователь удалён из workspace Operational Core." - }, - { - "id": "audit_alah_gmail_com_4", - "at": "2026-05-09T18:26:10.793Z", - "actorUserId": "system", - "actorName": "NODE.DC sync cleanup", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "alah@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_ayoyoyo_alah_gmail_com_5", - "at": "2026-05-09T18:57:32.381Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Создана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@gmail.com", - "clientId": null, - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_alah_gmail_com_5", - "at": "2026-05-09T18:58:00.118Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан platform-инвайт для workspace-инвайта", - "objectType": "invite", - "objectName": "alah@gmail.com", - "clientId": "client_public_pool", - "result": "success", - "details": "ayoyoyo; inviter: ayo.ayo.ae@gmail.com" - }, - { - "id": "audit_ayoyoyo_alah_gmail_com_6", - "at": "2026-05-09T18:58:00.166Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Подтверждена заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:alah@gmail.com", - "clientId": null, - "result": "success", - "details": "http://task.local.nodedc/workspace-invitations/?invitation_id=c6cc5c82-641a-4cf8-aa3d-c28fb76ee83c&slug=ayoyoyo&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6eyJlbWFpbCI6ImFsYWhAZ21haWwuY29tIiwicm9sZSI6MTV9LCJ0aW1lc3RhbXAiOjE3NzgzNTMwNTIuMzYxODc5fQ.NtsQ5-48bXpOCgU7Z4u4QxLHZZvgiWVXtJ6e_yUrpfg" - }, - { - "id": "audit_alah_gmail_com_6", - "at": "2026-05-09T18:58:27.834Z", - "actorUserId": "user_alah_gmail_com", - "actorName": "ALAH", - "action": "Инвайт принят", - "objectType": "invite", - "objectName": "alah@gmail.com", - "clientId": "client_public_pool", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_alah_gmail_com_7", - "at": "2026-05-09T18:58:28.494Z", - "actorUserId": "user_alah_gmail_com", - "actorName": "ALAH", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "alah@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_ayoyoyo_pupa_mail_ru", - "at": "2026-05-09T19:36:19.366Z", - "actorUserId": "user_ayo_ayo_ae_gmail_com", - "actorName": "Anna Ayo", - "action": "Создана заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:pupa@mail.ru", - "clientId": null, - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_pupa_mail_ru", - "at": "2026-05-09T19:36:41.118Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан platform-инвайт для workspace-инвайта", - "objectType": "invite", - "objectName": "pupa@mail.ru", - "clientId": "client_public_pool", - "result": "success", - "details": "ayoyoyo; inviter: ayo.ayo.ae@gmail.com" - }, - { - "id": "audit_ayoyoyo_pupa_mail_ru_2", - "at": "2026-05-09T19:36:41.170Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Подтверждена заявка workspace-инвайта", - "objectType": "tasker_invite_request", - "objectName": "ayoyoyo:pupa@mail.ru", - "clientId": null, - "result": "success", - "details": "http://task.local.nodedc/workspace-invitations/?invitation_id=9b470198-5685-4ebf-b330-75b357363e97&slug=ayoyoyo&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6eyJlbWFpbCI6InB1cGFAbWFpbC5ydSIsInJvbGUiOjE1fSwidGltZXN0YW1wIjoxNzc4MzU1Mzc5LjI4MDg0MX0.q9fLuUBLXNYK9XZk0y02zjc55uixPfKTMiS92oOfEoU" - }, - { - "id": "audit_pupa_mail_ru_2", - "at": "2026-05-09T19:37:43.521Z", - "actorUserId": "user_pupa_mail_ru", - "actorName": "PUPA", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "pupa@mail.ru", - "clientId": "client_public_pool", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_pupa_mail_ru_3", - "at": "2026-05-09T19:37:43.533Z", - "actorUserId": "user_pupa_mail_ru", - "actorName": "PUPA", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "pupa@mail.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_realla_mail_ru", - "at": "2026-05-10T13:18:08.052Z", - "actorUserId": "public", - "actorName": "Сервис Консалт", - "action": "Создана публичная заявка", - "objectType": "access_request", - "objectName": "realla@mail.ru", - "clientId": null, - "result": "success", - "details": "Сервис Консалт" - }, - { - "id": "audit_realla_mail_ru_2", - "at": "2026-05-10T13:18:41.837Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Подтверждена публичная заявка", - "objectType": "access_request", - "objectName": "realla@mail.ru", - "clientId": null, - "result": "success", - "details": "Invite: invite_realla_mail_ru; target: Открытый контур; role: member" - }, - { - "id": "audit_silver_psih_yahoo_com_task_manager_19", - "at": "2026-05-10T13:30:31.081Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "silver_psih@yahoo.com / task-manager", - "clientId": null, - "result": "success", - "details": "Value: member" - }, - { - "id": "audit_silver_psih_yahoo_com_49", - "at": "2026-05-10T13:30:31.884Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "silver_psih@yahoo.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, service-digital-twin" - }, - { - "id": "audit_alla_mail_ru", - "at": "2026-05-10T14:10:54.546Z", - "actorUserId": "public", - "actorName": "СВК", - "action": "Создана публичная заявка", - "objectType": "access_request", - "objectName": "alla@mail.ru", - "clientId": null, - "result": "success", - "details": "СВК" - }, - { - "id": "audit_alla_mail_ru_2", - "at": "2026-05-10T14:10:55.838Z", - "actorUserId": "user_alla_mail_ru", - "actorName": "Абрамова Алла В", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "alla@mail.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_dc_constrictions_3", - "at": "2026-05-10T14:40:32.513Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker project", - "objectType": "task-manager-project-membership", - "objectName": "DC CONSTRICTIONS", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Project: NODEDC TASKMANAGER; Role: member" - }, - { - "id": "audit_dc_abramov_2", - "at": "2026-05-10T14:40:50.588Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker project", - "objectType": "task-manager-project-membership", - "objectName": "DC ABRAMOV", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Project: NODEDC TASKMANAGER; Role: member" - }, - { - "id": "audit_dc_silver007_2", - "at": "2026-05-10T14:41:04.633Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Назначен Tasker project", - "objectType": "task-manager-project-membership", - "objectName": "DC SILVER007", - "clientId": "client_romashka", - "result": "success", - "details": "Workspace: NODE DC; Project: NODEDC TASKMANAGER; Role: member" - }, - { - "id": "audit_2_4", - "at": "2026-05-10T14:45:01.373Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Создан клиент", - "objectType": "client", - "objectName": "Новый клиент 2", - "clientId": "client_2", - "result": "success", - "details": null - }, - { - "id": "audit_2_5", - "at": "2026-05-10T14:45:10.438Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Удалён клиент", - "objectType": "client", - "objectName": "Новый клиент 2", - "clientId": "client_2", - "result": "warning", - "details": null - }, - { - "id": "audit_alla_mail_ru_3", - "at": "2026-05-10T18:47:35.011Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Подтверждена публичная заявка", - "objectType": "access_request", - "objectName": "alla@mail.ru", - "clientId": null, - "result": "success", - "details": "Account activated; target: Открытый контур; role: member" - }, - { - "id": "audit_alla_mail_ru_4", - "at": "2026-05-10T18:47:35.324Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "alla@mail.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - }, - { - "id": "audit_alla_mail_ru_task_manager", - "at": "2026-05-10T18:48:11.279Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён доступ пользователя к сервису", - "objectType": "grant", - "objectName": "alla@mail.ru / task-manager", - "clientId": null, - "result": "success", - "details": "Value: admin" - }, - { - "id": "audit_alla_mail_ru_5", - "at": "2026-05-10T18:48:11.539Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "alla@mail.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user, nodedc:taskmanager:admin" - }, - { - "id": "audit_alah_gmail_com_8", - "at": "2026-05-10T19:26:16.218Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "alah@gmail.com", - "clientId": "client_public_pool", - "result": "success", - "details": null - }, - { - "id": "audit_alah_gmail_com_9", - "at": "2026-05-10T19:59:32.745Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён профиль пользователя", - "objectType": "user", - "objectName": "alah@gmail.com", - "clientId": null, - "result": "success", - "details": null - }, - { - "id": "audit_alah_gmail_com_10", - "at": "2026-05-10T19:59:33.312Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "alah@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: none" - }, - { - "id": "audit_alah_gmail_com_11", - "at": "2026-05-10T20:00:08.117Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён профиль пользователя", - "objectType": "user", - "objectName": "alah@gmail.com", - "clientId": null, - "result": "success", - "details": null - }, - { - "id": "audit_alah_gmail_com_12", - "at": "2026-05-10T20:00:08.375Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "alah@gmail.com", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user, nodedc:taskmanager:user" - }, - { - "id": "audit_alah_mail_ru_2", - "at": "2026-05-10T20:03:28.324Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Удалён инвайт", - "objectType": "invite", - "objectName": "alah@mail.ru", - "clientId": "client_public_pool", - "result": "warning", - "details": null - }, - { - "id": "audit_alah_gmail_com_13", - "at": "2026-05-11T07:44:22.481Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь удалён полностью", - "objectType": "user", - "objectName": "alah@gmail.com", - "clientId": null, - "result": "warning", - "details": "Удалены профиль, членства: 1, инвайты: 2, заявки: 2" - }, - { - "id": "audit_alla_mail_ru_6", - "at": "2026-05-11T09:11:05.918Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Пользователь удалён полностью", - "objectType": "user", - "objectName": "alla@mail.ru", - "clientId": null, - "result": "warning", - "details": "Удалены профиль, членства: 1, инвайты: 0, заявки: 1" - }, - { - "id": "audit_realla_mail_ru_3", - "at": "2026-05-11T09:11:46.244Z", - "actorUserId": "user_root", - "actorName": "DC SUDO", - "action": "Обновлён инвайт", - "objectType": "invite", - "objectName": "realla@mail.ru", - "clientId": "client_public_pool", - "result": "success", - "details": null - }, - { - "id": "audit_realla_mail_ru_4", - "at": "2026-05-11T09:16:35.282Z", - "actorUserId": "user_realla_mail_ru", - "actorName": "АВ", - "action": "Регистрация по инвайту", - "objectType": "invite", - "objectName": "realla@mail.ru", - "clientId": "client_public_pool", - "result": "success", - "details": "Role: member" - }, - { - "id": "audit_realla_mail_ru_5", - "at": "2026-05-11T09:16:35.291Z", - "actorUserId": "user_realla_mail_ru", - "actorName": "АВ", - "action": "Пользователь синхронизирован в Authentik", - "objectType": "user", - "objectName": "realla@mail.ru", - "clientId": null, - "result": "success", - "details": "Groups: nodedc:launcher:user" - } - ], - "settings": { - "brand": { - "logoLinkUrl": "http://launcher.local.nodedc/" - }, - "taskManager": { - "workspaceCreationPolicy": "task_admins_only" - } - }, - "taskManagerMemberships": [ - { - "id": "tasker_mem_client_romashka_user_silver_psih_nodedc", - "clientId": "client_romashka", - "userId": "user_silver_psih", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "role": "member", - "planeUserId": "7315d59a-50e1-4d26-8de8-ae632777b46e", - "planeRole": 15, - "updatedAt": "2026-05-07T11:04:42.615Z" - }, - { - "id": "tasker_mem_client_romashka_user_constr_dc_yahoo_com_nodedc", - "clientId": "client_romashka", - "userId": "user_constr_dc_yahoo_com", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "role": "admin", - "planeUserId": "62aa744d-32ef-427f-8ad2-184d2ec2f5e5", - "planeRole": 20, - "updatedAt": "2026-05-07T09:41:45.137Z" - }, - { - "id": "tasker_mem_client_romashka_user_support_dctouch_ru_nodedc", - "clientId": "client_romashka", - "userId": "user_support_dctouch_ru", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "role": "member", - "planeUserId": "53e56870-8772-4dfd-9c8c-2eeacfb53caa", - "planeRole": 15, - "updatedAt": "2026-05-06T10:38:27.409Z" - }, - { - "id": "tasker_mem_client_romashka_user_root_nodedc", - "clientId": "client_romashka", - "userId": "user_root", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "role": "admin", - "planeUserId": "844d7f18-285d-4671-8371-8ca9ca5ffa39", - "planeRole": 20, - "updatedAt": "2026-05-06T10:54:33.542Z" - }, - { - "id": "tasker_mem_client_romashka_user_silverpsih007_gmail_com_nodedc", - "clientId": "client_romashka", - "userId": "user_silverpsih007_gmail_com", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "role": "member", - "planeUserId": "52817493-1ff4-44f9-aae4-463ecd512d51", - "planeRole": 15, - "updatedAt": "2026-05-06T11:20:45.826Z" - }, - { - "id": "tasker_mem_client_romashka_user_abramov_dcconstructions_ru_nodedc", - "clientId": "client_romashka", - "userId": "user_abramov_dcconstructions_ru", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "role": "member", - "planeUserId": "d28a2d28-da56-4625-a211-d9bb3d06b0d3", - "planeRole": 15, - "updatedAt": "2026-05-06T11:20:47.255Z" - }, - { - "id": "tasker_mem_client_romashka_user_support_dcconstructions_ru_nodedc", - "clientId": "client_romashka", - "userId": "user_support_dcconstructions_ru", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "role": "member", - "planeUserId": "1cc7ae3a-1f42-41ac-8cc2-1ff0fce59554", - "planeRole": 15, - "updatedAt": "2026-05-06T11:20:48.841Z" - }, - { - "id": "tasker_mem_client_romashka_user_support_dctouch_ru_dcabramov", - "clientId": "client_romashka", - "userId": "user_support_dctouch_ru", - "workspaceSlug": "dcabramov", - "workspaceName": "DCABRAMOV", - "role": "member", - "planeUserId": "53e56870-8772-4dfd-9c8c-2eeacfb53caa", - "planeRole": 15, - "updatedAt": "2026-05-08T10:14:37.448Z" - } - ], - "taskManagerProjectMemberships": [ - { - "id": "tasker_project_mem_client_romashka_user_support_dctouch_ru_nodedc_823af409_bcfd_498c_b2fb_31119ff23", - "clientId": "client_romashka", - "userId": "user_support_dctouch_ru", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "projectId": "823af409-bcfd-498c-b2fb-31119ff238a7", - "projectIdentifier": "CODEX", - "projectName": "DCTM-WT-CODEX", - "role": "member", - "planeUserId": "53e56870-8772-4dfd-9c8c-2eeacfb53caa", - "planeRole": 15, - "updatedAt": "2026-05-08T10:08:56.800Z" - }, - { - "id": "tasker_project_mem_client_romashka_user_support_dcconstructions_ru_nodedc_a3de175a_2df5_4604_aadf_6", - "clientId": "client_romashka", - "userId": "user_support_dcconstructions_ru", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "projectId": "a3de175a-2df5-4604-aadf-618877445135", - "projectIdentifier": "MGR", - "projectName": "Менеджмент", - "role": "member", - "planeUserId": "1cc7ae3a-1f42-41ac-8cc2-1ff0fce59554", - "planeRole": 15, - "updatedAt": "2026-05-08T11:52:50.104Z" - }, - { - "id": "tasker_project_mem_client_romashka_user_support_dcconstructions_ru_nodedc_53141195_0dcb_4206_90d3_0", - "clientId": "client_romashka", - "userId": "user_support_dcconstructions_ru", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "projectId": "53141195-0dcb-4206-90d3-0f1667f17cf6", - "projectIdentifier": "NODEDCTASK", - "projectName": "NODEDC TASKMANAGER", - "role": "member", - "managedBy": "launcher", - "planeUserId": "1cc7ae3a-1f42-41ac-8cc2-1ff0fce59554", - "planeRole": 15, - "updatedAt": "2026-05-10T14:40:32.512Z" - }, - { - "id": "tasker_project_mem_client_romashka_user_abramov_dcconstructions_ru_nodedc_53141195_0dcb_4206_90d3_0", - "clientId": "client_romashka", - "userId": "user_abramov_dcconstructions_ru", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "projectId": "53141195-0dcb-4206-90d3-0f1667f17cf6", - "projectIdentifier": "NODEDCTASK", - "projectName": "NODEDC TASKMANAGER", - "role": "member", - "managedBy": "launcher", - "planeUserId": "d28a2d28-da56-4625-a211-d9bb3d06b0d3", - "planeRole": 15, - "updatedAt": "2026-05-10T14:40:50.588Z" - }, - { - "id": "tasker_project_mem_client_romashka_user_silverpsih007_gmail_com_nodedc_53141195_0dcb_4206_90d3_0f16", - "clientId": "client_romashka", - "userId": "user_silverpsih007_gmail_com", - "workspaceSlug": "nodedc", - "workspaceName": "NODE DC", - "projectId": "53141195-0dcb-4206-90d3-0f1667f17cf6", - "projectIdentifier": "NODEDCTASK", - "projectName": "NODEDC TASKMANAGER", - "role": "member", - "managedBy": "launcher", - "planeUserId": "52817493-1ff4-44f9-aae4-463ecd512d51", - "planeRole": 15, - "updatedAt": "2026-05-10T14:41:04.633Z" - } - ], - "accessRequests": [ - { - "id": "access_request_ayo_ayo_ae_gmail_com", - "email": "ayo.ayo.ae@gmail.com", - "firstName": "Anna", - "lastName": "Ayo", - "middleName": "Ayo", - "phone": "+7 (925) 420-88-84", - "company": "DC", - "status": "approved", - "targetClientId": "client_public_pool", - "role": "member", - "approvedInviteId": "invite_ayo_ayo_ae_gmail_com", - "reviewedByUserId": "user_root", - "reviewedAt": "2026-05-09T11:32:40.370Z", - "comment": null, - "createdAt": "2026-05-09T11:01:08.481Z", - "updatedAt": "2026-05-09T11:32:40.370Z" - }, - { - "id": "access_request_realla_mail_ru", - "email": "realla@mail.ru", - "firstName": "А", - "lastName": "В", - "middleName": "А", - "phone": "+79036118477", - "company": "Сервис Консалт", - "status": "approved", - "targetClientId": "client_public_pool", - "role": "member", - "approvedInviteId": "invite_realla_mail_ru", - "reviewedByUserId": "user_root", - "reviewedAt": "2026-05-10T13:18:41.837Z", - "comment": null, - "createdAt": "2026-05-10T13:18:08.047Z", - "updatedAt": "2026-05-10T13:18:41.837Z" - } - ], - "taskerInviteRequests": [ - { - "id": "tasker_invite_request_ayoyoyo_alah_mail_ru", - "taskerInviteId": "af8c6a1c-9ac2-44c8-9023-f27bc93d76d8", - "workspaceId": "9554ef6f-afa0-424b-b27f-16cca437f2d2", - "workspaceSlug": "ayoyoyo", - "workspaceName": "AYOYOYO", - "inviteeEmail": "alah@mail.ru", - "role": "member", - "inviterUserId": "user_ayo_ayo_ae_gmail_com", - "inviterPlaneUserId": "b91bd701-9e50-41e7-a8de-255041772a39", - "inviterEmail": "ayo.ayo.ae@gmail.com", - "inviterName": "Anna Ayo", - "status": "cancelled", - "taskerInviteLink": null, - "platformInviteId": null, - "platformInviteToken": null, - "reviewedByUserId": "user_root", - "reviewedAt": "2026-05-09T13:43:47.185Z", - "comment": "Отозвано в Operational Core", - "createdAt": "2026-05-09T13:43:17.845Z", - "updatedAt": "2026-05-09T14:17:54.470Z" - }, - { - "id": "tasker_invite_request_ayoyoyo_alah_mail_ru_2", - "taskerInviteId": "bcb82953-f277-4f0c-a61a-1b0791a8a381", - "workspaceId": "9554ef6f-afa0-424b-b27f-16cca437f2d2", - "workspaceSlug": "ayoyoyo", - "workspaceName": "AYOYOYO", - "inviteeEmail": "alah@mail.ru", - "role": "member", - "inviterUserId": "user_ayo_ayo_ae_gmail_com", - "inviterPlaneUserId": "b91bd701-9e50-41e7-a8de-255041772a39", - "inviterEmail": "ayo.ayo.ae@gmail.com", - "inviterName": "Anna Ayo", - "status": "cancelled", - "taskerInviteLink": null, - "platformInviteId": "invite_ayoyoyo_alah_mail_ru", - "platformInviteToken": "e0726f74-82c0-49d8-bd08-e6df097bde44", - "reviewedByUserId": "user_root", - "reviewedAt": "2026-05-09T14:24:41.276Z", - "comment": "Отозвано в Operational Core", - "createdAt": "2026-05-09T14:24:31.256Z", - "updatedAt": "2026-05-09T17:25:17.778Z" - }, - { - "id": "tasker_invite_request_ayoyoyo_pupa_mail_ru", - "taskerInviteId": "9b470198-5685-4ebf-b330-75b357363e97", - "workspaceId": "9554ef6f-afa0-424b-b27f-16cca437f2d2", - "workspaceSlug": "ayoyoyo", - "workspaceName": "AYOYOYO", - "inviteeEmail": "pupa@mail.ru", - "role": "member", - "inviterUserId": "user_ayo_ayo_ae_gmail_com", - "inviterPlaneUserId": "b91bd701-9e50-41e7-a8de-255041772a39", - "inviterEmail": "ayo.ayo.ae@gmail.com", - "inviterName": "Anna Ayo", - "status": "approved", - "taskerInviteLink": "http://task.local.nodedc/workspace-invitations/?invitation_id=9b470198-5685-4ebf-b330-75b357363e97&slug=ayoyoyo&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6eyJlbWFpbCI6InB1cGFAbWFpbC5ydSIsInJvbGUiOjE1fSwidGltZXN0YW1wIjoxNzc4MzU1Mzc5LjI4MDg0MX0.q9fLuUBLXNYK9XZk0y02zjc55uixPfKTMiS92oOfEoU", - "platformInviteId": "invite_ayoyoyo_pupa_mail_ru", - "platformInviteToken": "dee0814c-917a-456c-be5d-f8da468136c9", - "reviewedByUserId": "user_root", - "reviewedAt": "2026-05-09T19:36:41.169Z", - "comment": null, - "createdAt": "2026-05-09T19:36:19.353Z", - "updatedAt": "2026-05-09T19:36:41.169Z" - } - ], - "revokedAccounts": [ - { - "id": "revoked_account_alla_mail_ru", - "email": "alla@mail.ru", - "name": "Абрамова Алла В", - "sourceUserId": "user_alla_mail_ru", - "authentikUserId": "216bb9c1-112e-4c5b-bcc3-a6a516955759", - "reason": "hard_deleted", - "revokedByUserId": "user_root", - "revokedByUserEmail": "dcctouch@gmail.com", - "revokedByUserName": "DC SUDO", - "revokedAt": "2026-05-11T09:11:05.917Z", - "createdAt": "2026-05-11T09:11:05.917Z", - "updatedAt": "2026-05-11T09:11:05.917Z" - } - ] -} diff --git a/scripts/seed-live-control-plane.mjs b/scripts/seed-live-control-plane.mjs index 7566670..b4f4751 100644 --- a/scripts/seed-live-control-plane.mjs +++ b/scripts/seed-live-control-plane.mjs @@ -1,14 +1,15 @@ import { existsSync, readFileSync } from "node:fs"; import { mkdir, writeFile } from "node:fs/promises"; -import { dirname, join } from "node:path"; +import { dirname, isAbsolute, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const projectRoot = dirname(dirname(fileURLToPath(import.meta.url))); -const publicDataPath = join(projectRoot, "public", "storage", "launcher-data.json"); -const distDataPath = join(projectRoot, "dist", "storage", "launcher-data.json"); +const serverStorageRoot = resolveStorageRoot(projectRoot); +const dataPath = join(serverStorageRoot, "launcher-data.json"); +const legacyPublicDataPath = join(projectRoot, "public", "storage", "launcher-data.json"); const now = new Date().toISOString(); -const existingData = readJson(publicDataPath); +const existingData = existsSync(dataPath) ? readJson(dataPath) : readJson(legacyPublicDataPath); const services = Array.isArray(existingData.services) ? existingData.services : []; const existingUsersByEmail = new Map( (Array.isArray(existingData.users) ? existingData.users : []).map((user) => [String(user.email || "").toLowerCase(), user]) @@ -214,11 +215,7 @@ const liveData = { services, }; -await writeJson(publicDataPath, liveData); - -if (existsSync(join(projectRoot, "dist"))) { - await writeJson(distDataPath, liveData); -} +await writeJson(dataPath, liveData); console.log(`Seeded ${liveData.users.length} users, ${liveData.clients.length} client, ${liveData.groups.length} groups.`); @@ -234,3 +231,13 @@ async function writeJson(path, data) { await mkdir(dirname(path), { recursive: true }); await writeFile(path, `${JSON.stringify(data, null, 2)}\n`, "utf8"); } + +function resolveStorageRoot(projectRoot) { + const configuredRoot = process.env.NODEDC_LAUNCHER_STORAGE_DIR; + + if (configuredRoot && configuredRoot.trim()) { + return isAbsolute(configuredRoot) ? configuredRoot : resolve(projectRoot, configuredRoot); + } + + return join(projectRoot, "server", "storage"); +} diff --git a/server/control-plane-store.mjs b/server/control-plane-store.mjs index 50c7ed0..c92f6e2 100644 --- a/server/control-plane-store.mjs +++ b/server/control-plane-store.mjs @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import { existsSync, readFileSync } from "node:fs"; import { mkdir, rename, writeFile } from "node:fs/promises"; -import { join } from "node:path"; +import { isAbsolute, join, resolve } from "node:path"; const collectionKeys = [ "clients", @@ -62,16 +62,18 @@ const defaultSettings = { }; export function createControlPlaneStore({ projectRoot }) { - const publicStorageRoot = join(projectRoot, "public", "storage"); - const distStorageRoot = join(projectRoot, "dist", "storage"); - const dataPath = join(publicStorageRoot, "launcher-data.json"); + const serverStorageRoot = resolveStorageRoot(projectRoot); + const legacyPublicDataPath = join(projectRoot, "public", "storage", "launcher-data.json"); + const dataPath = join(serverStorageRoot, "launcher-data.json"); function readData() { - if (!existsSync(dataPath)) { + const readablePath = existsSync(dataPath) ? dataPath : legacyPublicDataPath; + + if (!existsSync(readablePath)) { return normalizeData({}); } - return normalizeData(JSON.parse(readFileSync(dataPath, "utf8"))); + return normalizeData(JSON.parse(readFileSync(readablePath, "utf8"))); } async function writeData(data) { @@ -1192,6 +1194,10 @@ export function createControlPlaneStore({ projectRoot }) { throw new Error("Этот инвайт выписан на другую почту"); } + if (invite.status === "accepted") { + throw new Error("Инвайт уже принят"); + } + if (invite.status === "revoked") { throw new Error("Инвайт отозван"); } @@ -1711,13 +1717,7 @@ export function createControlPlaneStore({ projectRoot }) { } function getWritableStorageRoots() { - const roots = [publicStorageRoot]; - - if (existsSync(join(projectRoot, "dist"))) { - roots.push(distStorageRoot); - } - - return roots; + return [serverStorageRoot]; } function getLoginAccountStatus(email) { @@ -1799,6 +1799,16 @@ export function createControlPlaneStore({ projectRoot }) { }; } +function resolveStorageRoot(projectRoot) { + const configuredRoot = process.env.NODEDC_LAUNCHER_STORAGE_DIR; + + if (configuredRoot && configuredRoot.trim()) { + return isAbsolute(configuredRoot) ? configuredRoot : resolve(projectRoot, configuredRoot); + } + + return join(projectRoot, "server", "storage"); +} + function normalizeData(payload) { const data = typeof payload === "object" && payload !== null ? { ...payload } : {}; diff --git a/server/dev-server.mjs b/server/dev-server.mjs index c3c17b7..d0df8ab 100644 --- a/server/dev-server.mjs +++ b/server/dev-server.mjs @@ -249,7 +249,14 @@ app.get("/api/me", (req, res) => { return; } - const runtimeContext = getRuntimeSessionContext(session); + const sessionAccess = getSessionAccessState(session); + + if (!sessionAccess.ok) { + rejectInactiveSession(res, session, sessionAccess); + return; + } + + const runtimeContext = sessionAccess.runtimeContext; res.json({ authenticated: true, @@ -268,7 +275,14 @@ app.get("/api/apps", (req, res) => { return; } - res.json({ apps: getAppsForSession(session) }); + const sessionAccess = getSessionAccessState(session); + + if (!sessionAccess.ok) { + rejectInactiveSession(res, session, sessionAccess); + return; + } + + res.json({ apps: getAppsForUser(sessionAccess.runtimeContext.groups) }); }); app.get("/api/services/:serviceSlug/launch", requireSession, (req, res) => { @@ -456,9 +470,20 @@ app.post("/api/internal/tasker/invite-requests", asyncRoute(async (req, res) => const groups = resolveRequiredGroups(snapshot.data, inviter); const app = getAppsForUser(groups).find((candidate) => candidate.slug === "task-manager"); - const workspacePolicy = resolveTaskManagerWorkspacePolicy(snapshot.data, groups, Boolean(app?.hasAccess), inviter); + const workspaceSlug = req.body?.workspace?.slug ?? req.body?.workspaceSlug; + const workspacePolicy = resolveTaskManagerWorkspacePolicy( + snapshot.data, + groups, + Boolean(app?.hasAccess), + inviter, + workspaceSlug + ); - if (!app?.hasAccess || workspacePolicy.inviteApproval !== "nodedc") { + if ( + !app?.hasAccess || + workspacePolicy.managedBy !== "tasker" || + !["nodedc", "launcher"].includes(workspacePolicy.inviteApproval) + ) { res.status(403).json({ ok: false, error: "nodedc_tasker_invite_approval_not_allowed", workspacePolicy }); return; } @@ -518,9 +543,10 @@ app.patch("/api/profile", requireSession, asyncRoute(async (req, res) => { userId: actor.id, }); const storeResult = await controlPlaneStore.markUserAuthentikProvisioned(actor.id, provisionedUser, req.nodedcSession.user); + const taskManagerProfile = await syncTaskManagerUserProfile(storeResult.user); publishControlPlaneEvent("profile.updated", [actor.id]); - res.json({ ...storeResult, provisioning: toProvisioningResponse(provisionedUser) }); + res.json({ ...storeResult, provisioning: toProvisioningResponse(provisionedUser), taskManagerProfile }); })); app.post("/api/profile/password", requireSession, asyncRoute(async (req, res) => { @@ -629,7 +655,15 @@ app.get("/tasker-workspace-invite/:taskerInviteRequestId", (req, res) => { return; } - const runtimeContext = getRuntimeSessionContext(session); + const sessionAccess = getSessionAccessState(session); + + if (!sessionAccess.ok) { + expireSession(res, session); + res.redirect(buildLoginRedirectUrl(req.originalUrl, { forceLogin: true })); + return; + } + + const runtimeContext = sessionAccess.runtimeContext; const request = controlPlaneStore .getSnapshot({ name: "NODE.DC tasker invite redirect" }) .data.taskerInviteRequests.find((candidate) => candidate.id === req.params.taskerInviteRequestId); @@ -660,6 +694,25 @@ app.get("/api/admin/control-plane", requireLauncherAdmin, (req, res) => { res.json(scopeAdminSnapshot(req)); }); +app.get("/api/storage/data", requireSession, (req, res) => { + const snapshot = controlPlaneStore.getSnapshot(req.nodedcSession.user); + + if (snapshot.actor.source !== "launcher") { + res.status(403).json({ error: "Профиль пользователя не найден в Launcher control-plane" }); + return; + } + + const runtimeContext = getRuntimeSessionContext(req.nodedcSession); + const adminScope = resolveAdminScope(runtimeContext.user, runtimeContext.groups); + + if (adminScope.isRoot || adminScope.clientIds.size > 0) { + res.json(scopeControlPlaneData(snapshot.data, adminScope)); + return; + } + + res.json(scopeRuntimeControlPlaneData(snapshot.data, snapshot.actor.id)); +}); + app.patch("/api/admin/settings", requireLauncherAdmin, requireRootLauncherAdmin, asyncRoute(async (req, res) => { const result = await controlPlaneStore.updateSettings(req.body, req.nodedcSession.user); publishControlPlaneEvent("admin.settings.updated"); @@ -1019,8 +1072,10 @@ app.patch("/api/admin/users/:userId/profile", requireLauncherAdmin, asyncRoute(a const result = await controlPlaneStore.updateUserProfile(req.params.userId, req.body, req.nodedcSession.user); const syncResult = await syncUsersToAuthentik(result.data, [req.params.userId], req.nodedcSession.user); + const updatedUser = syncResult.data.users.find((candidate) => candidate.id === req.params.userId); + const taskManagerProfile = await syncTaskManagerUserProfile(updatedUser); publishControlPlaneEvent("admin.user.updated", syncResult.userIds); - res.json(scopeAdminMutationResult(req, { ...result, data: syncResult.data })); + res.json({ ...scopeAdminMutationResult(req, { ...result, data: syncResult.data }), taskManagerProfile }); })); app.delete("/api/admin/users/:userId", requireLauncherAdmin, requireRootLauncherAdmin, asyncRoute(async (req, res) => { @@ -1038,9 +1093,10 @@ app.delete("/api/admin/users/:userId", requireLauncherAdmin, requireRootLauncher authentik = await authentikSyncClient.deleteUser({ data: snapshot.data, userId: req.params.userId }); } + const taskManagerCleanup = await cleanupTaskManagerUserAccess(user); const result = await controlPlaneStore.deleteUser(req.params.userId, req.nodedcSession.user); publishControlPlaneEvent("admin.user.deleted", [req.params.userId]); - res.json({ ...scopeAdminMutationResult(req, result), authentik }); + res.json({ ...scopeAdminMutationResult(req, result), authentik, taskManagerCleanup }); })); app.post("/api/admin/users/:userId/provision-authentik", requireLauncherAdmin, asyncRoute(async (req, res) => { @@ -1371,7 +1427,7 @@ app.get("/api/admin/sync/authentik/plan", requireLauncherAdmin, requireRootLaunc res.json(controlPlaneStore.buildAuthentikSyncPlan()); }); -app.post("/api/storage/upload", asyncRoute(async (req, res) => { +app.post("/api/storage/upload", requireSession, asyncRoute(async (req, res) => { const result = await saveUploadedFile(req.body); res.json(result); })); @@ -1379,9 +1435,14 @@ app.post("/api/storage/upload", asyncRoute(async (req, res) => { app.post("/api/storage/data", requireLauncherAdmin, requireRootLauncherAdmin, asyncRoute(async (req, res) => { await saveLauncherData(req.body); publishControlPlaneEvent("storage.data.updated"); - res.json({ ok: true, url: "/storage/launcher-data.json" }); + res.json({ ok: true }); })); +app.get("/storage/launcher-data.json", (_req, res) => { + setNoStore(res); + res.status(404).json({ error: "not_found" }); +}); + const vite = await createViteServer({ root: projectRoot, appType: "spa", @@ -1433,7 +1494,6 @@ function readConfig() { internalAccessToken: process.env.NODEDC_INTERNAL_ACCESS_TOKEN ?? process.env.NODEDC_PLATFORM_SERVICE_TOKEN ?? - process.env.PLANE_OIDC_CLIENT_SECRET ?? "", taskLogoutUrl: process.env.TASK_LOGOUT_URL ?? @@ -1771,26 +1831,78 @@ function getRuntimeSessionContext(session) { return fallback; } - const groups = resolveRequiredGroups(snapshot.data, user); - - return { - groups, - user: { - ...session.user, - email: user.email, - name: user.name, - avatarUrl: user.avatarUrl ?? session.user.avatarUrl, - groups, - }, - }; + return buildRuntimeSessionContext(session, snapshot.data, user); } catch (error) { console.warn(error instanceof Error ? error.message : "Не удалось рассчитать runtime контекст Launcher"); return fallback; } } -function getAppsForSession(session) { - return getAppsForUser(getRuntimeSessionContext(session).groups); +function buildRuntimeSessionContext(session, data, user) { + const groups = resolveRequiredGroups(data, user); + + return { + groups, + user: { + ...session.user, + email: user.email, + name: user.name, + avatarUrl: user.avatarUrl ?? session.user.avatarUrl, + groups, + }, + }; +} + +function getSessionAccessState(session) { + try { + const snapshot = controlPlaneStore.getSnapshot(session.user); + const sessionEmail = typeof session.user?.email === "string" ? session.user.email.toLowerCase() : ""; + + if (snapshot.actor.source !== "launcher") { + const revokedAccount = snapshot.data.revokedAccounts.find((account) => account.email.toLowerCase() === sessionEmail); + return { + ok: false, + status: 401, + error: revokedAccount ? "account_revoked" : "account_not_found", + message: revokedAccount + ? "Аккаунт больше не активен. Запросите доступ, если хотите подключиться снова." + : "Профиль пользователя не найден в Launcher control-plane.", + }; + } + + const user = snapshot.data.users.find((candidate) => candidate.id === snapshot.actor.id); + + if (!user) { + return { + ok: false, + status: 401, + error: "account_not_found", + message: "Профиль пользователя не найден в Launcher control-plane.", + }; + } + + if (user.globalStatus === "blocked") { + return { + ok: false, + status: 401, + error: "account_blocked", + message: "Аккаунт заблокирован. Обратитесь к администратору NODE.DC.", + }; + } + + return { + ok: true, + runtimeContext: buildRuntimeSessionContext(session, snapshot.data, user), + }; + } catch (error) { + console.warn(error instanceof Error ? error.message : "Не удалось проверить Launcher-сессию"); + return { + ok: false, + status: 401, + error: "session_invalid", + message: "Не удалось проверить Launcher-сессию.", + }; + } } function getAppsForUser(userGroups) { @@ -1809,7 +1921,7 @@ function getAppsForUser(userGroups) { hasAccess, accessReason: hasAccess ? "Доступ подтверждён" : "Нет доступа", }; - }); + }).filter((app) => app.hasAccess); } function getAppCatalog() { @@ -1904,6 +2016,54 @@ async function requestTaskManagerInternalJson(pathname, init = {}) { return payload; } +async function syncTaskManagerUserProfile(user) { + if (!user?.email || !config.internalAccessToken) { + return null; + } + + try { + return await requestTaskManagerInternalJson("/api/internal/nodedc/users/profile-sync/", { + method: "POST", + body: { + email: user.email, + subject: user.authentikUserId ?? undefined, + name: user.name, + avatarUrl: resolveUserAvatarPublicUrl(user), + }, + }); + } catch (error) { + console.warn( + error instanceof Error + ? `Task Manager profile sync failed: ${error.message}` + : "Task Manager profile sync failed" + ); + return null; + } +} + +async function cleanupTaskManagerUserAccess(user) { + if (!user?.email || !config.internalAccessToken) { + return null; + } + + try { + return await requestTaskManagerInternalJson("/api/internal/nodedc/logout/", { + method: "POST", + body: { + source: "launcher-user-hard-delete", + subject: user.authentikUserId ?? undefined, + email: user.email, + revokeIdentityLinks: true, + revokeTaskerAccess: true, + }, + }); + } catch (error) { + const message = error instanceof Error ? error.message : "Task Manager user cleanup failed"; + console.warn(`Task Manager user cleanup failed: ${message}`); + return { ok: false, error: message }; + } +} + function parseJsonResponse(text, url) { try { return JSON.parse(text); @@ -2037,7 +2197,7 @@ function pruneExpiredServiceHandoffs() { } } -function resolveTaskManagerWorkspacePolicy(data, groups, hasTaskManagerAccess, user) { +function resolveTaskManagerWorkspacePolicy(data, groups, hasTaskManagerAccess, user, workspaceSlug = null) { const mode = data.settings?.taskManager?.workspaceCreationPolicy ?? "any_authorized_user"; const groupSet = new Set(groups); const isSuperAdmin = groupSet.has("nodedc:superadmin"); @@ -2049,6 +2209,10 @@ function resolveTaskManagerWorkspacePolicy(data, groups, hasTaskManagerAccess, u ); const defaultManagedBy = hasLauncherManagedWorkspace && !isSuperAdmin ? "launcher" : "tasker"; const defaultInviteApproval = hasLauncherManagedWorkspace && !isSuperAdmin ? "launcher" : isPublicPoolUser ? "nodedc" : "tasker"; + const workspaceAssignment = + typeof workspaceSlug === "string" && workspaceSlug.trim() + ? workspaces.find((workspace) => workspace.slug === workspaceSlug.trim()) + : null; if (!hasTaskManagerAccess) { return { @@ -2077,6 +2241,32 @@ function resolveTaskManagerWorkspacePolicy(data, groups, hasTaskManagerAccess, u } if (hasLauncherManagedWorkspace && !isSuperAdmin) { + if (workspaceAssignment?.managedBy === "launcher") { + return { + mode, + managedBy: "launcher", + defaultManagedBy: "launcher", + inviteApproval: "launcher", + defaultInviteApproval: "launcher", + workspaces, + canCreateWorkspace: false, + reason: "Рабочие пространства этого пользователя управляются через Launcher.", + }; + } + + if (workspaceSlug) { + return { + mode, + managedBy: "tasker", + defaultManagedBy: "launcher", + inviteApproval: defaultInviteApproval, + defaultInviteApproval, + workspaces, + canCreateWorkspace: false, + reason: "Self-service workspace работает через Tasker, approve инвайтов выполняет Launcher.", + }; + } + return { mode, managedBy: "launcher", @@ -2306,11 +2496,8 @@ function getSessionSyncAllowedOrigins() { } function readLauncherData() { - const dataPath = join(projectRoot, "public", "storage", "launcher-data.json"); - try { - if (!existsSync(dataPath)) return null; - return JSON.parse(readFileSync(dataPath, "utf8")); + return controlPlaneStore.readData(); } catch { return null; } @@ -2433,6 +2620,21 @@ function getCurrentSession(req) { return session; } +function expireSession(res, session) { + sessions.delete(session.id); + res.clearCookie(sessionCookieName, clearCookieOptions()); +} + +function rejectInactiveSession(res, session, sessionAccess) { + expireSession(res, session); + res.status(sessionAccess.status ?? 401).json({ + authenticated: false, + loginUrl: "/auth/login", + error: sessionAccess.error, + message: sessionAccess.message, + }); +} + function pruneExpiredSessions() { for (const [sessionId, session] of sessions) { if (session.expiresAt < Date.now()) { @@ -2501,7 +2703,14 @@ function requireLauncherAdmin(req, res, next) { return; } - const runtimeContext = getRuntimeSessionContext(session); + const sessionAccess = getSessionAccessState(session); + + if (!sessionAccess.ok) { + rejectInactiveSession(res, session, sessionAccess); + return; + } + + const runtimeContext = sessionAccess.runtimeContext; const adminScope = resolveAdminScope(runtimeContext.user, runtimeContext.groups); if (!adminScope.isRoot && adminScope.clientIds.size === 0) { @@ -2531,7 +2740,14 @@ function requireSession(req, res, next) { return; } - const runtimeContext = getRuntimeSessionContext(session); + const sessionAccess = getSessionAccessState(session); + + if (!sessionAccess.ok) { + rejectInactiveSession(res, session, sessionAccess); + return; + } + + const runtimeContext = sessionAccess.runtimeContext; req.nodedcSession = { ...session, user: runtimeContext.user }; next(); } @@ -2761,6 +2977,64 @@ function scopeControlPlaneData(data, scope) { }; } +function scopeRuntimeControlPlaneData(data, userId) { + const user = data.users.find((candidate) => candidate.id === userId); + + if (!user) { + return { + ...data, + clients: [], + users: [], + memberships: [], + groups: [], + invites: [], + accessRequests: [], + revokedAccounts: [], + taskerInviteRequests: [], + grants: [], + exceptions: [], + syncStatuses: [], + auditEvents: [], + taskManagerMemberships: [], + taskManagerProjectMemberships: [], + }; + } + + const memberships = data.memberships.filter((membership) => membership.userId === user.id); + const clientIds = new Set(memberships.map((membership) => membership.clientId)); + const groups = data.groups + .filter((group) => clientIds.has(group.clientId) && group.memberIds.includes(user.id)) + .map((group) => ({ ...group, memberIds: group.memberIds.filter((memberId) => memberId === user.id) })); + const groupIds = new Set(groups.map((group) => group.id)); + + return { + ...data, + clients: data.clients.filter((client) => clientIds.has(client.id)), + users: [user], + memberships, + groups, + invites: [], + accessRequests: [], + revokedAccounts: [], + taskerInviteRequests: [], + grants: data.grants.filter((grant) => { + if (grant.targetType === "client") return clientIds.has(grant.targetId); + if (grant.targetType === "group") return groupIds.has(grant.targetId); + if (grant.targetType === "user") return grant.targetId === user.id; + return false; + }), + exceptions: data.exceptions.filter((exception) => exception.userId === user.id), + syncStatuses: [], + auditEvents: [], + taskManagerMemberships: data.taskManagerMemberships.filter( + (membership) => membership.userId === user.id && clientIds.has(membership.clientId) + ), + taskManagerProjectMemberships: data.taskManagerProjectMemberships.filter( + (membership) => membership.userId === user.id && clientIds.has(membership.clientId) + ), + }; +} + function cookieOptions(maxAgeMs) { const options = { httpOnly: true, diff --git a/server/storage/.gitkeep b/server/storage/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/app/LauncherApp.tsx b/src/app/LauncherApp.tsx index bbfc7e5..6b90740 100644 --- a/src/app/LauncherApp.tsx +++ b/src/app/LauncherApp.tsx @@ -108,15 +108,19 @@ export function LauncherApp() { const runtimeDataRef = useRef(data); const runtimeProfileIdRef = useRef(activeProfileId); const runtimeClientIdRef = useRef(activeClientId); + const resolvedProfileId = useMemo( + () => resolveRuntimeProfileId(data, authSession, activeProfileId), + [activeProfileId, authSession, data] + ); useEffect(() => { runtimeDataRef.current = data; - runtimeProfileIdRef.current = activeProfileId; + runtimeProfileIdRef.current = resolvedProfileId; runtimeClientIdRef.current = activeClientId; - }, [activeClientId, activeProfileId, data]); + }, [activeClientId, data, resolvedProfileId]); - const me = useMemo(() => buildMe(data, activeProfileId, activeClientId), [data, activeProfileId, activeClientId]); - const activeProfileUser = data.users.find((user) => user.id === activeProfileId) ?? data.users[0]; + const me = useMemo(() => buildMe(data, resolvedProfileId, activeClientId), [data, resolvedProfileId, activeClientId]); + const activeProfileUser = data.users.find((user) => user.id === resolvedProfileId) ?? data.users[0]; const currentAccessRequest = useMemo(() => { if (!authSession?.authenticated || !authSession.user.email) return null; @@ -150,10 +154,10 @@ export function LauncherApp() { const authAppsBySlug = useMemo(() => new Map((authApps ?? []).map((app) => [app.slug, app])), [authApps]); const launcherServices = useMemo( () => { - const services = buildLauncherServices(data, activeProfileId, resolvedClientId); + const services = buildLauncherServices(data, resolvedProfileId, resolvedClientId); if (!authSession?.authenticated || authApps === null) { - return services; + return []; } return services.map((service) => { @@ -167,32 +171,34 @@ export function LauncherApp() { effectiveAccess: { ...service.effectiveAccess, allowed: false, - visible: true, + visible: false, openEnabled: false, reason: "Нет доступа", }, }; } - const openEnabled = app.hasAccess && app.status === "active"; + const appVisible = app.hasAccess && app.status !== "hidden" && app.status !== "disabled"; + const allowed = appVisible && service.effectiveAccess.allowed; + const openEnabled = appVisible && app.status === "active" && service.effectiveAccess.openEnabled; return { ...service, title: app.title || service.title, description: app.description || service.description, openUrl: openEnabled ? app.openUrl || app.url || service.openUrl : null, - userAccess: openEnabled ? ("allowed" as const) : ("denied" as const), + userAccess: allowed ? ("allowed" as const) : ("denied" as const), effectiveAccess: { ...service.effectiveAccess, - allowed: app.hasAccess, - visible: true, + allowed, + visible: appVisible && service.effectiveAccess.visible, openEnabled, - reason: app.accessReason || (app.hasAccess ? "Доступ подтверждён" : "Нет доступа"), + reason: !app.hasAccess ? app.accessReason || "Нет доступа" : service.effectiveAccess.reason, }, }; - }); + }).filter((service) => service.effectiveAccess.visible); }, - [authApps, authAppsBySlug, authSession, data, activeProfileId, resolvedClientId] + [authApps, authAppsBySlug, authSession, data, resolvedProfileId, resolvedClientId] ); useEffect(() => { @@ -846,7 +852,7 @@ export function LauncherApp() { me={runtimeMe} clients={data.clients} profileOptions={profileOptions} - activeProfileId={activeProfileId} + activeProfileId={resolvedProfileId} activeClientId={resolvedClientId} adminOpen={adminOpen} adminMode={runtimeMe.launcherRole === "root_admin" ? adminMode : "admin"} @@ -1191,6 +1197,28 @@ function resolveAuthenticatedContext( }; } +function resolveRuntimeProfileId(data: LauncherData, session: AuthSession | null, currentProfileId: string): string { + if (data.users.some((user) => user.id === currentProfileId)) { + return currentProfileId; + } + + if (session?.authenticated) { + const sessionEmail = session.user.email?.toLowerCase(); + const sessionSub = session.user.sub; + const sessionUser = data.users.find( + (user) => + (sessionSub && user.authentikUserId === sessionSub) || + (sessionEmail && user.email.toLowerCase() === sessionEmail) + ); + + if (sessionUser) { + return sessionUser.id; + } + } + + return data.users[0]?.id ?? currentProfileId; +} + function resolveDefaultClientId(data: LauncherData, userId: string, requestedClientId: string): string { const user = data.users.find((item) => item.id === userId); const isRoot = user?.id === "user_root"; diff --git a/src/shared/api/authApi.ts b/src/shared/api/authApi.ts index 0d1093f..ffbdbc0 100644 --- a/src/shared/api/authApi.ts +++ b/src/shared/api/authApi.ts @@ -45,7 +45,7 @@ export interface LauncherAuthApp { export async function fetchAuthSession(): Promise { const response = await fetch("/api/me", { cache: "no-store" }); - if (response.status === 401) { + if (response.status === 401 || response.status === 403) { return (await response.json()) as UnauthenticatedSession; } diff --git a/src/shared/api/mockApi.ts b/src/shared/api/mockApi.ts index 707fd98..e62d90b 100644 --- a/src/shared/api/mockApi.ts +++ b/src/shared/api/mockApi.ts @@ -261,7 +261,9 @@ export function buildMe(data: LauncherData, userId: string, requestedClientId?: })); const fallbackClientId = - profileOptions.find((option) => option.userId === user.id)?.defaultClientId ?? availableMemberships[0]?.clientId; + profileOptions.find((option) => option.userId === user.id)?.defaultClientId ?? + availableMemberships[0]?.clientId ?? + PUBLIC_POOL_CLIENT.id; const canUseRequestedClient = availableMemberships.some((membership) => membership.clientId === requestedClientId); const activeClientId = canUseRequestedClient ? requestedClientId! : fallbackClientId; const activeMembership = availableMemberships.find((membership) => membership.clientId === activeClientId); diff --git a/src/shared/api/storageApi.ts b/src/shared/api/storageApi.ts index 9638962..e4d4708 100644 --- a/src/shared/api/storageApi.ts +++ b/src/shared/api/storageApi.ts @@ -30,11 +30,13 @@ export async function uploadStorageFile(file: File): Promise export async function loadPersistedLauncherData(): Promise { try { - const response = await fetch(`/storage/launcher-data.json?ts=${Date.now()}`, { cache: "no-store" }); + const response = await fetch("/api/storage/data", { cache: "no-store" }); if (!response.ok) return null; - return normalizeLauncherData((await response.json()) as Partial); + const data = normalizeLauncherData((await response.json()) as Partial); + + return data.users.length > 0 ? data : null; } catch { return null; } diff --git a/src/widgets/profile-settings-panel/ProfileSettingsPanel.tsx b/src/widgets/profile-settings-panel/ProfileSettingsPanel.tsx index 3e7e025..5f483bc 100644 --- a/src/widgets/profile-settings-panel/ProfileSettingsPanel.tsx +++ b/src/widgets/profile-settings-panel/ProfileSettingsPanel.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { KeyRound, Save, Upload, X } from "lucide-react"; import type { LauncherUser } from "../../entities/user/types"; import { uploadStorageFile } from "../../shared/api/storageApi"; @@ -17,13 +17,42 @@ export function ProfileSettingsPanel({ onChangePassword: (newPassword: string) => Promise; }) { const [draft, setDraft] = useState(user); + const [avatarPreviewUrl, setAvatarPreviewUrl] = useState(user.avatarUrl ?? null); const [newPassword, setNewPassword] = useState(""); const [uploading, setUploading] = useState(false); const [savingProfile, setSavingProfile] = useState(false); const [savingPassword, setSavingPassword] = useState(false); const [message, setMessage] = useState(null); + const draftRef = useRef(draft); + const hasUnsavedProfileChangesRef = useRef(false); + const lastSyncedUserIdRef = useRef(user.id); - useEffect(() => setDraft(user), [user]); + useEffect(() => { + draftRef.current = draft; + }, [draft]); + + useEffect(() => { + const isAnotherUser = lastSyncedUserIdRef.current !== user.id; + + if (!isAnotherUser && hasUnsavedProfileChangesRef.current) { + return; + } + + lastSyncedUserIdRef.current = user.id; + hasUnsavedProfileChangesRef.current = false; + setDraft(user); + setAvatarPreviewUrl(user.avatarUrl ?? null); + setUploading(false); + }, [user]); + + useEffect( + () => () => { + if (avatarPreviewUrl?.startsWith("blob:")) { + URL.revokeObjectURL(avatarPreviewUrl); + } + }, + [avatarPreviewUrl] + ); useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { @@ -35,12 +64,20 @@ export function ProfileSettingsPanel({ }, [onClose]); function update(key: K, value: LauncherUser[K]) { - setDraft((current) => ({ ...current, [key]: value })); + hasUnsavedProfileChangesRef.current = true; + setDraft((current) => { + const nextDraft = { ...current, [key]: value }; + draftRef.current = nextDraft; + return nextDraft; + }); } async function handleAvatarUpload(file: File | undefined) { if (!file) return; + const localPreviewUrl = URL.createObjectURL(file); + hasUnsavedProfileChangesRef.current = true; + setAvatarPreviewUrl(localPreviewUrl); setUploading(true); setMessage(null); @@ -49,6 +86,7 @@ export function ProfileSettingsPanel({ update("avatarUrl", result.url); } catch (error) { setMessage(error instanceof Error ? error.message : "Не удалось загрузить аватар"); + setAvatarPreviewUrl(draftRef.current.avatarUrl ?? null); } finally { setUploading(false); } @@ -59,13 +97,16 @@ export function ProfileSettingsPanel({ setMessage(null); try { + const profileDraft = draftRef.current; await onSaveProfile({ - name: draft.name, - email: draft.email, - phone: draft.phone ?? null, - position: draft.position ?? null, - avatarUrl: draft.avatarUrl ?? null, + name: profileDraft.name, + email: profileDraft.email, + phone: profileDraft.phone ?? null, + position: profileDraft.position ?? null, + avatarUrl: profileDraft.avatarUrl ?? null, }); + hasUnsavedProfileChangesRef.current = false; + setAvatarPreviewUrl(profileDraft.avatarUrl ?? null); setMessage("Профиль сохранён"); } catch (error) { setMessage(error instanceof Error ? error.message : "Не удалось сохранить профиль"); @@ -109,8 +150,8 @@ export function ProfileSettingsPanel({
- {draft.avatarUrl ? ( - + {avatarPreviewUrl ? ( + ) : ( {initials(draft.name)} )} @@ -121,7 +162,11 @@ export function ProfileSettingsPanel({ type="file" accept="image/png,image/jpeg,image/webp,image/gif" disabled={uploading} - onChange={(event) => void handleAvatarUpload(event.target.files?.[0])} + onChange={(event) => { + const file = event.currentTarget.files?.[0]; + event.currentTarget.value = ""; + void handleAvatarUpload(file); + }} />