“backend + admin + ai 어떻게 설계할까?”
빠른 개발과 효율적인 유지보수를 위해, 저는 직관적으로 익숙한 기술들을 선택해 백엔드를 구성했습니다. 또한, AI 관련 기능 구현을 위해 Python 기반의 FastAPI를 도입하여, 전체 시스템의 성능과 관리의 편리함을 극대화했습니다. 오늘 포스트에서는 제가 왜 특정 기술을 선택했는지, 그리고 Monorepo 구조를 어떻게 활용했는지에 대해 상세히 풀어보고자 합니다.
먼저, 빠르게 개발할 수 있고 익숙한 Node.js, Express, 그리고 MySQL을 기반으로 백엔드를 구축하였습니다. 이 덕분에 기본적인 API 서비스(라우트, 모델, 컨트롤러 아키텍처)를 간단하게 구현할 수 있었으며, 사용자 인증은 JWT(JSON Web Token)를 통해 처리하였습니다. 반면, AI와 관련된 API는 Python의 FastAPI 프레임워크로 설계되었습니다. FastAPI는 비동기 처리와 높은 성능을 제공하므로, AI 기능 구현 및 퀴즈 시스템 운영에 적합했습니다.
각 API 서비스는 기본적인 routes, models, controller 구조로 설계되었습니다. 이로 인해 코드의 가독성과 유지보수성이 높아졌으며, 사용자 인증 및 보안을 위해 JWT 방식을 채택했습니다. 이러한 설계는 확장성이 뛰어나며, 팀 내 협업 시에도 명확한 역할 분담이 가능한 환경을 마련해 주었습니다.
여러 개의 개별 repository를 관리하는 번거로움을 줄이고자 Monorepo 방식을 선택했습니다. Monorepo를 사용하면 모든 프로젝트를 한 곳에서 관리할 수 있어, 협업 및 유지보수 측면에서 많은 이점을 제공합니다. 구체적인 디렉토리 구성은 다음과 같습니다:
apps
admin: 관리용 API 서버
ai-engine: AI 관련 로직과 문제 추천 API 서버
app: 일반 클라이언트용 API 서버
package
common: 여러 모듈에서 공통으로 사용하는 라이브러리
이를 통해 한 repository 내에서 각각의 API 서버를 동시에 실행하고 관리할 수 있습니다.
예를 들어,
localhost:10000 — admin API
localhost:10001 — ai-engine API
localhost:10002 — app API
공동 라이브러리는 package/common 내에 모듈화하여 각 애플리케이션에서 손쉽게 재사용할 수 있게 했습니다. 또한, pnpm을 활용하여 패키지 관리 속도와 의존성 관리를 효율적으로 처리할 수 있었습니다.
프로젝트의 ‘ai-engine’이라는 이름은 단순하지만 ㅋㅋ 요즘 나이가 들어서 좀 긴게 좋다...ㅋ
특히 AI 엔진에서는 TF-IDF 기반의 문제 추천 로직을 구현했습니다. 사용자에게 이미 풀었던 문제를 제외하고, 과거 틀렸던 문제나 다른 사용자들이 많이 틀린 문제 등을 다양한 라벨로 분류하여 추천하는 전략을 도입했습니다.
캐싱 전략: FastAPI 기반의 간단한 퀴즈 시스템 내에서, Redis에 미리 문제들을 캐싱하고 관리합니다.
데이터 관리: MySQL을 통해 문제와 사용자 정보를 확보, 새로운 스테이지가 시작될 때 캐시를 미리 준비합니다.
보충 로직: 만약 캐시된 문제가 부족할 경우, 유사 카테고리나 인접 학년의 문제를 보충함으로써 사용자에게 최적의 문제를 제공하고, Redis에
더 이상 데이터가 남지 않은 경우에는 TF-IDF 알고리즘을 통해 유사 문제를 추천합니다.
이러한 구조는 사용자 맞춤형 문제 제공은 물론, 학습량과 난이도의 밸런스를 유지하는 데 큰 도움이 되었다