From 2e123aeb5198b9b81d194a1c8de76a5d99718023 Mon Sep 17 00:00:00 2001 From: HiLeeS Date: Mon, 3 Nov 2025 13:53:07 +0900 Subject: [PATCH 1/7] =?UTF-8?q?[=EC=95=84=EB=AA=AC=EB=93=9C=205=C3=AC]?= =?UTF-8?q?=C2=A3=C2=BC=EC=B0=A8=20=EB=AF=B8=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- umc9th/.gitignore | 3 ++ .../member/repository/MemberRepository.java | 9 +++++ .../domain/mission/dto/HomeMissionDto.java | 22 +++++++++++ .../mission/repository/MissionRepository.java | 37 +++++++++++++++++++ .../repository/UserMissionRepository.java | 9 +++++ .../review/repository/ReviewRepository.java | 22 +++++++++++ umc9th/src/main/resources/application.yml | 3 +- 7 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/repository/MemberRepository.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/dto/HomeMissionDto.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/repository/MissionRepository.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewRepository.java diff --git a/umc9th/.gitignore b/umc9th/.gitignore index c2065bc..5fc642b 100644 --- a/umc9th/.gitignore +++ b/umc9th/.gitignore @@ -35,3 +35,6 @@ out/ ### VS Code ### .vscode/ + +# Spring Boot application configuration +application.yml \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/repository/MemberRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/member/repository/MemberRepository.java new file mode 100644 index 0000000..a9a3f27 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/repository/MemberRepository.java @@ -0,0 +1,9 @@ +package com.example.umc9th.domain.member.repository; + +import com.example.umc9th.domain.member.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + +public interface MemberRepository extends JpaRepository { + Optional findByIdAndStatusIsTrue(Long memberId); +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/HomeMissionDto.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/HomeMissionDto.java new file mode 100644 index 0000000..b76afc8 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/HomeMissionDto.java @@ -0,0 +1,22 @@ +package com.example.umc9th.domain.mission.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +/** + * 홈 화면에서 지역별 미참여 미션을 조회할 때 사용되는 DTO + * MissionRepository의 JPQL DTO Projection에서 사용됨. + */ +@Getter +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class HomeMissionDto { + + private String region; // 사용자가 선택한 지역명 + private Long missionId; // 미션 ID + private String storeName; // 가게 이름 + private int point; // 미션 포인트 +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/MissionRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/MissionRepository.java new file mode 100644 index 0000000..2830c23 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/MissionRepository.java @@ -0,0 +1,37 @@ +package com.example.umc9th.domain.mission.repository; + +import com.example.umc9th.domain.mission.entity.Mission; +import com.example.umc9th.domain.mission.dto.HomeMissionDto; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.*; +import org.springframework.data.repository.query.Param; + +public interface MissionRepository extends JpaRepository { + + @Query("SELECT COUNT(um) FROM UserMission um WHERE um.member.id = :memberId AND um.status = true") + long countPerformedMissions(@Param("memberId") Long memberId); + + @Query(""" + SELECT new com.example.umc9th.domain.mission.dto.HomeMissionDto( + :region, + m.id, + s.name, + m.point + ) + FROM Mission m + JOIN m.store s + WHERE s.address LIKE CONCAT(:region, '%') + AND NOT EXISTS ( + SELECT 1 FROM UserMission um + WHERE um.mission.id = m.id + AND um.member.id = :memberId + ) + ORDER BY m.id DESC + """) + Page findUnjoinedMissions( + @Param("region") String region, + @Param("memberId") Long memberId, + Pageable pageable + ); +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java new file mode 100644 index 0000000..35bd0bc --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java @@ -0,0 +1,9 @@ +package com.example.umc9th.domain.mission.repository; + +import com.example.umc9th.domain.mission.entity.UserMission; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + +public interface UserMissionRepository extends JpaRepository { + List findByMemberIdAndStatusInOrderByDeadlineDesc(Long memberId, List statuses); +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewRepository.java new file mode 100644 index 0000000..32d95b0 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewRepository.java @@ -0,0 +1,22 @@ +package com.example.umc9th.domain.review.repository; + +import org.springframework.data.jpa.repository.*; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface ReviewRepository extends JpaRepository { + + @Modifying + @Query( + value = "INSERT INTO review (member_id, store_id, star, content, created_at) " + + "VALUES (:memberId, :storeId, :star, :content, NOW())", + nativeQuery = true + ) + void insertReview( + @Param("memberId") Long memberId, + @Param("storeId") Long storeId, + @Param("star") int star, + @Param("content") String content + ); +} diff --git a/umc9th/src/main/resources/application.yml b/umc9th/src/main/resources/application.yml index d820e86..a94ba1c 100644 --- a/umc9th/src/main/resources/application.yml +++ b/umc9th/src/main/resources/application.yml @@ -16,4 +16,5 @@ spring: ddl-auto: create # 애플리케이션 실행 시 데이터베이스 스키마의 상태를 설정 properties: hibernate: - format_sql: true # 출력되는 SQL 쿼리를 보기 좋게 포맷팅 \ No newline at end of file + format_sql: true # 출력되는 SQL 쿼리를 보기 좋게 포맷팅 + From 499fed416bcdc582df5d210143d90023cd093138 Mon Sep 17 00:00:00 2001 From: HiLeeS Date: Tue, 11 Nov 2025 13:15:02 +0900 Subject: [PATCH 2/7] =?UTF-8?q?6=EC=A3=BC=EC=B0=A8=20=EB=AF=B8=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- umc9th/build.gradle | 26 +++++++ .../umc9th/domain/member/entity/Member.java | 3 + .../review/controller/ReviewController.java | 42 ++++++++++++ .../review/repository/ReviewQueryDsl.java | 9 +++ .../review/repository/ReviewQueryDslImpl.java | 33 +++++++++ .../review/repository/ReviewRepository.java | 5 +- .../domain/review/service/ReviewService.java | 68 +++++++++++++++++++ .../umc9th/domain/store/entity/Store.java | 3 + umc9th/src/main/resources/application.yml | 2 +- .../domain/review/ReviewRepositoryTest.java | 40 +++++++++++ 10 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewQueryDsl.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewQueryDslImpl.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/service/ReviewService.java create mode 100644 umc9th/src/test/java/com/example/umc9th/domain/review/ReviewRepositoryTest.java diff --git a/umc9th/build.gradle b/umc9th/build.gradle index c663a55..79ea1f5 100644 --- a/umc9th/build.gradle +++ b/umc9th/build.gradle @@ -35,8 +35,34 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // QueryDSL : OpenFeign + implementation "io.github.openfeign.querydsl:querydsl-jpa:7.0" + implementation "io.github.openfeign.querydsl:querydsl-core:7.0" + annotationProcessor "io.github.openfeign.querydsl:querydsl-apt:7.0:jpa" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" } tasks.named('test') { useJUnitPlatform() } + +// QueryDSL 관련 설정 +// generated/querydsl 폴더 생성 & 삽입 +def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile + +// 소스 세트에 생성 경로 추가 (구체적인 경로 지정) +sourceSets { + main.java.srcDirs += [ querydslDir ] +} + +// 컴파일 시 생성 경로 지정 +tasks.withType(JavaCompile).configureEach { + options.generatedSourceOutputDirectory.set(querydslDir) +} + +// clean 태스크에 생성 폴더 삭제 로직 추가 +clean.doLast { + file(querydslDir).deleteDir() +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Member.java b/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Member.java index e6387f3..12e09e5 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Member.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Member.java @@ -2,6 +2,7 @@ import com.example.umc9th.domain.member.enums.Gender; import com.example.umc9th.global.entity.BaseEntity; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.*; import java.time.LocalDate; @@ -49,9 +50,11 @@ public class Member extends BaseEntity { //연관 관계 @OneToMany(mappedBy = "member") + @JsonIgnore private List memberInterests = new ArrayList<>(); @OneToMany(mappedBy = "member") + @JsonIgnore private List memberTerms = new ArrayList<>(); } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java b/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java new file mode 100644 index 0000000..368c1fd --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java @@ -0,0 +1,42 @@ +package com.example.umc9th.domain.review.controller; + +import com.example.umc9th.domain.review.entity.Review; +import com.example.umc9th.domain.review.service.ReviewService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + + +@RestController +@RequestMapping("/api/reviews") +@RequiredArgsConstructor +public class ReviewController { + + private final ReviewService reviewService; + + //테스트 + @GetMapping("/search") + public List Search(@RequestParam String query, @RequestParam String type) { //query : "안암동", type:"location" + List reviews = reviewService.searchReview(query, type); + return reviews; + } + + //미션 : 내가 직접 작성한 리뷰 조회 (가게명 / 별점 필터링) + @GetMapping("/my") + public List My(@RequestParam(required = false) String storeName, //아무 값도 안 들어올 수 있음 + @RequestParam(required = false) Integer star) { + long memberId = 1; + List reviews = reviewService.getMyReviews(memberId, storeName, star); + return reviews; + + } + + + + +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewQueryDsl.java b/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewQueryDsl.java new file mode 100644 index 0000000..e11daa5 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewQueryDsl.java @@ -0,0 +1,9 @@ +package com.example.umc9th.domain.review.repository; + +import com.example.umc9th.domain.review.entity.Review; +import com.querydsl.core.types.Predicate; +import java.util.List; + +public interface ReviewQueryDsl { + List searchReview(Predicate predicate); //동적 쿼리를 위해 Predicate 객체 사용 +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewQueryDslImpl.java b/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewQueryDslImpl.java new file mode 100644 index 0000000..72bcdc1 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewQueryDslImpl.java @@ -0,0 +1,33 @@ +package com.example.umc9th.domain.review.repository; + +import com.example.umc9th.domain.review.entity.QReview; +import com.example.umc9th.domain.review.entity.Review; +import com.querydsl.core.types.Predicate; +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +@RequiredArgsConstructor +public class ReviewQueryDslImpl implements ReviewQueryDsl { + + private final EntityManager em; //데이터베이스와 통신할 때 사용하는 핵심 인터페이스 + + @Override + public List searchReview(Predicate predicate) { + //JPA 세팅 + JPAQueryFactory queryFactory = new JPAQueryFactory(em); + + //Q클래스 선언 + QReview review = QReview.review; + + return queryFactory + .selectFrom(review) + .leftJoin(review.store).fetchJoin() // 리뷰와 가게를 한 번에 로드 + .leftJoin(review.member).fetchJoin() // 리뷰와 회원을 한 번에 로드 + .where(predicate) + .orderBy(review.createdAt.desc()) // 최신순 정렬 + .fetch(); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewRepository.java index 32d95b0..b555573 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewRepository.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/repository/ReviewRepository.java @@ -1,11 +1,12 @@ package com.example.umc9th.domain.review.repository; +import com.example.umc9th.domain.review.entity.Review; import org.springframework.data.jpa.repository.*; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository -public interface ReviewRepository extends JpaRepository { +public interface ReviewRepository extends JpaRepository, ReviewQueryDsl { @Modifying @Query( @@ -19,4 +20,6 @@ void insertReview( @Param("star") int star, @Param("content") String content ); + + } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/service/ReviewService.java b/umc9th/src/main/java/com/example/umc9th/domain/review/service/ReviewService.java new file mode 100644 index 0000000..136a927 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/service/ReviewService.java @@ -0,0 +1,68 @@ +package com.example.umc9th.domain.review.service; + +import com.example.umc9th.domain.review.entity.QReview; +import com.example.umc9th.domain.review.entity.Review; +import com.example.umc9th.domain.review.repository.ReviewRepository; +import com.querydsl.core.BooleanBuilder; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class ReviewService { + + private final ReviewRepository reviewRepository; + + public String queryTest(String name) { + QReview review = QReview.review; + BooleanBuilder builder = new BooleanBuilder(); + + if (name != null) { + builder.and(review.member.name.eq(name)); + } + + List reviewList = reviewRepository.searchReview(builder); + return reviewList.toString(); + } + + public List searchReview(String query, String type) { + QReview review = QReview.review; + BooleanBuilder builder = new BooleanBuilder(); + + if ("location".equals(type)) { + builder.and(review.store.address.contains(query)); + } else if ("star".equals(type)) { + builder.and(review.star.goe(Integer.parseInt(query))); + } else if ("both".equals(type)) { + String[] parts = query.split("&"); + builder.and(review.store.address.contains(parts[0])); + builder.and(review.star.goe(Integer.parseInt(parts[1]))); + } + + return reviewRepository.searchReview(builder); + } + + //미션 + public List getMyReviews(long memberId, String storeName, Integer star) { + QReview review = QReview.review; + BooleanBuilder builder = new BooleanBuilder(); + + // 로그인 사용자 조건 + builder.and(review.member.id.eq(memberId)); + + // 가게명 필터 + if (storeName != null && !storeName.isEmpty()) { + builder.and(review.store.name.containsIgnoreCase(storeName)); + } + + // 별점 필터 + if (star != null) { + builder.and(review.star.goe(star)); + } + + return reviewRepository.searchReview(builder); + } +} + diff --git a/umc9th/src/main/java/com/example/umc9th/domain/store/entity/Store.java b/umc9th/src/main/java/com/example/umc9th/domain/store/entity/Store.java index 4a183e2..77c5c8d 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/store/entity/Store.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/store/entity/Store.java @@ -3,6 +3,7 @@ import com.example.umc9th.domain.mission.entity.Mission; import com.example.umc9th.domain.review.entity.Review; import com.example.umc9th.global.entity.BaseEntity; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.*; @@ -41,8 +42,10 @@ public class Store extends BaseEntity { // 연관 관계 @OneToMany(mappedBy = "store") + @JsonIgnore private List reviews = new ArrayList<>(); @OneToMany(mappedBy = "store") + @JsonIgnore private List missions = new ArrayList<>(); } diff --git a/umc9th/src/main/resources/application.yml b/umc9th/src/main/resources/application.yml index a94ba1c..87375cb 100644 --- a/umc9th/src/main/resources/application.yml +++ b/umc9th/src/main/resources/application.yml @@ -13,7 +13,7 @@ spring: database-platform: org.hibernate.dialect.MySQLDialect # Hibernate에서 사용할 MySQL 방언(dialect) 설정 show-sql: true # 실행된 SQL 쿼리를 콘솔에 출력할지 여부 설정 hibernate: - ddl-auto: create # 애플리케이션 실행 시 데이터베이스 스키마의 상태를 설정 + ddl-auto: update # 애플리케이션 실행 시 데이터베이스 스키마의 상태를 설정 properties: hibernate: format_sql: true # 출력되는 SQL 쿼리를 보기 좋게 포맷팅 diff --git a/umc9th/src/test/java/com/example/umc9th/domain/review/ReviewRepositoryTest.java b/umc9th/src/test/java/com/example/umc9th/domain/review/ReviewRepositoryTest.java new file mode 100644 index 0000000..3310b6d --- /dev/null +++ b/umc9th/src/test/java/com/example/umc9th/domain/review/ReviewRepositoryTest.java @@ -0,0 +1,40 @@ +package com.example.umc9th.domain.review; + +import com.example.umc9th.domain.review.entity.Review; +import com.example.umc9th.domain.review.repository.ReviewRepository; +import com.querydsl.core.BooleanBuilder; +import com.example.umc9th.domain.review.entity.QReview; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@SpringBootTest +@Transactional +public class ReviewRepositoryTest { + + @Autowired + private ReviewRepository reviewRepository; + + @Test + void testSearchReview_ByStoreName() { + // given + QReview review = QReview.review; + BooleanBuilder builder = new BooleanBuilder(); + + builder.and(review.store.name.containsIgnoreCase("반이학생마라탕마라반")); + + // when + List results = reviewRepository.searchReview(builder); + + // then + System.out.println("✅ 검색 결과 개수: " + results.size()); + for (Review r : results) { + System.out.println("가게명: " + r.getStore().getName() + + ", 별점: " + r.getStar() + + ", 작성자: " + r.getMember().getName()); + } + } +} From 6857e4e5c94c4547900360f18200b4d5987fb7ec Mon Sep 17 00:00:00 2001 From: HiLeeS Date: Fri, 14 Nov 2025 13:04:55 +0900 Subject: [PATCH 3/7] =?UTF-8?q?[=EC=95=84=EB=AA=AC=EB=93=9C]=207=EC=A3=BC?= =?UTF-8?q?=EC=B0=A8=20=EB=AF=B8=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/controller/ReviewController.java | 10 +-- .../domain/test/converter/TestConverter.java | 24 +++++++ .../domain/test/dto/res/TestResDTO.java | 19 ++++++ .../domain/test/exception/TestException.java | 10 +++ .../test/exception/code/TestErrorCode.java | 19 ++++++ .../umc9th/global/apiPayload/ApiResponse.java | 36 ++++++++++ .../global/apiPayload/code/BaseErrorCode.java | 10 +++ .../apiPayload/code/BaseSuccessCode.java | 10 +++ .../apiPayload/code/GeneralErrorCode.java | 32 +++++++++ .../apiPayload/code/GeneralSuccessCode.java | 17 +++++ .../exception/GeneralException.java | 13 ++++ .../exception/GlobalExceptionHandler.java | 68 +++++++++++++++++++ .../handler/GeneralExceptionAdvice.java | 42 ++++++++++++ 13 files changed, 306 insertions(+), 4 deletions(-) create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/test/converter/TestConverter.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/test/dto/res/TestResDTO.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/test/exception/TestException.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/test/exception/code/TestErrorCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/apiPayload/ApiResponse.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/BaseErrorCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/BaseSuccessCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralSuccessCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/apiPayload/exception/GeneralException.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/apiPayload/exception/GlobalExceptionHandler.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java b/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java index 368c1fd..3b45b44 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java @@ -2,6 +2,8 @@ import com.example.umc9th.domain.review.entity.Review; import com.example.umc9th.domain.review.service.ReviewService; +import com.example.umc9th.global.apiPayload.ApiResponse; +import com.example.umc9th.global.apiPayload.code.GeneralSuccessCode; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,18 +23,18 @@ public class ReviewController { //테스트 @GetMapping("/search") - public List Search(@RequestParam String query, @RequestParam String type) { //query : "안암동", type:"location" + public ApiResponse> Search(@RequestParam String query, @RequestParam String type) { //query : "안암동", type:"location" List reviews = reviewService.searchReview(query, type); - return reviews; + return ApiResponse.onSuccess(GeneralSuccessCode.SUCCESS, reviews); } //미션 : 내가 직접 작성한 리뷰 조회 (가게명 / 별점 필터링) @GetMapping("/my") - public List My(@RequestParam(required = false) String storeName, //아무 값도 안 들어올 수 있음 + public ApiResponse> My(@RequestParam(required = false) String storeName, //아무 값도 안 들어올 수 있음 @RequestParam(required = false) Integer star) { long memberId = 1; List reviews = reviewService.getMyReviews(memberId, storeName, star); - return reviews; + return ApiResponse.onSuccess(GeneralSuccessCode.SUCCESS, reviews); } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/test/converter/TestConverter.java b/umc9th/src/main/java/com/example/umc9th/domain/test/converter/TestConverter.java new file mode 100644 index 0000000..af81183 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/test/converter/TestConverter.java @@ -0,0 +1,24 @@ +package com.example.umc9th.domain.test.converter; + +import com.example.umc9th.domain.test.dto.res.TestResDTO; + +public class TestConverter { + + // 객체 -> DTO + public static TestResDTO.Testing toTestingDTO( + String testing + ) { + return TestResDTO.Testing.builder() + .testString(testing) + .build(); + } + + // 객체 -> DTO + public static TestResDTO.Exception toExceptionDTO( + String testing + ){ + return TestResDTO.Exception.builder() + .testString(testing) + .build(); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/test/dto/res/TestResDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/test/dto/res/TestResDTO.java new file mode 100644 index 0000000..9f13f52 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/test/dto/res/TestResDTO.java @@ -0,0 +1,19 @@ +package com.example.umc9th.domain.test.dto.res; + +import lombok.Builder; +import lombok.Getter; + +public class TestResDTO { + + @Builder + @Getter + public static class Testing { + private String testString; + } + + @Builder + @Getter + public static class Exception { + private String testString; + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/test/exception/TestException.java b/umc9th/src/main/java/com/example/umc9th/domain/test/exception/TestException.java new file mode 100644 index 0000000..3507b6c --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/test/exception/TestException.java @@ -0,0 +1,10 @@ +package com.example.umc9th.domain.test.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; + +public class TestException extends GeneralException { + public TestException(BaseErrorCode code) { + super(code); + } +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/test/exception/code/TestErrorCode.java b/umc9th/src/main/java/com/example/umc9th/domain/test/exception/code/TestErrorCode.java new file mode 100644 index 0000000..7264f21 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/test/exception/code/TestErrorCode.java @@ -0,0 +1,19 @@ +package com.example.umc9th.domain.test.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum TestErrorCode implements BaseErrorCode { + + // For test + TEST_EXCEPTION(HttpStatus.BAD_REQUEST, "TEST400_1", "이거는 테스트"), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/ApiResponse.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/ApiResponse.java new file mode 100644 index 0000000..809ea7c --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/ApiResponse.java @@ -0,0 +1,36 @@ +package com.example.umc9th.global.apiPayload; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.code.BaseSuccessCode; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@JsonPropertyOrder({"isSuccess", "code", "message", "result"}) +public class ApiResponse { + + @JsonProperty("isSuccess") + private final Boolean isSuccess; + + @JsonProperty("code") + private final String code; + + @JsonProperty("message") + private final String message; + + @JsonProperty("result") + private T result; + + // 성공한 경우 (result 포함) + public static ApiResponse onSuccess(BaseSuccessCode code, T result) { + return new ApiResponse<>(true, code.getCode(), code.getMessage(), result); + } + + // 실패한 경우 (result 포함) + public static ApiResponse onFailure(BaseErrorCode code, T result) { + return new ApiResponse<>(false, code.getCode(), code.getMessage(), result); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/BaseErrorCode.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/BaseErrorCode.java new file mode 100644 index 0000000..3830b84 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/BaseErrorCode.java @@ -0,0 +1,10 @@ +package com.example.umc9th.global.apiPayload.code; + +import org.springframework.http.HttpStatus; + +public interface BaseErrorCode { + + HttpStatus getStatus(); + String getCode(); + String getMessage(); +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/BaseSuccessCode.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/BaseSuccessCode.java new file mode 100644 index 0000000..2924540 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/BaseSuccessCode.java @@ -0,0 +1,10 @@ +package com.example.umc9th.global.apiPayload.code; + +import org.springframework.http.HttpStatus; + +public interface BaseSuccessCode { + + HttpStatus getStatus(); + String getCode(); + String getMessage(); +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java new file mode 100644 index 0000000..6dd1df5 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java @@ -0,0 +1,32 @@ +package com.example.umc9th.global.apiPayload.code; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum GeneralErrorCode implements BaseErrorCode{ + + BAD_REQUEST(HttpStatus.BAD_REQUEST, + "COMMON400_1", + "잘못된 요청입니다."), + UNAUTHORIZED(HttpStatus.UNAUTHORIZED, + "AUTH401_1", + "인증이 필요합니다."), + FORBIDDEN(HttpStatus.FORBIDDEN, + "AUTH403_1", + "요청이 거부되었습니다."), + NOT_FOUND(HttpStatus.NOT_FOUND, + "COMMON404_1", + "요청한 리소스를 찾을 수 없습니다."), + + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, + "COMMON500_1", + "예기치 않은 서버 에러가 발생했습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralSuccessCode.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralSuccessCode.java new file mode 100644 index 0000000..aea35aa --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralSuccessCode.java @@ -0,0 +1,17 @@ +package com.example.umc9th.global.apiPayload.code; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum GeneralSuccessCode implements BaseSuccessCode { + + SUCCESS(HttpStatus.OK, "COMMON200", "요청이 성공적으로 처리되었습니다."), + REVIEW_LIST_SUCCESS(HttpStatus.OK, "REVIEW200", "내가 작성한 리뷰 조회"), + ; + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/exception/GeneralException.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/exception/GeneralException.java new file mode 100644 index 0000000..420007c --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/exception/GeneralException.java @@ -0,0 +1,13 @@ +package com.example.umc9th.global.apiPayload.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class GeneralException extends RuntimeException { + + private final BaseErrorCode errorCode; + +} diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/exception/GlobalExceptionHandler.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..fcf2a44 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/exception/GlobalExceptionHandler.java @@ -0,0 +1,68 @@ +package com.example.umc9th.global.apiPayload.exception; + +import com.example.umc9th.global.apiPayload.ApiResponse; +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.code.GeneralErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 비즈니스 로직에서 발생시키는 Custom Exception 처리 + */ + @ExceptionHandler(GeneralException.class) + public ResponseEntity> handleGeneralException(GeneralException e) { + + BaseErrorCode errorCode = e.getErrorCode(); + + log.warn("[GeneralException] {} - {}", errorCode.getCode(), errorCode.getMessage()); + + return ResponseEntity + .status(errorCode.getStatus()) + .body(ApiResponse.onFailure(errorCode, null)); + } + + /** + * 잘못된 입력 예외 처리 + */ + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity> handleIllegalArgument(IllegalArgumentException e) { + + log.warn("[IllegalArgumentException] {}", e.getMessage()); + + return ResponseEntity + .status(GeneralErrorCode.BAD_REQUEST.getStatus()) + .body(ApiResponse.onFailure(GeneralErrorCode.BAD_REQUEST, null)); + } + + /** + * 인증 실패 예외 처리 (예: JWT 검증 실패) + */ + @ExceptionHandler(SecurityException.class) + public ResponseEntity> handleSecurityException(SecurityException e) { + + log.warn("[SecurityException] {}", e.getMessage()); + + return ResponseEntity + .status(GeneralErrorCode.UNAUTHORIZED.getStatus()) + .body(ApiResponse.onFailure(GeneralErrorCode.UNAUTHORIZED, null)); + } + + /** + * 예상하지 못한 모든 서버 오류 처리 + */ + @ExceptionHandler(Exception.class) + public ResponseEntity> handleUnexpectedException(Exception e) { + + log.error("[UnexpectedException]", e); + + return ResponseEntity + .status(GeneralErrorCode.INTERNAL_SERVER_ERROR.getStatus()) + .body(ApiResponse.onFailure(GeneralErrorCode.INTERNAL_SERVER_ERROR, null)); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java new file mode 100644 index 0000000..7704828 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java @@ -0,0 +1,42 @@ +package com.example.umc9th.global.apiPayload.handler; + +import com.example.umc9th.global.apiPayload.ApiResponse; +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.code.GeneralErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GeneralExceptionAdvice { + + // 애플리케이션에서 발생하는 커스텀 예외를 처리 + @ExceptionHandler(GeneralException.class) + public ResponseEntity> handleException( + GeneralException ex + ) { + + return ResponseEntity.status(ex.getErrorCode().getStatus()) + .body(ApiResponse.onFailure( + ex.getErrorCode(), + null + ) + ); + } + + // 그 외의 정의되지 않은 모든 예외 처리 + @ExceptionHandler(Exception.class) + public ResponseEntity> handleException( + Exception ex + ) { + + BaseErrorCode code = GeneralErrorCode.INTERNAL_SERVER_ERROR; + return ResponseEntity.status(code.getStatus()) + .body(ApiResponse.onFailure( + code, + ex.getMessage() + ) + ); + } +} From 939d5dcafaa76fd49b0e6f78e58e1db0a09ec5f5 Mon Sep 17 00:00:00 2001 From: HiLeeS Date: Thu, 20 Nov 2025 12:58:33 +0900 Subject: [PATCH 4/7] =?UTF-8?q?[=EC=95=84=EB=AA=AC=EB=93=9C]=208=EC=A3=BC?= =?UTF-8?q?=EC=B0=A8=20=EB=AF=B8=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- umc9th/build.gradle | 7 ++ .../member/controller/MemberController.java | 29 ++++++++ .../member/converter/MemberConverter.java | 31 ++++++++ .../domain/member/dto/MemberReqDTO.java | 22 ++++++ .../domain/member/dto/MemberResDTO.java | 14 ++++ .../umc9th/domain/member/entity/Interest.java | 6 +- .../umc9th/domain/member/entity/Member.java | 16 ++--- .../umc9th/domain/member/enums/FoodName.java | 2 +- .../member/exception/InterestException.java | 10 +++ .../member/exception/MemberException.java | 10 +++ .../exception/code/InterestErrorCode.java | 20 ++++++ .../exception/code/InterestSuccessCode.java | 20 ++++++ .../exception/code/MemberErrorCode.java | 20 ++++++ .../exception/code/MemberSuccessCode.java | 20 ++++++ .../member/repository/InterestRepository.java | 7 ++ .../repository/MemberInterestRepository.java | 7 ++ .../service/command/MemberCommandService.java | 10 +++ .../command/MemberCommandServiceImpl.java | 70 +++++++++++++++++++ .../service/query/MemberQueryService.java | 4 ++ .../service/query/MemberQueryServiceImpl.java | 4 ++ .../mission/controller/MissionController.java | 30 ++++++++ .../mission/converter/MissionConverter.java | 27 +++++++ .../domain/mission/dto/MissionReqDTO.java | 12 ++++ .../domain/mission/dto/MissionResDTO.java | 14 ++++ .../mission/exception/MissionException.java | 15 ++++ .../exception/code/MissionErrorCode.java | 27 +++++++ .../exception/code/MissionSuccessCode.java | 24 +++++++ .../repository/UserMissionRepository.java | 3 + .../mission/service/MissionService.java | 51 ++++++++++++++ .../review/controller/ReviewController.java | 18 +++-- .../review/converter/ReviewConverter.java | 30 ++++++++ .../domain/review/dto/ReviewReqDTO.java | 14 ++++ .../domain/review/dto/ReviewResDTO.java | 14 ++++ .../review/exception/ReviewException.java | 10 +++ .../exception/code/ReviewErrorCode.java | 20 ++++++ .../exception/code/ReviewSuccessCode.java | 24 +++++++ .../domain/review/service/ReviewService.java | 30 ++++++++ .../store/exception/StoreException.java | 10 +++ .../store/exception/code/StoreErrorCode.java | 20 ++++++ .../exception/code/StoreSuccessCode.java | 20 ++++++ .../store/repository/StoreRepository.java | 9 +++ .../umc9th/global/annotation/ExistFoods.java | 26 +++++++ .../apiPayload/code/GeneralErrorCode.java | 5 +- .../handler/GeneralExceptionAdvice.java | 23 ++++++ .../umc9th/global/config/SwaggerConfig.java | 37 ++++++++++ .../global/validator/FoodExistValidator.java | 33 +++++++++ 46 files changed, 855 insertions(+), 20 deletions(-) create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/controller/MemberController.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/converter/MemberConverter.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/dto/MemberReqDTO.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/dto/MemberResDTO.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/exception/InterestException.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/exception/MemberException.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/InterestErrorCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/InterestSuccessCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/MemberErrorCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/MemberSuccessCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/repository/InterestRepository.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/repository/MemberInterestRepository.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/service/command/MemberCommandService.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/service/command/MemberCommandServiceImpl.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/service/query/MemberQueryService.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/member/service/query/MemberQueryServiceImpl.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/controller/MissionController.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/converter/MissionConverter.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionReqDTO.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionResDTO.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/exception/MissionException.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionErrorCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionSuccessCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/mission/service/MissionService.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/converter/ReviewConverter.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/dto/ReviewReqDTO.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/dto/ReviewResDTO.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/exception/ReviewException.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewErrorCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewSuccessCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/store/exception/StoreException.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/store/exception/code/StoreErrorCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/store/exception/code/StoreSuccessCode.java create mode 100644 umc9th/src/main/java/com/example/umc9th/domain/store/repository/StoreRepository.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/annotation/ExistFoods.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/config/SwaggerConfig.java create mode 100644 umc9th/src/main/java/com/example/umc9th/global/validator/FoodExistValidator.java diff --git a/umc9th/build.gradle b/umc9th/build.gradle index 79ea1f5..a1c7908 100644 --- a/umc9th/build.gradle +++ b/umc9th/build.gradle @@ -42,6 +42,13 @@ dependencies { annotationProcessor "io.github.openfeign.querydsl:querydsl-apt:7.0:jpa" annotationProcessor "jakarta.persistence:jakarta.persistence-api" annotationProcessor "jakarta.annotation:jakarta.annotation-api" + + // Swagger + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.13' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.8.13' + + // Validation + implementation 'org.springframework.boot:spring-boot-starter-validation' } tasks.named('test') { diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/controller/MemberController.java b/umc9th/src/main/java/com/example/umc9th/domain/member/controller/MemberController.java new file mode 100644 index 0000000..a67f97c --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/controller/MemberController.java @@ -0,0 +1,29 @@ +package com.example.umc9th.domain.member.controller; + +import com.example.umc9th.domain.member.dto.MemberReqDTO; +import com.example.umc9th.domain.member.dto.MemberResDTO; +import com.example.umc9th.domain.member.exception.code.MemberSuccessCode; +import com.example.umc9th.domain.member.service.command.MemberCommandService; +import com.example.umc9th.global.apiPayload.ApiResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class MemberController { + + private final MemberCommandService memberCommandService; + + // 회원가입 + @PostMapping("/sign-up") + public ApiResponse signUp( + @RequestBody @Valid MemberReqDTO.JoinDTO dto + ){ + return ApiResponse.onSuccess(MemberSuccessCode.FOUND, memberCommandService.signup(dto)); + } + + +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/converter/MemberConverter.java b/umc9th/src/main/java/com/example/umc9th/domain/member/converter/MemberConverter.java new file mode 100644 index 0000000..ec9676d --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/converter/MemberConverter.java @@ -0,0 +1,31 @@ +package com.example.umc9th.domain.member.converter; + +import com.example.umc9th.domain.member.dto.MemberReqDTO; +import com.example.umc9th.domain.member.dto.MemberResDTO; +import com.example.umc9th.domain.member.entity.Member; + +public class MemberConverter { + + // Entity -> DTO + public static MemberResDTO.JoinDTO toJoinDTO( + Member member + ){ + return MemberResDTO.JoinDTO.builder() + .memberId(member.getId()) + .createAt(member.getCreatedAt()) + .build(); + } + + // DTO -> Entity + public static Member toMember(MemberReqDTO.JoinDTO dto) { + return Member.builder() + .name(dto.name()) + .birth(dto.birth()) + .address(dto.address()) + .gender(dto.gender()) + .email(dto.email()) + .password(dto.password()) + .phone(dto.phone()) + .build(); + } +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/dto/MemberReqDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/member/dto/MemberReqDTO.java new file mode 100644 index 0000000..4589e75 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/dto/MemberReqDTO.java @@ -0,0 +1,22 @@ +package com.example.umc9th.domain.member.dto; + +import com.example.umc9th.domain.member.enums.Gender; +import com.example.umc9th.global.annotation.ExistFoods; + +import java.time.LocalDate; +import java.util.List; + +public class MemberReqDTO { + + public record JoinDTO( + String name, + Gender gender, + LocalDate birth, + String address, + String email, + String password, + String phone, + @ExistFoods + List preferCategory + ){} +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/dto/MemberResDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/member/dto/MemberResDTO.java new file mode 100644 index 0000000..9bc5c5e --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/dto/MemberResDTO.java @@ -0,0 +1,14 @@ +package com.example.umc9th.domain.member.dto; + +import lombok.Builder; + +import java.time.LocalDateTime; + +public class MemberResDTO { + + @Builder + public record JoinDTO( + Long memberId, + LocalDateTime createAt + ){} +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Interest.java b/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Interest.java index 2701268..4a83acd 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Interest.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Interest.java @@ -22,9 +22,9 @@ public class Interest { @Enumerated(EnumType.STRING) private FoodName name; - //연관 관계 - @OneToMany(mappedBy = "interest") - private List memberInterests = new ArrayList<>(); +// //연관 관계 +// @OneToMany(mappedBy = "interest") +// private List memberInterests = new ArrayList<>(); } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Member.java b/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Member.java index 12e09e5..c3dd01f 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Member.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/entity/Member.java @@ -48,13 +48,13 @@ public class Member extends BaseEntity { @Column(name = "status") private boolean status; - //연관 관계 - @OneToMany(mappedBy = "member") - @JsonIgnore - private List memberInterests = new ArrayList<>(); - - @OneToMany(mappedBy = "member") - @JsonIgnore - private List memberTerms = new ArrayList<>(); +// //연관 관계 +// @OneToMany(mappedBy = "member") +// @JsonIgnore +// private List memberInterests = new ArrayList<>(); + +// @OneToMany(mappedBy = "member") +// @JsonIgnore +// private List memberTerms = new ArrayList<>(); } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/enums/FoodName.java b/umc9th/src/main/java/com/example/umc9th/domain/member/enums/FoodName.java index 701fc3d..a73d87e 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/member/enums/FoodName.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/enums/FoodName.java @@ -1,5 +1,5 @@ package com.example.umc9th.domain.member.enums; public enum FoodName { - A, B, C, D, E, F; + KOREAN, JAPAN, CHINA; } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/exception/InterestException.java b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/InterestException.java new file mode 100644 index 0000000..d9e83c2 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/InterestException.java @@ -0,0 +1,10 @@ +package com.example.umc9th.domain.member.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; + +public class InterestException extends GeneralException { + public InterestException(BaseErrorCode code) { + super(code); + } +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/exception/MemberException.java b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/MemberException.java new file mode 100644 index 0000000..43f63f3 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/MemberException.java @@ -0,0 +1,10 @@ +package com.example.umc9th.domain.member.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; + +public class MemberException extends GeneralException { + public MemberException(BaseErrorCode code) { + super(code); + } +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/InterestErrorCode.java b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/InterestErrorCode.java new file mode 100644 index 0000000..e3bd901 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/InterestErrorCode.java @@ -0,0 +1,20 @@ +package com.example.umc9th.domain.member.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum InterestErrorCode implements BaseErrorCode { + + NOT_FOUND(HttpStatus.NOT_FOUND, + "INTERSET404_1", + "해당 관심음식을 찾지 못했습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/InterestSuccessCode.java b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/InterestSuccessCode.java new file mode 100644 index 0000000..c905377 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/InterestSuccessCode.java @@ -0,0 +1,20 @@ +package com.example.umc9th.domain.member.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseSuccessCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum InterestSuccessCode implements BaseSuccessCode { + + FOUND(HttpStatus.OK, + "INTEREST200_1", + "성공적으로 관심음식를 조회했습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/MemberErrorCode.java b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/MemberErrorCode.java new file mode 100644 index 0000000..64645ae --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/MemberErrorCode.java @@ -0,0 +1,20 @@ +package com.example.umc9th.domain.member.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum MemberErrorCode implements BaseErrorCode { + + NOT_FOUND(HttpStatus.NOT_FOUND, + "MEMBER404_1", + "해당 사용자를 찾지 못했습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/MemberSuccessCode.java b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/MemberSuccessCode.java new file mode 100644 index 0000000..5b1e0e0 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/exception/code/MemberSuccessCode.java @@ -0,0 +1,20 @@ +package com.example.umc9th.domain.member.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseSuccessCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum MemberSuccessCode implements BaseSuccessCode { + + FOUND(HttpStatus.OK, + "MEMBER200_1", + "성공적으로 사용자를 조회했습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/repository/InterestRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/member/repository/InterestRepository.java new file mode 100644 index 0000000..57bc460 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/repository/InterestRepository.java @@ -0,0 +1,7 @@ +package com.example.umc9th.domain.member.repository; + +import com.example.umc9th.domain.member.entity.Interest; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface InterestRepository extends JpaRepository { +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/repository/MemberInterestRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/member/repository/MemberInterestRepository.java new file mode 100644 index 0000000..9b2bddd --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/repository/MemberInterestRepository.java @@ -0,0 +1,7 @@ +package com.example.umc9th.domain.member.repository; + +import com.example.umc9th.domain.member.entity.MemberInterest; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberInterestRepository extends JpaRepository { +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/service/command/MemberCommandService.java b/umc9th/src/main/java/com/example/umc9th/domain/member/service/command/MemberCommandService.java new file mode 100644 index 0000000..03ec6f2 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/service/command/MemberCommandService.java @@ -0,0 +1,10 @@ +package com.example.umc9th.domain.member.service.command; + +import com.example.umc9th.domain.member.dto.MemberReqDTO; +import com.example.umc9th.domain.member.dto.MemberResDTO; + +public interface MemberCommandService { + public MemberResDTO.JoinDTO signup( + MemberReqDTO.JoinDTO dto + ); +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/service/command/MemberCommandServiceImpl.java b/umc9th/src/main/java/com/example/umc9th/domain/member/service/command/MemberCommandServiceImpl.java new file mode 100644 index 0000000..3793a11 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/service/command/MemberCommandServiceImpl.java @@ -0,0 +1,70 @@ +package com.example.umc9th.domain.member.service.command; + +import com.example.umc9th.domain.member.converter.MemberConverter; +import com.example.umc9th.domain.member.dto.MemberReqDTO; +import com.example.umc9th.domain.member.dto.MemberResDTO; +import com.example.umc9th.domain.member.entity.Interest; +import com.example.umc9th.domain.member.entity.Member; +import com.example.umc9th.domain.member.entity.MemberInterest; +import com.example.umc9th.domain.member.exception.InterestException; +import com.example.umc9th.domain.member.exception.code.InterestErrorCode; +import com.example.umc9th.domain.member.repository.InterestRepository; +import com.example.umc9th.domain.member.repository.MemberInterestRepository; +import com.example.umc9th.domain.member.repository.MemberRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class MemberCommandServiceImpl implements MemberCommandService{ + + private final MemberRepository memberRepository; + private final MemberInterestRepository memberInterestRepository; + private final InterestRepository interestRepository; + + // 회원가입 + @Override + @Transactional + public MemberResDTO.JoinDTO signup( + MemberReqDTO.JoinDTO dto + ){ + //사용자 생성 + Member member = MemberConverter.toMember(dto); + //DB 적용 + memberRepository.save(member); + + //선호 음식 여부 존재 확인 + if(dto.preferCategory().size() > 0){ + List memberInterestList = new ArrayList<>(); + + // 선호 음식 ID별 조회 + for (Long id : dto.preferCategory()){ + + // 음식 존재 여부 검증 + Interest interest = interestRepository.findById(id) + .orElseThrow(() -> new InterestException(InterestErrorCode.NOT_FOUND)); + + // MemberFood 엔티티 생성 (컨버터 사용해야 함) + MemberInterest memberFood = MemberInterest.builder() + .member(member) + .interest(interest) + .build(); + + // 사용자 - 음식 (선호 음식) 추가 + memberInterestList.add(memberFood); + } + + // 모든 관심 음식 추가: DB 적용 + memberInterestRepository.saveAll(memberInterestList); + + + } + // 응답 DTO 생성 + return MemberConverter.toJoinDTO(member); + + } +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/service/query/MemberQueryService.java b/umc9th/src/main/java/com/example/umc9th/domain/member/service/query/MemberQueryService.java new file mode 100644 index 0000000..286df25 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/service/query/MemberQueryService.java @@ -0,0 +1,4 @@ +package com.example.umc9th.domain.member.service.query; + +public class MemberQueryService { +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/member/service/query/MemberQueryServiceImpl.java b/umc9th/src/main/java/com/example/umc9th/domain/member/service/query/MemberQueryServiceImpl.java new file mode 100644 index 0000000..7ce41c8 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/member/service/query/MemberQueryServiceImpl.java @@ -0,0 +1,4 @@ +package com.example.umc9th.domain.member.service.query; + +public class MemberQueryServiceImpl { +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/controller/MissionController.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/controller/MissionController.java new file mode 100644 index 0000000..bf32011 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/controller/MissionController.java @@ -0,0 +1,30 @@ +package com.example.umc9th.domain.mission.controller; + +import com.example.umc9th.domain.mission.dto.MissionReqDTO; +import com.example.umc9th.domain.mission.dto.MissionResDTO; +import com.example.umc9th.domain.mission.exception.code.MissionSuccessCode; +import com.example.umc9th.domain.mission.service.MissionService; +import com.example.umc9th.global.apiPayload.ApiResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/missions") +public class MissionController { + + private final MissionService missionService; + + @PostMapping("/challenge") + public ApiResponse challengeMission( + @RequestBody MissionReqDTO.ChallengeDTO dto) { + + MissionResDTO.ChallengeDTO result = + missionService.challengeMission(dto.memberId(), dto.missionId(), dto.deadline()); + + return ApiResponse.onSuccess(MissionSuccessCode.CREATE, result); + } +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/converter/MissionConverter.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/converter/MissionConverter.java new file mode 100644 index 0000000..9a9e527 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/converter/MissionConverter.java @@ -0,0 +1,27 @@ +package com.example.umc9th.domain.mission.converter; + +import com.example.umc9th.domain.member.entity.Member; +import com.example.umc9th.domain.mission.dto.MissionResDTO; +import com.example.umc9th.domain.mission.entity.Mission; +import com.example.umc9th.domain.mission.entity.UserMission; + +import java.time.LocalDate; + +public class MissionConverter { + + public static UserMission toUserMission(Member member, Mission mission, LocalDate deadline) { + return UserMission.builder() + .member(member) + .mission(mission) + .deadline(deadline) + .status(true) // 도전중 + .build(); + } + + public static MissionResDTO.ChallengeDTO toChallengeDTO(UserMission userMission) { + return MissionResDTO.ChallengeDTO.builder() + .userMissionId(userMission.getId()) + .deadline(userMission.getDeadline()) + .build(); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionReqDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionReqDTO.java new file mode 100644 index 0000000..6f3ad4e --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionReqDTO.java @@ -0,0 +1,12 @@ +package com.example.umc9th.domain.mission.dto; + +import java.time.LocalDate; + +public class MissionReqDTO { + + public record ChallengeDTO( + Long memberId, + Long missionId, + LocalDate deadline + ) {} +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionResDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionResDTO.java new file mode 100644 index 0000000..6f66d03 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionResDTO.java @@ -0,0 +1,14 @@ +package com.example.umc9th.domain.mission.dto; + +import lombok.Builder; + +import java.time.LocalDate; + +public class MissionResDTO { + + @Builder + public record ChallengeDTO( + Long userMissionId, + LocalDate deadline + ) {} +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/MissionException.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/MissionException.java new file mode 100644 index 0000000..222838a --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/MissionException.java @@ -0,0 +1,15 @@ +package com.example.umc9th.domain.mission.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.Getter; + +@Getter +public class MissionException extends RuntimeException { + + private final BaseErrorCode errorCode; + + public MissionException(BaseErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionErrorCode.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionErrorCode.java new file mode 100644 index 0000000..251ba56 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionErrorCode.java @@ -0,0 +1,27 @@ +package com.example.umc9th.domain.mission.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum MissionErrorCode implements BaseErrorCode { + + // 미션 조회 오류 + NOT_FOUND(HttpStatus.NOT_FOUND, "MISSION_404", "해당 미션을 찾을 수 없습니다."), + + // 이미 도전 중 + ALREADY_CHALLENGING(HttpStatus.CONFLICT, "MISSION_409", "이미 도전 중인 미션입니다."), + + // 유저 미션 조회 오류 + USER_MISSION_NOT_FOUND(HttpStatus.NOT_FOUND, "MISSION_404_U", "해당 유저의 미션 정보를 찾을 수 없습니다."), + + // 미션 비활성화 상태 + MISSION_DISABLED(HttpStatus.BAD_REQUEST, "MISSION_400", "활성화되지 않은 미션입니다."); + + private final HttpStatus status; + private final String code; + private final String message; +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionSuccessCode.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionSuccessCode.java new file mode 100644 index 0000000..65c13fa --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionSuccessCode.java @@ -0,0 +1,24 @@ +package com.example.umc9th.domain.mission.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseSuccessCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum MissionSuccessCode implements BaseSuccessCode { + + FOUND(HttpStatus.OK, + "INTEREST200_1", + "성공적으로 미션을 조회했습니다."), + + CREATE(HttpStatus.CREATED, + "REVIEW200_2", + "미션 추가 성공") + ; + + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java index 35bd0bc..08d910f 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java @@ -1,9 +1,12 @@ package com.example.umc9th.domain.mission.repository; +import com.example.umc9th.domain.member.entity.Member; +import com.example.umc9th.domain.mission.entity.Mission; import com.example.umc9th.domain.mission.entity.UserMission; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface UserMissionRepository extends JpaRepository { List findByMemberIdAndStatusInOrderByDeadlineDesc(Long memberId, List statuses); + boolean existsByMemberAndMission(Member member, Mission mission); } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/service/MissionService.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/service/MissionService.java new file mode 100644 index 0000000..b9944e4 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/service/MissionService.java @@ -0,0 +1,51 @@ +package com.example.umc9th.domain.mission.service; + +import com.example.umc9th.domain.member.entity.Member; +import com.example.umc9th.domain.member.exception.MemberException; +import com.example.umc9th.domain.member.exception.code.MemberErrorCode; +import com.example.umc9th.domain.member.repository.MemberRepository; +import com.example.umc9th.domain.mission.converter.MissionConverter; +import com.example.umc9th.domain.mission.dto.MissionResDTO; +import com.example.umc9th.domain.mission.entity.Mission; +import com.example.umc9th.domain.mission.entity.UserMission; +import com.example.umc9th.domain.mission.exception.MissionException; +import com.example.umc9th.domain.mission.exception.code.MissionErrorCode; +import com.example.umc9th.domain.mission.repository.MissionRepository; +import com.example.umc9th.domain.mission.repository.UserMissionRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; + +@Service +@RequiredArgsConstructor +public class MissionService { + + private final MemberRepository memberRepository; + private final MissionRepository missionRepository; + private final UserMissionRepository userMissionRepository; + + @Transactional + public MissionResDTO.ChallengeDTO challengeMission(Long memberId, Long missionId, LocalDate deadline) { + + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new MemberException(MemberErrorCode.NOT_FOUND)); + + Mission mission = missionRepository.findById(missionId) + .orElseThrow(() -> new MissionException(MissionErrorCode.NOT_FOUND)); + + // 이미 도전 중인지 체크 + if (userMissionRepository.existsByMemberAndMission(member, mission)) { + throw new MissionException(MissionErrorCode.ALREADY_CHALLENGING); + } + + // UserMission 생성 + UserMission userMission = + MissionConverter.toUserMission(member, mission, deadline != null ? deadline : LocalDate.now().plusDays(7)); + + userMissionRepository.save(userMission); + + return MissionConverter.toChallengeDTO(userMission); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java b/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java index 3b45b44..daefe51 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java @@ -1,16 +1,15 @@ package com.example.umc9th.domain.review.controller; +import com.example.umc9th.domain.review.dto.ReviewReqDTO; +import com.example.umc9th.domain.review.dto.ReviewResDTO; import com.example.umc9th.domain.review.entity.Review; +import com.example.umc9th.domain.review.exception.code.ReviewSuccessCode; import com.example.umc9th.domain.review.service.ReviewService; import com.example.umc9th.global.apiPayload.ApiResponse; import com.example.umc9th.global.apiPayload.code.GeneralSuccessCode; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; import java.util.List; @@ -38,7 +37,12 @@ public ApiResponse> My(@RequestParam(required = false) String store } - - + @PostMapping + public ApiResponse createReview( + @RequestBody ReviewReqDTO.CreateDTO dto + ){ + ReviewResDTO.CreateDTO result = reviewService.createReview(dto); + return ApiResponse.onSuccess(ReviewSuccessCode.CREATE, result); + } } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/converter/ReviewConverter.java b/umc9th/src/main/java/com/example/umc9th/domain/review/converter/ReviewConverter.java new file mode 100644 index 0000000..8a5ec83 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/converter/ReviewConverter.java @@ -0,0 +1,30 @@ +package com.example.umc9th.domain.review.converter; + +import com.example.umc9th.domain.member.entity.Member; +import com.example.umc9th.domain.review.dto.ReviewReqDTO; +import com.example.umc9th.domain.review.dto.ReviewResDTO; +import com.example.umc9th.domain.review.entity.Review; +import com.example.umc9th.domain.store.entity.Store; + +import java.time.LocalDate; + +public class ReviewConverter { + + public static Review toEntity(ReviewReqDTO.CreateDTO dto, Member member, Store store) { + return Review.builder() + .star(dto.star()) + .content(dto.content()) + .imageUrl(dto.imageUrl()) + .member(member) + .store(store) + .status(true) + .build(); + } + + public static ReviewResDTO.CreateDTO toCreateDTO(Review review) { + return ReviewResDTO.CreateDTO.builder() + .reviewId(review.getId()) + .createdAt(LocalDate.from(review.getCreatedAt())) + .build(); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/dto/ReviewReqDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/review/dto/ReviewReqDTO.java new file mode 100644 index 0000000..1d34903 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/dto/ReviewReqDTO.java @@ -0,0 +1,14 @@ +package com.example.umc9th.domain.review.dto; + +import java.time.LocalDate; + +public class ReviewReqDTO { + + public record CreateDTO( + Long memberId, + Long storeId, + Float star, + String content, + String imageUrl + ) {} +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/dto/ReviewResDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/review/dto/ReviewResDTO.java new file mode 100644 index 0000000..ba16496 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/dto/ReviewResDTO.java @@ -0,0 +1,14 @@ +package com.example.umc9th.domain.review.dto; + +import lombok.Builder; + +import java.time.LocalDate; + +public class ReviewResDTO { + + @Builder + public record CreateDTO( + Long reviewId, + LocalDate createdAt + ) {} +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/exception/ReviewException.java b/umc9th/src/main/java/com/example/umc9th/domain/review/exception/ReviewException.java new file mode 100644 index 0000000..afde6b0 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/exception/ReviewException.java @@ -0,0 +1,10 @@ +package com.example.umc9th.domain.review.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; + +public class ReviewException extends GeneralException { + public ReviewException(BaseErrorCode code) { + super(code); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewErrorCode.java b/umc9th/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewErrorCode.java new file mode 100644 index 0000000..bdd86b2 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewErrorCode.java @@ -0,0 +1,20 @@ +package com.example.umc9th.domain.review.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ReviewErrorCode implements BaseErrorCode { + + NOT_FOUND(HttpStatus.NOT_FOUND, + "STORE404_1", + "해당 리뷰를 찾지 못했습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; + } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewSuccessCode.java b/umc9th/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewSuccessCode.java new file mode 100644 index 0000000..efdc9c0 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewSuccessCode.java @@ -0,0 +1,24 @@ +package com.example.umc9th.domain.review.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseSuccessCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ReviewSuccessCode implements BaseSuccessCode { + + FOUND(HttpStatus.OK, + "INTEREST200_1", + "성공적으로 리뷰를 조회했습니다."), + + CREATE(HttpStatus.CREATED, + "REVIEW200_2", + "리뷰 작성 성공") + ; + + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/review/service/ReviewService.java b/umc9th/src/main/java/com/example/umc9th/domain/review/service/ReviewService.java index 136a927..b7f6b2e 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/review/service/ReviewService.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/review/service/ReviewService.java @@ -1,9 +1,21 @@ package com.example.umc9th.domain.review.service; +import com.example.umc9th.domain.member.entity.Member; +import com.example.umc9th.domain.member.exception.MemberException; +import com.example.umc9th.domain.member.exception.code.MemberErrorCode; +import com.example.umc9th.domain.member.repository.MemberRepository; +import com.example.umc9th.domain.review.converter.ReviewConverter; +import com.example.umc9th.domain.review.dto.ReviewReqDTO; +import com.example.umc9th.domain.review.dto.ReviewResDTO; import com.example.umc9th.domain.review.entity.QReview; import com.example.umc9th.domain.review.entity.Review; import com.example.umc9th.domain.review.repository.ReviewRepository; +import com.example.umc9th.domain.store.entity.Store; +import com.example.umc9th.domain.store.exception.StoreException; +import com.example.umc9th.domain.store.exception.code.StoreErrorCode; +import com.example.umc9th.domain.store.repository.StoreRepository; import com.querydsl.core.BooleanBuilder; +import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -14,6 +26,8 @@ public class ReviewService { private final ReviewRepository reviewRepository; + private final MemberRepository memberRepository; + private final StoreRepository storeRepository; public String queryTest(String name) { QReview review = QReview.review; @@ -64,5 +78,21 @@ public List getMyReviews(long memberId, String storeName, Integer star) return reviewRepository.searchReview(builder); } + + //리뷰 생성 + @Transactional + public ReviewResDTO.CreateDTO createReview(ReviewReqDTO.CreateDTO dto) { + + Member member = memberRepository.findById(dto.memberId()) + .orElseThrow(() -> new MemberException(MemberErrorCode.NOT_FOUND)); + + Store store = storeRepository.findById(dto.storeId()) + .orElseThrow(() -> new StoreException(StoreErrorCode.NOT_FOUND)); + + Review review = ReviewConverter.toEntity(dto, member, store); + reviewRepository.save(review); + + return ReviewConverter.toCreateDTO(review); + } } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/store/exception/StoreException.java b/umc9th/src/main/java/com/example/umc9th/domain/store/exception/StoreException.java new file mode 100644 index 0000000..a6e94bc --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/store/exception/StoreException.java @@ -0,0 +1,10 @@ +package com.example.umc9th.domain.store.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; + +public class StoreException extends GeneralException { + public StoreException(BaseErrorCode code) { + super(code); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/store/exception/code/StoreErrorCode.java b/umc9th/src/main/java/com/example/umc9th/domain/store/exception/code/StoreErrorCode.java new file mode 100644 index 0000000..b7a6d8b --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/store/exception/code/StoreErrorCode.java @@ -0,0 +1,20 @@ +package com.example.umc9th.domain.store.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum StoreErrorCode implements BaseErrorCode { + + NOT_FOUND(HttpStatus.NOT_FOUND, + "STORE404_1", + "해당 식당을 찾지 못했습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; + } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/store/exception/code/StoreSuccessCode.java b/umc9th/src/main/java/com/example/umc9th/domain/store/exception/code/StoreSuccessCode.java new file mode 100644 index 0000000..bcb92e2 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/store/exception/code/StoreSuccessCode.java @@ -0,0 +1,20 @@ +package com.example.umc9th.domain.store.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseSuccessCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum StoreSuccessCode implements BaseSuccessCode { + + FOUND(HttpStatus.OK, + "INTEREST200_1", + "성공적으로 식당을 조회했습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/domain/store/repository/StoreRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/store/repository/StoreRepository.java new file mode 100644 index 0000000..11861a5 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/domain/store/repository/StoreRepository.java @@ -0,0 +1,9 @@ +package com.example.umc9th.domain.store.repository; + +import com.example.umc9th.domain.review.entity.Review; +import com.example.umc9th.domain.store.entity.Store; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.CrudRepository; + +public interface StoreRepository extends JpaRepository { +} diff --git a/umc9th/src/main/java/com/example/umc9th/global/annotation/ExistFoods.java b/umc9th/src/main/java/com/example/umc9th/global/annotation/ExistFoods.java new file mode 100644 index 0000000..01c1172 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/annotation/ExistFoods.java @@ -0,0 +1,26 @@ +package com.example.umc9th.global.annotation; + +import com.example.umc9th.global.validator.FoodExistValidator; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.*; + +// +@Documented +@Constraint(validatedBy = FoodExistValidator.class) +@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExistFoods { + //여기서 디폴트 메시지를 설정합니다. + String message() default "해당 음식이 존재하지 않습니다."; + Class[] groups() default {}; + Class[] payload() default {}; +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java index 6dd1df5..3410535 100644 --- a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java @@ -24,7 +24,10 @@ public enum GeneralErrorCode implements BaseErrorCode{ INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500_1", "예기치 않은 서버 에러가 발생했습니다."), - ; + + VALID_FAIL(HttpStatus.BAD_REQUEST, + "COMMON400_2", + "요청 값이 유효하지 않습니다."); private final HttpStatus status; private final String code; diff --git a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java index 7704828..7512f95 100644 --- a/umc9th/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java +++ b/umc9th/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java @@ -5,9 +5,13 @@ import com.example.umc9th.global.apiPayload.code.GeneralErrorCode; import com.example.umc9th.global.apiPayload.exception.GeneralException; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import java.util.HashMap; +import java.util.Map; + @RestControllerAdvice public class GeneralExceptionAdvice { @@ -39,4 +43,23 @@ public ResponseEntity> handleException( ) ); } + + // 컨트롤러 메서드에서 @Valid 어노테이션을 사용하여 DTO의 유효성 검사를 수행 + @ExceptionHandler(MethodArgumentNotValidException.class) + protected ResponseEntity>> handleMethodArgumentNotValidException( + MethodArgumentNotValidException ex + ) { + // 검사에 실패한 필드와 그에 대한 메시지를 저장하는 Map + Map errors = new HashMap<>(); + ex.getBindingResult().getFieldErrors().forEach(error -> + errors.put(error.getField(), error.getDefaultMessage()) + ); + + GeneralErrorCode code = GeneralErrorCode.VALID_FAIL; + ApiResponse> errorResponse = ApiResponse.onFailure(code, errors); + + // 에러 코드, 메시지와 함께 errors를 반환 + return ResponseEntity.status(code.getStatus()).body(errorResponse); + } + } diff --git a/umc9th/src/main/java/com/example/umc9th/global/config/SwaggerConfig.java b/umc9th/src/main/java/com/example/umc9th/global/config/SwaggerConfig.java new file mode 100644 index 0000000..e3e85a2 --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/config/SwaggerConfig.java @@ -0,0 +1,37 @@ +package com.example.umc9th.global.config; + + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI swagger() { + Info info = new Info().title("UMC9th").description("Spring Boot").version("0.0.1"); + + // JWT 토큰 헤더 방식 + String securityScheme = "JWT TOKEN"; + SecurityRequirement securityRequirement = new SecurityRequirement().addList(securityScheme); + + Components components = new Components() + .addSecuritySchemes(securityScheme, new SecurityScheme() + .name(securityScheme) + .type(SecurityScheme.Type.HTTP) + .scheme("Bearer") + .bearerFormat("JWT")); + + return new OpenAPI() + .info(info) + .addServersItem(new Server().url("/")) + .addSecurityItem(securityRequirement) + .components(components); + } +} \ No newline at end of file diff --git a/umc9th/src/main/java/com/example/umc9th/global/validator/FoodExistValidator.java b/umc9th/src/main/java/com/example/umc9th/global/validator/FoodExistValidator.java new file mode 100644 index 0000000..57324cf --- /dev/null +++ b/umc9th/src/main/java/com/example/umc9th/global/validator/FoodExistValidator.java @@ -0,0 +1,33 @@ +package com.example.umc9th.global.validator; + +import com.example.umc9th.domain.member.exception.code.InterestErrorCode; +import com.example.umc9th.domain.member.repository.InterestRepository; +import com.example.umc9th.global.annotation.ExistFoods; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class FoodExistValidator implements ConstraintValidator> { + + private final InterestRepository interestRepository; + + @Override + public boolean isValid(List values, ConstraintValidatorContext context) { + boolean isValid = values.stream() + .allMatch(value -> interestRepository.existsById(value)); + + if (!isValid) { + // 이 부분에서 아까 디폴트 메시지를 초기화 시키고, 새로운 메시지로 덮어씌우게 됩니다. + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(InterestErrorCode.NOT_FOUND.getMessage()).addConstraintViolation(); + } + + return isValid; + + } +} \ No newline at end of file From 58470b3ae3047a33733c34b5038bdf12ac2089ce Mon Sep 17 00:00:00 2001 From: HiLeeS Date: Thu, 20 Nov 2025 13:45:38 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[=EC=95=84=EB=AA=AC=EB=93=9C]=208=EC=A3=BC?= =?UTF-8?q?=EC=B0=A8=20=EB=AF=B8=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mission/controller/MissionController.java | 30 +++++++++-- .../mission/converter/MissionConverter.java | 24 ++++++++- .../domain/mission/dto/MissionReqDTO.java | 9 +++- .../domain/mission/dto/MissionResDTO.java | 27 ++++++++++ .../domain/mission/entity/UserMission.java | 7 +++ .../exception/code/MissionSuccessCode.java | 13 ++--- .../repository/UserMissionRepository.java | 9 ++++ .../mission/service/MissionService.java | 50 +++++++++++++++++-- 8 files changed, 150 insertions(+), 19 deletions(-) diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/controller/MissionController.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/controller/MissionController.java index bf32011..c1961bd 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/controller/MissionController.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/controller/MissionController.java @@ -6,10 +6,9 @@ import com.example.umc9th.domain.mission.service.MissionService; import com.example.umc9th.global.apiPayload.ApiResponse; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @RestController @RequiredArgsConstructor @@ -18,6 +17,7 @@ public class MissionController { private final MissionService missionService; + // 미션 도전하기 @PostMapping("/challenge") public ApiResponse challengeMission( @RequestBody MissionReqDTO.ChallengeDTO dto) { @@ -27,4 +27,24 @@ public ApiResponse challengeMission( return ApiResponse.onSuccess(MissionSuccessCode.CREATE, result); } -} \ No newline at end of file + + // 내 미션 목록 조회 (진행중 + 성공) + @GetMapping("/my/{memberId}") + public ApiResponse> getMyMissions(@PathVariable Long memberId) { + return ApiResponse.onSuccess( + MissionSuccessCode.OK, + missionService.getMyMissions(memberId) + ); + } + + // 미션 성공 처리 + @PostMapping("/success") + public ApiResponse successMission( + @RequestBody MissionReqDTO.SuccessDTO dto) { + + MissionResDTO.SuccessDTO result = + missionService.successMission(dto.memberId(), dto.userMissionId()); + + return ApiResponse.onSuccess(MissionSuccessCode.SUCCESS, result); + } +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/converter/MissionConverter.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/converter/MissionConverter.java index 9a9e527..cde1c51 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/converter/MissionConverter.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/converter/MissionConverter.java @@ -9,19 +9,41 @@ public class MissionConverter { + // UserMission 생성 (도전하기) public static UserMission toUserMission(Member member, Mission mission, LocalDate deadline) { return UserMission.builder() .member(member) .mission(mission) .deadline(deadline) - .status(true) // 도전중 + .status(true) // 도전 시작 → 진행중 .build(); } + // 도전 응답 DTO public static MissionResDTO.ChallengeDTO toChallengeDTO(UserMission userMission) { return MissionResDTO.ChallengeDTO.builder() .userMissionId(userMission.getId()) .deadline(userMission.getDeadline()) .build(); } + + // 내 미션 목록 DTO + public static MissionResDTO.MyMissionDTO toMyMissionDTO(UserMission um) { + return MissionResDTO.MyMissionDTO.builder() + .userMissionId(um.getId()) + .missionId(um.getMission().getId()) + .missionStatus(um.isStatus() ? "CHALLENGING" : "SUCCESS") + .point(um.getMission().getPoint()) + .storeName(um.getMission().getStore().getName()) + .deadline(um.getDeadline()) + .build(); + } + + // 미션 성공 응답 DTO + public static MissionResDTO.SuccessDTO toSuccessDTO(UserMission um) { + return MissionResDTO.SuccessDTO.builder() + .userMissionId(um.getId()) + .missionStatus("SUCCESS") + .build(); + } } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionReqDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionReqDTO.java index 6f3ad4e..bb96078 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionReqDTO.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionReqDTO.java @@ -4,9 +4,16 @@ public class MissionReqDTO { + // 미션 도전하기 요청 public record ChallengeDTO( Long memberId, Long missionId, - LocalDate deadline + LocalDate deadline // null이면 서비스에서 기본값(예: +7일) 설정 + ) {} + + // 미션 성공 처리 요청 + public record SuccessDTO( + Long memberId, + Long userMissionId // 도전한 user_mission PK ) {} } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionResDTO.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionResDTO.java index 6f66d03..a73748a 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionResDTO.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/dto/MissionResDTO.java @@ -6,9 +6,36 @@ public class MissionResDTO { + // 미션 도전 성공 응답 @Builder public record ChallengeDTO( Long userMissionId, LocalDate deadline ) {} + + // 내 미션 목록 (진행중/성공) + @Builder + public record MyMissionDTO( + Long userMissionId, + Long missionId, + String missionStatus, // "CHALLENGING" 또는 "SUCCESS" + int point, + String storeName, + LocalDate deadline + ) {} + + // 미션 단일 정보 (필요하면 사용) + @Builder + public record MissionDTO( + Long missionId, + int point, + boolean status + ) {} + + // 미션 성공 처리 응답 + @Builder + public record SuccessDTO( + Long userMissionId, + String missionStatus // 항상 "SUCCESS" + ) {} } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/entity/UserMission.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/entity/UserMission.java index d596315..e3de7fa 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/entity/UserMission.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/entity/UserMission.java @@ -22,6 +22,8 @@ public class UserMission extends BaseEntity { @Column(name = "deadline", nullable = false) private LocalDate deadline; + // true = 진행중(CHALLENGING) + // false = 성공(SUCCESS) @Column(name = "status", nullable = false) private boolean status; @@ -33,4 +35,9 @@ public class UserMission extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "mission_id", nullable = false) private Mission mission; + + // ==== 비즈니스 메서드 ==== + public void complete() { + this.status = false; + } } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionSuccessCode.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionSuccessCode.java index 65c13fa..48bf48f 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionSuccessCode.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/exception/code/MissionSuccessCode.java @@ -9,16 +9,11 @@ @AllArgsConstructor public enum MissionSuccessCode implements BaseSuccessCode { - FOUND(HttpStatus.OK, - "INTEREST200_1", - "성공적으로 미션을 조회했습니다."), - - CREATE(HttpStatus.CREATED, - "REVIEW200_2", - "미션 추가 성공") - ; + OK(HttpStatus.OK, "MISSION_200", "미션 조회 성공"), + CREATE(HttpStatus.CREATED, "MISSION_201", "미션 도전 성공"), + SUCCESS(HttpStatus.OK, "MISSION_200_S", "미션 성공 처리 완료"); private final HttpStatus status; private final String code; private final String message; -} \ No newline at end of file +} diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java index 08d910f..b0ec599 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/repository/UserMissionRepository.java @@ -4,9 +4,18 @@ import com.example.umc9th.domain.mission.entity.Mission; import com.example.umc9th.domain.mission.entity.UserMission; import org.springframework.data.jpa.repository.JpaRepository; + import java.util.List; +import java.util.Optional; public interface UserMissionRepository extends JpaRepository { + List findByMemberIdAndStatusInOrderByDeadlineDesc(Long memberId, List statuses); + boolean existsByMemberAndMission(Member member, Mission mission); + + List findByMemberId(Long memberId); + + // 미션 성공 처리 시: 해당 회원의 해당 user_mission만 조회 + Optional findByIdAndMemberId(Long id, Long memberId); } diff --git a/umc9th/src/main/java/com/example/umc9th/domain/mission/service/MissionService.java b/umc9th/src/main/java/com/example/umc9th/domain/mission/service/MissionService.java index b9944e4..6c7e429 100644 --- a/umc9th/src/main/java/com/example/umc9th/domain/mission/service/MissionService.java +++ b/umc9th/src/main/java/com/example/umc9th/domain/mission/service/MissionService.java @@ -17,6 +17,7 @@ import org.springframework.stereotype.Service; import java.time.LocalDate; +import java.util.List; @Service @RequiredArgsConstructor @@ -26,6 +27,9 @@ public class MissionService { private final MissionRepository missionRepository; private final UserMissionRepository userMissionRepository; + /** + * 미션 도전하기 + */ @Transactional public MissionResDTO.ChallengeDTO challengeMission(Long memberId, Long missionId, LocalDate deadline) { @@ -40,12 +44,52 @@ public MissionResDTO.ChallengeDTO challengeMission(Long memberId, Long missionId throw new MissionException(MissionErrorCode.ALREADY_CHALLENGING); } - // UserMission 생성 - UserMission userMission = - MissionConverter.toUserMission(member, mission, deadline != null ? deadline : LocalDate.now().plusDays(7)); + // 마감 기한 기본값 설정 (null이면 +7일) + LocalDate finalDeadline = (deadline != null) ? deadline : LocalDate.now().plusDays(7); + // UserMission 생성 및 저장 + UserMission userMission = MissionConverter.toUserMission(member, mission, finalDeadline); userMissionRepository.save(userMission); return MissionConverter.toChallengeDTO(userMission); } + + /** + * 내 미션 목록 조회 (진행중 + 성공) + */ + @Transactional + public List getMyMissions(Long memberId) { + + // 유저 유효성 검사 + memberRepository.findById(memberId) + .orElseThrow(() -> new MemberException(MemberErrorCode.NOT_FOUND)); + + List list = userMissionRepository.findByMemberId(memberId); + + return list.stream() + .map(MissionConverter::toMyMissionDTO) + .toList(); + } + + /** + * 미션 성공 처리 + */ + @Transactional + public MissionResDTO.SuccessDTO successMission(Long memberId, Long userMissionId) { + + // 해당 회원의 user_mission인지 검증 + UserMission userMission = userMissionRepository.findByIdAndMemberId(userMissionId, memberId) + .orElseThrow(() -> new MissionException(MissionErrorCode.USER_MISSION_NOT_FOUND)); + + // 이미 성공 상태면 그냥 둠 (idempotent) + if (!userMission.isStatus()) { + // 이미 SUCCESS 상태 → 그대로 응답 + return MissionConverter.toSuccessDTO(userMission); + } + + // 진행중 → 성공 처리 + userMission.complete(); // status = false + + return MissionConverter.toSuccessDTO(userMission); + } } From f140a0a7d782af83550d76d6efef34ec61bbf48a Mon Sep 17 00:00:00 2001 From: HiLeeS Date: Thu, 20 Nov 2025 13:49:19 +0900 Subject: [PATCH 6/7] =?UTF-8?q?[=EC=95=84=EB=AA=AC=EB=93=9C]=208=EC=A3=BC?= =?UTF-8?q?=EC=B0=A8=20=EB=AF=B8=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week0/ERD.vuerd.json | 684 ++++++++++++++++--------------------------- 1 file changed, 255 insertions(+), 429 deletions(-) diff --git a/week0/ERD.vuerd.json b/week0/ERD.vuerd.json index 9b9623c..bf2867b 100644 --- a/week0/ERD.vuerd.json +++ b/week0/ERD.vuerd.json @@ -4,9 +4,9 @@ "settings": { "width": 2000, "height": 2000, - "scrollTop": -263.7869, - "scrollLeft": -267.5756, - "zoomLevel": 0.52, + "scrollTop": -146.1667, + "scrollLeft": -46, + "zoomLevel": 1, "show": 431, "database": 4, "databaseName": "", @@ -38,7 +38,8 @@ "ETcc-k8p-2Xj7Avc_QuIL", "YsXMe4aWI4vSU7M4Pdeny", "ORir_zY3zWs8fj9eKIhij", - "EPYnTEbnzHcSM-TV7Yogy" + "zrNDU9R9OQONz9IYpCOQv", + "yu3szoId7FctUvSa0xoTn" ], "relationshipIds": [ "fr8aQL5wJeCHd6nA3FkpV", @@ -48,8 +49,8 @@ "27fFwlvcry7s3zwMedMPL", "mokzjvYQM38mTea-1naJe", "leblF8kHmiRMhcnCVAceD", - "onHzSgg1u3-Nk4tYVf7t0", - "zdTWn5Wpu4-atC3FVpk1E" + "wbLj5mUjPu5rltCDHj3XD", + "8aesalFlcdiXVhsHAAd_f" ], "indexIds": [], "memoIds": [] @@ -58,7 +59,7 @@ "tableEntities": { "2y1bvJOIG1e0BeEWgxI08": { "id": "2y1bvJOIG1e0BeEWgxI08", - "name": "user", + "name": "member", "comment": "사용자", "columnIds": [ "vDFt6LsnU_OsODOI3QFtU", @@ -72,7 +73,8 @@ "-gL9Tv6k4tzEhExARRMVF", "rAo8blJvJWiSMdcXxPEQm", "AdD_6uo7QsyR4vZ5mWieR", - "sbMtd5RQq7uaV0Cru8P_v" + "sbMtd5RQq7uaV0Cru8P_v", + "rgoW8fTWbtyd9QtgnCv4X" ], "seqColumnIds": [ "WkqAgrjlXhLG2sEbIA5US", @@ -87,18 +89,19 @@ "-gL9Tv6k4tzEhExARRMVF", "rAo8blJvJWiSMdcXxPEQm", "AdD_6uo7QsyR4vZ5mWieR", - "sbMtd5RQq7uaV0Cru8P_v" + "sbMtd5RQq7uaV0Cru8P_v", + "rgoW8fTWbtyd9QtgnCv4X" ], "ui": { - "x": 212.9919, - "y": 486.4899, + "x": 298.9682, + "y": 607.0328, "zIndex": 2, "widthName": 60, "widthComment": 60, "color": "" }, "meta": { - "updateAt": 1758003899942, + "updateAt": 1759818994411, "createAt": 1758002169271 } }, @@ -115,15 +118,15 @@ "K_vOBQsbyMWekqQ_MEI4N" ], "ui": { - "x": 1246.7656, - "y": 203.1501, + "x": 1265.3757, + "y": 430.4087, "zIndex": 10, "widthName": 60, "widthComment": 60, "color": "" }, "meta": { - "updateAt": 1758005023914, + "updateAt": 1759818391682, "createAt": 1758002208352 } }, @@ -152,15 +155,15 @@ "TOi3d5nz-qA4ggbf5SGaA" ], "ui": { - "x": 689.4692, - "y": 190.8081, + "x": 793.9093, + "y": 419.843, "zIndex": 11, "widthName": 69, "widthComment": 67, "color": "" }, "meta": { - "updateAt": 1758005001026, + "updateAt": 1759818393286, "createAt": 1758002209969 } }, @@ -170,7 +173,6 @@ "comment": "가게", "columnIds": [ "F_CCSEveysTRYLn8lx8gE", - "GnAxf5fMaPNYtyzoiYMA-", "chq0SKqnzdsl00Sjku66M", "CXpU5qG_eglJfOISVq81C", "4Zf3gYPB2YGTzKHUoubEC", @@ -193,15 +195,15 @@ "uM2ODWrSWgyAfDgK5Acu0" ], "ui": { - "x": 1246.1474, - "y": 487.642, + "x": 1285.0693, + "y": 681.9737, "zIndex": 12, "widthName": 60, "widthComment": 60, "color": "" }, "meta": { - "updateAt": 1758005005400, + "updateAt": 1759818983111, "createAt": 1758002211392 } }, @@ -235,15 +237,15 @@ "6KXjwhh7zBv5U9ju-mYIk" ], "ui": { - "x": 743.7147, - "y": 492.0608, + "x": 798.4637, + "y": 668.3929, "zIndex": 13, "widthName": 60, "widthComment": 60, "color": "" }, "meta": { - "updateAt": 1758005004123, + "updateAt": 1759818388503, "createAt": 1758002211983 } }, @@ -255,8 +257,8 @@ "w4-iEtBZVv4oZMo29nEVr", "qyv68yagM3C9_IGyT2VLt", "DpzdVYsCL9lkCfts-ehwz", - "P5y2uZFuvYjeM7xY-aY56", "p5gVywEZV25DrR5jz4fkH", + "P5y2uZFuvYjeM7xY-aY56", "S2qqHB5cNDTVqitPQMpQ1" ], "seqColumnIds": [ @@ -265,20 +267,20 @@ "JtA1FPZRI3bkk9CFQzhXP", "qyv68yagM3C9_IGyT2VLt", "DpzdVYsCL9lkCfts-ehwz", - "P5y2uZFuvYjeM7xY-aY56", "p5gVywEZV25DrR5jz4fkH", + "P5y2uZFuvYjeM7xY-aY56", "S2qqHB5cNDTVqitPQMpQ1" ], "ui": { - "x": 205.9873, - "y": 937.228, + "x": 306.263, + "y": 1072.3362, "zIndex": 14, "widthName": 67, "widthComment": 85, "color": "" }, "meta": { - "updateAt": 1758004995283, + "updateAt": 1759818383231, "createAt": 1758002212209 } }, @@ -305,53 +307,68 @@ "ucsLuC5D65W0EisT2Jycw" ], "ui": { - "x": 889.8041, - "y": 952.9649, + "x": 839.0704, + "y": 1075.7449, "zIndex": 15, "widthName": 60, "widthComment": 60, "color": "" }, "meta": { - "updateAt": 1758004989746, + "updateAt": 1759818384505, "createAt": 1758002213387 } }, - "EPYnTEbnzHcSM-TV7Yogy": { - "id": "EPYnTEbnzHcSM-TV7Yogy", - "name": "alam", - "comment": "알람", + "zrNDU9R9OQONz9IYpCOQv": { + "id": "zrNDU9R9OQONz9IYpCOQv", + "name": "term", + "comment": "약관", + "columnIds": [ + "lzTP7Y9Q2wHxnor3iYbUN", + "n97RJkZ1d-qHS3OQ5IFWn" + ], + "seqColumnIds": [ + "lzTP7Y9Q2wHxnor3iYbUN", + "n97RJkZ1d-qHS3OQ5IFWn" + ], + "ui": { + "x": 312.2384, + "y": 156.6367, + "zIndex": 16, + "widthName": 60, + "widthComment": 60, + "color": "" + }, + "meta": { + "updateAt": 1759818397498, + "createAt": 1759711809275 + } + }, + "yu3szoId7FctUvSa0xoTn": { + "id": "yu3szoId7FctUvSa0xoTn", + "name": "User_term", + "comment": "유저약관", "columnIds": [ - "4djG9DS3q5mf3YpwU2HxJ", - "nbxToDPDboiyNNJkXi3gK", - "8AHxK4llaRij7qCl2APTB", - "SRBlLiACwF7a2KELunbz9", - "-d9Y5vU42vkDQB2q9tUd0", - "btij5fWDwHCTeHvbkXJGC", - "b5UklzcMtcMi11RLRp0Tz", - "CCq1c0NyEngIoj0AErl8d" + "Ad9Q86E6ce1GUaw49K9ni", + "IJ-OWDU5a6JkkFcx_lY2a", + "TgXJQ_3fDRKT5RxMLCCCW" ], "seqColumnIds": [ - "4djG9DS3q5mf3YpwU2HxJ", - "nbxToDPDboiyNNJkXi3gK", - "8AHxK4llaRij7qCl2APTB", - "SRBlLiACwF7a2KELunbz9", - "-d9Y5vU42vkDQB2q9tUd0", - "btij5fWDwHCTeHvbkXJGC", - "b5UklzcMtcMi11RLRp0Tz", - "CCq1c0NyEngIoj0AErl8d" + "Ad9Q86E6ce1GUaw49K9ni", + "IJ-OWDU5a6JkkFcx_lY2a", + "TgXJQ_3fDRKT5RxMLCCCW" ], "ui": { - "x": 119.2208, - "y": 96.1056, - "zIndex": 539, + "x": 300.585, + "y": 363.9731, + "zIndex": 61, "widthName": 60, "widthComment": 60, "color": "" }, "meta": { - "updateAt": 1758004999298, - "createAt": 1758004663649 + "updateAt": 1759818395578, + "createAt": 1759711945588 } } }, @@ -399,7 +416,7 @@ "KpiXQMwL5ze-vJKrQlQ1V": { "id": "KpiXQMwL5ze-vJKrQlQ1V", "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "sex", + "name": "gender", "comment": "", "dataType": "INT", "default": "", @@ -412,7 +429,7 @@ "widthDefault": 60 }, "meta": { - "updateAt": 1758002410593, + "updateAt": 1759819677323, "createAt": 1758002177165 } }, @@ -1676,34 +1693,14 @@ "createAt": 1758004517394 } }, - "4djG9DS3q5mf3YpwU2HxJ": { - "id": "4djG9DS3q5mf3YpwU2HxJ", - "tableId": "EPYnTEbnzHcSM-TV7Yogy", - "name": "id", + "GnAxf5fMaPNYtyzoiYMA-": { + "id": "GnAxf5fMaPNYtyzoiYMA-", + "tableId": "NA3wwYX9_yPbc5rR8NQP3", + "name": "categori_id", "comment": "", "dataType": "BIGINT", "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004789027, - "createAt": 1758004685866 - } - }, - "8AHxK4llaRij7qCl2APTB": { - "id": "8AHxK4llaRij7qCl2APTB", - "tableId": "EPYnTEbnzHcSM-TV7Yogy", - "name": "content", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, + "options": 8, "ui": { "keys": 0, "widthName": 60, @@ -1712,16 +1709,16 @@ "widthDefault": 60 }, "meta": { - "updateAt": 1758004760600, - "createAt": 1758004748516 + "updateAt": 1758004970506, + "createAt": 1758004959005 } }, - "SRBlLiACwF7a2KELunbz9": { - "id": "SRBlLiACwF7a2KELunbz9", - "tableId": "EPYnTEbnzHcSM-TV7Yogy", - "name": "dtype", + "n97RJkZ1d-qHS3OQ5IFWn": { + "id": "n97RJkZ1d-qHS3OQ5IFWn", + "tableId": "zrNDU9R9OQONz9IYpCOQv", + "name": "name", "comment": "", - "dataType": "VARCHAR", + "dataType": "ENUM", "default": "", "options": 0, "ui": { @@ -1732,78 +1729,58 @@ "widthDefault": 60 }, "meta": { - "updateAt": 1758004786975, - "createAt": 1758004761964 - } - }, - "-d9Y5vU42vkDQB2q9tUd0": { - "id": "-d9Y5vU42vkDQB2q9tUd0", - "tableId": "EPYnTEbnzHcSM-TV7Yogy", - "name": "is_confirmed", - "comment": "", - "dataType": "BOOLEAN", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 69, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004819783, - "createAt": 1758004803972 + "updateAt": 1759711854656, + "createAt": 1759711822863 } }, - "btij5fWDwHCTeHvbkXJGC": { - "id": "btij5fWDwHCTeHvbkXJGC", - "tableId": "EPYnTEbnzHcSM-TV7Yogy", - "name": "createdAt", + "lzTP7Y9Q2wHxnor3iYbUN": { + "id": "lzTP7Y9Q2wHxnor3iYbUN", + "tableId": "zrNDU9R9OQONz9IYpCOQv", + "name": "term_id", "comment": "", - "dataType": "DATETIME", + "dataType": "BIGINT", "default": "", - "options": 0, + "options": 10, "ui": { - "keys": 0, + "keys": 1, "widthName": 60, "widthComment": 60, "widthDataType": 60, "widthDefault": 60 }, "meta": { - "updateAt": 1758004834316, - "createAt": 1758004821577 + "updateAt": 1759712966327, + "createAt": 1759711868594 } }, - "b5UklzcMtcMi11RLRp0Tz": { - "id": "b5UklzcMtcMi11RLRp0Tz", - "tableId": "EPYnTEbnzHcSM-TV7Yogy", - "name": "updatedAt", + "Ad9Q86E6ce1GUaw49K9ni": { + "id": "Ad9Q86E6ce1GUaw49K9ni", + "tableId": "yu3szoId7FctUvSa0xoTn", + "name": "", "comment": "", - "dataType": "DATETIME", + "dataType": "", "default": "", - "options": 0, + "options": 10, "ui": { - "keys": 0, + "keys": 1, "widthName": 60, "widthComment": 60, "widthDataType": 60, "widthDefault": 60 }, "meta": { - "updateAt": 1758004844394, - "createAt": 1758004838567 + "updateAt": 1759712914169, + "createAt": 1759712914169 } }, - "nbxToDPDboiyNNJkXi3gK": { - "id": "nbxToDPDboiyNNJkXi3gK", - "tableId": "EPYnTEbnzHcSM-TV7Yogy", - "name": "title", + "rgoW8fTWbtyd9QtgnCv4X": { + "id": "rgoW8fTWbtyd9QtgnCv4X", + "tableId": "2y1bvJOIG1e0BeEWgxI08", + "name": "", "comment": "", - "dataType": "VARCHAR", + "dataType": "", "default": "", - "options": 0, + "options": 8, "ui": { "keys": 0, "widthName": 60, @@ -1812,14 +1789,14 @@ "widthDefault": 60 }, "meta": { - "updateAt": 1758004859027, - "createAt": 1758004845381 + "updateAt": 1759712916893, + "createAt": 1759712916893 } }, - "CCq1c0NyEngIoj0AErl8d": { - "id": "CCq1c0NyEngIoj0AErl8d", - "tableId": "EPYnTEbnzHcSM-TV7Yogy", - "name": "id", + "IJ-OWDU5a6JkkFcx_lY2a": { + "id": "IJ-OWDU5a6JkkFcx_lY2a", + "tableId": "yu3szoId7FctUvSa0xoTn", + "name": "user_id", "comment": "", "dataType": "BIGINT", "default": "", @@ -1832,14 +1809,14 @@ "widthDefault": 60 }, "meta": { - "updateAt": 1758004886190, - "createAt": 1758004886190 + "updateAt": 1759712959800, + "createAt": 1759712932112 } }, - "GnAxf5fMaPNYtyzoiYMA-": { - "id": "GnAxf5fMaPNYtyzoiYMA-", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "categori_id", + "TgXJQ_3fDRKT5RxMLCCCW": { + "id": "TgXJQ_3fDRKT5RxMLCCCW", + "tableId": "yu3szoId7FctUvSa0xoTn", + "name": "term_id", "comment": "", "dataType": "BIGINT", "default": "", @@ -1852,96 +1829,12 @@ "widthDefault": 60 }, "meta": { - "updateAt": 1758004970506, - "createAt": 1758004959005 + "updateAt": 1759712966327, + "createAt": 1759712939784 } } }, "relationshipEntities": { - "xK2wIzn8YvFuChzw0Dagu": { - "id": "xK2wIzn8YvFuChzw0Dagu", - "identification": false, - "relationshipType": 8, - "startRelationshipType": 2, - "start": { - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU" - ], - "x": 409.8077, - "y": 211.3846, - "direction": 4 - }, - "end": { - "tableId": "C70HRfoZAc7T12El2mwAl", - "columnIds": [ - "ZOfk9HJZaFLK5-NEKO8vl" - ], - "x": 424.5, - "y": 172, - "direction": 8 - }, - "meta": { - "updateAt": 1758003750071, - "createAt": 1758003750071 - } - }, - "CsYdwbemu7dScsssDAGrm": { - "id": "CsYdwbemu7dScsssDAGrm", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU" - ], - "x": 304.2419, - "y": 486.4899, - "direction": 4 - }, - "end": { - "tableId": "C70HRfoZAc7T12El2mwAl", - "columnIds": [ - "DTmy4dcbiGAdTi4A-XWI2" - ], - "x": 305.1974, - "y": 281.6316, - "direction": 8 - }, - "meta": { - "updateAt": 1758003899738, - "createAt": 1758003899738 - } - }, - "SCM3Y82XG6UqMZaqywoaC": { - "id": "SCM3Y82XG6UqMZaqywoaC", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "rtTGV1n8fXrv3EOos4XcJ", - "columnIds": [ - "aNu4U_tr1NuWc674pipto" - ], - "x": 821.6032, - "y": 187.4332, - "direction": 1 - }, - "end": { - "tableId": "C70HRfoZAc7T12El2mwAl", - "columnIds": [ - "mHW9ecFk_GQMdjVjAyLpl" - ], - "x": 578.9474, - "y": 193.6316, - "direction": 2 - }, - "meta": { - "updateAt": 1758003967414, - "createAt": 1758003967414 - } - }, "fr8aQL5wJeCHd6nA3FkpV": { "id": "fr8aQL5wJeCHd6nA3FkpV", "identification": false, @@ -1952,8 +1845,8 @@ "columnIds": [ "vDFt6LsnU_OsODOI3QFtU" ], - "x": 577.9919, - "y": 658.4899, + "x": 663.9682, + "y": 883.0328, "direction": 2 }, "end": { @@ -1961,8 +1854,8 @@ "columnIds": [ "2JRKA_JcUA-Bcyt770hvg" ], - "x": 743.7147, - "y": 628.0608, + "x": 798.4637, + "y": 804.3929, "direction": 1 }, "meta": { @@ -1970,146 +1863,6 @@ "createAt": 1758004034426 } }, - "tZExJN6wzYQQN6Tca1jgN": { - "id": "tZExJN6wzYQQN6Tca1jgN", - "identification": false, - "relationshipType": 8, - "startRelationshipType": 2, - "start": { - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "columnIds": [ - "PMYbggYiPE_sMz3U_2LqK" - ], - "x": 1241.6559, - "y": 648.0608, - "direction": 2 - }, - "end": { - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "columnIds": [ - "uM2ODWrSWgyAfDgK5Acu0" - ], - "x": 1510.0089, - "y": 659.2758, - "direction": 1 - }, - "meta": { - "updateAt": 1758004056510, - "createAt": 1758004056510 - } - }, - "gp8EmzSFJVNx_IWEC5SS_": { - "id": "gp8EmzSFJVNx_IWEC5SS_", - "identification": false, - "relationshipType": 8, - "startRelationshipType": 2, - "start": { - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU" - ], - "x": 395.4919, - "y": 486.4899, - "direction": 4 - }, - "end": { - "tableId": "C70HRfoZAc7T12El2mwAl", - "columnIds": [ - "ZbsPFDxV-m07EPay0qcI2" - ], - "x": 396.4474, - "y": 257.6316, - "direction": 8 - }, - "meta": { - "updateAt": 1758004190658, - "createAt": 1758004190658 - } - }, - "pAmwkZWnp6pSWMBQJSz0W": { - "id": "pAmwkZWnp6pSWMBQJSz0W", - "identification": false, - "relationshipType": 8, - "startRelationshipType": 2, - "start": { - "tableId": "rtTGV1n8fXrv3EOos4XcJ", - "columnIds": [ - "aNu4U_tr1NuWc674pipto" - ], - "x": 821.6032, - "y": 213.4332, - "direction": 1 - }, - "end": { - "tableId": "C70HRfoZAc7T12El2mwAl", - "columnIds": [ - "lRREo8Fk9Tkbs54oI_Cdg" - ], - "x": 578.9474, - "y": 243.6316, - "direction": 2 - }, - "meta": { - "updateAt": 1758004206973, - "createAt": 1758004206973 - } - }, - "X4sknonb_IgA-_vhYKmss": { - "id": "X4sknonb_IgA-_vhYKmss", - "identification": false, - "relationshipType": 8, - "startRelationshipType": 2, - "start": { - "tableId": "rtTGV1n8fXrv3EOos4XcJ", - "columnIds": [ - "aNu4U_tr1NuWc674pipto" - ], - "x": 842.6559, - "y": 196.6438, - "direction": 1 - }, - "end": { - "tableId": "C70HRfoZAc7T12El2mwAl", - "columnIds": [ - "VThr2Y2U3_ZJAmivzYUhu" - ], - "x": 578.9474, - "y": 181.6316, - "direction": 2 - }, - "meta": { - "updateAt": 1758004221323, - "createAt": 1758004221323 - } - }, - "fi6hg4FJxXwO9G-Q4dkuQ": { - "id": "fi6hg4FJxXwO9G-Q4dkuQ", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "columnIds": [ - "F_CCSEveysTRYLn8lx8gE" - ], - "x": 1457.3773, - "y": 592.4335, - "direction": 1 - }, - "end": { - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "columnIds": [ - "6KXjwhh7zBv5U9ju-mYIk" - ], - "x": 1241.6559, - "y": 592.0608, - "direction": 2 - }, - "meta": { - "updateAt": 1758004261137, - "createAt": 1758004261137 - } - }, "vUfGlcmJ3e4oTKMnvlBzJ": { "id": "vUfGlcmJ3e4oTKMnvlBzJ", "identification": false, @@ -2120,17 +1873,17 @@ "columnIds": [ "vDFt6LsnU_OsODOI3QFtU" ], - "x": 486.7419, - "y": 486.4899, - "direction": 4 + "x": 663.9682, + "y": 699.0328, + "direction": 2 }, "end": { "tableId": "C70HRfoZAc7T12El2mwAl", "columnIds": [ "mO1A7j7Qok_C85BipXICi" ], - "x": 689.4692, - "y": 254.8081, + "x": 793.9093, + "y": 483.843, "direction": 1 }, "meta": { @@ -2148,8 +1901,8 @@ "columnIds": [ "aNu4U_tr1NuWc674pipto" ], - "x": 1246.7656, - "y": 255.1501, + "x": 1265.3757, + "y": 482.4087, "direction": 1 }, "end": { @@ -2157,8 +1910,8 @@ "columnIds": [ "TOi3d5nz-qA4ggbf5SGaA" ], - "x": 1054.4692, - "y": 254.8081, + "x": 1158.9093, + "y": 483.843, "direction": 2 }, "meta": { @@ -2176,8 +1929,8 @@ "columnIds": [ "F_CCSEveysTRYLn8lx8gE" ], - "x": 1246.1474, - "y": 623.642, + "x": 1285.0693, + "y": 805.9737, "direction": 1 }, "end": { @@ -2185,8 +1938,8 @@ "columnIds": [ "YxWKD6oE6Vx5FQS9ihF1j" ], - "x": 1108.7147, - "y": 628.0608, + "x": 1163.4637, + "y": 804.3929, "direction": 2 }, "meta": { @@ -2204,8 +1957,8 @@ "columnIds": [ "F_CCSEveysTRYLn8lx8gE" ], - "x": 1436.1474, - "y": 759.642, + "x": 1475.0693, + "y": 929.9737, "direction": 8 }, "end": { @@ -2213,8 +1966,8 @@ "columnIds": [ "kFwVTJyPh2e9OaCMgJwgf" ], - "x": 1254.8040999999998, - "y": 1052.9649, + "x": 1204.0704, + "y": 1175.7449, "direction": 2 }, "meta": { @@ -2232,8 +1985,8 @@ "columnIds": [ "5rnWTeGw4icmvmMekej_n" ], - "x": 889.8041, - "y": 1052.9649, + "x": 839.0704, + "y": 1175.7449, "direction": 1 }, "end": { @@ -2241,8 +1994,8 @@ "columnIds": [ "w4-iEtBZVv4oZMo29nEVr" ], - "x": 570.9873, - "y": 1037.228, + "x": 671.2629999999999, + "y": 1172.3362, "direction": 2 }, "meta": { @@ -2260,8 +2013,8 @@ "columnIds": [ "vDFt6LsnU_OsODOI3QFtU" ], - "x": 395.4919, - "y": 830.4899, + "x": 481.4682, + "y": 975.0328, "direction": 8 }, "end": { @@ -2269,8 +2022,8 @@ "columnIds": [ "qyv68yagM3C9_IGyT2VLt" ], - "x": 388.4873, - "y": 937.228, + "x": 488.763, + "y": 1072.3362, "direction": 4 }, "meta": { @@ -2278,65 +2031,138 @@ "createAt": 1758004517394 } }, - "onHzSgg1u3-Nk4tYVf7t0": { - "id": "onHzSgg1u3-Nk4tYVf7t0", + "zdTWn5Wpu4-atC3FVpk1E": { + "id": "zdTWn5Wpu4-atC3FVpk1E", "identification": false, - "relationshipType": 4, + "relationshipType": 8, + "startRelationshipType": 2, + "start": { + "tableId": "rtTGV1n8fXrv3EOos4XcJ", + "columnIds": [ + "aNu4U_tr1NuWc674pipto" + ], + "x": 1447.8757, + "y": 534.4087, + "direction": 8 + }, + "end": { + "tableId": "NA3wwYX9_yPbc5rR8NQP3", + "columnIds": [ + "GnAxf5fMaPNYtyzoiYMA-" + ], + "x": 1446.3018, + "y": 661.4258, + "direction": 4 + }, + "meta": { + "updateAt": 1758004959005, + "createAt": 1758004959005 + } + }, + "nfjgOevdJXMmtpcAEuJM0": { + "id": "nfjgOevdJXMmtpcAEuJM0", + "identification": false, + "relationshipType": 16, "startRelationshipType": 2, "start": { + "tableId": "yu3szoId7FctUvSa0xoTn", + "columnIds": [ + "Ad9Q86E6ce1GUaw49K9ni" + ], + "x": 400.0516, + "y": 338.969, + "direction": 2 + }, + "end": { "tableId": "2y1bvJOIG1e0BeEWgxI08", "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU" + "rgoW8fTWbtyd9QtgnCv4X" ], "x": 304.2419, "y": 486.4899, "direction": 4 }, + "meta": { + "updateAt": 1759712916893, + "createAt": 1759712916893 + } + }, + "wbLj5mUjPu5rltCDHj3XD": { + "id": "wbLj5mUjPu5rltCDHj3XD", + "identification": false, + "relationshipType": 16, + "startRelationshipType": 2, + "start": { + "tableId": "2y1bvJOIG1e0BeEWgxI08", + "columnIds": [ + "vDFt6LsnU_OsODOI3QFtU" + ], + "x": 481.4682, + "y": 607.0328, + "direction": 4 + }, "end": { - "tableId": "EPYnTEbnzHcSM-TV7Yogy", + "tableId": "yu3szoId7FctUvSa0xoTn", "columnIds": [ - "CCq1c0NyEngIoj0AErl8d" + "IJ-OWDU5a6JkkFcx_lY2a" ], - "x": 306.2208, - "y": 344.1056, + "x": 483.085, + "y": 491.9731, "direction": 8 }, "meta": { - "updateAt": 1758004886190, - "createAt": 1758004886190 + "updateAt": 1759712932112, + "createAt": 1759712932112 } }, - "zdTWn5Wpu4-atC3FVpk1E": { - "id": "zdTWn5Wpu4-atC3FVpk1E", + "8aesalFlcdiXVhsHAAd_f": { + "id": "8aesalFlcdiXVhsHAAd_f", "identification": false, - "relationshipType": 8, + "relationshipType": 16, "startRelationshipType": 2, "start": { - "tableId": "rtTGV1n8fXrv3EOos4XcJ", + "tableId": "zrNDU9R9OQONz9IYpCOQv", "columnIds": [ - "aNu4U_tr1NuWc674pipto" + "lzTP7Y9Q2wHxnor3iYbUN" ], - "x": 1429.2656, - "y": 307.1501, + "x": 494.7384, + "y": 260.6367, "direction": 8 }, "end": { - "tableId": "NA3wwYX9_yPbc5rR8NQP3", + "tableId": "yu3szoId7FctUvSa0xoTn", "columnIds": [ - "GnAxf5fMaPNYtyzoiYMA-" + "TgXJQ_3fDRKT5RxMLCCCW" ], - "x": 1436.1474, - "y": 487.642, + "x": 483.085, + "y": 363.9731, "direction": 4 }, "meta": { - "updateAt": 1758004959005, - "createAt": 1758004959005 + "updateAt": 1759712939785, + "createAt": 1759712939785 } } }, "indexEntities": {}, "indexColumnEntities": {}, - "memoEntities": {} + "memoEntities": { + "s-_sL_Y8zYQKmGll8eCR7": { + "id": "s-_sL_Y8zYQKmGll8eCR7", + "value": "", + "ui": { + "x": 196.90721649484536, + "y": 191.75257731958766, + "zIndex": 68, + "width": 116, + "height": 100, + "color": "" + }, + "meta": { + "updateAt": 1759712899185, + "createAt": 1759712899185 + } + } + } } } \ No newline at end of file From 7a641d73be73a0cc2ab76eb459baa2a7b88311ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EC=A4=80?= <72748734+HiLeeS@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:08:19 +0900 Subject: [PATCH 7/7] Delete week0/ERD.vuerd.json --- week0/ERD.vuerd.json | 2168 ------------------------------------------ 1 file changed, 2168 deletions(-) delete mode 100644 week0/ERD.vuerd.json diff --git a/week0/ERD.vuerd.json b/week0/ERD.vuerd.json deleted file mode 100644 index bf2867b..0000000 --- a/week0/ERD.vuerd.json +++ /dev/null @@ -1,2168 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/dineug/erd-editor/main/json-schema/schema.json", - "version": "3.0.0", - "settings": { - "width": 2000, - "height": 2000, - "scrollTop": -146.1667, - "scrollLeft": -46, - "zoomLevel": 1, - "show": 431, - "database": 4, - "databaseName": "", - "canvasType": "ERD", - "language": 1, - "tableNameCase": 4, - "columnNameCase": 2, - "bracketType": 1, - "relationshipDataTypeSync": true, - "relationshipOptimization": false, - "columnOrder": [ - 1, - 2, - 4, - 8, - 16, - 32, - 64 - ], - "maxWidthComment": -1, - "ignoreSaveSettings": 0 - }, - "doc": { - "tableIds": [ - "2y1bvJOIG1e0BeEWgxI08", - "rtTGV1n8fXrv3EOos4XcJ", - "C70HRfoZAc7T12El2mwAl", - "NA3wwYX9_yPbc5rR8NQP3", - "ETcc-k8p-2Xj7Avc_QuIL", - "YsXMe4aWI4vSU7M4Pdeny", - "ORir_zY3zWs8fj9eKIhij", - "zrNDU9R9OQONz9IYpCOQv", - "yu3szoId7FctUvSa0xoTn" - ], - "relationshipIds": [ - "fr8aQL5wJeCHd6nA3FkpV", - "vUfGlcmJ3e4oTKMnvlBzJ", - "SsosDuomeYItbtek60tL8", - "Dbft5I8MTyNYVBBE8bJi3", - "27fFwlvcry7s3zwMedMPL", - "mokzjvYQM38mTea-1naJe", - "leblF8kHmiRMhcnCVAceD", - "wbLj5mUjPu5rltCDHj3XD", - "8aesalFlcdiXVhsHAAd_f" - ], - "indexIds": [], - "memoIds": [] - }, - "collections": { - "tableEntities": { - "2y1bvJOIG1e0BeEWgxI08": { - "id": "2y1bvJOIG1e0BeEWgxI08", - "name": "member", - "comment": "사용자", - "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU", - "BfvVdK0SF5_S-F3PvFVzl", - "KpiXQMwL5ze-vJKrQlQ1V", - "CPEv0NYYbfZ99wRzuH59U", - "ONrE7jtU9NhI2LDhx3Eu5", - "oU52cpVBEP62Bd-YEUSBd", - "ZRG-tqrVHD7qvwbIsCxij", - "LDPp74sjuq_edOeSxvkCj", - "-gL9Tv6k4tzEhExARRMVF", - "rAo8blJvJWiSMdcXxPEQm", - "AdD_6uo7QsyR4vZ5mWieR", - "sbMtd5RQq7uaV0Cru8P_v", - "rgoW8fTWbtyd9QtgnCv4X" - ], - "seqColumnIds": [ - "WkqAgrjlXhLG2sEbIA5US", - "vDFt6LsnU_OsODOI3QFtU", - "BfvVdK0SF5_S-F3PvFVzl", - "KpiXQMwL5ze-vJKrQlQ1V", - "CPEv0NYYbfZ99wRzuH59U", - "ONrE7jtU9NhI2LDhx3Eu5", - "oU52cpVBEP62Bd-YEUSBd", - "ZRG-tqrVHD7qvwbIsCxij", - "LDPp74sjuq_edOeSxvkCj", - "-gL9Tv6k4tzEhExARRMVF", - "rAo8blJvJWiSMdcXxPEQm", - "AdD_6uo7QsyR4vZ5mWieR", - "sbMtd5RQq7uaV0Cru8P_v", - "rgoW8fTWbtyd9QtgnCv4X" - ], - "ui": { - "x": 298.9682, - "y": 607.0328, - "zIndex": 2, - "widthName": 60, - "widthComment": 60, - "color": "" - }, - "meta": { - "updateAt": 1759818994411, - "createAt": 1758002169271 - } - }, - "rtTGV1n8fXrv3EOos4XcJ": { - "id": "rtTGV1n8fXrv3EOos4XcJ", - "name": "interest", - "comment": "선호조사", - "columnIds": [ - "aNu4U_tr1NuWc674pipto", - "K_vOBQsbyMWekqQ_MEI4N" - ], - "seqColumnIds": [ - "aNu4U_tr1NuWc674pipto", - "K_vOBQsbyMWekqQ_MEI4N" - ], - "ui": { - "x": 1265.3757, - "y": 430.4087, - "zIndex": 10, - "widthName": 60, - "widthComment": 60, - "color": "" - }, - "meta": { - "updateAt": 1759818391682, - "createAt": 1758002208352 - } - }, - "C70HRfoZAc7T12El2mwAl": { - "id": "C70HRfoZAc7T12El2mwAl", - "name": "user_interest", - "comment": "유저_선호도", - "columnIds": [ - "ZjOGl86CJEvJ0RrhbbwU6", - "mO1A7j7Qok_C85BipXICi", - "TOi3d5nz-qA4ggbf5SGaA" - ], - "seqColumnIds": [ - "DTmy4dcbiGAdTi4A-XWI2", - "YMASBpKizoBjilyztmjJw", - "mHW9ecFk_GQMdjVjAyLpl", - "TuJoJOEFzpUIH-vMsLceS", - "ZjOGl86CJEvJ0RrhbbwU6", - "6yNKlUgOR6xxUcTHjIBha", - "ZOfk9HJZaFLK5-NEKO8vl", - "3Uwxxt6EGW-qJqorWfAJw", - "ZbsPFDxV-m07EPay0qcI2", - "lRREo8Fk9Tkbs54oI_Cdg", - "VThr2Y2U3_ZJAmivzYUhu", - "mO1A7j7Qok_C85BipXICi", - "TOi3d5nz-qA4ggbf5SGaA" - ], - "ui": { - "x": 793.9093, - "y": 419.843, - "zIndex": 11, - "widthName": 69, - "widthComment": 67, - "color": "" - }, - "meta": { - "updateAt": 1759818393286, - "createAt": 1758002209969 - } - }, - "NA3wwYX9_yPbc5rR8NQP3": { - "id": "NA3wwYX9_yPbc5rR8NQP3", - "name": "store", - "comment": "가게", - "columnIds": [ - "F_CCSEveysTRYLn8lx8gE", - "chq0SKqnzdsl00Sjku66M", - "CXpU5qG_eglJfOISVq81C", - "4Zf3gYPB2YGTzKHUoubEC", - "WAkzAlU4FeofJm5HCmtbA", - "Z8tbMfid3UrIRtl_5g6Gf", - "zBPannWM-vuszorqrrPRy", - "Uyl-wmz-YUPjS_-t71ciN" - ], - "seqColumnIds": [ - "F_CCSEveysTRYLn8lx8gE", - "V8nBlqc3TJAqAXnaYYz1C", - "GnAxf5fMaPNYtyzoiYMA-", - "chq0SKqnzdsl00Sjku66M", - "CXpU5qG_eglJfOISVq81C", - "4Zf3gYPB2YGTzKHUoubEC", - "WAkzAlU4FeofJm5HCmtbA", - "Z8tbMfid3UrIRtl_5g6Gf", - "zBPannWM-vuszorqrrPRy", - "Uyl-wmz-YUPjS_-t71ciN", - "uM2ODWrSWgyAfDgK5Acu0" - ], - "ui": { - "x": 1285.0693, - "y": 681.9737, - "zIndex": 12, - "widthName": 60, - "widthComment": 60, - "color": "" - }, - "meta": { - "updateAt": 1759818983111, - "createAt": 1758002211392 - } - }, - "ETcc-k8p-2Xj7Avc_QuIL": { - "id": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "review", - "comment": "리뷰", - "columnIds": [ - "PMYbggYiPE_sMz3U_2LqK", - "2JRKA_JcUA-Bcyt770hvg", - "YxWKD6oE6Vx5FQS9ihF1j", - "TADzLT5Iy1-DnwdSdWGW5", - "8riY_zkqWhXWBs1nJq-ov", - "RZ6HLhbxxbfiqm-zqJylb", - "iLB48NnJniXTBCzu9DLXn", - "cbAXCG_peFxJDjmzh-Q-8", - "z_xv-ZhRyFXARZdrqLhG8" - ], - "seqColumnIds": [ - "PMYbggYiPE_sMz3U_2LqK", - "2JRKA_JcUA-Bcyt770hvg", - "6QIpc602j9EoJGfHiqBDe", - "6HKr1XtX6o2r29AAttbG0", - "YxWKD6oE6Vx5FQS9ihF1j", - "TADzLT5Iy1-DnwdSdWGW5", - "8riY_zkqWhXWBs1nJq-ov", - "RZ6HLhbxxbfiqm-zqJylb", - "iLB48NnJniXTBCzu9DLXn", - "cbAXCG_peFxJDjmzh-Q-8", - "z_xv-ZhRyFXARZdrqLhG8", - "6KXjwhh7zBv5U9ju-mYIk" - ], - "ui": { - "x": 798.4637, - "y": 668.3929, - "zIndex": 13, - "widthName": 60, - "widthComment": 60, - "color": "" - }, - "meta": { - "updateAt": 1759818388503, - "createAt": 1758002211983 - } - }, - "YsXMe4aWI4vSU7M4Pdeny": { - "id": "YsXMe4aWI4vSU7M4Pdeny", - "name": "user_misson", - "comment": "유저+미션 정보", - "columnIds": [ - "w4-iEtBZVv4oZMo29nEVr", - "qyv68yagM3C9_IGyT2VLt", - "DpzdVYsCL9lkCfts-ehwz", - "p5gVywEZV25DrR5jz4fkH", - "P5y2uZFuvYjeM7xY-aY56", - "S2qqHB5cNDTVqitPQMpQ1" - ], - "seqColumnIds": [ - "w4-iEtBZVv4oZMo29nEVr", - "VEnb5JFzd_h3CPZ0KYP49", - "JtA1FPZRI3bkk9CFQzhXP", - "qyv68yagM3C9_IGyT2VLt", - "DpzdVYsCL9lkCfts-ehwz", - "p5gVywEZV25DrR5jz4fkH", - "P5y2uZFuvYjeM7xY-aY56", - "S2qqHB5cNDTVqitPQMpQ1" - ], - "ui": { - "x": 306.263, - "y": 1072.3362, - "zIndex": 14, - "widthName": 67, - "widthComment": 85, - "color": "" - }, - "meta": { - "updateAt": 1759818383231, - "createAt": 1758002212209 - } - }, - "ORir_zY3zWs8fj9eKIhij": { - "id": "ORir_zY3zWs8fj9eKIhij", - "name": "mission", - "comment": "미션", - "columnIds": [ - "5rnWTeGw4icmvmMekej_n", - "kFwVTJyPh2e9OaCMgJwgf", - "8hkYv9EPb5YN4pbtA3lAP", - "xpF9-6BHmY2hAjnGZtJIs", - "xLjxhMuIUPvpQGztC2-uP", - "ucsLuC5D65W0EisT2Jycw" - ], - "seqColumnIds": [ - "5rnWTeGw4icmvmMekej_n", - "kFwVTJyPh2e9OaCMgJwgf", - "MDJpiqCun3ipr8-5x2Y1j", - "8hkYv9EPb5YN4pbtA3lAP", - "KINewFTpc2Rbnmxv9IuPN", - "xpF9-6BHmY2hAjnGZtJIs", - "xLjxhMuIUPvpQGztC2-uP", - "ucsLuC5D65W0EisT2Jycw" - ], - "ui": { - "x": 839.0704, - "y": 1075.7449, - "zIndex": 15, - "widthName": 60, - "widthComment": 60, - "color": "" - }, - "meta": { - "updateAt": 1759818384505, - "createAt": 1758002213387 - } - }, - "zrNDU9R9OQONz9IYpCOQv": { - "id": "zrNDU9R9OQONz9IYpCOQv", - "name": "term", - "comment": "약관", - "columnIds": [ - "lzTP7Y9Q2wHxnor3iYbUN", - "n97RJkZ1d-qHS3OQ5IFWn" - ], - "seqColumnIds": [ - "lzTP7Y9Q2wHxnor3iYbUN", - "n97RJkZ1d-qHS3OQ5IFWn" - ], - "ui": { - "x": 312.2384, - "y": 156.6367, - "zIndex": 16, - "widthName": 60, - "widthComment": 60, - "color": "" - }, - "meta": { - "updateAt": 1759818397498, - "createAt": 1759711809275 - } - }, - "yu3szoId7FctUvSa0xoTn": { - "id": "yu3szoId7FctUvSa0xoTn", - "name": "User_term", - "comment": "유저약관", - "columnIds": [ - "Ad9Q86E6ce1GUaw49K9ni", - "IJ-OWDU5a6JkkFcx_lY2a", - "TgXJQ_3fDRKT5RxMLCCCW" - ], - "seqColumnIds": [ - "Ad9Q86E6ce1GUaw49K9ni", - "IJ-OWDU5a6JkkFcx_lY2a", - "TgXJQ_3fDRKT5RxMLCCCW" - ], - "ui": { - "x": 300.585, - "y": 363.9731, - "zIndex": 61, - "widthName": 60, - "widthComment": 60, - "color": "" - }, - "meta": { - "updateAt": 1759818395578, - "createAt": 1759711945588 - } - } - }, - "tableColumnEntities": { - "vDFt6LsnU_OsODOI3QFtU": { - "id": "vDFt6LsnU_OsODOI3QFtU", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002565024, - "createAt": 1758002176062 - } - }, - "BfvVdK0SF5_S-F3PvFVzl": { - "id": "BfvVdK0SF5_S-F3PvFVzl", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "name", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002411607, - "createAt": 1758002176997 - } - }, - "KpiXQMwL5ze-vJKrQlQ1V": { - "id": "KpiXQMwL5ze-vJKrQlQ1V", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "gender", - "comment": "", - "dataType": "INT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1759819677323, - "createAt": 1758002177165 - } - }, - "CPEv0NYYbfZ99wRzuH59U": { - "id": "CPEv0NYYbfZ99wRzuH59U", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "birthday", - "comment": "", - "dataType": "DATE", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002434300, - "createAt": 1758002177388 - } - }, - "ONrE7jtU9NhI2LDhx3Eu5": { - "id": "ONrE7jtU9NhI2LDhx3Eu5", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "adress", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002451752, - "createAt": 1758002276724 - } - }, - "oU52cpVBEP62Bd-YEUSBd": { - "id": "oU52cpVBEP62Bd-YEUSBd", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "email", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002471108, - "createAt": 1758002328551 - } - }, - "ZRG-tqrVHD7qvwbIsCxij": { - "id": "ZRG-tqrVHD7qvwbIsCxij", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "password", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002464744, - "createAt": 1758002332815 - } - }, - "LDPp74sjuq_edOeSxvkCj": { - "id": "LDPp74sjuq_edOeSxvkCj", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "phone", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002474331, - "createAt": 1758002333325 - } - }, - "-gL9Tv6k4tzEhExARRMVF": { - "id": "-gL9Tv6k4tzEhExARRMVF", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "point", - "comment": "", - "dataType": "int", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002477308, - "createAt": 1758002348699 - } - }, - "rAo8blJvJWiSMdcXxPEQm": { - "id": "rAo8blJvJWiSMdcXxPEQm", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "createAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002483210, - "createAt": 1758002348910 - } - }, - "AdD_6uo7QsyR4vZ5mWieR": { - "id": "AdD_6uo7QsyR4vZ5mWieR", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "upateAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002487099, - "createAt": 1758002386257 - } - }, - "sbMtd5RQq7uaV0Cru8P_v": { - "id": "sbMtd5RQq7uaV0Cru8P_v", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "status", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002609142, - "createAt": 1758002386845 - } - }, - "MDJpiqCun3ipr8-5x2Y1j": { - "id": "MDJpiqCun3ipr8-5x2Y1j", - "tableId": "ORir_zY3zWs8fj9eKIhij", - "name": "store_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002553538, - "createAt": 1758002518872 - } - }, - "8hkYv9EPb5YN4pbtA3lAP": { - "id": "8hkYv9EPb5YN4pbtA3lAP", - "tableId": "ORir_zY3zWs8fj9eKIhij", - "name": "point", - "comment": "", - "dataType": "int", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002614654, - "createAt": 1758002520501 - } - }, - "xpF9-6BHmY2hAjnGZtJIs": { - "id": "xpF9-6BHmY2hAjnGZtJIs", - "tableId": "ORir_zY3zWs8fj9eKIhij", - "name": "createAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002586510, - "createAt": 1758002527502 - } - }, - "xLjxhMuIUPvpQGztC2-uP": { - "id": "xLjxhMuIUPvpQGztC2-uP", - "tableId": "ORir_zY3zWs8fj9eKIhij", - "name": "upateAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002590031, - "createAt": 1758002527844 - } - }, - "ucsLuC5D65W0EisT2Jycw": { - "id": "ucsLuC5D65W0EisT2Jycw", - "tableId": "ORir_zY3zWs8fj9eKIhij", - "name": "status", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002621934, - "createAt": 1758002528147 - } - }, - "VEnb5JFzd_h3CPZ0KYP49": { - "id": "VEnb5JFzd_h3CPZ0KYP49", - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "name": "user_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002675364, - "createAt": 1758002647784 - } - }, - "JtA1FPZRI3bkk9CFQzhXP": { - "id": "JtA1FPZRI3bkk9CFQzhXP", - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "name": "mission_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002760013, - "createAt": 1758002648236 - } - }, - "P5y2uZFuvYjeM7xY-aY56": { - "id": "P5y2uZFuvYjeM7xY-aY56", - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "name": "upateAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002802948, - "createAt": 1758002654537 - } - }, - "p5gVywEZV25DrR5jz4fkH": { - "id": "p5gVywEZV25DrR5jz4fkH", - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "name": "createAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002795917, - "createAt": 1758002656058 - } - }, - "5rnWTeGw4icmvmMekej_n": { - "id": "5rnWTeGw4icmvmMekej_n", - "tableId": "ORir_zY3zWs8fj9eKIhij", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003598435, - "createAt": 1758002688468 - } - }, - "S2qqHB5cNDTVqitPQMpQ1": { - "id": "S2qqHB5cNDTVqitPQMpQ1", - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "name": "status", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002798902, - "createAt": 1758002792542 - } - }, - "PMYbggYiPE_sMz3U_2LqK": { - "id": "PMYbggYiPE_sMz3U_2LqK", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003592824, - "createAt": 1758002822923 - } - }, - "6HKr1XtX6o2r29AAttbG0": { - "id": "6HKr1XtX6o2r29AAttbG0", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "store_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002851602, - "createAt": 1758002834332 - } - }, - "TADzLT5Iy1-DnwdSdWGW5": { - "id": "TADzLT5Iy1-DnwdSdWGW5", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "star", - "comment": "", - "dataType": "FLOAT", - "default": "0", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002870541, - "createAt": 1758002852579 - } - }, - "8riY_zkqWhXWBs1nJq-ov": { - "id": "8riY_zkqWhXWBs1nJq-ov", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "content", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002885701, - "createAt": 1758002874603 - } - }, - "RZ6HLhbxxbfiqm-zqJylb": { - "id": "RZ6HLhbxxbfiqm-zqJylb", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "images", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002922594, - "createAt": 1758002889030 - } - }, - "iLB48NnJniXTBCzu9DLXn": { - "id": "iLB48NnJniXTBCzu9DLXn", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "createAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002934078, - "createAt": 1758002923693 - } - }, - "cbAXCG_peFxJDjmzh-Q-8": { - "id": "cbAXCG_peFxJDjmzh-Q-8", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "updatedAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002941910, - "createAt": 1758002935672 - } - }, - "z_xv-ZhRyFXARZdrqLhG8": { - "id": "z_xv-ZhRyFXARZdrqLhG8", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "status", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758002953050, - "createAt": 1758002943155 - } - }, - "F_CCSEveysTRYLn8lx8gE": { - "id": "F_CCSEveysTRYLn8lx8gE", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003595545, - "createAt": 1758002973996 - } - }, - "chq0SKqnzdsl00Sjku66M": { - "id": "chq0SKqnzdsl00Sjku66M", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "name", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003009284, - "createAt": 1758003002273 - } - }, - "CXpU5qG_eglJfOISVq81C": { - "id": "CXpU5qG_eglJfOISVq81C", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "address", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003029776, - "createAt": 1758003011207 - } - }, - "4Zf3gYPB2YGTzKHUoubEC": { - "id": "4Zf3gYPB2YGTzKHUoubEC", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "boss", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003042039, - "createAt": 1758003031164 - } - }, - "WAkzAlU4FeofJm5HCmtbA": { - "id": "WAkzAlU4FeofJm5HCmtbA", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "store_number", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 75, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003058857, - "createAt": 1758003044580 - } - }, - "Z8tbMfid3UrIRtl_5g6Gf": { - "id": "Z8tbMfid3UrIRtl_5g6Gf", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "createdAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003067406, - "createAt": 1758003060401 - } - }, - "zBPannWM-vuszorqrrPRy": { - "id": "zBPannWM-vuszorqrrPRy", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "updatedAt", - "comment": "", - "dataType": "DATETIME", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003077323, - "createAt": 1758003068601 - } - }, - "Uyl-wmz-YUPjS_-t71ciN": { - "id": "Uyl-wmz-YUPjS_-t71ciN", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "status", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003084382, - "createAt": 1758003078444 - } - }, - "YMASBpKizoBjilyztmjJw": { - "id": "YMASBpKizoBjilyztmjJw", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "user_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003283691, - "createAt": 1758003272191 - } - }, - "TuJoJOEFzpUIH-vMsLceS": { - "id": "TuJoJOEFzpUIH-vMsLceS", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "interest_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003294806, - "createAt": 1758003284595 - } - }, - "ZjOGl86CJEvJ0RrhbbwU6": { - "id": "ZjOGl86CJEvJ0RrhbbwU6", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "", - "comment": "", - "dataType": "", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003295578, - "createAt": 1758003295578 - } - }, - "aNu4U_tr1NuWc674pipto": { - "id": "aNu4U_tr1NuWc674pipto", - "tableId": "rtTGV1n8fXrv3EOos4XcJ", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003590493, - "createAt": 1758003330679 - } - }, - "K_vOBQsbyMWekqQ_MEI4N": { - "id": "K_vOBQsbyMWekqQ_MEI4N", - "tableId": "rtTGV1n8fXrv3EOos4XcJ", - "name": "name", - "comment": "", - "dataType": "VARCHAR", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003368416, - "createAt": 1758003357168 - } - }, - "KINewFTpc2Rbnmxv9IuPN": { - "id": "KINewFTpc2Rbnmxv9IuPN", - "tableId": "ORir_zY3zWs8fj9eKIhij", - "name": "deadLine", - "comment": "", - "dataType": "INT", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003461287, - "createAt": 1758003449850 - } - }, - "6QIpc602j9EoJGfHiqBDe": { - "id": "6QIpc602j9EoJGfHiqBDe", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "user_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003558685, - "createAt": 1758003542692 - } - }, - "DpzdVYsCL9lkCfts-ehwz": { - "id": "DpzdVYsCL9lkCfts-ehwz", - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "name": "deadLine", - "comment": "", - "dataType": "INT", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003574822, - "createAt": 1758003574821 - } - }, - "V8nBlqc3TJAqAXnaYYz1C": { - "id": "V8nBlqc3TJAqAXnaYYz1C", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "categori_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003691494, - "createAt": 1758003673432 - } - }, - "6yNKlUgOR6xxUcTHjIBha": { - "id": "6yNKlUgOR6xxUcTHjIBha", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "", - "comment": "", - "dataType": "", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003706143, - "createAt": 1758003706143 - } - }, - "ZOfk9HJZaFLK5-NEKO8vl": { - "id": "ZOfk9HJZaFLK5-NEKO8vl", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003750071, - "createAt": 1758003750070 - } - }, - "3Uwxxt6EGW-qJqorWfAJw": { - "id": "3Uwxxt6EGW-qJqorWfAJw", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "", - "comment": "", - "dataType": "", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003866240, - "createAt": 1758003866240 - } - }, - "WkqAgrjlXhLG2sEbIA5US": { - "id": "WkqAgrjlXhLG2sEbIA5US", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "", - "comment": "", - "dataType": "", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003867276, - "createAt": 1758003867276 - } - }, - "DTmy4dcbiGAdTi4A-XWI2": { - "id": "DTmy4dcbiGAdTi4A-XWI2", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "user_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003910732, - "createAt": 1758003899738 - } - }, - "mHW9ecFk_GQMdjVjAyLpl": { - "id": "mHW9ecFk_GQMdjVjAyLpl", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "interset_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758003982598, - "createAt": 1758003967414 - } - }, - "2JRKA_JcUA-Bcyt770hvg": { - "id": "2JRKA_JcUA-Bcyt770hvg", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "user_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004080945, - "createAt": 1758004034426 - } - }, - "uM2ODWrSWgyAfDgK5Acu0": { - "id": "uM2ODWrSWgyAfDgK5Acu0", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004056510, - "createAt": 1758004056509 - } - }, - "ZbsPFDxV-m07EPay0qcI2": { - "id": "ZbsPFDxV-m07EPay0qcI2", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004190658, - "createAt": 1758004190658 - } - }, - "lRREo8Fk9Tkbs54oI_Cdg": { - "id": "lRREo8Fk9Tkbs54oI_Cdg", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004206973, - "createAt": 1758004206973 - } - }, - "VThr2Y2U3_ZJAmivzYUhu": { - "id": "VThr2Y2U3_ZJAmivzYUhu", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004221323, - "createAt": 1758004221323 - } - }, - "6KXjwhh7zBv5U9ju-mYIk": { - "id": "6KXjwhh7zBv5U9ju-mYIk", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004261136, - "createAt": 1758004261136 - } - }, - "mO1A7j7Qok_C85BipXICi": { - "id": "mO1A7j7Qok_C85BipXICi", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "user_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004527788, - "createAt": 1758004410855 - } - }, - "TOi3d5nz-qA4ggbf5SGaA": { - "id": "TOi3d5nz-qA4ggbf5SGaA", - "tableId": "C70HRfoZAc7T12El2mwAl", - "name": "interest_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004538380, - "createAt": 1758004421840 - } - }, - "YxWKD6oE6Vx5FQS9ihF1j": { - "id": "YxWKD6oE6Vx5FQS9ihF1j", - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "name": "store_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004551595, - "createAt": 1758004441852 - } - }, - "kFwVTJyPh2e9OaCMgJwgf": { - "id": "kFwVTJyPh2e9OaCMgJwgf", - "tableId": "ORir_zY3zWs8fj9eKIhij", - "name": "sotre_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004563363, - "createAt": 1758004489596 - } - }, - "w4-iEtBZVv4oZMo29nEVr": { - "id": "w4-iEtBZVv4oZMo29nEVr", - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "name": "user_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004573431, - "createAt": 1758004509769 - } - }, - "qyv68yagM3C9_IGyT2VLt": { - "id": "qyv68yagM3C9_IGyT2VLt", - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "name": "mission_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004578883, - "createAt": 1758004517394 - } - }, - "GnAxf5fMaPNYtyzoiYMA-": { - "id": "GnAxf5fMaPNYtyzoiYMA-", - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "name": "categori_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1758004970506, - "createAt": 1758004959005 - } - }, - "n97RJkZ1d-qHS3OQ5IFWn": { - "id": "n97RJkZ1d-qHS3OQ5IFWn", - "tableId": "zrNDU9R9OQONz9IYpCOQv", - "name": "name", - "comment": "", - "dataType": "ENUM", - "default": "", - "options": 0, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1759711854656, - "createAt": 1759711822863 - } - }, - "lzTP7Y9Q2wHxnor3iYbUN": { - "id": "lzTP7Y9Q2wHxnor3iYbUN", - "tableId": "zrNDU9R9OQONz9IYpCOQv", - "name": "term_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1759712966327, - "createAt": 1759711868594 - } - }, - "Ad9Q86E6ce1GUaw49K9ni": { - "id": "Ad9Q86E6ce1GUaw49K9ni", - "tableId": "yu3szoId7FctUvSa0xoTn", - "name": "", - "comment": "", - "dataType": "", - "default": "", - "options": 10, - "ui": { - "keys": 1, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1759712914169, - "createAt": 1759712914169 - } - }, - "rgoW8fTWbtyd9QtgnCv4X": { - "id": "rgoW8fTWbtyd9QtgnCv4X", - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "name": "", - "comment": "", - "dataType": "", - "default": "", - "options": 8, - "ui": { - "keys": 0, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1759712916893, - "createAt": 1759712916893 - } - }, - "IJ-OWDU5a6JkkFcx_lY2a": { - "id": "IJ-OWDU5a6JkkFcx_lY2a", - "tableId": "yu3szoId7FctUvSa0xoTn", - "name": "user_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1759712959800, - "createAt": 1759712932112 - } - }, - "TgXJQ_3fDRKT5RxMLCCCW": { - "id": "TgXJQ_3fDRKT5RxMLCCCW", - "tableId": "yu3szoId7FctUvSa0xoTn", - "name": "term_id", - "comment": "", - "dataType": "BIGINT", - "default": "", - "options": 8, - "ui": { - "keys": 2, - "widthName": 60, - "widthComment": 60, - "widthDataType": 60, - "widthDefault": 60 - }, - "meta": { - "updateAt": 1759712966327, - "createAt": 1759712939784 - } - } - }, - "relationshipEntities": { - "fr8aQL5wJeCHd6nA3FkpV": { - "id": "fr8aQL5wJeCHd6nA3FkpV", - "identification": false, - "relationshipType": 4, - "startRelationshipType": 2, - "start": { - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU" - ], - "x": 663.9682, - "y": 883.0328, - "direction": 2 - }, - "end": { - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "columnIds": [ - "2JRKA_JcUA-Bcyt770hvg" - ], - "x": 798.4637, - "y": 804.3929, - "direction": 1 - }, - "meta": { - "updateAt": 1758004034426, - "createAt": 1758004034426 - } - }, - "vUfGlcmJ3e4oTKMnvlBzJ": { - "id": "vUfGlcmJ3e4oTKMnvlBzJ", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU" - ], - "x": 663.9682, - "y": 699.0328, - "direction": 2 - }, - "end": { - "tableId": "C70HRfoZAc7T12El2mwAl", - "columnIds": [ - "mO1A7j7Qok_C85BipXICi" - ], - "x": 793.9093, - "y": 483.843, - "direction": 1 - }, - "meta": { - "updateAt": 1758004410855, - "createAt": 1758004410855 - } - }, - "SsosDuomeYItbtek60tL8": { - "id": "SsosDuomeYItbtek60tL8", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "rtTGV1n8fXrv3EOos4XcJ", - "columnIds": [ - "aNu4U_tr1NuWc674pipto" - ], - "x": 1265.3757, - "y": 482.4087, - "direction": 1 - }, - "end": { - "tableId": "C70HRfoZAc7T12El2mwAl", - "columnIds": [ - "TOi3d5nz-qA4ggbf5SGaA" - ], - "x": 1158.9093, - "y": 483.843, - "direction": 2 - }, - "meta": { - "updateAt": 1758004421840, - "createAt": 1758004421840 - } - }, - "Dbft5I8MTyNYVBBE8bJi3": { - "id": "Dbft5I8MTyNYVBBE8bJi3", - "identification": false, - "relationshipType": 4, - "startRelationshipType": 2, - "start": { - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "columnIds": [ - "F_CCSEveysTRYLn8lx8gE" - ], - "x": 1285.0693, - "y": 805.9737, - "direction": 1 - }, - "end": { - "tableId": "ETcc-k8p-2Xj7Avc_QuIL", - "columnIds": [ - "YxWKD6oE6Vx5FQS9ihF1j" - ], - "x": 1163.4637, - "y": 804.3929, - "direction": 2 - }, - "meta": { - "updateAt": 1758004441852, - "createAt": 1758004441852 - } - }, - "27fFwlvcry7s3zwMedMPL": { - "id": "27fFwlvcry7s3zwMedMPL", - "identification": false, - "relationshipType": 4, - "startRelationshipType": 2, - "start": { - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "columnIds": [ - "F_CCSEveysTRYLn8lx8gE" - ], - "x": 1475.0693, - "y": 929.9737, - "direction": 8 - }, - "end": { - "tableId": "ORir_zY3zWs8fj9eKIhij", - "columnIds": [ - "kFwVTJyPh2e9OaCMgJwgf" - ], - "x": 1204.0704, - "y": 1175.7449, - "direction": 2 - }, - "meta": { - "updateAt": 1758004489596, - "createAt": 1758004489596 - } - }, - "mokzjvYQM38mTea-1naJe": { - "id": "mokzjvYQM38mTea-1naJe", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "ORir_zY3zWs8fj9eKIhij", - "columnIds": [ - "5rnWTeGw4icmvmMekej_n" - ], - "x": 839.0704, - "y": 1175.7449, - "direction": 1 - }, - "end": { - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "columnIds": [ - "w4-iEtBZVv4oZMo29nEVr" - ], - "x": 671.2629999999999, - "y": 1172.3362, - "direction": 2 - }, - "meta": { - "updateAt": 1758004509769, - "createAt": 1758004509769 - } - }, - "leblF8kHmiRMhcnCVAceD": { - "id": "leblF8kHmiRMhcnCVAceD", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU" - ], - "x": 481.4682, - "y": 975.0328, - "direction": 8 - }, - "end": { - "tableId": "YsXMe4aWI4vSU7M4Pdeny", - "columnIds": [ - "qyv68yagM3C9_IGyT2VLt" - ], - "x": 488.763, - "y": 1072.3362, - "direction": 4 - }, - "meta": { - "updateAt": 1758004517394, - "createAt": 1758004517394 - } - }, - "zdTWn5Wpu4-atC3FVpk1E": { - "id": "zdTWn5Wpu4-atC3FVpk1E", - "identification": false, - "relationshipType": 8, - "startRelationshipType": 2, - "start": { - "tableId": "rtTGV1n8fXrv3EOos4XcJ", - "columnIds": [ - "aNu4U_tr1NuWc674pipto" - ], - "x": 1447.8757, - "y": 534.4087, - "direction": 8 - }, - "end": { - "tableId": "NA3wwYX9_yPbc5rR8NQP3", - "columnIds": [ - "GnAxf5fMaPNYtyzoiYMA-" - ], - "x": 1446.3018, - "y": 661.4258, - "direction": 4 - }, - "meta": { - "updateAt": 1758004959005, - "createAt": 1758004959005 - } - }, - "nfjgOevdJXMmtpcAEuJM0": { - "id": "nfjgOevdJXMmtpcAEuJM0", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "yu3szoId7FctUvSa0xoTn", - "columnIds": [ - "Ad9Q86E6ce1GUaw49K9ni" - ], - "x": 400.0516, - "y": 338.969, - "direction": 2 - }, - "end": { - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "columnIds": [ - "rgoW8fTWbtyd9QtgnCv4X" - ], - "x": 304.2419, - "y": 486.4899, - "direction": 4 - }, - "meta": { - "updateAt": 1759712916893, - "createAt": 1759712916893 - } - }, - "wbLj5mUjPu5rltCDHj3XD": { - "id": "wbLj5mUjPu5rltCDHj3XD", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "2y1bvJOIG1e0BeEWgxI08", - "columnIds": [ - "vDFt6LsnU_OsODOI3QFtU" - ], - "x": 481.4682, - "y": 607.0328, - "direction": 4 - }, - "end": { - "tableId": "yu3szoId7FctUvSa0xoTn", - "columnIds": [ - "IJ-OWDU5a6JkkFcx_lY2a" - ], - "x": 483.085, - "y": 491.9731, - "direction": 8 - }, - "meta": { - "updateAt": 1759712932112, - "createAt": 1759712932112 - } - }, - "8aesalFlcdiXVhsHAAd_f": { - "id": "8aesalFlcdiXVhsHAAd_f", - "identification": false, - "relationshipType": 16, - "startRelationshipType": 2, - "start": { - "tableId": "zrNDU9R9OQONz9IYpCOQv", - "columnIds": [ - "lzTP7Y9Q2wHxnor3iYbUN" - ], - "x": 494.7384, - "y": 260.6367, - "direction": 8 - }, - "end": { - "tableId": "yu3szoId7FctUvSa0xoTn", - "columnIds": [ - "TgXJQ_3fDRKT5RxMLCCCW" - ], - "x": 483.085, - "y": 363.9731, - "direction": 4 - }, - "meta": { - "updateAt": 1759712939785, - "createAt": 1759712939785 - } - } - }, - "indexEntities": {}, - "indexColumnEntities": {}, - "memoEntities": { - "s-_sL_Y8zYQKmGll8eCR7": { - "id": "s-_sL_Y8zYQKmGll8eCR7", - "value": "", - "ui": { - "x": 196.90721649484536, - "y": 191.75257731958766, - "zIndex": 68, - "width": 116, - "height": 100, - "color": "" - }, - "meta": { - "updateAt": 1759712899185, - "createAt": 1759712899185 - } - } - } - } -} \ No newline at end of file