Skip to content

feat: 유저 로그인, 활동 시간 추적#323

Merged
dh2906 merged 3 commits intodevelopfrom
feat/user-activity-trace
Feb 25, 2026
Merged

feat: 유저 로그인, 활동 시간 추적#323
dh2906 merged 3 commits intodevelopfrom
feat/user-activity-trace

Conversation

@dh2906
Copy link
Contributor

@dh2906 dh2906 commented Feb 25, 2026

🔍 개요

  • close #이슈번호

🚀 주요 변경 내용

  • users 테이블에 last_login_at, last_activity_at 컬럼을 추가했습니다.

  • /refresh 호출 시 사용자의 last_login_at를 갱신하도록 연동했습니다.

  • 인증된 API 요청 이후 last_activity_at를 갱신하는 AOP를 추가했습니다.


💬 참고 사항


✅ Checklist (완료 조건)

  • 코드 스타일 가이드 준수
  • 테스트 코드 포함됨
  • Reviewers / Assignees / Labels 지정 완료
  • 보안 및 민감 정보 검증 (API 키, 환경 변수, 개인정보 등)

dh2906 and others added 3 commits February 25, 2026 23:39
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@dh2906 dh2906 requested a review from Copilot February 25, 2026 14:47
@dh2906 dh2906 self-assigned this Feb 25, 2026
@dh2906 dh2906 added the 기능 새로운 기능을 개발합니다. label Feb 25, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a57653 and 1b4b79b.

📒 Files selected for processing (6)
  • build.gradle
  • src/main/java/gg/agit/konect/domain/user/controller/UserController.java
  • src/main/java/gg/agit/konect/domain/user/model/User.java
  • src/main/java/gg/agit/konect/domain/user/service/UserActivityService.java
  • src/main/java/gg/agit/konect/global/auth/aop/UserActivityUpdateAspect.java
  • src/main/resources/db/migration/V38__add_last_login_and_last_activity_to_users.sql

📝 Walkthrough

Walkthrough

사용자의 마지막 로그인 및 활동 시간을 추적하는 기능을 추가합니다. Spring AOP를 통해 컨트롤러 메서드 실행 후 활동 타임스탠프를 자동으로 업데이트하고, 로그인 시 로그인 타임스탠프를 기록하며, User 엔티티와 데이터베이스에 관련 필드를 추가합니다.

Changes

Cohort / File(s) Summary
빌드 구성
build.gradle
Spring Boot AOP 스타터 의존성 추가
엔티티 및 데이터베이스
src/main/java/gg/agit/konect/domain/user/model/User.java, src/main/resources/db/migration/V38__add_last_login_and_last_activity_to_users.sql
User 엔티티에 lastLoginAt, lastActivityAt 타임스탬프 필드 및 업데이트 메서드 추가, 데이터베이스 테이블에 대응하는 컬럼 추가
서비스 레이어
src/main/java/gg/agit/konect/domain/user/service/UserActivityService.java
새로운 UserActivityService 클래스로 사용자 활동 및 로그인 타임스탠프 업데이트 로직 제공
컨트롤러 및 AOP
src/main/java/gg/agit/konect/domain/user/controller/UserController.java, src/main/java/gg/agit/konect/global/auth/aop/UserActivityUpdateAspect.java
UserController에서 로그인 시 updateLastLoginAt() 호출, AOP Aspect를 통해 모든 컨트롤러 메서드 실행 후 updateLastActivityAt() 자동 실행

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller
    participant Aspect
    participant UserActivityService
    participant UserRepository
    participant Database

    Client->>Controller: 요청 (로그인 또는 일반 요청)
    activate Controller
    
    Controller->>UserActivityService: updateLastLoginAt(userId) [로그인 시에만]
    activate UserActivityService
    UserActivityService->>UserRepository: findById(userId)
    activate UserRepository
    UserRepository->>Database: SELECT user
    Database-->>UserRepository: User 객체
    UserRepository-->>UserActivityService: User 반환
    deactivate UserRepository
    
    UserActivityService->>UserActivityService: user.updateLastLoginAt(now())
    UserActivityService->>Database: UPDATE user.last_login_at
    deactivate UserActivityService
    
    Controller-->>Client: 응답
    deactivate Controller
    
    Note over Aspect: 컨트롤러 메서드 실행 후 AOP 트리거
    Aspect->>Aspect: 요청 컨텍스트에서 userId 추출
    Aspect->>UserActivityService: updateLastActivityAt(userId)
    activate UserActivityService
    UserActivityService->>UserRepository: findById(userId)
    activate UserRepository
    UserRepository->>Database: SELECT user
    Database-->>UserRepository: User 객체
    UserRepository-->>UserActivityService: User 반환
    deactivate UserRepository
    
    UserActivityService->>UserActivityService: user.updateLastActivityAt(now())
    UserActivityService->>Database: UPDATE user.last_activity_at
    deactivate UserActivityService
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 로그인한 사용자의 자취를 남기네,
마지막 접속 시간을 기록하고,
AOP의 마법으로 활동까지 추적하니,
사용자의 발자국이 데이터베이스에 쌓여가네! 🕐✨

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/user-activity-trace

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Comment @coderabbitai help to get the list of available commands and usage tips.

@dh2906 dh2906 merged commit 4c1e059 into develop Feb 25, 2026
3 of 4 checks passed
Copy link
Contributor

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

사용자의 마지막 로그인 시각(last_login_at)마지막 활동 시각(last_activity_at) 을 DB에 저장하고, /users/refresh 및 인증된 API 호출 이후 이를 자동 갱신하도록 연동하는 변경입니다.

Changes:

  • users 테이블에 last_login_at, last_activity_at 컬럼 추가 (Flyway V38)
  • /users/refresh에서 last_login_at 갱신 로직 연결
  • 컨트롤러 호출 이후 last_activity_at를 갱신하는 AOP(Aspect) 및 관련 서비스 추가

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/main/resources/db/migration/V38__add_last_login_and_last_activity_to_users.sql users 테이블에 마지막 로그인/활동 컬럼 추가
src/main/java/gg/agit/konect/global/auth/aop/UserActivityUpdateAspect.java 컨트롤러 실행 후 인증 사용자에 대해 활동 시각 갱신
src/main/java/gg/agit/konect/domain/user/service/UserActivityService.java last_login_at / last_activity_at 갱신 서비스 로직 추가
src/main/java/gg/agit/konect/domain/user/model/User.java User 엔티티에 lastLoginAt/lastActivityAt 필드 및 업데이트 메서드 추가
src/main/java/gg/agit/konect/domain/user/controller/UserController.java refresh 시 last_login_at 갱신 호출 추가
build.gradle AOP 스타터 의존성 추가

Comment on lines +95 to +98
@Column(name = "last_login_at", columnDefinition = "TIMESTAMP")
private LocalDateTime lastLoginAt;

@Column(name = "last_activity_at", columnDefinition = "TIMESTAMP")
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

Flyway 마이그레이션에서는 last_login_at/last_activity_at 컬럼 타입이 DATETIME인데, 엔티티는 columnDefinition="TIMESTAMP"로 선언되어 있어 spring.jpa.hibernate.ddl-auto=validate 환경에서 스키마 검증 실패가 발생할 수 있습니다. DB 타입과 엔티티 매핑을 동일하게 맞춰 주세요(마이그레이션을 TIMESTAMP로 바꾸거나, 엔티티의 columnDefinition을 DATETIME/기본 매핑으로 변경).

Suggested change
@Column(name = "last_login_at", columnDefinition = "TIMESTAMP")
private LocalDateTime lastLoginAt;
@Column(name = "last_activity_at", columnDefinition = "TIMESTAMP")
@Column(name = "last_login_at")
private LocalDateTime lastLoginAt;
@Column(name = "last_activity_at")

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +22
@After("execution(* gg.agit.konect..controller..*(..))")
public void updateLastActivity() {
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

현재 @After 어드바이스는 컨트롤러 메서드가 예외를 던져도 실행되므로, 5xx/4xx 등 실패 응답에서도 last_activity_at이 갱신됩니다. "인증된 API 요청 이후"를 성공 요청으로 한정하려면 @AfterReturning으로 변경하는 쪽이 의도에 더 맞습니다.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +28
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return;
}

HttpServletRequest request = attributes.getRequest();
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

RequestContextHolder.getRequestAttributes() 결과를 바로 ServletRequestAttributes로 캐스팅하고 있어(현재는 null만 체크) 비-서블릿 컨텍스트에서 호출되면 ClassCastException이 날 수 있습니다. instanceof ServletRequestAttributes 확인 후 캐스팅하도록 방어 코드를 추가해 주세요.

Suggested change
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return;
}
HttpServletRequest request = attributes.getRequest();
Object attributes = RequestContextHolder.getRequestAttributes();
if (attributes == null || !(attributes instanceof ServletRequestAttributes)) {
return;
}
HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest();

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +25
public void updateLastLoginAt(Integer userId) {
if (userId == null) {
return;
}

userRepository.getById(userId).updateLastLoginAt(LocalDateTime.now());
}
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

updateLastLoginAt가 userRepository.getById()로 엔티티를 먼저 조회한 뒤 dirty checking으로 UPDATE를 발생시키므로, 불필요한 SELECT가 추가됩니다. 단순 타임스탬프 갱신이면 @Modifying UPDATE 쿼리로 1쿼리 처리(SELECT 없이)하는 방식이 더 적합합니다.

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +34
return;
}

userRepository.getById(userId).updateLastActivityAt(LocalDateTime.now());
}
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

updateLastActivityAt도 매 요청마다 getById()로 SELECT 후 UPDATE가 발생합니다. 트래픽이 늘면 users 테이블에 대한 쓰기/락 경합이 커질 수 있으니, @Modifying UPDATE로 조회 없이 갱신하거나(필요 시) 일정 주기 이상 지난 경우에만 갱신하는 방식도 고려해 주세요.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

기능 새로운 기능을 개발합니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants