Files
clientsflow/Frontend/prisma/seed.mjs
2026-02-18 09:37:48 +07:00

216 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { PrismaClient } from "@prisma/client";
import fs from "node:fs";
import path from "node:path";
function loadEnvFromDotEnv() {
const p = path.resolve(process.cwd(), ".env");
if (!fs.existsSync(p)) return;
const raw = fs.readFileSync(p, "utf8");
for (const line of raw.split("\n")) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;
const idx = trimmed.indexOf("=");
if (idx === -1) continue;
const key = trimmed.slice(0, idx).trim();
let val = trimmed.slice(idx + 1).trim();
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
val = val.slice(1, -1);
}
if (!key) continue;
// Force DATABASE_URL from local .env for scripts, to avoid inheriting a stale shell env.
if (key === "DATABASE_URL") {
process.env[key] = val;
continue;
}
if (!process.env[key]) process.env[key] = val;
}
}
loadEnvFromDotEnv();
const prisma = new PrismaClient();
function atOffset(days, hour, minute) {
const d = new Date();
d.setDate(d.getDate() + days);
d.setHours(hour, minute, 0, 0);
return d;
}
async function main() {
// Create default team/user for dev.
const user = await prisma.user.upsert({
where: { id: "demo-user" },
update: { email: "demo@clientsflow.local", name: "Demo User" },
create: { id: "demo-user", email: "demo@clientsflow.local", name: "Demo User" },
});
const team = await prisma.team.upsert({
where: { id: "demo-team" },
update: { name: "Demo Team" },
create: { id: "demo-team", name: "Demo Team" },
});
await prisma.teamMember.upsert({
where: { teamId_userId: { teamId: team.id, userId: user.id } },
update: {},
create: { teamId: team.id, userId: user.id, role: "OWNER" },
});
// Idempotent-ish seed per team: if we already have contacts in this team, do nothing.
const existing = await prisma.contact.count({ where: { teamId: team.id } });
if (existing > 0) return;
const contacts = await prisma.contact.createManyAndReturn({
data: [
{
teamId: team.id,
name: "Anna Meyer",
company: "Nordline GmbH",
email: "anna@nordline.example",
phone: "+49 30 123 45 67",
},
{
teamId: team.id,
name: "Murat Ali",
company: "Connect FZCO",
email: "murat@connect.example",
phone: "+971 50 123 4567",
},
{
teamId: team.id,
name: "Ilya Petroff",
company: "Volta Tech",
email: "ilya@volta.example",
phone: "+374 10 123 456",
},
{
teamId: team.id,
name: "Carlos Rivera",
company: "BluePort",
email: "carlos@blueport.example",
phone: "+34 600 123 456",
},
{
teamId: team.id,
name: "Daria Ivanova",
company: "Skyline Trade",
email: "daria@skyline.example",
phone: "+7 777 123 45 67",
},
],
});
const byName = Object.fromEntries(contacts.map((c) => [c.name, c]));
await prisma.contactNote.createMany({
data: [
{
contactId: byName["Anna Meyer"].id,
content:
"Decision owner. Prefers short, concrete updates with a clear next step.\nRisk: decision date slips if we don't lock timeline.",
},
{
contactId: byName["Murat Ali"].id,
content:
"High activity. Needs legal path clarity and an explicit owner on their side.\nBest move: lock legal owner + target signature date.",
},
{
contactId: byName["Ilya Petroff"].id,
content:
"Early-stage. Wants structured onboarding before commercial details.\nBest move: onboarding plan + 2 time slots.",
},
],
});
await prisma.contactMessage.createMany({
data: [
{
contactId: byName["Anna Meyer"].id,
direction: "IN",
channel: "TELEGRAM",
content: "Thanks for the demo. Can you send 2 pricing options?",
occurredAt: atOffset(0, 10, 20),
},
{
contactId: byName["Anna Meyer"].id,
direction: "OUT",
channel: "EMAIL",
content: "Sure. Option A/B attached. Can you confirm decision date for this cycle?",
occurredAt: atOffset(0, 10, 35),
},
{
contactId: byName["Murat Ali"].id,
direction: "IN",
channel: "WHATSAPP",
content: "Let's do a quick call. Need to clarify legal owner.",
occurredAt: atOffset(-1, 18, 10),
},
{
contactId: byName["Ilya Petroff"].id,
direction: "OUT",
channel: "EMAIL",
content: "Draft: onboarding plan + two slots for tomorrow.",
occurredAt: atOffset(-1, 11, 12),
},
],
});
await prisma.calendarEvent.createMany({
data: [
{
teamId: team.id,
contactId: byName["Anna Meyer"].id,
title: "Follow-up: Anna",
startsAt: atOffset(0, 12, 30),
endsAt: atOffset(0, 13, 0),
note: "Lock decision date + confirm option A/B.",
status: "planned",
},
{
teamId: team.id,
contactId: byName["Murat Ali"].id,
title: "Call: Murat (legal owner)",
startsAt: atOffset(0, 15, 0),
endsAt: atOffset(0, 15, 20),
note: "Confirm legal owner + target signature date.",
status: "planned",
},
],
});
await prisma.chatConversation.upsert({
where: { id: `pilot-${team.id}` },
update: {},
create: {
id: `pilot-${team.id}`,
teamId: team.id,
createdByUserId: user.id,
title: "Pilot",
},
});
await prisma.chatMessage.createMany({
data: [
{
teamId: team.id,
conversationId: `pilot-${team.id}`,
authorUserId: null,
role: "ASSISTANT",
text:
"Я смотрю календарь, контакты и переписки как один поток. Спроси: \"чем заняться сегодня\" или \"покажи 10 лучших клиентов\".",
planJson: { steps: ["Скажи задачу", соберу срез данных", "Предложу план и действия"], tools: ["read index/contacts.json"] },
},
],
});
}
main()
.catch((e) => {
console.error(e);
process.exitCode = 1;
})
.finally(async () => {
await prisma.$disconnect();
});