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:
Ho Ngoc Hai
2026-04-11 23:43:20 +07:00
parent 9e2bf9a4b5
commit 1fbe2f4e73
131 changed files with 11436 additions and 2595 deletions

View File

@@ -3,6 +3,7 @@ import { CqrsModule } from '@nestjs/cqrs';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { CancelUserDeletionHandler } from './application/commands/cancel-user-deletion/cancel-user-deletion.handler';
import { DisableMfaHandler } from './application/commands/disable-mfa/disable-mfa.handler';
import { ExportUserDataHandler } from './application/commands/export-user-data/export-user-data.handler';
import { ForceDeleteUserHandler } from './application/commands/force-delete-user/force-delete-user.handler';
import { LoginUserHandler } from './application/commands/login-user/login-user.handler';
@@ -10,13 +11,21 @@ import { ProcessScheduledDeletionsHandler } from './application/commands/process
import { RefreshTokenHandler } from './application/commands/refresh-token/refresh-token.handler';
import { RegisterUserHandler } from './application/commands/register-user/register-user.handler';
import { RequestUserDeletionHandler } from './application/commands/request-user-deletion/request-user-deletion.handler';
import { SetupMfaHandler } from './application/commands/setup-mfa/setup-mfa.handler';
import { UseBackupCodeHandler } from './application/commands/use-backup-code/use-backup-code.handler';
import { VerifyKycHandler } from './application/commands/verify-kyc/verify-kyc.handler';
import { VerifyMfaChallengeHandler } from './application/commands/verify-mfa-challenge/verify-mfa-challenge.handler';
import { VerifyMfaSetupHandler } from './application/commands/verify-mfa-setup/verify-mfa-setup.handler';
import { GetAgentByUserIdHandler } from './application/queries/get-agent-by-user-id/get-agent-by-user-id.handler';
import { GetMfaStatusHandler } from './application/queries/get-mfa-status/get-mfa-status.handler';
import { GetProfileHandler } from './application/queries/get-profile/get-profile.handler';
import { MFA_CHALLENGE_REPOSITORY } from './domain/repositories/mfa-challenge.repository';
import { REFRESH_TOKEN_REPOSITORY } from './domain/repositories/refresh-token.repository';
import { USER_REPOSITORY } from './domain/repositories/user.repository';
import { PrismaMfaChallengeRepository } from './infrastructure/repositories/prisma-mfa-challenge.repository';
import { PrismaRefreshTokenRepository } from './infrastructure/repositories/prisma-refresh-token.repository';
import { PrismaUserRepository } from './infrastructure/repositories/prisma-user.repository';
import { MfaService } from './infrastructure/services/mfa.service';
import { OAuthService } from './infrastructure/services/oauth.service';
import { TokenService } from './infrastructure/services/token.service';
import { GoogleOAuthStrategy } from './infrastructure/strategies/google-oauth.strategy';
@@ -24,6 +33,7 @@ import { JwtStrategy } from './infrastructure/strategies/jwt.strategy';
import { LocalStrategy } from './infrastructure/strategies/local.strategy';
import { ZaloOAuthStrategy } from './infrastructure/strategies/zalo-oauth.strategy';
import { AuthController } from './presentation/controllers/auth.controller';
import { MfaController } from './presentation/controllers/mfa.controller';
import { OAuthController } from './presentation/controllers/oauth.controller';
import { UserDataController } from './presentation/controllers/user-data.controller';
@@ -37,9 +47,15 @@ const CommandHandlers = [
ForceDeleteUserHandler,
ProcessScheduledDeletionsHandler,
ExportUserDataHandler,
// MFA
SetupMfaHandler,
VerifyMfaSetupHandler,
VerifyMfaChallengeHandler,
DisableMfaHandler,
UseBackupCodeHandler,
];
const QueryHandlers = [GetProfileHandler, GetAgentByUserIdHandler];
const QueryHandlers = [GetProfileHandler, GetAgentByUserIdHandler, GetMfaStatusHandler];
@Module({
imports: [
@@ -58,11 +74,12 @@ const QueryHandlers = [GetProfileHandler, GetAgentByUserIdHandler];
},
}),
],
controllers: [AuthController, OAuthController, UserDataController],
controllers: [AuthController, MfaController, OAuthController, UserDataController],
providers: [
// Repositories
{ provide: USER_REPOSITORY, useClass: PrismaUserRepository },
{ provide: REFRESH_TOKEN_REPOSITORY, useClass: PrismaRefreshTokenRepository },
{ provide: MFA_CHALLENGE_REPOSITORY, useClass: PrismaMfaChallengeRepository },
// Strategies
JwtStrategy,
@@ -73,11 +90,12 @@ const QueryHandlers = [GetProfileHandler, GetAgentByUserIdHandler];
// Services
TokenService,
OAuthService,
MfaService,
// CQRS
...CommandHandlers,
...QueryHandlers,
],
exports: [TokenService, OAuthService, USER_REPOSITORY],
exports: [TokenService, OAuthService, MfaService, USER_REPOSITORY],
})
export class AuthModule {}