237 lines
7.4 KiB
JavaScript
237 lines
7.4 KiB
JavaScript
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");
|
||
}
|