Skip to content

Conversation

@erika0915
Copy link
Member

@erika0915 erika0915 commented Aug 13, 2025

📝 개요

로깅 시스템을 구현해보았습니다.

🛠️ 작업 사항

  1. 로컬 환경에서의 로깅 시스템을 개선해보았습니다.
    기존에는 Hibernate... 하면서 쿼리가 쭉 나오고 GlobalExceptionHandler에서 400, 500에러만 로깅이 되는 상황이었습니다.
    이 로깅을 조금 세세하게 나오게끔 Interceptor와 AOP를 활용해보았습니다.
  • 200 응답 시
image
  • 400 에러 시
image

로컬 환경에서의 로깅 시스템을 조금 더 일찍 해봤음 좋았겠다 ~ 하는 생각도 들었다 !! 이미 개발이 거의 끝난 상황이라,, 크게 의미있는 작업이 아닐 수도 있겠다는 생각이 들었지만,, 얼마나 걸리는지 시간도 콘솔에 찍히니깐,, 성능 개선이나,, 새로운 API 구현하면서 좀 참고해볼 수 있지 않을까 싶어유 !


  1. 배포 환경에서의 로깅 시스템을 개선해보았습니다. 기존에는 docker logs spring-blue(green) 이렇게 해서 들어가게 되면, 아래 사진과 같이 로그가 찍히는 것을 볼 수 있는데, 여기서 AOP 로그 부분과 Hibernate... 부분은 찍히지 않도록 하고 400,500 에러는 동일하게 나오게끔 설정했습니다.
image
  1. 그리고 500에러는 디스코드 웹훅 설정해서 백엔드에 '서버-에러'와 연결하였습니다 ! 로컬 테스트도 진행해보았는데, (내 개인 디스코드 서버에서!) 잘 되는 것 같아용 ~

🔗 관련 이슈 / JIRA

✅ 체크리스트

  • 코드 리뷰 반영 완료
  • 테스트 코드 작성
  • 로컬 테스트 완료
  • 문서 업데이트 필요 시 반영

🙏 기타 사항

  1. 코드레빗이 무료로 14일 사용할 수 있는데, 이미 내가 한 일주일 사용해서,, 남은 7일 정도 더 사용할 수 있어용~ㅎㅎ
  2. 그리고 로그도 .. grafana나.. Elasticsearch와 연결하여... 이 로그를 한 곳에 모으거나 시각화한 대시보드로 볼 수 있는 방법도 있는 것 같은데,, 아직 거기까지는 도입해보지 못했습니닷... !! 모니터링에서 Grafana 사용하니깐 로그까지 볼 수 있으면 좋을 것 같다고도 생각이 드는데,, 아직 잘 알아본 건 아니라서 차차 고민해볼게욧 ~!

Summary by CodeRabbit

  • 신기능

    • 프로덕션에서 서버 오류를 Discord 웹훅으로 알림하도록 통합.
    • HTTP 요청/응답과 서비스·저장소 실행에 대한 상세 실행시간 및 결과 로깅 도입(환경별 적용).
  • 스타일

    • 예외 로그 포맷을 더 간결한 단일 라인 형식으로 정리.
  • 작업

    • AOP 및 Discord 로깅 의존성 추가 및 외부 저장소 등록.
    • 프로덕션 환경에서 SQL 출력 비활성화 등 환경별 로깅 설정 추가.
    • 리뷰/자동응답 설정 파일 추가.

@erika0915 erika0915 self-assigned this Aug 13, 2025
@erika0915 erika0915 added the ✨ Feature 새로운 기능 추가 label Aug 13, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 13, 2025

Walkthrough

인터셉터와 AOP 기반 로깅 클래스를 추가·전역 등록하고, 프로파일별 로깅 설정과 Discord 알림을 도입하며 Gradle에 JitPack 및 AOP/Discord 의존성을 추가했다. 일부 JPA SQL 로그 설정을 프로덕션용 yml로 옮겼다.

Changes

Cohort / File(s) Change Summary
빌드/의존성
build.gradle
JitPack 저장소(maven { url 'https://jitpack.io' }) 추가 및 implementation 'org.springframework.boot:spring-boot-starter-aop', implementation 'com.github.napstr:logback-discord-appender:1.0.0' 의존성 추가.
웹 구성 / 인터셉터 등록
src/main/java/com/kkinikong/be/global/config/WebConfig.java
LoggingInterceptor를 Spring MVC 전역 인터셉터로 등록(경로 패턴: /api/**).
로깅: Interceptor / AOP
src/main/java/com/kkinikong/be/global/logging/LoggingInterceptor.java, src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java
HTTP 요청/응답 시간 및 상태 기반 로깅 인터셉터 추가. Service 계층 실행시간 측정용 Around 어드바이스 및 Repository 반환 타입 로깅용 AfterReturning 어드바이스 추가.
예외 처리 로그 포맷
src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java
예외/정보 로그 포맷을 더 간결한 단일라인 형태로 변경(핵심 처리 흐름에는 변경 없음).
로깅 설정 파일
src/main/resources/logback-spring.xml
로컬/프로덕션 프로필 분기 추가. 로컬은 Hibernate SQL 디버그 활성화, 프로덕션은 SQL 로그 비활성화·로거 레벨 조정 및 DiscordAppender(비동기)로 ERROR 전송 구성.
애플리케이션 설정
src/main/resources/application.yml, src/main/resources/application-prod.yml
기본 application.yml에서 JPA SQL 로그/다이얼렉트 항목 제거. application-prod.yml에 Hibernate SQL 표시/포맷 비활성화 및 logging.discord.webhook-url: ${DISCORD_WEBHOOK_URL} 추가.
CI/도구 설정
.coderabbit.yaml
코드리뷰/자동응답 설정 파일 신규 추가(한국어, 자동리뷰·자동응답 등 구성).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client
  participant D as Dispatcher (Spring MVC)
  participant I as LoggingInterceptor
  participant H as Controller/Handler
  participant E as GlobalExceptionHandler

  C->>D: HTTP 요청 (/api/**)
  D->>I: preHandle (시작시간 저장)
  D->>H: 핸들러 실행
  alt 예외 발생
    H-->>D: 예외 throw
    D->>E: 예외 처리 및 로그
  else 정상 처리
    H-->>D: 응답 반환
  end
  D->>I: afterCompletion (상태, 소요시간 계산)
  I-->>C: 응답 완료 (상태에 따라 INFO/WARN/ERROR 로그)
Loading
sequenceDiagram
  autonumber
  participant A as LoggingAspect
  participant S as Service Layer
  participant R as Repository Layer

  A->>S: Around advice 진입 (메서드 호출)
  A->>A: 시작시간 기록
  S->>R: Repository 호출
  R-->>S: 결과 반환
  A->>A: 실행시간 계산 및 INFO/경고 로그
  A-->>S: 원래 결과 반환

  A->>R: AfterReturning (Repository 메서드 성공 반환)
  A-->>A: 반환 타입 로깅
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

깡총! 요청이 오면 난 시곗줄에 뛰어들어,
시간 쟤고 상태 속삭이며 흔적을 남겨,
서비스는 탭, 저장소는 결과를 속삭여,
밤엔 디스코드가 경보를 울리네,
토끼는 웃으며 로그에 당근을 꽂네. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/SCRUM-355-prod-logging

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@erika0915 erika0915 changed the title [SCRUM-355] Feat: 로그 시스템 구축 [SCRUM-355] Feat: 로깅 시스템 구축 Aug 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🔭 Outside diff range comments (2)
src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java (2)

90-95: 메서드명 오타: ReviewException 핸들러 이름을 수정하세요.

ReviewException을 처리하는데 메서드명이 handleS3Exception으로 되어 있어 혼란을 줍니다.

-  public ResponseEntity<Object> handleS3Exception(
-      final ReviewException e, HttpServletRequest request) {
+  public ResponseEntity<Object> handleReviewException(
+      final ReviewException e, HttpServletRequest request) {

129-135: DTO 검증 실패(400)에 대해서도 로그를 남기세요.

현재 MethodArgumentNotValidException 처리에서 로그가 남지 않습니다. 인터셉터 외에도 여기서 일관된 포맷으로 남기면 추적성이 좋아집니다.

@@
   @Override
   public ResponseEntity<Object> handleMethodArgumentNotValid(
       @NonNull MethodArgumentNotValidException e,
       @NonNull HttpHeaders headers,
       @NonNull HttpStatusCode status,
       @NonNull WebRequest request) {
-    return handleExceptionInternal(e);
+    // WebRequest -> HttpServletRequest로 변환 가능 시 400 로그 기록
+    if (request instanceof org.springframework.web.context.request.ServletWebRequest swr) {
+      logInfo(GlobalErrorCode.INVALID_PARAMETER, e, swr.getRequest());
+    }
+    return handleExceptionInternal(e);
   }

추가 import 필요 없음(Java 17 pattern matching 사용 시 완전한 한정명으로 처리).

🧹 Nitpick comments (9)
.coderabbit.yaml (3)

5-5: request_changes_workflow의 동작 의미를 정확히 표기해주세요.

주석에 “리뷰 끝나면 알아서 PR 승인”이라고 되어 있으나, 해당 옵션은 “코멘트(요청 변경)들이 해결되면 승인” 워크플로를 활성화하는 설정입니다. 자동 병합/즉시 승인은 아닙니다. 혼동 방지를 위해 주석을 보완해 주세요.

-  request_changes_workflow: true # 코드래빗이 리뷰 끝나면 알아서 PR 승인
+  request_changes_workflow: true # 요청 변경이 모두 해결되면 CodeRabbit이 승인 처리(즉시 자동 승인/병합 아님)

7-7: 시끄러운 출력 방지: poem 설정은 비활성화를 고려하세요.

실서비스/팀 레포지토리에서는 리뷰 코멘트에 시를 포함하는 옵션은 불필요한 노이즈일 수 있습니다. 기본값 유지 또는 false로 두는 것을 권장합니다.

-  poem: true
+  poem: false

14-14: 파일 말미 개행(Newline) 누락을 수정해주세요.

YAMLLint가 EOF 개행 누락을 지적하고 있습니다. 말미에 빈 줄을 추가해 주세요.

 chat:
   auto_reply: true
+
build.gradle (1)

101-104: Discord Appender는 runtimeOnly로 지정하세요.

Logback Appender는 런타임에서만 필요하며 컴파일 타임 노출이 불필요합니다. 의존성 스코프를 runtimeOnly로 낮추면 컴파일 클래스패스가 깔끔해집니다.

 // AOP
 implementation 'org.springframework.boot:spring-boot-starter-aop'

 // Discord
-implementation 'com.github.napstr:logback-discord-appender:1.0.0'
+runtimeOnly 'com.github.napstr:logback-discord-appender:1.0.0'
src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java (2)

41-42: 로그 포맷 간결화는 좋으나, 클래스명은 simpleName이 가독성에 유리합니다.

전체 클래스명 대신 simpleName을 사용하면 로그 가독성이 개선됩니다. 또한 상태는 숫자 코드로 고정하면 파싱이 수월합니다.

-  private static final String LOG_FORMAT_INFO = "[🔵INFO] - ({} {}) {} {}: {}";
+  private static final String LOG_FORMAT_INFO = "[🔵INFO] - ({} {}) {} {}: {}"; // 상태코드 숫자/클래스 simpleName 사용 권장
@@
-        ec.getHttpStatus(),
-        e.getClass().getName(),
+        ec.getHttpStatus().value(),
+        e.getClass().getSimpleName(),

187-195: 예외 메시지(PII) 노출 최소화 권장.

e.getMessage()에 사용자 입력/민감정보가 포함될 수 있습니다. 필요 시 마스킹 전략을 도입하거나, 사용자 메시지 대신 사전 정의된 ErrorCode 메시지로 제한하는 것을 고려하세요.

src/main/java/com/kkinikong/be/global/config/WebConfig.java (1)

19-22: 정적 리소스 및 에러 엔드포인트 추가 제외 권장.

현재 swagger, api-docs, actuator만 제외되어 있습니다. 불필요한 노이즈를 줄이려면 정적 리소스 및 기본 에러 경로도 제외하세요.

     registry
         .addInterceptor(loggingInterceptor)
         .addPathPatterns("/**")
-        .excludePathPatterns("/swagger-ui/**", "/v3/api-docs/**", "/actuator/**");
+        .excludePathPatterns(
+            "/swagger-ui/**",
+            "/swagger-resources/**",
+            "/webjars/**",
+            "/v3/api-docs/**",
+            "/actuator/**",
+            "/error",
+            "/favicon.ico");
src/main/java/com/kkinikong/be/global/logging/LoggingInterceptor.java (1)

14-14: 상수 네이밍 컨벤션을 따르세요.

상수명은 스네이크 케이스를 사용하는 것이 Java 컨벤션에 맞습니다.

다음 diff를 적용하여 네이밍을 개선하세요:

-  private static final String START_TIME = "start_time";
+  private static final String START_TIME_ATTRIBUTE = "start_time";
src/main/resources/logback-spring.xml (1)

37-37: 로그 메시지에 마크다운 형식 개선이 필요합니다.

현재 패턴에서 예외 스택트레이스가 항상 마크다운 코드 블록으로 감싸지는데, 예외가 없는 경우 빈 코드 블록이 전송될 수 있습니다.

다음 diff를 적용하여 조건부 마크다운 포맷을 고려하세요:

-                <pattern>[%d{yyyy-MM-dd HH:mm:ss}] %-5level %logger{36} - %msg%n```%ex{10}```</pattern>
+                <pattern>[%d{yyyy-MM-dd HH:mm:ss}] %-5level %logger{36} - %msg%n%ex{10}</pattern>
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d89950d and baa6bfe.

📒 Files selected for processing (9)
  • .coderabbit.yaml (1 hunks)
  • build.gradle (2 hunks)
  • src/main/java/com/kkinikong/be/global/config/WebConfig.java (1 hunks)
  • src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java (1 hunks)
  • src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java (1 hunks)
  • src/main/java/com/kkinikong/be/global/logging/LoggingInterceptor.java (1 hunks)
  • src/main/resources/application-prod.yml (1 hunks)
  • src/main/resources/application.yml (0 hunks)
  • src/main/resources/logback-spring.xml (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/resources/application.yml
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.coderabbit.yaml

[error] 14-14: no new line character at the end of file

(new-line-at-end-of-file)

🔇 Additional comments (8)
.coderabbit.yaml (1)

10-13: 자동 리뷰 설정 적절합니다.

auto_review.enabled/drafts 설정이 목적에 부합합니다. 추가로 필요 시 labels/base_branches로 범위를 좁히는 것도 고려해 볼 수 있습니다.

src/main/resources/application-prod.yml (1)

10-17: 운영 환경에서 SQL 로그 억제 구성 적절합니다.

Hibernate/JPA의 show_sql, format_sql, highlight_sql, use_sql_comments를 모두 꺼서 운영 로그 노이즈를 줄였습니다. 운영에서의 성능/보안 측면에 부합합니다.

src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java (1)

187-199: Throwable 전달 방식 적절합니다.

ERROR 로그에서 플레이스홀더 2개(메서드, URI) + 마지막 인자로 Throwable을 전달하여 스택트레이스가 포함되도록 한 접근이 맞습니다.

src/main/java/com/kkinikong/be/global/logging/LoggingInterceptor.java (1)

35-41: 로깅 레벨과 메시지 일관성이 좋습니다.

HTTP 상태 코드에 따른 로깅 레벨 분류가 적절하고, 이모지를 사용한 시각적 구분과 일관된 메시지 포맷이 잘 구현되어 있습니다.

src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java (2)

28-35: Repository 로깅 로직이 적절합니다.

메서드 실행 후 결과 타입을 로깅하는 방식이 깔끔하고, null 체크도 잘 되어 있습니다.


17-17: Service·Repository 포인트컷 표현식은 이미 일관적입니다.
두 패턴 모두 execution(* com.kkinikong.be..*Xxx.*(..)) 구조를 따르고 있으며,
@Around vs @AfterReturning 차이는 서비스 실행 시간 측정과 레포지토리 호출 후 반환값 로깅이라는 서로 다른 로직을 위해 의도된 어드바이스 타입 구분이므로 별도 수정이 필요하지 않습니다.

Likely an incorrect or invalid review comment.

src/main/resources/logback-spring.xml (2)

34-41: Discord 알림 설정이 잘 구성되어 있습니다.

웹훅 URI를 환경변수로 관리하고, 한국어 사용자명과 적절한 메시지 포맷을 사용한 점이 좋습니다.


43-48: 비동기 Discord 앱펜더 설정이 적절합니다.

ERROR 레벨 필터링과 비동기 처리 설정이 성능상 좋은 구성입니다.

@erika0915 erika0915 requested a review from chaen-ing August 14, 2025 13:25
Copy link
Member

@chaen-ing chaen-ing left a comment

Choose a reason for hiding this comment

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

완전 수고했당!!!~~
넘 늦게 확인해서 미안,,,🥹🥹 진짜 Granfa연결해봐도 좋을듯합니다!!

erika0915 and others added 3 commits August 16, 2025 23:06
…or.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/main/java/com/kkinikong/be/global/config/WebConfig.java (2)

18-20: 헬스체크/문서/에러 엔드포인트는 기본 제외 권장

운영·로컬 모두에서 노이즈를 크게 줄이고 의미 있는 요청만 로깅하려면 actuator/health, Swagger, 에러 엔드포인트 등을 제외하는 것이 좋습니다.

다음 변경으로 제외 패턴을 추가해 주세요:

-    registry.addInterceptor(loggingInterceptor).addPathPatterns("/api/**");
+    registry.addInterceptor(loggingInterceptor)
+        .addPathPatterns("/api/**")
+        .excludePathPatterns(
+            "/error", "/error/**",
+            "/actuator/**",
+            "/health", "/actuator/health",
+            "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html",
+            "/favicon.ico"
+        );

15-20: 프로파일별 비활성화(예: prod) 시 컨텍스트 실패 방지용 선택적 주입 권장

현재는 LoggingInterceptor 빈이 존재하지 않으면 애플리케이션이 부팅에 실패합니다. 로컬에서만 활성, 운영에서 비활성 같은 전략을 고려 중이라면 선택적 주입(ObjectProvider)로 전환해 조건부 등록을 추천합니다.

아래와 같이 수정하면 해당 빈이 없는 프로파일에서도 안전하게 부팅됩니다.

@@
 package com.kkinikong.be.global.config;
 
+import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 import lombok.RequiredArgsConstructor;
 
 import com.kkinikong.be.global.logging.LoggingInterceptor;
 
 @Configuration
 @RequiredArgsConstructor
 public class WebConfig implements WebMvcConfigurer {
 
-  private final LoggingInterceptor loggingInterceptor;
+  private final ObjectProvider<LoggingInterceptor> loggingInterceptorProvider;
 
   @Override
   public void addInterceptors(InterceptorRegistry registry) {
-    registry.addInterceptor(loggingInterceptor).addPathPatterns("/api/**");
+    LoggingInterceptor interceptor = loggingInterceptorProvider.getIfAvailable();
+    if (interceptor != null) {
+      registry.addInterceptor(interceptor).addPathPatterns("/api/**");
+    }
   }
 }

참고: Spring Boot를 사용한다면 대안으로 @ConditionalOnBean(LoggingInterceptor.class)를 WebConfig에 추가하는 방법도 있습니다.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 98acc48 and 1522c4b.

📒 Files selected for processing (2)
  • src/main/java/com/kkinikong/be/global/config/WebConfig.java (1 hunks)
  • src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java
🔇 Additional comments (2)
src/main/java/com/kkinikong/be/global/config/WebConfig.java (2)

11-13: 구성 클래스/인터셉터 등록 구조 적절

@configuration + WebMvcConfigurer 조합과 생성자 주입(@requiredargsconstructor)은 표준적이며, 인터셉터 등록 책임이 명확합니다. 👍


15-15: 확인 결과 LoggingInterceptor@Component 애노테이션으로 등록되어 있어 WebConfig 생성자 주입 시 빈 주입에 문제가 없습니다.

@erika0915 erika0915 merged commit 259bf32 into develop Aug 17, 2025
2 checks passed
@erika0915 erika0915 deleted the feat/SCRUM-355-prod-logging branch August 18, 2025 11:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants