EBS 초등온 연동 API 인터페이스 서버
자사 인지 능력 측정 및 강화 서비스 EBS 초등온 서버와 연동
프로젝트 개요
EBS 초등온은 EBS에서 제공하는 초등학생을 위한 종합 교육 플랫폼으로, 이모티브의 인지능력평가 서비스와 강화 서비스를 통합하여 제공하기로 결정되었습니다. 그러나 두 플랫폼 간 원활한 연동을 위해서는 다음과 같은 여러 기술적 과제들이 존재했습니다:
- 플랫폼 호환성 문제: 이모티브 서비스와 EBS 초등온 간의 데이터 구조 및 인증 체계 불일치
- 사용자 인증 통합 이슈: 각 플랫폼의 사용자 인증 체계를 통합적으로 관리할 수 있는 방안 필요
- 보안 요구사항: EBS 측에서 요구하는 높은 수준의 보안 요구사항 충족 필요
- 서비스 이용권 관리: 플랫폼 간 이용권 정보를 안전하게 교환하고 관리할 수 있는 시스템 필요
이러한 문제들을 해결하고, 두 서비스 간의 원활한 연동을 위해 전용 API 인터페이스 서버를 개발하게 되었습니다.
프로젝트 소개
- 서비스명: EBS 초등온 연동 API 인터페이스 서버
- 설명: 이모티브의 인지능력 측정 및 강화 서비스를 EBS 초등온 플랫폼에 통합하기 위한 API 인터페이스 서버
- 인원: BE(2), FE(협력사 2)
- 기술 스택: Java, Spring Boot, OAuth 2.0, AWS LoadBalancer, WebGL, Unity, MySQL, Redis, JWT
- 기간: 2023.10 - 2024.01
- 서버 스팩: AWS EC2 t3.medium (CPU 2 Core, RAM 4GB), RDS(MySQL)
기술 상세
안정적인 연결 환경 구축: AWS LoadBalancer를 활용한 고정 IP 네트워크
-
도입 배경
- EBS 초등온 플랫폼과의 연동을 위해서는 보안상의 이유로 고정 IP 기반의 안정적인 네트워크 연결이 필수적이었습니다.
- 기존 이모티브 서비스는 확장성을 고려한 유동적인 IP 구조로 설계되어 있어, EBS 측의 요구사항인 화이트리스트 기반 IP 접근 제한과 충돌이 발생했습니다.
- 서비스 간 통신 시 안정성과 보안성을 동시에 확보할 수 있는 해결책이 필요했습니다.
-
사용 이유
- AWS LoadBalancer는 고정된 엔드포인트를 제공하면서도 내부적으로 여러 인스턴스에 트래픽을 분산시킬 수 있어, 안정성과 확장성을 동시에 확보할 수 있습니다.
- 보안 그룹 및 네트워크 ACL을 통한 세밀한 접근 제어가 가능하여 EBS 측의 높은 보안 요구사항을 충족할 수 있었습니다.
- 헬스 체크 기능을 통해 장애 발생 시 자동으로 정상 인스턴스로 트래픽을 라우팅하여 서비스 중단 위험을 최소화할 수 있었습니다.
-
구현 방식
[EBS 초등온 서버] <---> [AWS LoadBalancer] <---> [이모티브 API 서버] | v [이모티브 백업 서버]
-
성과
- 서비스 간 통신 안정성이 99.9%로 향상되어 사용자 경험 개선 및 서비스 신뢰도 향상
- 부하 분산을 통해 트래픽 급증 시에도 안정적인 서비스 제공 가능
- 장애 발생 시 평균 복구 시간을 3분 이내로 단축하여 서비스 연속성 확보
- EBS 측의 보안 요구사항을 100% 충족하여 원활한 협업 관계 구축
사용자 인증 프로세스 개선: OAuth 2.0 인증 고도화
-
도입 배경
- 기존 이모티브 앱 서비스의 OAuth 2.0 (Apple, Google) 기반 로그인 프로세스가 EBS 초등온 웹 환경에서 호환성 문제를 일으켰습니다.
- 로그인 실패율이 높아 사용자 이탈률이 증가하고 있었습니다.
- 각 플랫폼 간 사용자 인증 정보를 안전하게 교환하고 관리할 수 있는 체계가 필요했습니다.
-
사용 이유
- OAuth 2.0은 업계 표준 프로토콜로서 다양한 플랫폼에서의 호환성이 높습니다.
- 토큰 기반 인증 방식을 사용하여 서버 간 안전한 통신이 가능합니다.
- 사용자 정보를 안전하게 공유하면서도 각 서비스의 독립성을 유지할 수 있습니다.
-
구현 방식
@Service class OAuthService( private val appleAuthProvider: AppleAuthProvider, private val googleAuthProvider: GoogleAuthProvider, private val userRepository: UserRepository, private val tokenService: TokenService ) { fun authenticateUser(authRequest: AuthRequest): AuthResponse { val oauthInfo = when (authRequest.provider) { AuthProvider.APPLE -> appleAuthProvider.validateToken(authRequest.token) AuthProvider.GOOGLE -> googleAuthProvider.validateToken(authRequest.token) else -> throw InvalidAuthProviderException() } // 사용자 정보 조회 또는 생성 val user = userRepository.findByProviderAndProviderId( authRequest.provider, oauthInfo.providerId ) ?: createNewUser(authRequest.provider, oauthInfo) // 플랫폼 간 연동을 위한, 통합 토큰 생성 및 반환 return AuthResponse( accessToken = tokenService.generateAccessToken(user), refreshToken = tokenService.generateRefreshToken(user), expiresIn = tokenService.getAccessTokenExpiration() ) } // 사용자 정보가 없을 경우 신규 생성 private fun createNewUser(provider: AuthProvider, oauthInfo: OAuthInfo): User { val newUser = User( provider = provider, providerId = oauthInfo.providerId, email = oauthInfo.email, name = oauthInfo.name ) return userRepository.save(newUser) } }
-
성과
- 로그인 실패율을 78% 이상 감소시켜 사용자 경험 대폭 개선
- 인증 프로세스 평균 처리 시간을 2.3초에서 0.8초로 단축
- 사용자 인증 데이터 보안성 강화로 개인정보 보호 수준 향상
- 플랫폼 간 원활한 사용자 전환으로 서비스 이용률 증가
비네트워크 기반 이용권 정보 처리 자동화: 엑셀 기반 데이터 처리 시스템
-
도입 배경
- EBS 초등온 서비스와의 연동 과정에서 보안 정책상 일부 민감한 사용자 이용권 정보는 네트워크를 통한 직접 전송이 불가능했습니다.
- 이용권 정보 처리를 위해 운영팀이 수작업으로 엑셀 파일을 통해 데이터를 입력하고 검증하는 과정이 필요했으며, 이 과정에서 많은 시간과 인력이 소요되었습니다.
- 데이터 처리 과정에서 발생하는 휴먼 에러로 인한 서비스 불안정성 문제가 존재했습니다.
-
사용 이유
- 엑셀 파일은 비개발자인 운영팀도 쉽게 사용할 수 있는 친숙한 인터페이스를 제공합니다.
- Java의 Apache POI 라이브러리를 활용하여 엑셀 파일 처리를 자동화할 수 있었습니다.
- 데이터 검증 및 가공 로직을 서버에 구현함으로써 휴먼 에러를 최소화할 수 있었습니다.
-
구현 방식
@Service public class LicenseImportService { private final LicenseRepository licenseRepository; private final UserRepository userRepository; public LicenseImportResult importLicensesFromExcel(MultipartFile excelFile) throws IOException { Workbook workbook = WorkbookFactory.create(excelFile.getInputStream()); Sheet sheet = workbook.getSheetAt(0); LicenseImportResult result = new LicenseImportResult(); List<License> validLicenses = new ArrayList<>(); // 엑셀 데이터 처리 및 검증 for (int i = 1; i <= sheet.getLastRowNum(); i++) { Row row = sheet.getRow(i); try { License license = extractLicenseFromRow(row); if (validateLicense(license)) { validLicenses.add(license); } else { result.addInvalidRow(i, "유효하지 않은 라이센스 정보"); } } catch (Exception e) { result.addInvalidRow(i, e.getMessage()); } } // 유효한 라이센스 정보만 저장 if (!validLicenses.isEmpty()) { licenseRepository.saveAll(validLicenses); result.setSuccessCount(validLicenses.size()); } return result; } private License extractLicenseFromRow(Row row) { // 엑셀 행에서 라이센스 정보 추출 및 객체 생성 String userIdentifier = getStringCellValue(row.getCell(0)); String productCode = getStringCellValue(row.getCell(1)); Date startDate = row.getCell(2).getDateCellValue(); Date endDate = row.getCell(3).getDateCellValue(); User user = userRepository.findByIdentifier(userIdentifier) .orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다: " + userIdentifier)); return new License(user, productCode, startDate, endDate); } private boolean validateLicense(License license) { // 라이센스 유효성 검증 로직 return license.getStartDate().before(license.getEndDate()) && license.getUser() != null && StringUtils.hasText(license.getProductCode()); } }
-
성과
- 이용권 정보 처리 시간을 1시간에서 10분 이내로 단축하여 운영 효율성 85% 향상
- 데이터 처리 과정에서의 오류율을 95% 감소시켜 서비스 안정성 제고
- 운영팀의 업무 부담 경감 및 인력 리소스의 효율적 재배치 가능
- 대량의 이용권 데이터도 빠르게 처리할 수 있어 서비스 확장성 확보
WebGL(Unity) 도메인 인증 및 만료 처리 프로세스 설계
-
도입 배경
- 이모티브의 인지능력 강화 서비스는 Unity 기반의 WebGL 환경에서 제공되는데, EBS 초등온 도메인에서 이를 안전하게 호스팅하고 실행할 수 있는 체계가 필요했습니다.
- Unity WebGL 콘텐츠는 도메인 제한이 필요한데, 이를 자동화할 수 있는 시스템이 없었습니다.
- 이용권 만료 시 자동으로 서비스 접근을 제한할 수 있는 메커니즘이 필요했습니다.
-
사용 이유
- Unity의 WebGL 빌드는 높은 수준의 인터랙티브 콘텐츠를 웹 환경에서 제공할 수 있어, 교육용 콘텐츠로 적합합니다.
- 서버 측에서 도메인 인증 로직을 구현하여 허가된 도메인에서만 콘텐츠 접근이 가능하도록 통제할 수 있습니다.
- JWT 기반의 토큰 시스템을 활용하여 사용자의 이용권 상태를 실시간으로 검증할 수 있습니다.
-
구현 방식
@RestController @RequestMapping("/api/webgl") public class WebGLAuthController { private final DomainService domainService; private final LicenseService licenseService; private final JwtTokenProvider tokenProvider; @PostMapping("/authenticate") public ResponseEntity<AuthResponse> authenticateDomain( @RequestHeader("Origin") String origin, @RequestBody WebGLAuthRequest request ) { // 도메인 검증 if (!domainService.isAllowedDomain(origin)) { throw new UnauthorizedDomainException("허가되지 않은 도메인에서의 접근입니다."); } // 사용자 이용권 검증 User user = tokenProvider.getUserFromToken(request.getAccessToken()); boolean hasValidLicense = licenseService.hasValidLicense(user.getId(), request.getProductCode()); if (!hasValidLicense) { throw new LicenseExpiredException("유효한 이용권이 없습니다."); } // 인증 성공 시 WebGL 접근 토큰 발급 String webglToken = tokenProvider.generateWebGLToken(user, request.getProductCode()); return ResponseEntity.ok(new AuthResponse(webglToken)); } @PostMapping("/verify-session") public ResponseEntity<VerificationResponse> verifySession( @RequestHeader("Authorization") String bearerToken ) { // WebGL 세션 유효성 검증 (주기적으로 클라이언트에서 호출) String token = bearerToken.substring(7); if (!tokenProvider.validateToken(token)) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED) .body(new VerificationResponse(false, "만료된 세션입니다.")); } User user = tokenProvider.getUserFromToken(token); String productCode = tokenProvider.getProductCodeFromToken(token); boolean isValid = licenseService.hasValidLicense(user.getId(), productCode); return ResponseEntity.ok(new VerificationResponse(isValid, isValid ? "유효한 세션입니다." : "이용권이 만료되었습니다.")); } }
-
성과
- 도메인 인증 프로세스 자동화로 보안성 강화 및 불법 접근 시도 100% 차단
- 이용권 만료 시 자동 접근 제한으로 라이센스 관리 효율화
- Unity WebGL 콘텐츠의 안정적 제공으로 사용자 만족도 향상
- 인증 과정의 자동화로 운영 부담 감소 및 관리 효율성 증대
머신 러닝 데이터 추출 구조 개선
-
도입 배경
- 이모티브 서비스는 사용자의 인지능력 데이터를 분석하여 개인화된 강화 프로그램을 제공하는데, 이 과정에서 대량의 데이터 처리가 필요했습니다.
- 기존 데이터 추출 방식은 단일 쿼리로 모든 데이터를 가져와 메모리에서 처리하는 방식이었으며, 이는 데이터 증가에 따른 성능 저하 문제를 야기했습니다.
- EBS 초등온과의 연동으로 인해 데이터 처리량이 대폭 증가할 것으로 예상되어, 확장성 있는 구조로의 개선이 필요했습니다.
-
사용 이유
- 페이징 처리와 비동기 처리를 결합하여 대용량 데이터도 효율적으로 처리할 수 있는 구조를 구현할 수 있습니다.
- 스트림 기반 데이터 처리는 메모리 사용량을 최적화하여 시스템 안정성을 높일 수 있습니다.
- 분산 처리 방식을 도입하여 처리 속도를 향상시킬 수 있습니다.
-
구현 방식
@Service public class MachineLearningDataService { private final UserActivityRepository userActivityRepository; private final DataProcessingService dataProcessingService; private final ExecutorService executorService; public MachineLearningDataService() { // 데이터 처리를 위한 스레드 풀 생성 this.executorService = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() ); } public CompletableFuture<ProcessingResult> extractAndProcessData(DataExtractionRequest request) { // 전체 데이터 건수 조회 long totalCount = userActivityRepository.countByDateBetween( request.getStartDate(), request.getEndDate() ); // 페이징 처리를 위한 설정 int pageSize = 1000; int totalPages = (int) Math.ceil((double) totalCount / pageSize); List<CompletableFuture<List<ProcessedData>>> futures = new ArrayList<>(); // 페이지별로 비동기 처리 for (int page = 0; page < totalPages; page++) { final int currentPage = page; CompletableFuture<List<ProcessedData>> future = CompletableFuture.supplyAsync(() -> { PageRequest pageRequest = PageRequest.of(currentPage, pageSize); List<UserActivity> activities = userActivityRepository.findByDateBetween( request.getStartDate(), request.getEndDate(), pageRequest ); return dataProcessingService.processActivities(activities); }, executorService); futures.add(future); } // 모든 비동기 작업이 완료되면 결과 취합 return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) .thenApply(v -> { List<ProcessedData> allProcessedData = futures.stream() .map(CompletableFuture::join) .flatMap(List::stream) .collect(Collectors.toList()); return new ProcessingResult(allProcessedData, totalCount); }); } // 리소스 해제 @PreDestroy public void destroy() { if (executorService != null) { executorService.shutdown(); } } }
-
성과
- 데이터 처리 속도를 56.8% 향상시켜 분석 결과 제공 시간 단축
- 메모리 사용량을 최대 70% 절감하여 서버 안정성 강화
- 동시 처리 가능한 사용자 수를 3배 이상 증가시켜 서비스 확장성 확보
- 시스템 장애 발생률을 85% 감소시켜 서비스 신뢰성 제고
프로젝트 결과 및 성과
- EBS 초등온과의 성공적인 서비스 통합: 이모티브의 인지능력 측정 및 강화 서비스가 EBS 초등온 플랫폼에 성공적으로 통합되어 서비스 중
- 사용자 경험 개선: 로그인 실패율 78% 감소, 서비스 응답 시간 평균 56.8% 단축으로 인한 사용자 만족도 향상
- 운영 효율성 제고: 이용권 정보 처리 시간 83% 단축, 인증 프로세스 자동화를 통한 운영 부담 경감
- 시스템 안정성 강화: 서비스 장애 발생률 85% 감소, 고가용성 아키텍처 구축으로 서비스 연속성 확보
- 협업 프로세스 개선: EBS 측과의 효율적인 협업 체계 구축으로 추가 기능 개발 및 유지보수 효율성 제고
프로젝트를 통해 배운 점
이 프로젝트를 통해 서로 다른 플랫폼 간의 연동에서 발생할 수 있는 다양한 기술적 과제들을 해결하며, 특히 다음과 같은 부분에서 깊은 이해와 경험을 얻을 수 있었습니다:
- 분산 시스템 설계: 여러 서비스 간의 효율적인 통신 및 데이터 일관성 유지 방법
- 보안 인증 체계: OAuth 2.0 기반의 견고한 인증 시스템 구축 및 최적화 방법
- 대용량 데이터 처리: 페이징 및 비동기 처리를 활용한 대용량 데이터 효율적 처리 기법
- 자동화 시스템 구축: 반복적인 운영 작업을 자동화하여 효율성을 높이는 방법
이러한 경험은 향후 다양한 서비스 간 연동 및 대규모 시스템 설계에 있어 귀중한 자산이 될 것입니다.