mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 17:16:25 +00:00
for merge
This commit is contained in:
parent
1d9fa37fe7
commit
f8e41309a2
@ -650,7 +650,7 @@ code + .copy-button {
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function configurationCacheProblems() { return (
|
function configurationCacheProblems() { return (
|
||||||
// begin-report-data
|
// begin-report-data
|
||||||
{"diagnostics":[{"locations":[{"path":"/Users/jominseo/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java"},{"taskPath":":stt:compileJava"}],"problem":[{"text":"/Users/jominseo/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java uses unchecked or unsafe operations."}],"severity":"ADVICE","problemDetails":[{"text":"Note: /Users/jominseo/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java uses unchecked or unsafe operations."}],"contextualLabel":"/Users/jominseo/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java uses unchecked or unsafe operations.","problemId":[{"name":"java","displayName":"Java compilation"},{"name":"compilation","displayName":"Compilation"},{"name":"compiler.note.unchecked.filename","displayName":"/Users/jominseo/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java uses unchecked or unsafe operations."}]},{"locations":[{"path":"/Users/jominseo/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java"},{"taskPath":":stt:compileJava"}],"problem":[{"text":"Recompile with -Xlint:unchecked for details."}],"severity":"ADVICE","problemDetails":[{"text":"Note: Recompile with -Xlint:unchecked for details."}],"contextualLabel":"Recompile with -Xlint:unchecked for details.","problemId":[{"name":"java","displayName":"Java compilation"},{"name":"compilation","displayName":"Compilation"},{"name":"compiler.note.unchecked.recompile","displayName":"Recompile with -Xlint:unchecked for details."}]}],"problemsReport":{"totalProblemCount":2,"buildName":"hgzero","requestedTasks":":stt:bootRun","documentationLink":"https://docs.gradle.org/8.14/userguide/reporting_problems.html","documentationLinkCaption":"Problem report","summaries":[]}}
|
{"diagnostics":[{"locations":[{"path":"/Users/daewoong/home/workspace/HGZero/user/src/main/java/com/unicorn/hgzero/user/service/UserServiceImpl.java"},{"taskPath":":user:compileJava"}],"problem":[{"text":"/Users/daewoong/home/workspace/HGZero/user/src/main/java/com/unicorn/hgzero/user/service/UserServiceImpl.java uses or overrides a deprecated API."}],"severity":"ADVICE","problemDetails":[{"text":"Note: /Users/daewoong/home/workspace/HGZero/user/src/main/java/com/unicorn/hgzero/user/service/UserServiceImpl.java uses or overrides a deprecated API."}],"contextualLabel":"/Users/daewoong/home/workspace/HGZero/user/src/main/java/com/unicorn/hgzero/user/service/UserServiceImpl.java uses or overrides a deprecated API.","problemId":[{"name":"java","displayName":"Java compilation"},{"name":"compilation","displayName":"Compilation"},{"name":"compiler.note.deprecated.filename","displayName":"/Users/daewoong/home/workspace/HGZero/user/src/main/java/com/unicorn/hgzero/user/service/UserServiceImpl.java uses or overrides a deprecated API."}]},{"locations":[{"path":"/Users/daewoong/home/workspace/HGZero/user/src/main/java/com/unicorn/hgzero/user/service/UserServiceImpl.java"},{"taskPath":":user:compileJava"}],"problem":[{"text":"Recompile with -Xlint:deprecation for details."}],"severity":"ADVICE","problemDetails":[{"text":"Note: Recompile with -Xlint:deprecation for details."}],"contextualLabel":"Recompile with -Xlint:deprecation for details.","problemId":[{"name":"java","displayName":"Java compilation"},{"name":"compilation","displayName":"Compilation"},{"name":"compiler.note.deprecated.recompile","displayName":"Recompile with -Xlint:deprecation for details."}]},{"locations":[{"path":"/Users/daewoong/home/workspace/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java"},{"taskPath":":stt:compileJava"}],"problem":[{"text":"/Users/daewoong/home/workspace/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java uses unchecked or unsafe operations."}],"severity":"ADVICE","problemDetails":[{"text":"Note: /Users/daewoong/home/workspace/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java uses unchecked or unsafe operations."}],"contextualLabel":"/Users/daewoong/home/workspace/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java uses unchecked or unsafe operations.","problemId":[{"name":"java","displayName":"Java compilation"},{"name":"compilation","displayName":"Compilation"},{"name":"compiler.note.unchecked.filename","displayName":"/Users/daewoong/home/workspace/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java uses unchecked or unsafe operations."}]},{"locations":[{"path":"/Users/daewoong/home/workspace/HGZero/stt/src/main/java/com/unicorn/hgzero/stt/controller/AudioWebSocketHandler.java"},{"taskPath":":stt:compileJava"}],"problem":[{"text":"Recompile with -Xlint:unchecked for details."}],"severity":"ADVICE","problemDetails":[{"text":"Note: Recompile with -Xlint:unchecked for details."}],"contextualLabel":"Recompile with -Xlint:unchecked for details.","problemId":[{"name":"java","displayName":"Java compilation"},{"name":"compilation","displayName":"Compilation"},{"name":"compiler.note.unchecked.recompile","displayName":"Recompile with -Xlint:unchecked for details."}]}],"problemsReport":{"totalProblemCount":4,"buildName":"hgzero","requestedTasks":"build","documentationLink":"https://docs.gradle.org/8.14/userguide/reporting_problems.html","documentationLinkCaption":"Problem report","summaries":[]}}
|
||||||
// end-report-data
|
// end-report-data
|
||||||
);}
|
);}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
203
meeting/section_id.md
Normal file
203
meeting/section_id.md
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
# Meeting 서비스 section_id 이슈 해결 기록
|
||||||
|
|
||||||
|
## 문제 상황
|
||||||
|
|
||||||
|
### 발생한 에러
|
||||||
|
```
|
||||||
|
Caused by: org.postgresql.util.PSQLException: ERROR: column "section_id" of relation "minutes_sections" contains null values
|
||||||
|
```
|
||||||
|
|
||||||
|
### 에러 원인
|
||||||
|
- JPA Entity인 `MinutesSectionEntity`는 `section_id`를 Primary Key로 정의
|
||||||
|
- 실제 데이터베이스 테이블에는 `section_id` 컬럼이 존재하지 않음
|
||||||
|
- JPA가 `ddl-auto: update` 모드로 NOT NULL 제약조건을 추가하려고 시도했으나 실패
|
||||||
|
|
||||||
|
## 해결 과정
|
||||||
|
|
||||||
|
### 1단계: 문제 분석
|
||||||
|
- 마이그레이션 파일 확인: V1이 없고 V2, V3만 존재
|
||||||
|
- JPA 설정 확인: `ddl-auto: update` 모드 사용 중
|
||||||
|
- Entity 분석: `MinutesSectionEntity.section_id`는 Primary Key로 정의됨
|
||||||
|
|
||||||
|
### 2단계: 해결 방안 선택
|
||||||
|
사용자 선택:
|
||||||
|
- **방안 1**: 기존 데이터 정리 후 스키마 재구성
|
||||||
|
- **옵션 B**: Foreign Key 제약조건 제거하여 기존 데이터 보존
|
||||||
|
|
||||||
|
### 3단계: Flyway 마이그레이션 설정
|
||||||
|
|
||||||
|
#### build.gradle 수정
|
||||||
|
```gradle
|
||||||
|
// Flyway 의존성 추가
|
||||||
|
implementation 'org.flywaydb:flyway-core'
|
||||||
|
runtimeOnly 'org.flywaydb:flyway-database-postgresql'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### application.yml 수정
|
||||||
|
```yaml
|
||||||
|
jpa:
|
||||||
|
hibernate:
|
||||||
|
ddl-auto: validate # update → validate로 변경
|
||||||
|
|
||||||
|
# Flyway 설정 추가
|
||||||
|
flyway:
|
||||||
|
enabled: true
|
||||||
|
baseline-on-migrate: true
|
||||||
|
baseline-version: 0
|
||||||
|
validate-on-migrate: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4단계: 마이그레이션 파일 생성
|
||||||
|
|
||||||
|
#### V1__create_initial_schema.sql
|
||||||
|
- 모든 초기 테이블 생성
|
||||||
|
- Foreign Key 제약조건 주석 처리 (옵션 B 선택)
|
||||||
|
- `fk_todos_minutes`: todos 테이블의 minutes_id 외래키
|
||||||
|
- `fk_sessions_meetings`: sessions 테이블의 meeting_id 외래키
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 외래키 제약조건 비활성화 예시
|
||||||
|
-- ALTER TABLE todos DROP CONSTRAINT IF EXISTS fk_todos_minutes;
|
||||||
|
-- ALTER TABLE todos ADD CONSTRAINT fk_todos_minutes
|
||||||
|
-- FOREIGN KEY (minutes_id) REFERENCES minutes(minutes_id);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### V2__create_meeting_participants_table.sql
|
||||||
|
- V1에 통합되어 no-op 처리
|
||||||
|
```sql
|
||||||
|
SELECT 1; -- No-op statement
|
||||||
|
```
|
||||||
|
|
||||||
|
#### V4__fix_missing_columns.sql
|
||||||
|
- `minutes_sections` 테이블에 `section_id` 컬럼 추가
|
||||||
|
- 시퀀스 생성 후 기존 데이터에 자동 ID 할당
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 1. 시퀀스 생성
|
||||||
|
CREATE SEQUENCE IF NOT EXISTS minutes_sections_temp_seq;
|
||||||
|
|
||||||
|
-- 2. section_id 컬럼 추가
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_name = 'minutes_sections' AND column_name = 'section_id') THEN
|
||||||
|
-- 임시 컬럼 추가
|
||||||
|
ALTER TABLE minutes_sections ADD COLUMN temp_section_id VARCHAR(50);
|
||||||
|
|
||||||
|
-- 기존 데이터에 ID 생성
|
||||||
|
UPDATE minutes_sections
|
||||||
|
SET temp_section_id = 'section-' || nextval('minutes_sections_temp_seq'::regclass)
|
||||||
|
WHERE temp_section_id IS NULL;
|
||||||
|
|
||||||
|
-- 기존 Primary Key 제거
|
||||||
|
ALTER TABLE minutes_sections DROP CONSTRAINT IF EXISTS minutes_sections_pkey;
|
||||||
|
|
||||||
|
-- 컬럼명 변경
|
||||||
|
ALTER TABLE minutes_sections RENAME COLUMN temp_section_id TO section_id;
|
||||||
|
ALTER TABLE minutes_sections ALTER COLUMN section_id SET NOT NULL;
|
||||||
|
|
||||||
|
-- 새로운 Primary Key 설정
|
||||||
|
ALTER TABLE minutes_sections ADD PRIMARY KEY (section_id);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5단계: 실행 프로파일 수정
|
||||||
|
|
||||||
|
#### .run/meeting-service.run.xml
|
||||||
|
```xml
|
||||||
|
<entry key="JPA_DDL_AUTO" value="validate" />
|
||||||
|
```
|
||||||
|
|
||||||
|
## 발생한 에러들과 해결
|
||||||
|
|
||||||
|
### 에러 1: PostgreSQL 인증 실패
|
||||||
|
- 증상: psql 직접 연결 실패
|
||||||
|
- 해결: Flyway 마이그레이션 사용으로 전환
|
||||||
|
|
||||||
|
### 에러 2: 컬럼 존재하지 않음 (42703)
|
||||||
|
- 증상: V1 마이그레이션의 DELETE 문에서 존재하지 않는 컬럼 참조
|
||||||
|
- 해결: DELETE 문 제거, CREATE TABLE IF NOT EXISTS 활용
|
||||||
|
|
||||||
|
### 에러 3: Foreign Key 제약조건 위반 (23503)
|
||||||
|
- 증상: `ERROR: insert or update on table "todos" violates foreign key constraint "fk_todos_minutes"`
|
||||||
|
- 해결: 사용자 선택(옵션 B)에 따라 Foreign Key 제약조건 주석 처리
|
||||||
|
|
||||||
|
### 에러 4: 인덱스 중복 (42P07)
|
||||||
|
- 증상: V2 마이그레이션이 이미 존재하는 테이블/인덱스 생성 시도
|
||||||
|
- 해결: V2를 no-op으로 변경 (SELECT 1)
|
||||||
|
|
||||||
|
### 에러 5: section_id 컬럼 누락
|
||||||
|
- 증상: `Schema-validation: missing column [section_id] in table [minutes_sections]`
|
||||||
|
- 해결: V4 마이그레이션 생성하여 컬럼 추가
|
||||||
|
|
||||||
|
### 에러 6: 시퀀스 존재하지 않음 (42P01)
|
||||||
|
- 증상: V4에서 시퀀스를 생성 전에 사용 시도
|
||||||
|
- 해결: 시퀀스 생성을 DO 블록 앞으로 이동
|
||||||
|
|
||||||
|
### 에러 7: 포트 사용 중
|
||||||
|
- 증상: 8082 포트가 이미 사용 중
|
||||||
|
- 해결: `lsof -ti:8082 | xargs -r kill -9`로 프로세스 종료
|
||||||
|
|
||||||
|
## 최종 결과
|
||||||
|
|
||||||
|
### 서비스 정상 실행 확인
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8082/actuator/health
|
||||||
|
```
|
||||||
|
|
||||||
|
응답:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "UP",
|
||||||
|
"components": {
|
||||||
|
"db": {
|
||||||
|
"status": "UP",
|
||||||
|
"details": {
|
||||||
|
"database": "PostgreSQL",
|
||||||
|
"validationQuery": "isValid()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"diskSpace": {"status": "UP"},
|
||||||
|
"ping": {"status": "UP"},
|
||||||
|
"redis": {"status": "UP"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 마이그레이션 적용 결과
|
||||||
|
- V1: 초기 스키마 생성 (FK 제약조건 제외)
|
||||||
|
- V2: no-op (V1에 통합)
|
||||||
|
- V3: 기존 유지
|
||||||
|
- V4: section_id 컬럼 추가
|
||||||
|
|
||||||
|
## 주요 변경 파일
|
||||||
|
|
||||||
|
1. **meeting/src/main/resources/db/migration/V1__create_initial_schema.sql** (생성)
|
||||||
|
2. **meeting/src/main/resources/db/migration/V2__create_meeting_participants_table.sql** (수정)
|
||||||
|
3. **meeting/src/main/resources/db/migration/V4__fix_missing_columns.sql** (생성)
|
||||||
|
4. **meeting/src/main/resources/application.yml** (수정)
|
||||||
|
5. **meeting/.run/meeting-service.run.xml** (수정)
|
||||||
|
6. **build.gradle** (수정)
|
||||||
|
|
||||||
|
## 교훈
|
||||||
|
|
||||||
|
1. **Flyway를 초기부터 사용**: JPA의 `ddl-auto: update`는 프로덕션 환경에서 위험
|
||||||
|
2. **Baseline 마이그레이션 전략**: 기존 스키마를 버전 0으로 인정하고 점진적 수정
|
||||||
|
3. **데이터 보존 vs 무결성**: 비즈니스 요구사항에 따라 Foreign Key 제약조건 선택적 적용
|
||||||
|
4. **마이그레이션 테스트**: 각 마이그레이션은 독립적으로 실행 가능해야 함
|
||||||
|
5. **환경 변수 관리**: `ddl-auto` 설정은 환경별로 다르게 관리 필요
|
||||||
|
|
||||||
|
## 향후 개선 사항
|
||||||
|
|
||||||
|
1. Foreign Key 제약조건 재검토
|
||||||
|
- 데이터 정리 후 제약조건 활성화 검토
|
||||||
|
- 참조 무결성 확보 방안 논의
|
||||||
|
|
||||||
|
2. 마이그레이션 전략 수립
|
||||||
|
- 개발/스테이징/프로덕션 환경별 마이그레이션 절차
|
||||||
|
- 롤백 계획 수립
|
||||||
|
|
||||||
|
3. 모니터링 강화
|
||||||
|
- 데이터베이스 스키마 변경 추적
|
||||||
|
- 마이그레이션 실패 알림 설정
|
||||||
Loading…
x
Reference in New Issue
Block a user