[infra] flyway 기반 DB 마이그레이션 도입 & Room 테이블에 RoomStatus 컬럼 추가#285
[infra] flyway 기반 DB 마이그레이션 도입 & Room 테이블에 RoomStatus 컬럼 추가#285
Conversation
WalkthroughGradle에 Flyway 의존성을 추가하고, 방 상태(RoomStatus) 필드를 도메인/엔티티/매퍼에 도입했으며, Flyway 마이그레이션 스크립트로 rooms 테이블에 room_status 열을 추가하고 기존 데이터 상태를 날짜 기준으로 갱신했습니다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Service as RoomService
participant Mapper as RoomMapper
participant JPA as RoomJpaRepository
participant DB as Database
rect rgba(200,230,255,0.3)
note over User,DB: 생성(Recruiting 기본값)
User->>Service: createRoom(cmd)
Service->>Mapper: toEntity(Room{roomStatus=RECRUITING})
Mapper-->>Service: RoomJpaEntity{roomStatus=RECRUITING}
Service->>JPA: save(entity)
JPA->>DB: INSERT rooms(room_status=RECRUITING)
DB-->>JPA: OK
JPA-->>Service: entity
Service-->>User: Room
end
rect rgba(220,255,220,0.35)
note over Service,DB: 조회/매핑 시 상태 전파
User->>Service: getRoom(id)
Service->>JPA: findById(id)
JPA->>DB: SELECT * FROM rooms
DB-->>JPA: row(room_status=IN_PROGRESS|EXPIRED|RECRUITING)
JPA-->>Service: entity
Service->>Mapper: toDomain(entity.roomStatus)
Mapper-->>Service: Room{roomStatus=...}
Service-->>User: Room
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Test Results426 tests 426 ✅ 35s ⏱️ Results for commit 1d39c20. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/konkuk/thip/room/domain/Room.java (1)
109-111: isExpired의 의미 혼동 가능성(공통 StatusType vs RoomStatus)현재 isExpired()는 공통 StatusType.EXPIRED를 봅니다. 비즈니스 의미의 방 만료(RoomStatus.EXPIRED)와 혼선 우려가 큽니다. 메서드 명/역할을 분리하세요.
- public boolean isExpired() { - return this.getStatus() == StatusType.EXPIRED; - } + public boolean isEntityExpired() { // 시스템 공통 엔티티 상태 + return this.getStatus() == StatusType.EXPIRED; + } + public boolean isRoomExpired() { // 비즈니스 상태 + return this.roomStatus == RoomStatus.EXPIRED; + }
🧹 Nitpick comments (4)
src/main/resources/db/migration/V250828__Add_room_status.sql (3)
1-4: 상태 컬럼 제약/인덱스도 함께 고려해주세요
- 값 제약: MySQL 8.0.16+ 사용 시 CHECK 제약으로 허용값을 강제하면 데이터 무결성이 좋아집니다.
- 조회 최적화: room_status로 조회/정렬이 많다면 보조 인덱스 추가를 권장합니다.
적용 예시(별도 버전 파일로 추가 권장):
ALTER TABLE rooms ADD CONSTRAINT chk_rooms_room_status CHECK (room_status IN ('RECRUITING','IN_PROGRESS','EXPIRED')); CREATE INDEX idx_rooms_room_status ON rooms(room_status);
6-10: 주석과 조건 불일치주석은 “이전(<)”이라고 되어 있지만 조건은 “<= CURDATE()”로 오늘 포함입니다. 주석 또는 조건 중 하나를 통일하세요.
- -- 2) start_date가 현재 날짜보다 "이전"이면 IN_PROGRESS로 업데이트 + -- 2) start_date가 현재 날짜와 같거나 이전(<=)이면 IN_PROGRESS로 업데이트
6-14: 단일 UPDATE로 테이블 스캔/잠금 최소화두 번의 UPDATE 대신 CASE 한 번으로 갱신하면 락 홀드/스캔 비용을 줄일 수 있습니다. 의미도 동일합니다(만료 우선).
-UPDATE rooms -SET room_status = 'IN_PROGRESS' -WHERE start_date <= CURDATE(); - -UPDATE rooms -SET room_status = 'EXPIRED' -WHERE end_date < CURDATE(); +UPDATE rooms +SET room_status = CASE + WHEN end_date < CURRENT_DATE THEN 'EXPIRED' + WHEN start_date <= CURRENT_DATE THEN 'IN_PROGRESS' + ELSE room_status +END;src/main/java/konkuk/thip/room/domain/Room.java (1)
44-45: roomStatus 필드 불변/기본값 보장빌더 경로로 생성 시 null 가능성이 남습니다. Lombok @Builder.Default 또는 생성자에서 기본값을 강제해 불변식을 보장하세요.
- private RoomStatus roomStatus; + @lombok.Builder.Default + private RoomStatus roomStatus = RoomStatus.RECRUITING;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
build.gradle(1 hunks)src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java(2 hunks)src/main/java/konkuk/thip/room/adapter/out/jpa/RoomStatus.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/mapper/RoomMapper.java(2 hunks)src/main/java/konkuk/thip/room/domain/Room.java(3 hunks)src/main/resources/db/migration/V250828__Add_room_status.sql(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (7)
build.gradle (1)
81-85: Flyway 의존성 추가 LGTMSpring Boot 3.5 BOM 하에서 버전 관리도 자동이라 현재 선언 방식이 깔끔합니다.
src/main/resources/db/migration/V250828__Add_room_status.sql (1)
1-14: 문제 없음:RoomJpaEntity의@Table(name = "rooms")이 실제 테이블rooms와 일치하며,start_date·end_date컬럼도nullable = false로 설정되어 있어 마이그레이션 스크립트 적용에 문제가 없습니다.src/main/java/konkuk/thip/room/adapter/out/jpa/RoomStatus.java (1)
3-7: 열거형 정의 자체는 간결하고 적절합니다값 네이밍과 직렬화(EnumType.STRING 전제) 모두 일관적입니다.
src/main/java/konkuk/thip/room/adapter/out/mapper/RoomMapper.java (1)
22-25: roomStatus 매핑 추가 LGTM도메인↔JPA 양방향 매핑이 누락 없이 반영됐습니다. 기존 데이터는 NOT NULL+DEFAULT로 null 위험도 낮습니다.
Also applies to: 40-46
src/main/java/konkuk/thip/room/domain/Room.java (3)
68-69: 초기 기본값 설정 LGTM새 Room 생성시 RECRUITING으로 시작하는 정책이 DB 기본값과 일치합니다.
148-152: 모집 마감 판정 로직 재검토today.isAfter(startDate.minusDays(1))는 startDate 당일 00:00부터 “모집 마감”으로 봅니다. 기획이 “startDate 전날 23:59:59까지 모집”과 정확히 일치하는지 확인하세요.
176-181: startRoomProgress()에서 startDate 덮어쓰기 대신 상태 전이 적용- startDate = LocalDate.now(); + this.roomStatus = RoomStatus.IN_PROGRESS;RoomStatus enum에 IN_PROGRESS가 정의되어 있는지, 자정 경계에 맞춰 도메인 서비스/스케줄러에서 상태 전이 정책을 어떻게 운영할지 확인 부탁드립니다.
| @Builder.Default | ||
| @Column(name = "room_status", nullable = false) | ||
| @Enumerated(EnumType.STRING) | ||
| private RoomStatus roomStatus = RoomStatus.RECRUITING; | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
room_status 매핑은 적절. 다만 null 유입 방지(Bean Validation) 추가 필요
@Builder.Default만으로는 빌더가 명시적으로 null을 넣을 때/기본 생성자로 생성 후 세터로 null이 들어갈 때를 막지 못합니다. DB 제약(nullable=false) 위반 또는 INSERT 실패를 예방하려면 @NotNull을 붙여 조기 검증을 권장합니다.
적용 diff:
- @Builder.Default
- @Column(name = "room_status", nullable = false)
- @Enumerated(EnumType.STRING)
- private RoomStatus roomStatus = RoomStatus.RECRUITING;
+ @Builder.Default
+ @Column(name = "room_status", nullable = false)
+ @Enumerated(EnumType.STRING)
+ @NotNull
+ private RoomStatus roomStatus = RoomStatus.RECRUITING;추가 import(변경 범위 밖):
import jakarta.validation.constraints.NotNull;추가로, 생성 경로가 빌더가 아닌 경우를 대비해 PrePersist 가드도 고려 가능합니다(변경 범위 밖):
@PrePersist
void prePersistDefaultStatus() {
if (roomStatus == null) roomStatus = RoomStatus.RECRUITING;
}🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java around
lines 53 to 57, the roomStatus field relies on @Builder.Default but can still
become null via explicit builder/null setters which would violate the DB
nullable=false constraint; add jakarta.validation.constraints.NotNull to the
roomStatus field (and import jakarta.validation.constraints.NotNull) to enforce
Bean Validation at the entity level, and optionally add a @PrePersist method to
set roomStatus to RoomStatus.RECRUITING if null for non-builder creation paths.
💡 Verification agent
🧩 Analysis chain
계층 의존 역전 가능성: RoomStatus의 패키지 위치 재검토
Enum이 adapter.out.jpa 패키지에 있고, 도메인 객체(Room)가 이를 직접 참조하면 도메인→인프라 의존이 생깁니다. Enum을 도메인 계층(e.g., konkuk.thip.room.domain.value.RoomStatus)으로 승격하거나, 도메인 Enum ↔ JPA Enum 매핑을 명확히 분리해 주세요.
아래 스크립트로 도메인 계층이 adapter의 RoomStatus를 import하는지 확인해 주세요:
🏁 Script executed:
#!/bin/bash
# 도메인 코드에서 adapter.out.jpa.RoomStatus 참조 여부 확인
rg -nP 'import\s+konkuk\.thip\.room\.adapter\.out\.jpa\.RoomStatus' -C2 --type java
# 프로젝트 내 RoomStatus 선언 위치 확인
rg -nP '\benum\s+RoomStatus\b' -C2 --type javaLength of output: 1028
도메인 계층이 infra(adapter) enum을 직접 참조하지 않도록 분리 필요
Room.java(도메인)에서 konkuk.thip.room.adapter.out.jpa.RoomStatus를 import(Line 7)해 도메인→인프라 의존이 발생하고 있습니다.
src/main/java/konkuk/thip/room/domain/value패키지에 도메인 전용RoomStatusenum을 선언- JPA 어댑터 레이어에서는 도메인 enum을 참조하고,
@Enumerated필드 매핑 시 도메인 enum ↔ JPA enum 간 변환 로직(또는 AttributeConverter)을 구현하세요.
🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java around
lines 53–57, the JPA layer currently defines/uses an infra enum directly causing
domain→infra coupling; create a domain-only enum class RoomStatus in
src/main/java/konkuk/thip/room/domain/value, update the JPA entity to reference
the domain enum type (not an adapter-specific enum), and implement a conversion
layer: either add a JPA AttributeConverter that maps domain RoomStatus to its DB
representation (String) and annotate the entity field with
@Convert(converter=YourRoomStatusConverter.class) or create explicit mapping
methods between the domain enum and a JPA-specific enum; finally remove any
import of adapter enum from the domain package and ensure the entity uses the
converter so persistence uses the domain enum without introducing domain→infra
dependency.
| this.endDate = room.getEndDate(); | ||
| this.recruitCount = room.getRecruitCount(); | ||
| this.memberCount = room.getMemberCount(); | ||
| this.roomStatus = room.getRoomStatus(); |
There was a problem hiding this comment.
updateFrom에서 roomStatus null 덮어쓰기 방지
room.getRoomStatus()가 null이면 @column(nullable=false) 위반 가능성이 큽니다. null일 때는 필드 유지(또는 예외)하도록 가드하세요.
적용 diff:
- this.roomStatus = room.getRoomStatus();
+ if (room.getRoomStatus() != null) {
+ this.roomStatus = room.getRoomStatus();
+ }
+ // null을 허용하지 않으려면 다음처럼 실패 빠르게도 고려:
+ // Objects.requireNonNull(room.getRoomStatus(), "roomStatus must not be null");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| this.roomStatus = room.getRoomStatus(); | |
| // updateFrom에서 roomStatus null 덮어쓰기 방지 | |
| if (room.getRoomStatus() != null) { | |
| this.roomStatus = room.getRoomStatus(); | |
| } | |
| // null을 허용하지 않으려면 다음처럼 빠르게 실패시키는 방법도 고려: | |
| // Objects.requireNonNull(room.getRoomStatus(), "roomStatus must not be null"); |
🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java around line
76, the updateFrom method unconditionally sets this.roomStatus =
room.getRoomStatus(), which can overwrite a non-null DB-mandated field with null
and violate @Column(nullable=false); change the assignment to check for null
first and only assign when room.getRoomStatus() != null (or alternatively throw
a ValidationException when null) so the existing roomStatus is preserved when
the incoming value is null.
| package konkuk.thip.room.adapter.out.jpa; | ||
|
|
||
| public enum RoomStatus { | ||
| RECRUITING, | ||
| IN_PROGRESS, | ||
| EXPIRED | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
패키지 레이어링 역참조(도메인→어댑터) 발생
Room 도메인이 adapter.out.jpa 패키지의 enum을 import합니다. 도메인이 하위 레이어를 참조하지 않도록 RoomStatus를 도메인(or common) 레이어로 승격하고, JPA 엔티티가 그 도메인 enum을 사용하도록 방향을 정리하세요.
예(이 PR 외 파일 변경 수반):
- package konkuk.thip.room.adapter.out.jpa;
+ package konkuk.thip.room.domain;그리고 Room/RoomJpaEntity/Mapper의 import를 도메인 enum으로 교체.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| package konkuk.thip.room.adapter.out.jpa; | |
| public enum RoomStatus { | |
| RECRUITING, | |
| IN_PROGRESS, | |
| EXPIRED | |
| } | |
| package konkuk.thip.room.domain; | |
| public enum RoomStatus { | |
| RECRUITING, | |
| IN_PROGRESS, | |
| EXPIRED | |
| } |
🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/room/adapter/out/jpa/RoomStatus.java lines 1-7, the
enum is currently placed in the adapter layer causing a domain→adapter layering
violation; move RoomStatus into the domain (or a shared common) package (e.g.,
src/main/java/konkuk/thip/room/domain/RoomStatus.java or common package), update
its package declaration accordingly, and then change all imports in Room,
RoomJpaEntity, and Mapper to reference the new domain/common enum location so
the JPA entity uses the domain enum rather than the adapter enum.
There was a problem hiding this comment.
@seongjunnoh 네, 알겠습니다! enum 의존성에 대해 유연하게 접근하기로 하신 결정을 이해했어요. 실용적인 구현을 우선시하는 방향으로 진행하시는군요.
(・ω・) ♪
✏️ Learnings added
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#285
File: src/main/java/konkuk/thip/room/adapter/out/jpa/RoomStatus.java:1-7
Timestamp: 2025-08-31T05:25:14.835Z
Learning: seongjunnoh는 enum 의존성에 대해 유연한 접근을 선호하며, 도메인→어댑터 레이어 참조와 같은 아키텍처 layering 원칙보다 실용적인 구현을 우선시한다.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#113
File: src/main/java/konkuk/thip/recentSearch/adapter/out/persistence/RecentSearchCommandPersistenceAdapter.java:38-44
Timestamp: 2025-07-30T14:05:04.945Z
Learning: seongjunnoh는 코드 최적화 제안에 대해 구체적인 기술적 근거와 효율성 차이를 이해하고 싶어하며, 성능 개선 방식에 대한 상세한 설명을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#93
File: src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java:49-114
Timestamp: 2025-07-28T16:44:31.224Z
Learning: seongjunnoh는 코드 중복 문제에 대한 리팩토링 제안을 적극적으로 수용하고 함수형 인터페이스를 활용한 해결책을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#195
File: src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java:0-0
Timestamp: 2025-08-13T05:22:32.287Z
Learning: seongjunnoh는 데이터 무결성과 중복 방지에 대한 고민이 깊으며, LinkedHashSet을 활용한 중복 제거와 순서 보장을 동시에 달성하는 솔루션을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#180
File: src/main/java/konkuk/thip/room/application/service/AttendanceCheckCreateService.java:22-40
Timestamp: 2025-08-14T09:15:31.371Z
Learning: seongjunnoh는 기술적 완벽성보다 실제 비즈니스 시나리오와 사용자 행동 패턴을 우선 고려하며, 발생 가능성이 낮은 엣지 케이스보다는 실용적인 구현을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#278
File: src/main/java/konkuk/thip/common/exception/code/ErrorCode.java:210-211
Timestamp: 2025-08-24T09:40:48.595Z
Learning: seongjunnoh는 HTTP 상태 코드 선택에 대해 기술적 근거와 코드베이스 내 일관성을 중요하게 생각하며, 구체적인 사례 분석을 통한 설명을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#278
File: src/main/java/konkuk/thip/TestTokenController.java:0-0
Timestamp: 2025-08-24T09:33:52.982Z
Learning: seongjunnoh는 Spring의 ConditionalOnProperty 동작 원리를 정확히 이해하고 있으며, 보안 이슈에 대해서도 실질적인 위험성을 기준으로 판단하는 실용적 접근을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#112
File: src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java:272-272
Timestamp: 2025-07-30T10:44:34.115Z
Learning: seongjunnoh는 피드 커서 페이지네이션에서 LocalDateTime 단일 커서 방식을 선호하며, 복합 키 기반 커서보다 구현 단순성과 성능을 우선시한다.
| import konkuk.thip.common.exception.InvalidStateException; | ||
| import konkuk.thip.common.entity.StatusType; | ||
| import konkuk.thip.common.exception.code.ErrorCode; | ||
| import konkuk.thip.room.adapter.out.jpa.RoomStatus; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
도메인에서 어댑터 enum import 회피 필요
도메인 레이어가 adapter 패키지를 참조하지 않도록 RoomStatus를 도메인(or common)으로 이동시킨 뒤 import를 교체하세요.
- import konkuk.thip.room.adapter.out.jpa.RoomStatus;
+ import konkuk.thip.room.domain.RoomStatus; // enum을 도메인으로 이동했다고 가정📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import konkuk.thip.room.adapter.out.jpa.RoomStatus; | |
| // File: src/main/java/konkuk/thip/room/domain/Room.java | |
| import konkuk.thip.room.domain.RoomStatus; |
🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/room/domain/Room.java around line 7, the class
currently imports the adapter enum konkuk.thip.room.adapter.out.jpa.RoomStatus
which couples the domain to the adapter layer; move RoomStatus out of the
adapter package into the domain (or a shared common package), update the enum's
package declaration accordingly, and replace the import in Room.java with the
new package path so the domain layer no longer depends on adapter code.
| -- 1) 컬럼 추가: 기본값 RECRUITING, NOT NULL | ||
| ALTER TABLE rooms | ||
| ADD COLUMN room_status VARCHAR(32) NOT NULL DEFAULT 'RECRUITING' | ||
| COMMENT 'Room 상태: RECRUITING/IN_PROGRESS/EXPIRED'; | ||
|
|
||
| -- 2) start_date가 현재 날짜보다 "이전"이면 IN_PROGRESS로 업데이트 | ||
| UPDATE rooms | ||
| SET room_status = 'IN_PROGRESS' | ||
| WHERE start_date <= CURDATE(); | ||
|
|
||
| -- 3) end_date가 현재 날짜보다 "이전"이면 EXPIRED로 업데이트 | ||
| UPDATE rooms | ||
| SET room_status = 'EXPIRED' | ||
| WHERE end_date < CURDATE(); No newline at end of file |
There was a problem hiding this comment.
🛠️ Refactor suggestion
테스트(H2) 환경 호환성 주의
이 스크립트는 MySQL 전용 문법(CURDATE, COMMENT)을 사용합니다. H2에서 Flyway가 실행되면 실패할 수 있습니다. 파일을 MySQL 전용으로 분기(.mysql.sql)하거나 테스트 프로필에서 Flyway 적용을 비활성/분리하세요.
예:
- 파일명: V250828__Add_room_status.mysql.sql 로 변경
- (선택) H2 전용 스크립트: V250828__Add_room_status.h2.sql
🤖 Prompt for AI Agents
In src/main/resources/db/migration/V250828__Add_room_status.sql around lines
1-14: the migration uses MySQL-specific syntax (CURDATE(), COMMENT) which will
fail on H2 during tests; fix by making the migration MySQL-only (rename to
V250828__Add_room_status.mysql.sql) and either add a separate H2-compatible
migration (e.g., V250828__Add_room_status.h2.sql) with equivalent logic using H2
functions or disable/apply Flyway migrations differently under the test profile
so H2 does not try to run the MySQL script.
seongjunnoh
left a comment
There was a problem hiding this comment.
제 로컬 yml 에서 ddl-auto 값을 validate로 수정하고, flyway 관련 설정값을 주입하니 flyway_schema_history 테이블이 정상적으로 생기고, room table 의 구조가 정상적으로 수정된 것을 확인했습니다!
추후에 soft delete 적용대상이 아닌 테이블에 대해서 status 필드를 제거하는 리펙토링을 진행할때에도 DB 구조 수정이 필요한데, 이때 유용하게 사용할 수 있을 것 같네요!! 고생하셨습니다!
| public enum RoomStatus { | ||
| RECRUITING, | ||
| IN_PROGRESS, | ||
| EXPIRED | ||
| } |
|
|
||
| private int memberCount; | ||
|
|
||
| private RoomStatus roomStatus; |
There was a problem hiding this comment.
좋습니다! 도메인 entity 도 그냥 enum 자체를 의존하는게 더 나을 것 같습니다!!
현재 도메인 entity 에서 String 타입으로 enum을 의존하는 코드들도 수정하는게 좋을듯 하네요
언제하죠 하하
| public enum RoomStatus { | ||
| RECRUITING, | ||
| IN_PROGRESS, | ||
| EXPIRED | ||
| } |
|
|
||
| private int memberCount; | ||
|
|
||
| private RoomStatus roomStatus; |
| .endDate(endDate) | ||
| .recruitCount(recruitCount) | ||
| .memberCount(1) // 처음 Room 생성 시 방장 1명 | ||
| .roomStatus(RoomStatus.RECRUITING) // 처음 Room 생성 시 -> 모집중 |
현재 StatusType의 EXPIRED로 방 만료조건을 검증하는 서비스 로직이 존재하는 것 같아서 다음 pr에서 종합적으로 방 만료조건을 변경해서 올려보겠습니다! |
#️⃣ 연관된 이슈
📝 작업 내용
flyway를 통한 DB 마이그레이션을 도입했습니다. 밑에 내용 확인 부탁드립니다!
DB 마이그레이션 도입 배경
• 기존에는 ddl-auto 설정에 의존하여 스키마가 자동 변경되는 방식 → 운영/개발 환경 간의 스키마 차이 발생 위험.
• Flyway를 도입하여 DB 스키마 변경을 이력 관리 + 코드 리뷰 가능한 형태로 관리.
• 모든 스키마 변경 내역은 db/migration 디렉토리에 SQL 파일로 기록되며, flyway_schema_history 테이블을 통해 DB 적용 여부가 추적됩니다.
파일명 컨벤션
• 규칙:
V{날짜}__{변경 내용}.sql• 예시: V250828__Add_room_status.sql
• 동일한 날짜에 여러 개의 변경이 필요하다면 소수점 버전을 증가시켜 작성해주세요.
• V250828.1__Add_room_status.sql
• V250828.2__Delete_room_status.sql
• Flyway는 아래와 같이 flyway_schema_history 테이블을 통해 적용된 마이그레이션을 관리합니다.
• 이미 적용된 SQL 파일을 수정해도 Flyway는 이를 변경으로 인식하지 않기 때문에 새로운 변경사항이 있다면 반드시 새로운 버전 파일을 추가해주세요!
• 특정 컬럼을 추가/수정할 경우 테이블 전체를 재정의할 필요 없이 ALTER TABLE을 이용해 해당 컬럼만 변경해주세요!
로컬 환경 검증 절차
• 로컬 환경의 ddl-auto 옵션을 validate로 변경하여 로컬에서도 Flyway 마이그레이션을 통해 스키마가 적용되는지 확인 가능합니다.
• 따라서, 로컬에서 먼저 적용/테스트 후에 개발 서버에 머지 부탁드립니다!
엔티티 반영 필수
• DB 마이그레이션 후에는 반드시 엔티티 코드에도 동일하게 반영해야 합니다!
• (예: RoomJpaEntity에 roomStatus 필드 추가 완료)
📸 스크린샷
💬 리뷰 요구사항
이번 변경 사항
📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit