Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
c3d43b8
[Feat] #144 ImageUploader 인터페이스에 MultipartFile 외에 byte[] 업로드 지원 추가
JJUYAAA Nov 26, 2025
f9e7b99
[Feat] #144 S3ImageUploader 인터페이스에 MultipartFile 외에 byte[] 업로드 지원 추가
JJUYAAA Nov 26, 2025
4bbc453
[Feat] #144 유효하지 않은 count 요청 시 커스텀 에러 추가
JJUYAAA Nov 27, 2025
2f69fa5
[Refactor] #144 보호글 detail 전략 공통화 - 기본 조회, S3 랜덤 조회 모두 지원하도록 변경
JJUYAAA Nov 27, 2025
0294486
[Feat] #144 보호글 (s3) 랜덤조회 서비스 인터페이스 생성
JJUYAAA Nov 27, 2025
f89e7dc
[Feat] #144 보호글 (s3) 랜덤조회 기능 구현
JJUYAAA Nov 27, 2025
525e73b
[Feat] #144 보호글 (s3) 랜덤조회 컨트롤러에 추가
JJUYAAA Nov 27, 2025
0d84b70
[Refactor] #144 보호글 shuffle 전 가변리스트로 변환
JJUYAAA Nov 27, 2025
c3d6f07
[Test] #144 보호글(s3 url) 랜덤 조회 서비스 테스트
JJUYAAA Nov 27, 2025
1c483f7
[Test] #144 보호글(s3 url) 랜덤 조회 컨트롤러 테스트
JJUYAAA Nov 27, 2025
5bc3436
[Test] #144 보호글(s3 url) 랜덤 조회 서비스 테스트 추가
JJUYAAA Nov 27, 2025
dec96c4
[Test] #144 보호글(s3 url) 랜덤 조회 서비스 테스트 추가
JJUYAAA Nov 27, 2025
a19939d
[Test] #144 보호글(s3 url) 랜덤 조회 서비스 테스트 추가
JJUYAAA Nov 28, 2025
5f61bd6
[Refactor] #144 사용하지 않는 에러 코드 삭제
JJUYAAA Nov 28, 2025
a994d28
[Refactor] #144 컨트롤러 단에서 count 파라미터 값 검증 추가
JJUYAAA Nov 28, 2025
ca78cf3
[Refactor] #144 오타 수정
JJUYAAA Nov 29, 2025
ce85042
[Refactor] #144 보호글 레포지토리 - 랜덤 조회 메서드 추가
JJUYAAA Nov 29, 2025
aef254a
[Refactor] #144 전체 보호글 조회 후 랜덤 셔플이 아닌, 랜덤 개수만큼만 조회하도록 변경
JJUYAAA Nov 29, 2025
69c56f0
[Refactor] #144 보호글 레포지토리 - 랜덤 조회 메서드 파라미터 수정
JJUYAAA Nov 30, 2025
b6fde7a
[Refactor] #144 webconfig에 restTemplate 스프링빈으로 등록
JJUYAAA Nov 30, 2025
55b4069
[Refactor] #144 서비스가 restTemplate을 외부에서 주입받도록 변경
JJUYAAA Nov 30, 2025
9ffca9c
[Refactor] #144 컨트롤러 테스트 - 이미지 다운로드, 업로드만 모킹하도록 보완
JJUYAAA Nov 30, 2025
3315dfe
[Refactor] #144 서비스 테스트 코드 수정
JJUYAAA Nov 30, 2025
d915f32
Merge pull request #145 from FindYou-Kuit/feat/#144-protectingReport-…
JJUYAAA Dec 1, 2025
6e7ffc5
[Refactor] #146 레포지토리 수정 - 생성일 기준 조회 메서드 추가
JJUYAAA Dec 1, 2025
1f52dc2
[Refactor] #146 서비스 수정 - 작일,금일 보호글 랜덤 조회 방식으로 변경(created_at 기준)
JJUYAAA Dec 1, 2025
8a1bbab
[Refactor] #146 컨트롤러 수정 - 204 응답 시에는 baseresponse로 감싸지 않도록 변경
JJUYAAA Dec 1, 2025
5893835
[Refactor] #146 토큰 검증 없이 통과되도록 permitAll() 설정
JJUYAAA Dec 1, 2025
85b20e0
[Refactor] #146 서비스 테스트 코드 수정
JJUYAAA Dec 1, 2025
9ac7c5a
[Refactor] #146 컨트롤러 테스트 코드 수정, 204 응답 테스트 추가
JJUYAAA Dec 1, 2025
cefb8e6
[Refactor] #146 컨트롤러 테스트 코드 - createdAt 현재 시각으로 주입
JJUYAAA Dec 1, 2025
fd59583
[Refactor] #146 필요없는 주석 삭제
JJUYAAA Dec 1, 2025
402f94d
[Refactor] #146 컨트롤러 테스트 - createdAt 1시간 전으로 수정 (CI 환경 미세한 시간 차이 대비)
JJUYAAA Dec 1, 2025
59c1264
[Refactor] #146 컨트롤러 테스트 - createdAt 하루 전으로 수정 (CI 환경 시간 차이 대비)
JJUYAAA Dec 1, 2025
bbb0878
[Refactor] #146 조회 범위 수정 - end를 지금 이 순간 -> 오늘 밤 끝까지로 변경 (CI 환경 시간 차이 …
JJUYAAA Dec 1, 2025
06d0255
[Refactor] #146 요청 개수가 전체 개수보다 적은 경우 테스트 오류 수정
JJUYAAA Dec 3, 2025
d13a49a
[Refactor] #146 서비스 테스트코드 displayname 더 명확하게 변경
JJUYAAA Dec 3, 2025
798a268
[Refactor] #146 컨트롤러 테스트 - TestInitializer 활용
JJUYAAA Dec 3, 2025
d2adefa
Merge pull request #147 from FindYou-Kuit/refactor/#146-protectingRep…
JJUYAAA Dec 3, 2025
37afd36
[feat] #148 토큰 재발급 컨트롤러 메서드 작성
JangIkhwan Dec 8, 2025
5d24f31
[feat] #148 토큰 재발급 서비스 로직 작성
JangIkhwan Dec 8, 2025
0472cc2
[Test] #148 토큰 재발급 서비스 테스트 작성
JangIkhwan Dec 8, 2025
d2818c9
[Feat] #148 리프레시토큰 레포지토리에 findByUserId 메서드 구현
JangIkhwan Dec 19, 2025
98c691c
[Chore] #148 토큰 재발급 서비스 주석 수정
JangIkhwan Dec 19, 2025
7cc2223
[Feat] #148 게스트 로그인 응답 수정
JangIkhwan Dec 19, 2025
15f9c0f
[Feat] #148 카카오 로그인 응답 수정
JangIkhwan Dec 19, 2025
022a8f9
[Test] #148 테스트용 스프링부트 설정 파일 수정
JangIkhwan Dec 19, 2025
9d80a4a
[Test] #148 AuthService 테스트 코드 수정
JangIkhwan Dec 19, 2025
5946bb2
[Refactor] #148 AuthService 이름을 변경
JangIkhwan Dec 19, 2025
cf082c5
[Refactor] #148 auth의 서비스 레이어에 퍼사드패턴 도입
JangIkhwan Dec 19, 2025
5cde5cb
[Fix] #148 리프레시토큰 캐싱 관련 값을 환경변수로 주입하도록 수정
JangIkhwan Dec 19, 2025
48449b1
[Fix] #148 잘못된 메서드 제거
JangIkhwan Dec 20, 2025
2b5e3f7
[Test] #148 서비스 로직 변경에 따라 테스트 수정
JangIkhwan Dec 20, 2025
82009f1
[Fix] #148 리프레시 토큰에 jti 추가
JangIkhwan Dec 20, 2025
781d6fa
[Test] #148 토큰 재발급 API 테스트 작성 및 테스트 수정
JangIkhwan Dec 20, 2025
8f94057
[Docs] #148 토큰 재발급 API 명세 작성
JangIkhwan Dec 20, 2025
3081c66
[Fix] #148 토큰 재발급 서비스 로직 수정
JangIkhwan Dec 20, 2025
3c8ef42
[Test] #148 ReissueTokenService 테스트 수정
JangIkhwan Dec 20, 2025
70d70b3
[Test] #148 LoginService 테스트 수정
JangIkhwan Dec 20, 2025
564f007
[Test] #148 AuthControllerTest에 테스트용 레디스 컨테이너 설정 적용
JangIkhwan Dec 20, 2025
e45aa0f
[Test] #148 ReissueTokenService 테스트에 케이스 추가
JangIkhwan Dec 20, 2025
34d46b1
[Test] #148 ReissueTokenService 테스트 수정
JangIkhwan Dec 20, 2025
29375db
[Test] #148 AuthControllerTest 주석 수정
JangIkhwan Dec 20, 2025
9c3e390
[Chore] #148 AuthController 로그 수정
JangIkhwan Dec 20, 2025
18f8965
[Chore] #148 LoginServiceImpl의 로그 추가
JangIkhwan Dec 20, 2025
f8415e3
[Feat] #150 컨트롤러에 게스트 여부 조회 컨트롤러 메서드 구현
JangIkhwan Dec 23, 2025
de1f31c
[Feat] #150 게스트 여부 조회 서비스 로직 구현
JangIkhwan Dec 23, 2025
72e81d6
[Test] #150 게스트 여부 조회 API 테스트 작성
JangIkhwan Dec 23, 2025
ffee6df
[Fix] #150 불필요한 DTO 삭제
JangIkhwan Dec 26, 2025
8ba5138
[Refactor] #151 repository수정 - foundByDate
JJUYAAA Dec 27, 2025
53ed6e9
[Refactor] #151 서비스코드 수정 - foundDate 기준으로 어제 날짜 공고만 반환하도록
JJUYAAA Dec 27, 2025
a363882
[Refactor] #151 테스트 코드 수정 - founddate 기준 어제 공고만 반환하도록
JJUYAAA Dec 27, 2025
d24b039
[Fix] #148 레디스 키를 상수로 변경
JangIkhwan Dec 28, 2025
f038010
[Fix] #148 설정파일에서 불필요한 변수 삭제
JangIkhwan Dec 28, 2025
3631960
Merge pull request #149 from FindYou-Kuit/feat/#148-reissue-token
JangIkhwan Dec 28, 2025
2ec1270
[Docs] #150 게스트 여부 조회 API 명세 작성
JangIkhwan Dec 28, 2025
cd2fe0a
Merge pull request #153 from FindYou-Kuit/feat/#150-check-guest
JangIkhwan Dec 28, 2025
2b1c6bf
[Feat] #152 실종신고글 레포지토리 - findByDate 추가
JJUYAAA Dec 28, 2025
5a87455
[Feat] #152 서비스 인터페이스 생성
JJUYAAA Dec 28, 2025
6374b55
[Feat] #152 MissingReportRetrieveWithS3ServiceImpl 생성 - missingDate 기…
JJUYAAA Dec 28, 2025
fddca32
[Feat] #152 MissingReportDetailStrategy 에 s3url 포함하여 반환하는 toDetailDto…
JJUYAAA Dec 28, 2025
6d9a3e8
[Feat] #152 reportController에 실종 신고글 랜덤조회 API 추가
JJUYAAA Dec 28, 2025
17d37e4
[Feat] #152 실종신고글 랜덤조회 API에 토큰 인증 비활성화
JJUYAAA Dec 28, 2025
ffc1eff
[Test] #152 실종신고글 랜덤조회 서비스 테스트코드 생성
JJUYAAA Dec 28, 2025
09981a1
[Test] #152 ReportControllerTest 테스트코드 추가
JJUYAAA Dec 28, 2025
a2f5459
[Refactor] #152 서비스 코드 수정 - s3 업로드 필요 없음
JJUYAAA Dec 28, 2025
3adcadd
[Test] #152 서비스 테스트 코드 - 이미지 업로드 제거 및 테스트 추가
JJUYAAA Dec 28, 2025
5cc75d9
[Test] #152 컨트롤러 테스트 코드 - 신고글 생성 시 이미지 그대로 반환하도록 수정
JJUYAAA Dec 28, 2025
69d0f9e
Merge pull request #154 from FindYou-Kuit/refactor/#151-protectingRep…
JJUYAAA Dec 28, 2025
32d2663
[Refactor] #156 글 조회 API 수정
ksg1227 Dec 29, 2025
c41f404
[Test] #156 글 조회 API 수정에 따른 테스트 코드 수정
ksg1227 Dec 29, 2025
50fe09c
Merge pull request #157 from FindYou-Kuit/refactor/#156-add-createdAt
ksg1227 Jan 1, 2026
208863a
[Feat!] #159 프로필 수정 API 삭제
JangIkhwan Jan 3, 2026
8c952d8
Merge pull request #155 from FindYou-Kuit/feat/#152-missingReport-wit…
JJUYAAA Jan 3, 2026
24630a0
[Test] #159 프로필 수정 API 관련 테스트 삭제
JangIkhwan Jan 4, 2026
bcc35d5
[Feat] #159 UserServiceFacade에서 changeProfileImage 메서드 삭제
JangIkhwan Jan 4, 2026
7915494
[Feat] #159 프로필 수정 서비스 삭제
JangIkhwan Jan 4, 2026
b429e26
[Test] #159 프로필 수정 서비스 테스트 삭제
JangIkhwan Jan 4, 2026
6275e00
[Feat!] #159 프로필 조회 API의 응답 수정
JangIkhwan Jan 4, 2026
fa0e3f4
[Feat] #159 getUserProfile 메서드에서 응답 생성문을 수정
JangIkhwan Jan 4, 2026
070b45f
[Test] #159 getUserProfile 수정에 따라 테스트 수정
JangIkhwan Jan 4, 2026
ee01822
[Test] #159 TestInitializer에서 불필요한 메서드를 삭제
JangIkhwan Jan 4, 2026
bd75f6d
[Feat] #159 User 엔티티에서 프로필 이미지 수정하는 changeProfileImage 메서드 삭제
JangIkhwan Jan 4, 2026
f8f332b
[Test] #159 UserRepositoryTest에서 불필요한 테스트 삭제
JangIkhwan Jan 4, 2026
3689b0e
[Feat!] #159 회원정보 등록 API 요청 수정
JangIkhwan Jan 4, 2026
a98befd
[Docs] #159 회원정보 등록 API 명세 수정
JangIkhwan Jan 4, 2026
663f4e2
[Feat!] #159 회원정보 등록 API에서 요청 바디를 multipart가 아니라 json 형태로 받도록 수정
JangIkhwan Jan 4, 2026
cc10edb
[Test] #159 회원정보 등록 API 테스트 수정
JangIkhwan Jan 4, 2026
c0f611a
[Feat] #159 회원정보 등록 서비스 로직에서 프로필 이미지 관련 내용 삭제
JangIkhwan Jan 4, 2026
0ad89bb
[Test] #159 UserServiceTest에서 회원정보 등록 관련 테스트 수정
JangIkhwan Jan 4, 2026
cefb682
[Feat] #148 토큰 발급 서비스 IssueTokenService 구현
JangIkhwan Jan 4, 2026
27d3c91
[refactor] #148 IssueTokenService를 사용해서 토큰을 발급하도록 LoginServiceImpl 수정
JangIkhwan Jan 4, 2026
43dabd9
[Test] #148 LoginServiceTest에서 테스트 수정
JangIkhwan Jan 4, 2026
c316e8f
[refactor] #148 IssueTokenService를 사용해 토큰을 발급하도록 RegisterUserServiceI…
JangIkhwan Jan 4, 2026
152d569
[Feat] #148 회원정보 등록 API에서 리프레시 토큰을 응답하도록 수정
JangIkhwan Jan 4, 2026
254069b
[Test] #148 회원등록 API 테스트에서 리프레시 토큰을 검증하도록 수정
JangIkhwan Jan 4, 2026
7b3f1ce
[Test] #148 RegisterUserService 테스트 수정
JangIkhwan Jan 4, 2026
2066921
[Refactor] #148 RegisterUserService의 대응되는 테스트 클래스의 이름과 디렉토리 위치를 수정
JangIkhwan Jan 4, 2026
e60548a
[Chore] #159 CI에서 로그를 보기 위해서 설정 추가
JangIkhwan Jan 4, 2026
fab1d9e
[Test] #159 UserControllerTest에 테스트용 Redis 설정 적용
JangIkhwan Jan 4, 2026
0fbf3b8
[Chore] #159 gradle test 시에 showLogs 프로퍼티가 있을 때만 애플레케이션 로그가 보이도록 설정
JangIkhwan Jan 4, 2026
2b5aae6
Merge pull request #160 from FindYou-Kuit/feat/#159-remove-profile-im…
JangIkhwan Jan 7, 2026
56949f9
[Docs] #162 README.md 파일 초안 작성
ksg1227 Jan 8, 2026
c03825d
[Docs] #162 사진 사이즈 조정
ksg1227 Jan 8, 2026
c9699ce
[Docs] #162 README.md 내용 보완
ksg1227 Jan 8, 2026
ffd88ec
[Docs] #162 README.md 불필요한 이모지 삭제
ksg1227 Jan 8, 2026
0d9ffc0
[Docs] #162 README.md 초안 최종 수정
ksg1227 Jan 8, 2026
9d478d1
Merge pull request #163 from FindYou-Kuit/docs/#162-write-readme
ksg1227 Jan 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# 찾아유 - 유기동물 관련 종합 애플리케이션

## 👋 Project Overview
**WHAT?**
유실동물을 찾고 보호하는 것을 돕는 통합 플랫폼입니다. 실종 신고, 목격 제보부터 보호 센터 정보, AI 품종 분석까지 반려동물을 잃어버린 슬픔을 덜고 빠른 구조를 돕습니다.

**HOW?**
공공데이터 포털의 전국 유기동물/보호소 데이터와 사용자의 실시간 제보(위치, 사진)를 매핑하여 지도 기반 서비스를 제공합니다. OpenAI 기반의 품종 자동 분석을 도입하여 검색 정확도를 높였습니다.

**WHY?**
가족 같은 반려동물을 잃어버렸을 때의 막막함을 해소하고, 골든타임을 놓치지 않도록 기술적으로 지원하며, 나아가 성숙한 반려동물 문화를 만들기 위해 시작되었습니다.

<br>

## 🧑‍🧑‍🧒 Team Member
<table>
<tbody>
<tr>
<td align="center"><a href="https://github.com/JangIkhwan">
<img width=140px src="https://avatars.githubusercontent.com/u/87964632?s=64&v=4" alt=""/><br />
<sub><b>[Server] 장익환</b></sub></a><br /></td>
<td align="center"><a href="https://github.com/ksg1227">
<img width=140px src="https://avatars.githubusercontent.com/u/66379250?v=4" alt=""/><br />
<sub><b>[Server] 김상균</b></sub></a><br /></td>
<td align="center"><a href="https://github.com/JJUYAAA">
<img width=140px src="https://avatars.githubusercontent.com/u/121420399?v=4" alt=""/><br />
<sub><b>[Server] 정주연</b></sub></a><br /></td>
</tr>
</tbody>
</table>

<br>

## ⚒️ Tech Stack
<img src="assets/tech_stack.png" width="700">

### Backend
| Tech | Version / Description |
| --- | --- |
| **Java** | JDK 17 |
| **Spring Boot** | 3.5.0 |
| **Spring Data JPA** | ORM / Hibernate |
| **Spring Security** | Authentication & Authorization |
| **Spring AI** | OpenAI (GPT-4o) Integration |
| **Gradle** | Build Tool |

### Database & Storage
| Tech | Description |
| --- | --- |
| **MySQL** | Main RDBMS (v8.0) |
| **Redis** | Cache & Session Store |
| **Flyway** | DB Migration Tool |
| **AWS S3** | Image Storage |

### Infra & DevOps
| Tech | Description |
| --- | --- |
| **Docker** | Containerization |
| **AWS EC2** | (Expected Deployment Target) |
| **GitHub Actions** | CI/CD (Workflows configured) |

### Tools
- **Swagger (OpenAPI)**: API Documentation
- **Actuator & Prometheus/Loki/Grafana/Alloy**: Monitoring

<br>

## 🏗️ Architecture
<img src="assets/system_architecture.png" width="700">

<br>

## 📍 ERD
<img src="assets/erd.png" width="700">

<br>

## 📜 Convention

### Code Convention
| 항목 | 규칙 | 예시 |
| --- | --- | --- |
| **Class** | PascalCase | `UserProfile` |
| **Function** | camelCase | `getUserInfo` |
| **Variable** | camelCase | `userId` |
| **DB Table** | snake_case | `user_profile` |
| **Enum / Constant** | UPPER_SNAKE_CASE | `MAX_RETRY` |

### Git Convention

#### Commit Message
`[Prefix] #IssueNumber Description`
예시: `[Feat] #123 로그인 API 구현`

| Prefix | Description |
| --- | --- |
| `Feat` | 새로운 기능 추가 |
| `Fix` | 버그 수정 |
| `Refactor` | 코드 리팩토링 |
| `Chore` | 빌드 업무 수정, 패키지 매니저 수정 |
| `Docs` | 문서 수정 |
| `Infra` | 인프라 설정 |
| `Test` | 테스트 코드 |

#### Branch Strategy
`prefix/#issue-description`
예시: `feat/#123-login-api`, `fix/#45-bug-fix`

<br>

## 🗂️ Project Structure
```
com.kuit.findyou
├── 📂 domain // 도메인별 비즈니스 로직 (Feature Packaging)
│ ├── 📂 auth // 인증 (Login, Token)
│ ├── 📂 breed // 품종 정보
│ ├── 📂 city // 시/도, 시/군/구 지역 정보
│ ├── 📂 home // 홈 화면 (통계, 추천)
│ ├── 📂 image // 이미지 업로드/처리
│ ├── 📂 information // 동물보호센터, 봉사활동 정보
│ ├── 📂 inquiry // 문의하기
│ ├── 📂 notification // 알림
│ ├── 📂 report // 실종/목격 신고
│ └── 📂 user // 사용자 관리 (MyPage)
└── 📂 global // 전역 공유 모듈
├── 📂 common // 공통 Response, Exception
├── 📂 config // 설정 (Security, Swagger, S3, Redis...)
├── 📂 external // 외부 API 클라이언트 (Kakao, Public Data...)
├── 📂 infrastructure // 인프라 구현체 (ImageUploader...)
├── 📂 jwt // JWT 관련 유틸리티 및 필터
└── 📂 logging // 로깅 설정
```
Binary file added assets/erd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/system_architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/tech_stack.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ java {
}
}

test {
testLogging {
showStandardStreams = project.hasProperty("showLogs")
}
}

configurations {
compileOnly {
extendsFrom annotationProcessor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.kuit.findyou.domain.auth.controller;

import com.kuit.findyou.domain.auth.dto.ReissueTokenRequest;
import com.kuit.findyou.domain.auth.dto.ReissueTokenResponse;
import com.kuit.findyou.domain.auth.dto.request.GuestLoginRequest;
import com.kuit.findyou.domain.auth.dto.response.GuestLoginResponse;
import com.kuit.findyou.domain.auth.dto.request.KakaoLoginRequest;
import com.kuit.findyou.domain.auth.dto.response.KakaoLoginResponse;
import com.kuit.findyou.domain.auth.service.AuthService;
import com.kuit.findyou.domain.auth.service.AuthServiceFacade;
import com.kuit.findyou.global.common.annotation.CustomExceptionDescription;
import com.kuit.findyou.global.common.response.BaseResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -16,36 +18,44 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static com.kuit.findyou.global.common.swagger.SwaggerResponseDescription.GUEST_LOGIN;
import static com.kuit.findyou.global.common.swagger.SwaggerResponseDescription.KAKAO_LOGIN;
import static com.kuit.findyou.global.common.swagger.SwaggerResponseDescription.*;

@Tag(name = "Login", description = "로그인 관련 API")
@Slf4j
@RequiredArgsConstructor
@RequestMapping("api/v2/auth")
@RestController
public class AuthController {
private final AuthService authService;
private final AuthServiceFacade authServiceFacade;

@Operation(
summary = "카카오 로그인 API",
description = "카카오 사용자 식별자를 이용해서 유저 정보와 엑세스 토큰을 얻을 수 있습니다. 가입된 회원인지 여부를 반환합니다."
)
@PostMapping("/login/kakao")
@CustomExceptionDescription(KAKAO_LOGIN)
@PostMapping("/login/kakao")
public BaseResponse<KakaoLoginResponse> kakaoLogin(@RequestBody KakaoLoginRequest request){
log.info("[kakaoLogin]");
return BaseResponse.ok(authService.kakaoLogin(request));
return BaseResponse.ok(authServiceFacade.kakaoLogin(request));
}

@Operation(
summary = "게스트 로그인 API",
description = "디바이스id 식별자를 이용해서 유저 정보와 엑세스 토큰을 얻을 수 있습니다. 기존 게스트가 아니면 별도의 가입 API 호출 없이 정보가 자동으로 저장됩니다."
)
@PostMapping("/login/guest")
@CustomExceptionDescription(GUEST_LOGIN)
@PostMapping("/login/guest")
public BaseResponse<GuestLoginResponse> guestLogin(@RequestBody GuestLoginRequest request){
log.info("[guestLogin] deviceId = {}", request.deviceId());
return BaseResponse.ok(authService.guestLogin(request));
return BaseResponse.ok(authServiceFacade.guestLogin(request));
}

@Operation(
summary = "토큰 재발급 API",
description = "만료되지 않은 리프레시 토큰으로 요청하면 새로운 엑세스 토큰과 리프레시 토큰을 얻을 수 있습니다."
)
@CustomExceptionDescription(REISSUE_TOKEN)
@PostMapping("/reissue/token")
public BaseResponse<ReissueTokenResponse> reissueToken(@RequestBody ReissueTokenRequest request){
return BaseResponse.ok(authServiceFacade.reissueToken(request));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.kuit.findyou.domain.auth.dto;

public record ReissueTokenRequest(
String refreshToken
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.kuit.findyou.domain.auth.dto;

public record ReissueTokenResponse(
String accessToken,
String refreshToken
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public record GuestLoginResponse (
@Schema(description = "유저 식별자")
Long userId,
@Schema(description = "엑세스 토큰")
String accessToken
String accessToken,
@Schema(description = "리프레시 토큰")
String refreshToken
){
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ public record KakaoLoginResponse(
@Schema(description = "첫 로그인 여부 = 회원가입 여부", example = "false")
Boolean isFirstLogin
) {
public static KakaoLoginResponse fromUserAndAccessToken(User user, String accessToken) {
UserInfoDto userInfo = new UserInfoDto(user.getId(), user.getName(), accessToken);
public static KakaoLoginResponse fromUserAndTokens(User user, String accessToken, String refreshToken) {
UserInfoDto userInfo = new UserInfoDto(user.getId(), user.getName(), accessToken, refreshToken);
return new KakaoLoginResponse(userInfo, false);
}

public static KakaoLoginResponse notFound() {
public static KakaoLoginResponse firstLogin() {
return new KakaoLoginResponse(null, true);
}

Expand All @@ -25,7 +25,9 @@ public record UserInfoDto(
@Schema(description = "사용자 닉네임", example = "유저1")
String nickname,
@Schema(description = "찾아유 엑세스 토큰", example = "token1234token1234token1234")
String accessToken
String accessToken,
@Schema(description = "찾아유 리프레시 토큰", example = "token1234token1234token1234")
String refreshToken
) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.kuit.findyou.domain.auth.repository;

import java.util.Optional;

public interface RedisRefreshTokenRepository {
Optional<String> findByUserId(Long userId);

void save(Long id, String refreshToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.kuit.findyou.domain.auth.repository;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import java.time.Duration;
import java.util.Optional;

@RequiredArgsConstructor
@Repository
public class RedisRefreshTokenRepositoryImpl implements RedisRefreshTokenRepository {
private final RedisTemplate<String, String> redisTemplate;
private final String refreshTokenKeyPrefix = "refresh-token:";
@Value("${findyou.jwt.expiration-ms.refresh-token}")
private Long refreshTokenExpireMs;

private String key(Long userId) {
return refreshTokenKeyPrefix + userId;
}

@Override
public Optional<String> findByUserId(Long userId) {
String value = redisTemplate.opsForValue().get(key(userId));
return Optional.ofNullable(value);
}

@Override
public void save(Long userId, String refreshToken) {
redisTemplate.opsForValue().set(key(userId), refreshToken, Duration.ofMillis(refreshTokenExpireMs));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.kuit.findyou.domain.auth.service;

import com.kuit.findyou.domain.auth.dto.ReissueTokenRequest;
import com.kuit.findyou.domain.auth.dto.ReissueTokenResponse;
import com.kuit.findyou.domain.auth.dto.request.GuestLoginRequest;
import com.kuit.findyou.domain.auth.dto.request.KakaoLoginRequest;
import com.kuit.findyou.domain.auth.dto.response.GuestLoginResponse;
import com.kuit.findyou.domain.auth.dto.response.KakaoLoginResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class AuthServiceFacade {
private final LoginService loginService;
private final ReissueTokenService reissueTokenService;

public KakaoLoginResponse kakaoLogin(KakaoLoginRequest request) {
return loginService.kakaoLogin(request);
}

public GuestLoginResponse guestLogin(GuestLoginRequest request) {
return loginService.guestLogin(request);
}

public ReissueTokenResponse reissueToken(ReissueTokenRequest request) {
return reissueTokenService.reissueToken(request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.kuit.findyou.domain.auth.service;

import com.kuit.findyou.domain.user.model.Role;

public interface IssueTokenService {
String issueAccessToken(Long userId, Role role);
String issueRefreshToken(Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.kuit.findyou.domain.auth.service;

import com.kuit.findyou.domain.auth.repository.RedisRefreshTokenRepository;
import com.kuit.findyou.domain.user.model.Role;
import com.kuit.findyou.global.jwt.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class IssueTokenServiceImpl implements IssueTokenService {
private final JwtUtil jwtUtil;
private final RedisRefreshTokenRepository redisRefreshTokenRepository;

@Override
public String issueAccessToken(Long userId, Role role) {
return jwtUtil.createAccessJwt(userId, role);
}

@Override
public String issueRefreshToken(Long userId) {
String refreshToken = jwtUtil.createRefreshJwt(userId);
redisRefreshTokenRepository.save(userId, refreshToken);
return refreshToken;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.kuit.findyou.domain.auth.dto.request.KakaoLoginRequest;
import com.kuit.findyou.domain.auth.dto.response.KakaoLoginResponse;

public interface AuthService {
public interface LoginService {
KakaoLoginResponse kakaoLogin(KakaoLoginRequest request);

GuestLoginResponse guestLogin(GuestLoginRequest request);
Expand Down
Loading