seed-mock-data.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/env node
  2. /**
  3. * Seed script — injects mock data into the VidReview database.
  4. *
  5. * Creates:
  6. * 1 admin
  7. * 3 members (each owns 2-3 projects)
  8. * Per project: 1 editor + 1 reviewer (taken from the 3 members)
  9. *
  10. * Usage:
  11. * node scripts/seed-mock-data.js
  12. *
  13. * Env vars (optional, defaults work for local docker):
  14. * DATABASE_URL=postgresql://vidreview:vidreview123@localhost:5432/vidreview
  15. */
  16. import { PrismaClient } from '@prisma/client';
  17. import bcrypt from 'bcryptjs';
  18. const prisma = new PrismaClient();
  19. const BCRYPT_ROUNDS = 10;
  20. const PASSWORD = 'demo1234';
  21. async function cleanAll() {
  22. console.log('\n🧹 Cleaning existing data...');
  23. await prisma.comment.deleteMany();
  24. await prisma.asset.deleteMany();
  25. await prisma.invitation.deleteMany();
  26. await prisma.projectMember.deleteMany();
  27. await prisma.project.deleteMany();
  28. await prisma.user.deleteMany();
  29. console.log(' All tables cleared.');
  30. }
  31. async function createUser(email: string, name: string, globalRole: 'ADMIN' | 'MEMBER', projectRole?: 'ADMIN' | 'EDITOR' | 'REVIEWER' | 'VIEWER') {
  32. const password = await bcrypt.hash(PASSWORD, BCRYPT_ROUNDS);
  33. return prisma.user.create({
  34. data: { email, name, password, globalRole, storageQuota: 524288000, storageUsed: 0 },
  35. select: { id: true, email: true, name: true, globalRole: true },
  36. });
  37. }
  38. async function createProject(name: string, ownerId: string, editorId: string, reviewerId: string) {
  39. const slug = name.toLowerCase().replace(/\s+/g, '-');
  40. // Create project
  41. const project = await prisma.project.create({
  42. data: {
  43. name,
  44. ownerId,
  45. },
  46. });
  47. // Add owner as ADMIN of project
  48. await prisma.projectMember.create({
  49. data: { userId: ownerId, projectId: project.id, role: 'ADMIN', invitedBy: ownerId },
  50. });
  51. // Add editor
  52. await prisma.projectMember.create({
  53. data: { userId: editorId, projectId: project.id, role: 'EDITOR', invitedBy: ownerId },
  54. });
  55. // Add reviewer
  56. await prisma.projectMember.create({
  57. data: { userId: reviewerId, projectId: project.id, role: 'REVIEWER', invitedBy: ownerId },
  58. });
  59. return project;
  60. }
  61. async function main() {
  62. console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
  63. console.log(' VidReview — Mock Data Seeder');
  64. console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
  65. await cleanAll();
  66. // ── 1. Admin ──────────────────────────────────────────────────────────────
  67. const admin = await createUser('admin@vidreview.local', 'Admin', 'ADMIN');
  68. console.log(`✅ Admin created`);
  69. // ── 2. Members ────────────────────────────────────────────────────────────
  70. const memberDefs = [
  71. { email: 'alice@vidreview.local', name: 'Alice Johnson' },
  72. { email: 'bob@vidreview.local', name: 'Bob Smith' },
  73. { email: 'carol@vidreview.local', name: 'Carol White' },
  74. ];
  75. const members = await Promise.all(
  76. memberDefs.map(m => createUser(m.email, m.name, 'MEMBER'))
  77. );
  78. console.log(`✅ ${members.length} members created`);
  79. // ── 3. Projects per member ─────────────────────────────────────────────────
  80. const projectDefs = [
  81. // Alice owns 3 projects
  82. { name: 'Brand Campaign Q2', ownerIdx: 0, editorIdx: 1, reviewerIdx: 2 },
  83. { name: 'Product Launch Video', ownerIdx: 0, editorIdx: 2, reviewerIdx: 1 },
  84. { name: 'Internal Training Clips', ownerIdx: 0, editorIdx: 1, reviewerIdx: 2 },
  85. // Bob owns 2 projects
  86. { name: 'Customer Testimonials', ownerIdx: 1, editorIdx: 0, reviewerIdx: 2 },
  87. { name: 'Event Highlights Reel', ownerIdx: 1, editorIdx: 2, reviewerIdx: 0 },
  88. // Carol owns 3 projects
  89. { name: 'Social Media Shorts', ownerIdx: 2, editorIdx: 0, reviewerIdx: 1 },
  90. { name: 'How-To Tutorial Series', ownerIdx: 2, editorIdx: 1, reviewerIdx: 0 },
  91. { name: 'Partner Collaboration', ownerIdx: 2, editorIdx: 0, reviewerIdx: 1 },
  92. ];
  93. const projects = await Promise.all(
  94. projectDefs.map(p =>
  95. createProject(
  96. p.name,
  97. members[p.ownerIdx].id,
  98. members[p.editorIdx].id,
  99. members[p.reviewerIdx].id,
  100. )
  101. )
  102. );
  103. console.log(`✅ ${projects.length} projects created\n`);
  104. // ── Output credentials table ───────────────────────────────────────────────
  105. const divider = '─'.repeat(72);
  106. console.log(divider);
  107. console.log(' 📋 Login Credentials');
  108. console.log(divider);
  109. console.log(` ${'Type'.padEnd(10)} ${'Name'.padEnd(22)} ${'Email'.padEnd(35)} Password`);
  110. console.log(divider);
  111. console.log(` ${'ADMIN'.padEnd(10)} ${admin.name.padEnd(22)} ${admin.email.padEnd(35)} ${PASSWORD}`);
  112. for (const m of members) {
  113. console.log(` ${'MEMBER'.padEnd(10)} ${m.name.padEnd(22)} ${m.email.padEnd(35)} ${PASSWORD}`);
  114. }
  115. console.log(divider);
  116. console.log(`\n All users have storage quota: 500 MB`);
  117. console.log(` Password for all accounts: ${PASSWORD}`);
  118. console.log('');
  119. console.log(' Project membership per user:');
  120. console.log(divider);
  121. for (const m of members) {
  122. const memberProjects = projects.filter((_, i) => projectDefs[i].ownerIdx === members.indexOf(m));
  123. const roleMap: Record<string, string> = {};
  124. for (const proj of memberProjects) {
  125. const def = projectDefs.find(p => p.name === proj.name)!;
  126. const role = members[projectDefs.findIndex(p => p.name === proj.name)].id === m.id
  127. ? 'owner → project ADMIN'
  128. : `project ${projectDefs.findIndex(p => p.name === proj.name) < 3 ? ['EDITOR', 'REVIEWER', 'EDITOR'][projectDefs.findIndex(p => p.name === proj.name) % 3] : ['REVIEWER', 'EDITOR', 'REVIEWER'][projectDefs.findIndex(p => p.name === proj.name) % 3]}`;
  129. }
  130. const memberships = await prisma.projectMember.findMany({
  131. where: { userId: m.id },
  132. include: { project: true },
  133. });
  134. const roles = await prisma.projectMember.findMany({ where: { userId: m.id } });
  135. const lines = memberships.map((pm, i) => {
  136. const def = projectDefs.find(p => p.name === pm.project.name)!;
  137. const role = pm.userId === members[def.ownerIdx].id ? 'ADMIN (owner)' : roles[i].role;
  138. return ` • ${pm.project.name.padEnd(30)} [${role}]`;
  139. });
  140. console.log(` ${m.name} (${m.email}):`);
  141. lines.forEach(l => console.log(l));
  142. }
  143. console.log(divider);
  144. console.log('\n✅ Done!\n');
  145. await prisma.$disconnect();
  146. }
  147. main().catch(err => {
  148. console.error('\n❌ Seed failed:', err);
  149. process.exit(1);
  150. });