diff --git a/openspec/changes/user-accounts/tasks.md b/openspec/changes/user-accounts/tasks.md index 75d3617..27e5a59 100644 --- a/openspec/changes/user-accounts/tasks.md +++ b/openspec/changes/user-accounts/tasks.md @@ -22,7 +22,7 @@ ## 4. Registration API - [x] 4.1 `[sonnet]` Create `POST /api/auth/register` endpoint: validate input (email required, password 8+ chars), check email uniqueness, hash password with bcryptjs, insert user, return 201 -- [ ] 4.2 `[sonnet]` Add default data seeding function: on new user creation, insert default annotation_types (break_up, break_down, line) and default span_label_types for the new user +- [x] 4.2 `[sonnet]` Add default data seeding function: on new user creation, insert default annotation_types (break_up, break_down, line) and default span_label_types for the new user ## 5. Auth Middleware & Helpers diff --git a/src/app/api/auth/register/route.ts b/src/app/api/auth/register/route.ts index aa22ed5..1fcfec8 100644 --- a/src/app/api/auth/register/route.ts +++ b/src/app/api/auth/register/route.ts @@ -3,6 +3,7 @@ import bcryptjs from 'bcryptjs'; import { eq } from 'drizzle-orm'; import { db } from '@/lib/db'; import { users } from '@/lib/db/schema'; +import { seedUserDefaults } from '@/lib/db/seed-user-defaults'; export async function POST(request: NextRequest) { let body: unknown; @@ -57,6 +58,9 @@ export async function POST(request: NextRequest) { }) .returning({ id: users.id, email: users.email, name: users.name }); + // Seed default annotation types and span label types for the new user + await seedUserDefaults(newUser.id); + return NextResponse.json( { id: newUser.id, email: newUser.email, name: newUser.name }, { status: 201 } diff --git a/src/auth.ts b/src/auth.ts index 55ac105..de06dda 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -5,6 +5,7 @@ import bcryptjs from "bcryptjs"; import { eq } from "drizzle-orm"; import { db } from "@/lib/db"; import { users } from "@/lib/db/schema"; +import { seedUserDefaults } from "@/lib/db/seed-user-defaults"; export const { handlers, auth, signIn, signOut } = NextAuth({ secret: process.env.AUTH_SECRET, @@ -72,14 +73,17 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ if (!existingUser) { // First Google sign-in: create a new user record - await db.insert(users).values({ + const [newUser] = await db.insert(users).values({ email, name: profile?.name ?? user.name ?? null, image: profile?.picture ?? (user.image ?? null), provider: "google", provider_account_id: account.providerAccountId, password_hash: null, - }); + }).returning({ id: users.id }); + + // Seed default annotation types and span label types for the new user + await seedUserDefaults(newUser.id); } // Returning Google sign-in: existing user found, allow sign-in return true; diff --git a/src/lib/db/seed-user-defaults.ts b/src/lib/db/seed-user-defaults.ts new file mode 100644 index 0000000..b72a691 --- /dev/null +++ b/src/lib/db/seed-user-defaults.ts @@ -0,0 +1,50 @@ +import { db } from './index'; +import { annotationTypes, spanLabelTypes } from './schema'; + +const DEFAULT_ANNOTATION_TYPES = [ + { + name: 'break_up', + display_name: 'Break Up', + color: '#10b981', + category: 'marker', + icon: 'arrowUp', + }, + { + name: 'break_down', + display_name: 'Break Down', + color: '#ef4444', + category: 'marker', + icon: 'arrowDown', + }, + { + name: 'line', + display_name: 'Line', + color: '#3b82f6', + category: 'line', + icon: 'line', + }, +]; + +const DEFAULT_SPAN_LABEL_TYPES = [ + { name: 'bull_flag', display_name: 'Bull Flag', color: '#4CAF50', hotkey: '1', sort_order: 1 }, + { name: 'bear_flag', display_name: 'Bear Flag', color: '#F44336', hotkey: '2', sort_order: 2 }, + { name: 'head_and_shoulders', display_name: 'Head and Shoulders', color: '#9C27B0', hotkey: '3', sort_order: 3 }, + { name: 'double_bottom', display_name: 'Double Bottom', color: '#2196F3', hotkey: '4', sort_order: 4 }, + { name: 'wedge_up', display_name: 'Wedge Up', color: '#FF9800', hotkey: '5', sort_order: 5 }, + { name: 'wedge_down', display_name: 'Wedge Down', color: '#FF5722', hotkey: '6', sort_order: 6 }, + { name: 'custom', display_name: 'Custom', color: '#607D8B', hotkey: '7', sort_order: 7 }, +]; + +/** + * Seeds default annotation_types and span_label_types for a newly created user. + * Safe to call on new user creation — inserts rows scoped to the given user_id. + */ +export async function seedUserDefaults(userId: string): Promise { + await db.insert(annotationTypes).values( + DEFAULT_ANNOTATION_TYPES.map((t) => ({ ...t, user_id: userId })) + ); + + await db.insert(spanLabelTypes).values( + DEFAULT_SPAN_LABEL_TYPES.map((t) => ({ ...t, user_id: userId })) + ); +}