website refactor

This commit is contained in:
2026-01-16 16:46:57 +01:00
parent 37b1aa626c
commit 2f53727702
445 changed files with 1160 additions and 1150 deletions

View File

@@ -17,7 +17,7 @@ const mockRepository = {
create: vi.fn(),
update: vi.fn(),
delete: vi.fn(),
} as unknown as IAdminUserRepository;
} as unknown as AdminUserRepository;
describe('ListUsersUseCase', () => {
let useCase: ListUsersUseCase;

View File

@@ -44,7 +44,7 @@ export type ListUsersApplicationError = ApplicationErrorCode<ListUsersErrorCode,
*/
export class ListUsersUseCase {
constructor(
private readonly adminUserRepository: IAdminUserRepository,
private readonly adminUserRepository: AdminUserRepository,
) {}
async execute(

View File

@@ -1,4 +1,4 @@
import type { Entity } from '@core/shared/domain/Entity';
import { Entity } from '@core/shared/domain/Entity';
import { AdminDomainInvariantError, AdminDomainValidationError } from '../errors/AdminDomainError';
import { Email } from '../value-objects/Email';
import { UserId } from '../value-objects/UserId';
@@ -17,8 +17,7 @@ export interface AdminUserProps {
primaryDriverId: string | undefined;
}
export class AdminUser implements Entity<UserId> {
readonly id: UserId;
export class AdminUser extends Entity<UserId> {
private _email: Email;
private _roles: UserRole[];
private _status: UserStatus;
@@ -29,7 +28,8 @@ export class AdminUser implements Entity<UserId> {
private _primaryDriverId: string | undefined;
private constructor(props: AdminUserProps) {
this.id = props.id;
super(props.id);
this._email = props.email;
this._roles = props.roles;
this._status = props.status;

View File

@@ -1,6 +1,6 @@
import type { DomainError, CommonDomainErrorKind } from '@core/shared/errors';
import type { DomainErrorProps, CommonDomainErrorKind } from '@core/shared/errors/DomainError';
export abstract class AdminDomainError extends Error implements DomainError<CommonDomainErrorKind> {
export abstract class AdminDomainError extends Error implements DomainErrorProps<CommonDomainErrorKind> {
readonly type = 'domain' as const;
readonly context = 'admin-domain';
abstract readonly kind: CommonDomainErrorKind;

View File

@@ -1,4 +1,4 @@
import { ValueObject } from '@core/shared/domain';
import { ValueObject } from '@core/shared/domain/ValueObject';
import { AdminDomainValidationError } from '../errors/AdminDomainError';
export interface EmailProps {
@@ -40,7 +40,7 @@ export class Email implements ValueObject<EmailProps> {
return this.value;
}
equals(other: IValueObject<EmailProps>): boolean {
equals(other: ValueObject<EmailProps>): boolean {
return this.value === other.props.value;
}
}

View File

@@ -1,4 +1,4 @@
import { ValueObject } from '@core/shared/domain';
import { ValueObject } from '@core/shared/domain/ValueObject';
import { AdminDomainValidationError } from '../errors/AdminDomainError';
export interface UserIdProps {
@@ -28,7 +28,7 @@ export class UserId implements ValueObject<UserIdProps> {
return { value: this.value };
}
equals(other: IValueObject<UserIdProps>): boolean {
equals(other: ValueObject<UserIdProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,4 +1,4 @@
import { ValueObject } from '@core/shared/domain';
import { ValueObject } from '@core/shared/domain/ValueObject';
import { AdminDomainValidationError } from '../errors/AdminDomainError';
export type UserRoleValue = string;
@@ -41,7 +41,7 @@ export class UserRole implements ValueObject<UserRoleProps> {
return this.value;
}
equals(other: IValueObject<UserRoleProps>): boolean {
equals(other: ValueObject<UserRoleProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,4 +1,4 @@
import { ValueObject } from '@core/shared/domain';
import { ValueObject } from '@core/shared/domain/ValueObject';
import { AdminDomainValidationError } from '../errors/AdminDomainError';
export type UserStatusValue = string;
@@ -41,7 +41,7 @@ export class UserStatus implements ValueObject<UserStatusProps> {
return this.value;
}
equals(other: IValueObject<UserStatusProps>): boolean {
equals(other: ValueObject<UserStatusProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,4 +1,5 @@
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { PageViewRepository } from '../repositories/PageViewRepository';
@@ -20,7 +21,7 @@ export type GetAnalyticsMetricsErrorCode = 'REPOSITORY_ERROR';
export class GetAnalyticsMetricsUseCase implements UseCase<GetAnalyticsMetricsInput, GetAnalyticsMetricsOutput, GetAnalyticsMetricsErrorCode> {
constructor(
private readonly logger: Logger,
private readonly pageViewRepository?: IPageViewRepository,
private readonly pageViewRepository?: PageViewRepository,
) {}
async execute(

View File

@@ -1,4 +1,5 @@
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';

View File

@@ -32,8 +32,8 @@ describe('GetEntityAnalyticsQuery', () => {
} as unknown as Logger;
useCase = new GetEntityAnalyticsQuery(
pageViewRepository as unknown as IPageViewRepository,
engagementRepository as unknown as IEngagementRepository,
pageViewRepository as unknown as PageViewRepository,
engagementRepository as unknown as EngagementRepository,
logger,
);
});

View File

@@ -5,7 +5,8 @@
* Returns metrics formatted for display to sponsors and admins.
*/
import type { AsyncUseCase , Logger } from '@core/shared/application';
import type { AsyncUseCase } from '@core/shared/application/AsyncUseCase';
import type { Logger } from '@core/shared/domain/Logger';
import type { PageViewRepository } from '../repositories/PageViewRepository';
import type { EngagementRepository } from '@core/analytics/domain/repositories/EngagementRepository';
import type { EntityType } from '../../domain/types/PageView';
@@ -48,8 +49,8 @@ export type GetEntityAnalyticsErrorCode = 'REPOSITORY_ERROR';
export class GetEntityAnalyticsQuery
implements AsyncUseCase<GetEntityAnalyticsInput, EntityAnalyticsOutput, GetEntityAnalyticsErrorCode> {
constructor(
private readonly pageViewRepository: IPageViewRepository,
private readonly engagementRepository: IEngagementRepository,
private readonly pageViewRepository: PageViewRepository,
private readonly engagementRepository: EngagementRepository,
private readonly logger: Logger
) {}

View File

@@ -24,7 +24,7 @@ describe('RecordEngagementUseCase', () => {
} as unknown as Logger;
useCase = new RecordEngagementUseCase(
engagementRepository as unknown as IEngagementRepository,
engagementRepository as unknown as EngagementRepository,
logger,
);
});

View File

@@ -1,4 +1,5 @@
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import { EngagementEvent } from '../../domain/entities/EngagementEvent';
@@ -24,7 +25,7 @@ export type RecordEngagementErrorCode = 'REPOSITORY_ERROR';
export class RecordEngagementUseCase implements UseCase<RecordEngagementInput, RecordEngagementOutput, RecordEngagementErrorCode> {
constructor(
private readonly engagementRepository: IEngagementRepository,
private readonly engagementRepository: EngagementRepository,
private readonly logger: Logger,
) {}

View File

@@ -1,4 +1,5 @@
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
import type { PageViewRepository } from '../repositories/PageViewRepository';
import { PageView } from '../../domain/entities/PageView';
import type { EntityType, VisitorType } from '../../domain/types/PageView';
@@ -24,7 +25,7 @@ export type RecordPageViewErrorCode = 'REPOSITORY_ERROR';
export class RecordPageViewUseCase implements UseCase<RecordPageViewInput, RecordPageViewOutput, RecordPageViewErrorCode> {
constructor(
private readonly pageViewRepository: IPageViewRepository,
private readonly pageViewRepository: PageViewRepository,
private readonly logger: Logger,
) {}

View File

@@ -5,7 +5,7 @@
* Pre-calculated metrics for sponsor dashboard and entity analytics.
*/
import type { Entity } from '@core/shared/domain/Entity';
import { Entity } from '@core/shared/domain/Entity';
import type {
AnalyticsMetrics,
AnalyticsSnapshotProps,
@@ -15,8 +15,7 @@ import type {
import { AnalyticsEntityId } from '../value-objects/AnalyticsEntityId';
export type { SnapshotEntityType, SnapshotPeriod } from '../types/AnalyticsSnapshot';
export class AnalyticsSnapshot implements Entity<string> {
readonly id: string;
export class AnalyticsSnapshot extends Entity<string> {
readonly entityType: SnapshotEntityType;
readonly period: SnapshotPeriod;
readonly startDate: Date;
@@ -27,7 +26,7 @@ export class AnalyticsSnapshot implements Entity<string> {
private readonly entityIdVo: AnalyticsEntityId;
private constructor(props: AnalyticsSnapshotProps) {
this.id = props.id;
super(props.id);
this.entityType = props.entityType;
this.entityIdVo = AnalyticsEntityId.create(props.entityId);
this.period = props.period;

View File

@@ -5,7 +5,7 @@
* Tracks clicks, downloads, sign-ups, and other engagement actions.
*/
import type { Entity } from '@core/shared/domain/Entity';
import { Entity } from '@core/shared/domain/Entity';
import type {
EngagementAction,
EngagementEntityType,
@@ -15,8 +15,7 @@ import { AnalyticsEntityId } from '../value-objects/AnalyticsEntityId';
export type { EngagementAction, EngagementEntityType } from '../types/EngagementEvent';
export class EngagementEvent implements Entity<string> {
readonly id: string;
export class EngagementEvent extends Entity<string> {
readonly action: EngagementAction;
readonly entityType: EngagementEntityType;
readonly actorId: string | undefined;
@@ -28,7 +27,8 @@ export class EngagementEvent implements Entity<string> {
private readonly entityIdVo: AnalyticsEntityId;
private constructor(props: EngagementEventProps) {
this.id = props.id;
super(props.id);
this.action = props.action;
this.entityType = props.entityType;
this.entityIdVo = AnalyticsEntityId.create(props.entityId);

View File

@@ -5,7 +5,7 @@
* Captures visitor interactions with leagues, drivers, teams, races.
*/
import type { Entity } from '@core/shared/domain/Entity';
import { Entity } from '@core/shared/domain/Entity';
import type { EntityType, PageViewProps, VisitorType } from '../types/PageView';
import { AnalyticsEntityId } from '../value-objects/AnalyticsEntityId';
import { AnalyticsSessionId } from '../value-objects/AnalyticsSessionId';
@@ -13,7 +13,7 @@ import { PageViewId } from '../value-objects/PageViewId';
export type { EntityType, VisitorType } from '../types/PageView';
export class PageView implements Entity<string> {
export class PageView extends Entity<string> {
readonly entityType: EntityType;
readonly visitorId: string | undefined;
readonly visitorType: VisitorType;
@@ -28,6 +28,7 @@ export class PageView implements Entity<string> {
private readonly sessionIdVo: AnalyticsSessionId;
private constructor(props: PageViewProps) {
super(props.id);
this.idVo = PageViewId.create(props.id);
this.entityType = props.entityType;
this.entityIdVo = AnalyticsEntityId.create(props.entityId);
@@ -41,10 +42,6 @@ export class PageView implements Entity<string> {
this.durationMs = props.durationMs;
}
get id(): string {
return this.idVo.value;
}
get entityId(): string {
return this.entityIdVo.value;
}

View File

@@ -1,5 +1,5 @@
/**
* Repository Interface: IAnalyticsSnapshotRepository
* Repository Interface: AnalyticsSnapshotRepository
*
* Defines persistence operations for AnalyticsSnapshot entities.
*/

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
export interface AnalyticsEntityIdProps {
value: string;
@@ -31,7 +31,7 @@ export class AnalyticsEntityId implements ValueObject<AnalyticsEntityIdProps> {
return this.props.value;
}
equals(other: IValueObject<AnalyticsEntityIdProps>): boolean {
equals(other: ValueObject<AnalyticsEntityIdProps>): boolean {
return this.props.value === other.props.value;
}
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
export interface AnalyticsSessionIdProps {
value: string;
@@ -30,7 +30,7 @@ export class AnalyticsSessionId implements ValueObject<AnalyticsSessionIdProps>
return this.props.value;
}
equals(other: IValueObject<AnalyticsSessionIdProps>): boolean {
equals(other: ValueObject<AnalyticsSessionIdProps>): boolean {
return this.props.value === other.props.value;
}
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
export interface PageViewIdProps {
value: string;
@@ -30,7 +30,7 @@ export class PageViewId implements ValueObject<PageViewIdProps> {
return this.props.value;
}
equals(other: IValueObject<PageViewIdProps>): boolean {
equals(other: ValueObject<PageViewIdProps>): boolean {
return this.props.value === other.props.value;
}
}

View File

@@ -10,7 +10,7 @@
* Follows clean architecture and TDD principles.
*/
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
// Variant types for system-default references
export type MediaVariant = 'avatar' | 'logo';
@@ -236,7 +236,7 @@ export class MediaReference implements ValueObject<MediaReferenceProps> {
/**
* Equality comparison
*/
equals(other: IValueObject<MediaReferenceProps>): boolean {
equals(other: ValueObject<MediaReferenceProps>): boolean {
if (!(other instanceof MediaReference)) {
return false;
}

View File

@@ -1,5 +1,5 @@
/**
* Port: IRaceResultsProvider
* Port: RaceResultsProvider
*
* Provider interface for race results data needed for rating calculations.
* This is an application layer port that bridges racing context to identity context.

View File

@@ -13,15 +13,15 @@ import { UserRatingRepository } from '../../domain/repositories/UserRatingReposi
import { ExternalGameRatingRepository } from '../../domain/repositories/ExternalGameRatingRepository';
describe('GetLeagueEligibilityPreviewQuery', () => {
let mockUserRatingRepo: IUserRatingRepository;
let mockExternalRatingRepo: IExternalGameRatingRepository;
let mockUserRatingRepo: UserRatingRepository;
let mockExternalRatingRepo: ExternalGameRatingRepository;
let handler: GetLeagueEligibilityPreviewQueryHandler;
beforeEach(() => {
mockUserRatingRepo = {
findByUserId: vi.fn(),
save: vi.fn(),
} as unknown as IUserRatingRepository;
} as unknown as UserRatingRepository;
mockExternalRatingRepo = {
findByUserId: vi.fn(),
@@ -32,7 +32,7 @@ describe('GetLeagueEligibilityPreviewQuery', () => {
delete: vi.fn(),
exists: vi.fn(),
findProfilesPaginated: vi.fn(),
} as unknown as IExternalGameRatingRepository;
} as unknown as ExternalGameRatingRepository;
handler = new GetLeagueEligibilityPreviewQueryHandler(
mockUserRatingRepo,

View File

@@ -21,8 +21,8 @@ export class GetLeagueEligibilityPreviewQueryHandler {
private readonly evaluator: EligibilityEvaluator;
constructor(
private readonly userRatingRepo: IUserRatingRepository,
private readonly externalRatingRepo: IExternalGameRatingRepository
private readonly userRatingRepo: UserRatingRepository,
private readonly externalRatingRepo: ExternalGameRatingRepository
) {
this.evaluator = new EligibilityEvaluator();
}

View File

@@ -16,7 +16,7 @@ export interface GetUserRatingLedgerQuery {
export class GetUserRatingLedgerQueryHandler {
constructor(
private readonly ratingEventRepo: IRatingEventRepository
private readonly ratingEventRepo: RatingEventRepository
) {}
async execute(query: GetUserRatingLedgerQuery): Promise<PaginatedLedgerResult> {

View File

@@ -16,9 +16,9 @@ export interface GetUserRatingsSummaryQuery {
export class GetUserRatingsSummaryQueryHandler {
constructor(
private readonly userRatingRepo: IUserRatingRepository,
private readonly externalRatingRepo: IExternalGameRatingRepository,
private readonly ratingEventRepo: IRatingEventRepository
private readonly userRatingRepo: UserRatingRepository,
private readonly externalRatingRepo: ExternalGameRatingRepository,
private readonly ratingEventRepo: RatingEventRepository
) {}
async execute(query: GetUserRatingsSummaryQuery): Promise<RatingSummaryDto> {

View File

@@ -71,7 +71,7 @@ class MockRatingEventRepository {
return Array.from(this.events.values()).filter(e => e.userId === userId);
}
async findEventsPaginated(userId: string, options?: import('@core/identity/domain/repositories/IRatingEventRepository').PaginatedQueryOptions): Promise<import('@core/identity/domain/repositories/IRatingEventRepository').PaginatedResult<RatingEvent>> {
async findEventsPaginated(userId: string, options?: import('@core/identity/domain/repositories/RatingEventRepository').PaginatedQueryOptions): Promise<import('@core/identity/domain/repositories/RatingEventRepository').PaginatedResult<RatingEvent>> {
const allEvents = await this.findByUserId(userId);
// Apply filters
@@ -105,7 +105,7 @@ class MockRatingEventRepository {
const hasMore = offset + limit < total;
const nextOffset = hasMore ? offset + limit : undefined;
const result: import('@core/identity/domain/repositories/IRatingEventRepository').PaginatedResult<RatingEvent> = {
const result: import('@core/identity/domain/repositories/RatingEventRepository').PaginatedResult<RatingEvent> = {
items,
total,
limit,

View File

@@ -8,8 +8,8 @@ import { UserRating } from '../../domain/value-objects/UserRating';
import { RatingEventId } from '../../domain/value-objects/RatingEventId';
describe('AppendRatingEventsUseCase', () => {
let mockEventRepo: Partial<IRatingEventRepository>;
let mockRatingRepo: Partial<IUserRatingRepository>;
let mockEventRepo: Partial<RatingEventRepository>;
let mockRatingRepo: Partial<UserRatingRepository>;
beforeEach(() => {
mockEventRepo = {
@@ -24,16 +24,16 @@ describe('AppendRatingEventsUseCase', () => {
it('should be constructed with repositories', () => {
const useCase = new AppendRatingEventsUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
expect(useCase).toBeInstanceOf(AppendRatingEventsUseCase);
});
it('should handle empty input (no events)', async () => {
const useCase = new AppendRatingEventsUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const input: AppendRatingEventsInput = {
@@ -50,8 +50,8 @@ describe('AppendRatingEventsUseCase', () => {
it('should create and save events from direct input', async () => {
const useCase = new AppendRatingEventsUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const input: AppendRatingEventsInput = {
@@ -79,8 +79,8 @@ describe('AppendRatingEventsUseCase', () => {
it('should create events from race results using factory', async () => {
const useCase = new AppendRatingEventsUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const input: AppendRatingEventsInput = {
@@ -108,8 +108,8 @@ describe('AppendRatingEventsUseCase', () => {
it('should handle multiple race results', async () => {
const useCase = new AppendRatingEventsUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const input: AppendRatingEventsInput = {
@@ -129,8 +129,8 @@ describe('AppendRatingEventsUseCase', () => {
it('should handle DNF status', async () => {
const useCase = new AppendRatingEventsUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const input: AppendRatingEventsInput = {
@@ -159,8 +159,8 @@ describe('AppendRatingEventsUseCase', () => {
};
const useCase = new AppendRatingEventsUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const input: AppendRatingEventsInput = {

View File

@@ -42,8 +42,8 @@ export interface AppendRatingEventsOutput {
*/
export class AppendRatingEventsUseCase {
constructor(
private readonly ratingEventRepository: IRatingEventRepository,
private readonly userRatingRepository: IUserRatingRepository,
private readonly ratingEventRepository: RatingEventRepository,
private readonly userRatingRepository: UserRatingRepository,
) {}
async execute(input: AppendRatingEventsInput): Promise<AppendRatingEventsOutput> {

View File

@@ -11,7 +11,7 @@ import { CastAdminVoteInput, CastAdminVoteOutput } from '../dtos/AdminVoteSessio
*/
export class CastAdminVoteUseCase {
constructor(
private readonly adminVoteSessionRepository: IAdminVoteSessionRepository,
private readonly adminVoteSessionRepository: AdminVoteSessionRepository,
) {}
async execute(input: CastAdminVoteInput): Promise<CastAdminVoteOutput> {

View File

@@ -23,9 +23,9 @@ import { CloseAdminVoteSessionInput, CloseAdminVoteSessionOutput } from '../dtos
*/
export class CloseAdminVoteSessionUseCase {
constructor(
private readonly adminVoteSessionRepository: IAdminVoteSessionRepository,
private readonly ratingEventRepository: IRatingEventRepository,
private readonly userRatingRepository: IUserRatingRepository,
private readonly adminVoteSessionRepository: AdminVoteSessionRepository,
private readonly ratingEventRepository: RatingEventRepository,
private readonly userRatingRepository: UserRatingRepository,
private readonly appendRatingEventsUseCase: any, // Will be typed properly in integration
) {}

View File

@@ -42,9 +42,9 @@ describe('ForgotPasswordUseCase', () => {
} as unknown as Logger;
useCase = new ForgotPasswordUseCase(
authRepo as unknown as IAuthRepository,
magicLinkRepo as unknown as IMagicLinkRepository,
notificationPort as unknown as IMagicLinkNotificationPort,
authRepo as unknown as AuthRepository,
magicLinkRepo as unknown as MagicLinkRepository,
notificationPort as unknown as MagicLinkNotificationPort,
logger,
);
});

View File

@@ -4,7 +4,8 @@ import { MagicLinkRepository } from '../../domain/repositories/MagicLinkReposito
import { MagicLinkNotificationPort } from '../../domain/ports/MagicLinkNotificationPort';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
import { randomBytes } from 'crypto';
export type ForgotPasswordInput = {
@@ -29,9 +30,9 @@ export type ForgotPasswordApplicationError = ApplicationErrorCode<ForgotPassword
*/
export class ForgotPasswordUseCase implements UseCase<ForgotPasswordInput, ForgotPasswordResult, ForgotPasswordErrorCode> {
constructor(
private readonly authRepo: IAuthRepository,
private readonly magicLinkRepo: IMagicLinkRepository,
private readonly notificationPort: IMagicLinkNotificationPort,
private readonly authRepo: AuthRepository,
private readonly magicLinkRepo: MagicLinkRepository,
private readonly notificationPort: MagicLinkNotificationPort,
private readonly logger: Logger,
) {}

View File

@@ -30,7 +30,7 @@ describe('GetCurrentSessionUseCase', () => {
error: vi.fn(),
} as unknown as Logger;
useCase = new GetCurrentSessionUseCase(
mockUserRepo as IUserRepository,
mockUserRepo as UserRepository,
logger,
);
});

View File

@@ -25,7 +25,7 @@ export type GetCurrentSessionApplicationError = ApplicationErrorCode<
*/
export class GetCurrentSessionUseCase {
constructor(
private readonly userRepo: IUserRepository,
private readonly userRepo: UserRepository,
private readonly logger: Logger,
) {}

View File

@@ -22,7 +22,7 @@ describe('GetUserUseCase', () => {
} as unknown as Logger;
useCase = new GetUserUseCase(
userRepo as unknown as IUserRepository,
userRepo as unknown as UserRepository,
logger,
);
});

View File

@@ -2,7 +2,8 @@ import { User } from '../../domain/entities/User';
import { UserRepository } from '../../domain/repositories/UserRepository';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
export type GetUserInput = {
userId: string;
@@ -21,7 +22,7 @@ export type GetUserApplicationError = ApplicationErrorCode<
export class GetUserUseCase implements UseCase<GetUserInput, GetUserResult, GetUserErrorCode> {
constructor(
private readonly userRepo: IUserRepository,
private readonly userRepo: UserRepository,
private readonly logger: Logger,
) {}

View File

@@ -32,8 +32,8 @@ describe('LoginUseCase', () => {
} as unknown as Logger;
useCase = new LoginUseCase(
authRepo as unknown as IAuthRepository,
passwordService as unknown as IPasswordHashingService,
authRepo as unknown as AuthRepository,
passwordService as unknown as PasswordHashingService,
logger,
);
});

View File

@@ -4,7 +4,8 @@ import { AuthRepository } from '../../domain/repositories/AuthRepository';
import { PasswordHashingService } from '../../domain/services/PasswordHashingService';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
export type LoginInput = {
email: string;
@@ -26,8 +27,8 @@ export type LoginApplicationError = ApplicationErrorCode<LoginErrorCode, { messa
*/
export class LoginUseCase implements UseCase<LoginInput, LoginResult, LoginErrorCode> {
constructor(
private readonly authRepo: IAuthRepository,
private readonly passwordService: IPasswordHashingService,
private readonly authRepo: AuthRepository,
private readonly passwordService: PasswordHashingService,
private readonly logger: Logger,
) {}

View File

@@ -40,7 +40,7 @@ describe('LoginWithEmailUseCase', () => {
} as unknown as Logger;
useCase = new LoginWithEmailUseCase(
userRepository as unknown as IUserRepository,
userRepository as unknown as UserRepository,
sessionPort as unknown as IdentitySessionPort,
logger,
);

View File

@@ -37,7 +37,7 @@ export type LoginWithEmailApplicationError = ApplicationErrorCode<
export class LoginWithEmailUseCase {
constructor(
private readonly userRepository: IUserRepository,
private readonly userRepository: UserRepository,
private readonly sessionPort: IdentitySessionPort,
private readonly logger: Logger,
) {}

View File

@@ -1,7 +1,8 @@
import type { IdentitySessionPort } from '../ports/IdentitySessionPort';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
export type LogoutInput = {};

View File

@@ -12,7 +12,7 @@ import { OpenAdminVoteSessionInput, OpenAdminVoteSessionOutput } from '../dtos/A
*/
export class OpenAdminVoteSessionUseCase {
constructor(
private readonly adminVoteSessionRepository: IAdminVoteSessionRepository,
private readonly adminVoteSessionRepository: AdminVoteSessionRepository,
) {}
async execute(input: OpenAdminVoteSessionInput): Promise<OpenAdminVoteSessionOutput> {

View File

@@ -10,8 +10,8 @@ import { RatingDimensionKey } from '../../domain/value-objects/RatingDimensionKe
import { RatingDelta } from '../../domain/value-objects/RatingDelta';
describe('RecomputeUserRatingSnapshotUseCase', () => {
let mockEventRepo: Partial<IRatingEventRepository>;
let mockRatingRepo: Partial<IUserRatingRepository>;
let mockEventRepo: Partial<RatingEventRepository>;
let mockRatingRepo: Partial<UserRatingRepository>;
beforeEach(() => {
mockEventRepo = {
@@ -25,16 +25,16 @@ describe('RecomputeUserRatingSnapshotUseCase', () => {
it('should be constructed with repositories', () => {
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
expect(useCase).toBeInstanceOf(RecomputeUserRatingSnapshotUseCase);
});
it('should compute snapshot from empty event list', async () => {
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const result = await useCase.execute({ userId: 'user-1' });
@@ -64,8 +64,8 @@ describe('RecomputeUserRatingSnapshotUseCase', () => {
mockEventRepo.getAllByUserId = vi.fn().mockResolvedValue(events);
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const result = await useCase.execute({ userId: 'user-1' });
@@ -78,8 +78,8 @@ describe('RecomputeUserRatingSnapshotUseCase', () => {
it('should return proper DTO format', async () => {
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const result = await useCase.execute({ userId: 'user-1' });
@@ -117,8 +117,8 @@ describe('RecomputeUserRatingSnapshotUseCase', () => {
mockRatingRepo.save = vi.fn().mockResolvedValue(updated);
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as IRatingEventRepository,
mockRatingRepo as IUserRatingRepository,
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const result = await useCase.execute({ userId: 'user-1' });

View File

@@ -28,8 +28,8 @@ export interface RecomputeUserRatingSnapshotOutput {
*/
export class RecomputeUserRatingSnapshotUseCase {
constructor(
private readonly ratingEventRepository: IRatingEventRepository,
private readonly userRatingRepository: IUserRatingRepository,
private readonly ratingEventRepository: RatingEventRepository,
private readonly userRatingRepository: UserRatingRepository,
) {}
async execute(input: RecomputeUserRatingSnapshotInput): Promise<RecomputeUserRatingSnapshotOutput> {

View File

@@ -24,9 +24,9 @@ import { RecordRaceRatingEventsInput, RecordRaceRatingEventsOutput } from '../dt
*/
export class RecordRaceRatingEventsUseCase {
constructor(
private readonly raceResultsProvider: IRaceResultsProvider,
private readonly ratingEventRepository: IRatingEventRepository,
private readonly userRatingRepository: IUserRatingRepository,
private readonly raceResultsProvider: RaceResultsProvider,
private readonly ratingEventRepository: RatingEventRepository,
private readonly userRatingRepository: UserRatingRepository,
private readonly appendRatingEventsUseCase: AppendRatingEventsUseCase,
) {}

View File

@@ -43,9 +43,9 @@ describe('ResetPasswordUseCase', () => {
} as unknown as Logger;
useCase = new ResetPasswordUseCase(
authRepo as unknown as IAuthRepository,
magicLinkRepo as unknown as IMagicLinkRepository,
passwordService as unknown as IPasswordHashingService,
authRepo as unknown as AuthRepository,
magicLinkRepo as unknown as MagicLinkRepository,
passwordService as unknown as PasswordHashingService,
logger,
);
});

View File

@@ -5,7 +5,8 @@ import { EmailAddress } from '../../domain/value-objects/EmailAddress';
import { PasswordHash } from '../../domain/value-objects/PasswordHash';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
export type ResetPasswordInput = {
token: string;
@@ -28,9 +29,9 @@ export type ResetPasswordApplicationError = ApplicationErrorCode<ResetPasswordEr
*/
export class ResetPasswordUseCase implements UseCase<ResetPasswordInput, ResetPasswordResult, ResetPasswordErrorCode> {
constructor(
private readonly authRepo: IAuthRepository,
private readonly magicLinkRepo: IMagicLinkRepository,
private readonly passwordService: IPasswordHashingService,
private readonly authRepo: AuthRepository,
private readonly magicLinkRepo: MagicLinkRepository,
private readonly passwordService: PasswordHashingService,
private readonly logger: Logger,
) {}

View File

@@ -42,9 +42,9 @@ describe('SignupSponsorUseCase', () => {
} as unknown as Logger;
useCase = new SignupSponsorUseCase(
authRepo as unknown as IAuthRepository,
companyRepo as unknown as ICompanyRepository,
passwordService as unknown as IPasswordHashingService,
authRepo as unknown as AuthRepository,
companyRepo as unknown as CompanyRepository,
passwordService as unknown as PasswordHashingService,
logger,
);
});

View File

@@ -7,7 +7,8 @@ import { CompanyRepository } from '../../domain/repositories/CompanyRepository';
import { PasswordHashingService } from '../../domain/services/PasswordHashingService';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
export type SignupSponsorInput = {
email: string;
@@ -33,9 +34,9 @@ export type SignupSponsorApplicationError = ApplicationErrorCode<SignupSponsorEr
*/
export class SignupSponsorUseCase implements UseCase<SignupSponsorInput, SignupSponsorResult, SignupSponsorErrorCode> {
constructor(
private readonly authRepo: IAuthRepository,
private readonly companyRepo: ICompanyRepository,
private readonly passwordService: IPasswordHashingService,
private readonly authRepo: AuthRepository,
private readonly companyRepo: CompanyRepository,
private readonly passwordService: PasswordHashingService,
private readonly logger: Logger,
) {}

View File

@@ -34,8 +34,8 @@ describe('SignupUseCase', () => {
} as unknown as Logger;
useCase = new SignupUseCase(
authRepo as unknown as IAuthRepository,
passwordService as unknown as IPasswordHashingService,
authRepo as unknown as AuthRepository,
passwordService as unknown as PasswordHashingService,
logger,
);
});

View File

@@ -6,7 +6,8 @@ import { PasswordHashingService } from '../../domain/services/PasswordHashingSer
import { PasswordHash } from '../../domain/value-objects/PasswordHash';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger, UseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/domain/Logger';
import type { UseCase } from '@core/shared/application/UseCase';
export type SignupInput = {
email: string;
@@ -29,8 +30,8 @@ export type SignupApplicationError = ApplicationErrorCode<SignupErrorCode, { mes
*/
export class SignupUseCase implements UseCase<SignupInput, SignupResult, SignupErrorCode> {
constructor(
private readonly authRepo: IAuthRepository,
private readonly passwordService: IPasswordHashingService,
private readonly authRepo: AuthRepository,
private readonly passwordService: PasswordHashingService,
private readonly logger: Logger,
) {}

View File

@@ -32,7 +32,7 @@ describe('SignupWithEmailUseCase', () => {
} as unknown as Logger;
useCase = new SignupWithEmailUseCase(
userRepository as unknown as IUserRepository,
userRepository as unknown as UserRepository,
sessionPort as unknown as IdentitySessionPort,
logger,
);

View File

@@ -33,7 +33,7 @@ export type SignupWithEmailApplicationError = ApplicationErrorCode<
export class SignupWithEmailUseCase {
constructor(
private readonly userRepository: IUserRepository,
private readonly userRepository: UserRepository,
private readonly sessionPort: IdentitySessionPort,
private readonly logger: Logger,
) {}

View File

@@ -10,7 +10,7 @@ import { vi, describe, it, expect, beforeEach } from 'vitest';
describe('UpsertExternalGameRatingUseCase', () => {
let useCase: UpsertExternalGameRatingUseCase;
let mockRepository: IExternalGameRatingRepository;
let mockRepository: ExternalGameRatingRepository;
beforeEach(() => {
mockRepository = {

View File

@@ -23,7 +23,7 @@ import { UpsertExternalGameRatingInput, UpsertExternalGameRatingOutput } from '.
*/
export class UpsertExternalGameRatingUseCase {
constructor(
private readonly externalGameRatingRepository: IExternalGameRatingRepository
private readonly externalGameRatingRepository: ExternalGameRatingRepository
) {}
async execute(input: UpsertExternalGameRatingInput): Promise<UpsertExternalGameRatingOutput> {

View File

@@ -1,6 +1,6 @@
import type { Logger } from '@core/shared/domain/Logger';
import { describe, expect, it, vi, type Mock } from 'vitest';
import { CreateAchievementUseCase, type IAchievementRepository } from './CreateAchievementUseCase';
import { CreateAchievementUseCase, type AchievementRepository } from './CreateAchievementUseCase';
describe('CreateAchievementUseCase', () => {
let achievementRepository: {
@@ -24,7 +24,7 @@ describe('CreateAchievementUseCase', () => {
} as unknown as Logger;
useCase = new CreateAchievementUseCase(
achievementRepository as unknown as IAchievementRepository,
achievementRepository as unknown as AchievementRepository,
logger,
);
});

View File

@@ -23,7 +23,7 @@ export type CreateAchievementApplicationError = ApplicationErrorCode<
export class CreateAchievementUseCase {
constructor(
private readonly achievementRepository: IAchievementRepository,
private readonly achievementRepository: AchievementRepository,
private readonly logger: Logger,
) {}

View File

@@ -5,7 +5,7 @@
* Achievements are categorized by role (driver, steward, admin) and type.
*/
import type { Entity } from '@core/shared/domain/Entity';
import { Entity } from '@core/shared/domain/Entity';
export type AchievementCategory = 'driver' | 'steward' | 'admin' | 'community';
@@ -32,8 +32,7 @@ export interface AchievementRequirement {
operator: '>=' | '>' | '=' | '<' | '<=';
}
export class Achievement implements Entity<string> {
readonly id: string;
export class Achievement extends Entity<string> {
readonly name: string;
readonly description: string;
readonly category: AchievementCategory;
@@ -45,7 +44,8 @@ export class Achievement implements Entity<string> {
readonly createdAt: Date;
private constructor(props: AchievementProps) {
this.id = props.id;
super(props.id);
this.name = props.name;
this.description = props.description;
this.category = props.category;

View File

@@ -1,4 +1,4 @@
import type { Entity, IEntity } from '@core/shared/domain/Entity';
import { Entity } from '@core/shared/domain/Entity';
import { IdentityDomainInvariantError, IdentityDomainValidationError } from '../errors/IdentityDomainError';
export interface AdminVote {
@@ -42,8 +42,7 @@ export interface AdminVoteSessionProps {
*
* Based on ratings-architecture-concept.md sections 5.2.1 and 7.1.1
*/
export class AdminVoteSession implements Entity<string> {
readonly id: string;
export class AdminVoteSession extends Entity<string> {
readonly leagueId: string;
readonly adminId: string;
readonly startDate: Date;
@@ -56,7 +55,7 @@ export class AdminVoteSession implements Entity<string> {
private _updatedAt: Date;
private constructor(props: AdminVoteSessionProps) {
this.id = props.voteSessionId;
super(props.voteSessionId);
this.leagueId = props.leagueId;
this.adminId = props.adminId;
this.startDate = props.startDate;
@@ -269,7 +268,7 @@ export class AdminVoteSession implements Entity<string> {
return now >= this.startDate && now <= this.endDate && !this._closed;
}
equals(other: IEntity<string>): boolean {
equals(other: Entity<string>): boolean {
return this.id === other.id;
}

View File

@@ -1,4 +1,4 @@
import type { Entity, IEntity } from '@core/shared/domain/Entity';
import { Entity } from '@core/shared/domain/Entity';
import { IdentityDomainInvariantError, IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { RatingDelta } from '../value-objects/RatingDelta';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
@@ -34,8 +34,7 @@ export interface RatingEventProps {
version: number;
}
export class RatingEvent implements Entity<RatingEventId> {
readonly id: RatingEventId;
export class RatingEvent extends Entity<RatingEventId> {
readonly userId: string;
readonly dimension: RatingDimensionKey;
readonly delta: RatingDelta;
@@ -48,7 +47,8 @@ export class RatingEvent implements Entity<RatingEventId> {
readonly version: number;
private constructor(props: RatingEventProps) {
this.id = props.id;
super(props.id);
this.userId = props.userId;
this.dimension = props.dimension;
this.delta = props.delta;
@@ -118,7 +118,7 @@ export class RatingEvent implements Entity<RatingEventId> {
return new RatingEvent(props);
}
equals(other: IEntity<RatingEventId>): boolean {
equals(other: Entity<RatingEventId>): boolean {
return this.id.equals(other.id);
}

View File

@@ -4,7 +4,7 @@
* Represents an achievement earned by a specific user.
*/
import type { Entity } from '@core/shared/domain/Entity';
import { Entity } from '@core/shared/domain/Entity';
export interface UserAchievementProps {
id: string;
@@ -15,8 +15,7 @@ export interface UserAchievementProps {
progress?: number; // For partial progress tracking (0-100)
}
export class UserAchievement implements Entity<string> {
readonly id: string;
export class UserAchievement extends Entity<string> {
readonly userId: string;
readonly achievementId: string;
readonly earnedAt: Date;
@@ -24,7 +23,8 @@ export class UserAchievement implements Entity<string> {
readonly progress: number;
private constructor(props: UserAchievementProps) {
this.id = props.id;
super(props.id);
this.userId = props.userId;
this.achievementId = props.achievementId;
this.earnedAt = props.earnedAt;

View File

@@ -1,4 +1,5 @@
import type { DomainError, CommonDomainErrorKind } from '@core/shared/errors';
import type { DomainError } from '@core/shared/errors/DomainError';
import type { CommonDomainErrorKind } from '@core/shared/errors/DomainError';
export abstract class IdentityDomainError extends Error implements DomainError<CommonDomainErrorKind> {
readonly type = 'domain' as const;

View File

@@ -1,5 +1,5 @@
/**
* Repository Interface: IAchievementRepository
* Repository Interface: AchievementRepository
*
* Defines operations for Achievement and UserAchievement entities
*/

View File

@@ -1,7 +1,7 @@
import type { AdminVoteSession } from '../entities/AdminVoteSession';
/**
* Repository Interface: IAdminVoteSessionRepository
* Repository Interface: AdminVoteSessionRepository
*
* Port for persisting and retrieving admin vote sessions.
* Sessions are scoped to leagues and control voting windows.

View File

@@ -2,7 +2,7 @@ import { EmailAddress } from '../value-objects/EmailAddress';
import { User } from '../entities/User';
/**
* Domain Repository: IAuthRepository
* Domain Repository: AuthRepository
*
* Repository interface for authentication operations.
*/

View File

@@ -1,7 +1,7 @@
import { Company } from '../entities/Company';
/**
* Domain Repository: ICompanyRepository
* Domain Repository: CompanyRepository
*
* Repository interface for Company entity operations.
*/

View File

@@ -6,10 +6,10 @@ import { ExternalRating } from '../value-objects/ExternalRating';
import { ExternalRatingProvenance } from '../value-objects/ExternalRatingProvenance';
/**
* Test suite for IExternalGameRatingRepository interface
* Test suite for ExternalGameRatingRepository interface
* This tests the contract that all implementations must satisfy
*/
describe('IExternalGameRatingRepository', () => {
describe('ExternalGameRatingRepository', () => {
// Mock implementation for testing
class MockExternalGameRatingRepository implements ExternalGameRatingRepository {
private profiles: Map<string, ExternalGameRatingProfile> = new Map();
@@ -105,7 +105,7 @@ describe('IExternalGameRatingRepository', () => {
}
}
let repository: IExternalGameRatingRepository;
let repository: ExternalGameRatingRepository;
beforeEach(() => {
repository = new MockExternalGameRatingRepository();

View File

@@ -1,7 +1,7 @@
import { ExternalGameRatingProfile } from '../entities/ExternalGameRatingProfile';
/**
* Repository Interface: IExternalGameRatingRepository
* Repository Interface: ExternalGameRatingRepository
*
* Port for persisting and retrieving external game rating profiles.
* Store/display only, no compute.

View File

@@ -1,5 +1,5 @@
/**
* Unit tests for IRatingEventRepository
* Unit tests for RatingEventRepository
*/
import { RatingEvent } from '../entities/RatingEvent';
@@ -110,7 +110,7 @@ class InMemoryRatingEventRepository implements RatingEventRepository {
}
}
describe('IRatingEventRepository', () => {
describe('RatingEventRepository', () => {
let repository: InMemoryRatingEventRepository;
beforeEach(() => {

View File

@@ -1,5 +1,5 @@
/**
* Repository Interface: IRatingEventRepository
* Repository Interface: RatingEventRepository
*
* Port for persisting and retrieving rating events (ledger).
* Events are immutable and ordered by occurredAt for deterministic snapshot computation.

View File

@@ -1,5 +1,5 @@
/**
* Repository Interface: ISponsorAccountRepository
* Repository Interface: SponsorAccountRepository
*
* Defines persistence operations for SponsorAccount entities.
*/

View File

@@ -1,5 +1,5 @@
/**
* Unit tests for IUserRatingRepository
* Unit tests for UserRatingRepository
*/
import { UserRating } from '../value-objects/UserRating';
@@ -19,7 +19,7 @@ class InMemoryUserRatingRepository implements UserRatingRepository {
}
}
describe('IUserRatingRepository', () => {
describe('UserRatingRepository', () => {
let repository: InMemoryUserRatingRepository;
beforeEach(() => {

View File

@@ -1,5 +1,5 @@
/**
* Repository Interface: IUserRatingRepository
* Repository Interface: UserRatingRepository
*
* Port for persisting and retrieving UserRating snapshots.
* Snapshots are derived from rating events for fast reads.

View File

@@ -1,5 +1,5 @@
/**
* Domain Repository: IUserRepository
* Domain Repository: UserRepository
*
* Repository interface for User entity operations.
*/

View File

@@ -1,4 +1,4 @@
import type { DomainService } from '@core/shared/domain';
import type { DomainService } from '@core/shared/domain/Service';
import type { UserRatingRepository } from '../repositories/UserRatingRepository';
import type { RatingEventRepository } from '../repositories/RatingEventRepository';
import { RatingEventFactory } from './RatingEventFactory';
@@ -21,8 +21,8 @@ export class RatingUpdateService implements DomainService {
readonly serviceName = 'RatingUpdateService';
constructor(
private readonly userRatingRepository: IUserRatingRepository,
private readonly ratingEventRepository: IRatingEventRepository
private readonly userRatingRepository: UserRatingRepository,
private readonly ratingEventRepository: RatingEventRepository
) {}
/**

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
/**
@@ -68,7 +68,7 @@ export class AdminTrustReasonCode implements ValueObject<AdminTrustReasonCodePro
return { value: this.value };
}
equals(other: IValueObject<AdminTrustReasonCodeProps>): boolean {
equals(other: ValueObject<AdminTrustReasonCodeProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
/**
@@ -80,7 +80,7 @@ export class DrivingReasonCode implements ValueObject<DrivingReasonCodeProps> {
return { value: this.value };
}
equals(other: IValueObject<DrivingReasonCodeProps>): boolean {
equals(other: ValueObject<DrivingReasonCodeProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import type { EmailValidationResult } from '../types/EmailAddress';
import { validateEmail, isDisposableEmail } from '../types/EmailAddress';
@@ -35,7 +35,7 @@ export class EmailAddress implements ValueObject<EmailAddressProps> {
return this.props.value;
}
equals(other: IValueObject<EmailAddressProps>): boolean {
equals(other: ValueObject<EmailAddressProps>): boolean {
return this.props.value === other.props.value;
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { GameKey } from './GameKey';
@@ -40,7 +40,7 @@ export class ExternalRating implements ValueObject<ExternalRatingProps> {
};
}
equals(other: IValueObject<ExternalRatingProps>): boolean {
equals(other: ValueObject<ExternalRatingProps>): boolean {
return (
this.gameKey.equals(other.props.gameKey) &&
this.type === other.props.type &&

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
export interface ExternalRatingProvenanceProps {
@@ -45,7 +45,7 @@ export class ExternalRatingProvenance implements ValueObject<ExternalRatingProve
};
}
equals(other: IValueObject<ExternalRatingProvenanceProps>): boolean {
equals(other: ValueObject<ExternalRatingProvenanceProps>): boolean {
return (
this.source === other.props.source &&
this.lastSyncedAt.getTime() === other.props.lastSyncedAt.getTime() &&

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
export interface GameKeyProps {
@@ -33,7 +33,7 @@ export class GameKey implements ValueObject<GameKeyProps> {
return { value: this.value };
}
equals(other: IValueObject<GameKeyProps>): boolean {
equals(other: ValueObject<GameKeyProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,5 +1,5 @@
import bcrypt from 'bcrypt';
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
export interface PasswordHashProps {
value: string;
@@ -35,7 +35,7 @@ export class PasswordHash implements ValueObject<PasswordHashProps> {
return bcrypt.compare(plain, this.props.value);
}
equals(other: IValueObject<PasswordHashProps>): boolean {
equals(other: ValueObject<PasswordHashProps>): boolean {
return this.props.value === other.props.value;
}
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
export interface RatingDeltaProps {
@@ -30,7 +30,7 @@ export class RatingDelta implements ValueObject<RatingDeltaProps> {
return { value: this.value };
}
equals(other: IValueObject<RatingDeltaProps>): boolean {
equals(other: ValueObject<RatingDeltaProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
export interface RatingDimensionKeyProps {
@@ -39,7 +39,7 @@ export class RatingDimensionKey implements ValueObject<RatingDimensionKeyProps>
return { value: this.value };
}
equals(other: IValueObject<RatingDimensionKeyProps>): boolean {
equals(other: ValueObject<RatingDimensionKeyProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { v4 as uuidv4 } from 'uuid';
@@ -38,7 +38,7 @@ export class RatingEventId implements ValueObject<RatingEventIdProps> {
return { value: this.value };
}
equals(other: IValueObject<RatingEventIdProps>): boolean {
equals(other: ValueObject<RatingEventIdProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
export type RatingReferenceType = 'race' | 'penalty' | 'vote' | 'adminAction';
@@ -38,7 +38,7 @@ export class RatingReference implements ValueObject<RatingReferenceProps> {
return { type: this.type, id: this.id };
}
equals(other: IValueObject<RatingReferenceProps>): boolean {
equals(other: ValueObject<RatingReferenceProps>): boolean {
return this.type === other.props.type && this.id === other.props.id;
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
export interface RatingValueProps {
@@ -30,7 +30,7 @@ export class RatingValue implements ValueObject<RatingValueProps> {
return { value: this.value };
}
equals(other: IValueObject<RatingValueProps>): boolean {
equals(other: ValueObject<RatingValueProps>): boolean {
return this.value === other.props.value;
}

View File

@@ -1,5 +1,5 @@
import { v4 as uuidv4 } from 'uuid';
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
export interface UserIdProps {
value: string;
@@ -31,7 +31,7 @@ export class UserId implements ValueObject<UserIdProps> {
return this.props.value;
}
public equals(other: IValueObject<UserIdProps>): boolean {
public equals(other: ValueObject<UserIdProps>): boolean {
return this.props.value === other.props.value;
}
}

View File

@@ -1,4 +1,4 @@
import type { ValueObject } from '@core/shared/domain';
import type { ValueObject } from '@core/shared/domain/ValueObject';
/**
* Value Object: UserRating
@@ -111,7 +111,7 @@ export class UserRating implements ValueObject<UserRatingProps> {
return new UserRating(props);
}
equals(other: IValueObject<UserRatingProps>): boolean {
equals(other: ValueObject<UserRatingProps>): boolean {
return this.props.userId === other.props.userId;
}

View File

@@ -39,7 +39,7 @@ describe('DeleteMediaUseCase', () => {
} as unknown as Logger;
useCase = new DeleteMediaUseCase(
mediaRepo as unknown as IMediaRepository,
mediaRepo as unknown as MediaRepository,
mediaStorage as unknown as MediaStoragePort,
logger,
);

View File

@@ -26,7 +26,7 @@ export type DeleteMediaApplicationError = ApplicationErrorCode<
export class DeleteMediaUseCase {
constructor(
private readonly mediaRepo: IMediaRepository,
private readonly mediaRepo: MediaRepository,
private readonly mediaStorage: MediaStoragePort,
private readonly logger: Logger,
) {}

View File

@@ -31,7 +31,7 @@ describe('GetAvatarUseCase', () => {
} as unknown as Logger;
useCase = new GetAvatarUseCase(
avatarRepo as unknown as IAvatarRepository,
avatarRepo as unknown as AvatarRepository,
logger,
);
});

View File

@@ -29,7 +29,7 @@ export type GetAvatarApplicationError = ApplicationErrorCode<
export class GetAvatarUseCase {
constructor(
private readonly avatarRepo: IAvatarRepository,
private readonly avatarRepo: AvatarRepository,
private readonly logger: Logger,
) {}

View File

@@ -29,7 +29,7 @@ describe('GetMediaUseCase', () => {
} as unknown as Logger;
useCase = new GetMediaUseCase(
mediaRepo as unknown as IMediaRepository,
mediaRepo as unknown as MediaRepository,
logger,
);
});

View File

@@ -30,7 +30,7 @@ export type GetMediaErrorCode = 'MEDIA_NOT_FOUND' | 'REPOSITORY_ERROR';
export class GetMediaUseCase {
constructor(
private readonly mediaRepo: IMediaRepository,
private readonly mediaRepo: MediaRepository,
private readonly logger: Logger,
) {}

View File

@@ -43,7 +43,7 @@ describe('RequestAvatarGenerationUseCase', () => {
} as unknown as Logger;
useCase = new RequestAvatarGenerationUseCase(
avatarRepo as unknown as IAvatarGenerationRepository,
avatarRepo as unknown as AvatarGenerationRepository,
faceValidation as unknown as FaceValidationPort,
avatarGeneration as unknown as AvatarGenerationPort,
logger,

View File

@@ -38,7 +38,7 @@ export type RequestAvatarGenerationApplicationError = ApplicationErrorCode<
export class RequestAvatarGenerationUseCase {
constructor(
private readonly avatarRepo: IAvatarGenerationRepository,
private readonly avatarRepo: AvatarGenerationRepository,
private readonly faceValidation: FaceValidationPort,
private readonly avatarGeneration: AvatarGenerationPort,
private readonly logger: Logger,

Some files were not shown because too many files have changed in this diff Show More