Skip to content

#452 [Merge] dev 변경사항을 main에 반영 (v2.0.38) - #453

Merged
si-zero merged 73 commits into
mainfrom
merge/#452
Sep 9, 2026
Merged

#452 [Merge] dev 변경사항을 main에 반영 (v2.0.38)#453
si-zero merged 73 commits into
mainfrom
merge/#452

Conversation

@Roy-wonji

Copy link
Copy Markdown
Contributor

closes #452

dev 72커밋을 프로덕션(main)에 반영한다.

범위

유형
Feat 29
Fix 26
Refactor 5
Docs · Chore 4

주요 변경

배경

AdminWeb /ad집계를 불러오지 못했습니다 로 실패한다. 코드·스펙은 서로 맞는다 — swagger(dev.picke.store) 와 AdminWeb 의 AdHttpRepository 를 대조해 엔드포인트 7개와 AdCreativeResponse·PageResponse 필드가 전부 일치함을 확인했다. 원인은 오직 프로덕션 미배포다. 대시보드 지표 API 도 같은 상태라 /dashboard 일부도 영향을 받는다.

검증

  • 로컬 ./gradlew build 통과
  • 로컬 ./gradlew test — 240개 중 238개 통과. 실패 2건은 ffmpeg 미설치로 인한 로컬 환경 문제이며(CI 는 설치함) 시나리오 도메인 테스트다. 광고 도메인 테스트는 AdApiIntegrationTest·AdminAdServiceTest·AdQueryServiceTest 등 전부 통과
  • CI 결과는 이 PR 체크 참고

HYH0804 and others added 30 commits May 27, 2026 21:58
## #️⃣ 연관된 이슈
<!-- Ex) - #이슈번호 -->
<!-- 연관된 이슈 번호를 링크 형태로 작성하세요 -->
- #250 

## 📝 작업 내용
<!-- 이번 PR/이슈에서 실제 수행한 작업 내용을 작성하세요 -->

### ♻️ Refactor
<!-- 기존 코드 리팩토링 내용 작성 -->
| 내용 | 파일 |
|------|------|
| 불필요한 import 제거 | `UserService.java` |
| 투표 비율 계산 기준을 preVoteOption → postVoteOption으로 수정 |
`BattleVoteServiceImpl.java` |
| totalCount도 사후 투표 완료된 건만 카운트하도록 수정 | `BattleVoteServiceImpl.java` |
| countByBattleAndPostVoteOption,
countByBattleAndPostVoteOptionIsNotNull 메서드 추가 |
`BattleVoteServiceImpl.java` |

## 📌 공유 사항
<!-- 팀원에게 공유할 내용이나 참고 사항 작성 -->
<!-- 노션 환경 설정 파일 확인 부탁드립니다! -->
> ▎ 1. 기존 코드에서 투표 비율(%)이 preVoteOption 기준으로 계산되어 사전 투표만 한 유저도 카운트에 포함되고
있었습니다.
  ▎ 2. 사후 투표(postVoteOption)가 완료된 건만 기준으로 비율을 계산하도록 수정했습니다.

## ✅ 체크리스트
<!-- PR 제출 전에 체크해야 할 사항들 -->
- [x] Reviewer에 팀원들을 선택했나요?
- [x] Assignees에 본인을 선택했나요?
- [x] 컨벤션에 맞는 Type을 선택했나요?
- [x] Development에 이슈를 연동했나요?
- [x] Merge 하려는 브랜치가 올바르게 설정되어 있나요?
- [x] 컨벤션을 지키고 있나요?
- [x] 로컬에서 실행했을 때 에러가 발생하지 않나요?
- [x] 팀원들에게 PR 링크 공유를 했나요?

## 📸 스크린샷
<!-- Swagger, Postman, JUnit 테스트 화면 첨부 -->
<!-- 기능 동작 화면이나 테스트 결과 캡처를 첨부하면 좋습니다 -->

## 💬 리뷰 요구사항
<!-- 리뷰어에게 요청하는 구체적인 사항 작성 -->
<!-- 종료 의도 판단을 Java 키워드 → AI 2차 검증 구조로 설계했는데
해당 구조가 유지보수 및 확장 측면에서 적절한지 의견 부탁드립니다. -->
> 1.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## #️ 연관된 이슈
  - #254

  ## 📝 작업 내용

  ### ♻️ Refactor
  | 내용 | 파일 |
  |------|------|
  | 관점 등록/수정 시 GPT 검수 주석 코드 제거 | `PerspectiveService.java` |

  ## 📌 공유 사항
> 1. 기존에 `createPerspective()`, `updatePerspective()`에서 GPT 검수 호출이 주석
처리된 채 남아있던 dead code를 제거했습니다. 동작 방식은 동일하게 등록/수정 즉시 `PUBLISHED` 상태로
저장됩니다.

  ## ✅  체크리스트
  - [x] Reviewer에 팀원들을 선택했나요?
  - [x] Assignees에 본인을 선택했나요?
  - [x] 컨벤션에 맞는 Type을 선택했나요?
  - [x] Development에 이슈를 연동했나요?
  - [x] Merge 하려는 브랜치가 올바르게 설정되어 있나요?
  - [x] 컨벤션을 지키고 있나요?
  - [x] 로컬에서 실행했을 때 에러가 발생하지 않나요?
  - [x] 팀원들에게 PR 링크 공유를 했나요?

  ## 📸 스크린샷
  해당 없음 (코드 정리 작업)

  ## 💬 리뷰 요구사항
  > 1. 없습니다.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## #️ 연관된 이슈
  - #255

  ## 📝 작업 내용

  ### ♻️ Refactor
  | 내용 | 파일 |
  |------|------|
| VoteStatsResponse OptionStat에 title 필드 추가 | `VoteStatsResponse.java`,
`BattleVoteServiceImpl.java` |

  ## 📌 공유 사항
> 1. `GET /api/v1/battles/{battleId}/vote-stats` 응답의 `OptionStat`에
`title` 필드가 추가되었습니다. 옵션 이름(ex. "변기는 변기다")을 투표 % 바 및 관점 탭 구성에 활용해 주세요.
> 2. 관점 목록 조회 시 옵션 탭 필터는 `optionId` 파라미터로 전달하면 됩니다. (`GET
/api/v1/battles/{battleId}/perspectives?optionId={optionId}`)

  ## ✅  체크리스트
  - [x] Reviewer에 팀원들을 선택했나요?
  - [x] Assignees에 본인을 선택했나요?
  - [x] 컨벤션에 맞는 Type을 선택했나요?
  - [x] Development에 이슈를 연동했나요?
  - [x] Merge 하려는 브랜치가 올바르게 설정되어 있나요?
  - [x] 컨벤션을 지키고 있나요?
  - [x] 로컬에서 실행했을 때 에러가 발생하지 않나요?
  - [x] 팀원들에게 PR 링크 공유를 했나요?

  ## 📸 스크린샷
  해당 없음 (응답 필드 추가)

  ## 💬 리뷰 요구사항
  > 1. 없습니다.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## #️⃣연관된 이슈
  - #262
  
  ## 📝 작업 내용

  ### ✨ Feat                                                           
  | 내용 | 파일 |
  |------|------|
| 디바이스 푸시 토큰 등록/해제 API 추가 (Android: FCM 토큰, iOS: APNs 디바이스 토큰) |
`DeviceController.java`, `DeviceService.java`,
`RegisterDeviceRequest.java`,
`UserDevice.java`, `DevicePlatform.java`, `UserDeviceRepository.java` |
| FCM(Android) 푸시 발송 인프라 구축 (Firebase Admin SDK) |
`FirebaseConfig.java`, `FcmPushService.java`, `build.gradle` |
| iOS 푸시를 FCM 경유 방식에서 다이렉트 APNs 발송으로 전환 (Pushy) | `ApnsConfig.java`,
`ApnsPushService.java`, `FcmPushService.java`,
`NotificationDispatchService.java`,
  `build.gradle` |
| 새 배틀 발행 시 인앱 알림 + 푸시 발송 | `BattleServiceImpl.java`,
`NotificationDispatchService.java` |
| 답글 좋아요 / 새 댓글 발생 시 인앱 알림 + 푸시 발송 | `CommentLikeService.java`,
`PerspectiveCommentService.java`, `NotificationDispatchService.java` |
  | 포인트 적립 시 인앱 알림 발송 | `CreditService.java` |
  | 알림 API 명세 문서 작성 | `docs/api-specs/notification-api.md` |

  ### ♻️ Refactor
  | 내용 | 파일 |
  |------|------|
| 답글 좋아요/새 댓글 알림 문구에 배틀 제목 포함하도록 개선 |
`NotificationDispatchService.java`, `CommentLikeService.java`,
`PerspectiveCommentService.java` |

  ### 🐛 Fix
  | 내용 | 파일 |
  |------|------|
| 컨테이너 배포 환경(Railway)에서 FCM/APNs 자격증명 파일(JSON/.p8)을 읽지 못해 서버 기동 자체가 실패하던
문제 수정 — S3에서 자격증명을 다운로드해 사용하도록 변경 (로컬은 기존
파일 경로 방식 그대로 폴백) | `FirebaseConfig.java`, `ApnsConfig.java`,
`application.yml` |

  ## 📌 공유 사항
> 1. **(중요) Railway dev Variables 추가 완료** — 이 PR이 배포되려면 아래 값이 필요하며, dev
환경엔 이미 세팅해뒀습니다.
> - `FCM_CREDENTIALS_S3_KEY`, `APNS_CREDENTIALS_S3_KEY` (S3
`pique-bucket/credentials/`에 Firebase 서비스 계정 JSON, APNs `.p8` 키 업로드 완료)
> - `APNS_ENABLED=true`, `APNS_KEY_ID`, `APNS_BUNDLE_ID`,
`APNS_PRODUCTION`
  >    - `APNS_TEAM_ID`는 따로 안 넣어도 기존 `APPLE_TEAM_ID`로 폴백됩니다.
  > 2. **운영(main) 배포 시에도 동일하게 Railway 변수 추가 + S3 파일 업로드가 필요**합니다.
> 3. iOS는 더 이상 FCM을 거치지 않고 서버가 APNs로 직접 발송합니다. 디바이스 등록 시 `fcmToken` 필드에
iOS는 APNs 디바이스 토큰(hex 문자열)을 보내야 합니다. 자세한 내용은
  `docs/api-specs/notification-api.md` 참고.
  > 4. 새 의존성 추가: `firebase-admin:9.9.0`, `com.eatthepath:pushy:0.15.4`

  ## ✅ 체크리스트
  - [x] Reviewer에 팀원들을 선택했나요?
  - [x] Assignees에 본인을 선택했나요?
  - [x] 컨벤션에 맞는 Type을 선택했나요?
  - [x] Development에 이슈를 연동했나요?
  - [x] Merge 하려는 브랜치가 올바르게 설정되어 있나요?
  - [x] 컨벤션을 지키고 있나요?
  - [x] 로컬에서 실행했을 때 에러가 발생하지 않나요?
  - [x] 팀원들에게 PR 링크 공유를 했나요?

  ## 📸 스크린샷
  <!-- Swagger/Postman으로 디바이스 등록, 알림함 조회, 푸시 수신 테스트 캡처 첨부 -->

  ## 💬 리뷰 요구사항
> 1. APNs 환경(sandbox/production)이 `APNS_PRODUCTION` 전역 설정 1개로 고정되는 구조인데,
개발(TestFlight)/운영(App Store) 빌드를 동시에 지원하려면 별도 설계가 필요해 보입니다 —
  의견 부탁드립니다.
> 2. FCM/APNs 자격증명을 S3에서 받아오는 방식(이번 Fix)이 적절한지, 다른 방식을 선호하시면 의견 부탁드립니다.

---------

Co-authored-by: 현준혁 <guswnsgur2276@metabuild.co.kr>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
createTempFile로 생성된 빈 파일이 이미 존재해 S3 getObject의
toFile 다운로드가 FileAlreadyExistsException으로 실패하던 문제 수정
## #️ 연관된 이슈
  - #262

  ## 📝 작업 내용

  ### ✨  Feat
  | 내용 | 파일 |
  |------|------|
| 새 배틀/답글 좋아요/새 댓글/관리자 공지·이벤트 알림 발송 시 UserSettings의 ON/OFF 설정을 확인해 OFF인
사용자에게는 푸시를 보내지 않도록 분기 (인앱 알림은 항상 생성) |
`NotificationDispatchService.java`,
`UserSettingsRepository.java`, `UserDeviceRepository.java`,
`AdminNotificationService.java` |
| 오늘의 픽으로 자동 배정된 배틀에도 새 배틀 알림(인앱+푸시) 발송 추가 | `BattleServiceImpl.java` |

  ### 🐛 Fix
  | 내용 | 파일 |
  |------|------|
| 관점/댓글 삭제 시 좋아요·신고 잔여 데이터가 남아 FK 제약 조건 위반 오류가 발생하던 문제 수정 |
`PerspectiveService.java`, `PerspectiveCommentService.java`,
`CommentLikeRepository.java`,
`CommentReportRepository.java`, `PerspectiveCommentRepository.java`,
`PerspectiveLikeRepository.java`, `PerspectiveReportRepository.java` |

  ## 📌 공유 사항
  > 1. 알림 ON/OFF 설정 매핑은 다음과 같습니다.
  >    - `newBattleEnabled` → 새 배틀 알림
  >    - `contentLikeEnabled` → 좋아요 알림
  >    - `newCommentEnabled` → 새 댓글 알림
  >    - `marketingEventEnabled` → 이벤트 및 소식 알림 (공지/이벤트)
> - `commentReplyEnabled`, `battleResultEnabled` → 현재 매핑되는 알림 이벤트가 없어 보류
(정책 미정)
> 2. OFF 상태여도 인앱 Notification은 항상 생성되고, 푸시 발송만 차단됩니다. UserSettings가 없는
레거시 유저는 기본값 ON으로 처리됩니다.

  ## ✅  체크리스트
  - [x] Reviewer에 팀원들을 선택했나요?
  - [x] Assignees에 본인을 선택했나요?
  - [x] 컨벤션에 맞는 Type을 선택했나요?
  - [x] Development에 이슈를 연동했나요?
  - [x] Merge 하려는 브랜치가 올바르게 설정되어 있나요?
  - [x] 컨벤션을 지키고 있나요?
  - [x] 로컬에서 실행했을 때 에러가 발생하지 않나요?
  - [x] 팀원들에게 PR 링크 공유를 했나요?

  ## 📸 스크린샷


  ## 💬 리뷰 요구사항
> 1. 관리자 공지/이벤트 알림(POLICY_CHANGE/PROMOTION)을 `marketingEventEnabled` 하나로
묶어서 게이팅했는데, 이 매핑이 적절한지 의견 부탁드립니다.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## #️⃣ 연관된 이슈
<!-- Ex) - #이슈번호 -->
<!-- 연관된 이슈 번호를 링크 형태로 작성하세요 -->
- closed #268  

## 📝 작업 내용
<!-- 이번 PR/이슈에서 실제 수행한 작업 내용을 작성하세요 -->

### 🔨 Chore
<!-- 새로운 기능 구현 내용 작성 -->
| 내용 | 파일 |
|------|------|
| 크롤링 파일 추가 | `app-ads.txt` |
|  |  |

## 📌 공유 사항
<!-- 팀원에게 공유할 내용이나 참고 사항 작성 -->
<!-- 노션 환경 설정 파일 확인 부탁드립니다! -->
> 없음

## ✅ 체크리스트
<!-- PR 제출 전에 체크해야 할 사항들 -->
- [x] Reviewer에 팀원들을 선택했나요?
- [x] Assignees에 본인을 선택했나요?
- [x] 컨벤션에 맞는 Type을 선택했나요?
- [x] Development에 이슈를 연동했나요?
- [x] Merge 하려는 브랜치가 올바르게 설정되어 있나요?
- [x] 컨벤션을 지키고 있나요?
- [x] 로컬에서 실행했을 때 에러가 발생하지 않나요?
- [ ] 팀원들에게 PR 링크 공유를 했나요?

## 📸 스크린샷
<!-- Swagger, Postman, JUnit 테스트 화면 첨부 -->
<!-- 기능 동작 화면이나 테스트 결과 캡처를 첨부하면 좋습니다 -->
> 없음

## 💬 리뷰 요구사항
<!-- 리뷰어에게 요청하는 구체적인 사항 작성 -->
<!-- 종료 의도 판단을 Java 키워드 → AI 2차 검증 구조로 설계했는데
해당 구조가 유지보수 및 확장 측면에서 적절한지 의견 부탁드립니다. -->
> 없음
## #️⃣ 연관된 이슈
<!-- Ex) - #이슈번호 -->
<!-- 연관된 이슈 번호를 링크 형태로 작성하세요 -->
- #268

## 📝 작업 내용
<!-- 이번 PR/이슈에서 실제 수행한 작업 내용을 작성하세요 -->

### ✨ Feat
<!-- 새로운 기능 구현 내용 작성 -->
| 내용 | 파일 |
|------|------|
| 허용 설정 추가 | `SecurityConfig.java` |
|  |  |

## 📌 공유 사항
<!-- 팀원에게 공유할 내용이나 참고 사항 작성 -->
<!-- 노션 환경 설정 파일 확인 부탁드립니다! -->
> 없음

## ✅ 체크리스트
<!-- PR 제출 전에 체크해야 할 사항들 -->
- [x] Reviewer에 팀원들을 선택했나요?
- [x] Assignees에 본인을 선택했나요?
- [x] 컨벤션에 맞는 Type을 선택했나요?
- [x] Development에 이슈를 연동했나요?
- [x] Merge 하려는 브랜치가 올바르게 설정되어 있나요?
- [x] 컨벤션을 지키고 있나요?
- [x] 로컬에서 실행했을 때 에러가 발생하지 않나요?
- [ ] 팀원들에게 PR 링크 공유를 했나요?

## 📸 스크린샷
<!-- Swagger, Postman, JUnit 테스트 화면 첨부 -->
<!-- 기능 동작 화면이나 테스트 결과 캡처를 첨부하면 좋습니다 -->
> 없음

## 💬 리뷰 요구사항
<!-- 리뷰어에게 요청하는 구체적인 사항 작성 -->
<!-- 종료 의도 판단을 Java 키워드 → AI 2차 검증 구조로 설계했는데
해당 구조가 유지보수 및 확장 측면에서 적절한지 의견 부탁드립니다. -->
> 없음
si-zero and others added 19 commits August 26, 2026 16:24
## 문제

dev 스웨거에서 광고 API 를 Try it out 하면 401 이 떨어집니다.

```
https://dev.picke.store/swagger-ui/index.html?urls.primaryName=3.+광고+API
→ Execute
→ 401 AUTH_401 "인증이 필요합니다"
```

요청이 dev 가 아니라 **운영으로 나가고 있었습니다.** Swagger UI 는 서버 목록의 첫 번째를 기본으로 골라 두는데,
공통 목록이 운영을 맨 앞에 두고 있습니다.

```
1. https://picke.store      ← 기본 선택
2. http://localhost:8080
3. https://dev.picke.store
```

운영에는 광고 경로가 아직 배포되지 않아 JwtFilter 화이트리스트에 없고, 그래서 401 입니다.

| 요청 대상 | 결과 |
|---|---|
| `dev.picke.store/api/v1/ads?slot=HOME_FEED` | 200
`{"statusCode":200,"data":[]}` |
| `picke.store/api/v1/ads?slot=HOME_FEED` | 401 `AUTH_401` |

지금은 401 로 막히지만, 광고가 운영에 배포되면 같은 실수가 조용히 통과합니다. 광고 그룹에는 소재 등록·수정·삭제가 함께
묶여 있어 **운영 데이터가 바뀝니다.**

## 왜 프로파일로 가르지 않는가

`prod` 프로파일이면 운영, 아니면 dev 로 나누는 방법을 먼저 검토했습니다. **쓸 수 없습니다.**

dev 서버도 `prod` 프로파일로 돕니다. 부팅 로그에 그대로 남아 있습니다.

```
The following 1 profile is active: "prod"     ← dev.picke.store 컨테이너
```

`application-prod.yml` 에도 호스트를 가르는 설정이 없습니다. 프로파일로 나누면 dev 스웨거가 운영을 가리키는
지금 상태가 그대로 유지됩니다.

## 변경

- 광고 그룹의 서버 목록 맨 앞에 상대 경로(`/`)를 둔다. Swagger UI 가 이를 현재 origin 으로 풀어 주므로,
운영에서 연 문서는 운영으로, dev 에서 연 문서는 dev 로 나간다.
- 절대 주소 세 개는 목록에 남겨 둔다. 다른 환경을 일부러 고르는 것은 그대로 가능하다.
- 다른 그룹(사용자·관리자·전체)의 서버 순서는 건드리지 않는다.
- 서버 정의가 두 곳에서 필요해져 메서드로 뽑았다. 값은 그대로다.
- 광고 그룹의 기본 서버와, 다른 그룹이 종전 순서를 유지하는지 검사하는 테스트를 추가한다.

## 검증

- `./gradlew test --tests "com.swyp.picke.domain.ad.*" --tests
"com.swyp.picke.global.config.*" --rerun-tasks` → BUILD SUCCESSFUL
- `SwaggerAdGroupTest` 4건 통과 (failures 0, errors 0)
- 역검증: 상대 경로를 빼고 운영 우선으로 되돌리면 해당 테스트 FAILED

## 남은 것

이 PR 범위 밖이라 손대지 않았습니다. 별도로 다룰지 판단이 필요합니다.

`slot` 파라미터를 빼면 400 이 아니라 500 이 납니다. 스웨거에서 파라미터를 채우지 않고 Execute 하면 이 응답을
보게 됩니다.

```
GET /api/v1/ads   → 500 COMMON_500 "서버 오류가 발생했습니다"
```

`MissingServletRequestParameterException` 이 전역 핸들러에 잡히지 않는 것으로 보입니다.
## 문제

운영 광고를 스웨거에서 조회할 방법이 없습니다. 광고 그룹의 서버 목록에 `ad.picke.store` 가 아예 없습니다.

세 도메인이 각각 다른 Railway 서비스입니다.

| 도메인 | Railway 서비스 | 광고 기능 |
|---|---|---|
| dev.picke.store | `hqjtvzmx` | 있음 |
| picke.store (운영 API) | `uz2tygnb` | 없음 |
| ad.picke.store (운영 광고) | `u9l7w51v` | 없음 (구 빌드) |

운영에서 광고를 받는 곳은 `ad.picke.store` 인데, 목록에는 `picke.store` 만 있어 고를 수가 없었습니다.

## 변경

- 광고 그룹 서버 목록에 `https://ad.picke.store` 를 추가한다. 문서를 연 주소(`/`) 다음 순서에 둔다.
- 문서를 연 주소를 첫 번째로 두는 동작은 그대로 둔다.
- 다른 그룹의 서버 목록은 건드리지 않는다.

## 검증

- `./gradlew test --tests "com.swyp.picke.domain.ad.*" --tests
"com.swyp.picke.global.*" --rerun-tasks` → BUILD SUCCESSFUL
- `SwaggerAdGroupTest` 5건 통과 (failures 0, errors 0)

## 이 PR 만으로는 운영 광고가 뜨지 않습니다

`ad.picke.store` 서비스가 **광고 코드가 없는 구 빌드**로 돌고 있습니다. 스웨거 그룹이 `0. 모든 API /
1. 사용자 API / 2. 관리자 API` 뿐이고 `3. 광고 API` 가 없습니다. `/` 와 `/c/{code}` 모두
401 이라 클릭 리다이렉트와 랜딩이 동작하지 않습니다.

별도로 필요한 조치입니다.

1. `dev` → `main` 릴리스 (광고 기능이 dev 에만 있음)
2. `u9l7w51v` 서비스를 그 빌드로 재배포
3. 환경변수 주입 (아래)
@si-zero si-zero self-assigned this Sep 9, 2026
@si-zero si-zero added the 🔀 Merge (병합) 브랜치를 Merge할 때 사용합니다. label Sep 9, 2026
@si-zero
si-zero self-requested a review September 9, 2026 03:56
@si-zero si-zero assigned si-zero and Roy-wonji and unassigned si-zero Sep 9, 2026
@si-zero si-zero linked an issue Sep 9, 2026 that may be closed by this pull request
4 tasks
@si-zero
si-zero merged commit 0551d9d into main Sep 9, 2026
1 check passed
@si-zero
si-zero deleted the merge/#452 branch September 9, 2026 04:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔀 Merge (병합) 브랜치를 Merge할 때 사용합니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🔀 Merge: dev를 main에 병합 (v2.0.37)

4 participants