Phase 1: Forward Assist initial build
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>
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
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();
|
||||
});
|
||||
Reference in New Issue
Block a user