better seed data

This commit is contained in:
Oliver Bryan
2026-01-08 19:43:36 +00:00
parent 8cea2815e0
commit 5014822cec

View File

@@ -1,7 +1,7 @@
import "dotenv/config"; import "dotenv/config";
import { drizzle } from "drizzle-orm/node-postgres";
import { Issue, Organisation, OrganisationMember, Project, User } from "@issue/shared"; import { Issue, Organisation, OrganisationMember, Project, User } from "@issue/shared";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
import { drizzle } from "drizzle-orm/node-postgres";
const DATABASE_URL = process.env.DATABASE_URL; const DATABASE_URL = process.env.DATABASE_URL;
@@ -18,50 +18,52 @@ const db = drizzle({
const hashPassword = (password: string) => bcrypt.hash(password, 10); const hashPassword = (password: string) => bcrypt.hash(password, 10);
const issueTitles = [ const issues = [
"Fix login redirect loop", {
"Add pagination to user list", title: "Fix login redirect loop",
"Update dependencies to latest versions", description: "Users are getting stuck in a redirect loop after login.",
"Refactor authentication middleware", },
"Add unit tests for payment service", {
"Fix memory leak in websocket handler", title: "Add pagination to user list",
"Implement password reset flow", description: "The user list loads all users at once, causing slow performance.",
"Add caching for API responses", },
"Fix date formatting in reports", { title: "Update dependencies", description: "Several packages have security updates available." },
"Add export to CSV feature", { title: "Refactor auth middleware", description: "Current implementation is hard to maintain." },
"Improve error messages for form validation", { title: "Add unit tests for payments", description: "Payment service has no test coverage." },
"Fix race condition in queue processor", {
"Add dark mode support", title: "Fix memory leak in websocket",
"Optimize database queries for dashboard", description: "Memory usage grows over time with active connections.",
"Fix broken image uploads on Safari", },
"Add rate limiting to public endpoints", { title: "Implement password reset", description: "Users currently can't reset forgotten passwords." },
"Implement user activity logging", { title: "Add API response caching", description: "Frequently accessed endpoints should be cached." },
"Fix timezone handling in scheduler", { title: "Fix date formatting", description: "Dates display incorrectly in some timezones." },
"Add search functionality to admin panel", { title: "Add CSV export", description: "Users want to export their data to CSV." },
"Refactor legacy billing code", { title: "Improve form validation errors", description: "Error messages are not clear enough." },
"Fix email template rendering", { title: "Fix race condition in queue", description: "Jobs occasionally process twice." },
"Add webhook retry mechanism", { title: "Add dark mode", description: "Users have requested a dark theme option." },
"Improve loading states across app", { title: "Optimize dashboard queries", description: "Dashboard takes too long to load." },
"Fix notification preferences not saving", { title: "Fix image uploads on Safari", description: "Upload fails silently on Safari browsers." },
"Add bulk delete for archived items", { title: "Add rate limiting", description: "API endpoints need protection from abuse." },
"Fix SSO integration with Okta", { title: "Implement activity logging", description: "Need to track user actions for audit purposes." },
"Add two-factor authentication", { title: "Fix timezone handling", description: "Scheduled tasks run at wrong times." },
"Fix scroll position reset on navigation", { title: "Add admin search", description: "Admin panel needs search functionality." },
"Implement lazy loading for images", { title: "Refactor billing code", description: "Legacy billing code needs cleanup." },
"Add audit log for sensitive actions", { title: "Fix email templates", description: "Some email clients render templates incorrectly." },
"Fix PDF generation timeout", { title: "Add webhook retries", description: "Failed webhooks should retry automatically." },
"Add keyboard shortcuts for common actions", { title: "Improve loading states", description: "Users don't know when content is loading." },
]; { title: "Fix notification settings", description: "Preference changes don't persist." },
{ title: "Add bulk delete", description: "Users want to delete multiple items at once." },
const issueDescriptions = [ { title: "Fix SSO integration", description: "SSO login fails intermittently." },
"Users are reporting this issue in production. Need to investigate and fix.", { title: "Add two-factor auth", description: "Security requirement for enterprise users." },
"This has been requested by several customers. Should be straightforward to implement.", { title: "Fix scroll position", description: "Page scrolls to top on navigation." },
"Low priority but would improve developer experience.", { title: "Implement lazy loading", description: "Images should load as user scrolls." },
"Blocking other work. Please prioritize.", { title: "Add audit logging", description: "Need to log sensitive operations." },
"Follow-up from the security audit.", { title: "Fix PDF export timeout", description: "Large reports timeout during export." },
"Performance improvement that could reduce server costs.", { title: "Add keyboard shortcuts", description: "Power users want keyboard navigation." },
"Part of the Q1 roadmap.", { title: "Fix mobile layout", description: "Layout breaks on small screens." },
"Tech debt that we should address soon.", { title: "Add file preview", description: "Users want to preview files before download." },
{ title: "Fix session expiry", description: "Users get logged out unexpectedly." },
{ title: "Add batch processing", description: "Need to process large datasets efficiently." },
]; ];
async function seed() { async function seed() {
@@ -80,8 +82,10 @@ async function seed() {
]) ])
.returning(); .returning();
const u1 = users[0]!; if (users.length < 2 || !users[0] || !users[1]) {
const u2 = users[1]!; throw new Error("failed to create users");
}
const [u1, u2] = users;
console.log(`created ${users.length} users`); console.log(`created ${users.length} users`);
@@ -90,31 +94,31 @@ async function seed() {
const orgs = await db const orgs = await db
.insert(Organisation) .insert(Organisation)
.values([ .values([
{ name: "u1o1", slug: "u1o1", description: "User 1 organisation 1" }, { name: "Acme Corp", slug: "acme", description: "Enterprise software solutions" },
{ name: "u1o2", slug: "u1o2", description: "User 1 organisation 2" }, { name: "Startup Labs", slug: "startup-labs", description: "Innovation hub" },
{ name: "u2o1", slug: "u2o1", description: "User 2 organisation 1" }, { name: "Tech Solutions", slug: "tech-solutions", description: "IT consulting services" },
{ name: "u2o2", slug: "u2o2", description: "User 2 organisation 2" }, { name: "Digital Agency", slug: "digital-agency", description: "Web and mobile development" },
]) ])
.returning(); .returning();
const u1o1 = orgs[0]!; const [acme, startupLabs, techSolutions, digitalAgency] = orgs;
const u1o2 = orgs[1]!; if (!acme || !startupLabs || !techSolutions || !digitalAgency) {
const u2o1 = orgs[2]!; throw new Error("failed to create organisations");
const u2o2 = orgs[3]!; }
console.log(`created ${orgs.length} organisations`); console.log(`created ${orgs.length} organisations`);
// add members to organisations // add members to organisations (both users are members of all orgs)
console.log("adding organisation members..."); console.log("adding organisation members...");
await db.insert(OrganisationMember).values([ await db.insert(OrganisationMember).values([
{ organisationId: u1o1.id, userId: u1.id, role: "owner" }, { organisationId: acme.id, userId: u1.id, role: "owner" },
{ organisationId: u1o1.id, userId: u2.id, role: "member" }, { organisationId: acme.id, userId: u2.id, role: "member" },
{ organisationId: u1o2.id, userId: u1.id, role: "owner" }, { organisationId: startupLabs.id, userId: u1.id, role: "owner" },
{ organisationId: u1o2.id, userId: u2.id, role: "member" }, { organisationId: startupLabs.id, userId: u2.id, role: "member" },
{ organisationId: u2o1.id, userId: u2.id, role: "owner" }, { organisationId: techSolutions.id, userId: u2.id, role: "owner" },
{ organisationId: u2o1.id, userId: u1.id, role: "member" }, { organisationId: techSolutions.id, userId: u1.id, role: "member" },
{ organisationId: u2o2.id, userId: u2.id, role: "owner" }, { organisationId: digitalAgency.id, userId: u2.id, role: "owner" },
{ organisationId: u2o2.id, userId: u1.id, role: "member" }, { organisationId: digitalAgency.id, userId: u1.id, role: "member" },
]); ]);
console.log("added organisation members"); console.log("added organisation members");
@@ -124,49 +128,52 @@ async function seed() {
const projects = await db const projects = await db
.insert(Project) .insert(Project)
.values([ .values([
{ key: "11P1", name: "u1o1p1", organisationId: u1o1.id, creatorId: u1.id }, { key: "WEB", name: "Website Redesign", organisationId: acme.id, creatorId: u1.id },
{ key: "11P2", name: "u1o1p2", organisationId: u1o1.id, creatorId: u1.id }, { key: "API", name: "API Platform", organisationId: acme.id, creatorId: u1.id },
{ key: "12P1", name: "u1o2p1", organisationId: u1o2.id, creatorId: u1.id }, { key: "APP", name: "Mobile App", organisationId: startupLabs.id, creatorId: u1.id },
{ key: "12P2", name: "u1o2p2", organisationId: u1o2.id, creatorId: u1.id }, { key: "DASH", name: "Dashboard", organisationId: startupLabs.id, creatorId: u1.id },
{ key: "21P1", name: "u2o1p1", organisationId: u2o1.id, creatorId: u2.id }, { key: "CRM", name: "CRM System", organisationId: techSolutions.id, creatorId: u2.id },
{ key: "21P2", name: "u2o1p2", organisationId: u2o1.id, creatorId: u2.id }, { key: "ERP", name: "ERP Module", organisationId: techSolutions.id, creatorId: u2.id },
{ key: "22P1", name: "u2o2p1", organisationId: u2o2.id, creatorId: u2.id }, { key: "SHOP", name: "E-commerce Site", organisationId: digitalAgency.id, creatorId: u2.id },
{ key: "22P2", name: "u2o2p2", organisationId: u2o2.id, creatorId: u2.id }, { key: "CMS", name: "Content Platform", organisationId: digitalAgency.id, creatorId: u2.id },
]) ])
.returning(); .returning();
console.log(`created ${projects.length} projects`); console.log(`created ${projects.length} projects`);
// create 0-4 issues per project // create 3-6 issues per project
console.log("creating issues..."); console.log("creating issues...");
const allUsers = [u1, u2]; const allUsers = [u1, u2];
const issueValues = []; const issueValues = [];
let issueTitleIndex = 0; let issueIndex = 0;
for (const project of projects) { for (const project of projects) {
const numIssues = Math.floor(Math.random() * 5); // 0-4 issues const numIssues = Math.floor(Math.random() * 4) + 3; // 3-6 issues
for (let i = 1; i <= numIssues; i++) { for (let i = 1; i <= numIssues; i++) {
const creator = allUsers[Math.floor(Math.random() * allUsers.length)]!; const creator = allUsers[Math.floor(Math.random() * allUsers.length)];
if (!creator) {
throw new Error("failed to select issue creator");
}
const assignee = const assignee =
Math.random() > 0.3 ? allUsers[Math.floor(Math.random() * allUsers.length)] : null; Math.random() > 0.25 ? allUsers[Math.floor(Math.random() * allUsers.length)] : null;
const title = issueTitles[issueTitleIndex % issueTitles.length]!; const issue = issues[issueIndex % issues.length];
const description = issueDescriptions[Math.floor(Math.random() * issueDescriptions.length)]!; if (!issue) {
issueTitleIndex++; throw new Error("failed to select issue");
}
issueIndex++;
issueValues.push({ issueValues.push({
projectId: project.id, projectId: project.id,
number: i, number: i,
title, title: issue.title,
description, description: issue.description,
creatorId: creator.id, creatorId: creator.id,
assigneeId: assignee?.id ?? null, assigneeId: assignee?.id ?? null,
}); });
} }
} }
if (issueValues.length > 0) {
await db.insert(Issue).values(issueValues); await db.insert(Issue).values(issueValues);
}
console.log(`created ${issueValues.length} issues`); console.log(`created ${issueValues.length} issues`);