Problem (문제점)
기존 ‘애프터노트’는 일기, 깊은 생각, 질문 답변을 MindRecord라는 하나의 통합 테이블로 관리했습니다. 하지만 카테고리별로 필요한 필드가 달라지면서 DB에 null 허용 컬럼이 급증했고, 하나의 API에서 세 가지 로직을 분기 처리하느라 가독성이 급격히 저하되었습니다. 특히 수신자(Receiver) 매핑이 통합 관리되다 보니 도메인별 개별 노출 로직을 구현하는 데 한계가 있었습니다.
Analysis (분석)
근본적인 해결을 위해 테이블 분리를 결정했으나, 마이그레이션 과정에서 메타데이터(CreatedAt, UpdatedAt)의 관리 주체에 대한 기술적 선택이 필요했습니다.
- JPA Auditing 방식: @CreatedDate 등 애플리케이션 레벨의 자동 주입은 개발이 편리하지만, 대량의 데이터를 SQL로 직접 이관하는 상황(Migration)에서는 작동하지 않아 데이터의 생성 시점이 누락될 위험이 있었습니다.
- 서비스의 특수성: 고인의 데이터를 다루는 서비스 특성상, 데이터가 생성되고 수정된 '기록의 시간'은 단순한 정보 이상의 가치를 지닙니다. 따라서 어떤 상황에서도 시간이 정확히 기록되는 데이터 무결성(Integrity) 확보가 최우선이었습니다.
Action (해결 과정)
편리한 자동화 도구 대신, 데이터의 정밀도를 보장하기 위해 DB Native SQL 기반의 단계적 리팩터링을 수행했습니다.
- 메타데이터 관리의 DB 내재화:
- 애플리케이션의 Audit 기능에 의존하는 대신, 모든 신규 테이블(diary, deep_thought 등)의 created_at 컬럼에 DEFAULT CURRENT_TIMESTAMP 설정을 적용했습니다.
- 이를 통해 JPA를 통한 저장은 물론, 직접적인 SQL 조작이나 마이그레이션 스크립트 실행 시에도 DB 서버 시간을 기준으로 한 정밀한 기록이 강제되도록 '안전망'을 구축했습니다.
- 이렇게 한 이유는 저희 프로젝트가 성능보단 "안정성"이 더 중요하다고 생각했기 때문입니다.
- Native SQL을 활용한 정교한 이관:
- INSERT INTO ... SELECT 문을 직접 작성하여 기존 MindRecord의 데이터를 새 도메인 테이블로 1:1 매핑했습니다. 이 과정에서 기존 데이터의 과거 생성 시점을 그대로 보존하면서도, 누락된 데이터는 DB 엔진이 스스로 채우도록 설계했습니다.
- 제약 조건의 수동 제어:
- ERROR 3730(FK 제약 오류)을 해결하기 위해, SQL로 외래 키 참조 관계를 역추적하여 해제하고 재설정하는 과정을 거쳤습니다. 이는 JPA의 자동 DDL 기능으로는 통제하기 어려운 정교한 작업이었습니다.
Result (결과)
- 데이터 무결성 확보: 수동으로 모든 의존 관계를 파악하고 이관함으로써 데이터 유실률 0%의 리팩터링을 완수했습니다.
- 시스템 신뢰도 향상: 애플리케이션 로직과 별개로 DB 단에서 데이터 생성/수정 시간이 강제됨에 따라, 어떤 경로로 데이터가 인입되어도 무결성이 유지되는 Single Source of Truth(단일 진실 공급원)를 확보했습니다.
- 엔지니어링 역량 강화: 편리한 추상화 도구(JPA)의 이면을 이해하고, 서비스의 본질인 '데이터'를 보호하기 위해 가장 확실한 로우 레벨(Low-level) 기술을 선택하고 제어하는 경험을 쌓았습니다.
- 운영 시뮬레이션 경험: 실제 운영 환경에서의 스키마 변경 프로세스를 직접 SQL로 수행하며, DB 레벨의 트랜잭션 관리와 제약 조건 제어에 대한 깊은 이해도를 얻었습니다.
'Project > Afternote' 카테고리의 다른 글
| [EC2] Amazon linux (0) | 2026.05.03 |
|---|---|
| [CDN] S3 presigned URL에서 CDN 도메인 전환하기 (0) | 2026.04.12 |
| [Github Action] CI/CD 적용기 (0) | 2026.04.05 |
| [VPC/EC2/RDS] 인프라 적용기 (0) | 2026.03.29 |
| [트러블슈팅] OCP 위반 코드 수정 (0) | 2026.03.22 |