Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b7d8c03
merge: Log 파일 관련 설정 및 CI/CD 파이프라인 개선점 적용
snowykte0426 Feb 8, 2025
b0d5e75
add: EmailVerification 도메인 모델 추가
se0hui Feb 13, 2025
51ce29f
add: 이메일 인증 관련 예외 처리 추가
se0hui Feb 13, 2025
79942e1
add: JPA 기반 EmailVerificationRepository 구현
se0hui Feb 13, 2025
f02ecdb
add: Spring Data 기반 EmailVerificationRepository 추가
se0hui Feb 13, 2025
1a5653d
add: EmailVerificationPort 인터페이스 추가
se0hui Feb 13, 2025
9065c9c
add: 이메일 인증 서비스 구현
se0hui Feb 13, 2025
39cf97c
add: 이메일 인증 UseCase
se0hui Feb 13, 2025
77ee375
add: 이메일 설정을 위한 Config
se0hui Feb 13, 2025
6c672d0
add: AuthController에 이메일 인증 API 추가
se0hui Feb 13, 2025
7c54617
update: 인증 코드 생성 범위 수정
se0hui Feb 14, 2025
778d8c6
test: EmailVerificationservice, AuthController test 추가
se0hui Feb 14, 2025
2037fec
delete: unused import 삭제
se0hui Feb 14, 2025
79f27a5
update: 이메일 관련 기능 엔드포인트 변경
se0hui Feb 14, 2025
a856bfc
test: 변경된 엔드포인드로 수정
se0hui Feb 14, 2025
b2f0b14
update: 이메일 인증 엔티티 생성 및 테이블 이름을 'email'로 지정
se0hui Feb 14, 2025
95bd04f
Merge remote-tracking branch 'origin/develop' into feature/email-api
se0hui Feb 14, 2025
9dab2e1
update: @RequiredArgsConstructor 적용하여 생성자 코드 간소화
se0hui Feb 14, 2025
7787679
update: 인증 코드 생성 부분 주석 수정
se0hui Feb 14, 2025
028e202
update: UseCaseTransaction 어노테이션 및 RequiredArgsConstructor 어노테이션 적용
se0hui Feb 14, 2025
7b9c962
update: RequiredArgsConstructor 어노테이션 적용
se0hui Feb 14, 2025
c520a2c
update: 변경된 엔드포인트로 수정
se0hui Feb 14, 2025
334075e
update: 하드코딩된 숫자 상수화
se0hui Feb 14, 2025
61dc311
test: 변경된 엔드포인트로 수정
se0hui Feb 14, 2025
5200658
add: AuthException을 구체적인 예외 클래스로 분리
se0hui Feb 15, 2025
e49d0e0
add: 오류 추가
se0hui Feb 15, 2025
8fb525f
delete: AuthException 삭제
se0hui Feb 16, 2025
2b42387
update: persistence 계층 이동 및 @setter 제거
se0hui Feb 16, 2025
9699ed3
add: EmailVerificationAdapter 추가
se0hui Feb 16, 2025
78070cf
update: port 상속 제거
se0hui Feb 16, 2025
88ba256
update: @Transactional 제거
se0hui Feb 16, 2025
6ab30b2
chore: EmailVerification의 계층 이동에 따른 update
se0hui Feb 16, 2025
cc63744
add: EmailRequest, VerificationCodeRequest 정의
se0hui Feb 16, 2025
4057cd6
add: EmailSchedulingService 생성
se0hui Feb 16, 2025
f32e1c9
add: @Valid 어노테이션 추가 및 검증 로직 Application 계층으로 이동
se0hui Feb 16, 2025
f3af5d7
delete: 사용하지 않는 테스트 코드 제거
se0hui Feb 16, 2025
b8088ba
add: EmailVerificationUseCase에 대한 test 코드 작성
se0hui Feb 16, 2025
0bcc57c
update: email 및 verificationCode 검증 코드 수정
se0hui Feb 16, 2025
80b7d29
update: 이메일 인증 로직 개선
se0hui Feb 16, 2025
afe7b1a
test: test 코드 수정
se0hui Feb 16, 2025
8947267
add: application-test.yml 이메일 설정 추가
se0hui Feb 16, 2025
b8decdf
chore: application-test.yml
se0hui Feb 16, 2025
6287c15
chore: package 변경
se0hui Feb 17, 2025
3028cb3
delete: 사용하지 않는 Exception 클래스
se0hui Feb 17, 2025
9571324
add: 예외 명칭 세분화
se0hui Feb 17, 2025
bbbd82d
update: 예외 명칭 변경에 따른 코드 수정
se0hui Feb 17, 2025
13f9762
chore: ErrorCode
se0hui Feb 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ name: Test and Build
on:
pull_request:
branches: ["*"]
push:
branches: ["develop"]

jobs:
gradle:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ jobs:
DISCORD_EMBEDS: |
[
{
"title": "🚀 성공적으로 배포 되었습니다!",
"title": "🚀 성공적으로 배포 되었습니다!\n",
"description": "🎉 프로덕션 서버에 성공적으로 배포되었습니다.",
"color": 3066993,
"fields": [
Expand All @@ -208,7 +208,7 @@ jobs:
DISCORD_EMBEDS: |
[
{
"title": "🔄 롤백이 성공적으로 실행되었습니다!",
"title": "🔄 롤백이 성공적으로 실행되었습니다!\n",
"description": "❌ 배포가 실패하여 이전 이미지로 롤백되었습니다.",
"color": 15158332,
"fields": [
Expand All @@ -229,8 +229,8 @@ jobs:
DISCORD_EMBEDS: |
[
{
"title": "❌ 롤백이 실패하였습니다!",
"description": "롤백이 실패하여 이전 이미지로 롤백되지 않았습니다.직접 서버를 확인해주세요.",
"title": "❌ 롤백이 실패하였습니다!\n",
"description": "롤백이 실패하여 이전 이미지로 롤백되지 않았습니다.직접 서버를 확인해주세요.",
"color": 15158332
}
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.ampersand.groom.domain.auth.application.port;

import com.ampersand.groom.domain.auth.domain.model.EmailVerification;

import java.time.LocalDateTime;
import java.util.Optional;

public interface EmailVerificationPort {

// 인증 정보 저장
EmailVerification save(EmailVerification emailVerification);

// 인증 코드로 이메일 조회
Optional<EmailVerification> findByCode(String code);

// 이메일로 인증 정보 조회
Optional<EmailVerification> findByEmail(String email);

// 만료된 인증 정보 삭제
void deleteAllExpired(LocalDateTime now);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.ampersand.groom.domain.auth.application.service;

import com.ampersand.groom.domain.auth.application.port.EmailVerificationPort;
import com.ampersand.groom.domain.auth.domain.model.EmailVerification;
import com.ampersand.groom.domain.auth.expection.AuthException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Random;

@Service
public class EmailVerificationService {

private final EmailVerificationPort emailVerificationPort;
private final JavaMailSender javaMailSender;

public EmailVerificationService(EmailVerificationPort emailVerificationPort, JavaMailSender javaMailSender) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 생성자 주입을 사용하고 있는데, Lombok의 @RequiredArgsConstructor를 사용하시면 가독성과 유지보수 측면에서 더 좋을 것 같아요.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9dab2e1

피드백 반영 하였습니다.
리뷰 감사합니다!

this.emailVerificationPort = emailVerificationPort;
this.javaMailSender = javaMailSender;
}

//6자리 숫자 인증 코드 생성
private String generateVerificationCode() {
Random random = new Random();
int code = 10000000 + random.nextInt(90000000);
return String.valueOf(code);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8자리 숫자 인증 코드인데 맞나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7787679

주석 수정하여 피드백 반영하였습니다.
리뷰 감사합니다!


// 이메일 전송 메서드
private void sendEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
javaMailSender.send(message);
}

// 회원가입 인증 이메일 전송
public void sendSignupVerificationEmail(String email) {
String code = generateVerificationCode();
sendEmail(email, "회원가입 인증", "귀하의 인증 코드는: " + code);

EmailVerification emailVerification = new EmailVerification(email, code);
emailVerificationPort.save(emailVerification);
}

// 비밀번호 변경을 위한 인증 이메일 전송
public void sendPasswordResetEmail(String email) {
String code = generateVerificationCode();
sendEmail(email, "비밀번호 변경 인증", "귀하의 인증 코드는: " + code);

EmailVerification emailVerification = new EmailVerification(email, code);
emailVerificationPort.save(emailVerification);
}

// 인증 코드 검증
public boolean verifyEmailCode(String code) {
EmailVerification emailVerification = emailVerificationPort.findByCode(code)
.orElseThrow(() -> new AuthException("Invalid or expired verification code"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AuthException이라는 여러가지 의미를 가질 수 있는 예외에 에러 메세지로만 예외 상황을 전달하는것보단 확실한 Exception 클래스를 생성하던가 또는 알맞은 Exception을 반환하도록 설계하는것이 로깅이나 클라이언트 응답에 더 유리할 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5200658

피드백 반영 하였습니다.
리뷰 감사합니다.


emailVerification.setVerified(true);
emailVerificationPort.save(emailVerification);
return true;
}

// 만료된 인증 정보 삭제(1시간)
@Scheduled(fixedRate = 3600000)
public void deleteExpiredVerifications() {
emailVerificationPort.deleteAllExpired(LocalDateTime.now());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하나의 클래스가 이미 여러 책임을 가지고 있는데 스케쥴까지 처리하도록 하는것 보단 스케쥴링 클래스를 따로 생성해서 관리하는게 나을 것 같은데 어떤가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4057cd6

피드백 반영하였습니다.
리뷰 감사합니다.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.ampersand.groom.domain.auth.application.usecase;

import com.ampersand.groom.domain.auth.application.service.EmailVerificationService;
import org.springframework.stereotype.Service;

@Service
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 @Service를 사용하고 있는데, 만들어둔 @UseCaseWithReadOnlyTransaction이나 @UseCaseTransaction 어노테이션을 적용해보는건 어떤가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

028e202

@UseCaseTransaction 적용하여 피드백 반영하였습니다.
리뷰 감사합니다!

public class EmailVerificationUseCase {

private final EmailVerificationService emailVerificationService;

public EmailVerificationUseCase(EmailVerificationService emailVerificationService) {
this.emailVerificationService = emailVerificationService;
}

// 회원가입 인증 이메일 전송
public void executeSendSignupVerificationEmail(String email) {
emailVerificationService.sendSignupVerificationEmail(email);
}

// 비밀번호 변경 인증 이메일 전송
public void executeSendPasswordResetEmail(String email) {
emailVerificationService.sendPasswordResetEmail(email);
}

// 이메일 인증 코드 검증
public boolean executeVerifyEmail(String code) {
return emailVerificationService.verifyEmailCode(code);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.ampersand.groom.domain.auth.domain.model;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JPA Entity가 Persistence(영속성) 계층에 있는게 아니라 domain 계층에 있는 이유가 있을까요?
domain model은 비즈니스 로직을 포함하거나 최소한 비즈니스 로직에서 값 객체로서 사용되도록 기능해야 하는데 Entity를 직접 사용하는것은 좋지 않을 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2b42387

피드백 반영 했습니다.
리뷰 감사합니다.


import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;

@Entity
@Getter
@Setter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 Builder 클래스가 있는데 @Setter를 쓴 이유가 있을까요?
가능하다면 Entity에서 @Setter 사용은 지양하는게 좋을것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2b42387

피드백 반영 하였습니다.
리뷰 감사합니다.

@NoArgsConstructor
@Table(name = "email")
@ToString
public class EmailVerification {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String code;
@Column(nullable = false)
private boolean isVerified;
@Column(nullable = false)
private LocalDateTime verificationDate;

public EmailVerification(String email, String code) {
this.email = email;
this.code = code;
this.isVerified = false;
this.verificationDate = LocalDateTime.now().plusMinutes(5);
}

@Builder
public EmailVerification(Long id, String email, String code, boolean isVerified, LocalDateTime verificationDate) {
this.id = id;
this.email = email;
this.code = code;
this.isVerified = isVerified;
this.verificationDate = verificationDate;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ampersand.groom.domain.auth.expection;

public class AuthException extends RuntimeException {
public AuthException(String message) {
super(message);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 정의한 GroomException을 사용해보는게 어떨까요?
ErrorCode Enum 클래스에 오류를 추가하고 GroomException을 상속받아 사용하는게 좋아보입니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5200658
e49d0e0

GroomException 사용하여 피드백 반영하였습니다!
리뷰 감사합니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.ampersand.groom.domain.auth.persistence.adapter;
Copy link
Member

@snowykte0426 snowykte0426 Feb 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JPA Repository가 adapter 패키지 안에 있을 필요는 없을 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피드백 반영했습니다.
리뷰 감사합니다.


import com.ampersand.groom.domain.auth.application.port.EmailVerificationPort;
import com.ampersand.groom.domain.auth.domain.model.EmailVerification;
import com.ampersand.groom.domain.auth.persistence.adapter.email.SpringDataEmailVerificationRepository;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.Optional;

@Repository
public class JpaEmailVerificationRepository implements EmailVerificationPort {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repository가 직접 Port를 상속받아 사용하는건 클래스간 결합도를 지나치게 올리고 헥사고날 아키택쳐의 의의에 반하는 설계같습니다
중간에 adapter 클래스를 하나 더 만들어서 adapter 클래스에서 port를 상속받아 구현하고 repository를 그 클래스에서 호출하도록 하는건 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

78070cf
9699ed3

피드백 반영 했습니다.
리뷰 감사합니다.


private final SpringDataEmailVerificationRepository repository;

public JpaEmailVerificationRepository(SpringDataEmailVerificationRepository repository) {
this.repository = repository;
}

@Override
public EmailVerification save(EmailVerification emailVerification) {
return repository.save(emailVerification);
}

@Override
public Optional<EmailVerification> findByCode(String code) {
return repository.findByCode(code);
}

@Override
public Optional<EmailVerification> findByEmail(String email) {
return repository.findByEmail(email);
}

@Override
public void deleteAllExpired(LocalDateTime now) {
repository.deleteAllExpired(now);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.ampersand.groom.domain.auth.persistence.adapter.email;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import java.util.Properties;

@Configuration
public class EmailConfig {

@Value("${email.host}")
private String host;

@Value("${email.port}")
private int port;

@Value("${email.username}")
private String username;

@Value("${email.password}")
private String password;

@Bean
public JavaMailSender emailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(host);
mailSender.setPort(port);
mailSender.setUsername(username);
mailSender.setPassword(password);

Properties properties = new Properties();
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.starttls.enable", "true");
mailSender.setJavaMailProperties(properties);

return mailSender;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.ampersand.groom.domain.auth.persistence.adapter.email;

import com.ampersand.groom.domain.auth.domain.model.EmailVerification;
import io.lettuce.core.dynamic.annotation.Param;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Optional;

@Repository
public interface SpringDataEmailVerificationRepository extends JpaRepository<EmailVerification, Long> {

Optional<EmailVerification> findByCode(String code);

Optional<EmailVerification> findByEmail(String email);

@Transactional
@Modifying
@Query("DELETE FROM EmailVerification e WHERE e.verificationDate < :now")
void deleteAllExpired(@Param("now") LocalDateTime now);
}
Copy link
Member

@snowykte0426 snowykte0426 Feb 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

애플리케이션의 처리량도 그렇게 많지 않고 복잡한 쿼리도 아니여서 JPQL을 이용해서 사용해도 될것 같은데...프로젝트 통일성을 위해서 QueryDSL을 사용해보는건 어떤가요?...?
이런 단순한 쿼리를 위해서 QeuryDSL을 사용하는건 오히려 복잡도를 높힐거 같기도 해서 고민해보시고 결정해주세요😢

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리뷰 감사합니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.ampersand.groom.domain.auth.presentation.controller;

import com.ampersand.groom.domain.auth.application.usecase.EmailVerificationUseCase;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/auth")
public class AuthController {

private final EmailVerificationUseCase emailVerificationUseCase;

public AuthController(EmailVerificationUseCase emailVerificationUseCase) {
this.emailVerificationUseCase = emailVerificationUseCase;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RequiredArgsConstructor 어노테이션을 알아보고 한번 사용해보시면 좋을 것 같아요
보일러플레이트 코드를 줄일 수 있는 등의 장점이 있습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7b9c962

@RequiredArgsConstructor 적용하여 피드백 반영 하였습니다.
리뷰 감사합니다!


@PostMapping("/email/verify-email")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더 추가 할 기능이 없다면 @RequestMapping("/auth/email")이렇게 쓰셔도 좋을 것 같아요
그리고 API명세서에는 /email/signup 이런 식으로 되어있는데 확인해 보셔야 할 것 같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c520a2c

수정한 API 명세서에 맞게 엔드포인트 수정하였습니다.
리뷰 감사합니다!

public ResponseEntity<?> verifyEmail(@RequestBody Map<String, Object> body) {
String code = (String) body.get("code");

if (code == null || code.length() != 8) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8이라는 숫자를 직접 하드코딩 하는 것보다
상수화시켜 사용해주시는 것이 더욱 명확하게 쓰임새도 알 수 있고 유지보수에도 좋을 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

334075e

인증 코드 길이, 이메일 길이 상수화 시켜 피드백 반영 하였습니다.
리뷰 감사합니다!

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid verification code format.");
}

boolean result = emailVerificationUseCase.executeVerifyEmail(code);
if (result) {
return ResponseEntity.status(HttpStatus.RESET_CONTENT).body("Verification successful.");
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid or expired verification code");
}
}

@PostMapping("/email/signup")
public ResponseEntity<?> signup(@RequestBody Map<String, Object> body) {
String email = (String) body.get("email");

if (email == null || email.length() > 16) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid email format.");
}

emailVerificationUseCase.executeSendSignupVerificationEmail(email);
return ResponseEntity.status(HttpStatus.RESET_CONTENT).body("Verification email sent");
}

@PostMapping("/email/refresh")
public ResponseEntity<?> refresh(@RequestBody Map<String, Object> body) {
String email = (String) body.get("email");

if (email == null || email.length() > 16) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid email format.");
}

emailVerificationUseCase.executeSendPasswordResetEmail(email);
return ResponseEntity.status(HttpStatus.RESET_CONTENT).body("Verification email sent");
}
}
Loading
Loading