[1편] 설계편: Kotlin + Spring Boot로 콘티 서비스 시작하기

박경희·2025년 4월 23일

프로젝트

목록 보기
20/22

예배 콘티 관리 프로젝트를 실무 설계 기준으로 구현해 나가며 깨달은 점들을 기록해보자


도메인 구조

  • Team: 콘티를 카테고리별로 분류하기 위한 개념

  • Conti: 하나의 콘티, 예배 시 사용할 곡 모음

  • Song: 콘티 안에 포함된 개별 찬양 곡

각 도메인의 관계:

  • Team 1:N Conti

  • Conti 1:N Song


엔티티 설계 핵심 포인트

1. @Column(length = ?) 설정 기준

팀명 컬럼 길이 선정

  • 한글 10자 내외 → UTF-8 기준 약 30 bytes (2~3 bytes/자)

  • @Column(length = 50)이면 충분하며, 여유 있게 100으로 설정해도 무방

URL 저장 시 컬럼 길이

  • 이미지 URL은 S3, Firebase, Supabase 등 클라우드 저장소 기반이 많음

  • 대부분 200자 내외이나, 넉넉하게 length = 255 설정

@Column(length = 100)
val teamName: String

@Column(length = 255)
val logoUrl: String

2. 이미지 저장은 URL로만 처리

이미지 자체를 DB에 넣는 것은 다음 이유로 지양했다:

  • 이미지 용량이 크면 DB 성능 저하

  • 텍스트 기반 쿼리에선 다루기 힘듦

  • 클라우드 저장소를 사용하고 링크만 저장하는 것이 실무 표준


@Lob과 Lazy 로딩 전략

콘티에는 찬양 가사 같은 대용량 텍스트가 들어간다. 이를 위해 @LobTEXT 타입을 사용하고, 꼭 필요한 경우에만 로딩되게 설정했다.

@Lob
@Basic(fetch = FetchType.LAZY)
@Column(columnDefinition = "TEXT")
val lyrics: String
  • @Lob은 기본적으로 EAGER 로딩이므로 Lazy로 명시하지 않으면 콘티 목록 조회 시 전체 가사까지 로딩되는 성능 문제 발생한다.

  • 상세 페이지에서만 가사를 보므로 Lazy 설정


연관 관계 설계

  • 팀 → 콘티 → 곡 구조
  • 팀과 콘티는 1:N 관계

콘티와 곡도 1:N 관계, 단 곡은 콘티에 종속된 구조 (독립적으로 CRUD 하지 않았다.)

@OneToMany(mappedBy = "conti", cascade = [CascadeType.ALL], orphanRemoval = true)
val songs: MutableList<Song> = mutableListOf()
  • cascade = ALL → 콘티 저장 시 곡도 함께 저장됨

  • orphanRemoval = true → 곡 제거 시 DB에서도 삭제됨


필드 네이밍 전략

  • title, date → 의미가 모호해
    → contiTitle, songTitle로 변경하여 가독성 향상

  • 응답 DTO는 용도별로 나눴다.

용도DTO 이름설명
홈 전용ContiPreviewResponse최신 콘티 요약 (곡 제목들만)
목록ContiSummaryResponse콘티 리스트 보기용 정보 요약
상세ContiDetailResponse콘티 + 곡 정보 + 링크 등 전체 포함

페이징 처리 기준

방식설명구현 방식
페이지네이션1,2,3 버튼 클릭PageRequest.of(page, size)
무한 스크롤스크롤 시 10개씩 로딩offset + limit (Pageable)

현재는:

  • 홈 최신 1건 → findFirstBy...OrderByIdDesc() (단건 조회)

  • 목록 조회 → Page<Conti>로 페이징 적용


권한 처리 예고: @PreAuthorize

  • 리더 인증이 된 사용자만 콘티를 작성할 수 있도록 할 예정

  • 지금은 isLeader, userId 하드코딩 상태지만 추후 JWT로 전환 예정

@PreAuthorize("hasRole('LEADER')")
fun createConti(...) { ... }
  • Spring Boot 3.x 이상: @EnableMethodSecurity 설정 필요하다.
@Configuration
@EnableMethodSecurity
class SecurityConfig

0개의 댓글