TMS 아키텍처 혁신을 위한 M:N 스키마 정규화 및 RPC 트랜잭션 가이드

번역 관리 시스템(TMS)의 규모가 커지고 지원하는 제품군이 늘어날수록 데이터베이스의 관계 설계와 트랜잭션의 원자성(Atomicity)은 시스템의 성패를 가르는 핵심 지표가 된다. 기존의 단일 테이블 중심 구조는 컬럼 파편화와 중복 데이터를 양산하여 결합도를 높이고 성능을 저하시키는 원인이 된다.

최근 ‘Translation Manager’ 프로젝트의 Phase 3~5 스프린트에서는 데이터 구조의 한계를 극복하기 위해 다대다(M:N) 링크 테이블 기반의 스키마 정규화를 단행하고, Supabase/SQLite를 동시에 지원하는 제품 필터 레이어 구축 및 RPC(Remote Procedure Call) 기반의 ACID 마이그레이션 저장소 엔진을 전격 도입하였다.

이 과정에서 마주한 데이터베이스 캐시 및 파라미터 오버로딩 에러를 극복한 실무 디버깅 노하우와 상세 아키텍처 변화를 공유한다.

1. 컬럼 제거에서 관계형 테이블 전환으로의 스키마 정규화

기존 아키텍처는 translations 테이블과 glossary 테이블 내부에 product_code 컬럼이 직접 하드코딩되어 박혀 있는 구조적 취약점을 안고 있었다. 이는 하나의 번역 자산이나 용어가 여러 제품군에 교차 소속될 때 데이터베이스 레코드 자체를 복사해야 하는 비효율을 초래했다.

  • 다대다(M:N) 링크 테이블 구조 전환: 중복 적재를 원천 차단하기 위해 코어 테이블에서 product_code 컬럼을 과감히 Drop 처리하였음. 대신 교차 엔티티 역할을 수행할 translation_productsglossary_products 링크 테이블을 신설하여 완벽한 정규화를 이룩하였음.
  • 원자적 데이터 이주 SQL: 기존에 누적되어 있던 데이터의 영속성을 보장하기 위해, 컬럼을 삭제하기 전 서브쿼리를 이용하여 기존 매핑 관계를 신규 교차 테이블에 안전하게 복사·이식하는 선행 작업을 완료하였음.
SQL 예시 문

2. 하이브리드 Product Filter Layer 및 중복 체크 서비스 구축

스키마가 정규화되면서 테이블 조인 연산의 복잡도가 증가함에 따라, 백엔드 레이어 전반의 쿼리 가독성을 유지하기 위해 독립된 필터 추상화 레이어(product-filter.ts)를 아키텍처 단에 매핑하였음.

듀얼 인프라 지원: 클라우드 환경(Supabase)과 로컬 경량 환경(SQLite)을 동시에 스코핑할 수 있도록 설계하였으며, Phase 3에서 수립한 다대다 링크 테이블만을 정밀 추적하여 관계 데이터 ID 배열을 리턴하는 ProductQueryBuilder 헬퍼 클래스를 이식하였음.

Duplicate Check Service 최적화: 중복 검증 연산의 데이터베이스 병목을 제거하기 위해 5분 만료 세션 TTL(Time-To-Live) 캐싱 메커니즘을 장착하고 대용량 파일 인입에 대응하는 벌크 배치(Batch) 처리 파이프라인을 구축하였음.

통계 API 정정: 단용 용어명(term) 기준으로만 그룹핑을 수행하여 Stats API 카운트와 실제 UI 테이블 행 수가 어긋나던 버그를 해결하기 위해, term|product_codes 복합 맵 구조의 연산 식으로 교정하여 정합성을 회복하였음.

3. 트랜잭션 완벽 보장: RPC 기반 ACID 마이그레이션 파이프라인 가동

대량의 벌크 마이그레이션 커밋 요청 시 네트워크 지연이나 구문 오류로 인해 데이터가 불완전하게 적재되는 파손 현상을 방지하기 위해, 데이터베이스 엔진 단에서 완전한 원자성 및 고속 실행을 보장하는 데이터베이스 내장 스토어드 프로시저(RPC) 체계를 수립하였음.

ㄱ. 4대 핵심 RPC 마이그레이션 함수 배포

개별 엔트리 제어: 용어 데이터와 번역 엔트리를 원자적으로 인서트하는 migrate_glossary_entrymigrate_translation_entry 스크립트를 구현 배치하였음.

배치 및 가비지 컬렉션: 대용량 리스트를 한 번에 트랜잭션으로 묶어 처리하는 migrate_batch 함수와, 마이그레이션 과정 중 발생한 일정 시간 이전의 유실 찌꺼기 데이터를 영구 청소하는 cleanup_orphaned_migration_data(p_hours_old) 가비지 컬렉터 스크립트를 배포 완료하였음.

ㄴ. 구조적 설계 결정: PostgREST Hint 제안에 따른 파라미터 순서 재정렬

RPC 아키텍처를 가동하는 과정에서 Supabase PostgREST 컴파일러가 특정 오버로딩 함수를 오인하거나 쿼리 힌트(Hint)가 불일치하여 API 호출 실패를 뿜어내는 현상이 관측되었음.

해결 방안: 복합 데이터 셋 처리 시 인덱싱 효율을 극대화하기 위해, SQL 명세와 런타임 클라이언트(rpc-migration.ts) 양측 모두에서 배치 고유 식별자 키인 p_batch_id 인자 값을 첫 번째 최상단 인덱스 매개변수로 전격 재배치하여 호출 지연 및 예외를 완벽하게 해소하였음.

타입스크립트

4. 데이터베이스 인프라 크래시 디버깅 사례

스프린트 막바지 단계에서 원격 Supabase 인프라 레이어와 소스 코드 간의 교차 통합 테스트 중 치명적인 시스템 예외가 감지되어 즉각 처리를 단행하였음.

ㄱ. PGRST202 Schema Cache Not Found 오류 정복

데이터베이스 단에서 프로시저 RPC 함수를 DROP 후 다시 CREATE 하는 수동 마이그레이션 작업을 반복 전개하는 과정에서, Supabase의 상위 게이트웨이 파서인 PostgREST 엔진이 과거의 함수 명세 스키마 캐시를 그대로 잔존 시켜 발생하는 함수 부재(function not found) 크래시가 포착되었음.

해결 및 복구 파이프라인

  1. 인프라 완전 삭제: 꼬여 있던 과거 함수 아티팩트 개체들을 완전히 데이터베이스 내부에서 DROP 소멸시켰음.
  2. 캐시 플러시(Flush) 명령 송신: 원격 SQL 에디터 파이프라인에 NOTIFY pgrst, 'reload schema' 시그널 스크립트를 직접 쏘아 올려 게이트웨이 레이어의 메모리 캐시 인프라를 강제 리프레시 처리하였음.
  3. 조인 문법 폴백: 링크 테이블 구조 개편에 따라 관계 오인으로 발생하던 !inner 조인 문법 에러 레이어들을 안전하게 추상화된 ProductFilter 헬퍼 모듈 호출 방식으로 대체하여 방어 코드를 마감하였음.

5. 차기 인수인계 가이드라인

이번 정규화 및 트랜잭션 고도화 스프린트를 통해 src/repositories/migration-repository.ts 기반의 견고한 레포지토리 패턴이 완성되었으며, ESLint 정적 분석 통과 및 프로덕션 배포용 본 빌드 테스트를 완벽하게 통과(✓ Compiled successfully) 하였음.

시스템 결함이 완전 소멸된 만큼 다음 릴리즈 공정을 이어받을 후속 개발팀은 반드시 아래의 3대 인프라 상태를 크로스 체크해야 함.

RPC 배포 검증 명령어 구동: Supabase SQL Editor에 SELECT proname, pg_get_function_arguments(oid) FROM pg_proc WHERE proname LIKE 'migrate%'; 구문을 실행하여 4대 프로시저가 정상 상주 중인지 정량 확인할 것.

파라미터 인덱스 동기화 상태: 클라이언트 단에서 트랜잭션을 쏠 때 p_batch_id가 최선행 파라미터로 명시되어 나가는지 코드 레이어 점검할 것.

크론 시크릿(CRON_SECRET) 확인: 가비지 컬렉터 함수인 cleanup_orphaned_migration_data를 주기적으로 트리거해 줄 스케줄러 환경 변수가 정상 래핑되어 있는지 확인할 것.

댓글 남기기