/** * Domain Entity: Team * * Represents a racing team in the GridPilot platform. * Implements the shared IEntity contract and encapsulates * basic invariants around identity and core properties. */ import type { IEntity } from '@gridpilot/shared/domain'; import { RacingDomainValidationError } from '../errors/RacingDomainError'; export class Team implements IEntity { readonly id: string; readonly name: string; readonly tag: string; readonly description: string; readonly ownerId: string; readonly leagues: string[]; readonly createdAt: Date; private constructor(props: { id: string; name: string; tag: string; description: string; ownerId: string; leagues: string[]; createdAt: Date; }) { this.id = props.id; this.name = props.name; this.tag = props.tag; this.description = props.description; this.ownerId = props.ownerId; this.leagues = props.leagues; this.createdAt = props.createdAt; } /** * Factory method to create a new Team entity. */ static create(props: { id: string; name: string; tag: string; description: string; ownerId: string; leagues: string[]; createdAt?: Date; }): Team { this.validate(props); return new Team({ id: props.id, name: props.name, tag: props.tag, description: props.description, ownerId: props.ownerId, leagues: [...props.leagues], createdAt: props.createdAt ?? new Date(), }); } /** * Create a copy with updated properties. */ update(props: Partial<{ name: string; tag: string; description: string; ownerId: string; leagues: string[]; }>): Team { const next: Team = new Team({ id: this.id, name: props.name ?? this.name, tag: props.tag ?? this.tag, description: props.description ?? this.description, ownerId: props.ownerId ?? this.ownerId, leagues: props.leagues ? [...props.leagues] : [...this.leagues], createdAt: this.createdAt, }); // Re-validate updated aggregate Team.validate({ id: next.id, name: next.name, tag: next.tag, description: next.description, ownerId: next.ownerId, leagues: next.leagues, }); return next; } /** * Domain validation logic for core invariants. */ private static validate(props: { id: string; name: string; tag: string; description: string; ownerId: string; leagues: string[]; }): void { if (!props.id || props.id.trim().length === 0) { throw new RacingDomainValidationError('Team ID is required'); } if (!props.name || props.name.trim().length === 0) { throw new RacingDomainValidationError('Team name is required'); } if (!props.tag || props.tag.trim().length === 0) { throw new RacingDomainValidationError('Team tag is required'); } if (!props.ownerId || props.ownerId.trim().length === 0) { throw new RacingDomainValidationError('Team owner ID is required'); } if (!Array.isArray(props.leagues)) { throw new RacingDomainValidationError('Team leagues must be an array'); } } }