Spaces:
Sleeping
Sleeping
| const bcrypt = require('bcryptjs'); | |
| const { collections, FieldValue } = require('./firestore'); | |
| function slug(s) { | |
| return s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); | |
| } | |
| async function seed() { | |
| try { | |
| // Demo user | |
| const demoEmail = 'demo@bolt.run'; | |
| const existing = await collections.users.where('email', '==', demoEmail).limit(1).get(); | |
| if (existing.empty) { | |
| const hash = await bcrypt.hash('password123', 10); | |
| const ref = collections.users.doc(); | |
| await ref.set({ | |
| name: 'Demo Runner', | |
| email: demoEmail, | |
| password_hash: hash, | |
| avatar_url: null, | |
| weight_kg: 70, | |
| height_cm: 175, | |
| date_of_birth: null, | |
| total_runs: 0, | |
| total_distance_km: 0, | |
| total_duration_sec: 0, | |
| total_calories: 0, | |
| created_at: FieldValue.serverTimestamp(), | |
| updated_at: FieldValue.serverTimestamp(), | |
| }); | |
| console.log(' + demo user created'); | |
| } else { | |
| console.log(' · demo user exists'); | |
| } | |
| // Programs (deterministic doc IDs from title slug for idempotent seed) | |
| const programs = [ | |
| { title: '5K Beginner Plan', description: 'Go from couch to 5K in 8 weeks', coach_name: 'Eliud Kipchoge', duration_weeks: 8, sessions_per_week: 3, difficulty: 'beginner', category: '5K', is_featured: true }, | |
| { title: '10K Speed Builder', description: 'Build speed and endurance for 10K', coach_name: 'Joshua Cheptegei', duration_weeks: 10, sessions_per_week: 4, difficulty: 'intermediate', category: '10K', is_featured: true }, | |
| { title: 'Half Marathon Prep', description: 'Complete your first half marathon', coach_name: 'Brigid Kosgei', duration_weeks: 12, sessions_per_week: 5, difficulty: 'intermediate', category: 'Half Marathon', is_featured: false }, | |
| { title: 'Marathon Masters', description: 'Advanced marathon training plan', coach_name: 'Kenenisa Bekele', duration_weeks: 16, sessions_per_week: 6, difficulty: 'advanced', category: 'Marathon', is_featured: false }, | |
| ]; | |
| for (const p of programs) { | |
| const id = slug(p.title); | |
| const ref = collections.programs.doc(id); | |
| const snap = await ref.get(); | |
| if (!snap.exists) { | |
| await ref.set({ | |
| ...p, | |
| coach_avatar_url: null, | |
| image_url: null, | |
| total_enrolled: 0, | |
| created_at: FieldValue.serverTimestamp(), | |
| }); | |
| console.log(` + program "${p.title}"`); | |
| } | |
| } | |
| // Clubs | |
| const clubs = [ | |
| { name: 'Morning Milers', description: 'Early birds who love the sunrise run', location: 'New York, NY', member_count: 124 }, | |
| { name: 'Trail Blazers', description: 'Off-road and trail running enthusiasts', location: 'Denver, CO', member_count: 89 }, | |
| { name: 'Speed Demons', description: 'Track and interval training focus', location: 'Los Angeles, CA', member_count: 203 }, | |
| { name: 'Weekend Warriors', description: 'Casual runners, serious fun', location: 'Chicago, IL', member_count: 156 }, | |
| ]; | |
| for (const c of clubs) { | |
| const id = slug(c.name); | |
| const ref = collections.clubs.doc(id); | |
| const snap = await ref.get(); | |
| if (!snap.exists) { | |
| await ref.set({ | |
| ...c, | |
| avatar_url: null, | |
| cover_url: null, | |
| is_public: true, | |
| created_by: null, | |
| created_at: FieldValue.serverTimestamp(), | |
| }); | |
| console.log(` + club "${c.name}"`); | |
| } | |
| } | |
| console.log('Seed complete.'); | |
| process.exit(0); | |
| } catch (err) { | |
| console.error('Seed failed:', err); | |
| process.exit(1); | |
| } | |
| } | |
| seed(); | |