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