Skip to content

Conversation

@jhan0121
Copy link
Owner

🚀 작업 내용

  • 이메일 인증을 통한 멀티 디바이스 등록 및 관리 시스템 구축
  • 동일한 이메일로 노트북, 데스크탑 등 여러 기기에서 로그인할 수 있는 환경 제공
  • 신규 디바이스 등록 시 이메일 발송 및 링크 클릭을 통한 is_active 활성화 처리

📸 이슈 번호

✍ 궁금한 점

  • 이메일 전송 기능을 비동기 처리하였음. 해당 방법을 더 고도화 하는 방법을 찾아봐도 좋아 보인다.

@jhan0121 jhan0121 requested a review from Copilot December 23, 2025 15:33
@jhan0121 jhan0121 self-assigned this Dec 23, 2025
@jhan0121 jhan0121 added BE Backend ✨ feat 기능 추가 labels Dec 23, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements an email-based multi-device authentication and management system that allows users to register and manage multiple devices (laptop, desktop, etc.) using a single email address. New devices are registered through an email verification flow where users receive an authentication link to activate their devices.

Key changes include:

  • Domain model with Member and Device entities supporting multi-device registration per email
  • Email verification system with async email delivery using JavaMailSender and Thymeleaf templates
  • REST APIs for device registration, authentication, and device list retrieval

Reviewed changes

Copilot reviewed 38 out of 39 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
src/main/java/com/recyclestudy/member/domain/Member.java Member entity with embedded Email value object for user representation
src/main/java/com/recyclestudy/member/domain/Device.java Device entity tracking registered devices with activation status
src/main/java/com/recyclestudy/member/domain/Email.java Email value object with format validation using regex pattern
src/main/java/com/recyclestudy/member/domain/DeviceIdentifier.java Device identifier value object with UUID-based generation
src/main/java/com/recyclestudy/member/domain/IdentifierCreator.java Utility class for generating unique device identifiers
src/main/java/com/recyclestudy/member/repository/MemberRepository.java JPA repository for member persistence with email lookup
src/main/java/com/recyclestudy/member/repository/DeviceRepository.java JPA repository for device persistence with JPQL query for member's devices
src/main/java/com/recyclestudy/member/service/MemberService.java Business logic for device registration, authentication, and retrieval
src/main/java/com/recyclestudy/member/controller/MemberController.java REST endpoints for device registration and member device listing
src/main/java/com/recyclestudy/member/DeviceController.java Controller handling device authentication via email link
src/main/java/com/recyclestudy/email/EmailService.java Async email service using JavaMailSender and Thymeleaf for device authentication emails
src/main/java/com/recyclestudy/common/BaseEntity.java Base entity with id, timestamps, and properly implemented equals/hashCode
src/main/java/com/recyclestudy/common/NullValidator.java Utility for validating non-null domain object fields
src/main/java/com/recyclestudy/exception/* Custom exception classes and global exception handler for error responses
src/main/java/com/recyclestudy/RecyclestudyApplication.java Application entry point with @EnableAsync for asynchronous email processing
src/main/resources/application.yaml Configuration for database, JPA, mail server, and base URL
src/main/resources/templates/auth_email.html Thymeleaf template for device authentication email
src/main/resources/templates/auth_success.html HTML page displayed after successful device authentication
build.gradle Added dependencies for JPA, JavaMail, Thymeleaf, and RestAssured
docker-compose.yaml MySQL 8.4 database setup for local development
src/test/**/*Test.java Comprehensive test coverage for domain, service, and controller layers

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 40 to 42
} catch (final Exception e) {
throw new RuntimeException("메일 전송에 실패했습니다.", e);
}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The email sending failure in the catch block is thrown as a RuntimeException, but there's no logging before throwing. Since this is an async method, adding proper logging would help with debugging and monitoring email delivery failures. Consider adding a logger to record the exception details before throwing.

Copilot uses AI. Check for mistakes.
Comment on lines 19 to 26
@GetMapping("/auth")
public String authenticateDevice(
@RequestParam("email") String email,
@RequestParam("device") String deviceIdentifier
) {
memberService.authenticateDevice(Email.from(email), DeviceIdentifier.from(deviceIdentifier));
return "auth_success";
}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The device authentication endpoint has no rate limiting or protection against brute force attacks. An attacker could repeatedly try different device identifiers to activate devices. Consider implementing rate limiting, adding authentication token expiration, or limiting the number of authentication attempts per device/email.

Copilot uses AI. Check for mistakes.
@Async
public void sendDeviceAuthMail(String email, String deviceId) {
try {
final String authUrl = baseUrl + "/api/v1/device/auth?email=" + email + "&device=" + deviceId;
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The email and deviceId parameters are concatenated directly into the URL without proper encoding. This could cause issues if the email contains special characters (though the email format validation should prevent most cases). Consider using UriComponentsBuilder or URLEncoder to properly encode the query parameters to ensure URL safety.

Copilot uses AI. Check for mistakes.
@jhan0121 jhan0121 merged commit 7dd27a5 into be/dev Dec 24, 2025
@jhan0121 jhan0121 deleted the be/feat/email-registration branch December 24, 2025 04:44
@jhan0121 jhan0121 added this to the v1.0.0 milestone Dec 25, 2025
jhan0121 added a commit that referenced this pull request Jan 3, 2026
* init: 프로젝트 초기 설정 추가

* 이메일 기반 멀티 디바이스 인증 및 관리 기능 구현 (#3)

* build: JPA 의존성 추가

* feat: BaseEntity 추가

* feat: NullValidator 추가

* feat: docker compose 파일 추가

* feat: Email 추가

* feat: DeviceIdentifier 추가

* test: BaseEntity equals 검증 테스트 추가

* feat: Member 추가

* feat: Device 추가

* style: 불필요한 개행 제거

* feat: DeviceIdentifier 추가

* feat: email에 toString 추가

* feat: Device 정적 팩터리 메서드 구조 수정

- isActive 추가

* feat: RecyclestudyApplication에 비동기 설정 추가

* feat: 이메일 전송 기능을 위한 의존성 추가

* feat: 전역 예외 처리용 ControllerAdvice 추가

* feat: EmailService  추가

* feat: IdentifierCreator 추가

* feat: 멤버 저장 기능 추가

- 멤버 저장
- 디바이스 id 발급

* feat: 멤버의 디바이스 전체 조회 기능 추가

* feat: 디바이스 이메일 인증 메일 발송 기능 추가

* feat: 이메일 인증 기능 추가

* test: MemberServiceTest 불필요한 검증 로직 제거

* feat: GlobalControllerAdvice 예외 처리 로직 추가

* test: MemberControllerTest 추가

* test: DeviceControllerTest 추가

* chore: DeviceControllerTest 패키지 위치 수정

* refactor: Member 이메일 유니크 제약 조건 설정

* refactor: Device 내 Member에 JoinColumn 추가

* refactor: Device identifier 유니크 제약 조건 설정

* refactor: DeviceController 패키지 위치 수정 및 파라미터명 변경

* feat: ActivationExpiredDateTime 추가

* refactor: EmailService 구조 개선

- 로그 추가
- 메서드 분리

* feat: Member 이메일 검증 기능 추가

* feat: Device 소유 검증 기능 추가

* feat: GlobalControllerAdvice  내 DeviceActivationExpiredException 처리 추가

* refactor: 이메일 인증 제한 시간 로직 추가

* jacoco 기반 테스트 커버리지 CI 구축 (#6)

* feat: jacoco 기반 테스트 커버리지 CI 스크립트 추자

* test: 테스트 환경 DB H2 사용하도록 변경

* 디바이스 삭제 기능 추가 (#7)

* feat: 디바이스 삭제 기능 추가

* chore: final 키워드 누락 수정

* fix: 대상 디바이스를 제거하도록 기능 수정

* 등록한 디바이스 조회 기능 응답 형식 수정 (#9)

* fix: 등록한 디바이스 조회 기능 응답 형식 수정

* chore: 실행 sql 로그 출력 기능 활성화

* 복습할 URL 저장 기능 추가 (#10)

* feat: 리뷰 대상 url 저장 기능 추가

* fix: ReviewService 트랜잭션 누락 수정

* swagger 기반 API 문서 작성 (#12)

* feat: swagger 기반 api 문서 기능 추가

* refactor: 불필요한 로그 출력 제거

* refactor: 누락된 타입 명시 로직 추가

* CI 대상 branch 설정 추가 (#13)

* 복습 대상 URL 이메일 전송 스케줄러 구현 (#19)

* feat: Review 엔티티에 Member 연관 관계 추가

* feat: 주기적 복습 이메일 전송 기능 추가

- 공통 이메일 전송 기능 별도 분리 리팩터링 진행

* test: ReviewCycleServiceTest 추가

* refactor: ReviewSendOutput collect 내 불변 리스트를 사용하도록 수정

* refactor: html 태그에 lang 추가

* feat: 이메일 전송 이력 관리 기능 추가

* style: 코드 구조 정리

* refactor: ReviewEmailSender 타임존 설정 추가

* test: 메일 발송 실패 처리 검증 추가

* 로그 기능 추가 (#21)

* feat: 로그 기능 추가

* chore: 신규 유저 이메일 등록 시작 로그 태그명 수정

* feat: 이메일 마스킹 기능 적용

* refactor: 복습 주기 저장 로그 포맷 수정

* refactor: 이메일 전송 기능 도메인 객체 파라미터로 변경

* test: MemberServiceTest#authenticateDevice 테스트 커버리지 보완 (#22)

* flyway 기반 db 마이그레이션 의존성 추가 (#24)

* feat: flyway 기반 db 마이그레이션 의존성 추가

- 환경별 jpa sql 출력 여부 분리

* fix: ReviewCycle#scheduledAt not null 누락 수정

* test: 테스트 환경에서 flyway 비활성화

* 로그 기능 추가 (#21)

* feat: 로그 기능 추가

* chore: 신규 유저 이메일 등록 시작 로그 태그명 수정

* feat: 이메일 마스킹 기능 적용

* refactor: 복습 주기 저장 로그 포맷 수정

* refactor: 이메일 전송 기능 도메인 객체 파라미터로 변경

* test: MemberServiceTest#authenticateDevice 테스트 커버리지 보완 (#22)

* 배포 스크립트 추가 (#31)

* feat: 배포 스크립트 추가

* refactor: docker-compose.yaml env 설정 수정

* chore: 태그 검증 로그 메시지 수정
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BE Backend ✨ feat 기능 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants