Skip to content

Conversation

@ose0221
Copy link
Contributor

@ose0221 ose0221 commented Dec 29, 2025

🚀 PR 요약

목적이 무엇인가요? - 지우고 작성

✨ PR 상세 내용

어떤 부분이 어떻게 변경이 되었나요? - 지우고 작성

🚨 주의 사항

주의할 부분이 무엇인가요? - 지우고 작성

✅ 체크 리스트

  • 리뷰어 설정했나요?
  • Label 설정했나요?
  • 제목 양식 맞췄나요? (ex. feat: 기능 추가)
  • 변경 사항에 대한 테스트를 진행했나요?

Summary by CodeRabbit

  • New Features

    • Added Google login authentication
    • Introduced user profile management with customizable profile images
    • Enhanced article reminders with improved read/unread status tracking
    • Added profile image upload and storage capabilities
  • Infrastructure

    • Updated Docker runtime base image for improved performance
    • Enhanced deployment pipeline configuration

✏️ Tip: You can customize this high-level summary in your review settings.

ose0221 and others added 30 commits November 15, 2025 02:28
FEAT: 구글 소셜 로그인 구현
FEAT: 구글 소셜 로그인 api path 변경
FEAT: 북마크 리마인드 아티클 읽음 상태 분리
@coderabbitai
Copy link

coderabbitai bot commented Dec 29, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This PR introduces Google OAuth authentication, user profile management with image storage, and enhanced article reminder endpoints. Changes span CI/CD workflows, Docker configuration, domain entities (User, Article), multiple service layers (Google OAuth client, S3 storage), and new API controllers with corresponding DTOs.

Changes

Cohort / File(s) Summary
CI/CD Deployment Workflow
.github/workflows/dev.yml
Replaced SSH key handling with environment-variable-based configuration. Added remote server initialization, pinback.env file management, and docker-compose orchestration (down/pull/up/prune with --remove-orphans).
Docker & Build Configuration
Dockerfile, api/build.gradle, application/build.gradle, infrastructure/build.gradle, build.gradle
Updated base image from openjdk:21-jdk-slim to eclipse-temurin:21-jre-jammy. Added spring-boot-starter-webflux across modules and AWS S3 dependencies.
Core Entity Models
domain/src/main/java/com/pinback/domain/article/entity/Article.java, domain/src/main/java/com/pinback/domain/user/entity/User.java
Added isReadAfterRemind boolean field to Article entity. Extended User entity with googleProfileImage, username, and profileImage fields; introduced TEMP_REMIND_DEFAULT_MARKER constant; added createTempUser factory and mutator methods for profile updates.
Google OAuth Integration
application/src/main/java/com/pinback/application/google/*, infrastructure/src/main/java/com/pinback/infrastructure/config/google/GoogleConfig.java, infrastructure/src/main/java/com/pinback/infrastructure/s3/*
Introduced GoogleOAuthClient service with token exchange and user info retrieval; GoogleUsecase orchestrator; multiple exception types for validation failures (GoogleEmailMissingException, GoogleNameMissingException, GoogleProfileImageMissingException, GoogleTokenMissingException, GoogleApiException). Added GoogleConfig for OAuth endpoint configuration and S3StorageService for profile image uploads.
Authentication & API Controllers
api/src/main/java/com/pinback/api/google/controller/GoogleLonginController.java, api/src/main/java/com/pinback/api/user/controller/UserControllerV2.java, api/src/main/java/com/pinback/api/article/controller/ArticleControllerV2.java, api/src/main/java/com/pinback/api/config/filter/JwtAuthenticationFilter.java, api/src/main/java/com/pinback/api/config/security/SecurityConfig.java
Added GoogleLonginController for POST /api/v2/auth/google (login) and PATCH /api/v2/auth/signup endpoints. Added UserControllerV2 for GET /api/v2/users/me (profile info) and GET /api/v2/users/me/google-profile endpoints. Added ArticleControllerV2 for GET /api/v2/articles/remind and PATCH /api/v2/articles/remind/{articleId}/read-status endpoints. Expanded JwtAuthenticationFilter and SecurityConfig to permit new OAuth/auth paths.
Application Layer Use Cases & DTOs
application/src/main/java/com/pinback/application/auth/usecase/AuthUsecase.java, application/src/main/java/com/pinback/application/article/usecase/*, application/src/main/java/com/pinback/application/user/usecase/UserManagementUsecase.java, application/src/main/java/com/pinback/application/user/usecase/UserOAuthUsecase.java
Enhanced AuthUsecase with getInfoAndToken (Mono-based Google login) and signUpV2 methods for user onboarding and profile image assignment. Added GetArticleUsecase.getRemindArticlesV2 for article reminder retrieval with read/unread counts. Introduced UserManagementUsecase methods for profile queries; UserOAuthUsecase for downloading and uploading Google profile images to S3.
Port Definitions (Boundaries)
application/src/main/java/com/pinback/application/article/port/in/GetArticlePort.java, application/src/main/java/com/pinback/application/article/port/in/UpdateArticleStatusPort.java, application/src/main/java/com/pinback/application/article/port/out/ArticleGetServicePort.java, application/src/main/java/com/pinback/application/user/port/in/UserManagementPort.java, application/src/main/java/com/pinback/application/user/port/out/UserGetServicePort.java, application/src/main/java/com/pinback/application/user/port/out/UserSaveServicePort.java, application/src/main/java/com/pinback/application/user/port/out/UserUpdateServicePort.java, application/src/main/java/com/pinback/application/google/port/out/GoogleOAuthPort.java, application/src/main/java/com/pinback/application/s3/port/out/S3StorageServicePort.java
Added V2 variants (getRemindArticlesV2, updateRemindArticleStatus, findTodayRemindWithCountV2) to article ports. Added user profile/Google profile query methods to UserManagementPort. Introduced reactive variants (findUserByEmail, saveUser, updateUser) to user service ports. Added new ports: GoogleOAuthPort (fetchUserInfo) and S3StorageServicePort (uploadProfileImage).
Repository & Infrastructure Services
infrastructure/src/main/java/com/pinback/infrastructure/article/repository/ArticleRepositoryCustom.java, infrastructure/src/main/java/com/pinback/infrastructure/article/repository/ArticleRepositoryCustomImpl.java, infrastructure/src/main/java/com/pinback/infrastructure/article/repository/dto/RemindArticlesWithCountV2.java, infrastructure/src/main/java/com/pinback/infrastructure/article/service/ArticleGetService.java, infrastructure/src/main/java/com/pinback/infrastructure/user/repository/UserRepository.java, infrastructure/src/main/java/com/pinback/infrastructure/user/service/UserGetService.java, infrastructure/src/main/java/com/pinback/infrastructure/user/service/UserSaveService.java, infrastructure/src/main/java/com/pinback/infrastructure/user/service/UserUpdateService.java
Added findTodayRemindWithCountV2 custom query implementations for article reminders with read/unread counts and pagination. Added new UserRepository update methods (updateRemindDefault, updateProfileImage). Introduced UserGetService.findUserByEmail (Mono-based) and UserSaveService.saveUser (reactive). Added new UserUpdateService to implement user update port operations.
Configuration & Constants
api/src/main/resources/application.yml, application/src/main/java/com/pinback/application/config/ProfileImageConfig.java, shared/src/main/java/com/pinback/shared/constant/ExceptionCode.java, api/src/main/java/com/pinback/api/PinbackApiApplication.java
Added google and cloud.aws configuration sections to application.yml. Introduced ProfileImageConfig class for type-safe binding of profile image URLs. Extended ExceptionCode enum with Google OAuth and S3 failure codes (7 new constants). Annotated PinbackApiApplication with @EnableConfigurationProperties.
Request/Response DTOs
api/src/main/java/com/pinback/api/google/dto/request/GoogleLoginRequest.java, application/src/main/java/com/pinback/application/google/dto/GoogleLoginCommand.java, application/src/main/java/com/pinback/application/google/dto/response/GoogleApiResponse.java, application/src/main/java/com/pinback/application/google/dto/response/GoogleTokenResponse.java, application/src/main/java/com/pinback/application/google/dto/response/GoogleUserInfoResponse.java, application/src/main/java/com/pinback/application/google/dto/response/GoogleLoginResponse.java, application/src/main/java/com/pinback/application/article/dto/response/RemindArticleResponseV2.java, application/src/main/java/com/pinback/application/article/dto/response/TodayRemindResponseV2.java, application/src/main/java/com/pinback/application/article/dto/response/ReadRemindArticleResponse.java, application/src/main/java/com/pinback/application/article/dto/RemindArticlesWithCountDtoV2.java, application/src/main/java/com/pinback/application/user/dto/response/UserProfileInfoResponse.java, application/src/main/java/com/pinback/application/user/dto/response/UserGoogleProfileResponse.java
Added GoogleLoginRequest, GoogleLoginCommand, and Google API response DTOs (GoogleApiResponse, GoogleTokenResponse, GoogleUserInfoResponse, GoogleLoginResponse). Added article reminder V2 response types (RemindArticleResponseV2, TodayRemindResponseV2, ReadRemindArticleResponse, RemindArticlesWithCountDtoV2). Added user profile DTOs (UserProfileInfoResponse, UserGoogleProfileResponse).
Firebase & Messaging Updates
infrastructure/src/main/java/com/pinback/infrastructure/firebase/FcmService.java
Updated FCM message construction to use data payloads instead of Notification object; added token validation; enhanced logging with Message ID and error details.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Controller as GoogleLonginController
    participant GoogleUsecase as GoogleUsecase
    participant OAuthClient as GoogleOAuthClient
    participant GoogleAPI as Google OAuth API
    participant AuthUsecase as AuthUsecase
    participant UserService as UserService<br/>(Save & Update)
    participant S3 as S3 Storage
    participant DB as Database

    rect rgb(220, 240, 255)
    Note over Client,DB: Google Login Flow
    Client->>Controller: POST /api/v2/auth/google<br/>{code}
    Controller->>GoogleUsecase: getUserInfo(command)
    GoogleUsecase->>OAuthClient: fetchUserInfo(code)
    OAuthClient->>GoogleAPI: requestAccessToken(code)
    GoogleAPI-->>OAuthClient: {access_token, expires_in}
    OAuthClient->>GoogleAPI: GET /userinfo<br/>(Bearer token)
    GoogleAPI-->>OAuthClient: {email, picture, name, ...}
    OAuthClient->>OAuthClient: validateEmail,<br/>validateName,<br/>validatePicture
    OAuthClient-->>GoogleUsecase: Mono<GoogleUserInfoResponse>
    GoogleUsecase-->>Controller: Mono<GoogleUserInfoResponse>
    Controller->>AuthUsecase: getInfoAndToken(email,<br/>pictureUrl, name)
    rect rgb(240, 255, 240)
    Note over AuthUsecase,DB: User Lookup & Creation
    AuthUsecase->>UserService: findUserByEmail(email)
    alt User Found
        UserService->>DB: SELECT user WHERE email
        DB-->>UserService: Existing User
        UserService-->>AuthUsecase: Mono<User>
        AuthUsecase->>AuthUsecase: applyMissingUserInfo
    else User Not Found
        UserService-->>AuthUsecase: empty Mono
        AuthUsecase->>UserService: saveUser(tempUser)
        UserService->>DB: INSERT new User
        DB-->>UserService: User saved
        UserService-->>AuthUsecase: Mono<User>
    end
    end
    AuthUsecase->>UserService: saveProfileImage(userId,<br/>pictureUrl)
    UserService->>S3: downloadImage(pictureUrl)
    S3-->>UserService: InputStream
    UserService->>S3: uploadProfileImage(stream,<br/>userId)
    S3-->>UserService: Mono<S3 URL>
    AuthUsecase->>AuthUsecase: matchingProfileImage<br/>(time-based)
    AuthUsecase->>UserService: updateProfileImage(userId,<br/>imageKey)
    UserService->>DB: UPDATE profile_image
    AuthUsecase->>AuthUsecase: createAccessToken
    AuthUsecase-->>Controller: Mono<GoogleLoginResponse><br/>{isUser, userId, token}
    Controller-->>Client: ResponseDto<br/><GoogleLoginResponse>
    end
Loading
sequenceDiagram
    participant Client as Client
    participant Controller as ArticleControllerV2
    participant GetArticlePort as GetArticlePort
    participant GetArticleUsecase as GetArticleUsecase
    participant ArticleGetService as ArticleGetService
    participant Repository as ArticleRepository
    participant DB as Database

    rect rgb(220, 240, 255)
    Note over Client,DB: Get Remind Articles V2 Flow
    Client->>Controller: GET /api/v2/articles/remind<br/>?now=..., readStatus=..., page=0, size=8
    Controller->>GetArticlePort: getRemindArticlesV2(user,<br/>now, readStatus, pageQuery)
    GetArticlePort->>GetArticleUsecase: getRemindArticlesV2(...)
    
    rect rgb(240, 255, 240)
    Note over GetArticleUsecase,DB: Compute 24-hour Window
    GetArticleUsecase->>GetArticleUsecase: startTime = now - 24h<br/>endTime = now
    end
    
    GetArticleUsecase->>ArticleGetService: findTodayRemindWithCountV2<br/>(user, start, end, pageable,<br/>readStatus)
    ArticleGetService->>Repository: findTodayRemindWithCountV2<br/>(userId, start, end,<br/>pageable, readStatus)
    Repository->>DB: SELECT articles WHERE<br/>userId AND remindAt BETWEEN<br/>start AND end
    DB-->>Repository: Page<Article>
    Repository->>DB: SELECT COUNT(*) WHERE<br/>userId AND isRead=true
    DB-->>Repository: readCount
    Repository->>DB: SELECT COUNT(*) WHERE<br/>userId AND isRead=false
    DB-->>Repository: unreadCount
    Repository-->>ArticleGetService: RemindArticlesWithCountV2<br/>{readCount, unreadCount,<br/>totalCount, articles}
    
    ArticleGetService->>ArticleGetService: Map to<br/>RemindArticlesWithCountDtoV2
    ArticleGetService-->>GetArticleUsecase: RemindArticlesWithCountDtoV2
    
    GetArticleUsecase->>GetArticleUsecase: Map Articles to<br/>RemindArticleResponseV2[]<br/>(includes category)
    GetArticleUsecase-->>GetArticlePort: TodayRemindResponseV2<br/>{hasNext, totalCount,<br/>readCount, unreadCount,<br/>articles[]}
    GetArticlePort-->>Controller: TodayRemindResponseV2
    Controller-->>Client: ResponseDto<br/><TodayRemindResponseV2>
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #47: Directly related to GitHub Actions deployment workflow changes (dev.yml) using environment variables and docker-compose orchestration.
  • PR #92: Related to article reminder repository and service enhancements (findTodayRemindWithCount and RemindArticlesWithCount DTOs).
  • PR #101: Overlaps with CI/CD workflow modifications for environment variable handling and branch-based deployment configuration.

Suggested labels

FEAT, AUTH, AWS, API

Suggested reviewers

  • rootTiket

Poem

🐰 A rabbit hops through OAuth flows,
With Google tokens as it goes,
S3 buckets hold profile dreams,
While articles remind by moonlight beams,
From temp users to verified friends—
Where security and growth transcends! 🌙

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a69f6fb and 8b9d7af.

📒 Files selected for processing (63)
  • .github/workflows/dev.yml
  • Dockerfile
  • api/build.gradle
  • api/src/main/java/com/pinback/api/PinbackApiApplication.java
  • api/src/main/java/com/pinback/api/article/controller/ArticleControllerV2.java
  • api/src/main/java/com/pinback/api/config/filter/JwtAuthenticationFilter.java
  • api/src/main/java/com/pinback/api/config/security/SecurityConfig.java
  • api/src/main/java/com/pinback/api/google/controller/GoogleLonginController.java
  • api/src/main/java/com/pinback/api/google/dto/request/GoogleLoginRequest.java
  • api/src/main/java/com/pinback/api/user/controller/UserControllerV2.java
  • api/src/main/resources/application.yml
  • application/build.gradle
  • application/src/main/java/com/pinback/application/article/dto/RemindArticlesWithCountDtoV2.java
  • application/src/main/java/com/pinback/application/article/dto/response/ReadRemindArticleResponse.java
  • application/src/main/java/com/pinback/application/article/dto/response/RemindArticleResponseV2.java
  • application/src/main/java/com/pinback/application/article/dto/response/TodayRemindResponseV2.java
  • application/src/main/java/com/pinback/application/article/port/in/GetArticlePort.java
  • application/src/main/java/com/pinback/application/article/port/in/UpdateArticleStatusPort.java
  • application/src/main/java/com/pinback/application/article/port/out/ArticleGetServicePort.java
  • application/src/main/java/com/pinback/application/article/usecase/command/UpdateArticleStatusUsecase.java
  • application/src/main/java/com/pinback/application/article/usecase/query/GetArticleUsecase.java
  • application/src/main/java/com/pinback/application/auth/usecase/AuthUsecase.java
  • application/src/main/java/com/pinback/application/common/exception/GoogleApiException.java
  • application/src/main/java/com/pinback/application/common/exception/GoogleEmailMissingException.java
  • application/src/main/java/com/pinback/application/common/exception/GoogleNameMissingException.java
  • application/src/main/java/com/pinback/application/common/exception/GoogleProfileImageMissingException.java
  • application/src/main/java/com/pinback/application/common/exception/GoogleTokenMissingException.java
  • application/src/main/java/com/pinback/application/common/exception/S3UploadException.java
  • application/src/main/java/com/pinback/application/config/ProfileImageConfig.java
  • application/src/main/java/com/pinback/application/google/dto/GoogleLoginCommand.java
  • application/src/main/java/com/pinback/application/google/dto/response/GoogleApiResponse.java
  • application/src/main/java/com/pinback/application/google/dto/response/GoogleLoginResponse.java
  • application/src/main/java/com/pinback/application/google/dto/response/GoogleTokenResponse.java
  • application/src/main/java/com/pinback/application/google/dto/response/GoogleUserInfoResponse.java
  • application/src/main/java/com/pinback/application/google/port/out/GoogleOAuthPort.java
  • application/src/main/java/com/pinback/application/google/service/GoogleOAuthClient.java
  • application/src/main/java/com/pinback/application/google/usecase/GoogleUsecase.java
  • application/src/main/java/com/pinback/application/s3/port/out/S3StorageServicePort.java
  • application/src/main/java/com/pinback/application/user/dto/response/UserGoogleProfileResponse.java
  • application/src/main/java/com/pinback/application/user/dto/response/UserProfileInfoResponse.java
  • application/src/main/java/com/pinback/application/user/port/in/UserManagementPort.java
  • application/src/main/java/com/pinback/application/user/port/out/UserGetServicePort.java
  • application/src/main/java/com/pinback/application/user/port/out/UserSaveServicePort.java
  • application/src/main/java/com/pinback/application/user/port/out/UserUpdateServicePort.java
  • application/src/main/java/com/pinback/application/user/usecase/UserManagementUsecase.java
  • application/src/main/java/com/pinback/application/user/usecase/UserOAuthUsecase.java
  • build.gradle
  • domain/src/main/java/com/pinback/domain/article/entity/Article.java
  • domain/src/main/java/com/pinback/domain/user/entity/User.java
  • infrastructure/build.gradle
  • infrastructure/src/main/java/com/pinback/infrastructure/article/repository/ArticleRepositoryCustom.java
  • infrastructure/src/main/java/com/pinback/infrastructure/article/repository/ArticleRepositoryCustomImpl.java
  • infrastructure/src/main/java/com/pinback/infrastructure/article/repository/dto/RemindArticlesWithCountV2.java
  • infrastructure/src/main/java/com/pinback/infrastructure/article/service/ArticleGetService.java
  • infrastructure/src/main/java/com/pinback/infrastructure/config/google/GoogleConfig.java
  • infrastructure/src/main/java/com/pinback/infrastructure/config/s3/S3Config.java
  • infrastructure/src/main/java/com/pinback/infrastructure/firebase/FcmService.java
  • infrastructure/src/main/java/com/pinback/infrastructure/s3/service/S3StorageService.java
  • infrastructure/src/main/java/com/pinback/infrastructure/user/repository/UserRepository.java
  • infrastructure/src/main/java/com/pinback/infrastructure/user/service/UserGetService.java
  • infrastructure/src/main/java/com/pinback/infrastructure/user/service/UserSaveService.java
  • infrastructure/src/main/java/com/pinback/infrastructure/user/service/UserUpdateService.java
  • shared/src/main/java/com/pinback/shared/constant/ExceptionCode.java

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@ose0221 ose0221 merged commit b45e0b8 into main Dec 29, 2025
25 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants