iconsulting/packages/services/user-service/src/domain/entities/verification-code.entity.ts

87 lines
1.9 KiB
TypeScript

/**
* Verification Code Domain Entity
* Pure domain object without infrastructure dependencies
*/
export class VerificationCodeEntity {
readonly id: string;
readonly phone: string;
readonly code: string;
readonly expiresAt: Date;
isUsed: boolean;
readonly createdAt: Date;
private constructor(props: {
id: string;
phone: string;
code: string;
expiresAt: Date;
isUsed: boolean;
createdAt: Date;
}) {
this.id = props.id;
this.phone = props.phone;
this.code = props.code;
this.expiresAt = props.expiresAt;
this.isUsed = props.isUsed;
this.createdAt = props.createdAt;
}
/**
* Create a new verification code
* Code expires in 5 minutes by default
*/
static create(phone: string, expirationMinutes: number = 5): VerificationCodeEntity {
const now = new Date();
return new VerificationCodeEntity({
id: crypto.randomUUID(),
phone,
code: VerificationCodeEntity.generateCode(),
expiresAt: new Date(now.getTime() + expirationMinutes * 60 * 1000),
isUsed: false,
createdAt: now,
});
}
/**
* Reconstruct from persistence
*/
static fromPersistence(props: {
id: string;
phone: string;
code: string;
expiresAt: Date;
isUsed: boolean;
createdAt: Date;
}): VerificationCodeEntity {
return new VerificationCodeEntity(props);
}
/**
* Generate 6-digit verification code
*/
private static generateCode(): string {
return Math.floor(100000 + Math.random() * 900000).toString();
}
/**
* Check if the code is valid (not used and not expired)
*/
isValid(): boolean {
return !this.isUsed && this.expiresAt > new Date();
}
/**
* Mark the code as used
*/
markAsUsed(): void {
this.isUsed = true;
}
/**
* Check if this code matches the provided code
*/
matches(code: string): boolean {
return this.code === code;
}
}