feat(auth): add PATCH /auth/profile endpoint for user profile updates

Implement user profile update with fullName, avatarUrl, and email fields.
Email changes include uniqueness validation and Email VO verification.
Follows existing DDD/CQRS patterns with cache invalidation.
19 unit tests covering handler logic and DTO validation.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-15 22:34:40 +07:00
parent 8039b47795
commit 74c52198b3
9 changed files with 496 additions and 12 deletions

View File

@@ -2,6 +2,11 @@ import { Module } from '@nestjs/common';
import { CqrsModule } from '@nestjs/cqrs';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { MulterModule } from '@nestjs/platform-express';
import {
MEDIA_STORAGE_SERVICE,
MinioMediaStorageService,
} from '../listings/infrastructure/services/media-storage.service';
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';
@@ -12,6 +17,8 @@ import { RefreshTokenHandler } from './application/commands/refresh-token/refres
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 { SubmitKycHandler } from './application/commands/submit-kyc/submit-kyc.handler';
import { UpdateProfileHandler } from './application/commands/update-profile/update-profile.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';
@@ -42,6 +49,8 @@ const CommandHandlers = [
LoginUserHandler,
RefreshTokenHandler,
VerifyKycHandler,
SubmitKycHandler,
UpdateProfileHandler,
RequestUserDeletionHandler,
CancelUserDeletionHandler,
ForceDeleteUserHandler,
@@ -61,6 +70,9 @@ const QueryHandlers = [GetProfileHandler, GetAgentByUserIdHandler, GetMfaStatusH
imports: [
CqrsModule,
PassportModule,
MulterModule.register({
limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB — per-type limits enforced by FileValidationPipe
}),
JwtModule.registerAsync({
useFactory: () => {
const secret = process.env['JWT_SECRET'];
@@ -81,6 +93,9 @@ const QueryHandlers = [GetProfileHandler, GetAgentByUserIdHandler, GetMfaStatusH
{ provide: REFRESH_TOKEN_REPOSITORY, useClass: PrismaRefreshTokenRepository },
{ provide: MFA_CHALLENGE_REPOSITORY, useClass: PrismaMfaChallengeRepository },
// Storage
{ provide: MEDIA_STORAGE_SERVICE, useClass: MinioMediaStorageService },
// Strategies
JwtStrategy,
LocalStrategy,