diff --git "a/.github/ISSUE_TEMPLATE/\342\231\273\357\270\217-refactor.md" "b/.github/ISSUE_TEMPLATE/\342\231\273\357\270\217-refactor.md" index cbbafba..093496e 100644 --- "a/.github/ISSUE_TEMPLATE/\342\231\273\357\270\217-refactor.md" +++ "b/.github/ISSUE_TEMPLATE/\342\231\273\357\270\217-refactor.md" @@ -2,7 +2,7 @@ name: "♻️ Refactor" about: 리팩토링 이슈 템플릿 title: "♻️Refactor: " -labels: '' +labels: ":recycle: Refactor" assignees: '' --- diff --git "a/.github/ISSUE_TEMPLATE/\342\234\250-feature.md" "b/.github/ISSUE_TEMPLATE/\342\234\250-feature.md" index 07d5fd2..aa13c26 100644 --- "a/.github/ISSUE_TEMPLATE/\342\234\250-feature.md" +++ "b/.github/ISSUE_TEMPLATE/\342\234\250-feature.md" @@ -2,7 +2,7 @@ name: "✨ Feature" about: 기능 추가 이슈 템플릿 title: "✨Feat: " -labels: enhancement +labels: "✨ Feature" assignees: '' --- diff --git "a/.github/ISSUE_TEMPLATE/\360\237\220\233-fix.md" "b/.github/ISSUE_TEMPLATE/\360\237\220\233-fix.md" index d0b3059..b9141c3 100644 --- "a/.github/ISSUE_TEMPLATE/\360\237\220\233-fix.md" +++ "b/.github/ISSUE_TEMPLATE/\360\237\220\233-fix.md" @@ -2,7 +2,7 @@ name: "\U0001F41B Fix" about: 버그 및 에러 이슈 템플릿 title: "\U0001F41BFix: " -labels: bug +labels: "\U0001F41E BugFix" assignees: '' --- diff --git "a/.github/ISSUE_TEMPLATE/\360\237\223\235-documentation.md" "b/.github/ISSUE_TEMPLATE/\360\237\223\235-documentation.md" index 314db28..07edba1 100644 --- "a/.github/ISSUE_TEMPLATE/\360\237\223\235-documentation.md" +++ "b/.github/ISSUE_TEMPLATE/\360\237\223\235-documentation.md" @@ -2,7 +2,7 @@ name: "\U0001F4DD Documentation" about: 문서 수정 이슈 템플릿 title: "\U0001F4DDDocs: " -labels: documentation +labels: "\U0001F4C3 Docs" assignees: '' --- diff --git a/src/main/java/com/likelion/trendithon/domain/card/controller/CardController.java b/src/main/java/com/likelion/trendithon/domain/card/controller/CardController.java new file mode 100644 index 0000000..57c9410 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/controller/CardController.java @@ -0,0 +1,57 @@ +package com.likelion.trendithon.domain.card.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.likelion.trendithon.domain.card.dto.request.CardRequest; +import com.likelion.trendithon.domain.card.service.CardService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; + +@RestController +@AllArgsConstructor +@RequestMapping("/api/cards") +@Tag(name = "Card", description = "Card 관리 API") +public class CardController { + + private CardService cardService; + + @Operation(summary = "[ 토큰 O | 카드 등록 ]", description = "새로운 카드 등록") + @PostMapping("/create") + public ResponseEntity createCard(@RequestBody CardRequest card) { + return cardService.createCard(card); + } + + @Operation(summary = "[ 토큰 O | 카드 조회 ]", description = "ID를 통해 특정 카드 조회") + @GetMapping("/{id}") + public ResponseEntity getCardById(@PathVariable Long id) { + return cardService.getCardById(id); + } + + @Operation(summary = "[ 토큰 O | 카드 목록 조회 ]", description = "사용자 ID를 통해 특정 카드 조회") + @GetMapping("/all/{userId}") + public ResponseEntity getAllCards(@PathVariable String userId) { + return cardService.getAllCards(userId); + } + + @Operation(summary = "[ 토큰 O | 카드 삭제 ]", description = "ID를 통해 특정 카드 삭제") + @DeleteMapping("/{id}") + public ResponseEntity deleteCard(@PathVariable Long id) { + return cardService.deleteCard(id); + } + + @Operation(summary = "[ 토큰 O | 카드 수정 ]", description = "ID를 통해 특정 카드 수정") + @PutMapping("/update/{id}") + public ResponseEntity updateCard(@PathVariable Long id, @RequestBody CardRequest updatedCard) { + return cardService.updateCard(id, updatedCard); + } +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/request/CardRequest.java b/src/main/java/com/likelion/trendithon/domain/card/dto/request/CardRequest.java new file mode 100644 index 0000000..2322867 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/request/CardRequest.java @@ -0,0 +1,24 @@ +package com.likelion.trendithon.domain.card.dto.request; + +import java.util.List; + +import com.likelion.trendithon.domain.tag.dto.TagDto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +public class CardRequest { + + @Schema(description = "카드 제목", example = "멋쟁이사자 되기") + private String title; + + @Schema(description = "카드 내용", example = "나는 오늘 멋쟁이 사자가 되다.") + private String content; + + @Schema(description = "이모지 Url") + private String imgUrl; + + @Schema(description = "태그 목록", example = "[{\"tagTitle\": \"팁\", \"tagContent\": \"열심히 하기\"}]") + private List tagItems; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardDto.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardDto.java new file mode 100644 index 0000000..d73b05d --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardDto.java @@ -0,0 +1,29 @@ +package com.likelion.trendithon.domain.card.dto.response; + +import java.util.List; + +import com.likelion.trendithon.domain.tag.dto.TagDto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class CardDto { + + @Schema(description = "카드 제목", example = "멋쟁이사자 되기") + private String title; + + @Schema(description = "카드 내용", example = "나는 오늘 멋쟁이 사자가 되다.") + private String content; + + @Schema(description = "이모지 Url") + private String imgUrl; + + @Schema(description = "사용자 Id", example = "likelion") + private String userId; + + @Schema(description = "태그 목록", example = "[{\"tagTitle\": \"팁\", \"tagContent\": \"열심히 하기\"}]") + private List tagItems; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListResponse.java new file mode 100644 index 0000000..fb12184 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListResponse.java @@ -0,0 +1,21 @@ +package com.likelion.trendithon.domain.card.dto.response; + +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class CardListResponse { + + @Schema(description = "카드 생성 결과", example = "true") + private boolean success; + + @Schema(description = "응답 메세지", example = "성공적으로 카드가 생성되었습니다.") + private String message; + + @Schema(description = "보유한 카드 리스트") + private List cardList; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListSummaryDto.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListSummaryDto.java new file mode 100644 index 0000000..17b53e2 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListSummaryDto.java @@ -0,0 +1,22 @@ +package com.likelion.trendithon.domain.card.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@Builder +@NoArgsConstructor +public class CardListSummaryDto { + + @Schema(description = "카드 Id", example = "1234") + private Long cardId; + + @Schema(description = "카드 제목", example = "멋쟁이사자 되기") + private String title; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardResponse.java new file mode 100644 index 0000000..883cbe8 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardResponse.java @@ -0,0 +1,16 @@ +package com.likelion.trendithon.domain.card.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class CardResponse { + + @Schema(description = "카드 생성 결과", example = "true") + private boolean success; + + @Schema(description = "응답 메세지", example = "카드가 생성 성공하였습니다.") + private String message; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardSearchResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardSearchResponse.java new file mode 100644 index 0000000..4afecb3 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardSearchResponse.java @@ -0,0 +1,19 @@ +package com.likelion.trendithon.domain.card.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class CardSearchResponse { + + @Schema(description = "카드 조회 결과", example = "true") + private boolean success; + + @Schema(description = "응답 메세지", example = "카드가 조회 성공하였습니다.") + private String message; + + @Schema(description = "카드") + private CardDto card; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/entity/Card.java b/src/main/java/com/likelion/trendithon/domain/card/entity/Card.java new file mode 100644 index 0000000..7f8258d --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/entity/Card.java @@ -0,0 +1,47 @@ +package com.likelion.trendithon.domain.card.entity; + +import java.util.*; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; + +import com.likelion.trendithon.domain.tag.entity.Tag; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Card { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long cardId; + + @Column(name = "title", nullable = false) + private String title; + + @Column(name = "content", nullable = false) + private String content; + + @Column(name = "imgUrl") + private String imgUrl; + + @Column(name = "user_id") + private String userId; + + @OneToMany(mappedBy = "card", cascade = CascadeType.ALL, orphanRemoval = true) + private List TagItems = new ArrayList<>(); +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/repository/CardRepository.java b/src/main/java/com/likelion/trendithon/domain/card/repository/CardRepository.java new file mode 100644 index 0000000..28ac040 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/repository/CardRepository.java @@ -0,0 +1,11 @@ +package com.likelion.trendithon.domain.card.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.likelion.trendithon.domain.card.entity.Card; + +public interface CardRepository extends JpaRepository { + List findByUserId(String id); +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/service/CardService.java b/src/main/java/com/likelion/trendithon/domain/card/service/CardService.java new file mode 100644 index 0000000..c099e02 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/service/CardService.java @@ -0,0 +1,209 @@ +package com.likelion.trendithon.domain.card.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.likelion.trendithon.domain.card.dto.request.CardRequest; +import com.likelion.trendithon.domain.card.dto.response.CardDto; +import com.likelion.trendithon.domain.card.dto.response.CardListResponse; +import com.likelion.trendithon.domain.card.dto.response.CardListSummaryDto; +import com.likelion.trendithon.domain.card.dto.response.CardResponse; +import com.likelion.trendithon.domain.card.dto.response.CardSearchResponse; +import com.likelion.trendithon.domain.card.entity.Card; +import com.likelion.trendithon.domain.card.repository.CardRepository; +import com.likelion.trendithon.domain.tag.Service.TagService; +import com.likelion.trendithon.domain.tag.dto.TagDto; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@AllArgsConstructor +@Slf4j +public class CardService { + + private CardRepository cardRepository; + private TagService tagService; + + // 카드 생성 - tag도 저장함 + @Transactional + public ResponseEntity createCard(CardRequest card) { + try { + List tags = card.getTagItems(); + Card newCard = + Card.builder() + .title(card.getTitle()) + .content(card.getContent()) + .imgUrl(card.getImgUrl()) + .build(); + cardRepository.save(newCard); + tagService.saveTag(tags, newCard); + + return ResponseEntity.ok( + CardResponse.builder().success(true).message("카드가 생성 성공하였습니다.").build()); + } catch (Exception e) { + return ResponseEntity.ok( + CardResponse.builder().success(false).message("카드 생성 실패하였습니다.").build()); + } + } + + // 카드 한장 조회 + @Transactional + public ResponseEntity getCardById(Long id) { + + try { + Optional optionalCard = cardRepository.findById(id); + Card card; + + if (optionalCard.isPresent()) { + card = optionalCard.get(); + + List tags = + card.getTagItems().stream() + .map( + tag -> + TagDto.builder() + .tagTitle(tag.getTagTitle()) + .tagContent(tag.getTagContent()) + .build()) + .toList(); + + return ResponseEntity.ok( + CardSearchResponse.builder() + .success(true) + .message("카드 조회 성공하였습니다.") + .card( + CardDto.builder() + .title(card.getTitle()) + .content(card.getContent()) + .imgUrl(card.getImgUrl()) + .tagItems(tags) + .build()) + .build()); + } else + return ResponseEntity.ok( + CardSearchResponse.builder().success(false).message("카드가 존재하지 않습니다.").build()); + + } catch (Exception e) { + return ResponseEntity.ok( + CardSearchResponse.builder().success(false).message("카드 조회 중 오류가 발생하였습니다.").build()); + } + } + + // 사용자 아이디로 모든 카드 목록 조회 + @Transactional + public ResponseEntity getAllCards(String userId) { + try { + + List cardList = cardRepository.findByUserId(userId); + List cardDtos = new ArrayList<>(); + + for (Card card : cardList) { + + // 제목이랑 카드 아이디만 추출 + cardDtos.add( + CardListSummaryDto.builder().cardId(card.getCardId()).title(card.getTitle()).build()); + } + + // 카드가 존재하는지 안하는지 검사 + if (!cardDtos.isEmpty()) + return ResponseEntity.ok( + CardListResponse.builder() + .success(true) + .message("전체 카드가 조회 되었습니다.") + .cardList(cardDtos) + .build()); + else + return ResponseEntity.ok( + CardListResponse.builder() + .success(false) + .message("카드가 존재하지 않습니다.") + .cardList(cardDtos) + .build()); + + } catch (Exception e) { + return ResponseEntity.ok( + CardListResponse.builder() + .success(false) + .message("사용자의 카드 목록을 조회 중 에러가 발생했습니다.") + .build()); + } + } + + // 카드 삭제 + @Transactional + public ResponseEntity deleteCard(Long id) { + + try { + Optional optionalCard = cardRepository.findById(id); + if (optionalCard.isPresent()) { + + Card card = optionalCard.get(); + cardRepository.delete(card); + return ResponseEntity.ok( + CardResponse.builder().success(true).message("카드 삭제 성공하였습니다.").build()); + + } else + return ResponseEntity.ok( + CardResponse.builder().success(false).message("해당 카드가 존재하지 않습니다.").build()); + + } catch (Exception e) { + return ResponseEntity.ok( + CardResponse.builder().success(false).message("카드를 삭제 중 에러가 발생했습니다.").build()); + } + } + + // 카드 수정- 수정 시 기존 태그 리스트와 비교하여 태그 삭제 수정 추가 + @Transactional + public ResponseEntity updateCard(Long id, CardRequest updatedCard) { + + try { + + Optional optionalCard = cardRepository.findById(id); + Card newCard; + + if (optionalCard.isPresent()) { + newCard = optionalCard.get(); + tagService.updateTags(newCard, updatedCard.getTagItems()); + + newCard.setContent(updatedCard.getContent()); + newCard.setTitle(updatedCard.getTitle()); + newCard.setImgUrl(updatedCard.getImgUrl()); + + List tags = + newCard.getTagItems().stream() + .map( + tag -> + TagDto.builder() + .tagTitle(tag.getTagTitle()) + .tagContent(tag.getTagContent()) + .build()) + .toList(); + + return ResponseEntity.ok( + CardSearchResponse.builder() + .success(true) + .message("카드 수정 성공하였습니다.") + .card( + CardDto.builder() + .title(newCard.getTitle()) + .content(newCard.getContent()) + .imgUrl(newCard.getImgUrl()) + .tagItems(tags) + .build()) + .build()); + } else + return ResponseEntity.ok( + CardSearchResponse.builder().success(false).message("해당 카드가 존재하지 않습니다.").build()); + + } catch (Exception e) { + return ResponseEntity.ok( + CardSearchResponse.builder().success(false).message("카드 수정 중 에러가 발생했습니다.").build()); + } + } +} diff --git a/src/main/java/com/likelion/trendithon/domain/tag/Service/TagService.java b/src/main/java/com/likelion/trendithon/domain/tag/Service/TagService.java new file mode 100644 index 0000000..1fc4ea3 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/tag/Service/TagService.java @@ -0,0 +1,89 @@ +package com.likelion.trendithon.domain.tag.Service; + +import java.util.List; +import java.util.Objects; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.likelion.trendithon.domain.card.entity.Card; +import com.likelion.trendithon.domain.tag.dto.TagDto; +import com.likelion.trendithon.domain.tag.entity.Tag; +import com.likelion.trendithon.domain.tag.repository.TagRepository; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@AllArgsConstructor +@Slf4j +public class TagService { + + private TagRepository tagRepository; + + public void saveTag(List tags, Card newCard) { + List newTags = + tags.stream() + .map( + tagDto -> + Tag.builder() + .tagTitle(tagDto.getTagTitle()) + .tagContent(tagDto.getTagContent()) + .card(newCard) + .build()) + .toList(); + tagRepository.saveAll(newTags); + } + + @Transactional + public List getTags(Card card) { + + return tagRepository.findByCard(card); + } + + @Transactional + public void updateTags(Card card, List newTags) { + + List tags = tagRepository.findByCard(card); + + // tags엔 존재하는데 newTags에 존재하지 않으면 삭제 같으면 업뎃 + for (Tag tag : tags) { + boolean found = false; + for (TagDto newTag : newTags) { + if (Objects.equals(tag.getTagTitle(), newTag.getTagTitle())) { + tag.setTagTitle(newTag.getTagTitle()); + tag.setTagContent(newTag.getTagContent()); + found = true; + } + } + + if (!found) { + tagRepository.delete(tag); + } + } + + // newTags엔 존재하는데 tags엔 존재하지 않으면 추가 + for (TagDto newTag : newTags) { + // 기존 [1,2,3,4] 업데이트 [2,3,6] + boolean found = false; + + for (Tag tag : tags) { + if (Objects.equals(tag.getTagTitle(), newTag.getTagTitle())) { + found = true; + break; + } + } + + if (!found) { + + Tag tmp = + Tag.builder() + .tagTitle(newTag.getTagTitle()) + .tagContent(newTag.getTagContent()) + .card(card) + .build(); + tagRepository.save(tmp); + } + } + } +} diff --git a/src/main/java/com/likelion/trendithon/domain/tag/dto/TagDto.java b/src/main/java/com/likelion/trendithon/domain/tag/dto/TagDto.java new file mode 100644 index 0000000..ce69705 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/tag/dto/TagDto.java @@ -0,0 +1,16 @@ +package com.likelion.trendithon.domain.tag.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class TagDto { + + @Schema(description = "태그 제목", example = "팁") + private String tagTitle; + + @Schema(description = "태그 내용", example = "열심히 공부하기") + private String tagContent; +} diff --git a/src/main/java/com/likelion/trendithon/domain/tag/entity/Tag.java b/src/main/java/com/likelion/trendithon/domain/tag/entity/Tag.java new file mode 100644 index 0000000..c2d634d --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/tag/entity/Tag.java @@ -0,0 +1,40 @@ +package com.likelion.trendithon.domain.tag.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +import com.likelion.trendithon.domain.card.entity.Card; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Tag { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long tagId; + + @Column(name = "title", nullable = false) + private String tagTitle; + + @Column(name = "content", nullable = false) + private String tagContent; + + @ManyToOne + @JoinColumn(name = "card_id", nullable = false) + private Card card; +} diff --git a/src/main/java/com/likelion/trendithon/domain/tag/repository/TagRepository.java b/src/main/java/com/likelion/trendithon/domain/tag/repository/TagRepository.java new file mode 100644 index 0000000..3a06b72 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/tag/repository/TagRepository.java @@ -0,0 +1,13 @@ +package com.likelion.trendithon.domain.tag.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.likelion.trendithon.domain.card.entity.Card; +import com.likelion.trendithon.domain.tag.entity.Tag; + +public interface TagRepository extends JpaRepository { + + List findByCard(Card card); +} diff --git a/src/main/java/com/likelion/trendithon/global/config/SecurityConfig.java b/src/main/java/com/likelion/trendithon/global/config/SecurityConfig.java index 6f5b8de..3bcd1f8 100644 --- a/src/main/java/com/likelion/trendithon/global/config/SecurityConfig.java +++ b/src/main/java/com/likelion/trendithon/global/config/SecurityConfig.java @@ -42,8 +42,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "/", "/api/**", // 테스트용 모든 API 열어놓음. 나중에 삭제 "/swagger-ui/**", // Swagger UI - "/v3/api-docs/**" // API 문서 - ) + "/v3/api-docs/**", // API 문서 + "/api/cards/**") .permitAll() // 관리자 권한이 필요한 경로 설정 // .requestMatchers(HttpMethod.POST, "/api/**")