기술

스키마 설정을 파일과 DB 양쪽에 뒀더니, 결국 어긋나기 시작했습니다

2026.04.2110분 읽기

파일에서 시작한 설정 관리

프로젝트 초반에는 설정을 전부 파일로 관리했습니다. ontology.yaml에 온톨로지 스키마를 담고, prompts/ 아래에 문서 유형별 프롬프트를 뒀거든요. 파일 관리가 편했습니다. Git으로 버전 추적되고, 에디터로 바로 열어볼 수 있고, 서버에 올라가는 코드와 같이 배포되니까요.

그런데 운영하다 보니 UI에서 프롬프트를 수정할 일이 생겼습니다. 브라우저에서 직접 프롬프트를 고치고 저장하려면 DB에 넣어야 했거든요. 그래서 Spring Boot 쪽에 prompt_version 테이블을 만들고, UI에서 저장하면 거기 들어가도록 했습니다. 온톨로지 거버넌스 승격도 DB에 쌓이게 했고요(ontology_version 테이블).

여기서 문제가 시작됩니다. AI Server(FastAPI)는 여전히 파일을 읽고 있었거든요.


파일에서 읽는데 DB에서 저장했다

상황을 정리하면 이랬습니다.

Spring Boot UI → DB에 저장 (prompt_version, ontology_version)

AI Server → prompts/rag/system.md, ontology.yaml 파일을 직접 읽음

같은 프롬프트가 두 군데 있는 겁니다. DB에도 있고, 파일에도 있고.

"그럼 둘 다 업데이트하면 되잖아" 싶은데, 실제로는 계속 어긋나거든요. UI에서 저장하면 DB만 바뀝니다. AI Server는 파일을 읽으니까 옛 프롬프트로 추출을 계속해요. 사용자는 "고쳤는데 왜 안 바뀌지?" 하는 상황이 반복됩니다.

반대로 파일만 수정하면 DB에는 옛 버전이 남아서, UI에서 활성 버전을 조회하면 옛날 것이 보여요. 어느 쪽이 진짜인지 매번 헷갈립니다.

서버 환경에서는 문제가 하나 더 있었는데요. 파일 경로가 로컬과 서버에서 달라서, 같은 코드인데 어느 쪽에선 파일을 못 찾는 일도 생기더라고요.

1.jpeg


한 정보는 한 곳에서만 관리한다

Single Source of Truth라는 원칙이 있습니다. 한 정보는 한 곳에서만 관리해야 한다는 건데요. 같은 정보를 두 군데에 두면 언젠가 어긋나게 돼있거든요. 저희가 겪은 문제가 정확히 그거였어요.

그럼 어디를 메인으로 할까. 파일이냐 DB냐.

기준

파일

DB

UI에서 수정

어려움

쉬움

Git 버전 관리

자연스러움

별도 설계 필요

배포 일체화

가능

가능

장애 복구

즉시

백업 필요

UI에서 사용자가 직접 수정하고, 버전 이력을 축적해야 하는 상황이었습니다. 그러면 DB를 메인으로 할 수밖에 없어요. 다만 파일을 아예 없애는 건 겁이 났습니다. DB에 장애가 나면 서버 자체가 기동이 안 될 수도 있거든요. 프롬프트는 매 요청마다 읽는 설정이라서요.

그래서 정한 원칙은 이렇습니다.

읽기: DB 조회 → 실패 시 → 파일에서 읽기 (폴백)

쓰기: DB 저장 → 파일에도 동기화

DB가 메인, 파일은 폴백 + 백업. 평상시엔 DB 하나로 운영되지만 장애 상황에서도 서비스가 죽지 않습니다. ontology.yaml이 Single Source of Truth라는 원칙을 글에서 쓴 적이 있는데, 그 "하나의 진실"이 파일에서 DB로 이동한 셈이에요.


테이블 하나와 로더 하나로 합쳤습니다

먼저 테이블을 합쳤습니다. prompt_versionontology_version 두 개를 config_version 하나로 통합했어요.

config_version
├── type: ontology / prompt
├── path: ontology.yaml, prompts/rag/system.md 등
├── content: 전체 텍스트
└── is_active: 현재 활성 버전

같은 구조(path + content + 활성 플래그)를 공유하는데 굳이 테이블 두 개로 관리할 이유가 없었거든요. type 컬럼으로 구분하면 충분합니다.

그리고 로더를 통합했습니다. AI Server에서 파일 읽던 코드를 전부 한 함수로 모았어요.

# shared/config_loader.py
load_config("ontology.yaml")           # DB → 파일 폴백
load_config("prompts/rag/system.md")   # DB → 파일 폴백
save_config(path, content, note)       # DB 저장 + 파일 동기화

기존에 곳곳에 흩어져 있던 with open("prompts/...") as f: 같은 코드가 전부 load_config(...) 한 줄로 바뀝니다. 어떤 설정이든 이 함수 하나만 거치게 만들면, 나중에 폴백 로직을 고치거나 DB 인덱스를 걸 때 한 군데만 손대면 돼요.

이 구조는 직전에 정리했던 임포트 파이프라인의 Canonical Path 원칙과 같은 발상이에요. "모든 경로가 한 관문을 지나게 만든다"는 거요.

2.jpeg


Spring Boot는 프록시로

여기서 한 단계 더 정리했습니다. 원래 Spring Boot에 PromptService.java, PromptVersion.java, PromptController.java, PromptVersionRepository.java 같은 프롬프트 도메인 코드가 꽤 있었거든요. 전부 삭제하고, AI Server의 /api/config/* 엔드포인트를 프록시하는 컨트롤러 하나로 대체했습니다.

이유는 단순해요. 프롬프트·온톨로지는 AI 도메인이니까 AI Server에서 관리하는 게 맞고, Spring Boot가 중간에서 비즈니스 로직을 가지면 또 이중 소스가 되거든요. "내가 가진 프롬프트 데이터"와 "AI Server가 가진 프롬프트 데이터"가 따로 돌아가기 시작합니다.

정리한 역할 분리는 이렇습니다.

Spring Boot: 웹 서비스 도메인(대화, 북마크, 알림, 통계) 직접 처리

Spring Boot → AI Server 프록시: AI 도메인(온톨로지, 프롬프트, RAG, 임포트)

한 쪽이 주인이면 그 쪽에만 로직을 둔다는 원칙. 이중 소스를 테이블 레벨에서 해결하고 나니까, 서버 간 역할 분리에서도 같은 원칙을 적용하게 되더라고요.


통합해도 운영 규칙은 나눠야 했습니다

테이블을 합치긴 했는데, 온톨로지와 프롬프트의 운영 방식은 달라야 했어요.

온톨로지 변경은 "새 타입 승격" 같은 명확한 이벤트가 있어서, 문서를 저장할 때 ontology_version_id를 자동으로 기록해둡니다. 나중에 재임포트가 필요한지 판단할 때 쓰려고요. 새 노드 타입이 승격되면 기존 문서를 다시 뽑아야 그 타입이 붙거든요.

프롬프트 변경은 자동 추적을 안 합니다. 프롬프트 변경은 품질 개선이지 스키마 변경이 아니거든요. 문서 유형별로 다른 프롬프트를 쓰는데(엑셀은 classify.md, PPT는 extract_entity.md 식), 어떤 프롬프트가 어떤 문서에 영향을 주는지 매핑하는 것도 복잡하고요.

프롬프트를 수정한 뒤 재임포트가 필요하다고 판단되면, 사용자가 파이프라인에서 수동으로 재임포트합니다. 자동으로 하면 프롬프트 한 번 고칠 때마다 전체 재임포트가 돌아서 비용이 크거든요.

구분

역할

변경 영향

추적

온톨로지

무엇을 뽑을지 정의

새 타입 → 재임포트 필수

자동

프롬프트

어떻게 뽑을지 지시

추출 품질 변화 → 재임포트 선택

수동 판단

같은 테이블(config_version)에 저장해도, type에 따라 운영 규칙은 분리합니다. 테이블 통합이 곧 운영 통합은 아니거든요.


마무리

파일에서 시작해서 DB로 옮겼고, 파일은 폴백으로 남겼습니다. 테이블은 prompt_versionontology_versionconfig_version 하나로 합쳤고, 로더도 shared/config_loader.py로 통일했습니다. Spring Boot는 프롬프트·온톨로지에 대해 프록시 역할만 하게 정리했어요.

"설정을 파일에 둘까 DB에 둘까"는 프로젝트 초반에 한 번 정해놓고 끝내는 게 좋습니다. 양쪽 다 지원한다는 선택지가 가장 편해 보이는데, 운영하다 보면 두 소스가 어긋나는 시점이 반드시 오거든요. 어느 쪽을 메인으로 할지 먼저 정하고, 다른 쪽은 복구용 백업으로만 쓰는 구조를 추천합니다.

#SEO태그:설정관리#SingleSourceOfTruth#DB-First#온톨로지#프롬프트관리#config_version#FastAPI#SpringBoot#AI전환기