/** * Application Use Case: ReviewProtestUseCase * * Allows a steward to review a protest and make a decision (uphold or dismiss). */ import type { IProtestRepository } from '../../domain/repositories/IProtestRepository'; import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'; import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository'; import { Result } from '@core/shared/application/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; export interface ReviewProtestCommand { protestId: string; stewardId: string; decision: 'uphold' | 'dismiss'; decisionNotes: string; } export class ReviewProtestUseCase { constructor( private readonly protestRepository: IProtestRepository, private readonly raceRepository: IRaceRepository, private readonly leagueMembershipRepository: ILeagueMembershipRepository, ) {} async execute(command: ReviewProtestCommand): Promise>> { // Load the protest const protest = await this.protestRepository.findById(command.protestId); if (!protest) { return Result.err({ code: 'PROTEST_NOT_FOUND' }); } // Load the race to get league ID const race = await this.raceRepository.findById(protest.raceId); if (!race) { return Result.err({ code: 'RACE_NOT_FOUND' }); } // Validate steward has authority (owner or admin of the league) const memberships = await this.leagueMembershipRepository.getLeagueMembers(race.leagueId); const stewardMembership = memberships.find( m => m.driverId === command.stewardId && m.status === 'active' ); if (!stewardMembership || (stewardMembership.role !== 'owner' && stewardMembership.role !== 'admin')) { return Result.err({ code: 'NOT_LEAGUE_ADMIN' }); } // Apply the decision let updatedProtest; if (command.decision === 'uphold') { updatedProtest = protest.uphold(command.stewardId, command.decisionNotes); } else { updatedProtest = protest.dismiss(command.stewardId, command.decisionNotes); } await this.protestRepository.update(updatedProtest); return Result.ok(undefined); } }