WELCOME TO THE PROJECT STORE

Hola Climbing

클라이밍 영상을 AI로 분석해, 기록과 피드·암장 탐색으로 이어지는 서비스

AI Climbing SNS2026.05.15 ~ 2026.06.252명운영 중
ROLE
Spring Boot 백엔드 + Python AI worker pipeline 단독 담당
IMPACT
GCS 직접 업로드, Redis Streams/SSE, snapshot cursor로 업로드·분석·추천 흐름 분리
PROOF
cursor aggregate p95 9.794ms, Spring/AI E2E smoke, raw/presentation evidence

IN THE STORE

프로젝트 안내

WHY THIS STORE EXISTS
목적
영상 공유를 넘어 동작 데이터 회고와 성장 흐름 추적
목표
대용량 영상 업로드 · AI 분석 · 실시간 진행률 · 추천 피드 · 암장 데이터 · 기록/통계 API 연결
개발 과제
수십~수백 MB 영상 파일의 WAS 대역폭·스레드 포화 위험. 장기 실행 AI 분석의 요청/응답 흐름 분리 필요.
결과
  • GCS v4 Signed URL 기반 영상 바이너리 업로드 분리
  • Redis Streams + Pub/Sub + SSE 기반 AI 분석 요청·진행률·결과 저장 분리
  • Spring Boot 서버와 Python AI 워커 간 callback 계약 정리, E2E smoke 검증
  • snapshot cursor cache + public thumbnail URL 전환, cursor page p95 약 9.8ms 증거 확보

IN THE STORE

내가 맡은 일

OWNERSHIP
역할
Backend & AI pipeline
기여도
Spring Boot 백엔드와 Python AI 워커 파이프라인 단독 담당. 프론트엔드 팀원 담당, 백엔드 API 계약과 AI 워커 입출력 계약 정합 책임.
구현한 기능
  • 회원·인증·OAuth·JWT·약관·프로필 API
  • 영상 메타데이터, GCS Signed URL, 댓글, 좋아요 API
  • 암장 검색, 난이도, 리뷰, 즐겨찾기, 운영상태 API
  • Redis Streams 기반 AI 분석 dispatch와 SSE 진행률
  • AI worker callback 결과 저장, 분석 피드백, 재시도
  • WebSocket STOMP 암장별 채팅과 GPS 암장 인증
  • pgvector + 팔로잉 boost 기반 추천 피드와 snapshot cursor
  • Flyway, Testcontainers, Swagger/ErrorCode 문서화
개인 성과
  • Spring REST/STOMP API 계약 다수, AI worker health/readiness 계약 코드 기준 정리
  • PostgreSQL·Redis·GCS·AI worker 연결 분석 E2E 흐름 검증
  • 추천 피드 성능 evidence: raw 결과 + presentation 이미지 분리, 포트폴리오용 근거 확보

IN THE STORE

기술과 선택

TECH & DECISIONS

백엔드

Java 25
Spring Boot 4 기반 백엔드 런타임, 최신 Java API 정합성
Spring Boot 4
회원·영상·암장·채팅·분석 callback 등 인증/권한 API의 일관된 구현
Spring Security 7 + JWT
모바일/웹 클라이언트 인증, 토큰 재발급, 로그아웃 블랙리스트 처리

AI

Python 3.11 + FastAPI
AI worker health/readiness, 장기 실행 stream consumer 구성
MediaPipe Pose
클라이밍 영상 33개 pose keypoint 추출, 규칙 기반 기술 판정 입력
OpenCV + Optical Flow
dynamic/static 영상 단위 보정용 flow feature 추출
RandomForest flow gate
규칙 기반 segment 결과의 약한 dynamic 오탐 보정, 영상 단위 prior

데이터

MyBatis 4
pgvector 추천, 통계, 집계성 조회 등 SQL 제어 중심 워크로드
PostgreSQL + pgvector
관계형 도메인과 스타일 임베딩 기반 추천의 단일 저장소 처리

인프라

Redis Streams
기존 Redis 활용, Kafka 추가 없이 AI 작업 큐 구성
Redis Pub/Sub + SSE
서버 → 클라이언트 단방향 분석 진행률, WebSocket 대신 SSE 단순화
Google Cloud Storage Signed URL
대용량 영상 바이너리의 WAS 우회, 서버 부하 감소

테스트

JUnit 5 + Testcontainers
PostgreSQL/Redis 실제 컨테이너 기반 통합 테스트 재현성
pytest + ruff + mypy
Python AI worker 계약, Redis bus, callback, vision 유틸 검증

GCS Signed URL 직접 업로드

선택
백엔드는 업로드 URL·메타데이터만 관리. 영상 바이너리는 클라이언트의 GCS 직접 PUT.
이유
수십~수백 MB 영상 트래픽으로 인한 WAS 대역폭·스레드 점유 회피
대안
백엔드 multipart proxy, 업로드 전담 서비스 분리
트레이드오프
서버 부하 감소 vs GCS CORS·만료 시간·object path 검증·업로드 완료 후 메타데이터 정합 관리
검증
GCS Signed URL double slash 회귀 테스트, 운영 upload path 검증
주도성
직접 구현/결정

Redis Streams 기반 AI dispatch

선택
별도 메시지 브로커 신규 도입 없이 기존 Redis 기반 AI 분석 작업 큐 구성
이유
JWT 블랙리스트·진행 버스용 Redis 선사용, 1인 운영 기준 신규 인프라 최소화
대안
Kafka/RabbitMQ 신규 도입, HTTP direct call
트레이드오프
운영 단순성 확보 vs Kafka 수준 생태계·장기 보관·관측성 약화
검증
Spring -> Redis Stream -> AI worker -> Spring callback -> SSE E2E smoke
주도성
직접 구현/결정

MyBatis over JPA

선택
ORM 영속성 컨텍스트보다 SQL 제어 우선. MyBatis 선택.
이유
추천, 통계, 차단, cursor pagination, pgvector 거리 정렬 등 native SQL 중심 API
대안
Spring Data JPA, JPA + native query 혼용
트레이드오프
SQL 명시성·성능 제어 확보 vs 반복 mapping 코드·mapper 테스트 부담
검증
Mapper/Integration 테스트, SQL explain evidence 기반 주요 조회 성능 확인
주도성
직접 구현/결정

IN THE STORE

문제를 푼 방식

PROBLEM SOLVING

추천 피드 tail latency와 signed URL 병목

문제
SQL 병목 제거 이후에도 목표보다 높은 추천 피드 API p95
접근
k6 · SQL explain · presentation evidence 분리, DB/API 레이어 별도 해석
원인
추천 피드 응답마다 streamUrl·thumbnailUrl signed URL 반복 생성 비용
해결
추천 피드 streamUrl 제거, 썸네일 public GCS bucket URL 제공. cursor page는 Redis snapshot으로 ranking SQL 재계산 회피.
결과
baseline 대비 current p95·cursor page p95 개선, cursor aggregate p95 약 9.8ms 측정

AI worker callback 계약 정합

문제
Spring/Python 워커 간 분석 결과 shape, snake_case/camelCase, dynamic/static 필드 해석 차이 위험
접근
Spring API 명세 SSOT, 워커 DTO와 callback body 정합
원인
동일 도메인 결과의 서로 다른 타입 시스템·naming convention 처리
해결
top-level techniques, is_dynamic, dynamic_probability callback payload 명시. Notion/API 명세와 테스트 갱신.
결과
Spring targeted tests, AI pytest subset, local E2E 기반 callback 저장·조회 응답 정합 검증

IN THE STORE

AI·데이터 파이프라인

FROM INPUT TO RESULT
모델
rule_v3 + flow_rf_v2
입력 데이터
GCS에 업로드된 클라이밍 영상과 MediaPipe Pose keypoint sequence
출력 데이터
techniques, isDynamic, dynamicProbability, segment start/end/confidence
전처리
  • GCS object 다운로드
  • OpenCV frame sampling
  • MediaPipe Pose 33 keypoint 추출
  • segment 분리
  • optical flow 기반 영상 단위 dynamic/static feature 추출
데이터 특성
  • 촬영 각도, 루트, 동작 속도 편차가 큰 클라이밍 영상
  • 정적 자세에서도 발생하는 keypoint jitter, coordination false positive 가능성
  • 동작 라벨: 하이스텝, 플래깅, 훅, 락오프, 다이노, 코디네이션 중심
선택 이유
Frozen video encoder 실험 기준 미달, 새 오답 비용 부담. MVP 기준: 설명 가능·디버깅 가능한 규칙 기반 판정 + flow RF 보정.
결과 기반 개선
  • coordination one-hit false positive 감소: active frame ratio + same-frame 동시 이동 조건
  • flagging/hook 오탐 조정: rule_v3
  • flow RF 역할 제한: dynamic/static 영상 단위 prior, 약한 dynamic segment 보정만

IN THE STORE

검증 자료

EVIDENCE, NOT DECORATION
Backend/AI Architecture

Backend/AI Architecture

GCS direct upload, Cloud Run Spring backend, Redis Streams, AI worker, PostgreSQL/pgvector, 외부 OAuth/SMTP/FCM 흐름

Minjoon 담당: Spring backend, Redis dispatch, AI worker pipeline

ERD

ERD

회원, 영상, 암장, 분석, 추천, 기록, 채팅 도메인 관계

Recommendation Performance Summary

Recommendation Performance Summary

추천 피드 성능 테스트 요약: 100k videos / 10k users seed 기준 p95, SQL 실행 시간, 오류율

p95 123ms, SQL 81ms, error_rate 0% 측정 근거

Cursor Cache Comparison

Cursor Cache Comparison

Redis snapshot cursor cache 적용 후 2·3페이지 cursor 호출 p95 분리 측정

2페이지 9ms, 3페이지 10ms, cursor 전체 10ms

App Screen Overview

App Screen Overview

마이페이지, 주변 암장 탐색, 월간 기록 화면 최종 UI

영상 분석 결과를 기록·암장 탐색·월간 회고 흐름으로 연결

AI Pose Analysis

AI Pose Analysis

MediaPipe 33 keypoints 기반 클라이밍 자세 추출 화면

Technique Classification

Technique Classification

프레임별 기술명과 dynamic/static 성향 분류 결과

Monthly Report

Monthly Report

월간 클라이밍 리포트: 성향 비율, 기술 빈도, 코칭 팁

Gym Detail

Gym Detail

암장 상세: 관련 영상, 운영 시간, 실시간 채팅 진입

Gym Exploration

Gym Exploration

내 주변 암장 탐색과 맞춤 추천 화면

추천 피드 HTTP p95

251.233ms → 122.642mslocal-baseline 대비 current 측정. 같은 조건 반복 측정 결과로만 최종 문구 확정.

추천 피드 SQL execution

181.086ms → 80.966mstemp blocks written 9,138 -> 0.

cursor aggregate p95

9.794msRedis snapshot cursor cache 적용 후 2~3페이지 호출 기준.

AI worker model version

rule_v3+flow_rf_v2flow gate on일 때 top-level dynamicProbability와 isDynamic을 callback.

IN THE STORE

회고

WHAT I LEARNED

배운 점

  • 런타임이 다른 백엔드/AI worker: 메시지 큐와 결과 callback 분리 필요
  • 대용량 바이너리: 애플리케이션 서버 우회 설계로 운영 부담 감소
  • 포트폴리오용 성능 주장: raw evidence + 사람이 읽는 presentation evidence 동시 보관

아쉬운 점

  • Kafka vs Redis Streams 사전 실측 비교 부족
  • 데이터 누적 이후 확정 가능한 pgvector 인덱스 전략
  • 단일 노드 가정 밖의 멀티 노드 STOMP/SSE fan-out 과제

다음 개선

  • 동일 조건 3회 이상 반복 측정, 최종 성능 수치 고정
  • post-MVP AI 모델 재평가: fine-tuning 또는 재촬영 UX
  • 발표용 아키텍처 도식의 담당 영역 명확화

협업

프론트 담당자와 API 명세, OAuth callback, 영상 업로드 완료 후 메타데이터 등록, 분석 상태 vocabulary 정합

IN THE STORE

면접에서 설명할 사례

STAR STORIES

대용량 영상 업로드와 AI 분석 파이프라인

상황
수십~수백 MB 클라이밍 영상, 장기 실행 AI 분석, 단순 request/response 처리 시 서버·사용자 경험 리스크
행동
GCS Signed URL 기반 영상 업로드 분리, Redis Streams + Pub/Sub + SSE 기반 분석 요청/진행률/결과 저장 분리
결과
서버는 메타데이터·계약 관리, 영상 바이너리와 장기 실행 AI 작업은 독립 흐름 처리
배움
운영 부담 감소의 출발점: 기술 추가보다 명확한 책임 경계