Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
74 changes: 74 additions & 0 deletions .github/workflows/prod-openapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Prod-OpenAPI to CodiveAPI

on:
push:
branches: [ "main" ]
workflow_dispatch: {}

permissions:
contents: read

concurrency:
group: sync-openapi
cancel-in-progress: true

jobs:
sync:
runs-on: ubuntu-latest

env:
CODIVEAPI_BRANCH: main
TARGET_PATH: Sources/CodiveAPI/openapi.yaml

steps:
- name: Checkout backend repo (for context only)
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Fetch OpenAPI JSON from production
env:
PROD_OPENAPI_URL: ${{ secrets.PROD_OPENAPI_URL }}
run: |
set -euo pipefail
echo "Fetching OpenAPI from: $PROD_OPENAPI_URL"
curl -fsSL --retry 5 --retry-delay 2 --connect-timeout 10 --max-time 30 \
"$PROD_OPENAPI_URL" -o openapi.json
test -s openapi.json
head -c 1 openapi.json | grep -q '{'

- name: Convert OpenAPI JSON -> YAML (swagger-cli)
run: |
set -euo pipefail
npm i -g @apidevtools/swagger-cli
swagger-cli bundle openapi.json --type yaml --outfile openapi.yaml

- name: Checkout CodiveAPI repo
uses: actions/checkout@v4
with:
repository: Clokey-dev/CodiveAPI
ref: ${{ env.CODIVEAPI_BRANCH }}
token: ${{ secrets.CODIVEAPI_PAT }}
path: codiveapi
fetch-depth: 1

- name: Copy openapi.yaml into CodiveAPI
run: |
set -euo pipefail
cp openapi.yaml "codiveapi/${TARGET_PATH}"

- name: Commit & push if changed
working-directory: codiveapi
run: |
set -euo pipefail
git config user.name "clokey-bot"
git config user.email "[email protected]"

if git diff --quiet; then
echo "No changes detected. Skipping commit."
exit 0
fi

git add "${TARGET_PATH}"
git commit -m "chore: update openapi.yaml from production"
git push origin "${CODIVEAPI_BRANCH}"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ out/

### Custom ###
.env
firebase-sa.**
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,26 @@
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@Tag(name = "1-1. 인증 API", description = "인증 관련 API입니다.")
@Tag(name = "01. 인증 API", description = "인증 관련 API입니다.")
public class AuthController {

private final AuthService authService;

@GetMapping("/my-status")
@Operation(summary = "회원 상태 확인", description = "가입 완료 or 약관 동의 여부 확인 가능.")
@Operation(
operationId = "Auth_getUserStatus",
summary = "회원 상태 확인",
description = "가입 완료 or 약관 동의 여부 확인 가능.")
public BaseResponse<UserStatusResponse> getUserStatus() {
UserStatusResponse response = authService.getUserStatus();
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
}

@PatchMapping("/device-token")
@Operation(summary = "Device Token 갱신", description = "디바이스 토큰을 갱신합니다.")
@Operation(
operationId = "Auth_renewDeviceToken",
summary = "Device Token 갱신",
description = "디바이스 토큰을 갱신합니다.")
public BaseResponse<Void> renewDeviceToken(
@Valid @RequestBody DeviceTokenRenewRequest request) {
authService.renewDeviceToken(request);
Expand All @@ -40,6 +46,7 @@ public BaseResponse<Void> renewDeviceToken(

@PostMapping("/reissue-token")
@Operation(
operationId = "Auth_reissueTokens",
summary = "토큰 재발급",
description = "리프레시 토큰을 바탕으로 Access Token과 Refresh Token을 재발급합니다.")
public BaseResponse<TokenResponse> reissueTokens(
Expand All @@ -49,7 +56,10 @@ public BaseResponse<TokenResponse> reissueTokens(
}

@PostMapping("/logout")
@Operation(summary = "로그 아웃", description = "Redis에 저장된 사용자의 리프레시 토큰을 삭제합니다.")
@Operation(
operationId = "Auth_logoutUser",
summary = "로그 아웃",
description = "Redis에 저장된 사용자의 리프레시 토큰을 삭제합니다.")
public BaseResponse<Void> logoutUser() {
authService.logoutUser();
return BaseResponse.onSuccess(GlobalBaseSuccessCode.NO_CONTENT, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@
@RestController
@RequestMapping("/categories")
@RequiredArgsConstructor
@Tag(name = "2. 카테고리 API", description = "카테고리 관련 API입니다.")
@Tag(name = "02. 카테고리 API", description = "카테고리 관련 API입니다.")
@Validated
public class CategoryController {

private final CategoryService categoryService;

@GetMapping
@Operation(summary = "카테고리 목록 조회", description = "카테고리 목록을 조회합니다.")
@Operation(
operationId = "Category_getAllCategories",
summary = "카테고리 목록 조회",
description = "카테고리 목록을 조회합니다.")
public BaseResponse<List<GetCategoryListResponse>> getAllCategories() {
List<GetCategoryListResponse> categories = categoryService.getCategoryList();
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, categories);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@
@RestController
@RequestMapping("/clothes")
@RequiredArgsConstructor
@Tag(name = "3. 옷 API", description = "옷 관련 API입니다.")
@Tag(name = "03. 옷 API", description = "옷 관련 API입니다.")
@Validated
public class ClothController {

private final ClothService clothService;

@PostMapping("/images")
@Operation(
operationId = "Cloth_getClothUploadPresignedUrl",
summary = "옷 이미지 업로드용 presignedUrl 발급",
description = "옷 이미지 업로드용 presignedUrl을 발급합니다.")
public BaseResponse<ClothImagesPresignedUrlResponse> getClothUploadPresignedUrl(
Expand All @@ -41,15 +42,18 @@ public BaseResponse<ClothImagesPresignedUrlResponse> getClothUploadPresignedUrl(
}

@PostMapping
@Operation(summary = "옷 생성", description = "새로운 옷을 생성합니다.")
@Operation(operationId = "Cloth_createClothes", summary = "옷 생성", description = "새로운 옷을 생성합니다.")
public BaseResponse<ClothCreateResponse> createClothes(
@Valid @RequestBody ClothCreateRequests request) {
ClothCreateResponse response = clothService.createClothes(request);
return BaseResponse.onSuccess(GlobalBaseSuccessCode.CREATED, response);
}

@GetMapping("/recommend")
@Operation(summary = "카테고리별 계절에 맞는 옷 조회", description = "카테고리별로 계절에 맞는 옷을 조회하는 API입니다.")
@Operation(
operationId = "Cloth_recommendCategoryClothes",
summary = "카테고리별 계절에 맞는 옷 조회",
description = "카테고리별로 계절에 맞는 옷을 조회하는 API입니다.")
public BaseResponse<SliceResponse<ClothRecommendListResponse>> recommendCategoryClothes(
@Parameter(description = "이전 페이지의 옷ID (첫 요청 시 생략)") @RequestParam(required = false)
Long lastClothId,
Expand All @@ -62,7 +66,10 @@ public BaseResponse<SliceResponse<ClothRecommendListResponse>> recommendCategory
}

@GetMapping
@Operation(summary = "옷 목록 조회", description = "옷장에서 옷 목록을 조회하는 API입니다.")
@Operation(
operationId = "Cloth_getClothes",
summary = "옷 목록 조회",
description = "옷장에서 옷 목록을 조회하는 API입니다.")
public BaseResponse<SliceResponse<ClothListResponse>> getClothes(
@Parameter(description = "이전 페이지의 옷 ID(첫 요청 시 생략)") @RequestParam(required = false)
Long lastClothId,
Expand All @@ -80,22 +87,25 @@ public BaseResponse<SliceResponse<ClothListResponse>> getClothes(
}

@GetMapping("/{clothId}")
@Operation(summary = "옷 상세 조회", description = "옷을 상세 조회하는 API입니다.")
@Operation(
operationId = "Cloth_getClothDetails",
summary = "옷 상세 조회",
description = "옷을 상세 조회하는 API입니다.")
public BaseResponse<ClothDetailsResponse> getClothDetails(@PathVariable Long clothId) {
ClothDetailsResponse response = clothService.getClothDetails(clothId);
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
}

@PatchMapping("/{clothId}")
@Operation(summary = "옷 수정", description = "옷을 수정하는 API입니다.")
@Operation(operationId = "Cloth_updateCloth", summary = "옷 수정", description = "옷을 수정하는 API입니다.")
public BaseResponse<Void> updateCloth(
@PathVariable Long clothId, @RequestBody @Valid ClothUpdateRequest request) {
clothService.updateCloth(clothId, request);
return BaseResponse.onSuccess(GlobalBaseSuccessCode.NO_CONTENT, null);
}

@DeleteMapping("/{clothId}")
@Operation(summary = "옷 삭제", description = "옷을 삭제합니다.")
@Operation(operationId = "Cloth_deleteCloth", summary = "옷 삭제", description = "옷을 삭제합니다.")
public BaseResponse<Void> deleteCloth(@PathVariable Long clothId) {
clothService.deleteCloth(clothId);
return BaseResponse.onSuccess(GlobalBaseSuccessCode.NO_CONTENT, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,33 @@
@RestController
@RequestMapping("/comments")
@RequiredArgsConstructor
@Tag(name = "4. 댓글 API", description = "댓글 관련 API입니다.")
@Tag(name = "04. 댓글 API", description = "댓글 관련 API입니다.")
@Validated
public class CommentController {

private final CommentService commentService;

@PostMapping
@Operation(summary = "댓글 작성", description = "새로운 댓글을 작성합니다.")
@Operation(
operationId = "Comment_createComment",
summary = "댓글 작성",
description = "새로운 댓글을 작성합니다.")
public BaseResponse<CommentCreateResponse> createComment(
@Valid @RequestBody CommentCreateRequest request) {
CommentCreateResponse response = commentService.createComment(request);
return BaseResponse.onSuccess(GlobalBaseSuccessCode.CREATED, response);
}

@PostMapping("/{commentId}/replies")
@Operation(summary = "대댓글 작성", description = "대댓글을 작성합니다.")
@Operation(operationId = "Comment_createReply", summary = "대댓글 작성", description = "대댓글을 작성합니다.")
public BaseResponse<CommentCreateResponse> createReply(
@PathVariable Long commentId, @Valid @RequestBody CommentCreateRequest request) {
CommentCreateResponse response = commentService.createReply(commentId, request);
return BaseResponse.onSuccess(GlobalBaseSuccessCode.CREATED, response);
}

@GetMapping
@Operation(summary = "댓글 조회", description = "댓글을 조회합니다")
@Operation(operationId = "Comment_getComments", summary = "댓글 조회", description = "댓글을 조회합니다")
public BaseResponse<SliceResponse<CommentListResponse>> getComments(
@Parameter(description = "조회중인 기록의 ID") @RequestParam Long historyId,
@Parameter(description = "이전 페이지의 마지막 댓글 ID (첫 요청 시 생략)")
Expand All @@ -61,7 +64,7 @@ public BaseResponse<SliceResponse<CommentListResponse>> getComments(
}

@GetMapping("/{commentId}/replies")
@Operation(summary = "대댓글 조회", description = "대댓글을 조회합니다")
@Operation(operationId = "Comment_getReplies", summary = "대댓글 조회", description = "대댓글을 조회합니다")
public BaseResponse<SliceResponse<ReplyListResponse>> getReplies(
@PathVariable Long commentId,
@Parameter(description = "이전 페이지의 마지막 대댓글 ID (첫 요청 시 생략)")
Expand All @@ -77,14 +80,20 @@ public BaseResponse<SliceResponse<ReplyListResponse>> getReplies(
}

@DeleteMapping("/{commentId}")
@Operation(summary = "댓글 삭제 API", description = "댓글을 삭제합니다.")
@Operation(
operationId = "Comment_deleteComment",
summary = "댓글 삭제 API",
description = "댓글을 삭제합니다.")
public BaseResponse<Void> deleteComment(@PathVariable Long commentId) {
commentService.deleteComment(commentId);
return BaseResponse.onSuccess(GlobalBaseSuccessCode.NO_CONTENT, null);
}

@GetMapping("/my-comments")
@Operation(summary = "내가 작성한 댓글 조회 API", description = "내가 작성한 댓글을 조회합니다.")
@Operation(
operationId = "Comment_getMyComments",
summary = "내가 작성한 댓글 조회 API",
description = "내가 작성한 댓글을 조회합니다.")
public BaseResponse<SliceResponse<MyCommentListResponse>> getMyComments(
@Parameter(description = "이전 페이지의 마지막 기록 ID (첫 요청 시 생략)")
@RequestParam(required = false)
Expand Down
Loading