# 06. 의사결정 기록 이 문서는 프로젝트에서 중요한 기술 선택을 왜 했는지 기록합니다. 형식은 가벼운 ADR(Architecture Decision Record) 스타일을 따릅니다. ## ADR-001. UI는 Streamlit을 사용한다 - 상태: 채택 - 날짜: 2026-06-07 ### 배경 이 프로젝트는 문제풀이 화면, PDF 업로드 화면, 처리 현황 화면을 빠르게 만들고 검증해야 합니다. 개인 프로젝트 단계에서는 복잡한 프론트엔드 구조보다 기능 검증 속도가 중요합니다. ### 결정 웹 UI는 Streamlit으로 만든다. ### 이유 - Python 코드만으로 웹 화면을 빠르게 만들 수 있다. - 데이터 처리 코드와 연결하기 쉽다. - 개인 프로젝트나 프로토타입에 적합하다. - 문제 풀이, 업로드, 표, 진행률 표시 같은 화면을 빠르게 구성할 수 있다. ### 결과 빠르게 기능을 만들 수 있는 대신, 세밀한 UI/UX 커스터마이징에는 한계가 있습니다. 사용자가 많아지거나 복잡한 인터랙션이 필요해지면 별도 프론트엔드 전환을 검토할 수 있습니다. ## ADR-002. 메인 데이터베이스는 PostgreSQL을 사용한다 - 상태: 채택 - 날짜: 2026-06-07 ### 배경 문제, 정답, 풀이 기록, PDF 처리 작업 상태는 정확하게 저장되어야 합니다. Docker와 Airflow를 함께 쓰는 구조에서는 파일 기반 SQLite보다 서버형 데이터베이스가 더 적합합니다. ### 결정 메인 데이터베이스는 PostgreSQL을 사용한다. ### 이유 - 문제와 풀이 기록을 안정적으로 저장할 수 있다. - Docker Compose에서 서비스로 띄우기 쉽다. - 향후 배포 환경에서도 그대로 사용할 수 있다. - Airflow 작업과 Streamlit 앱이 같은 DB를 바라볼 수 있다. ### 결과 로컬 실행 시 PostgreSQL 컨테이너가 필요합니다. 대신 실제 배포에 가까운 구조로 개발할 수 있습니다. ## ADR-003. 유사 문제 검색은 Chroma를 사용한다 - 상태: 채택 - 날짜: 2026-06-07 ### 배경 문제풀이 앱에서는 단순 키워드 검색뿐 아니라 의미가 비슷한 문제를 찾는 기능이 필요합니다. ### 결정 유사 문제 검색을 위해 Chroma를 사용한다. ### 이유 - 로컬에서 벡터 검색을 실험하기 쉽다. - 문제 임베딩을 저장하고 유사도를 계산할 수 있다. - PostgreSQL과 역할을 분리할 수 있다. ### 결과 PostgreSQL에는 원본 문제 데이터를 저장하고, Chroma에는 검색용 벡터를 저장합니다. 임베딩 모델이 바뀌면 기존 인덱스와 차원이 맞지 않을 수 있으므로 모델별 컬렉션 관리가 필요합니다. ## ADR-004. PDF 처리 작업은 Airflow로 관리한다 - 상태: 채택 - 날짜: 2026-06-07 ### 배경 PDF 파싱, 품질 검증, 이미지 분석, 벡터 색인은 시간이 오래 걸릴 수 있습니다. 웹 요청 안에서 모두 처리하면 화면이 멈추거나 실패 추적이 어려워질 수 있습니다. ### 결정 PDF 처리 파이프라인은 Airflow DAG로 실행하고 관리한다. ### 이유 - 긴 작업을 백그라운드에서 실행할 수 있다. - 실패한 작업을 추적하기 쉽다. - 단계별 로그를 확인할 수 있다. - 나중에 재실행이나 예약 작업으로 확장하기 좋다. ### 결과 구조는 더 명확해지지만 Airflow 자체 운영 비용이 생깁니다. 개인 프로젝트 단계에서는 복잡도가 늘어날 수 있으므로, 꼭 필요한 긴 작업부터 Airflow로 분리합니다. ## ADR-005. 실행 환경은 Docker Compose로 통일한다 - 상태: 채택 - 날짜: 2026-06-07 ### 배경 이 프로젝트는 웹 앱, PostgreSQL, Airflow, Chroma, PDF 처리 라이브러리 등 여러 구성 요소를 함께 사용합니다. 로컬 환경에 직접 설치하면 버전 차이와 설정 차이가 생길 수 있습니다. ### 결정 개발과 배포의 기본 실행 방식은 Docker Compose로 통일한다. ### 이유 - 여러 서비스를 한 명령으로 실행할 수 있다. - 다른 환경에서도 비슷하게 재현할 수 있다. - PostgreSQL과 Airflow를 함께 실행하기 쉽다. - 향후 서버 배포와 연결하기 좋다. ### 결과 Docker를 모르면 처음 실행 장벽이 생길 수 있습니다. 그래서 README와 배포 문서에 실행 방법을 명확히 기록합니다. ## ADR-006. 향후 배포 대상은 Oracle Cloud Ubuntu로 계획한다 - 상태: 계획 - 날짜: 2026-06-07 ### 배경 포트폴리오 프로젝트로 남기려면 로컬 실행뿐 아니라 실제 서버 배포 경험도 중요합니다. ### 결정 향후 Oracle Cloud의 Ubuntu 서버에 Docker 기반으로 배포하는 것을 목표로 한다. ### 이유 - Ubuntu 서버는 Docker 배포 자료가 많다. - 개인 프로젝트 배포 연습에 적합하다. - Streamlit, PostgreSQL, Airflow를 한 서버에서 실험하기 좋다. - 실제 접속 가능한 포트폴리오 결과물을 만들 수 있다. ### 결과 배포 전에는 보안, 환경 변수, 데이터 백업, HTTPS 설정을 정리해야 합니다. ## ADR-007. 문제 저장 전 품질 게이트를 둔다 - 상태: 채택 - 날짜: 2026-06-07 ### 배경 PDF 파싱은 항상 정확하지 않습니다. 잘못 나뉜 문제나 정답이 비어 있는 문제가 그대로 저장되면 학습 경험이 나빠집니다. ### 결정 PDF 파싱 후 바로 저장하지 않고, 파싱 품질 검증과 Quality Gate 단계를 둔다. ### 이유 - 잘못 파싱된 문제를 줄일 수 있다. - 문제 청킹 상태를 자동으로 점검할 수 있다. - 사람이 모든 문제를 직접 검수하는 부담을 줄일 수 있다. - LLM 사용을 최소화하면서도 품질을 높일 수 있다. ### 결과 파이프라인 단계는 늘어나지만, 문제 데이터의 신뢰도를 높일 수 있습니다. 앞으로는 품질 리포트를 UI에서 더 보기 쉽게 만드는 작업이 필요합니다. ## ADR-008. 문제 유형과 정답 비교는 별도 계층에서 표준화한다 - 상태: 채택 - 날짜: 2026-06-07 ### 배경 자격증 문제에는 단일 선택, 복수 선택, Yes/No 진술형, 핫스팟, 드래그 앤 드롭, 공통 지문 문제가 섞여 있습니다. 원본 데이터의 `question_type`도 `Hotspot (True/False)`처럼 다양한 문자열로 들어올 수 있습니다. ### 결정 문제 유형은 `question_type_metadata_service.py`에서 내부 표준 유형으로 변환하고, 정답 비교는 `answer_normalizer.py`에서 처리한다. ### 이유 - 화면, 검수, 채점 로직이 서로 다른 기준을 쓰는 문제를 줄일 수 있다. - 새 문제 유형 alias가 들어와도 한 곳에서 추가할 수 있다. - Yes/No와 순서형 답안처럼 일반 객관식과 다른 채점 방식을 분리할 수 있다. ### 결과 문제풀이 화면과 자동 검수 서비스가 같은 문제 유형 기준을 공유합니다. 앞으로 새 유형을 추가할 때는 먼저 표준 유형 변환과 테스트를 추가해야 합니다. ## ADR-009. 배포 전 품질 검사는 스크립트와 GitHub Actions로 자동화한다 - 상태: 채택 - 날짜: 2026-06-07 ### 배경 Hugging Face Space에는 DB 전체가 아니라 seed 파일과 정적 이미지를 올립니다. 따라서 seed 구조, 문제 유형 alias, 정답 정규화가 깨지면 배포 후 문제풀이가 바로 영향을 받습니다. ### 결정 `scripts/check_quality.py`를 추가하고, GitHub Actions에서 핵심 테스트와 문법 검사를 실행한다. ### 이유 - push 전에 로컬에서 같은 검사를 실행할 수 있다. - GitHub에서도 최소 품질 검사를 자동으로 남길 수 있다. - 무거운 OCR/LLM 의존성을 설치하지 않고 핵심 도메인 로직만 빠르게 검증할 수 있다. ### 결과 현재 자동 검사는 문제 유형/정답/seed 리포트 중심입니다. 이후 PDF 파싱과 DB 저장 테스트까지 점진적으로 넓힐 수 있습니다.