This commit is contained in:
2025-12-29 22:27:33 +01:00
parent 3f610c1cb6
commit 7a853d4e43
96 changed files with 14790 additions and 111 deletions

View File

@@ -0,0 +1,73 @@
/**
* DTOs for Admin Vote Session Use Cases
*/
/**
* Input for OpenAdminVoteSessionUseCase
*/
export interface OpenAdminVoteSessionInput {
voteSessionId: string;
leagueId: string;
adminId: string;
startDate: string; // ISO date string
endDate: string; // ISO date string
eligibleVoters: string[]; // User IDs
}
/**
* Output for OpenAdminVoteSessionUseCase
*/
export interface OpenAdminVoteSessionOutput {
success: boolean;
voteSessionId: string;
errors?: string[];
}
/**
* Input for CastAdminVoteUseCase
*/
export interface CastAdminVoteInput {
voteSessionId: string;
voterId: string;
positive: boolean; // true = positive vote, false = negative vote
votedAt?: string; // ISO date string (optional, defaults to now)
}
/**
* Output for CastAdminVoteUseCase
*/
export interface CastAdminVoteOutput {
success: boolean;
voteSessionId: string;
voterId: string;
errors?: string[];
}
/**
* Input for CloseAdminVoteSessionUseCase
*/
export interface CloseAdminVoteSessionInput {
voteSessionId: string;
adminId: string; // For validation
}
/**
* Output for CloseAdminVoteSessionUseCase
*/
export interface CloseAdminVoteSessionOutput {
success: boolean;
voteSessionId: string;
outcome?: {
percentPositive: number;
count: {
positive: number;
negative: number;
total: number;
};
eligibleVoterCount: number;
participationRate: number;
outcome: 'positive' | 'negative' | 'tie';
};
eventsCreated?: number;
errors?: string[];
}

View File

@@ -0,0 +1,18 @@
/**
* DTO: CreateRatingEventDto
*
* Input for creating a rating event from external sources
*/
export interface CreateRatingEventDto {
userId: string;
dimension: string;
delta: number;
weight?: number;
sourceType: 'race' | 'penalty' | 'vote' | 'adminAction' | 'manualAdjustment';
sourceId: string;
reasonCode: string;
reasonSummary: string;
reasonDetails?: Record<string, unknown>;
occurredAt?: string; // ISO date string
}

View File

@@ -0,0 +1,45 @@
/**
* DTO: EligibilityFilterDto
*
* DSL-based eligibility filter for league/competition rules.
* Example: "platform.driving >= 55 OR external.iracing.iRating between 2000 2500"
*/
export interface EligibilityFilterDto {
/**
* DSL expression for eligibility rules
* Supports:
* - Comparisons: >=, <=, >, <, =, !=, between
* - Logical: AND, OR, NOT
* - Dimensions: platform.{dimension}, external.{game}.{type}
*
* Examples:
* - "platform.driving >= 55"
* - "external.iracing.iRating between 2000 2500"
* - "platform.driving >= 55 AND external.iracing.iRating >= 2000"
* - "platform.driving >= 55 OR external.iracing.iRating between 2000 2500"
*/
dsl: string;
/**
* Optional context for evaluation
*/
context?: {
userId?: string;
leagueId?: string;
[key: string]: unknown;
};
}
export interface EligibilityCondition {
target: 'platform' | 'external';
dimension?: string; // e.g., 'driving', 'admin', 'iRating'
game?: string; // e.g., 'iracing'
operator: string; // '>=', '<=', '>', '<', '=', '!=', 'between'
expected: number | [number, number];
}
export interface ParsedEligibilityFilter {
conditions: EligibilityCondition[];
logicalOperator: 'AND' | 'OR';
}

View File

@@ -0,0 +1,68 @@
/**
* DTO: EvaluationResultDto
*
* Result of DSL eligibility evaluation with explainable reasons.
*/
export interface EvaluationReason {
/**
* What was evaluated
*/
target: string; // e.g., 'platform.driving', 'external.iracing.iRating'
/**
* Operator used
*/
operator: string; // e.g., '>=', 'between'
/**
* Expected threshold/range
*/
expected: number | [number, number];
/**
* Actual value found
*/
actual: number;
/**
* Whether this condition failed
*/
failed: boolean;
/**
* Human-readable explanation
*/
message?: string;
}
export interface EvaluationResultDto {
/**
* Overall eligibility status
*/
eligible: boolean;
/**
* Individual condition results
*/
reasons: EvaluationReason[];
/**
* Summary message
*/
summary: string;
/**
* Timestamp of evaluation
*/
evaluatedAt: string; // ISO date string
/**
* Optional metadata
*/
metadata?: {
userId?: string;
filter?: string;
[key: string]: unknown;
};
}

View File

@@ -0,0 +1,51 @@
/**
* DTO: LedgerEntryDto
*
* Simplified rating event for ledger display/query.
* Pragmatic read model - direct repo DTOs, no domain logic.
*/
export interface LedgerEntryDto {
id: string;
userId: string;
dimension: string; // 'driving', 'admin', 'steward', 'trust', 'fairness'
delta: number; // positive or negative change
weight?: number;
occurredAt: string; // ISO date string
createdAt: string; // ISO date string
source: {
type: 'race' | 'penalty' | 'vote' | 'adminAction' | 'manualAdjustment';
id: string;
};
reason: {
code: string;
summary: string;
details: Record<string, unknown>;
};
visibility: {
public: boolean;
redactedFields: string[];
};
}
export interface LedgerFilter {
dimensions?: string[]; // Filter by dimension keys
sourceTypes?: ('race' | 'penalty' | 'vote' | 'adminAction' | 'manualAdjustment')[];
from?: string; // ISO date string
to?: string; // ISO date string
reasonCodes?: string[];
}
export interface PaginatedLedgerResult {
entries: LedgerEntryDto[];
pagination: {
total: number;
limit: number;
offset: number;
hasMore: boolean;
nextOffset?: number | null;
};
}

View File

@@ -0,0 +1,56 @@
/**
* DTO: RatingSummaryDto
*
* Comprehensive rating summary with platform and external game ratings.
* Pragmatic read model - direct repo DTOs, no domain logic.
*/
export interface PlatformRatingDimension {
value: number;
confidence: number;
sampleSize: number;
trend: 'rising' | 'stable' | 'falling';
lastUpdated: string; // ISO date string
}
export interface ExternalGameRating {
gameKey: string;
type: string;
value: number;
lastUpdated: string; // ISO date string
}
export interface ExternalGameRatings {
gameKey: string;
ratings: Map<string, number>; // type -> value
source: string;
lastSyncedAt: string; // ISO date string
verified: boolean;
}
export interface RatingSummaryDto {
userId: string;
// Platform ratings (from internal calculations)
platform: {
driving: PlatformRatingDimension;
admin: PlatformRatingDimension;
steward: PlatformRatingDimension;
trust: PlatformRatingDimension;
fairness: PlatformRatingDimension;
overallReputation: number;
};
// External game ratings (from third-party sources)
external: {
// gameKey -> { type -> value }
[gameKey: string]: {
[type: string]: number;
};
};
// Timestamps
createdAt: string; // ISO date string
updatedAt: string; // ISO date string
lastRatingEventAt?: string; // ISO date string (optional)
}

View File

@@ -0,0 +1,17 @@
/**
* DTO: RecordRaceRatingEventsDto
*
* Input for RecordRaceRatingEventsUseCase
*/
export interface RecordRaceRatingEventsInput {
raceId: string;
}
export interface RecordRaceRatingEventsOutput {
success: boolean;
raceId: string;
eventsCreated: number;
driversUpdated: string[];
errors: string[];
}

View File

@@ -0,0 +1,32 @@
/**
* DTOs for UpsertExternalGameRatingUseCase
*/
export interface UpsertExternalGameRatingInput {
userId: string;
gameKey: string;
ratings: Array<{
type: string;
value: number;
}>;
provenance: {
source: string;
lastSyncedAt: string; // ISO 8601
verified?: boolean;
};
}
export interface UpsertExternalGameRatingOutput {
success: boolean;
profile: {
userId: string;
gameKey: string;
ratingCount: number;
ratingTypes: string[];
source: string;
lastSyncedAt: string;
verified: boolean;
};
action: 'created' | 'updated';
errors?: string[];
}

View File

@@ -0,0 +1,26 @@
/**
* DTO: UserRatingDto
*
* Output for user rating snapshot
*/
export interface RatingDimensionDto {
value: number;
confidence: number;
sampleSize: number;
trend: 'rising' | 'stable' | 'falling';
lastUpdated: string; // ISO date string
}
export interface UserRatingDto {
userId: string;
driver: RatingDimensionDto;
admin: RatingDimensionDto;
steward: RatingDimensionDto;
trust: RatingDimensionDto;
fairness: RatingDimensionDto;
overallReputation: number;
calculatorVersion?: string;
createdAt: string; // ISO date string
updatedAt: string; // ISO date string
}

View File

@@ -0,0 +1,13 @@
/**
* DTOs Index
*
* Export all DTO types
*/
export type { RatingSummaryDto, PlatformRatingDimension, ExternalGameRating, ExternalGameRatings } from './RatingSummaryDto';
export type { LedgerEntryDto, LedgerFilter, PaginatedLedgerResult } from './LedgerEntryDto';
export type { EligibilityFilterDto, EligibilityCondition, ParsedEligibilityFilter } from './EligibilityFilterDto';
export type { EvaluationResultDto, EvaluationReason } from './EvaluationResultDto';
// Existing DTOs
export type { UserRatingDto, RatingDimensionDto } from './UserRatingDto';