feat: add MFA/TOTP auth, PII encryption, agents/leads/inquiries modules, and comprehensive tests
- Add TOTP-based MFA with setup, verify, disable, backup codes, and challenge flow - Add PII field encryption middleware with AES-256-GCM and deterministic search hashes - Add agents, inquiries, and leads domain modules with entities, events, value objects - Add web dashboard pages for inquiries and leads with detail dialogs - Add 30+ component tests (valuation, charts, listings, search, providers, UI) - Add Prisma migrations for encryption hash columns and MFA TOTP support - Fix all ESLint errors (unused imports, duplicate imports, lint auto-fixes) - Update dependencies and lock file - Clean up obsolete exploration/QA docs, add audit documentation Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
61
apps/api/src/modules/agents/domain/entities/agent.entity.ts
Normal file
61
apps/api/src/modules/agents/domain/entities/agent.entity.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { AggregateRoot } from '@modules/shared';
|
||||
import { QualityScoreUpdatedEvent } from '../events/quality-score-updated.event';
|
||||
import { type QualityScore } from '../value-objects/quality-score.vo';
|
||||
|
||||
export interface AgentProps {
|
||||
userId: string;
|
||||
licenseNumber: string | null;
|
||||
agency: string | null;
|
||||
qualityScore: QualityScore;
|
||||
totalDeals: number;
|
||||
responseTimeAvg: number | null;
|
||||
bio: string | null;
|
||||
serviceAreas: string[];
|
||||
isVerified: boolean;
|
||||
}
|
||||
|
||||
export class AgentEntity extends AggregateRoot<string> {
|
||||
private _userId: string;
|
||||
private _licenseNumber: string | null;
|
||||
private _agency: string | null;
|
||||
private _qualityScore: QualityScore;
|
||||
private _totalDeals: number;
|
||||
private _responseTimeAvg: number | null;
|
||||
private _bio: string | null;
|
||||
private _serviceAreas: string[];
|
||||
private _isVerified: boolean;
|
||||
|
||||
constructor(id: string, props: AgentProps, createdAt?: Date, updatedAt?: Date) {
|
||||
super(id, createdAt);
|
||||
if (updatedAt) this.updatedAt = updatedAt;
|
||||
this._userId = props.userId;
|
||||
this._licenseNumber = props.licenseNumber;
|
||||
this._agency = props.agency;
|
||||
this._qualityScore = props.qualityScore;
|
||||
this._totalDeals = props.totalDeals;
|
||||
this._responseTimeAvg = props.responseTimeAvg;
|
||||
this._bio = props.bio;
|
||||
this._serviceAreas = props.serviceAreas;
|
||||
this._isVerified = props.isVerified;
|
||||
}
|
||||
|
||||
get userId(): string { return this._userId; }
|
||||
get licenseNumber(): string | null { return this._licenseNumber; }
|
||||
get agency(): string | null { return this._agency; }
|
||||
get qualityScore(): QualityScore { return this._qualityScore; }
|
||||
get totalDeals(): number { return this._totalDeals; }
|
||||
get responseTimeAvg(): number | null { return this._responseTimeAvg; }
|
||||
get bio(): string | null { return this._bio; }
|
||||
get serviceAreas(): string[] { return this._serviceAreas; }
|
||||
get isVerified(): boolean { return this._isVerified; }
|
||||
|
||||
updateQualityScore(newScore: QualityScore): void {
|
||||
const oldScore = this._qualityScore.value;
|
||||
this._qualityScore = newScore;
|
||||
this.updatedAt = new Date();
|
||||
|
||||
this.addDomainEvent(
|
||||
new QualityScoreUpdatedEvent(this.id, oldScore, newScore.value),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user