ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: Launcher control plane и доступы

This commit is contained in:
DCCONSTRUCTIONS
2026-05-04 17:16:47 +03:00
parent de0a0d2948
commit b221ccb83e
19 changed files with 4137 additions and 999 deletions
+236
View File
@@ -0,0 +1,236 @@
import { existsSync, readFileSync } from "node:fs";
import { mkdir, writeFile } from "node:fs/promises";
import { dirname, join } 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 now = new Date().toISOString();
const existingData = readJson(publicDataPath);
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])
);
const dcTouchAuthentikUserId = existingUsersByEmail.get("dcctouch@gmail.com")?.authentikUserId ?? null;
const silverPsihAuthentikUserId = existingUsersByEmail.get("silver_psih@yahoo.com")?.authentikUserId ?? null;
const liveData = {
...existingData,
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 Touch",
contactEmail: "dcctouch@gmail.com",
notes: "Live-клиент NODE.DC для первичной проверки control-plane, SSO и доступа к сервисам.",
createdAt: "2026-05-04T00:00:00.000Z",
updatedAt: now,
},
],
users: [
{
id: "user_root",
authentikUserId: dcTouchAuthentikUserId,
name: "DC Touch",
email: "dcctouch@gmail.com",
phone: null,
position: "NODE.DC Super Admin",
notes: "Главный супер-администратор NODE.DC. Authentik-пользователь уже создан в dev-контуре.",
avatarUrl: null,
globalStatus: "active",
createdAt: "2026-05-04T00:00:00.000Z",
updatedAt: now,
},
{
id: "user_silver_psih",
authentikUserId: silverPsihAuthentikUserId,
name: "Silver Psy",
email: "silver_psih@yahoo.com",
phone: null,
position: "Manager",
notes: "Живой пользователь из Plane. Требует создания/синхронизации в Authentik через Launcher flow.",
avatarUrl: null,
globalStatus: "active",
createdAt: "2026-05-04T00:00:00.000Z",
updatedAt: now,
},
],
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: now,
},
{
id: "mem_silver_psih_dctouch",
clientId: "client_romashka",
userId: "user_silver_psih",
role: "member",
status: "active",
createdAt: "2026-05-04T00:00:00.000Z",
updatedAt: now,
},
],
groups: [
{
id: "group_dctouch_admins",
clientId: "client_romashka",
name: "Администраторы",
description: "Администраторы клиента и владельцы платформенного доступа.",
memberIds: ["user_root"],
createdAt: "2026-05-04T00:00:00.000Z",
updatedAt: now,
},
{
id: "group_dctouch_managers",
clientId: "client_romashka",
name: "Менеджеры",
description: "Рабочая группа менеджеров с доступом к операционному контуру.",
memberIds: ["user_silver_psih"],
createdAt: "2026-05-04T00:00:00.000Z",
updatedAt: now,
},
],
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: now,
},
{
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: now,
},
{
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: now,
},
],
exceptions: [],
invites: [],
syncStatuses: [
{
id: "sync_dctouch_client_authentik",
objectId: "client_romashka",
objectName: "DCTOUCH",
objectType: "client",
target: "authentik",
state: "synced",
lastSyncAt: now,
error: null,
updatedAt: now,
},
{
id: "sync_dc_touch_authentik",
objectId: "user_root",
objectName: "dcctouch@gmail.com",
objectType: "user",
target: "authentik",
state: dcTouchAuthentikUserId ? "synced" : "pending",
lastSyncAt: dcTouchAuthentikUserId ? now : null,
error: dcTouchAuthentikUserId ? null : "Пользователь есть в Authentik, но Launcher seed ещё не содержит Authentik UUID.",
updatedAt: now,
},
{
id: "sync_silver_psih_authentik",
objectId: "user_silver_psih",
objectName: "silver_psih@yahoo.com",
objectType: "user",
target: "authentik",
state: silverPsihAuthentikUserId ? "synced" : "pending",
lastSyncAt: silverPsihAuthentikUserId ? now : null,
error: silverPsihAuthentikUserId
? null
: "Пользователь найден в Plane, но ещё не создан в Authentik через Launcher invite/sync flow.",
updatedAt: now,
},
{
id: "sync_dctouch_groups_authentik",
objectId: "client_romashka:groups",
objectName: "DCTOUCH groups",
objectType: "group",
target: "authentik",
state: "pending",
lastSyncAt: null,
error: null,
updatedAt: now,
},
{
id: "sync_task_manager_authentik",
objectId: "service_task_manager",
objectName: "OPERATIONAL CORE",
objectType: "service",
target: "authentik",
state: "synced",
lastSyncAt: now,
error: null,
updatedAt: now,
},
],
auditEvents: [
{
id: "audit_live_seed_control_plane",
at: now,
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.",
},
],
services,
};
await writeJson(publicDataPath, liveData);
if (existsSync(join(projectRoot, "dist"))) {
await writeJson(distDataPath, liveData);
}
console.log(`Seeded ${liveData.users.length} users, ${liveData.clients.length} client, ${liveData.groups.length} groups.`);
function readJson(path) {
if (!existsSync(path)) {
return {};
}
return JSON.parse(readFileSync(path, "utf8"));
}
async function writeJson(path, data) {
await mkdir(dirname(path), { recursive: true });
await writeFile(path, `${JSON.stringify(data, null, 2)}\n`, "utf8");
}