From 06207bf835f65ab17cf4098dfbe13889a5f7bfaf Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Tue, 20 Jan 2026 18:48:14 +0100 Subject: [PATCH] website refactor --- adapters/bootstrap/SeedRacingData.ts | 17 ++++++- .../racing/RacingRaceFactory.test.ts | 46 +++++++++++++++++++ .../bootstrap/racing/RacingRaceFactory.ts | 4 +- docker-compose.dev.yml | 1 + 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 adapters/bootstrap/racing/RacingRaceFactory.test.ts diff --git a/adapters/bootstrap/SeedRacingData.ts b/adapters/bootstrap/SeedRacingData.ts index 36cfb9800..c2272fdca 100644 --- a/adapters/bootstrap/SeedRacingData.ts +++ b/adapters/bootstrap/SeedRacingData.ts @@ -87,6 +87,7 @@ export class SeedRacingData { async execute(): Promise { const existingDrivers = await this.seedDeps.driverRepository.findAll(); const existingTeams = await this.seedDeps.teamRepository.findAll().catch(() => []); + const existingRaces = await this.seedDeps.raceRepository.findAll().catch(() => []); const persistence = this.getApiPersistence(); // Check for force reseed via environment variable @@ -94,7 +95,7 @@ export class SeedRacingData { const forceReseed = forceReseedRaw !== undefined && forceReseedRaw !== '0' && forceReseedRaw.toLowerCase() !== 'false'; this.logger.info( - `[Bootstrap] Racing seed precheck: forceReseed=${forceReseed}, drivers=${existingDrivers.length}, teams=${existingTeams.length}, persistence=${persistence}`, + `[Bootstrap] Racing seed precheck: forceReseed=${forceReseed}, drivers=${existingDrivers.length}, teams=${existingTeams.length}, races=${existingRaces.length}, persistence=${persistence}`, ); if (existingDrivers.length > 0 && !forceReseed) { @@ -329,8 +330,20 @@ export class SeedRacingData { // Compute and store team stats from real data await this.computeAndStoreTeamStats(); + // Log race distribution for transparency + const raceStatusCounts = seed.races.reduce((acc, race) => { + const status = race.status.toString(); + acc[status] = (acc[status] || 0) + 1; + return acc; + }, {} as Record); + + const upcomingRaces = seed.races.filter((r) => r.status.toString() === 'scheduled' && r.scheduledAt > new Date()); + this.logger.info( - `[Bootstrap] Seeded racing data: drivers=${seed.drivers.length}, leagues=${seed.leagues.length}, races=${seed.races.length}`, + `[Bootstrap] Seeded racing data: drivers=${seed.drivers.length}, leagues=${seed.leagues.length}, races=${seed.races.length} (scheduled=${raceStatusCounts.scheduled || 0}, running=${raceStatusCounts.running || 0}, completed=${raceStatusCounts.completed || 0}, cancelled=${raceStatusCounts.cancelled || 0})`, + ); + this.logger.info( + `[Bootstrap] Upcoming races: ${upcomingRaces.length} scheduled in the future`, ); } diff --git a/adapters/bootstrap/racing/RacingRaceFactory.test.ts b/adapters/bootstrap/racing/RacingRaceFactory.test.ts new file mode 100644 index 000000000..55a76de10 --- /dev/null +++ b/adapters/bootstrap/racing/RacingRaceFactory.test.ts @@ -0,0 +1,46 @@ +import { RacingRaceFactory } from './RacingRaceFactory'; +import { RacingLeagueFactory } from './RacingLeagueFactory'; +import { RacingTrackFactory } from './RacingTrackFactory'; +import { RacingDriverFactory } from './RacingDriverFactory'; +import { describe, expect, it } from 'vitest'; + +describe('RacingRaceFactory', () => { + it('creates upcoming races in the future', () => { + const baseDate = new Date('2024-01-01'); + const driverFactory = new RacingDriverFactory(10, baseDate, 'inmemory'); + const drivers = driverFactory.create(); + const leagueFactory = new RacingLeagueFactory(baseDate, drivers, 'inmemory'); + const leagues = leagueFactory.create(); + const trackFactory = new RacingTrackFactory(); + const tracks = trackFactory.create(); + + const raceFactory = new RacingRaceFactory(baseDate, 'inmemory'); + const races = raceFactory.create(leagues, tracks); + + const scheduledRaces = races.filter((r) => r.status.toString() === 'scheduled'); + expect(scheduledRaces.length).toBeGreaterThan(0); + + const now = new Date(); + const upcomingRaces = scheduledRaces.filter((r) => r.scheduledAt > now); + expect(upcomingRaces.length).toBeGreaterThan(0); + }); + + it('creates races with various statuses', () => { + const baseDate = new Date('2024-01-01'); + const driverFactory = new RacingDriverFactory(10, baseDate, 'inmemory'); + const drivers = driverFactory.create(); + const leagueFactory = new RacingLeagueFactory(baseDate, drivers, 'inmemory'); + const leagues = leagueFactory.create(); + const trackFactory = new RacingTrackFactory(); + const tracks = trackFactory.create(); + + const raceFactory = new RacingRaceFactory(baseDate, 'inmemory'); + const races = raceFactory.create(leagues, tracks); + + const statuses = new Set(races.map((r) => r.status.toString())); + expect(statuses.has('scheduled')).toBe(true); + expect(statuses.has('running')).toBe(true); + expect(statuses.has('completed')).toBe(true); + expect(statuses.has('cancelled')).toBe(true); + }); +}); diff --git a/adapters/bootstrap/racing/RacingRaceFactory.ts b/adapters/bootstrap/racing/RacingRaceFactory.ts index 168de574d..74fb9a8cb 100644 --- a/adapters/bootstrap/racing/RacingRaceFactory.ts +++ b/adapters/bootstrap/racing/RacingRaceFactory.ts @@ -47,7 +47,9 @@ export class RacingRaceFactory { } else { // 40% scheduled (8 out of 20) status = 'scheduled'; - scheduledAt = this.addDays(this.baseDate, 1 + ((statusMod - 13) * 2)); + // Ensure scheduled races are always in the future by using current date as reference + const now = new Date(); + scheduledAt = this.addDays(now, 1 + ((statusMod - 13) * 2)); } const base = { diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 52c2281ae..d2a67b41e 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -39,6 +39,7 @@ services: # Using ${VAR:-} here expands to an empty string when VAR is not set in the # host shell, which *overrides* env_file and disables force reseed. - MEDIA_STORAGE_DIR=/data/media + - GRIDPILOT_API_FORCE_RESEED=${GRIDPILOT_API_FORCE_RESEED:-} ports: - "3001:3000" - "9229:9229"