diff --git a/backend/package.json b/backend/package.json index 9f65bd2..8bfc61e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -54,5 +54,8 @@ "testMatch": [ "**/__tests__/**/*.test.js" ] + }, + "prisma": { + "seed": "node prisma/seed.js" } } diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index bde4451..664801f 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -62,7 +62,7 @@ model User { // Events table (dance events from worldsdc.com) model Event { id Int @id @default(autoincrement()) - slug String @unique @db.VarChar(50) + slug String @unique @default(cuid()) @db.VarChar(50) name String @db.VarChar(255) location String @db.VarChar(255) startDate DateTime @map("start_date") @db.Date diff --git a/backend/prisma/seed.js b/backend/prisma/seed.js index e40f523..d288250 100644 --- a/backend/prisma/seed.js +++ b/backend/prisma/seed.js @@ -1,10 +1,70 @@ const { PrismaClient } = require('@prisma/client'); +const bcrypt = require('bcryptjs'); const prisma = new PrismaClient(); async function main() { console.log('🌱 Seeding database...'); + // Create test users + const testUsers = await Promise.all([ + prisma.user.upsert({ + where: { email: 'john@example.com' }, + update: {}, + create: { + username: 'john_dancer', + email: 'john@example.com', + passwordHash: await bcrypt.hash('Dance123!', 10), + firstName: 'John', + lastName: 'Smith', + wsdcId: '12345', + emailVerified: true, + country: 'United States', + city: 'Los Angeles', + instagramUrl: 'https://instagram.com/johndancer', + youtubeUrl: 'https://youtube.com/@johndancer', + }, + }), + prisma.user.upsert({ + where: { email: 'sarah@example.com' }, + update: {}, + create: { + username: 'sarah_swings', + email: 'sarah@example.com', + passwordHash: await bcrypt.hash('Swing456!', 10), + firstName: 'Sarah', + lastName: 'Johnson', + wsdcId: '23456', + emailVerified: true, + country: 'United Kingdom', + city: 'London', + tiktokUrl: 'https://tiktok.com/@sarahswings', + facebookUrl: 'https://facebook.com/sarah.swings', + }, + }), + prisma.user.upsert({ + where: { email: 'mike@example.com' }, + update: {}, + create: { + username: 'mike_blues', + email: 'mike@example.com', + passwordHash: await bcrypt.hash('Blues789!', 10), + firstName: 'Mike', + lastName: 'Williams', + wsdcId: '34567', + emailVerified: true, + country: 'Sweden', + city: 'Stockholm', + instagramUrl: 'https://instagram.com/mikeblues', + youtubeUrl: 'https://youtube.com/@mikeblues', + tiktokUrl: 'https://tiktok.com/@mikeblues', + facebookUrl: 'https://facebook.com/mike.blues', + }, + }), + ]); + + console.log(`✅ Created ${testUsers.length} test users`); + // Create divisions const divisions = await Promise.all([ prisma.division.upsert({ @@ -57,13 +117,12 @@ async function main() { console.log(`✅ Created ${competitionTypes.length} competition types`); - // Create events + // Create events (slug will be auto-generated as cuid for security) const events = await Promise.all([ prisma.event.upsert({ - where: { slug: 'warsaw-dance-festival-2025' }, + where: { worldsdcId: 'wdf-2025' }, update: {}, create: { - slug: 'warsaw-dance-festival-2025', name: 'Warsaw Dance Festival 2025', location: 'Warsaw, Poland', startDate: new Date('2025-03-15'), @@ -74,10 +133,9 @@ async function main() { }, }), prisma.event.upsert({ - where: { slug: 'swing-camp-barcelona-2025' }, + where: { worldsdcId: 'scb-2025' }, update: {}, create: { - slug: 'swing-camp-barcelona-2025', name: 'Swing Camp Barcelona 2025', location: 'Barcelona, Spain', startDate: new Date('2025-04-20'), @@ -88,10 +146,9 @@ async function main() { }, }), prisma.event.upsert({ - where: { slug: 'blues-week-herrang-2025' }, + where: { worldsdcId: 'bwh-2025' }, update: {}, create: { - slug: 'blues-week-herrang-2025', name: 'Blues Week Herräng 2025', location: 'Herräng, Sweden', startDate: new Date('2025-07-14'), @@ -102,10 +159,9 @@ async function main() { }, }), prisma.event.upsert({ - where: { slug: 'krakow-swing-connection-2025' }, + where: { worldsdcId: 'ksc-2025' }, update: {}, create: { - slug: 'krakow-swing-connection-2025', name: 'Krakow Swing Connection 2025', location: 'Krakow, Poland', startDate: new Date('2025-05-10'), @@ -133,13 +189,161 @@ async function main() { console.log(`✅ Created ${chatRooms.length} event chat rooms`); + // Add test users as event participants (check-in) + const warsawEvent = events[0]; // Warsaw Dance Festival + const barcelonaEvent = events[1]; // Swing Camp Barcelona + + const eventParticipants = await Promise.all([ + // John participates in Warsaw + prisma.eventParticipant.upsert({ + where: { + userId_eventId: { + userId: testUsers[0].id, + eventId: warsawEvent.id, + }, + }, + update: {}, + create: { + userId: testUsers[0].id, + eventId: warsawEvent.id, + }, + }), + // Sarah participates in Warsaw + prisma.eventParticipant.upsert({ + where: { + userId_eventId: { + userId: testUsers[1].id, + eventId: warsawEvent.id, + }, + }, + update: {}, + create: { + userId: testUsers[1].id, + eventId: warsawEvent.id, + }, + }), + // Mike participates in Warsaw + prisma.eventParticipant.upsert({ + where: { + userId_eventId: { + userId: testUsers[2].id, + eventId: warsawEvent.id, + }, + }, + update: {}, + create: { + userId: testUsers[2].id, + eventId: warsawEvent.id, + }, + }), + // John also in Barcelona + prisma.eventParticipant.upsert({ + where: { + userId_eventId: { + userId: testUsers[0].id, + eventId: barcelonaEvent.id, + }, + }, + update: {}, + create: { + userId: testUsers[0].id, + eventId: barcelonaEvent.id, + }, + }), + ]); + + console.log(`✅ Added ${eventParticipants.length} event participants`); + + // Create sample heats for test users in Warsaw event + const jjType = competitionTypes[0]; // Jack & Jill + const strType = competitionTypes[1]; // Strictly + const novDiv = divisions[1]; // Novice + const intDiv = divisions[2]; // Intermediate + const advDiv = divisions[3]; // Advanced + + const heats = await Promise.all([ + // John: J&J Novice Heat 1 (Leader), Strictly Intermediate Heat 2 (Leader) + prisma.eventUserHeat.create({ + data: { + userId: testUsers[0].id, + eventId: warsawEvent.id, + divisionId: novDiv.id, + competitionTypeId: jjType.id, + heatNumber: 1, + role: 'Leader', + }, + }), + prisma.eventUserHeat.create({ + data: { + userId: testUsers[0].id, + eventId: warsawEvent.id, + divisionId: intDiv.id, + competitionTypeId: strType.id, + heatNumber: 2, + role: 'Leader', + }, + }), + // Sarah: J&J Novice Heat 1 (Follower), J&J Advanced Heat 3 + prisma.eventUserHeat.create({ + data: { + userId: testUsers[1].id, + eventId: warsawEvent.id, + divisionId: novDiv.id, + competitionTypeId: jjType.id, + heatNumber: 1, + role: 'Follower', + }, + }), + prisma.eventUserHeat.create({ + data: { + userId: testUsers[1].id, + eventId: warsawEvent.id, + divisionId: advDiv.id, + competitionTypeId: jjType.id, + heatNumber: 3, + role: null, + }, + }), + // Mike: J&J Intermediate Heat 5 (Leader), Strictly Advanced Heat 1 (Follower) + prisma.eventUserHeat.create({ + data: { + userId: testUsers[2].id, + eventId: warsawEvent.id, + divisionId: intDiv.id, + competitionTypeId: jjType.id, + heatNumber: 5, + role: 'Leader', + }, + }), + prisma.eventUserHeat.create({ + data: { + userId: testUsers[2].id, + eventId: warsawEvent.id, + divisionId: advDiv.id, + competitionTypeId: strType.id, + heatNumber: 1, + role: 'Follower', + }, + }), + ]); + + console.log(`✅ Created ${heats.length} sample heats`); + console.log('🎉 Seeding completed successfully!'); console.log(''); console.log('Created:'); + console.log(` - ${testUsers.length} test users`); console.log(` - ${divisions.length} divisions`); console.log(` - ${competitionTypes.length} competition types`); console.log(` - ${events.length} events`); console.log(` - ${chatRooms.length} chat rooms`); + console.log(` - ${eventParticipants.length} event participants`); + console.log(` - ${heats.length} sample heats`); + console.log(''); + console.log('Test accounts:'); + console.log(' 1. john_dancer / Dance123!'); + console.log(' 2. sarah_swings / Swing456!'); + console.log(' 3. mike_blues / Blues789!'); } main() diff --git a/docs/SESSION_CONTEXT.md b/docs/SESSION_CONTEXT.md index 949f1b9..04d9e62 100644 --- a/docs/SESSION_CONTEXT.md +++ b/docs/SESSION_CONTEXT.md @@ -339,17 +339,47 @@ RUN apk add --no-cache openssl --- -## Quick Reference - Mock Data +## Test Accounts -**Mock User (logged in):** -- ID: 1 -- Username: john_doe -- Email: john@example.com +**Test users for manual testing (seeded in database):** -**Mock Events:** -- ID: 1 - Warsaw Dance Festival 2025 -- ID: 2 - Swing Camp Barcelona 2025 -- ID: 3 - Blues Week Herräng 2025 +1. **john_dancer** + - Email: `john@example.com` + - Password: `Dance123!` + - Profile: John Smith (WSDC #12345), Los Angeles, USA + - Social: Instagram, YouTube + - Events: Warsaw Dance Festival (checked in), Swing Camp Barcelona (checked in) + - Heats in Warsaw: J&J NOV 1 L, STR INT 2 L + +2. **sarah_swings** + - Email: `sarah@example.com` + - Password: `Swing456!` + - Profile: Sarah Johnson (WSDC #23456), London, UK + - Social: TikTok, Facebook + - Events: Warsaw Dance Festival (checked in) + - Heats in Warsaw: J&J NOV 1 F, J&J ADV 3 + +3. **mike_blues** + - Email: `mike@example.com` + - Password: `Blues789!` + - Profile: Mike Williams (WSDC #34567), Stockholm, Sweden + - Social: Instagram, YouTube, TikTok, Facebook + - Events: Warsaw Dance Festival (checked in) + - Heats in Warsaw: J&J INT 5 L, STR ADV 1 F + +**Note:** All test users are verified and checked in to Warsaw Dance Festival 2025 event. They have pre-configured heats to test the matchmaking system. + +--- + +## Quick Reference - Events + +**Seeded Events (slugs are auto-generated cuid for security):** +- Warsaw Dance Festival 2025 (slug: auto-generated, e.g. `cmhz3lcgb00018vbn34v4phoi`) +- Swing Camp Barcelona 2025 (slug: auto-generated) +- Blues Week Herräng 2025 (slug: auto-generated) +- Krakow Swing Connection 2025 (slug: auto-generated) + +**Note:** Event slugs are randomly generated cuid strings to prevent ID enumeration attacks. To find the actual slug, log in and check the Events page URL. ---