website refactor

This commit is contained in:
2026-01-16 19:46:49 +01:00
parent 26fc726556
commit 77a923e6a3
563 changed files with 1643 additions and 2259 deletions

View File

@@ -1,5 +1,5 @@
import { IdentityDomainInvariantError, IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { AdminVoteSession } from './AdminVoteSession';
import { IdentityDomainValidationError, IdentityDomainInvariantError } from '../errors/IdentityDomainError';
describe('AdminVoteSession', () => {
const now = new Date('2025-01-01T00:00:00Z');

View File

@@ -1,9 +1,9 @@
import { ExternalGameRatingProfile } from './ExternalGameRatingProfile';
import { UserId } from '../value-objects/UserId';
import { GameKey } from '../value-objects/GameKey';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { ExternalRating } from '../value-objects/ExternalRating';
import { ExternalRatingProvenance } from '../value-objects/ExternalRatingProvenance';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { GameKey } from '../value-objects/GameKey';
import { UserId } from '../value-objects/UserId';
import { ExternalGameRatingProfile } from './ExternalGameRatingProfile';
describe('ExternalGameRatingProfile', () => {
let userId: UserId;

View File

@@ -1,9 +1,9 @@
import { Entity } from '@core/shared/domain/Entity';
import { UserId } from '../value-objects/UserId';
import { GameKey } from '../value-objects/GameKey';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { ExternalRating } from '../value-objects/ExternalRating';
import { ExternalRatingProvenance } from '../value-objects/ExternalRatingProvenance';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { GameKey } from '../value-objects/GameKey';
import { UserId } from '../value-objects/UserId';
export interface ExternalGameRatingProfileProps {
userId: UserId;

View File

@@ -1,8 +1,8 @@
import { RatingEvent } from './RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { IdentityDomainInvariantError, IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { RatingDelta } from '../value-objects/RatingDelta';
import { IdentityDomainValidationError, IdentityDomainInvariantError } from '../errors/IdentityDomainError';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingEvent } from './RatingEvent';
describe('RatingEvent', () => {
const validProps = {

View File

@@ -1,4 +1,5 @@
import * as mod from '@core/identity/domain/entities/SponsorAccount';
import { describe, expect, it } from 'vitest';
describe('identity/domain/entities/SponsorAccount.ts', () => {
it('imports', () => {

View File

@@ -5,9 +5,9 @@
* Separate from the racing domain's Sponsor entity which holds business data.
*/
import { UserId } from '../value-objects/UserId';
import type { EmailValidationResult } from '../types/EmailAddress';
import { validateEmail } from '../types/EmailAddress';
import { UserId } from '../value-objects/UserId';
export interface SponsorAccountProps {
id: UserId;

View File

@@ -1,4 +1,5 @@
import * as mod from '@core/identity/domain/entities/User';
import { describe, expect, it } from 'vitest';
describe('identity/domain/entities/User.ts', () => {
it('imports', () => {

View File

@@ -1,8 +1,8 @@
import { StoredUser } from '../repositories/UserRepository';
import type { EmailValidationResult } from '../types/EmailAddress';
import { validateEmail } from '../types/EmailAddress';
import { UserId } from '../value-objects/UserId';
import { PasswordHash } from '../value-objects/PasswordHash';
import { StoredUser } from '../repositories/UserRepository';
import { UserId } from '../value-objects/UserId';
export interface UserProps {
id: UserId;

View File

@@ -1,4 +1,5 @@
import * as mod from '@core/identity/domain/entities/UserAchievement';
import { describe, expect, it } from 'vitest';
describe('identity/domain/entities/UserAchievement.ts', () => {
it('imports', () => {

View File

@@ -1,4 +1,4 @@
import type { DomainError, CommonDomainErrorKind } from '@core/shared/errors/DomainError';
import type { CommonDomainErrorKind, DomainError } 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 @@
import { EmailAddress } from '../value-objects/EmailAddress';
import { User } from '../entities/User';
import { EmailAddress } from '../value-objects/EmailAddress';
/**
* Domain Repository: AuthRepository

View File

@@ -1,10 +1,10 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { ExternalGameRatingRepository } from './ExternalGameRatingRepository';
import { beforeEach, describe, expect, it } from 'vitest';
import { ExternalGameRatingProfile } from '../entities/ExternalGameRatingProfile';
import { UserId } from '../value-objects/UserId';
import { GameKey } from '../value-objects/GameKey';
import { ExternalRating } from '../value-objects/ExternalRating';
import { ExternalRatingProvenance } from '../value-objects/ExternalRatingProvenance';
import { GameKey } from '../value-objects/GameKey';
import { UserId } from '../value-objects/UserId';
import { ExternalGameRatingRepository } from './ExternalGameRatingRepository';
/**
* Test suite for ExternalGameRatingRepository interface

View File

@@ -3,10 +3,10 @@
*/
import { RatingEvent } from '../entities/RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingDelta } from '../value-objects/RatingDelta';
import { RatingEventRepository, FindByUserIdOptions, PaginatedQueryOptions, PaginatedResult } from './RatingEventRepository';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingEventId } from '../value-objects/RatingEventId';
import { FindByUserIdOptions, PaginatedQueryOptions, PaginatedResult, RatingEventRepository } from './RatingEventRepository';
// In-memory test implementation
class InMemoryRatingEventRepository implements RatingEventRepository {

View File

@@ -1,8 +1,8 @@
import { AdminTrustRatingCalculator, VoteOutcomeInput, SystemSignalInput } from './AdminTrustRatingCalculator';
import { RatingEvent } from '../entities/RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingDelta } from '../value-objects/RatingDelta';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingEventId } from '../value-objects/RatingEventId';
import { AdminTrustRatingCalculator, SystemSignalInput, VoteOutcomeInput } from './AdminTrustRatingCalculator';
describe('AdminTrustRatingCalculator', () => {
describe('calculate', () => {

View File

@@ -1,5 +1,5 @@
import { RatingEvent } from '../entities/RatingEvent';
import { AdminVoteOutcome } from '../entities/AdminVoteSession';
import { RatingEvent } from '../entities/RatingEvent';
import { RatingDelta } from '../value-objects/RatingDelta';
/**

View File

@@ -1,8 +1,8 @@
import { DrivingRatingCalculator, DrivingRaceFactsDto } from './DrivingRatingCalculator';
import { RatingEvent } from '../entities/RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingDelta } from '../value-objects/RatingDelta';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingEventId } from '../value-objects/RatingEventId';
import { DrivingRaceFactsDto, DrivingRatingCalculator } from './DrivingRatingCalculator';
describe('DrivingRatingCalculator', () => {
describe('calculateFromRaceFacts', () => {

View File

@@ -56,7 +56,6 @@ export class DrivingRatingCalculator {
// Incident penalty per incident
private static readonly INCIDENT_PENALTY = -5;
private static readonly MAJOR_INCIDENT_PENALTY = -15;
/**
* Calculate driving rating deltas from race facts

View File

@@ -2,8 +2,8 @@
* Tests for EligibilityEvaluator
*/
import { EligibilityEvaluator, RatingData } from './EligibilityEvaluator';
import { EligibilityFilterDto } from '../types/Eligibility';
import { EligibilityEvaluator, RatingData } from './EligibilityEvaluator';
describe('EligibilityEvaluator', () => {
let evaluator: EligibilityEvaluator;

View File

@@ -6,12 +6,12 @@
* Provides explainable results with detailed reasons.
*/
import {
EvaluationResultDto,
EvaluationReason,
EligibilityFilterDto,
ParsedEligibilityFilter,
EligibilityCondition
import {
EligibilityCondition,
EligibilityFilterDto,
EvaluationReason,
EvaluationResultDto,
ParsedEligibilityFilter
} from '../types/Eligibility';
export interface RatingData {

View File

@@ -1,4 +1,4 @@
import { RatingEventFactory, RaceFactsDto } from './RatingEventFactory';
import { RaceFactsDto, RatingEventFactory } from './RatingEventFactory';
describe('RatingEventFactory', () => {
describe('createFromRaceFinish', () => {

View File

@@ -1,9 +1,9 @@
import { RatingEvent } from '../entities/RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingDelta } from '../value-objects/RatingDelta';
import { DrivingReasonCode } from '../value-objects/DrivingReasonCode';
import { AdminTrustReasonCode } from '../value-objects/AdminTrustReasonCode';
import { DrivingReasonCode } from '../value-objects/DrivingReasonCode';
import { RatingDelta } from '../value-objects/RatingDelta';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingEventId } from '../value-objects/RatingEventId';
// Existing interfaces
interface RaceFinishInput {

View File

@@ -1,8 +1,8 @@
import { RatingSnapshotCalculator } from './RatingSnapshotCalculator';
import { RatingEvent } from '../entities/RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingDelta } from '../value-objects/RatingDelta';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingSnapshotCalculator } from './RatingSnapshotCalculator';
describe('RatingSnapshotCalculator', () => {
describe('calculate', () => {

View File

@@ -1,5 +1,5 @@
import { UserRating } from '../value-objects/UserRating';
import { RatingEvent } from '../entities/RatingEvent';
import { UserRating } from '../value-objects/UserRating';
/**
* Domain Service: RatingSnapshotCalculator

View File

@@ -1,12 +1,12 @@
import { describe, it, expect, beforeEach, vi, type Mock } from 'vitest';
import { RatingUpdateService } from './RatingUpdateService';
import type { UserRatingRepository } from '../repositories/UserRatingRepository';
import type { RatingEventRepository } from '../repositories/RatingEventRepository';
import { UserRating } from '../value-objects/UserRating';
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import { RatingEvent } from '../entities/RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import type { RatingEventRepository } from '../repositories/RatingEventRepository';
import type { UserRatingRepository } from '../repositories/UserRatingRepository';
import { RatingDelta } from '../value-objects/RatingDelta';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingEventId } from '../value-objects/RatingEventId';
import { UserRating } from '../value-objects/UserRating';
import { RatingUpdateService } from './RatingUpdateService';
describe('RatingUpdateService - Slice 7 Evolution', () => {
let service: RatingUpdateService;

View File

@@ -1,12 +1,12 @@
import type { DomainService } from '@core/shared/domain/Service';
import type { UserRatingRepository } from '../repositories/UserRatingRepository';
import { RatingEvent } from '../entities/RatingEvent';
import type { RatingEventRepository } from '../repositories/RatingEventRepository';
import type { UserRatingRepository } from '../repositories/UserRatingRepository';
import { RatingDelta } from '../value-objects/RatingDelta';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingEventFactory } from './RatingEventFactory';
import { RatingSnapshotCalculator } from './RatingSnapshotCalculator';
import { RatingEvent } from '../entities/RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingDelta } from '../value-objects/RatingDelta';
/**
* Domain Service: RatingUpdateService
@@ -112,20 +112,6 @@ export class RatingUpdateService implements DomainService {
}
}
/**
* Update individual driver rating based on race result (LEGACY - DEPRECATED)
* Kept for backward compatibility but now uses event-based approach
*/
private async updateDriverRating(result: {
driverId: string;
position: number;
totalDrivers: number;
incidents: number;
startPosition: number;
}): Promise<void> {
// Delegate to new event-based approach
await this.updateDriverRatingsAfterRace([result]);
}
/**
* Update trust score based on sportsmanship actions (USES LEDGER)
@@ -193,34 +179,5 @@ export class RatingUpdateService implements DomainService {
await this.userRatingRepository.save(snapshot);
}
/**
* Calculate performance score based on finishing position and field strength
* (Utility method kept for reference, but now handled by RatingEventFactory)
*/
private calculatePerformanceScore(
position: number,
totalDrivers: number,
startPosition: number
): number {
const positionScore = ((totalDrivers - position + 1) / totalDrivers) * 100;
const positionsGained = startPosition - position;
const gainBonus = Math.max(0, positionsGained * 2);
const fieldStrengthMultiplier = 0.8 + (totalDrivers / 50);
const rawScore = (positionScore + gainBonus) * fieldStrengthMultiplier;
return Math.max(0, Math.min(100, rawScore));
}
/**
* Calculate fairness score based on incident involvement
* (Utility method kept for reference, but now handled by RatingEventFactory)
*/
private calculateFairnessScore(incidents: number, totalDrivers: number): number {
let fairnessScore = 100;
fairnessScore -= incidents * 15;
const incidentRate = incidents / totalDrivers;
if (incidentRate > 0.5) {
fairnessScore -= 20;
}
return Math.max(0, Math.min(100, fairnessScore));
}
}

View File

@@ -1,6 +1,6 @@
import { AdminTrustReasonCode, type AdminTrustReasonCodeValue } from './AdminTrustReasonCode';
import { describe, expect, it } from 'vitest';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { describe, it, expect } from 'vitest';
import { AdminTrustReasonCode, type AdminTrustReasonCodeValue } from './AdminTrustReasonCode';
describe('AdminTrustReasonCode', () => {
describe('create', () => {

View File

@@ -1,6 +1,6 @@
import { DrivingReasonCode, type DrivingReasonCodeValue } from './DrivingReasonCode';
import { describe, expect, it } from 'vitest';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { describe, it, expect } from 'vitest';
import { DrivingReasonCode, type DrivingReasonCodeValue } from './DrivingReasonCode';
describe('DrivingReasonCode', () => {
describe('create', () => {

View File

@@ -1,4 +1,5 @@
import * as mod from '@core/identity/domain/value-objects/EmailAddress';
import { describe, expect, it } from 'vitest';
describe('identity/domain/value-objects/EmailAddress.ts', () => {
it('imports', () => {

View File

@@ -1,6 +1,6 @@
import type { ValueObject } from '@core/shared/domain/ValueObject';
import type { EmailValidationResult } from '../types/EmailAddress';
import { validateEmail, isDisposableEmail } from '../types/EmailAddress';
import { isDisposableEmail, validateEmail } from '../types/EmailAddress';
export interface EmailAddressProps {
value: string;
@@ -44,5 +44,6 @@ export class EmailAddress implements ValueObject<EmailAddressProps> {
}
}
export { isDisposableEmail, validateEmail } from '../types/EmailAddress';
export type { EmailValidationResult } from '../types/EmailAddress';
export { validateEmail, isDisposableEmail } from '../types/EmailAddress';

View File

@@ -1,6 +1,6 @@
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { ExternalRating } from './ExternalRating';
import { GameKey } from './GameKey';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
describe('ExternalRating', () => {
describe('create', () => {

View File

@@ -1,5 +1,5 @@
import { ExternalRatingProvenance } from './ExternalRatingProvenance';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { ExternalRatingProvenance } from './ExternalRatingProvenance';
describe('ExternalRatingProvenance', () => {
describe('create', () => {

View File

@@ -1,5 +1,5 @@
import { GameKey } from './GameKey';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { GameKey } from './GameKey';
describe('GameKey', () => {
describe('create', () => {

View File

@@ -1,4 +1,5 @@
import * as mod from '@core/identity/domain/value-objects/PasswordHash';
import { describe, expect, it } from 'vitest';
describe('identity/domain/value-objects/PasswordHash.ts', () => {
it('imports', () => {

View File

@@ -1,5 +1,5 @@
import bcrypt from 'bcrypt';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import bcrypt from 'bcrypt';
export interface PasswordHashProps {
value: string;

View File

@@ -1,5 +1,5 @@
import { RatingDelta } from './RatingDelta';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { RatingDelta } from './RatingDelta';
describe('RatingDelta', () => {
describe('create', () => {

View File

@@ -1,5 +1,5 @@
import { RatingDimensionKey } from './RatingDimensionKey';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { RatingDimensionKey } from './RatingDimensionKey';
describe('RatingDimensionKey', () => {
describe('create', () => {

View File

@@ -1,5 +1,5 @@
import { RatingEventId } from './RatingEventId';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { RatingEventId } from './RatingEventId';
describe('RatingEventId', () => {
describe('create', () => {

View File

@@ -1,6 +1,6 @@
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { v4 as uuidv4 } from 'uuid';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
export interface RatingEventIdProps {
value: string;

View File

@@ -1,5 +1,5 @@
import { RatingReference } from './RatingReference';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { RatingReference } from './RatingReference';
describe('RatingReference', () => {
describe('create', () => {

View File

@@ -1,5 +1,5 @@
import { RatingValue } from './RatingValue';
import { IdentityDomainValidationError } from '../errors/IdentityDomainError';
import { RatingValue } from './RatingValue';
describe('RatingValue', () => {
describe('create', () => {

View File

@@ -1,4 +1,5 @@
import * as mod from '@core/identity/domain/value-objects/UserId';
import { describe, expect, it } from 'vitest';
describe('identity/domain/value-objects/UserId.ts', () => {
it('imports', () => {

View File

@@ -1,5 +1,5 @@
import { v4 as uuidv4 } from 'uuid';
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { v4 as uuidv4 } from 'uuid';
export interface UserIdProps {
value: string;

View File

@@ -1,4 +1,5 @@
import * as mod from '@core/identity/domain/value-objects/UserRating';
import { describe, expect, it } from 'vitest';
describe('identity/domain/value-objects/UserRating.ts', () => {
it('imports', () => {