경계선 지능 특성을 가진 아동을 위한 학습 플랫폼 Banolim의 Spring Boot 기반 백엔드 서버입니다.
Banolim은 경계선 지능 특성을 가진 아동을 위한 학습 플랫폼입니다.
문장 이해, 어휘 학습, 감정 표현 및 사회적 상황 이해를 돕기 위해 학습 기능과 게임적 요소를 결합했습니다.
본 레포지토리는 Banolim 서비스의 Spring Boot 기반 백엔드 서버입니다.
프론트엔드 요청 처리, 사용자 및 학습 데이터 관리, FastAPI 서버 연동, AWS RDS 데이터베이스 접근, GitHub Actions 기반 배포 자동화 연동을 담당합니다.
| 기능 | 설명 |
|---|---|
| 문장분해 | 긴 문장을 의미 단위로 나누어 학습하는 블록 맞추기 기능입니다. 사용자는 단어와 구절 블록을 알맞은 위치에 배치하며 문장 구조를 익힙니다. 힌트보기와 단어검색 기능을 통해 어려운 문장도 단계적으로 이해할 수 있습니다. |
| 눈치코치 | 4개의 챗봇 캐릭터와 대화하며 사회적 상황을 연습하는 기능입니다. 사용자는 상황에 맞는 대화를 이어가며 감정 표현과 소통 방식을 익힙니다. 대화 과정에서 마음의 온도를 올리며 게임처럼 학습할 수 있습니다. |
| 나만의 단어장 | 학습 중 모르는 단어를 검색하고 저장할 수 있는 개인 단어장 기능입니다. 저장한 단어는 지식그래프로 시각화되어 단어 간 관계를 확인할 수 있습니다. 단어의 뜻과 연결 관계를 함께 보며 어휘 이해를 확장할 수 있습니다. |
| 대시보드 | 출석체크, 오답노트, 챗봇 로그를 한 화면에서 확인하는 학습 관리 기능입니다. 사용자는 학습 활동으로 XP를 얻고, 누적 경험치에 따라 등급과 캐릭터를 성장시킬 수 있습니다. 학습 달력과 진행 상태를 통해 자신의 학습 기록을 쉽게 확인할 수 있습니다. |
Banolim Backend는 프론트엔드, FastAPI 서버, 데이터베이스를 연결하는 중심 API 서버 역할을 수행합니다.
- 프론트엔드 API 요청 처리
- 사용자 정보 및 학습 데이터 관리
- 문장분해 기능에서 FastAPI 서버 호출
- 눈치코치 기능에서 FastAPI 서버 호출
- 단어장 및 지식그래프 관련 데이터 관리
- 출석체크, XP, 레벨 등 대시보드 데이터 관리
- AWS RDS 기반 PostgreSQL 데이터베이스 접근
- Neo4j 기반 지식그래프 데이터 관리
- GitHub Actions 기반 CI/CD 및 배포 자동화 연동
본 프로젝트는 기능 도메인별로 패키지를 분리하고, 각 도메인 내부에서 계층별 역할을 나누어 관리합니다.
src
└─ main
├─ java
│ └─ com.banolim.backend
│ ├─ domain
│ │ └─ {domain}
│ │ ├─ entity
│ │ ├─ exception
│ │ ├─ repository
│ │ ├─ service
│ │ └─ web
│ │ ├─ controller
│ │ └─ dto
│ │
│ └─ global
│
└─ resources
└─ application.properties
| Package | Description |
|---|---|
domain |
서비스의 핵심 도메인 로직을 관리하는 패키지 |
domain.{domain} |
기능별 도메인 단위 패키지 |
domain.{domain}.entity |
JPA Entity 및 도메인 모델 관리 |
domain.{domain}.repository |
데이터베이스 접근 계층 |
domain.{domain}.service |
주요 비즈니스 로직 처리 계층 |
domain.{domain}.exception |
도메인별 예외 처리 관리 |
domain.{domain}.web.controller |
도메인별 클라이언트 API 요청 처리 계층 |
domain.{domain}.web.dto |
도메인별 API 요청 및 응답 DTO 관리 |
global |
전역 설정, 공통 응답, 공통 예외 처리를 관리하는 패키지 |
resources |
애플리케이션 설정 파일 관리 |
본 프로젝트는 GitHub Actions를 이용하여 백엔드 서버의 빌드 및 Docker 이미지 배포 과정을 자동화했습니다.
push to main/develop
↓
GitHub Actions
↓
Gradle Build
↓
Docker Image Build & Push
↓
Docker Hub
main branch only
↓
Repository Dispatch to Infra
↓
Deploy
| Branch | 동작 |
|---|---|
develop |
Gradle Build, Docker Image Build & Push |
main |
Gradle Build, Docker Image Build & Push, Infra Repository 배포 트리거 |
gimn70009(김나영) Backend Developer Global 패키지 구축 카카오 로그인 눈치코치 기능 |
youserlol(나윤서) Backend Developer 카카오 로그인 문장분해 기능 대시보드 기능 |
7hokerz(임주혁) Backend Developer 지식그래프 기능 대시보드 기능 |
로그인 기능을 구현하면서 처음에는 Spring Security 설정이 어떤 순서로 동작하는지 이해하기 어려웠습니다.
특히 카카오 OAuth2 로그인을 적용하는 과정에서 요청이 컨트롤러로 바로 들어오는 것이 아니라 여러 Security Filter를 거쳐 처리된다는 점을 확인하게 되었습니다.
이 부분을 이해하기 위해 Spring Security 공식 문서와 여러 구현 사례를 찾아보며 인증 요청, 로그인 성공 처리, 사용자 정보 연동 흐름을 정리했습니다.
그 결과 단순히 로그인 기능을 붙이는 것을 넘어서, Spring Security 기반 인증 구조가 어떻게 동작하는지 조금 더 명확히 이해할 수 있었습니다.
프론트엔드와 연동하는 과정에서 CORS 설정을 추가했음에도 요청이 계속 막히는 문제가 있었습니다.
처음에는 WebMvcConfigurer 설정만 확인했지만, 구글링과 Spring Security 관련 자료를 찾아보며 Security Filter Chain에서도 CORS 설정이 필요할 수 있다는 점을 알게 되었습니다. 이후 CorsConfigurationSource를 Bean으로 등록하고 Security 설정과 연결하여, 인증 필터를 거치는 요청에도 CORS 정책이 적용되도록 수정했습니다.
그 결과 프론트엔드 요청이 정상적으로 처리되었고, Spring Security 환경에서는 CORS를 MVC 설정과 Security 설정 관점에서 함께 봐야 한다는 점을 배웠습니다.
처음 OAuth2 로그인 기능을 구현하면서 카카오 인증 완료 후 전달되는 Authorization Code를 직접 처리해야 한다고 생각했습니다.
특히 프론트엔드로 리다이렉트되는 구조를 설계하는 과정에서 OAuth 인증 코드를 백엔드에서 받아 처리하는지, 프론트엔드에서 받아 다시 백엔드로 전달해야 하는지 흐름이 명확하지 않아 혼란이 있었습니다.
Spring Security OAuth2 로그인 구조를 분석하며 oauth2Login(), CustomOAuth2UserService, OAuth2SuccessHandler의 동작 과정을 추적한 결과,
현재 프로젝트는 Spring Security가 /login/oauth2/code/{provider} 엔드포인트를 자동으로 처리하는 구조임을 확인했습니다.
이를 통해 OAuth 인증 코드를 직접 처리하는 API를 구현할 필요 없이, 로그인 성공 이후 OAuth2SuccessHandler에서 JWT를 발급하고 프론트엔드로 리다이렉트하는 방식으로 문제를 해결하였습니다.
이 과정에서, OAuth2 로그인 흐름과 Spring Security Filter Chain 기반 인증 구조를 더욱 명확히 학습할 수 있었습니다.
GraphRepository.java 31-59 Neo4j cypher 쿼리를 이용하여 User와 Word 간 관계 쿼리에서 발생한 문제. 유저가 선택한 단어 목록과 단어 간 관계 정보를 함께 조회할 때, 연관 관계가 존재하지 않으면 전체 결과가 null로 누락되는 문제가 발생했습니다. 기존 쿼리의 MATCH 구문은 패턴이 일치하는 행만 반환하므로, 연결된 관계가 없으면 UNWIND 이후의 행 전체가 탈락하여 앞서 수집한 단어 데이터까지 함께 소멸했기 때문입니다. 이를 해결하기 위해 매칭되는 패턴이 없더라도 행을 탈락시키지 않는 OPTIONAL MATCH 구문으로 변경했습니다. 이 수정을 통해 단어 간 관계가 없는 상태에서도 선택한 단어 정보는 유실 없이 정상 조회되며, 관계 데이터는 빈 배열([])로 안전하게 반환됩니다.