seed data

This commit is contained in:
2025-12-30 18:33:15 +01:00
parent 83371ea839
commit 92226800df
306 changed files with 1753 additions and 501 deletions

View File

@@ -78,6 +78,10 @@ export class SeedRacingData {
return process.env.DATABASE_URL ? 'postgres' : 'inmemory';
}
private getMediaBaseUrl(): string {
return process.env.NODE_ENV === 'development' ? 'http://localhost:3001' : 'https://api.gridpilot.io';
}
async execute(): Promise<void> {
const existingDrivers = await this.seedDeps.driverRepository.findAll();
const persistence = this.getApiPersistence();
@@ -428,7 +432,7 @@ export class SeedRacingData {
private calculateTeamStats(team: Team, results: Result[], drivers: Driver[]): TeamStats {
const wins = results.filter(r => r.position.toNumber() === 1).length;
const totalRaces = results.length;
// Calculate rating
const baseRating = 1000;
const winBonus = wins * 50;
@@ -462,7 +466,7 @@ export class SeedRacingData {
})));
return {
logoUrl: `https://api.gridpilot.io/media/team/${team.id}/logo.png`,
logoUrl: `${this.getMediaBaseUrl()}/api/media/teams/${team.id}/logo`,
performanceLevel,
specialization,
region,
@@ -482,21 +486,22 @@ export class SeedRacingData {
}
private async seedMediaAssets(seed: any): Promise<void> {
// Seed driver avatars
const baseUrl = this.getMediaBaseUrl();
// Seed driver avatars using static files
for (const driver of seed.drivers) {
const avatarUrl = `https://api.gridpilot.io/media/driver/${driver.id}/avatar.png`;
// Type assertion to access the helper method
const avatarUrl = this.getDriverAvatarUrl(driver.id);
const mediaRepo = this.seedDeps.mediaRepository as any;
if (mediaRepo.setDriverAvatar) {
mediaRepo.setDriverAvatar(driver.id, avatarUrl);
}
}
// Seed team logos
// Seed team logos using API routes
for (const team of seed.teams) {
const logoUrl = `https://api.gridpilot.io/media/team/${team.id}/logo.png`;
const logoUrl = `${baseUrl}/api/media/teams/${team.id}/logo`;
const mediaRepo = this.seedDeps.mediaRepository as any;
if (mediaRepo.setTeamLogo) {
mediaRepo.setTeamLogo(team.id, logoUrl);
@@ -505,8 +510,8 @@ export class SeedRacingData {
// Seed track images
for (const track of seed.tracks || []) {
const trackImageUrl = `https://api.gridpilot.io/media/track/${track.id}/image.png`;
const trackImageUrl = `${baseUrl}/api/media/tracks/${track.id}/image`;
const mediaRepo = this.seedDeps.mediaRepository as any;
if (mediaRepo.setTrackImage) {
mediaRepo.setTrackImage(track.id, trackImageUrl);
@@ -516,8 +521,8 @@ export class SeedRacingData {
// Seed category icons (if categories exist)
const categories = ['beginner', 'intermediate', 'advanced', 'pro', 'endurance', 'sprint'];
for (const category of categories) {
const iconUrl = `https://api.gridpilot.io/media/category/${category}/icon.png`;
const iconUrl = `${baseUrl}/api/media/categories/${category}/icon`;
const mediaRepo = this.seedDeps.mediaRepository as any;
if (mediaRepo.setCategoryIcon) {
mediaRepo.setCategoryIcon(category, iconUrl);
@@ -526,8 +531,8 @@ export class SeedRacingData {
// Seed sponsor logos
for (const sponsor of seed.sponsors || []) {
const logoUrl = `https://api.gridpilot.io/media/sponsor/${sponsor.id}/logo.png`;
const logoUrl = `${baseUrl}/api/media/sponsors/${sponsor.id}/logo`;
const mediaRepo = this.seedDeps.mediaRepository as any;
if (mediaRepo.setSponsorLogo) {
mediaRepo.setSponsorLogo(sponsor.id, logoUrl);
@@ -537,6 +542,48 @@ export class SeedRacingData {
this.logger.info(`[Bootstrap] Seeded media assets for ${seed.drivers.length} drivers, ${seed.teams.length} teams`);
}
/**
* Get deterministic avatar URL for a driver based on their ID
* Uses static files from the website public directory
*/
private getDriverAvatarUrl(driverId: string): string {
// Deterministic selection based on driver ID
const numericSuffixMatch = driverId.match(/(\d+)$/);
let useFemale = false;
let useNeutral = false;
if (numericSuffixMatch && numericSuffixMatch[1]) {
const numericSuffix = parseInt(numericSuffixMatch[1], 10);
// 40% female, 40% male, 20% neutral
if (numericSuffix % 5 === 0) {
useNeutral = true;
} else if (numericSuffix % 2 === 0) {
useFemale = true;
}
} else {
// Fallback hash
let hash = 0;
for (let i = 0; i < driverId.length; i++) {
hash = (hash * 31 + driverId.charCodeAt(i)) | 0;
}
const hashValue = Math.abs(hash);
if (hashValue % 5 === 0) {
useNeutral = true;
} else if (hashValue % 2 === 0) {
useFemale = true;
}
}
// Return static file paths that Next.js can serve
if (useNeutral) {
return '/images/avatars/neutral-default-avatar.jpeg';
} else if (useFemale) {
return '/images/avatars/female-default-avatar.jpeg';
} else {
return '/images/avatars/male-default-avatar.jpg';
}
}
private async clearExistingRacingData(): Promise<void> {
// Get all existing drivers
const drivers = await this.seedDeps.driverRepository.findAll();