좌석 예약 시스템
2026.02 – 2026.05 · 개인 프로젝트공연 좌석 예약 — 대기열 · 락 전략 · 이벤트 전달 · 설계 · 구현 · 측정 전체
Java 21, Spring Boot 3.4.1, PostgreSQL 16, Redis 7 · Redisson 3.40.2, Apache Kafka (cp 7.6.0), JPA, Flyway, Testcontainers, k6 v1.5.0
- 같은 좌석에 100명이 몰릴 때 나던 중복 판매를 락 3종 비교로 막아 oversell 0건, p95는 106–215ms로 실측
- 다른 좌석인데 예매가 서로 실패하던 원인이 잔여석 카운터 한 줄이었음을 밝혀 성공률 40% → 100%
- 매진된 좌석 요청까지 DB를 잡던 것을 Redis에서 미리 걸러 쓰기 p95 37ms → 6ms, 총 RPS 969 → 1,005
- 결제·만료 race와 멱등 replay, 대기열 토큰 우회를 시나리오로 재현해 체크 594/594 통과
- JWT 인증(가입·로그인)과 내 정보 조회, 데모 계정 원클릭 로그인
- 콘서트 목록·회차·좌석 배치 조회와 예매 내역 조회·취소, 대기열 순번은 SSE로 전달
- Transactional Outbox로 커밋과 발행을 분리하고, 재고 정합성 대조와 Kafka DLT 수동 replay를 운영용 엔드포인트로 제공
실시간 채팅 서버
2026.02 – 2026.05 · 개인 프로젝트다중 인스턴스 채팅 — 메시지 영속화 · fan-out · 전달 검증 · 설계 · 구현 · 측정 전체
Java 21, Spring Boot 3.4.3, WebSocket · STOMP, Apache Kafka 3.9.0 (KRaft), Redis 7 Pub/Sub, PostgreSQL 16, JPA, Testcontainers, k6 v1.5.0
- 채팅방 목록이 방 개수만큼 쿼리를 날리던 것을 JPQL 프로젝션과 IN 배치로 모아 방 50개 기준 101회 → 3회 고정
- 커서 페이지네이션·멱등성·unread 등 핵심 쿼리를 EXPLAIN ANALYZE로 분석해 인덱스 5개 설계, 이미 커버되는 3개는 근거를 적고 추가하지 않음
- DB 커밋이 끝난 뒤에만 브로드캐스트하도록 순서를 강제 — 50명이 두 인스턴스에 나뉜 3회 반복에서 기대 4,900건 전부 도착, 누락·중복·순서 위반 0건
- 현재 커밋에서 200 VU 조회 부하를 3회 반복 재측정해 RPS 1,806–1,940 · p95 129–133ms · 39.8만 요청 중 HTTP 실패 0건 확인
- JWT 인증(가입·로그인)과 사용자 검색, 1:1·그룹 방 생성과 참여
- 커서 기반 메시지 조회와 읽음 처리, 재접속 시 마지막 수신 ID 기준으로 놓친 구간 보충 조회
- Redis 패턴 구독이 수신 채널명을 목적지로 쓰던 것을 payload 기준으로 고쳐 다른 방으로 새던 메시지를 막고 단위 테스트로 고정
FinMate — 청년 금융 온보딩
2026.04 – 2026.07 · 4명 — 기획 2 / 풀스택 1(본인) / 데이터 1소셜 핀테크 — 원장 파생 지표 · 또래 비교 · 미션 · 풀스택 — 앱의 프론트·백엔드 단독
React 19, TypeScript strict, Vite, Tailwind CSS v4, Motion v12, React Router 7, html-to-image, Java 21 · Spring Boot 3.5, PostgreSQL 16, Flyway · Testcontainers, fal.ai (FLUX)
- 또래 비교가 매 요청 원장 88만 행을 다시 세던 것을 사람×월 사전 집계로 접어 p50 32.5ms → 0.72ms
- 고치기 전에 먼저 재서 개인 화면은 p95 0.96ms로 문제가 아님을 확인하고, 인덱스(50MB·24.0ms) 대신 사전 집계(1.9MB·0.72ms)를 선택
- 외부 이미지 생성 API가 3~6초 걸리는 동안 행 잠금이 풀리던 것을 상태 값으로 선점하게 바꿔 두 인스턴스가 같은 작업을 가져가지 못하게 함
- 합성 데이터셋 2,000명 887,002행을 JDBC 배치로 적재(34,490행/초)하고 원장·프로필 정합성을 통합 테스트로 고정
- 하루의 거래에서 그날의 주인공(소비·저축·투자)을 뽑아 AI 그림일기 한 장으로 기록 — 하루 한 장 멱등성, 3회 재시도, 응답 없는 작업 회수
- 예산 챌린지 판정을 저장하지 않고 매번 원장에서 세고, 포인트는 잔액이 아니라 원장으로 쌓아 이중 지급 차단 — 또래 비교는 금액을 구간으로만 내보내고 20명 미만 그룹은 만들지 않는다
- 화면의 모든 수치를 거래 원장에서 파생하는 순수 셀렉터로 통일하고, 차트는 라이브러리 없이 SVG로 직접 구현해 번들에 차트 의존성 0개
배리어프리 길찾기 (My ETA)
2026 · 해커톤 · 7명 — 개발 4명 / 기획·리서치 3명 (24시간 해커톤)교통약자 대상 경로 안내 — 개인화 ETA · 접근성 데이터 통합 · 백엔드 · 프론트엔드 — 커밋 기준 최다 기여 (전체 코드의 91%)
Python 3.12, FastAPI, Pydantic, HTTPX, TMAP API, 서울 공공데이터, Kakao Local, pytest, OpenAPI 3.1
- 경로에 접근성 정보를 붙일 때 구간마다 외부를 차례로 묻던 것을 같이 물어 대기 3,097ms → 52ms, 외부 호출 60회 → 20회
- 표준 보행속도로 낸 ETA가 교통약자에게 항상 틀리던 것을 이동 유형·보조기구 프로필과 안내 중 모은 실제 속도로 보정
- 확인 못 한 시설 정보를 '있음'으로 채우던 것을 '확인 안 됨'으로 그대로 응답하도록 상태를 정의
- 경로 이탈과 대중교통 놓침을 감지해 현재 위치를 새 출발점으로 경로와 ETA를 다시 계산
- TMAP 경로·서울 버스·지하철 실시간 도착·엘리베이터·장소 검색 등 외부 API 5종을 provider 어댑터 계층으로 통합
- 이동 프로필 조회·수정과 목적지 장소 검색, 대중교통·도보·택시 유형별 경로 검색과 상세 조회
- 안내 세션 시작·위치 갱신·재탐색·완료 — 완료 시 실제 속도를 프로필에 반영하고, 원본 좌표는 안내 중 계산에만 쓰고 영구 저장하지 않는다