Files
whatsapp-inbox-platform/prisma/seed.cjs
Wira Basalamah adde003fba
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
chore: initial project import
2026-04-21 09:29:29 +07:00

590 lines
18 KiB
JavaScript

const { PrismaClient, RoleCode, TenantStatus, UserStatus, ChannelStatus, ConversationStatus, ConversationPriority, MessageDirection, MessageType, DeliveryStatus, OptInStatus, TemplateApprovalStatus, CampaignStatus, CampaignAudienceType, CampaignType, PaymentStatus } = require("@prisma/client");
const { pbkdf2Sync, randomBytes } = require("crypto");
const prisma = new PrismaClient();
function hashPassword(password) {
const iterations = 120000;
const salt = randomBytes(16);
const digest = pbkdf2Sync(password, salt, iterations, 32, "sha256");
return `pbkdf2$${iterations}$${salt.toString("base64url")}$${digest.toString("base64url")}`;
}
async function main() {
await prisma.campaignRecipient.deleteMany();
await prisma.broadcastCampaign.deleteMany();
await prisma.messageTemplate.deleteMany();
await prisma.segmentMember.deleteMany();
await prisma.contactSegment.deleteMany();
await prisma.conversationActivity.deleteMany();
await prisma.conversationTag.deleteMany();
await prisma.conversationNote.deleteMany();
await prisma.message.deleteMany();
await prisma.conversation.deleteMany();
await prisma.contactTag.deleteMany();
await prisma.tag.deleteMany();
await prisma.contact.deleteMany();
await prisma.webhookEvent.deleteMany();
await prisma.auditLog.deleteMany();
await prisma.usageMetric.deleteMany();
await prisma.billingInvoice.deleteMany();
await prisma.authToken.deleteMany();
await prisma.channel.deleteMany();
await prisma.user.deleteMany();
await prisma.role.deleteMany();
await prisma.tenant.deleteMany();
await prisma.subscriptionPlan.deleteMany();
await prisma.subscriptionPlan.createMany({
data: [
{
id: "plan-basic",
name: "Basic",
code: "basic",
priceMonthly: 1500000,
messageQuota: 10000,
seatQuota: 5,
broadcastQuota: 2000,
featuresJson: JSON.stringify({ inbox: true, contacts: true, analytics: "basic" })
},
{
id: "plan-pro",
name: "Pro",
code: "pro",
priceMonthly: 2500000,
messageQuota: 50000,
seatQuota: 15,
broadcastQuota: 10000,
featuresJson: JSON.stringify({ inbox: true, contacts: true, analytics: "extended", broadcast: true })
}
]
});
await prisma.tenant.createMany({
data: [
{
id: "tenant-acme",
name: "Acme Co",
slug: "acme-co",
companyName: "Acme Co",
timezone: "Asia/Jakarta",
status: TenantStatus.ACTIVE,
planId: "plan-pro"
},
{
id: "tenant-sinar",
name: "Sinar Abadi",
slug: "sinar-abadi",
companyName: "PT Sinar Abadi",
timezone: "Asia/Jakarta",
status: TenantStatus.TRIAL,
planId: "plan-basic"
}
]
});
await prisma.role.createMany({
data: [
{ id: "role-super-admin", name: "Super Admin", code: RoleCode.SUPER_ADMIN, permissionsJson: JSON.stringify({ global: true }) },
{ id: "role-admin-acme", tenantId: "tenant-acme", name: "Admin Client", code: RoleCode.ADMIN_CLIENT, permissionsJson: JSON.stringify({ tenant: true }) },
{ id: "role-agent-acme", tenantId: "tenant-acme", name: "Agent", code: RoleCode.AGENT, permissionsJson: JSON.stringify({ inbox: true }) },
{ id: "role-admin-sinar", tenantId: "tenant-sinar", name: "Admin Client", code: RoleCode.ADMIN_CLIENT, permissionsJson: JSON.stringify({ tenant: true }) }
]
});
await prisma.user.createMany({
data: [
{
id: "user-super-admin",
tenantId: "tenant-acme",
fullName: "Platform Owner",
email: "owner@inboxsuite.test",
passwordHash: hashPassword("demo123"),
roleId: "role-super-admin",
status: UserStatus.ACTIVE,
lastLoginAt: new Date("2026-04-20T08:00:00Z")
},
{
id: "user-admin-001",
tenantId: "tenant-acme",
fullName: "Admin Operations",
email: "admin@acme.test",
passwordHash: hashPassword("admin123"),
roleId: "role-admin-acme",
status: UserStatus.ACTIVE,
lastLoginAt: new Date("2026-04-20T09:00:00Z")
},
{
id: "user-agent-001",
tenantId: "tenant-acme",
fullName: "Farhan",
email: "farhan@acme.test",
passwordHash: hashPassword("agent123"),
roleId: "role-agent-acme",
status: UserStatus.ACTIVE,
lastLoginAt: new Date("2026-04-20T09:12:00Z")
},
{
id: "user-agent-002",
tenantId: "tenant-acme",
fullName: "Tiara",
email: "tiara@acme.test",
passwordHash: hashPassword("agent123"),
roleId: "role-agent-acme",
status: UserStatus.ACTIVE,
lastLoginAt: new Date("2026-04-20T08:54:00Z")
},
{
id: "user-admin-sinar",
tenantId: "tenant-sinar",
fullName: "Sinar Admin",
email: "admin@sinar.test",
passwordHash: hashPassword("sinar123"),
roleId: "role-admin-sinar",
status: UserStatus.INVITED
}
]
});
await prisma.channel.createMany({
data: [
{
id: "channel-main-acme",
tenantId: "tenant-acme",
channelName: "Main WA",
provider: "Meta BSP",
wabaId: "waba-acme-main",
phoneNumberId: "phone-acme-main",
displayPhoneNumber: "+628111111111",
status: ChannelStatus.CONNECTED,
webhookStatus: "healthy",
lastSyncAt: new Date("2026-04-20T09:10:00Z")
},
{
id: "channel-ops-acme",
tenantId: "tenant-acme",
channelName: "Ops WA",
provider: "Meta BSP",
wabaId: "waba-acme-ops",
phoneNumberId: "phone-acme-ops",
displayPhoneNumber: "+628222222222",
status: ChannelStatus.CONNECTED,
webhookStatus: "healthy",
lastSyncAt: new Date("2026-04-20T08:45:00Z")
},
{
id: "channel-sinar",
tenantId: "tenant-sinar",
channelName: "Sales WA",
provider: "Meta BSP",
wabaId: "waba-sinar-main",
phoneNumberId: "phone-sinar-main",
displayPhoneNumber: "+628333333333",
status: ChannelStatus.PENDING,
webhookStatus: "pending"
}
]
});
await prisma.tag.createMany({
data: [
{ id: "tag-enterprise", tenantId: "tenant-acme", name: "Enterprise", color: "#155eef" },
{ id: "tag-hot-lead", tenantId: "tenant-acme", name: "Hot Lead", color: "#ff7a00" },
{ id: "tag-payment", tenantId: "tenant-acme", name: "Payment Follow-up", color: "#b54708" },
{ id: "tag-b2b", tenantId: "tenant-acme", name: "B2B", color: "#067647" }
]
});
await prisma.contact.createMany({
data: [
{
id: "contact-001",
tenantId: "tenant-acme",
channelId: "channel-main-acme",
fullName: "Nadia Pratama",
phoneNumber: "+628123456789",
email: "nadia@example.com",
countryCode: "ID",
optInStatus: OptInStatus.OPTED_IN,
lastInteractionAt: new Date("2026-04-20T09:12:00Z")
},
{
id: "contact-002",
tenantId: "tenant-acme",
channelId: "channel-ops-acme",
fullName: "PT Sinar Abadi",
phoneNumber: "+62219876543",
email: "ops@sinarabadi.co.id",
countryCode: "ID",
optInStatus: OptInStatus.UNKNOWN,
lastInteractionAt: new Date("2026-04-19T11:00:00Z")
},
{
id: "contact-003",
tenantId: "tenant-acme",
channelId: "channel-main-acme",
fullName: "Rizky Saputra",
phoneNumber: "+628777777777",
email: "rizky@example.com",
countryCode: "ID",
optInStatus: OptInStatus.OPTED_IN,
lastInteractionAt: new Date("2026-04-18T12:00:00Z")
}
]
});
await prisma.contactTag.createMany({
data: [
{ id: "ct-001", tenantId: "tenant-acme", contactId: "contact-001", tagId: "tag-enterprise" },
{ id: "ct-002", tenantId: "tenant-acme", contactId: "contact-001", tagId: "tag-hot-lead" },
{ id: "ct-003", tenantId: "tenant-acme", contactId: "contact-002", tagId: "tag-b2b" },
{ id: "ct-004", tenantId: "tenant-acme", contactId: "contact-003", tagId: "tag-payment" }
]
});
await prisma.contactSegment.create({
data: {
id: "segment-hot-leads",
tenantId: "tenant-acme",
name: "Hot Leads",
description: "Enterprise prospects",
rulesJson: JSON.stringify({ tags: ["Enterprise", "Hot Lead"] })
}
});
await prisma.segmentMember.create({
data: {
id: "segment-member-001",
tenantId: "tenant-acme",
segmentId: "segment-hot-leads",
contactId: "contact-001"
}
});
await prisma.conversation.createMany({
data: [
{
id: "conv-001",
tenantId: "tenant-acme",
channelId: "channel-main-acme",
contactId: "contact-001",
subject: "Enterprise pricing",
status: ConversationStatus.OPEN,
priority: ConversationPriority.HIGH,
assignedUserId: "user-agent-001",
firstMessageAt: new Date("2026-04-20T09:00:00Z"),
lastMessageAt: new Date("2026-04-20T09:12:00Z"),
lastInboundAt: new Date("2026-04-20T09:12:00Z")
},
{
id: "conv-002",
tenantId: "tenant-acme",
channelId: "channel-main-acme",
contactId: "contact-003",
subject: "Payment follow-up",
status: ConversationStatus.PENDING,
priority: ConversationPriority.NORMAL,
firstMessageAt: new Date("2026-04-20T08:30:00Z"),
lastMessageAt: new Date("2026-04-20T08:47:00Z"),
lastInboundAt: new Date("2026-04-20T08:47:00Z")
},
{
id: "conv-003",
tenantId: "tenant-acme",
channelId: "channel-ops-acme",
contactId: "contact-002",
subject: "Template request",
status: ConversationStatus.RESOLVED,
priority: ConversationPriority.NORMAL,
assignedUserId: "user-agent-002",
firstMessageAt: new Date("2026-04-19T09:00:00Z"),
lastMessageAt: new Date("2026-04-19T11:00:00Z"),
lastInboundAt: new Date("2026-04-19T10:20:00Z"),
lastOutboundAt: new Date("2026-04-19T11:00:00Z"),
resolvedAt: new Date("2026-04-19T11:10:00Z")
}
]
});
await prisma.conversationTag.createMany({
data: [
{ id: "cvt-001", tenantId: "tenant-acme", conversationId: "conv-001", tagId: "tag-enterprise" },
{ id: "cvt-002", tenantId: "tenant-acme", conversationId: "conv-001", tagId: "tag-hot-lead" },
{ id: "cvt-003", tenantId: "tenant-acme", conversationId: "conv-002", tagId: "tag-payment" },
{ id: "cvt-004", tenantId: "tenant-acme", conversationId: "conv-003", tagId: "tag-b2b" }
]
});
await prisma.message.createMany({
data: [
{
id: "msg-001",
tenantId: "tenant-acme",
conversationId: "conv-001",
channelId: "channel-main-acme",
contactId: "contact-001",
direction: MessageDirection.INBOUND,
type: MessageType.TEXT,
contentText: "Halo, saya mau tanya soal paket enterprise untuk tim saya.",
deliveryStatus: DeliveryStatus.READ,
createdAt: new Date("2026-04-20T09:00:00Z"),
readAt: new Date("2026-04-20T09:00:00Z")
},
{
id: "msg-002",
tenantId: "tenant-acme",
conversationId: "conv-001",
channelId: "channel-main-acme",
direction: MessageDirection.OUTBOUND,
type: MessageType.TEXT,
contentText: "Tentu. Boleh saya tahu estimasi jumlah agent yang akan memakai sistem?",
deliveryStatus: DeliveryStatus.DELIVERED,
sentByUserId: "user-agent-001",
createdAt: new Date("2026-04-20T09:05:00Z"),
sentAt: new Date("2026-04-20T09:05:00Z"),
deliveredAt: new Date("2026-04-20T09:05:05Z")
},
{
id: "msg-003",
tenantId: "tenant-acme",
conversationId: "conv-002",
channelId: "channel-main-acme",
contactId: "contact-003",
direction: MessageDirection.INBOUND,
type: MessageType.TEXT,
contentText: "Sudah saya transfer, mohon dicek ya.",
deliveryStatus: DeliveryStatus.READ,
createdAt: new Date("2026-04-20T08:47:00Z"),
readAt: new Date("2026-04-20T08:47:00Z")
}
]
});
await prisma.conversationNote.create({
data: {
id: "note-001",
tenantId: "tenant-acme",
conversationId: "conv-001",
userId: "user-agent-001",
content: "Prospek enterprise, follow-up sore ini."
}
});
await prisma.conversationActivity.createMany({
data: [
{
id: "act-001",
tenantId: "tenant-acme",
conversationId: "conv-001",
actorUserId: "user-agent-001",
activityType: "assigned",
metadataJson: JSON.stringify({ assignee: "Farhan" })
},
{
id: "act-002",
tenantId: "tenant-acme",
conversationId: "conv-001",
actorUserId: "user-agent-001",
activityType: "message_sent",
metadataJson: JSON.stringify({ messageId: "msg-002" })
}
]
});
await prisma.messageTemplate.createMany({
data: [
{
id: "tpl-001",
tenantId: "tenant-acme",
channelId: "channel-main-acme",
name: "promo_april_2026",
category: "Marketing",
languageCode: "id",
templateType: "text",
bodyText: "Halo {{1}}, ada promo spesial untuk bisnis Anda minggu ini.",
approvalStatus: TemplateApprovalStatus.APPROVED
},
{
id: "tpl-002",
tenantId: "tenant-acme",
channelId: "channel-ops-acme",
name: "billing_reminder",
category: "Utility",
languageCode: "id",
templateType: "text",
bodyText: "Halo {{1}}, berikut pengingat pembayaran Anda.",
approvalStatus: TemplateApprovalStatus.PENDING
}
]
});
await prisma.broadcastCampaign.createMany({
data: [
{
id: "campaign-001",
tenantId: "tenant-acme",
channelId: "channel-main-acme",
templateId: "tpl-001",
createdByUserId: "user-admin-001",
name: "Promo April",
campaignType: CampaignType.BROADCAST,
audienceType: CampaignAudienceType.SEGMENT,
segmentId: "segment-hot-leads",
scheduledAt: new Date("2026-04-20T10:00:00Z"),
startedAt: new Date("2026-04-20T10:00:00Z"),
finishedAt: new Date("2026-04-20T10:30:00Z"),
status: CampaignStatus.COMPLETED,
totalRecipients: 1203,
totalSent: 1203,
totalDelivered: 1180,
totalRead: 873,
totalFailed: 23
},
{
id: "campaign-002",
tenantId: "tenant-acme",
channelId: "channel-ops-acme",
templateId: "tpl-002",
createdByUserId: "user-admin-001",
name: "Billing Reminder",
campaignType: CampaignType.BULK_FOLLOWUP,
audienceType: CampaignAudienceType.MANUAL,
status: CampaignStatus.DRAFT,
totalRecipients: 0
}
]
});
await prisma.campaignRecipient.createMany({
data: [
{
id: "recipient-001",
tenantId: "tenant-acme",
campaignId: "campaign-001",
contactId: "contact-001",
phoneNumber: "+628123456789",
sendStatus: DeliveryStatus.DELIVERED,
sentAt: new Date("2026-04-20T10:01:00Z"),
deliveredAt: new Date("2026-04-20T10:01:05Z"),
readAt: new Date("2026-04-20T11:00:00Z")
},
{
id: "recipient-002",
tenantId: "tenant-acme",
campaignId: "campaign-001",
contactId: "contact-003",
phoneNumber: "+628777777777",
sendStatus: DeliveryStatus.FAILED,
failureReason: "Template mismatch"
}
]
});
await prisma.usageMetric.createMany({
data: [
{
id: "usage-001",
tenantId: "tenant-acme",
metricDate: new Date("2026-04-20T00:00:00Z"),
inboundMessages: 128,
outboundMessages: 96,
activeContacts: 3,
activeAgents: 2,
broadcastSent: 1203,
storageUsedMb: 512
}
]
});
await prisma.billingInvoice.createMany({
data: [
{
id: "invoice-001",
tenantId: "tenant-acme",
planId: "plan-pro",
invoiceNumber: "INV-2026-001",
periodStart: new Date("2026-04-01T00:00:00Z"),
periodEnd: new Date("2026-04-30T23:59:59Z"),
subtotal: 2500000,
taxAmount: 275000,
totalAmount: 2775000,
paymentStatus: PaymentStatus.PAID,
dueDate: new Date("2026-04-30T00:00:00Z"),
paidAt: new Date("2026-04-15T00:00:00Z")
},
{
id: "invoice-002",
tenantId: "tenant-sinar",
planId: "plan-basic",
invoiceNumber: "INV-2026-002",
periodStart: new Date("2026-04-01T00:00:00Z"),
periodEnd: new Date("2026-04-30T23:59:59Z"),
subtotal: 1500000,
taxAmount: 165000,
totalAmount: 1665000,
paymentStatus: PaymentStatus.UNPAID,
dueDate: new Date("2026-05-01T00:00:00Z")
}
]
});
await prisma.auditLog.createMany({
data: [
{
id: "audit-001",
tenantId: "tenant-acme",
actorUserId: "user-agent-001",
entityType: "conversation",
entityId: "conv-001",
action: "message_sent",
metadataJson: JSON.stringify({ messageId: "msg-002" })
},
{
id: "audit-002",
tenantId: "tenant-acme",
actorUserId: "user-admin-001",
entityType: "campaign",
entityId: "campaign-001",
action: "campaign_created",
metadataJson: JSON.stringify({ recipients: 1203 })
}
]
});
await prisma.webhookEvent.createMany({
data: [
{
id: "webhook-001",
tenantId: "tenant-acme",
channelId: "channel-main-acme",
eventType: "message.inbound",
providerEventId: "evt_001",
payloadJson: JSON.stringify({ source: "meta", conversationId: "conv-001" }),
processStatus: "processed",
processedAt: new Date("2026-04-20T09:00:02Z")
},
{
id: "webhook-002",
tenantId: "tenant-acme",
channelId: "channel-main-acme",
eventType: "message.status",
providerEventId: "evt_002",
payloadJson: JSON.stringify({ source: "meta", campaignId: "campaign-001" }),
processStatus: "failed",
failedReason: "Temporary provider mismatch"
}
]
});
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (error) => {
console.error(error);
await prisma.$disconnect();
process.exit(1);
});