/** * Domain Entity: EngagementEvent * * Represents user interactions beyond page views. * Tracks clicks, downloads, sign-ups, and other engagement actions. */ export type EngagementAction = | 'click_sponsor_logo' | 'click_sponsor_url' | 'download_livery_pack' | 'join_league' | 'register_race' | 'view_standings' | 'view_schedule' | 'share_social' | 'contact_sponsor'; export type EngagementEntityType = 'league' | 'driver' | 'team' | 'race' | 'sponsor' | 'sponsorship'; export interface EngagementEventProps { id: string; action: EngagementAction; entityType: EngagementEntityType; entityId: string; actorId?: string; actorType: 'anonymous' | 'driver' | 'sponsor'; sessionId: string; metadata?: Record; timestamp: Date; } export class EngagementEvent { readonly id: string; readonly action: EngagementAction; readonly entityType: EngagementEntityType; readonly entityId: string; readonly actorId?: string; readonly actorType: 'anonymous' | 'driver' | 'sponsor'; readonly sessionId: string; readonly metadata?: Record; readonly timestamp: Date; private constructor(props: EngagementEventProps) { this.id = props.id; this.action = props.action; this.entityType = props.entityType; this.entityId = props.entityId; this.actorId = props.actorId; this.actorType = props.actorType; this.sessionId = props.sessionId; this.metadata = props.metadata; this.timestamp = props.timestamp; } static create(props: Omit & { timestamp?: Date }): EngagementEvent { this.validate(props); return new EngagementEvent({ ...props, timestamp: props.timestamp ?? new Date(), }); } private static validate(props: Omit): void { if (!props.id || props.id.trim().length === 0) { throw new Error('EngagementEvent ID is required'); } if (!props.action) { throw new Error('EngagementEvent action is required'); } if (!props.entityType) { throw new Error('EngagementEvent entityType is required'); } if (!props.entityId || props.entityId.trim().length === 0) { throw new Error('EngagementEvent entityId is required'); } if (!props.sessionId || props.sessionId.trim().length === 0) { throw new Error('EngagementEvent sessionId is required'); } } /** * Check if this is a sponsor-related engagement */ isSponsorEngagement(): boolean { return this.action.startsWith('click_sponsor') || this.action === 'contact_sponsor' || this.entityType === 'sponsor' || this.entityType === 'sponsorship'; } /** * Check if this is a conversion event (high-value action) */ isConversionEvent(): boolean { return ['join_league', 'register_race', 'click_sponsor_url', 'contact_sponsor'].includes(this.action); } /** * Get engagement weight for analytics calculations */ getEngagementWeight(): number { const weights: Record = { 'click_sponsor_logo': 2, 'click_sponsor_url': 5, 'download_livery_pack': 3, 'join_league': 10, 'register_race': 8, 'view_standings': 1, 'view_schedule': 1, 'share_social': 4, 'contact_sponsor': 15, }; return weights[this.action] || 1; } }