Skip to content

Commit 53cd12a

Browse files
committed
fix(ci): Fix FK constraint in seed script by making admin membership conditional
Problem: - Seed script ran before server started, so admin user didn't exist yet - Tried to create organization memberships with non-existent user ID - PostgresError: FK constraint violation on member.user_id Solution: - Made adminUserId nullable (string | null) - Skip membership creation if adminUserId is null - Better Auth auto-adds user to default org on signup via API Workflow: 1. Seed script creates organizations (no memberships) 2. CI workflow starts server 3. CI workflow calls Better Auth signup API 4. Better Auth creates user with correct password hash 5. Better Auth auto-adds user to default organization Result: - No FK constraint violations - Password hashing guaranteed to match Better Auth format - Organization membership created via Better Auth plugin 🤖 Generated with Claude Code
1 parent 6113ba6 commit 53cd12a

File tree

1 file changed

+54
-50
lines changed

1 file changed

+54
-50
lines changed

auth-server/scripts/seed-setup.ts

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ async function createAdminUser() {
267267
/**
268268
* Seed default organization (production + dev)
269269
*/
270-
async function seedDefaultOrganization(adminUserId: string) {
270+
async function seedDefaultOrganization(adminUserId: string | null) {
271271
console.log("\n📊 Seeding default organization...\n");
272272

273273
// Create or update default organization
@@ -294,35 +294,39 @@ async function seedDefaultOrganization(adminUserId: string) {
294294
});
295295
}
296296

297-
// Add admin user as owner
298-
const existingMember = await db
299-
.select()
300-
.from(member)
301-
.where(
302-
and(
303-
eq(member.userId, adminUserId),
304-
eq(member.organizationId, DEFAULT_ORG_ID)
305-
)
306-
);
307-
308-
if (existingMember.length > 0) {
309-
console.log(` ✅ Admin already owner of ${DEFAULT_ORG_NAME}`);
297+
// Add admin user as owner (only if user exists)
298+
if (adminUserId) {
299+
const existingMember = await db
300+
.select()
301+
.from(member)
302+
.where(
303+
and(
304+
eq(member.userId, adminUserId),
305+
eq(member.organizationId, DEFAULT_ORG_ID)
306+
)
307+
);
308+
309+
if (existingMember.length > 0) {
310+
console.log(` ✅ Admin already owner of ${DEFAULT_ORG_NAME}`);
311+
} else {
312+
console.log(` ✅ Adding admin as owner`);
313+
await db.insert(member).values({
314+
id: `member-${adminUserId}-${DEFAULT_ORG_ID}`,
315+
userId: adminUserId,
316+
organizationId: DEFAULT_ORG_ID,
317+
role: "owner",
318+
createdAt: new Date(),
319+
});
320+
}
310321
} else {
311-
console.log(` ✅ Adding admin as owner`);
312-
await db.insert(member).values({
313-
id: `member-${adminUserId}-${DEFAULT_ORG_ID}`,
314-
userId: adminUserId,
315-
organizationId: DEFAULT_ORG_ID,
316-
role: "owner",
317-
createdAt: new Date(),
318-
});
322+
console.log(` ⏭️ Skipping admin membership (user will be auto-added on signup)`);
319323
}
320324
}
321325

322326
/**
323327
* Seed test organization (dev only)
324328
*/
325-
async function seedTestOrganization(adminUserId: string) {
329+
async function seedTestOrganization(adminUserId: string | null) {
326330
console.log("\n📊 Seeding test organization...\n");
327331

328332
// Create or update test organization
@@ -349,28 +353,32 @@ async function seedTestOrganization(adminUserId: string) {
349353
});
350354
}
351355

352-
// Add admin user as owner
353-
const existingMember = await db
354-
.select()
355-
.from(member)
356-
.where(
357-
and(
358-
eq(member.userId, adminUserId),
359-
eq(member.organizationId, TEST_ORG.id)
360-
)
361-
);
362-
363-
if (existingMember.length > 0) {
364-
console.log(` ✅ Admin already member of ${TEST_ORG.name}`);
356+
// Add admin user as owner (only if user exists)
357+
if (adminUserId) {
358+
const existingMember = await db
359+
.select()
360+
.from(member)
361+
.where(
362+
and(
363+
eq(member.userId, adminUserId),
364+
eq(member.organizationId, TEST_ORG.id)
365+
)
366+
);
367+
368+
if (existingMember.length > 0) {
369+
console.log(` ✅ Admin already member of ${TEST_ORG.name}`);
370+
} else {
371+
console.log(` ✅ Adding admin as owner`);
372+
await db.insert(member).values({
373+
id: `member-${adminUserId}-${TEST_ORG.id}`,
374+
userId: adminUserId,
375+
organizationId: TEST_ORG.id,
376+
role: "owner",
377+
createdAt: new Date(),
378+
});
379+
}
365380
} else {
366-
console.log(` ✅ Adding admin as owner`);
367-
await db.insert(member).values({
368-
id: `member-${adminUserId}-${TEST_ORG.id}`,
369-
userId: adminUserId,
370-
organizationId: TEST_ORG.id,
371-
role: "owner",
372-
createdAt: new Date(),
373-
});
381+
console.log(` ⏭️ Skipping admin membership (user will join via API)`);
374382
}
375383
}
376384

@@ -417,7 +425,7 @@ async function seed() {
417425
.from(user)
418426
.where(eq(user.email, TEST_ADMIN_EMAIL));
419427

420-
let adminUserId: string;
428+
let adminUserId: string | null = null;
421429
if (existingAdmin.length > 0) {
422430
adminUserId = existingAdmin[0].id;
423431
console.log(` ✅ Admin user exists: ${TEST_ADMIN_EMAIL}`);
@@ -428,11 +436,7 @@ async function seed() {
428436
console.log(` curl -X POST http://localhost:3001/api/auth/sign-up/email \\`);
429437
console.log(` -H "Content-Type: application/json" \\`);
430438
console.log(` -d '{"email":"${TEST_ADMIN_EMAIL}","password":"${TEST_ADMIN_PASSWORD}","name":"${TEST_ADMIN_NAME}"}'`);
431-
432-
// Create a placeholder user ID for organization membership
433-
// The actual user will be created via API, but we need an ID now for the org setup
434-
adminUserId = "admin-user-placeholder-id";
435-
console.log(` ⏭️ Using placeholder ID for organization setup`);
439+
console.log(` ℹ️ User will be auto-added to default organization on signup`);
436440
}
437441

438442
// Seed default organization (ALWAYS - both dev and prod)

0 commit comments

Comments
 (0)