From 9a74e16f118e3cfcebcebddc08138354b364805a Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Sat, 27 Dec 2025 01:25:56 +0100 Subject: [PATCH] fix seeds --- adapters/bootstrap/EnsureInitialData.ts | 30 +-- apps/api/src/app.module.ts | 2 - .../src/domain/bootstrap/BootstrapModule.ts | 82 +------- .../domain/bootstrap/BootstrapProviders.ts | 53 ++++- .../bootstrap/BootstrapSeed.http.test.ts | 52 +++++ .../src/domain/dashboard/DashboardModule.ts | 3 + .../domain/dashboard/DashboardProviders.ts | 77 -------- apps/api/src/domain/driver/DriverModule.ts | 3 + apps/api/src/domain/driver/DriverProviders.ts | 33 +--- apps/api/src/domain/league/LeagueModule.ts | 2 + apps/api/src/domain/league/LeagueProviders.ts | 67 +------ .../persistence/InMemoryPersistenceModule.ts | 138 ++----------- .../api/src/domain/protests/ProtestsModule.ts | 2 + .../src/domain/protests/ProtestsProviders.ts | 18 -- apps/api/src/domain/race/RaceModule.ts | 2 + apps/api/src/domain/race/RaceProviders.ts | 55 ------ apps/api/src/domain/race/RaceService.ts | 40 ++-- apps/api/src/domain/sponsor/SponsorModule.ts | 3 +- .../src/domain/sponsor/SponsorProviders.ts | 56 +----- apps/api/src/domain/team/TeamModule.ts | 2 + apps/api/src/domain/team/TeamProviders.ts | 26 +-- .../InMemoryRacingPersistenceModule.ts | 187 ++++++++++++++++++ .../InMemorySocialPersistenceModule.ts | 36 ++++ 23 files changed, 405 insertions(+), 564 deletions(-) create mode 100644 apps/api/src/domain/bootstrap/BootstrapSeed.http.test.ts create mode 100644 apps/api/src/persistence/inmemory/InMemoryRacingPersistenceModule.ts create mode 100644 apps/api/src/persistence/inmemory/InMemorySocialPersistenceModule.ts diff --git a/adapters/bootstrap/EnsureInitialData.ts b/adapters/bootstrap/EnsureInitialData.ts index cb59931c5..0f4c4d12f 100644 --- a/adapters/bootstrap/EnsureInitialData.ts +++ b/adapters/bootstrap/EnsureInitialData.ts @@ -20,21 +20,23 @@ export class EnsureInitialData { async execute(): Promise { // Ensure initial admin user exists - try { - await this.signupUseCase.execute({ - email: 'admin@gridpilot.local', - password: 'admin123', - displayName: 'Admin', - }); + const signupResult = await this.signupUseCase.execute({ + email: 'admin@gridpilot.local', + password: 'admin123', + displayName: 'Admin', + }); + + if (signupResult.isOk()) { this.logger.info('[Bootstrap] Initial admin user created'); - } catch (error) { - if (error instanceof Error && error.message === 'An account with this email already exists') { - // User already exists, nothing to do - this.logger.info('[Bootstrap] Admin user already exists'); - } else { - // Re-throw other errors - throw error; - } + } else if (signupResult.error?.code === 'EMAIL_ALREADY_EXISTS') { + this.logger.info('[Bootstrap] Admin user already exists'); + } else { + const detailsMessage = + signupResult.error && typeof signupResult.error === 'object' && 'details' in signupResult.error + ? (signupResult.error as { details?: { message?: string } }).details?.message + : undefined; + + throw new Error(detailsMessage ?? 'Failed to ensure initial admin user'); } // Ensure initial achievements exist diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts index daa651fd9..6a0e8ee2e 100644 --- a/apps/api/src/app.module.ts +++ b/apps/api/src/app.module.ts @@ -5,7 +5,6 @@ import { AuthModule } from './domain/auth/AuthModule'; import { BootstrapModule } from './domain/bootstrap/BootstrapModule'; import { DashboardModule } from './domain/dashboard/DashboardModule'; import { DatabaseModule } from './domain/database/DatabaseModule'; -import { InMemoryPersistenceModule } from './domain/persistence/InMemoryPersistenceModule'; import { DriverModule } from './domain/driver/DriverModule'; import { HelloModule } from './domain/hello/HelloModule'; import { LeagueModule } from './domain/league/LeagueModule'; @@ -31,7 +30,6 @@ const ENABLE_BOOTSTRAP = getEnableBootstrap(); imports: [ HelloModule, ...(USE_DATABASE ? [DatabaseModule] : []), - ...(!USE_DATABASE ? [InMemoryPersistenceModule] : []), LoggingModule, ...(ENABLE_BOOTSTRAP ? [BootstrapModule] : []), AnalyticsModule, diff --git a/apps/api/src/domain/bootstrap/BootstrapModule.ts b/apps/api/src/domain/bootstrap/BootstrapModule.ts index b9bd86877..f9e722e8f 100644 --- a/apps/api/src/domain/bootstrap/BootstrapModule.ts +++ b/apps/api/src/domain/bootstrap/BootstrapModule.ts @@ -1,18 +1,21 @@ import type { Logger } from '@core/shared/application'; -import { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData'; +import type { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData'; import { SeedRacingData, type RacingSeedDependencies } from '../../../../../adapters/bootstrap/SeedRacingData'; -import { Module, OnModuleInit } from '@nestjs/common'; -import { ModuleRef } from '@nestjs/core'; +import { Inject, Module, OnModuleInit } from '@nestjs/common'; import { getApiPersistence } from '../../env'; -import { BootstrapProviders } from './BootstrapProviders'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; +import { InMemorySocialPersistenceModule } from '../../persistence/inmemory/InMemorySocialPersistenceModule'; +import { BootstrapProviders, ENSURE_INITIAL_DATA_TOKEN } from './BootstrapProviders'; @Module({ + imports: [InMemoryRacingPersistenceModule, InMemorySocialPersistenceModule], providers: BootstrapProviders, }) export class BootstrapModule implements OnModuleInit { constructor( - private readonly ensureInitialData: EnsureInitialData, - private readonly moduleRef: ModuleRef, + @Inject(ENSURE_INITIAL_DATA_TOKEN) private readonly ensureInitialData: EnsureInitialData, + @Inject('Logger') private readonly logger: Logger, + @Inject('RacingSeedDependencies') private readonly seedDeps: RacingSeedDependencies, ) {} async onModuleInit() { @@ -21,14 +24,7 @@ export class BootstrapModule implements OnModuleInit { await this.ensureInitialData.execute(); if (this.shouldSeedRacingData()) { - const logger = this.tryGet('Logger'); - const seedDeps = this.tryGetSeedDeps(); - - if (!logger || !seedDeps) { - console.log('[Bootstrap] Racing seed skipped (missing providers)'); - } else { - await new SeedRacingData(logger, seedDeps).execute(); - } + await new SeedRacingData(this.logger, this.seedDeps).execute(); } console.log('[Bootstrap] Application data initialized successfully'); @@ -41,62 +37,4 @@ export class BootstrapModule implements OnModuleInit { private shouldSeedRacingData(): boolean { return getApiPersistence() === 'inmemory'; } - - private tryGet(token: string): T | undefined { - try { - return this.moduleRef.get(token, { strict: false }); - } catch { - return undefined; - } - } - - private tryGetSeedDeps(): RacingSeedDependencies | undefined { - const driverRepository = this.tryGet('IDriverRepository'); - const leagueRepository = this.tryGet('ILeagueRepository'); - const raceRepository = this.tryGet('IRaceRepository'); - const resultRepository = this.tryGet('IResultRepository'); - const standingRepository = this.tryGet('IStandingRepository'); - const leagueMembershipRepository = this.tryGet( - 'ILeagueMembershipRepository', - ); - const raceRegistrationRepository = this.tryGet( - 'IRaceRegistrationRepository', - ); - const teamRepository = this.tryGet('ITeamRepository'); - const teamMembershipRepository = this.tryGet( - 'ITeamMembershipRepository', - ); - const feedRepository = this.tryGet('IFeedRepository'); - const socialGraphRepository = this.tryGet('ISocialGraphRepository'); - - if ( - !driverRepository || - !leagueRepository || - !raceRepository || - !resultRepository || - !standingRepository || - !leagueMembershipRepository || - !raceRegistrationRepository || - !teamRepository || - !teamMembershipRepository || - !feedRepository || - !socialGraphRepository - ) { - return undefined; - } - - return { - driverRepository, - leagueRepository, - raceRepository, - resultRepository, - standingRepository, - leagueMembershipRepository, - raceRegistrationRepository, - teamRepository, - teamMembershipRepository, - feedRepository, - socialGraphRepository, - }; - } } \ No newline at end of file diff --git a/apps/api/src/domain/bootstrap/BootstrapProviders.ts b/apps/api/src/domain/bootstrap/BootstrapProviders.ts index 8eb322d14..ea667a5a0 100644 --- a/apps/api/src/domain/bootstrap/BootstrapProviders.ts +++ b/apps/api/src/domain/bootstrap/BootstrapProviders.ts @@ -1,5 +1,6 @@ import { Provider } from '@nestjs/common'; import { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData'; +import type { RacingSeedDependencies } from '../../../../../adapters/bootstrap/SeedRacingData'; import { SignupWithEmailUseCase, type SignupWithEmailResult } from '@core/identity/application/use-cases/SignupWithEmailUseCase'; import { CreateAchievementUseCase, @@ -21,6 +22,9 @@ export const IDENTITY_SESSION_PORT_TOKEN = 'IdentitySessionPort_Bootstrap'; export const SIGNUP_USE_CASE_TOKEN = 'SignupWithEmailUseCase_Bootstrap'; export const CREATE_ACHIEVEMENT_USE_CASE_TOKEN = 'CreateAchievementUseCase_Bootstrap'; +export const RACING_SEED_DEPENDENCIES_TOKEN = 'RacingSeedDependencies'; +export const ENSURE_INITIAL_DATA_TOKEN = 'EnsureInitialData_Bootstrap'; + // Adapter classes for output ports class SignupWithEmailOutputAdapter implements UseCaseOutputPort { present(result: SignupWithEmailResult): void { @@ -37,6 +41,47 @@ class CreateAchievementOutputAdapter implements UseCaseOutputPort ({ + driverRepository, + leagueRepository, + raceRepository, + resultRepository, + standingRepository, + leagueMembershipRepository, + raceRegistrationRepository, + teamRepository, + teamMembershipRepository, + feedRepository, + socialGraphRepository, + }), + inject: [ + 'IDriverRepository', + 'ILeagueRepository', + 'IRaceRepository', + 'IResultRepository', + 'IStandingRepository', + 'ILeagueMembershipRepository', + 'IRaceRegistrationRepository', + 'ITeamRepository', + 'ITeamMembershipRepository', + 'IFeedRepository', + 'ISocialGraphRepository', + ], + }, { provide: USER_REPOSITORY_TOKEN, useFactory: (logger: Logger) => new InMemoryUserRepository(logger), @@ -82,7 +127,7 @@ export const BootstrapProviders: Provider[] = [ inject: [ACHIEVEMENT_REPOSITORY_TOKEN, 'Logger'], }, { - provide: EnsureInitialData, + provide: ENSURE_INITIAL_DATA_TOKEN, useFactory: ( signupUseCase: SignupWithEmailUseCase, createAchievementUseCase: CreateAchievementUseCase, @@ -90,10 +135,6 @@ export const BootstrapProviders: Provider[] = [ ) => { return new EnsureInitialData(signupUseCase, createAchievementUseCase, logger); }, - inject: [ - SIGNUP_USE_CASE_TOKEN, - CREATE_ACHIEVEMENT_USE_CASE_TOKEN, - 'Logger', - ], + inject: [SIGNUP_USE_CASE_TOKEN, CREATE_ACHIEVEMENT_USE_CASE_TOKEN, 'Logger'], }, ]; \ No newline at end of file diff --git a/apps/api/src/domain/bootstrap/BootstrapSeed.http.test.ts b/apps/api/src/domain/bootstrap/BootstrapSeed.http.test.ts new file mode 100644 index 000000000..450b11afc --- /dev/null +++ b/apps/api/src/domain/bootstrap/BootstrapSeed.http.test.ts @@ -0,0 +1,52 @@ +import 'reflect-metadata'; + +import { Test } from '@nestjs/testing'; +import type { TestingModule } from '@nestjs/testing'; +import request from 'supertest'; +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; + +describe('Bootstrap seeding (HTTP, inmemory)', () => { + const originalEnv = { ...process.env }; + + let module: TestingModule | undefined; + let app: any; + + beforeAll(async () => { + vi.resetModules(); + + process.env.GRIDPILOT_API_PERSISTENCE = 'inmemory'; + process.env.GRIDPILOT_API_BOOTSTRAP = 'true'; + delete process.env.DATABASE_URL; + + const { AppModule } = await import('../../app.module'); + + module = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + }, 20_000); + + afterAll(async () => { + await app?.close(); + await module?.close(); + + process.env = originalEnv; + vi.restoreAllMocks(); + }); + + it('exposes seeded leagues via HTTP (regression for repo instance mismatch)', async () => { + const leaguesRes = await request(app.getHttpServer()).get('/leagues/total-leagues').expect(200); + + expect(leaguesRes.body).toBeDefined(); + expect(typeof leaguesRes.body.totalLeagues).toBe('number'); + expect(leaguesRes.body.totalLeagues).toBeGreaterThan(0); + + const racesRes = await request(app.getHttpServer()).get('/races/total-races').expect(200); + + expect(racesRes.body).toBeDefined(); + expect(typeof racesRes.body.totalRaces).toBe('number'); + expect(racesRes.body.totalRaces).toBeGreaterThan(0); + }); +}); \ No newline at end of file diff --git a/apps/api/src/domain/dashboard/DashboardModule.ts b/apps/api/src/domain/dashboard/DashboardModule.ts index 9b6ee9670..0f0500695 100644 --- a/apps/api/src/domain/dashboard/DashboardModule.ts +++ b/apps/api/src/domain/dashboard/DashboardModule.ts @@ -1,9 +1,12 @@ import { Module } from '@nestjs/common'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; +import { InMemorySocialPersistenceModule } from '../../persistence/inmemory/InMemorySocialPersistenceModule'; import { DashboardService } from './DashboardService'; import { DashboardController } from './DashboardController'; import { DashboardProviders } from './DashboardProviders'; @Module({ + imports: [InMemoryRacingPersistenceModule, InMemorySocialPersistenceModule], controllers: [DashboardController], providers: [DashboardService, ...DashboardProviders], exports: [DashboardService], diff --git a/apps/api/src/domain/dashboard/DashboardProviders.ts b/apps/api/src/domain/dashboard/DashboardProviders.ts index 569d6faca..35033686e 100644 --- a/apps/api/src/domain/dashboard/DashboardProviders.ts +++ b/apps/api/src/domain/dashboard/DashboardProviders.ts @@ -16,43 +16,9 @@ import { DashboardOverviewUseCase } from '@core/racing/application/use-cases/Das // Import concrete implementations import { ConsoleLogger } from '@adapters/logging/ConsoleLogger'; -import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository'; -import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository'; -import { InMemoryResultRepository } from '@adapters/racing/persistence/inmemory/InMemoryResultRepository'; -import { InMemoryLeagueRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; -import { InMemoryStandingRepository } from '@adapters/racing/persistence/inmemory/InMemoryStandingRepository'; -import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; -import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository'; import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter'; import { DashboardOverviewPresenter } from './presenters/DashboardOverviewPresenter'; -// Simple mock implementations for missing adapters -class MockFeedRepository implements IFeedRepository { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async getFeedForDriver(_driverId: string, _limit?: number) { - return []; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async getGlobalFeed(_limit?: number) { - return []; - } -} - -class MockSocialGraphRepository implements ISocialGraphRepository { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async getFriends(_driverId: string) { - return []; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async getFriendIds(_driverId: string) { - return []; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async getSuggestedFriends(_driverId: string, _limit?: number) { - return []; - } -} - // Define injection tokens export const LOGGER_TOKEN = 'Logger'; export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository'; @@ -74,49 +40,6 @@ export const DashboardProviders: Provider[] = [ provide: LOGGER_TOKEN, useClass: ConsoleLogger, }, - { - provide: DRIVER_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryDriverRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: RACE_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryRaceRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: RESULT_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryResultRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: STANDING_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryStandingRepository(logger, {}), - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueMembershipRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: RACE_REGISTRATION_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryRaceRegistrationRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: FEED_REPOSITORY_TOKEN, - useFactory: () => new MockFeedRepository(), - }, - { - provide: SOCIAL_GRAPH_REPOSITORY_TOKEN, - useFactory: () => new MockSocialGraphRepository(), - }, { provide: IMAGE_SERVICE_TOKEN, useFactory: (logger: Logger) => new InMemoryImageServiceAdapter(logger), diff --git a/apps/api/src/domain/driver/DriverModule.ts b/apps/api/src/domain/driver/DriverModule.ts index 71dd128c7..b26c49b5b 100644 --- a/apps/api/src/domain/driver/DriverModule.ts +++ b/apps/api/src/domain/driver/DriverModule.ts @@ -1,9 +1,12 @@ import { Module } from '@nestjs/common'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; +import { InMemorySocialPersistenceModule } from '../../persistence/inmemory/InMemorySocialPersistenceModule'; import { DriverService } from './DriverService'; import { DriverController } from './DriverController'; import { DriverProviders } from './DriverProviders'; @Module({ + imports: [InMemoryRacingPersistenceModule, InMemorySocialPersistenceModule], controllers: [DriverController], providers: [DriverService, ...DriverProviders], exports: [DriverService], diff --git a/apps/api/src/domain/driver/DriverProviders.ts b/apps/api/src/domain/driver/DriverProviders.ts index 0ff71549a..18bc1ba4a 100644 --- a/apps/api/src/domain/driver/DriverProviders.ts +++ b/apps/api/src/domain/driver/DriverProviders.ts @@ -23,16 +23,11 @@ import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/U import { ConsoleLogger } from '@adapters/logging/ConsoleLogger'; import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter'; import { InMemoryNotificationPreferenceRepository } from '@adapters/notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository'; -import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository'; -import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository'; -import { InMemoryTeamMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamMembershipRepository'; -import { InMemoryTeamRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamRepository'; import { InMemoryDriverExtendedProfileProvider } from '@adapters/racing/ports/InMemoryDriverExtendedProfileProvider'; import { InMemoryDriverRatingProvider } from '@adapters/racing/ports/InMemoryDriverRatingProvider'; import { InMemoryDriverStatsService } from '@adapters/racing/services/InMemoryDriverStatsService'; import { InMemoryRankingService } from '@adapters/racing/services/InMemoryRankingService'; import { IImageServicePort } from '@core/racing/application/ports/IImageServicePort'; -import { InMemorySocialGraphRepository } from '@adapters/social/persistence/inmemory/InMemorySocialAndFeed'; // Import presenters import { CompleteOnboardingPresenter } from './presenters/CompleteOnboardingPresenter'; @@ -113,12 +108,7 @@ export const DriverProviders: Provider[] = [ useClass: ConsoleLogger, }, - // Repositories - { - provide: DRIVER_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryDriverRepository(logger), - inject: [LOGGER_TOKEN], - }, + // Repositories (racing + social repos are provided by imported persistence modules) { provide: RANKING_SERVICE_TOKEN, useFactory: (logger: Logger) => new InMemoryRankingService(logger), @@ -144,32 +134,11 @@ export const DriverProviders: Provider[] = [ useFactory: (logger: Logger) => new InMemoryImageServiceAdapter(logger), inject: [LOGGER_TOKEN], }, - { - provide: RACE_REGISTRATION_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryRaceRegistrationRepository(logger), - inject: [LOGGER_TOKEN], - }, { provide: NOTIFICATION_PREFERENCE_REPOSITORY_TOKEN, useFactory: (logger: Logger) => new InMemoryNotificationPreferenceRepository(logger), inject: [LOGGER_TOKEN], }, - { - provide: TEAM_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryTeamRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: TEAM_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryTeamMembershipRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: SOCIAL_GRAPH_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => - new InMemorySocialGraphRepository(logger, { drivers: [], friendships: [], feedEvents: [] }), - inject: [LOGGER_TOKEN], - }, // Use cases { diff --git a/apps/api/src/domain/league/LeagueModule.ts b/apps/api/src/domain/league/LeagueModule.ts index 7c9520e8c..90b5a5965 100644 --- a/apps/api/src/domain/league/LeagueModule.ts +++ b/apps/api/src/domain/league/LeagueModule.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; import { LeagueService } from './LeagueService'; import { LeagueController } from './LeagueController'; import { LeagueProviders } from './LeagueProviders'; @Module({ + imports: [InMemoryRacingPersistenceModule], controllers: [LeagueController], providers: LeagueProviders, exports: [LeagueService], diff --git a/apps/api/src/domain/league/LeagueProviders.ts b/apps/api/src/domain/league/LeagueProviders.ts index dd899d056..0e216cd4d 100644 --- a/apps/api/src/domain/league/LeagueProviders.ts +++ b/apps/api/src/domain/league/LeagueProviders.ts @@ -16,21 +16,10 @@ import type { Logger } from '@core/shared/application/Logger'; import type { ILeagueWalletRepository } from "@core/racing/domain/repositories/ILeagueWalletRepository"; import type { ITransactionRepository } from "@core/racing/domain/repositories/ITransactionRepository"; import { listLeagueScoringPresets } from '@adapters/bootstrap/LeagueScoringPresets'; -import { getPointsSystems } from '@adapters/bootstrap/PointsSystems'; import { ConsoleLogger } from '@adapters/logging/ConsoleLogger'; -import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository'; import { InMemoryGameRepository } from '@adapters/racing/persistence/inmemory/InMemoryGameRepository'; -import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; -import { InMemoryLeagueRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; import { InMemoryLeagueScoringConfigRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueScoringConfigRepository'; import { InMemoryLeagueStandingsRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueStandingsRepository'; -import { InMemoryLeagueWalletRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueWalletRepository'; -import { InMemoryProtestRepository } from '@adapters/racing/persistence/inmemory/InMemoryProtestRepository'; -import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository'; -import { InMemorySeasonRepository } from '@adapters/racing/persistence/inmemory/InMemorySeasonRepository'; -import { InMemorySeasonSponsorshipRepository } from '@adapters/racing/persistence/inmemory/InMemorySeasonSponsorshipRepository'; -import { InMemoryStandingRepository } from '@adapters/racing/persistence/inmemory/InMemoryStandingRepository'; -import { InMemoryTransactionRepository } from '@adapters/racing/persistence/inmemory/InMemoryTransactionRepository'; // Import use cases import { ApproveLeagueJoinRequestUseCase } from '@core/racing/application/use-cases/ApproveLeagueJoinRequestUseCase'; @@ -149,37 +138,12 @@ export const GET_LEAGUE_WALLET_OUTPUT_PORT_TOKEN = 'GetLeagueWalletOutputPort_TO export const WITHDRAW_FROM_LEAGUE_WALLET_OUTPUT_PORT_TOKEN = 'WithdrawFromLeagueWalletOutputPort_TOKEN'; export const LeagueProviders: Provider[] = [ - LeagueService, // Provide the service itself - { - provide: LEAGUE_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueRepository(logger), // Factory for InMemoryLeagueRepository - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueMembershipRepository(logger), // Factory for InMemoryLeagueMembershipRepository - inject: [LOGGER_TOKEN], - }, + LeagueService, { provide: LEAGUE_STANDINGS_REPOSITORY_TOKEN, useFactory: (logger: Logger) => new InMemoryLeagueStandingsRepository(logger), // Factory for InMemoryLeagueStandingsRepository inject: [LOGGER_TOKEN], }, - { - provide: STANDING_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryStandingRepository(logger, getPointsSystems()), // Factory for InMemoryStandingRepository - inject: [LOGGER_TOKEN], - }, - { - provide: SEASON_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemorySeasonRepository(logger), // Factory for InMemorySeasonRepository - inject: [LOGGER_TOKEN], - }, - { - provide: 'ISeasonSponsorshipRepository', - useFactory: (logger: Logger) => new InMemorySeasonSponsorshipRepository(logger), - inject: [LOGGER_TOKEN], - }, { provide: LEAGUE_SCORING_CONFIG_REPOSITORY_TOKEN, useFactory: (logger: Logger) => new InMemoryLeagueScoringConfigRepository(logger), // Factory for InMemoryLeagueScoringConfigRepository @@ -190,31 +154,6 @@ export const LeagueProviders: Provider[] = [ useFactory: (logger: Logger) => new InMemoryGameRepository(logger), inject: [LOGGER_TOKEN], }, - { - provide: PROTEST_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryProtestRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: RACE_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryRaceRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: DRIVER_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryDriverRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_WALLET_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueWalletRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: TRANSACTION_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryTransactionRepository(logger), - inject: [LOGGER_TOKEN], - }, { provide: LOGGER_TOKEN, useClass: ConsoleLogger, @@ -376,7 +315,9 @@ export const LeagueProviders: Provider[] = [ }, { provide: GET_TOTAL_LEAGUES_USE_CASE, - useClass: GetTotalLeaguesUseCase, + useFactory: (leagueRepo: ILeagueRepository, output: TotalLeaguesPresenter) => + new GetTotalLeaguesUseCase(leagueRepo, output), + inject: [LEAGUE_REPOSITORY_TOKEN, TOTAL_LEAGUES_OUTPUT_PORT_TOKEN], }, { provide: GET_LEAGUE_JOIN_REQUESTS_USE_CASE, diff --git a/apps/api/src/domain/persistence/InMemoryPersistenceModule.ts b/apps/api/src/domain/persistence/InMemoryPersistenceModule.ts index c8fee2563..f193a923a 100644 --- a/apps/api/src/domain/persistence/InMemoryPersistenceModule.ts +++ b/apps/api/src/domain/persistence/InMemoryPersistenceModule.ts @@ -1,129 +1,19 @@ -import { Global, Module } from '@nestjs/common'; +import { Module } from '@nestjs/common'; -import type { Logger } from '@core/shared/application/Logger'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; +import { InMemorySocialPersistenceModule } from '../../persistence/inmemory/InMemorySocialPersistenceModule'; -import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository'; -import type { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository'; -import type { IRaceRepository } from '@core/racing/domain/repositories/IRaceRepository'; -import type { IResultRepository } from '@core/racing/domain/repositories/IResultRepository'; -import type { IStandingRepository } from '@core/racing/domain/repositories/IStandingRepository'; -import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository'; -import type { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository'; -import type { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository'; -import type { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository'; - -import type { IFeedRepository } from '@core/social/domain/repositories/IFeedRepository'; -import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository'; - -import { getPointsSystems } from '@adapters/bootstrap/PointsSystems'; - -import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository'; -import { InMemoryLeagueRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; -import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository'; -import { InMemoryResultRepository } from '@adapters/racing/persistence/inmemory/InMemoryResultRepository'; -import { InMemoryStandingRepository } from '@adapters/racing/persistence/inmemory/InMemoryStandingRepository'; -import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; -import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository'; -import { InMemoryTeamRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamRepository'; -import { InMemoryTeamMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamMembershipRepository'; - -import { - InMemoryFeedRepository, - InMemorySocialGraphRepository, -} from '@adapters/social/persistence/inmemory/InMemorySocialAndFeed'; - -export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository'; -export const LEAGUE_REPOSITORY_TOKEN = 'ILeagueRepository'; -export const RACE_REPOSITORY_TOKEN = 'IRaceRepository'; -export const RESULT_REPOSITORY_TOKEN = 'IResultRepository'; -export const STANDING_REPOSITORY_TOKEN = 'IStandingRepository'; -export const LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN = 'ILeagueMembershipRepository'; -export const RACE_REGISTRATION_REPOSITORY_TOKEN = 'IRaceRegistrationRepository'; -export const TEAM_REPOSITORY_TOKEN = 'ITeamRepository'; -export const TEAM_MEMBERSHIP_REPOSITORY_TOKEN = 'ITeamMembershipRepository'; - -export const FEED_REPOSITORY_TOKEN = 'IFeedRepository'; -export const SOCIAL_GRAPH_REPOSITORY_TOKEN = 'ISocialGraphRepository'; - -@Global() +/** + * @deprecated Legacy compatibility module. + * + * The real in-memory persistence wiring lives in bounded, non-global modules: + * - `InMemoryRacingPersistenceModule` + * - `InMemorySocialPersistenceModule` + * + * This module intentionally does not define providers itself (to avoid competing instances). + */ @Module({ - providers: [ - { - provide: DRIVER_REPOSITORY_TOKEN, - useFactory: (logger: Logger): IDriverRepository => new InMemoryDriverRepository(logger), - inject: ['Logger'], - }, - { - provide: LEAGUE_REPOSITORY_TOKEN, - useFactory: (logger: Logger): ILeagueRepository => new InMemoryLeagueRepository(logger), - inject: ['Logger'], - }, - { - provide: RACE_REPOSITORY_TOKEN, - useFactory: (logger: Logger): IRaceRepository => new InMemoryRaceRepository(logger), - inject: ['Logger'], - }, - { - provide: RESULT_REPOSITORY_TOKEN, - useFactory: (logger: Logger, raceRepo: IRaceRepository): IResultRepository => - new InMemoryResultRepository(logger, raceRepo), - inject: ['Logger', RACE_REPOSITORY_TOKEN], - }, - { - provide: STANDING_REPOSITORY_TOKEN, - useFactory: ( - logger: Logger, - resultRepo: IResultRepository, - raceRepo: IRaceRepository, - leagueRepo: ILeagueRepository, - ): IStandingRepository => new InMemoryStandingRepository(logger, getPointsSystems(), resultRepo, raceRepo, leagueRepo), - inject: ['Logger', RESULT_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_REPOSITORY_TOKEN], - }, - { - provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger): ILeagueMembershipRepository => new InMemoryLeagueMembershipRepository(logger), - inject: ['Logger'], - }, - { - provide: RACE_REGISTRATION_REPOSITORY_TOKEN, - useFactory: (logger: Logger): IRaceRegistrationRepository => new InMemoryRaceRegistrationRepository(logger), - inject: ['Logger'], - }, - { - provide: TEAM_REPOSITORY_TOKEN, - useFactory: (logger: Logger): ITeamRepository => new InMemoryTeamRepository(logger), - inject: ['Logger'], - }, - { - provide: TEAM_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger): ITeamMembershipRepository => new InMemoryTeamMembershipRepository(logger), - inject: ['Logger'], - }, - { - provide: FEED_REPOSITORY_TOKEN, - useFactory: (logger: Logger): IFeedRepository => - new InMemoryFeedRepository(logger, { drivers: [], friendships: [], feedEvents: [] }), - inject: ['Logger'], - }, - { - provide: SOCIAL_GRAPH_REPOSITORY_TOKEN, - useFactory: (logger: Logger): ISocialGraphRepository => - new InMemorySocialGraphRepository(logger, { drivers: [], friendships: [], feedEvents: [] }), - inject: ['Logger'], - }, - ], - exports: [ - DRIVER_REPOSITORY_TOKEN, - LEAGUE_REPOSITORY_TOKEN, - RACE_REPOSITORY_TOKEN, - RESULT_REPOSITORY_TOKEN, - STANDING_REPOSITORY_TOKEN, - LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, - RACE_REGISTRATION_REPOSITORY_TOKEN, - TEAM_REPOSITORY_TOKEN, - TEAM_MEMBERSHIP_REPOSITORY_TOKEN, - FEED_REPOSITORY_TOKEN, - SOCIAL_GRAPH_REPOSITORY_TOKEN, - ], + imports: [InMemoryRacingPersistenceModule, InMemorySocialPersistenceModule], + exports: [InMemoryRacingPersistenceModule, InMemorySocialPersistenceModule], }) export class InMemoryPersistenceModule {} \ No newline at end of file diff --git a/apps/api/src/domain/protests/ProtestsModule.ts b/apps/api/src/domain/protests/ProtestsModule.ts index 257c8d0f9..401f18d71 100644 --- a/apps/api/src/domain/protests/ProtestsModule.ts +++ b/apps/api/src/domain/protests/ProtestsModule.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; import { ProtestsController } from './ProtestsController'; import { ProtestsService } from './ProtestsService'; import { ProtestsProviders } from './ProtestsProviders'; @Module({ + imports: [InMemoryRacingPersistenceModule], providers: [ProtestsService, ...ProtestsProviders], controllers: [ProtestsController], }) diff --git a/apps/api/src/domain/protests/ProtestsProviders.ts b/apps/api/src/domain/protests/ProtestsProviders.ts index 6b0f239fc..64d91871a 100644 --- a/apps/api/src/domain/protests/ProtestsProviders.ts +++ b/apps/api/src/domain/protests/ProtestsProviders.ts @@ -7,9 +7,6 @@ import type { IRaceRepository } from '@core/racing/domain/repositories/IRaceRepo import type { Logger } from '@core/shared/application/Logger'; // Import concrete in-memory implementations -import { InMemoryProtestRepository } from '@adapters/racing/persistence/inmemory/InMemoryProtestRepository'; -import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository'; -import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; import { ConsoleLogger } from '@adapters/logging/ConsoleLogger'; // Import use cases @@ -26,21 +23,6 @@ export const LOGGER_TOKEN = 'Logger'; export const REVIEW_PROTEST_PRESENTER_TOKEN = 'ReviewProtestPresenter'; export const ProtestsProviders: Provider[] = [ - { - provide: PROTEST_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryProtestRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: RACE_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryRaceRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueMembershipRepository(logger), - inject: [LOGGER_TOKEN], - }, { provide: LOGGER_TOKEN, useClass: ConsoleLogger, diff --git a/apps/api/src/domain/race/RaceModule.ts b/apps/api/src/domain/race/RaceModule.ts index fc8e3f841..e05a88cfc 100644 --- a/apps/api/src/domain/race/RaceModule.ts +++ b/apps/api/src/domain/race/RaceModule.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; import { RaceService } from './RaceService'; import { RaceController } from './RaceController'; import { RaceProviders } from './RaceProviders'; @Module({ + imports: [InMemoryRacingPersistenceModule], controllers: [RaceController], providers: [RaceService, ...RaceProviders], exports: [RaceService], diff --git a/apps/api/src/domain/race/RaceProviders.ts b/apps/api/src/domain/race/RaceProviders.ts index c2671649f..abd624a51 100644 --- a/apps/api/src/domain/race/RaceProviders.ts +++ b/apps/api/src/domain/race/RaceProviders.ts @@ -16,18 +16,8 @@ import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPo import { Result } from '@core/shared/application/Result'; // Import concrete in-memory implementations -import { getPointsSystems } from '@adapters/bootstrap/PointsSystems'; import { ConsoleLogger } from '@adapters/logging/ConsoleLogger'; import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter'; -import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository'; -import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; -import { InMemoryLeagueRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; -import { InMemoryPenaltyRepository } from '@adapters/racing/persistence/inmemory/InMemoryPenaltyRepository'; -import { InMemoryProtestRepository } from '@adapters/racing/persistence/inmemory/InMemoryProtestRepository'; -import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository'; -import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository'; -import { InMemoryResultRepository } from '@adapters/racing/persistence/inmemory/InMemoryResultRepository'; -import { InMemoryStandingRepository } from '@adapters/racing/persistence/inmemory/InMemoryStandingRepository'; import { InMemoryDriverRatingProvider } from '@adapters/racing/ports/InMemoryDriverRatingProvider'; // Import use cases @@ -295,51 +285,6 @@ class ReviewProtestOutputAdapter implements UseCaseOutputPort new InMemoryRaceRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: DRIVER_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryDriverRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: RACE_REGISTRATION_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryRaceRegistrationRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: RESULT_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryResultRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueMembershipRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: PENALTY_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryPenaltyRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: PROTEST_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryProtestRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: STANDING_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryStandingRepository(logger, getPointsSystems()), - inject: [LOGGER_TOKEN], - }, { provide: DRIVER_RATING_PROVIDER_TOKEN, useFactory: (logger: Logger) => new InMemoryDriverRatingProvider(logger), diff --git a/apps/api/src/domain/race/RaceService.ts b/apps/api/src/domain/race/RaceService.ts index 8232fdc0d..46e848b55 100644 --- a/apps/api/src/domain/race/RaceService.ts +++ b/apps/api/src/domain/race/RaceService.ts @@ -79,26 +79,26 @@ import { penaltyTypeRequiresValue } from '@core/racing/domain/entities/penalty/P @Injectable() export class RaceService { constructor( - private readonly getAllRacesUseCase: GetAllRacesUseCase, - private readonly getTotalRacesUseCase: GetTotalRacesUseCase, - private readonly importRaceResultsApiUseCase: ImportRaceResultsApiUseCase, - private readonly getRaceDetailUseCase: GetRaceDetailUseCase, - private readonly getRacesPageDataUseCase: GetRacesPageDataUseCase, - private readonly getAllRacesPageDataUseCase: GetAllRacesPageDataUseCase, - private readonly getRaceResultsDetailUseCase: GetRaceResultsDetailUseCase, - private readonly getRaceWithSOFUseCase: GetRaceWithSOFUseCase, - private readonly getRaceProtestsUseCase: GetRaceProtestsUseCase, - private readonly getRacePenaltiesUseCase: GetRacePenaltiesUseCase, - private readonly registerForRaceUseCase: RegisterForRaceUseCase, - private readonly withdrawFromRaceUseCase: WithdrawFromRaceUseCase, - private readonly cancelRaceUseCase: CancelRaceUseCase, - private readonly completeRaceUseCase: CompleteRaceUseCase, - private readonly fileProtestUseCase: FileProtestUseCase, - private readonly quickPenaltyUseCase: QuickPenaltyUseCase, - private readonly applyPenaltyUseCase: ApplyPenaltyUseCase, - private readonly requestProtestDefenseUseCase: RequestProtestDefenseUseCase, - private readonly reviewProtestUseCase: ReviewProtestUseCase, - private readonly reopenRaceUseCase: ReopenRaceUseCase, + @Inject(GetAllRacesUseCase) private readonly getAllRacesUseCase: GetAllRacesUseCase, + @Inject(GetTotalRacesUseCase) private readonly getTotalRacesUseCase: GetTotalRacesUseCase, + @Inject(ImportRaceResultsApiUseCase) private readonly importRaceResultsApiUseCase: ImportRaceResultsApiUseCase, + @Inject(GetRaceDetailUseCase) private readonly getRaceDetailUseCase: GetRaceDetailUseCase, + @Inject(GetRacesPageDataUseCase) private readonly getRacesPageDataUseCase: GetRacesPageDataUseCase, + @Inject(GetAllRacesPageDataUseCase) private readonly getAllRacesPageDataUseCase: GetAllRacesPageDataUseCase, + @Inject(GetRaceResultsDetailUseCase) private readonly getRaceResultsDetailUseCase: GetRaceResultsDetailUseCase, + @Inject(GetRaceWithSOFUseCase) private readonly getRaceWithSOFUseCase: GetRaceWithSOFUseCase, + @Inject(GetRaceProtestsUseCase) private readonly getRaceProtestsUseCase: GetRaceProtestsUseCase, + @Inject(GetRacePenaltiesUseCase) private readonly getRacePenaltiesUseCase: GetRacePenaltiesUseCase, + @Inject(RegisterForRaceUseCase) private readonly registerForRaceUseCase: RegisterForRaceUseCase, + @Inject(WithdrawFromRaceUseCase) private readonly withdrawFromRaceUseCase: WithdrawFromRaceUseCase, + @Inject(CancelRaceUseCase) private readonly cancelRaceUseCase: CancelRaceUseCase, + @Inject(CompleteRaceUseCase) private readonly completeRaceUseCase: CompleteRaceUseCase, + @Inject(FileProtestUseCase) private readonly fileProtestUseCase: FileProtestUseCase, + @Inject(QuickPenaltyUseCase) private readonly quickPenaltyUseCase: QuickPenaltyUseCase, + @Inject(ApplyPenaltyUseCase) private readonly applyPenaltyUseCase: ApplyPenaltyUseCase, + @Inject(RequestProtestDefenseUseCase) private readonly requestProtestDefenseUseCase: RequestProtestDefenseUseCase, + @Inject(ReviewProtestUseCase) private readonly reviewProtestUseCase: ReviewProtestUseCase, + @Inject(ReopenRaceUseCase) private readonly reopenRaceUseCase: ReopenRaceUseCase, @Inject(LOGGER_TOKEN) private readonly logger: Logger, // Injected presenters @Inject(GET_ALL_RACES_PRESENTER_TOKEN) private readonly getAllRacesPresenter: GetAllRacesPresenter, diff --git a/apps/api/src/domain/sponsor/SponsorModule.ts b/apps/api/src/domain/sponsor/SponsorModule.ts index aed8eb43e..9e27f7218 100644 --- a/apps/api/src/domain/sponsor/SponsorModule.ts +++ b/apps/api/src/domain/sponsor/SponsorModule.ts @@ -1,4 +1,5 @@ import { Module } from '@nestjs/common'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; import { AuthModule } from '../auth/AuthModule'; import { PolicyModule } from '../policy/PolicyModule'; import { SponsorService } from './SponsorService'; @@ -6,7 +7,7 @@ import { SponsorController } from './SponsorController'; import { SponsorProviders } from './SponsorProviders'; @Module({ - imports: [AuthModule, PolicyModule], + imports: [InMemoryRacingPersistenceModule, AuthModule, PolicyModule], controllers: [SponsorController], providers: SponsorProviders, exports: [SponsorService], diff --git a/apps/api/src/domain/sponsor/SponsorProviders.ts b/apps/api/src/domain/sponsor/SponsorProviders.ts index caee31451..fc7fcfb4b 100644 --- a/apps/api/src/domain/sponsor/SponsorProviders.ts +++ b/apps/api/src/domain/sponsor/SponsorProviders.ts @@ -34,15 +34,6 @@ import { RejectSponsorshipRequestUseCase } from '@core/racing/application/use-ca import { ConsoleLogger } from '@adapters/logging/ConsoleLogger'; import { InMemoryPaymentRepository } from '@adapters/payments/persistence/inmemory/InMemoryPaymentRepository'; import { InMemoryWalletRepository } from '@adapters/payments/persistence/inmemory/InMemoryWalletRepository'; -import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; -import { InMemoryLeagueRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; -import { InMemoryLeagueWalletRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueWalletRepository'; -import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository'; -import { InMemorySeasonRepository } from '@adapters/racing/persistence/inmemory/InMemorySeasonRepository'; -import { InMemorySeasonSponsorshipRepository } from '@adapters/racing/persistence/inmemory/InMemorySeasonSponsorshipRepository'; -import { InMemorySponsorRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorRepository'; -import { InMemorySponsorshipPricingRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorshipPricingRepository'; -import { InMemorySponsorshipRequestRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorshipRequestRepository'; // Import presenters import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter'; @@ -111,47 +102,7 @@ export const GET_SPONSOR_BILLING_OUTPUT_PORT_TOKEN = 'GetSponsorBillingOutputPor export const SponsorProviders: Provider[] = [ SponsorService, - // Repositories - { - provide: SPONSOR_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemorySponsorRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: SEASON_SPONSORSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemorySeasonSponsorshipRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: SEASON_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemorySeasonRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueMembershipRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: RACE_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryRaceRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: SPONSORSHIP_PRICING_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemorySponsorshipPricingRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemorySponsorshipRequestRepository(logger), - inject: [LOGGER_TOKEN], - }, + // Repositories (payments repos are local to this module; racing repos come from InMemoryRacingPersistenceModule) { provide: PAYMENT_REPOSITORY_TOKEN, useFactory: (logger: Logger) => new InMemoryPaymentRepository(logger), @@ -162,11 +113,6 @@ export const SponsorProviders: Provider[] = [ useFactory: (logger: Logger) => new InMemoryWalletRepository(logger), inject: [LOGGER_TOKEN], }, - { - provide: LEAGUE_WALLET_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryLeagueWalletRepository(logger), - inject: [LOGGER_TOKEN], - }, { provide: NOTIFICATION_SERVICE_TOKEN, useFactory: (logger: Logger): NotificationService => ({ diff --git a/apps/api/src/domain/team/TeamModule.ts b/apps/api/src/domain/team/TeamModule.ts index d82943e3d..2cff98eee 100644 --- a/apps/api/src/domain/team/TeamModule.ts +++ b/apps/api/src/domain/team/TeamModule.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; +import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule'; import { TeamService } from './TeamService'; import { TeamController } from './TeamController'; import { TeamProviders } from './TeamProviders'; @Module({ + imports: [InMemoryRacingPersistenceModule], controllers: [TeamController], providers: [TeamService, ...TeamProviders], exports: [TeamService], diff --git a/apps/api/src/domain/team/TeamProviders.ts b/apps/api/src/domain/team/TeamProviders.ts index 12741a985..130f94582 100644 --- a/apps/api/src/domain/team/TeamProviders.ts +++ b/apps/api/src/domain/team/TeamProviders.ts @@ -1,12 +1,6 @@ import { Provider } from '@nestjs/common'; -import { - TEAM_REPOSITORY_TOKEN, - TEAM_MEMBERSHIP_REPOSITORY_TOKEN, - DRIVER_REPOSITORY_TOKEN, - IMAGE_SERVICE_TOKEN, - LOGGER_TOKEN, -} from './TeamTokens'; +import { IMAGE_SERVICE_TOKEN, LOGGER_TOKEN } from './TeamTokens'; export { TEAM_REPOSITORY_TOKEN, @@ -20,30 +14,12 @@ export { import type { Logger } from '@core/shared/application/Logger'; // Import concrete in-memory implementations -import { InMemoryTeamRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamRepository'; -import { InMemoryTeamMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamMembershipRepository'; -import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository'; import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter'; import { ConsoleLogger } from '@adapters/logging/ConsoleLogger'; // Use cases are imported and used directly in the service export const TeamProviders: Provider[] = [ - { - provide: TEAM_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryTeamRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: TEAM_MEMBERSHIP_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryTeamMembershipRepository(logger), - inject: [LOGGER_TOKEN], - }, - { - provide: DRIVER_REPOSITORY_TOKEN, - useFactory: (logger: Logger) => new InMemoryDriverRepository(logger), - inject: [LOGGER_TOKEN], - }, { provide: IMAGE_SERVICE_TOKEN, useFactory: (logger: Logger) => new InMemoryImageServiceAdapter(logger), diff --git a/apps/api/src/persistence/inmemory/InMemoryRacingPersistenceModule.ts b/apps/api/src/persistence/inmemory/InMemoryRacingPersistenceModule.ts new file mode 100644 index 000000000..0ae3e6c89 --- /dev/null +++ b/apps/api/src/persistence/inmemory/InMemoryRacingPersistenceModule.ts @@ -0,0 +1,187 @@ +import { Module } from '@nestjs/common'; + +import { LoggingModule } from '../../domain/logging/LoggingModule'; + +import type { Logger } from '@core/shared/application/Logger'; + +import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository'; +import type { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository'; +import type { IRaceRepository } from '@core/racing/domain/repositories/IRaceRepository'; +import type { IResultRepository } from '@core/racing/domain/repositories/IResultRepository'; +import type { IStandingRepository } from '@core/racing/domain/repositories/IStandingRepository'; +import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository'; +import type { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository'; +import type { IPenaltyRepository } from '@core/racing/domain/repositories/IPenaltyRepository'; +import type { IProtestRepository } from '@core/racing/domain/repositories/IProtestRepository'; +import type { ISeasonRepository } from '@core/racing/domain/repositories/ISeasonRepository'; +import type { ISeasonSponsorshipRepository } from '@core/racing/domain/repositories/ISeasonSponsorshipRepository'; +import type { ILeagueWalletRepository } from '@core/racing/domain/repositories/ILeagueWalletRepository'; +import type { ITransactionRepository } from '@core/racing/domain/repositories/ITransactionRepository'; +import type { ISponsorRepository } from '@core/racing/domain/repositories/ISponsorRepository'; +import type { ISponsorshipPricingRepository } from '@core/racing/domain/repositories/ISponsorshipPricingRepository'; +import type { ISponsorshipRequestRepository } from '@core/racing/domain/repositories/ISponsorshipRequestRepository'; +import type { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository'; +import type { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository'; + +import { getPointsSystems } from '@adapters/bootstrap/PointsSystems'; + +import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository'; +import { InMemoryLeagueRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; +import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository'; +import { InMemoryResultRepository } from '@adapters/racing/persistence/inmemory/InMemoryResultRepository'; +import { InMemoryStandingRepository } from '@adapters/racing/persistence/inmemory/InMemoryStandingRepository'; +import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; +import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository'; +import { InMemoryTeamRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamRepository'; +import { InMemoryTeamMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamMembershipRepository'; +import { InMemoryPenaltyRepository } from '@adapters/racing/persistence/inmemory/InMemoryPenaltyRepository'; +import { InMemoryProtestRepository } from '@adapters/racing/persistence/inmemory/InMemoryProtestRepository'; +import { InMemorySeasonRepository } from '@adapters/racing/persistence/inmemory/InMemorySeasonRepository'; +import { InMemorySeasonSponsorshipRepository } from '@adapters/racing/persistence/inmemory/InMemorySeasonSponsorshipRepository'; +import { InMemoryLeagueWalletRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueWalletRepository'; +import { InMemoryTransactionRepository } from '@adapters/racing/persistence/inmemory/InMemoryTransactionRepository'; +import { InMemorySponsorRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorRepository'; +import { InMemorySponsorshipPricingRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorshipPricingRepository'; +import { InMemorySponsorshipRequestRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorshipRequestRepository'; + +export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository'; +export const LEAGUE_REPOSITORY_TOKEN = 'ILeagueRepository'; +export const RACE_REPOSITORY_TOKEN = 'IRaceRepository'; +export const RESULT_REPOSITORY_TOKEN = 'IResultRepository'; +export const STANDING_REPOSITORY_TOKEN = 'IStandingRepository'; +export const LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN = 'ILeagueMembershipRepository'; +export const RACE_REGISTRATION_REPOSITORY_TOKEN = 'IRaceRegistrationRepository'; +export const TEAM_REPOSITORY_TOKEN = 'ITeamRepository'; +export const TEAM_MEMBERSHIP_REPOSITORY_TOKEN = 'ITeamMembershipRepository'; +export const PENALTY_REPOSITORY_TOKEN = 'IPenaltyRepository'; +export const PROTEST_REPOSITORY_TOKEN = 'IProtestRepository'; +export const SEASON_REPOSITORY_TOKEN = 'ISeasonRepository'; +export const SEASON_SPONSORSHIP_REPOSITORY_TOKEN = 'ISeasonSponsorshipRepository'; +export const LEAGUE_WALLET_REPOSITORY_TOKEN = 'ILeagueWalletRepository'; +export const TRANSACTION_REPOSITORY_TOKEN = 'ITransactionRepository'; +export const SPONSOR_REPOSITORY_TOKEN = 'ISponsorRepository'; +export const SPONSORSHIP_PRICING_REPOSITORY_TOKEN = 'ISponsorshipPricingRepository'; +export const SPONSORSHIP_REQUEST_REPOSITORY_TOKEN = 'ISponsorshipRequestRepository'; + +@Module({ + imports: [LoggingModule], + providers: [ + { + provide: DRIVER_REPOSITORY_TOKEN, + useFactory: (logger: Logger): IDriverRepository => new InMemoryDriverRepository(logger), + inject: ['Logger'], + }, + { + provide: LEAGUE_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ILeagueRepository => new InMemoryLeagueRepository(logger), + inject: ['Logger'], + }, + { + provide: RACE_REPOSITORY_TOKEN, + useFactory: (logger: Logger): IRaceRepository => new InMemoryRaceRepository(logger), + inject: ['Logger'], + }, + { + provide: RESULT_REPOSITORY_TOKEN, + useFactory: (logger: Logger, raceRepo: IRaceRepository): IResultRepository => + new InMemoryResultRepository(logger, raceRepo), + inject: ['Logger', RACE_REPOSITORY_TOKEN], + }, + { + provide: STANDING_REPOSITORY_TOKEN, + useFactory: ( + logger: Logger, + resultRepo: IResultRepository, + raceRepo: IRaceRepository, + leagueRepo: ILeagueRepository, + ): IStandingRepository => new InMemoryStandingRepository(logger, getPointsSystems(), resultRepo, raceRepo, leagueRepo), + inject: ['Logger', RESULT_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN, LEAGUE_REPOSITORY_TOKEN], + }, + { + provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ILeagueMembershipRepository => new InMemoryLeagueMembershipRepository(logger), + inject: ['Logger'], + }, + { + provide: RACE_REGISTRATION_REPOSITORY_TOKEN, + useFactory: (logger: Logger): IRaceRegistrationRepository => new InMemoryRaceRegistrationRepository(logger), + inject: ['Logger'], + }, + { + provide: TEAM_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ITeamRepository => new InMemoryTeamRepository(logger), + inject: ['Logger'], + }, + { + provide: TEAM_MEMBERSHIP_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ITeamMembershipRepository => new InMemoryTeamMembershipRepository(logger), + inject: ['Logger'], + }, + { + provide: PENALTY_REPOSITORY_TOKEN, + useFactory: (logger: Logger): IPenaltyRepository => new InMemoryPenaltyRepository(logger), + inject: ['Logger'], + }, + { + provide: PROTEST_REPOSITORY_TOKEN, + useFactory: (logger: Logger): IProtestRepository => new InMemoryProtestRepository(logger), + inject: ['Logger'], + }, + { + provide: SEASON_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ISeasonRepository => new InMemorySeasonRepository(logger), + inject: ['Logger'], + }, + { + provide: SEASON_SPONSORSHIP_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ISeasonSponsorshipRepository => new InMemorySeasonSponsorshipRepository(logger), + inject: ['Logger'], + }, + { + provide: LEAGUE_WALLET_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ILeagueWalletRepository => new InMemoryLeagueWalletRepository(logger), + inject: ['Logger'], + }, + { + provide: TRANSACTION_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ITransactionRepository => new InMemoryTransactionRepository(logger), + inject: ['Logger'], + }, + { + provide: SPONSOR_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ISponsorRepository => new InMemorySponsorRepository(logger), + inject: ['Logger'], + }, + { + provide: SPONSORSHIP_PRICING_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ISponsorshipPricingRepository => new InMemorySponsorshipPricingRepository(logger), + inject: ['Logger'], + }, + { + provide: SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ISponsorshipRequestRepository => new InMemorySponsorshipRequestRepository(logger), + inject: ['Logger'], + }, + ], + exports: [ + DRIVER_REPOSITORY_TOKEN, + LEAGUE_REPOSITORY_TOKEN, + RACE_REPOSITORY_TOKEN, + RESULT_REPOSITORY_TOKEN, + STANDING_REPOSITORY_TOKEN, + LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN, + RACE_REGISTRATION_REPOSITORY_TOKEN, + TEAM_REPOSITORY_TOKEN, + TEAM_MEMBERSHIP_REPOSITORY_TOKEN, + PENALTY_REPOSITORY_TOKEN, + PROTEST_REPOSITORY_TOKEN, + SEASON_REPOSITORY_TOKEN, + SEASON_SPONSORSHIP_REPOSITORY_TOKEN, + LEAGUE_WALLET_REPOSITORY_TOKEN, + TRANSACTION_REPOSITORY_TOKEN, + SPONSOR_REPOSITORY_TOKEN, + SPONSORSHIP_PRICING_REPOSITORY_TOKEN, + SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, + ], +}) +export class InMemoryRacingPersistenceModule {} \ No newline at end of file diff --git a/apps/api/src/persistence/inmemory/InMemorySocialPersistenceModule.ts b/apps/api/src/persistence/inmemory/InMemorySocialPersistenceModule.ts new file mode 100644 index 000000000..39056f9be --- /dev/null +++ b/apps/api/src/persistence/inmemory/InMemorySocialPersistenceModule.ts @@ -0,0 +1,36 @@ +import { Module } from '@nestjs/common'; + +import { LoggingModule } from '../../domain/logging/LoggingModule'; + +import type { Logger } from '@core/shared/application/Logger'; + +import type { IFeedRepository } from '@core/social/domain/repositories/IFeedRepository'; +import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository'; + +import { + InMemoryFeedRepository, + InMemorySocialGraphRepository, +} from '@adapters/social/persistence/inmemory/InMemorySocialAndFeed'; + +export const FEED_REPOSITORY_TOKEN = 'IFeedRepository'; +export const SOCIAL_GRAPH_REPOSITORY_TOKEN = 'ISocialGraphRepository'; + +@Module({ + imports: [LoggingModule], + providers: [ + { + provide: FEED_REPOSITORY_TOKEN, + useFactory: (logger: Logger): IFeedRepository => + new InMemoryFeedRepository(logger, { drivers: [], friendships: [], feedEvents: [] }), + inject: ['Logger'], + }, + { + provide: SOCIAL_GRAPH_REPOSITORY_TOKEN, + useFactory: (logger: Logger): ISocialGraphRepository => + new InMemorySocialGraphRepository(logger, { drivers: [], friendships: [], feedEvents: [] }), + inject: ['Logger'], + }, + ], + exports: [FEED_REPOSITORY_TOKEN, SOCIAL_GRAPH_REPOSITORY_TOKEN], +}) +export class InMemorySocialPersistenceModule {} \ No newline at end of file