Skip to content

[FEAT] ERDCloud SQL → JPA 엔터티 변환 및 프로젝트 구조 정리 #13

@millkk04

Description

@millkk04

BookLog 엔터티 구조 설계 및 구현 완료 보고서

작업 결과: 29개 엔터티 + 10개 Enum 생성 완료 (총 39개 파일)


1. 생성된 엔터티 목록

1. users 도메인 (4개 엔터티 + 2개 Enum)

엔터티 파일명 책임 주요 필드
Users Users.java 사용자 기본 정보 id, nickname, profileImageUrl, status
AuthAccounts AuthAccounts.java 소셜 로그인 계정 id, userId, provider, providerId
UserSettings UserSettings.java 사용자 설정 (1:1) userId, isShelfPublic, isPostPublic
UserFollows UserFollows.java 팔로우 관계 (복합키) followerId, followeeId, followedAt

Enum 타입:

  • UserStatus.java: ACTIVE / INACTIVE / DELETED
  • AuthProvider.java: GOOGLE / NAVER / KAKAO / LOCAL

2. library.books 도메인 (7개 엔터티 + 2개 Enum)

엔터티 파일명 책임 주요 필드
Books Books.java 도서 메타 정보 (외부 API 캐싱) id, title, isbn13, publisherId, source, rawData
Authors Authors.java 작가 정보 id, name, biography, wikidataId
BookAuthors BookAuthors.java 도서-작가 매핑 (복합키) bookId, authorId, role, displayOrder
AuthorAwards AuthorAwards.java 작가 수상 이력 id, authorId, awardName, year
Genres Genres.java 장르 마스터 id, name
BookGenres BookGenres.java 도서-장르 매핑 (복합키) bookId, genreId
Publishers Publishers.java 출판사 id, name

Enum 타입:

  • BookSource.java: KAKAO / NAVER / ALADIN / MANUAL
  • AuthorRole.java: AUTHOR / TRANSLATOR

3. library.shelves 도메인 (4개 엔터티 + 2개 Enum)

엔터티 파일명 책임 주요 필드
UserBooks UserBooks.java 핵심! 사용자별 독서 기록 id, userId, bookId, status, progress
Shelves Shelves.java 서재/폴더 id, userId, name, isPublic
ShelfBooks ShelfBooks.java 서재-도서 매핑 (복합키) shelfId, userBookId, addedAt
ReadingLogs ReadingLogs.java 일별 독서 기록 id, userBookId, logDate, pagesRead

Enum 타입:

  • ReadingStatus.java: PLANNING / READING / COMPLETED / STOPPED
  • MediaType.java: PAPER / EBOOK / AUDIO

4. tags 도메인 (2개 엔터티 + 1개 Enum)

엔터티 파일명 책임 주요 필드
Tags Tags.java 태그 마스터 (분위기/문체/몰입도) id, category, name
BookTags BookTags.java 도서-태그 매핑 (복합키) userBookId, tagId

Enum 타입:

  • TagCategory.java: MOOD / STYLE / IMMERSION

5. posts 도메인 (6개 엔터티 + 1개 Enum)

엔터티 파일명 책임 주요 필드
Posts Posts.java 북로그 게시글 id, userId, userBookId, status, content
PostImages PostImages.java 게시글 이미지 id, postId, imageUrl, displayOrder
Comments Comments.java 댓글 (대댓글 지원) id, postId, userId, parentCommentId
PostLikes PostLikes.java 좋아요 (복합키) postId, userId, likedAt
PostBookmarks PostBookmarks.java 북마크 (복합키) postId, userId, bookmarkedAt
PostViews PostViews.java 조회수 추적 id, postId, userId, sessionId

Enum 타입:

  • PostStatus.java: DRAFT / PUBLISHED

6. onboarding 도메인 (4개 엔터티 + 1개 Enum)

엔터티 파일명 책임 주요 필드
OnboardingQuestions OnboardingQuestions.java 온보딩 질문 id, questionKey, questionType
OnboardingOptions OnboardingOptions.java 온보딩 선택지 id, questionId, optionKey, label
UserOnboardingAnswers UserOnboardingAnswers.java 사용자 답변 (복합키) userId, questionId, optionId
UserOnboardingStatus UserOnboardingStatus.java 온보딩 완료 상태 (1:1) userId, isCompleted, isSkipped

Enum 타입:

  • QuestionType.java: SINGLE / MULTI

7. ai 도메인 (1개 엔터티)

엔터티 파일명 책임 주요 필드
AiBookInsights AiBookInsights.java AI 기반 도서 인사이트 id, userId, userBookId, insightType

8. search 도메인 (1개 엔터티)

엔터티 파일명 책임 주요 필드
SearchHistory SearchHistory.java 최근 검색어 (선택적) id, userId, keyword, searchedAt

참고: 프론트엔드 localStorage로 처리 검토 대상


2. 기존 디렉토리 구조 변경 사항

📁 변경 전 (기존 구조)

domain/library/books/entity/
├── common/
│   ├── Authors.java
│   ├── AuthorRole.java
│   ├── AuthorRewards.java
│   └── Genres.java
└── mapping/
    └── BookAuthors.java

📁 변경 후 (신규 구조)

domain/library/books/entity/
├── Books.java
├── BookSource.java
├── Authors.java
├── AuthorRole.java
├── AuthorAwards.java        ← AuthorRewards에서 이름 변경
├── BookAuthors.java         ← mapping에서 이동
├── Genres.java
├── BookGenres.java
└── Publishers.java

변경 이유

  1. 패키지 구조 단순화

    • common/, mapping/ 서브 패키지 제거
    • 모든 엔터티를 entity/ 직접 하위에 배치
    • import 경로 단순화: entity.common.Authorsentity.Authors
  2. ERD 명명 규칙 통일

    • ERD에서 author_awardsAuthorAwards (일관성)
    • 기존 AuthorRewards에서 변경
  3. 도메인별 분리 명확화

    • library.books: 도서 메타데이터 관련
    • library.shelves: 사용자 독서 기록 관련
    • tags: 태그 관련 (별도 도메인)

3. 수정된 파일 목록 및 이유

🔧 신규 생성 엔터티 (29개)

모든 엔터티는 ERDCloud SQL을 기반으로 JPA 엔터티로 변환하여 새로 생성되었습니다.


🔧 기존 파일 수정 (7개)

1. Books.java

수정 이유: 기존 서비스와 호환성 유지

// 추가된 필드
@Column(name = "publisher_name", length = 255)
private String publisherName;

@OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
private List<BookAuthors> bookAuthors = new ArrayList<>();

// 추가된 메서드
public LocalDateTime getPublishedAt() {
    return this.publishedDate;
}

public void updateBasicInfo(...)  // BookImportService 호환
public void replaceBookAuthors(...) // BookAuthors 관리

변경 내용:

  • publisherName 필드 추가 (BookSearchConverter 호환)
  • bookAuthors 양방향 관계 추가
  • getPublishedAt() getter 추가
  • updateBasicInfo(), replaceBookAuthors() 비즈니스 메서드 추가

2. Authors.java

수정 이유: Wikidata 연동 기능 지원

// 추가된 필드
@Column(name = "wikidata_id", length = 20)
private String wikidataId;

@Column(name = "wikidata_raw_json", columnDefinition = "TEXT")
private String wikidataRawJson;

// 추가된 메서드
public boolean hasWikidataId() { ... }
public void applyWikidataEnrichment(AuthorWikidataEnrichment enrichment) { ... }
public static Authors ofName(String name) { ... }

변경 내용:

  • Wikidata 관련 필드 추가 (작가 정보 자동 보강)
  • 정적 팩토리 메서드 추가
  • 메타데이터 적용 메서드 추가

3. BookAuthors.java

수정 이유: 새로운 엔터티 구조로 재작성

// 위치 변경: entity/mapping/ → entity/
// 복합키 전략: @EmbeddedId → @IdClass

@IdClass(BookAuthors.BookAuthorId.class)
public class BookAuthors {
    @Id private Long bookId;
    @Id private Long authorId;
    @Id private AuthorRole role;
    
    // 양방향 관계 지원
    public void setBook(Books book) { ... }
}

변경 내용:

  • 복합키 구조 변경 (기존 단일 ID → 복합키)
  • Books와 양방향 관계 설정
  • displayOrder 필드 추가 (정렬 순서)

4. BooksRepository.java

수정 이유: 필드명 변경 반영

// 변경 전
Optional<Books> findByKakaoUrl(String kakaoUrl);

// 변경 후
Optional<Books> findByDetailUrl(String detailUrl);

변경 내용:

  • Books 엔터티 필드명에 맞게 수정 (kakaoUrldetailUrl)

5. AuthorsRepository.java

수정 이유: import 경로 수정

// 변경 전
import com.example.booklog.domain.library.books.entity.common.Authors;

// 변경 후
import com.example.booklog.domain.library.books.entity.Authors;

변경 내용:

  • 패키지 구조 변경에 따른 import 경로 수정

6. GenresRepository.java

수정 이유: import 경로 수정

// 변경 전
import com.example.booklog.domain.library.books.entity.common.Genres;

// 변경 후
import com.example.booklog.domain.library.books.entity.Genres;

7. AuthorRewardRepository.java

수정 이유: 엔터티명 변경 및 메서드 수정

// 변경 전
import com.example.booklog.domain.library.books.entity.common.AuthorRewards;
public interface AuthorRewardRepository extends JpaRepository<AuthorRewards, Long> {
    List<AuthorRewards> findAllByAuthor_AuthorId(Long authorId);
}

// 변경 후
import com.example.booklog.domain.library.books.entity.AuthorAwards;
public interface AuthorRewardRepository extends JpaRepository<AuthorAwards, Long> {
    List<AuthorAwards> findAllByAuthor_Id(Long authorId);
}

변경 내용:

  • AuthorRewardsAuthorAwards (ERD 통일)
  • 연관관계 메서드명 수정 (Author_AuthorIdAuthor_Id)

8. BookImportService.java

수정 이유: 새 엔터티 구조 반영

// import 경로 수정
import com.example.booklog.domain.library.books.entity.BookSource;
import com.example.booklog.domain.library.books.entity.AuthorRole;
import com.example.booklog.domain.library.books.entity.Authors;
import com.example.booklog.domain.library.books.entity.BookAuthors;

// BookAuthors 생성 시 book 파라미터 추가
mappings.add(BookAuthors.builder()
        .book(book)  // ← 추가
        .author(author)
        .role(AuthorRole.AUTHOR)
        .displayOrder(order++)
        .build());

// Authors 생성
Authors.builder().name(normalized).build()

변경 내용:

  • import 경로 전면 수정
  • BookAuthors 빌더에 book 파라미터 추가
  • sortOrderdisplayOrder 사용

9. AuthorEnrichmentService.java

수정 이유: import 경로 수정

// 변경 전
import com.example.booklog.domain.library.books.entity.common.Authors;

// 변경 후
import com.example.booklog.domain.library.books.entity.Authors;

🗑️ 삭제된 디렉토리 및 파일

✅ 삭제: domain/library/books/entity/common/
  ├── Authors.java (신규 entity/Authors.java로 대체)
  ├── AuthorRole.java (신규 entity/AuthorRole.java로 대체)
  ├── AuthorRewards.java (AuthorAwards로 이름 변경)
  └── Genres.java (신규 entity/Genres.java로 대체)

✅ 삭제: domain/library/books/entity/mapping/
  └── BookAuthors.java (신규 entity/BookAuthors.java로 대체)

삭제 이유:

  • 패키지 구조 단순화
  • 중복 파일 제거
  • ERD 기반 신규 엔터티로 완전 대체

4. 핵심 설계 특징

JPA Best Practice 적용

  1. BaseEntity 상속

    public abstract class BaseEntity {
        @CreatedDate
        private LocalDateTime createdAt;
        
        @LastModifiedDate
        private LocalDateTime updatedAt;
    }
  2. 복합키 패턴 통일

    @IdClass(BookAuthors.BookAuthorId.class)
    public class BookAuthors {
        @Id private Long bookId;
        @Id private Long authorId;
        @Id private AuthorRole role;
        
        public static class BookAuthorId implements Serializable {
            // equals, hashCode 구현
        }
    }
  3. 1:1 관계 최적화

    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    public class UserSettings {
        @Id
        private Long userId;
    }
  4. Enum 활용

    • 10개 Enum으로 상태 관리 명확화
    • DB에는 VARCHAR로 저장 (@Enumerated(EnumType.STRING))

연관관계 설계 원칙

관계 유형 매핑 방식 예시
1:N @ManyToOne 단방향 우선 UserBooks → Users
N:M 중간 엔터티 + 복합키 BookAuthors (Books ↔ Authors)
1:1 @OneToOne + @MapsId UserSettings ↔ Users

기본 원칙:

  • FetchType.LAZY 기본값
  • 단방향 관계 우선, 양방향은 필요시만
  • FK 명시적 네이밍 (fk_테이블_참조테이블)

5. 최종 통계

항목 개수 비고
총 엔터티 29개 BaseEntity 상속
총 Enum 10개 상태 관리용
복합키 엔터티 9개 @IdClass 패턴
1:1 관계 2개 @mapsid 사용
새로 생성된 파일 39개 엔터티 + Enum
수정된 파일 9개 Service, Repository
삭제된 디렉토리 2개 common/, mapping/

📦 패키지 구조

domain/
├── users/entity/          (4 entities + 2 enums)
├── library/
│   ├── books/entity/      (7 entities + 2 enums)
│   └── shelves/entity/    (4 entities + 2 enums)
├── tags/
│   ├── entity/           (1 entity + 1 enum)
│   └── mapping/          (1 entity)
├── posts/entity/          (6 entities + 1 enum)
├── onboarding/entity/     (4 entities + 1 enum)
├── ai/entity/             (1 entity)
└── search/entity/         (1 entity)

해결된 이슈

  • import 경로 불일치로 인한 컴파일 에러 해결
  • 중복 엔터티 파일 제거
  • ERD 명명 규칙 통일 (AuthorRewards → AuthorAwards)

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request
No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions