05aad75272
Multi-tenant AI help desk SaaS for the firearms industry. Full monorepo: API (Express/Prisma), Worker (BullMQ), Frontend (React/Vite/Tailwind). PostgreSQL 16 + pgvector, Redis 7, JWT auth, RLS tenant isolation. Dark Armory theme with tactical branding throughout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
148 lines
3.7 KiB
TypeScript
148 lines
3.7 KiB
TypeScript
import { PrismaClient } from '@prisma/client';
|
|
import bcrypt from 'bcryptjs';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
console.log('Seeding Forward Assist database...');
|
|
|
|
// Create plans
|
|
const trialPlan = await prisma.plan.upsert({
|
|
where: { slug: 'trial' },
|
|
update: {},
|
|
create: {
|
|
name: 'Trial',
|
|
slug: 'trial',
|
|
maxUsers: 2,
|
|
maxEmailAccounts: 1,
|
|
maxTicketsPerMonth: 100,
|
|
aiDraftsEnabled: true,
|
|
knowledgeBaseEnabled: false,
|
|
priceMonthly: 0,
|
|
priceYearly: 0,
|
|
},
|
|
});
|
|
|
|
await prisma.plan.upsert({
|
|
where: { slug: 'starter' },
|
|
update: {},
|
|
create: {
|
|
name: 'Starter',
|
|
slug: 'starter',
|
|
maxUsers: 5,
|
|
maxEmailAccounts: 2,
|
|
maxTicketsPerMonth: 1000,
|
|
aiDraftsEnabled: true,
|
|
knowledgeBaseEnabled: false,
|
|
priceMonthly: 49,
|
|
priceYearly: 470,
|
|
},
|
|
});
|
|
|
|
await prisma.plan.upsert({
|
|
where: { slug: 'pro' },
|
|
update: {},
|
|
create: {
|
|
name: 'Pro',
|
|
slug: 'pro',
|
|
maxUsers: 20,
|
|
maxEmailAccounts: 10,
|
|
maxTicketsPerMonth: 10000,
|
|
aiDraftsEnabled: true,
|
|
knowledgeBaseEnabled: true,
|
|
priceMonthly: 149,
|
|
priceYearly: 1430,
|
|
},
|
|
});
|
|
|
|
await prisma.plan.upsert({
|
|
where: { slug: 'enterprise' },
|
|
update: {},
|
|
create: {
|
|
name: 'Enterprise',
|
|
slug: 'enterprise',
|
|
maxUsers: 999,
|
|
maxEmailAccounts: 50,
|
|
maxTicketsPerMonth: 999999,
|
|
aiDraftsEnabled: true,
|
|
knowledgeBaseEnabled: true,
|
|
priceMonthly: 499,
|
|
priceYearly: 4790,
|
|
},
|
|
});
|
|
|
|
// Create test tenant
|
|
const tenant = await prisma.tenant.upsert({
|
|
where: { slug: 'demo-armory' },
|
|
update: {},
|
|
create: {
|
|
name: 'Demo Armory',
|
|
slug: 'demo-armory',
|
|
planId: trialPlan.id,
|
|
settings: {
|
|
timezone: 'America/Chicago',
|
|
businessHours: {
|
|
monday: { enabled: true, start: '09:00', end: '17:00' },
|
|
tuesday: { enabled: true, start: '09:00', end: '17:00' },
|
|
wednesday: { enabled: true, start: '09:00', end: '17:00' },
|
|
thursday: { enabled: true, start: '09:00', end: '17:00' },
|
|
friday: { enabled: true, start: '09:00', end: '17:00' },
|
|
saturday: { enabled: false, start: '10:00', end: '14:00' },
|
|
sunday: { enabled: false, start: '10:00', end: '14:00' },
|
|
},
|
|
autoReplyEnabled: false,
|
|
autoReplyMessage: 'Thank you for contacting us. We will respond within 24 hours.',
|
|
aiDraftEnabled: false,
|
|
aiTone: 'professional',
|
|
ticketPrefix: 'FA',
|
|
maxTicketsPerDay: 100,
|
|
},
|
|
},
|
|
});
|
|
|
|
// Create admin user (password: "admin123")
|
|
const passwordHash = await bcrypt.hash('admin123', 12);
|
|
const adminUser = await prisma.user.upsert({
|
|
where: { tenantId_email: { tenantId: tenant.id, email: 'admin@demo-armory.com' } },
|
|
update: {},
|
|
create: {
|
|
tenantId: tenant.id,
|
|
email: 'admin@demo-armory.com',
|
|
passwordHash,
|
|
name: 'Range Master',
|
|
role: 'owner',
|
|
isActive: true,
|
|
},
|
|
});
|
|
|
|
// Create notification preferences for admin
|
|
await prisma.notificationPreference.upsert({
|
|
where: { userId: adminUser.id },
|
|
update: {},
|
|
create: {
|
|
userId: adminUser.id,
|
|
tenantId: tenant.id,
|
|
newTicket: true,
|
|
ticketAssigned: true,
|
|
ticketReply: true,
|
|
aiDraftReady: true,
|
|
dailyDigest: false,
|
|
emailNotifications: true,
|
|
},
|
|
});
|
|
|
|
console.log('Seed complete!');
|
|
console.log(` Plans: trial, starter, pro, enterprise`);
|
|
console.log(` Tenant: ${tenant.name} (${tenant.slug})`);
|
|
console.log(` Admin: ${adminUser.email} / admin123`);
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|