Files
gridpilot.gg/core/identity/domain/entities/SponsorAccount.ts
2025-12-15 13:46:07 +01:00

151 lines
3.9 KiB
TypeScript

/**
* Domain Entity: SponsorAccount
*
* Represents a sponsor's login account in the identity bounded context.
* 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';
export interface SponsorAccountProps {
id: UserId;
sponsorId: string; // Reference to racing domain's Sponsor entity
email: string;
passwordHash: string;
companyName: string;
isActive: boolean;
createdAt: Date;
lastLoginAt?: Date;
}
export class SponsorAccount {
private readonly id: UserId;
private readonly sponsorId: string;
private email: string;
private passwordHash: string;
private companyName: string;
private isActive: boolean;
private readonly createdAt: Date;
private lastLoginAt: Date | undefined;
private constructor(props: SponsorAccountProps) {
this.id = props.id;
this.sponsorId = props.sponsorId;
this.email = props.email;
this.passwordHash = props.passwordHash;
this.companyName = props.companyName;
this.isActive = props.isActive;
this.createdAt = props.createdAt ?? new Date();
this.lastLoginAt = props.lastLoginAt;
}
public static create(props: Omit<SponsorAccountProps, 'createdAt' | 'isActive'> & {
createdAt?: Date;
isActive?: boolean;
}): SponsorAccount {
if (!props.sponsorId || !props.sponsorId.trim()) {
throw new Error('SponsorAccount sponsorId is required');
}
if (!props.companyName || !props.companyName.trim()) {
throw new Error('SponsorAccount companyName is required');
}
if (!props.passwordHash || !props.passwordHash.trim()) {
throw new Error('SponsorAccount passwordHash is required');
}
const emailResult: EmailValidationResult = validateEmail(props.email);
if (!emailResult.success) {
throw new Error(emailResult.error);
}
return new SponsorAccount({
...props,
email: emailResult.email,
createdAt: props.createdAt ?? new Date(),
isActive: props.isActive ?? true,
});
}
public getId(): UserId {
return this.id;
}
public getSponsorId(): string {
return this.sponsorId;
}
public getEmail(): string {
return this.email;
}
public getPasswordHash(): string {
return this.passwordHash;
}
public getCompanyName(): string {
return this.companyName;
}
public getIsActive(): boolean {
return this.isActive;
}
public getCreatedAt(): Date {
return this.createdAt;
}
public getLastLoginAt(): Date | undefined {
return this.lastLoginAt;
}
public canLogin(): boolean {
return this.isActive;
}
public recordLogin(): SponsorAccount {
return new SponsorAccount({
id: this.id,
sponsorId: this.sponsorId,
email: this.email,
passwordHash: this.passwordHash,
companyName: this.companyName,
isActive: this.isActive,
createdAt: this.createdAt,
lastLoginAt: new Date(),
});
}
public deactivate(): SponsorAccount {
return new SponsorAccount({
id: this.id,
sponsorId: this.sponsorId,
email: this.email,
passwordHash: this.passwordHash,
companyName: this.companyName,
isActive: false,
createdAt: this.createdAt,
...(this.lastLoginAt ? { lastLoginAt: this.lastLoginAt } : {}),
});
}
public updatePassword(newPasswordHash: string): SponsorAccount {
if (!newPasswordHash || !newPasswordHash.trim()) {
throw new Error('Password hash cannot be empty');
}
return new SponsorAccount({
id: this.id,
sponsorId: this.sponsorId,
email: this.email,
passwordHash: newPasswordHash,
companyName: this.companyName,
isActive: this.isActive,
createdAt: this.createdAt,
...(this.lastLoginAt ? { lastLoginAt: this.lastLoginAt } : {}),
});
}
}