[Findex] 프로젝트 개발 리포트

dustle·2026년 3월 18일

코드잇

목록 보기
1/2

1. 프로젝트 개요

Findex는 금융 지수 데이터를 한눈에 제공하는 대시보드 서비스입니다.
금융위원회 오픈 API와 연동하여 지수 정보를 자동으로 수집·관리하고, 사용자에게 성과 차트, 랭킹, 즐겨찾기 등의 기능을 제공합니다.

  • 개발 기간: 2026년 3월 11일 ~ 3월 20일 (약 10일)
  • 팀 구성: Spring Backend 10기 팀5 (Ant-Man) — 5인 (송시연, 김민형, 박성국, 성주현, 전창현)
  • 핵심 기능: 지수 정보 CRUD, 지수 데이터 관리 및 CSV 다운로드, 금융위원회 오픈 API 연동, 자동 연동 스케줄러, 대시보드

2. 담당한 작업

저는 프로젝트 내에서 자동 연동(Auto Sync) 도메인을 설계·구현했으며, 프로젝트 초기 설정 및 인프라 작업도 담당했습니다.

초기 설정 및 인프라

작업이슈/PR내용
협업 환경 구축Issue #3Git 브랜치 전략, 협업 도구(Discord, Notion 등) 환경 세팅
개발 규칙 정의Issue #4코딩 컨벤션, 커밋 메시지 규칙 등 팀 개발 규칙 정의
프로젝트 초기 설정Issue #5프로젝트 초기 구조 설정 및 Initial Commit
요구사항 정의서Issue #6요구사항 정의서 작성
ERD 설계Issue #2팀 전체와 함께 핵심 엔티티 도출, 속성 정의, 관계 설정 진행
DB 환경 설정Issue #9 / PR #12H2(로컬) / PostgreSQL(운영) 프로필 분리
도메인 Entity 구현Issue #11 / PR #34Swagger 명세 기준 엔티티 필드명·JOIN 컬럼명·NOT NULL 매핑 정비
PR 템플릿PR #7팀 전체가 일관된 PR 작성을 할 수 있도록 템플릿 추가
Projects 설정Issue #39GitHub Projects 보드 설정
Railway 배포Issue #31Railway 플랫폼을 통한 서비스 배포

자동 연동(Auto Sync) 도메인 — 핵심 담당 영역

작업이슈/PR내용
자동 연동 생성Issue #44 / PR #45AutoSyncConfig 엔티티·리포지토리·매퍼·서비스 구현, 지수 등록 시 비활성 상태로 자동 생성
자동 연동 수정Issue #29 / PR #46, PR #50수정 API 구현, DTO 검증 로직 추가, Swagger 컨트롤러 설명 추가
자동 연동 목록 조회Issue #28 / PR #64QueryDSL 기반 필터링·단일 필드 정렬·커서 기반 페이지네이션 구현
자동 연동 스케줄러Issue #30 / PR #67주기적으로 연동 대상 식별 후 금융위원회 API 호출하여 자동 동기화하는 스케줄러 구현
정렬 Enum 리팩토링Issue #74 / PR #75문자열 기반 정렬 분기를 타입 안전한 SortField Enum으로 전환
기준일 정책 변경Issue #79 / PR #78동기화 이력 없는 경우 baseDateFrom = baseDateTo로 1일치만 동기화하도록 정책 수정, 테스트 보완

성능 최적화 및 운영

작업이슈/PR내용
캐시 적용Issue #91 / PR #99금융위원회 API 응답에 캐시 적용 (과거 데이터 7일, 당일 데이터 1시간)

3. 기술적 성과

사용 기술 스택

  • Backend: Spring Boot, Spring Data JPA, QueryDSL, MapStruct, Spring Scheduler
  • API 문서화: Swagger (springdoc-openapi)
  • Database: PostgreSQL (운영), H2 (로컬/테스트)
  • 배포: Railway
  • 협업: Git/GitHub, Discord, Notion

주요 구현 성과

1) 자동 연동 시스템 전체 설계 및 구현

  • AutoSyncConfig CRU API, 스케줄러까지 자동 연동 도메인 전체를 end-to-end로 구현했습니다.
  • 지수 등록 시 비활성 상태의 자동 연동 설정이 함께 생성되는 연동 로직을 구현했습니다.
  • AutoSyncSchedulerIntegrationTaskServiceIndexSyncService 로 이어지는 자동 동기화 파이프라인을 설계했습니다.

2) QueryDSL 기반 조회 기능

  • 필터링(indexInfoId, enabled), 단일 필드 정렬, 커서 기반 페이지네이션을 지원하는 목록 조회 API를 구현했습니다.
  • AutoSyncConfigSortField Enum을 도입하여 정렬 대상 필드 반환, 커서 값 추출, 커서 조건 생성을 타입 안전하게 처리했습니다.

3) 캐시

  • 금융위원회 오픈 API 응답에 대한 캐시 레이어(MarketIndexApiCacheService)를 구현했습니다.
  • 과거 데이터(변경 불가)는 7일 TTL, 당일 데이터(갱신 가능)는 1시간 TTL로 차등 적용했습니다.
  • 지수 데이터 연동의 약 1,000건 기준(2020~2026 KRX 반도체 데이터) 응답 시간을 개선했습니다.(4183ms -> 495ms)
  • 지수 정보 연동의 약 200건 기준 응답 시간을 개선했습니다.(892ms -> 210ms)

4) 개발 환경 및 인프라 기반 구축

  • H2/PostgreSQL 프로필 분리로 로컬 개발 환경과 운영 환경을 독립적으로 관리할 수 있도록 했습니다.
  • PR 템플릿, GitHub Projects 설정 등 팀 협업 기반 도구를 마련했습니다.

4. 문제점 및 해결 과정

문제 1: 동기화 이력이 없는 지수의 기준일 처리

  • 문제: 자동 연동 스케줄러가 동기화 대상을 생성할 때, 성공 이력이 없는 지수에 대해 baseDateFromnull로 설정되어 API 호출 시 의도치 않은 대량 데이터 요청이 발생할 수 있었습니다.
  • 해결: 성공 이력이 없는 경우 baseDateFrom = baseDateTo로 설정하여 1일치 데이터만 동기화하도록 정책을 변경했습니다. 또한 정책 결정 로직을 SyncService에서 대상 생성 단계(IntegrationTaskService)로 이동시켜, 동기화 서비스는 순수하게 동기화 실행에만 집중하도록 책임을 분리했습니다. (Issue #79 / PR #78)

문제 2: 문자열 기반 정렬 로직의 타입 안전성 부재

  • 문제: QueryDSL 조회 시 정렬 필드를 문자열로 처리하고 있어, 잘못된 필드명이 런타임에서야 발견되고, 중첩 필드(예: indexInfo.indexName) 바인딩 시 오류가 발생하는 등 유지보수성이 떨어지는 상황이었습니다.
  • 해결: AutoSyncConfigSortField Enum을 도입하여 정렬 대상 필드 반환, 커서 값 추출, 커서 조건 생성 로직을 Enum 내부에 캡슐화했습니다. 리뷰어가 지적해 준 중첩 필드 바인딩 이슈를 반영하여 후속 커밋으로 수정을 완료했습니다. (Issue #74 / PR #75)

문제 3: 외부 API 호출 병목

  • 문제: IndexSyncController.syncIndexData()가 약 1000건을 불러올 때 배포 서버 기준 10258ms로 응답 시간이 느렸습니다. 금융위원회 오픈 API를 매번 직접 호출하기 때문에 동일한 과거 데이터를 반복 요청하는 비효율이 있었습니다.
  • 해결: MarketIndexApiCacheService를 도입하여 API 요청 파라미터 조합 기반의 캐시 키를 생성하고, 과거 데이터(7일 TTL)와 당일 데이터(1시간 TTL)에 차등 TTL을 적용했습니다. 생성형 AI를 활용하여 캐시 hit/miss를 검증했고, 약 1,000건 기준으로 유의미한 성능 개선을 확인했습니다. (Issue #91 / PR #99)

5. 협업 및 피드백

코드 리뷰 문화

  • 브랜치 보호 규칙을 설정하여 PR 리뷰 승인 없이는 병합할 수 없도록 팀 규칙을 만들었습니다.
  • 모든 PR에서 팀원의 코드 리뷰를 받고 병합하는 프로세스를 준수했습니다.
  • 리뷰를 통해 Lombok 활용, 중첩 필드 바인딩 이슈, 캐시 성능 개선 결과 추가 등 실질적인 피드백을 받고 반영했습니다.
  • 머지 후 반드시 pull을 받는 프로세스를 팀 규칙으로 정립하여, 프로젝트 기간 동안 Git 충돌이나 브랜치가 꼬이는 사태를 예방하였습니다.

팀 기여

  • 팀장을 맡아 매일 회의를 주관하고, 각 팀원의 진행 상황을 확인하며, 기술적 의사결정이 필요한 부분에서 방향을 정해주는 역할을 했습니다.
  • 프로젝트 협업 환경 구축(Issue #3), 개발 규칙 정의(Issue #4), GitHub Projects 설정(Issue #39) 등 팀 전체 인프라 세팅을 주도했습니다.
  • PR 템플릿을 도입하여 팀 전체가 일관된 형식으로 PR을 작성할 수 있게 했습니다.

느낀 점

  • 짧은 개발 기간(10일) 내에 도메인 하나를 전담하면서, 설계부터 최적화까지 전체 생애주기를 경험할 수 있었습니다.
  • 리뷰어의 피드백을 통해 Enum 기반 정렬, 중첩 필드 바인딩 등 실무에서 발생할 수 있는 이슈를 사전에 발견하고 해결할 수 있었습니다.
  • 팀원 간 작업 의존 관계(예: 스케줄러 → SyncService)를 조율하며 비동기적 협업의 중요성을 배웠습니다.
  • 팀장 역할을 맡으며 단순히 개발을 수행하는 것을 넘어, 팀 전체의 방향성과 진행 상황을 책임지는 경험을 할 수 있었습니다.
  • 회의를 주도하며 의견을 정리하고 팀원들의 참여를 이끌어내는 과정에서 커뮤니케이션, 조율 능력과 같은 소프트 스킬이 크게 향상되었음을 느꼈습니다.

6. 코드 품질 및 최적화

코드 가독성 및 유지보수성

  • Enum 기반 설계: 정렬 로직을 AutoSyncConfigSortField Enum으로 캡슐화하여 새로운 정렬 필드 추가 시 Enum 값만 추가하면 되도록 확장성을 확보했습니다.
  • MapStruct 활용: 엔티티 ↔ DTO 변환을 MapStruct로 자동화하여 수동 매핑 코드를 제거하고, 필드 누락 가능성을 컴파일 타임에 검출할 수 있게 했습니다.
  • Swagger 문서화: 모든 컨트롤러에 Swagger 설명을 추가하여 프론트엔드 협업 및 API 테스트가 용이하도록 했습니다.
  • 코드 컨벤션 준수: Google Java Style XML을 적용하고, 코드 포맷팅 PR #49을 통해 일관된 코드 스타일을 유지했습니다.
  • 책임 분리: 기준일 정책 결정 로직을 SyncService에서 IntegrationTaskService로 이동시켜, 각 서비스가 단일 책임을 갖도록 리팩토링했습니다.

성능 최적화

  • 병목 지점 식별 (Issue #91): 실제 메서드 실행 시간을 측정하여 syncIndexData() (814~1,258ms)를 병목으로 정확히 파악한 후 캐시를 적용했습니다.
  • 캐시: 금융위원회 API 응답에 대해 데이터 특성에 따른 차등 캐시 전략을 적용했습니다.
    • 과거 데이터: 7일 TTL (변경 가능성 희박 → 호출 최소화)
    • 당일 데이터: 1시간 TTL (변경 가능 → 최신성 확보)
  • 커서 기반 페이지네이션: 오프셋 기반 대비 대규모 데이터셋에서 일관된 조회 성능을 보장하는 커서 기반 페이지네이션을 적용했습니다.

테스트

  • 모든 PR에서 단위 테스트(Unit Test), 로컬 테스트, API 테스트를 수행했습니다.
  • 기준일 정책 변경 시 이력 없음·실패 이력 시나리오에 대한 테스트 케이스를 추가했습니다 (PR #78).

7. 향후 개선 사항 및 제안

단기 개선 사항

  1. 캐시 무효화 전략 정교화: 현재 TTL 기반 만료만 적용되어 있으므로, 수동 연동이 발생했을 때 해당 캐시를 즉시 무효화하는 이벤트 기반 전략을 추가하면 데이터 정합성이 향상될 것으로 보입니다.
  2. 스케줄러 모니터링: 10분 간격 스케줄러의 실행 이력·성공/실패 건수를 로깅하고 대시보드에서 확인할 수 있도록 모니터링 체계를 구축하면 운영 안정성이 높아질 것입니다.

장기 개선 제안

  1. 분산 환경 대응: Railway 스케일 아웃 시 스케줄러 중복 실행을 방지하기 위해 ShedLock 등 분산 락 도입을 고려할 수 있습니다.
  2. QueryDSL 정렬 일반화: AutoSyncConfigSortField Enum 패턴을 다른 도메인(IndexInfo, IndexData 등)에도 공통 인터페이스로 확장하여 정렬 로직의 재사용성을 높일 수 있다고 생각합니다.
  3. 비동기 동기화: 현재 스케줄러가 동기적으로 API를 호출하므로, 대량의 지수를 처리할 때 병렬 비동기 호출(@Async 또는 CompletableFuture)을 도입하면 전체 동기화 시간을 단축할 수 있습니다.
  4. 통합 테스트: 현재 단위 테스트 중심으로 검증하고 있으므로, 스케줄러 → 서비스 → 외부 API 연동까지 이어지는 통합 테스트를 추가하면 배포 안정성이 크게 향상될 것입니다.

0개의 댓글