website refactor

This commit is contained in:
2026-01-16 21:57:44 +01:00
parent 83a9092c50
commit 27f5a52e04
30 changed files with 166 additions and 161 deletions

View File

@@ -4,7 +4,8 @@
* In-memory implementation of IAnalyticsSnapshotRepository for development/testing.
*/
import { AnalyticsSnapshot, SnapshotPeriod } from '@core/analytics/application/repositories/PageViewRepository';
import { AnalyticsSnapshot, type SnapshotEntityType, type SnapshotPeriod } from '@core/analytics/domain/entities/AnalyticsSnapshot';
import type { AnalyticsSnapshotRepository } from '@core/analytics/domain/repositories/AnalyticsSnapshotRepository';
import { Logger } from '@core/shared/domain/Logger';
export class InMemoryAnalyticsSnapshotRepository implements AnalyticsSnapshotRepository {

View File

@@ -6,7 +6,7 @@
import type { PageViewRepository } from '@core/analytics/application/repositories/PageViewRepository';
import { PageView, type EntityType } from '@core/analytics/domain/entities/PageView';
import { Logger } from '@core/shared/domain';
import { Logger } from '@core/shared/domain/Logger';
export class InMemoryPageViewRepository implements PageViewRepository {
private pageViews: Map<string, PageView> = new Map();

View File

@@ -1,6 +1,10 @@
import { AdminUser } from '@core/admin/domain/entities/AdminUser';
import { Email } from '@core/admin/domain/value-objects/Email';
import type { AdminUserRepository } from '@core/admin/domain/repositories/AdminUserRepository';
import { User } from '@core/identity/domain/entities/User';
import type { AuthRepository } from '@core/identity/domain/repositories/AuthRepository';
import type { UserRepository } from '@core/identity/domain/repositories/UserRepository';
import type { PasswordHashingService } from '@core/identity/domain/services/PasswordHashingService';
import { EmailAddress } from '@core/identity/domain/value-objects/EmailAddress';
import { PasswordHash } from '@core/identity/domain/value-objects/PasswordHash';
import { UserId } from '@core/identity/domain/value-objects/UserId';
@@ -84,9 +88,9 @@ export class SeedDemoUsers {
constructor(
private readonly logger: Logger,
private readonly authRepository: IAuthRepository,
private readonly passwordHashingService: IPasswordHashingService,
private readonly adminUserRepository: IAdminUserRepository,
private readonly authRepository: AuthRepository,
private readonly passwordHashingService: PasswordHashingService,
private readonly adminUserRepository: AdminUserRepository,
) {}
private getApiPersistence(): 'postgres' | 'inmemory' {

View File

@@ -4,40 +4,65 @@ import { Result } from '@core/racing/domain/entities/result/Result';
import type { Season } from '@core/racing/domain/entities/season/Season';
import { Standing } from '@core/racing/domain/entities/Standing';
import { Team } from '@core/racing/domain/entities/Team';
import type { TeamStats } from '@core/racing/domain/repositories/TeamStatsRepository';
import type { DriverRepository } from '@core/racing/domain/repositories/DriverRepository';
import type { LeagueRepository } from '@core/racing/domain/repositories/LeagueRepository';
import type { SeasonRepository } from '@core/racing/domain/repositories/SeasonRepository';
import type { LeagueScoringConfigRepository } from '@core/racing/domain/repositories/LeagueScoringConfigRepository';
import type { SeasonSponsorshipRepository } from '@core/racing/domain/repositories/SeasonSponsorshipRepository';
import type { SponsorshipRequestRepository } from '@core/racing/domain/repositories/SponsorshipRequestRepository';
import type { LeagueWalletRepository } from '@core/racing/domain/repositories/LeagueWalletRepository';
import type { TransactionRepository } from '@core/racing/domain/repositories/TransactionRepository';
import type { ProtestRepository } from '@core/racing/domain/repositories/ProtestRepository';
import type { PenaltyRepository } from '@core/racing/domain/repositories/PenaltyRepository';
import type { RaceRepository } from '@core/racing/domain/repositories/RaceRepository';
import type { ResultRepository } from '@core/racing/domain/repositories/ResultRepository';
import type { StandingRepository } from '@core/racing/domain/repositories/StandingRepository';
import type { LeagueMembershipRepository } from '@core/racing/domain/repositories/LeagueMembershipRepository';
import type { RaceRegistrationRepository } from '@core/racing/domain/repositories/RaceRegistrationRepository';
import type { TeamRepository } from '@core/racing/domain/repositories/TeamRepository';
import type { TeamMembershipRepository } from '@core/racing/domain/repositories/TeamMembershipRepository';
import type { SponsorRepository } from '@core/racing/domain/repositories/SponsorRepository';
import type { FeedRepository } from '@core/social/domain/repositories/FeedRepository';
import type { SocialGraphRepository } from '@core/social/domain/repositories/SocialGraphRepository';
import type { DriverStatsRepository } from '@core/racing/domain/repositories/DriverStatsRepository';
import type { TeamStatsRepository, TeamStats } from '@core/racing/domain/repositories/TeamStatsRepository';
import type { MediaRepository } from '@core/racing/domain/repositories/MediaRepository';
import type { AuthRepository } from '@core/identity/domain/repositories/AuthRepository';
import type { PasswordHashingService } from '@core/identity/domain/services/PasswordHashingService';
import type { AdminUserRepository } from '@core/admin/domain/repositories/AdminUserRepository';
import type { Logger } from '@core/shared/domain/Logger';
import { getLeagueScoringPresetById } from './LeagueScoringPresets';
import { createRacingSeed } from './racing/RacingSeed';
import { seedId } from './racing/SeedIdHelper';
export type RacingSeedDependencies = {
driverRepository: IDriverRepository;
leagueRepository: ILeagueRepository;
seasonRepository: ISeasonRepository;
leagueScoringConfigRepository: ILeagueScoringConfigRepository;
seasonSponsorshipRepository: ISeasonSponsorshipRepository;
sponsorshipRequestRepository: ISponsorshipRequestRepository;
leagueWalletRepository: ILeagueWalletRepository;
transactionRepository: ITransactionRepository;
protestRepository: IProtestRepository;
penaltyRepository: IPenaltyRepository;
raceRepository: IRaceRepository;
resultRepository: IResultRepository;
standingRepository: IStandingRepository;
leagueMembershipRepository: ILeagueMembershipRepository;
raceRegistrationRepository: IRaceRegistrationRepository;
teamRepository: ITeamRepository;
teamMembershipRepository: ITeamMembershipRepository;
sponsorRepository: ISponsorRepository;
feedRepository: IFeedRepository;
socialGraphRepository: ISocialGraphRepository;
driverStatsRepository: IDriverStatsRepository;
teamStatsRepository: ITeamStatsRepository;
mediaRepository: IMediaRepository;
driverRepository: DriverRepository;
leagueRepository: LeagueRepository;
seasonRepository: SeasonRepository;
leagueScoringConfigRepository: LeagueScoringConfigRepository;
seasonSponsorshipRepository: SeasonSponsorshipRepository;
sponsorshipRequestRepository: SponsorshipRequestRepository;
leagueWalletRepository: LeagueWalletRepository;
transactionRepository: TransactionRepository;
protestRepository: ProtestRepository;
penaltyRepository: PenaltyRepository;
raceRepository: RaceRepository;
resultRepository: ResultRepository;
standingRepository: StandingRepository;
leagueMembershipRepository: LeagueMembershipRepository;
raceRegistrationRepository: RaceRegistrationRepository;
teamRepository: TeamRepository;
teamMembershipRepository: TeamMembershipRepository;
sponsorRepository: SponsorRepository;
feedRepository: FeedRepository;
socialGraphRepository: SocialGraphRepository;
driverStatsRepository: DriverStatsRepository;
teamStatsRepository: TeamStatsRepository;
mediaRepository: MediaRepository;
// Identity dependencies for demo user seed
authRepository: IAuthRepository;
passwordHashingService: IPasswordHashingService;
adminUserRepository: IAdminUserRepository;
authRepository: AuthRepository;
passwordHashingService: PasswordHashingService;
adminUserRepository: AdminUserRepository;
};
export class SeedRacingData {
@@ -280,7 +305,7 @@ export class SeedRacingData {
// ignore duplicates
}
const seedableFeed = this.seedDeps.feedRepository as unknown as { seed?: (input: unknown) => void };
const seedableFeed = this.seedDeps.feedRepository as unknown as { seed?: (input: any) => void };
if (typeof seedableFeed.seed === 'function') {
seedableFeed.seed({
drivers: seed.drivers,
@@ -289,7 +314,7 @@ export class SeedRacingData {
});
}
const seedableSocial = this.seedDeps.socialGraphRepository as unknown as { seed?: (input: unknown) => void };
const seedableSocial = this.seedDeps.socialGraphRepository as unknown as { seed?: (input: any) => void };
if (typeof seedableSocial.seed === 'function') {
seedableSocial.seed({
drivers: seed.drivers,
@@ -317,8 +342,8 @@ export class SeedRacingData {
this.logger.info(`[Bootstrap] Computing stats for ${drivers.length} drivers from ${standings.length} standings and ${results.length} results`);
for (const driver of drivers) {
const driverResults = results.filter(r => r.driverId.toString() === driver.id);
const driverStandings = standings.filter(s => s.driverId.toString() === driver.id);
const driverResults = results.filter((r: Result) => r.driverId.toString() === driver.id);
const driverStandings = standings.filter((s: Standing) => s.driverId.toString() === driver.id);
if (driverResults.length === 0) continue;
@@ -398,13 +423,13 @@ export class SeedRacingData {
for (const team of teams) {
// Get team members using the correct method
const teamMemberships = await this.seedDeps.teamMembershipRepository.getTeamMembers(team.id);
const teamMemberIds = teamMemberships.map(m => m.driverId.toString());
const teamMemberIds = teamMemberships.map((m: any) => m.driverId.toString());
// Get results for team members
const teamResults = results.filter(r => teamMemberIds.includes(r.driverId.toString()));
const teamResults = results.filter((r: Result) => teamMemberIds.includes(r.driverId.toString()));
// Get team drivers for name resolution
const teamDrivers = drivers.filter(d => teamMemberIds.includes(d.id));
const teamDrivers = drivers.filter((d: Driver) => teamMemberIds.includes(d.id));
const stats = this.calculateTeamStats(team, teamResults, teamDrivers);
await this.seedDeps.teamStatsRepository.saveTeamStats(team.id, stats);

View File

@@ -1,37 +0,0 @@
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Enforce adapter naming conventions',
category: 'Architecture',
recommended: true,
},
fixable: null,
schema: [],
messages: {
invalidNaming: 'Adapter classes should end with "Adapter", "Repository", "Service", "Factory" or "Entity". Found: {{name}}',
},
},
create(context) {
return {
ClassDeclaration(node) {
const filename = context.getFilename();
if (!filename.includes('adapters/')) return;
const name = node.id.name;
const isValidName = /(.+)(Adapter|Factory|Repository|Service|Entity|Mapper|Schema|Guard|Module|Controller)$/.test(name);
if (!isValidName) {
context.report({
node,
messageId: 'invalidNaming',
data: {
name,
},
});
}
},
};
},
};

View File

@@ -1,17 +1,14 @@
const noIndexFiles = require('./no-index-files');
const adapterNaming = require('./adapter-naming');
module.exports = {
rules: {
'no-index-files': noIndexFiles,
'adapter-naming': adapterNaming,
},
configs: {
recommended: {
plugins: ['gridpilot-adapters-rules'],
rules: {
'gridpilot-adapters-rules/no-index-files': 'error',
'gridpilot-adapters-rules/adapter-naming': 'error',
},
},
},

View File

@@ -5,11 +5,10 @@
*/
import { ADMIN_ACHIEVEMENTS, COMMUNITY_ACHIEVEMENTS, DRIVER_ACHIEVEMENTS, STEWARD_ACHIEVEMENTS } from "@core/identity/domain/AchievementConstants";
import { Achievement } from "@core/identity/domain/entities/Achievement";
import { Achievement, type AchievementCategory } from "@core/identity/domain/entities/Achievement";
import { UserAchievement } from "@core/identity/domain/entities/UserAchievement";
import { AchievementRepository } from "@core/identity/domain/repositories/AchievementRepository";
import { AchievementCategory } from "@core/identity/domain/types/AchievementTypes";
import { Logger } from "@core/shared/domain";
import type { Logger } from "@core/shared/domain/Logger";
export class InMemoryAchievementRepository implements AchievementRepository {
private achievements: Map<string, Achievement> = new Map();

View File

@@ -1,14 +1,14 @@
import { User } from '@core/identity/domain/entities/User';
import { AuthRepository } from '@core/identity/domain/repositories/AuthRepository';
import { StoredUser } from '@core/identity/domain/repositories/UserRepository';
import type { AuthRepository } from '@core/identity/domain/repositories/AuthRepository';
import type { UserRepository, StoredUser } from '@core/identity/domain/repositories/UserRepository';
import type { PasswordHashingService } from '@core/identity/domain/services/PasswordHashingService';
import { EmailAddress } from '@core/identity/domain/value-objects/EmailAddress';
import { Logger } from '@core/shared/domain';
import type { Logger } from '@core/shared/domain/Logger';
export class InMemoryAuthRepository implements AuthRepository {
constructor(
private readonly userRepository: IUserRepository,
private readonly passwordHashingService: IPasswordHashingService,
private readonly userRepository: UserRepository,
private readonly passwordHashingService: PasswordHashingService,
private readonly logger: Logger,
) {}

View File

@@ -1,5 +1,5 @@
import { MagicLinkRepository, PasswordResetRequest } from '@core/identity/domain/repositories/MagicLinkRepository';
import { Logger } from '@core/shared/domain';
import type { MagicLinkRepository, PasswordResetRequest } from '@core/identity/domain/repositories/MagicLinkRepository';
import type { Logger } from '@core/shared/domain/Logger';
import { Result } from '@core/shared/domain/Result';
export class InMemoryMagicLinkRepository implements MagicLinkRepository {

View File

@@ -4,8 +4,10 @@
* In-memory implementation of ISponsorAccountRepository for development/testing.
*/
import { SponsorAccount, SponsorAccountRepository, UserId } from '@core/identity';
import { Logger } from '@core/shared/domain';
import { SponsorAccount } from '@core/identity/domain/entities/SponsorAccount';
import type { SponsorAccountRepository } from '@core/identity/domain/repositories/SponsorAccountRepository';
import { UserId } from '@core/identity/domain/value-objects/UserId';
import type { Logger } from '@core/shared/domain/Logger';
export class InMemorySponsorAccountRepository implements SponsorAccountRepository {
private accounts: Map<string, SponsorAccount> = new Map();

View File

@@ -4,8 +4,9 @@
* In-memory implementation of IUserRatingRepository
*/
import { UserRating, UserRatingRepository } from '@core/identity';
import { Logger } from '@core/shared/domain';
import { UserRating } from '@core/identity/domain/value-objects/UserRating';
import type { UserRatingRepository } from '@core/identity/domain/repositories/UserRatingRepository';
import type { Logger } from '@core/shared/domain/Logger';
export class InMemoryUserRatingRepository implements UserRatingRepository {
private ratings: Map<string, UserRating> = new Map();

View File

@@ -5,7 +5,7 @@
*/
import type { StoredUser, UserRepository } from '@core/identity/domain/repositories/UserRepository';
import { Logger } from '@core/shared/domain';
import type { Logger } from '@core/shared/domain/Logger';
export class InMemoryUserRepository implements UserRepository {
private users: Map<string, StoredUser> = new Map();

View File

@@ -1,5 +1,5 @@
import { MagicLinkRepository, PasswordResetRequest } from '@core/identity/domain/repositories/MagicLinkRepository';
import { Logger } from '@core/shared/domain';
import type { MagicLinkRepository, PasswordResetRequest } from '@core/identity/domain/repositories/MagicLinkRepository';
import type { Logger } from '@core/shared/domain/Logger';
import { Result } from '@core/shared/domain/Result';
import type { DataSource } from 'typeorm';
import { PasswordResetRequestOrmEntity } from '../entities/PasswordResetRequestOrmEntity';

View File

@@ -1,4 +1,4 @@
import { ErrorReporter } from "@core/shared/domain";
import type { ErrorReporter } from "@core/shared/application/ErrorReporter";
export class ConsoleErrorReporter implements ErrorReporter {
report(error: Error, context?: unknown): void {

View File

@@ -1,4 +1,4 @@
import { Logger } from "@core/shared/domain";
import type { Logger } from "@core/shared/domain/Logger";
export class ConsoleLogger implements Logger {
private formatMessage(level: string, message: string, context?: unknown): string {

View File

@@ -1,6 +1,6 @@
import { AvatarGenerationRequest } from '@core/media/domain/entities/AvatarGenerationRequest';
import { AvatarGenerationRepository } from '@core/media/domain/repositories/AvatarGenerationRepository';
import { Logger } from '@core/shared/domain';
import type { AvatarGenerationRepository } from '@core/media/domain/repositories/AvatarGenerationRepository';
import type { Logger } from '@core/shared/domain/Logger';
export class InMemoryAvatarGenerationRepository implements AvatarGenerationRepository {
private requests: Map<string, AvatarGenerationRequest> = new Map(); // Key: requestId

View File

@@ -32,7 +32,7 @@ export class InAppNotificationAdapter implements NotificationGateway {
return {
success: true,
channel: this.channel,
externalId: notification.id,
externalId: notification.id.value,
attemptedAt: new Date(),
};
}

View File

@@ -1,6 +1,6 @@
import { NotificationPreference } from '@core/notifications/domain/entities/NotificationPreference';
import { NotificationPreferenceRepository } from '@core/notifications/domain/repositories/NotificationPreferenceRepository';
import { Logger } from '@core/shared/domain';
import type { NotificationPreferenceRepository } from '@core/notifications/domain/repositories/NotificationPreferenceRepository';
import type { Logger } from '@core/shared/domain/Logger';
export class InMemoryNotificationPreferenceRepository implements NotificationPreferenceRepository {
private preferences: Map<string, NotificationPreference> = new Map();

View File

@@ -17,8 +17,8 @@ export class InMemoryNotificationRepository implements NotificationRepository {
this.logger = logger;
this.logger.info('InMemoryNotificationRepository initialized.');
initialNotifications.forEach(notification => {
this.notifications.set(notification.id, notification);
this.logger.debug(`Seeded notification: ${notification.id}`);
this.notifications.set(notification.id.value, notification);
this.logger.debug(`Seeded notification: ${notification.id.value}`);
});
}
@@ -95,31 +95,31 @@ export class InMemoryNotificationRepository implements NotificationRepository {
}
async create(notification: Notification): Promise<void> {
this.logger.debug(`Creating notification: ${notification.id}`);
this.logger.debug(`Creating notification: ${notification.id.value}`);
try {
if (this.notifications.has(notification.id)) {
this.logger.warn(`Notification with ID ${notification.id} already exists. Throwing error.`);
throw new Error(`Notification with ID ${notification.id} already exists`);
if (this.notifications.has(notification.id.value)) {
this.logger.warn(`Notification with ID ${notification.id.value} already exists. Throwing error.`);
throw new Error(`Notification with ID ${notification.id.value} already exists`);
}
this.notifications.set(notification.id, notification);
this.logger.info(`Notification ${notification.id} created successfully.`);
this.notifications.set(notification.id.value, notification);
this.logger.info(`Notification ${notification.id.value} created successfully.`);
} catch (error) {
this.logger.error(`Error creating notification ${notification.id}:`, error instanceof Error ? error : new Error(String(error)));
this.logger.error(`Error creating notification ${notification.id.value}:`, error instanceof Error ? error : new Error(String(error)));
throw error;
}
}
async update(notification: Notification): Promise<void> {
this.logger.debug(`Updating notification: ${notification.id}`);
this.logger.debug(`Updating notification: ${notification.id.value}`);
try {
if (!this.notifications.has(notification.id)) {
this.logger.warn(`Notification with ID ${notification.id} not found for update. Throwing error.`);
throw new Error(`Notification with ID ${notification.id} not found`);
if (!this.notifications.has(notification.id.value)) {
this.logger.warn(`Notification with ID ${notification.id.value} not found for update. Throwing error.`);
throw new Error(`Notification with ID ${notification.id.value} not found`);
}
this.notifications.set(notification.id, notification);
this.logger.info(`Notification ${notification.id} updated successfully.`);
this.notifications.set(notification.id.value, notification);
this.logger.info(`Notification ${notification.id.value} updated successfully.`);
} catch (error) {
this.logger.error(`Error updating notification ${notification.id}:`, error instanceof Error ? error : new Error(String(error)));
this.logger.error(`Error updating notification ${notification.id.value}:`, error instanceof Error ? error : new Error(String(error)));
throw error;
}
}
@@ -143,7 +143,7 @@ export class InMemoryNotificationRepository implements NotificationRepository {
try {
const toDelete = Array.from(this.notifications.values())
.filter(n => n.recipientId === recipientId)
.map(n => n.id);
.map(n => n.id.value);
toDelete.forEach(id => this.notifications.delete(id));
this.logger.info(`Deleted ${toDelete.length} notifications for recipient ID: ${recipientId}.`);
@@ -163,7 +163,7 @@ export class InMemoryNotificationRepository implements NotificationRepository {
toUpdate.forEach(n => {
const updated = n.markAsRead();
this.notifications.set(updated.id, updated);
this.notifications.set(updated.id.value, updated);
});
this.logger.info(`Marked ${toUpdate.length} notifications as read for recipient ID: ${recipientId}.`);
} catch (error) {

View File

@@ -1,5 +1,5 @@
import { MagicLinkNotificationInput, MagicLinkNotificationPort } from '@core/identity/domain/ports/MagicLinkNotificationPort';
import { Logger } from '@core/shared/domain';
import type { MagicLinkNotificationInput, MagicLinkNotificationPort } from '@core/identity/domain/ports/MagicLinkNotificationPort';
import type { Logger } from '@core/shared/domain/Logger';
/**
* Console adapter for magic link notifications

View File

@@ -1,6 +1,8 @@
import type { NotificationGatewayRegistry } from '@core/notifications/application/ports/NotificationGateway';
import type { NotificationService, SendNotificationCommand } from '@core/notifications/application/ports/NotificationService';
import { SendNotificationUseCase } from '@core/notifications/application/use-cases/SendNotificationUseCase';
import type { NotificationRepository } from '@core/notifications/domain/repositories/NotificationRepository';
import type { NotificationPreferenceRepository } from '@core/notifications/domain/repositories/NotificationPreferenceRepository';
import type { Logger } from '@core/shared/domain/Logger';
export class NotificationServiceAdapter implements NotificationService {
@@ -8,8 +10,8 @@ export class NotificationServiceAdapter implements NotificationService {
private readonly logger: Logger;
constructor(
notificationRepository: INotificationRepository,
preferenceRepository: INotificationPreferenceRepository,
notificationRepository: NotificationRepository,
preferenceRepository: NotificationPreferenceRepository,
gatewayRegistry: NotificationGatewayRegistry,
logger: Logger,
) {

View File

@@ -4,7 +4,7 @@
import type { MemberPayment } from '@core/payments/domain/entities/MemberPayment';
import type { MembershipFee } from '@core/payments/domain/entities/MembershipFee';
import type { MembershipFeeRepository } from '@core/payments/domain/repositories/MembershipFeeRepository';
import type { MembershipFeeRepository, MemberPaymentRepository } from '@core/payments/domain/repositories/MembershipFeeRepository';
import type { Logger } from '@core/shared/domain/Logger';
const membershipFees: Map<string, MembershipFee> = new Map();
@@ -51,7 +51,7 @@ export class InMemoryMemberPaymentRepository implements MemberPaymentRepository
) || null;
}
async findByLeagueIdAndDriverId(leagueId: string, driverId: string, membershipFeeRepo: IMembershipFeeRepository): Promise<MemberPayment[]> {
async findByLeagueIdAndDriverId(leagueId: string, driverId: string, membershipFeeRepo: MembershipFeeRepository): Promise<MemberPayment[]> {
this.logger.debug('[InMemoryMemberPaymentRepository] findByLeagueIdAndDriverId', { leagueId, driverId });
const results: MemberPayment[] = [];
for (const payment of memberPayments.values()) {

View File

@@ -3,7 +3,7 @@
*/
import type { Transaction, Wallet } from '@core/payments/domain/entities/Wallet';
import type { WalletRepository } from '@core/payments/domain/repositories/WalletRepository';
import type { WalletRepository, TransactionRepository } from '@core/payments/domain/repositories/WalletRepository';
import type { Logger } from '@core/shared/domain/Logger';
const wallets: Map<string, Wallet> = new Map();

View File

@@ -2,7 +2,7 @@ import type { DataSource } from 'typeorm';
import type { MemberPayment } from '@core/payments/domain/entities/MemberPayment';
import type { MembershipFee } from '@core/payments/domain/entities/MembershipFee';
import type { IMembershipFeeRepository, MemberPaymentRepository } from '@core/payments/domain/repositories/MembershipFeeRepository';
import type { MembershipFeeRepository, MemberPaymentRepository } from '@core/payments/domain/repositories/MembershipFeeRepository';
import { PaymentsMemberPaymentOrmEntity } from '../entities/PaymentsMemberPaymentOrmEntity';
import { PaymentsMembershipFeeOrmEntity } from '../entities/PaymentsMembershipFeeOrmEntity';
@@ -61,7 +61,7 @@ export class TypeOrmMemberPaymentRepository implements MemberPaymentRepository {
async findByLeagueIdAndDriverId(
leagueId: string,
driverId: string,
membershipFeeRepo: IMembershipFeeRepository,
membershipFeeRepo: MembershipFeeRepository,
): Promise<MemberPayment[]> {
const fee = await membershipFeeRepo.findByLeagueId(leagueId);
if (!fee) {

View File

@@ -1,7 +1,7 @@
import type { DataSource } from 'typeorm';
import type { Transaction, Wallet } from '@core/payments/domain/entities/Wallet';
import type { TransactionRepository } from '@core/payments/domain/repositories/WalletRepository';
import type { WalletRepository, TransactionRepository } from '@core/payments/domain/repositories/WalletRepository';
import { PaymentsTransactionOrmEntity } from '../entities/PaymentsTransactionOrmEntity';
import { PaymentsWalletOrmEntity } from '../entities/PaymentsWalletOrmEntity';

View File

@@ -16,8 +16,8 @@ export class InMemoryPenaltyRepository implements PenaltyRepository {
this.logger = logger;
this.logger.info('InMemoryPenaltyRepository initialized.');
initialPenalties.forEach(penalty => {
this.penalties.set(penalty.id, penalty);
this.logger.debug(`Seeded penalty: ${penalty.id}`);
this.penalties.set(penalty.id.toString(), penalty);
this.logger.debug(`Seeded penalty: ${penalty.id.toString()}`);
});
}
@@ -108,31 +108,31 @@ export class InMemoryPenaltyRepository implements PenaltyRepository {
}
async create(penalty: Penalty): Promise<void> {
this.logger.debug(`Creating penalty: ${penalty.id}`);
this.logger.debug(`Creating penalty: ${penalty.id.toString()}`);
try {
if (this.penalties.has(penalty.id)) {
this.logger.warn(`Penalty with ID ${penalty.id} already exists.`);
throw new Error(`Penalty with ID ${penalty.id} already exists`);
if (this.penalties.has(penalty.id.toString())) {
this.logger.warn(`Penalty with ID ${penalty.id.toString()} already exists.`);
throw new Error(`Penalty with ID ${penalty.id.toString()} already exists`);
}
this.penalties.set(penalty.id, penalty);
this.logger.info(`Penalty ${penalty.id} created successfully.`);
this.penalties.set(penalty.id.toString(), penalty);
this.logger.info(`Penalty ${penalty.id.toString()} created successfully.`);
} catch (error) {
this.logger.error(`Error creating penalty ${penalty.id}:`, error instanceof Error ? error : new Error(String(error)));
this.logger.error(`Error creating penalty ${penalty.id.toString()}:`, error instanceof Error ? error : new Error(String(error)));
throw error;
}
}
async update(penalty: Penalty): Promise<void> {
this.logger.debug(`Updating penalty: ${penalty.id}`);
this.logger.debug(`Updating penalty: ${penalty.id.toString()}`);
try {
if (!this.penalties.has(penalty.id)) {
this.logger.warn(`Penalty with ID ${penalty.id} not found for update.`);
throw new Error(`Penalty with ID ${penalty.id} not found`);
if (!this.penalties.has(penalty.id.toString())) {
this.logger.warn(`Penalty with ID ${penalty.id.toString()} not found for update.`);
throw new Error(`Penalty with ID ${penalty.id.toString()} not found`);
}
this.penalties.set(penalty.id, penalty);
this.logger.info(`Penalty ${penalty.id} updated successfully.`);
this.penalties.set(penalty.id.toString(), penalty);
this.logger.info(`Penalty ${penalty.id.toString()} updated successfully.`);
} catch (error) {
this.logger.error(`Error updating penalty ${penalty.id}:`, error instanceof Error ? error : new Error(String(error)));
this.logger.error(`Error updating penalty ${penalty.id.toString()}:`, error instanceof Error ? error : new Error(String(error)));
throw error;
}
}

View File

@@ -7,15 +7,16 @@
import { Result } from '@core/racing/domain/entities/result/Result';
import type { ResultRepository } from '@core/racing/domain/repositories/ResultRepository';
import type { RaceRepository } from '@core/racing/domain/repositories/RaceRepository';
import type { Logger } from '@core/shared/domain/Logger';
import { v4 as uuidv4 } from 'uuid';
export class InMemoryResultRepository implements ResultRepository {
private results: Map<string, Result>;
private raceRepository: IRaceRepository | null;
private raceRepository: RaceRepository | null;
private readonly logger: Logger;
constructor(logger: Logger, raceRepository?: IRaceRepository | null) {
constructor(logger: Logger, raceRepository?: RaceRepository | null) {
this.logger = logger;
this.logger.info('[InMemoryResultRepository] Initialized.');
this.results = new Map();
@@ -86,7 +87,7 @@ export class InMemoryResultRepository implements ResultRepository {
}
const leagueRaces = await this.raceRepository.findByLeagueId(leagueId);
const leagueRaceIds = new Set(leagueRaces.map(race => race.id));
const leagueRaceIds = new Set(leagueRaces.map((race: any) => race.id));
this.logger.debug(`[InMemoryResultRepository] Found ${leagueRaces.length} races in league ${leagueId}.`);
const results = Array.from(this.results.values())

View File

@@ -7,22 +7,25 @@
import { Standing } from '@core/racing/domain/entities/Standing';
import type { StandingRepository } from '@core/racing/domain/repositories/StandingRepository';
import type { ResultRepository } from '@core/racing/domain/repositories/ResultRepository';
import type { RaceRepository } from '@core/racing/domain/repositories/RaceRepository';
import type { LeagueRepository } from '@core/racing/domain/repositories/LeagueRepository';
import type { Logger } from '@core/shared/domain/Logger';
export class InMemoryStandingRepository implements StandingRepository {
private standings: Map<string, Standing>;
private resultRepository: IResultRepository | null;
private raceRepository: IRaceRepository | null;
private leagueRepository: ILeagueRepository | null;
private resultRepository: ResultRepository | null;
private raceRepository: RaceRepository | null;
private leagueRepository: LeagueRepository | null;
private readonly logger: Logger;
private readonly pointsSystems: Record<string, Record<number, number>>;
constructor(
logger: Logger,
pointsSystems: Record<string, Record<number, number>>,
resultRepository?: IResultRepository | null,
raceRepository?: IRaceRepository | null,
leagueRepository?: ILeagueRepository | null
resultRepository?: ResultRepository | null,
raceRepository?: RaceRepository | null,
leagueRepository?: LeagueRepository | null
) {
this.logger = logger;
this.pointsSystems = pointsSystems;
@@ -198,7 +201,7 @@ export class InMemoryStandingRepository implements StandingRepository {
}
const allResults = await Promise.all(
races.map(async race => {
races.map(async (race: any) => {
this.logger.debug(`Fetching results for race ${race.id}.`);
const results = await this.resultRepository!.findByRaceId(race.id);
this.logger.debug(`Found ${results.length} results for race ${race.id}.`);
@@ -219,7 +222,7 @@ export class InMemoryStandingRepository implements StandingRepository {
return Number(position);
};
results.forEach((result) => {
results.forEach((result: any) => {
const driverIdStr = result.driverId.toString();
let standing = standingsMap.get(driverIdStr);

View File

@@ -136,7 +136,7 @@ function serializeProtestDefense(defense: Protest['defense']): SerializedProtest
export class PenaltyOrmMapper {
toOrmEntity(domain: Penalty): PenaltyOrmEntity {
const entity = new PenaltyOrmEntity();
entity.id = domain.id;
entity.id = domain.id.toString();
entity.leagueId = domain.leagueId;
entity.raceId = domain.raceId;
entity.driverId = domain.driverId;
@@ -197,7 +197,7 @@ export class PenaltyOrmMapper {
export class ProtestOrmMapper {
toOrmEntity(domain: Protest): ProtestOrmEntity {
const entity = new ProtestOrmEntity();
entity.id = domain.id;
entity.id = domain.id.toString();
entity.raceId = domain.raceId;
entity.protestingDriverId = domain.protestingDriverId;
entity.accusedDriverId = domain.accusedDriverId;

View File

@@ -0,0 +1,7 @@
export * from './DomainEvent';
export * from './Entity';
export * from './Logger';
export * from './Option';
export * from './Result';
export * from './Service';
export * from './ValueObject';