유다현 프로필 사진

유다현

개발자

Contact

고객의 경험과 운영끝까지 개선하는 개발자

  1. 01

    Make it

    문제를 발견하면 기준을 세우고, 작동하는 결과로 완성합니다.

  2. 02

    Grow up

    한 번의 해결에 머물지 않고, 다음 개선의 단서까지 남깁니다.

  3. 03

    Work Together

    역할과 진행 상황을 투명하게 공유하며 함께 답을 찾습니다.

  4. 04

    Customer Success

    기능이 아닌 고객의 다음 행동까지 생각해 경험을 설계합니다.

Tech Stack

Java

Spring Boot

Spring Security

Redis

SQL

React

TypeScript

01

SCROLL

02

개발의 흐름

개발자로서의 여정

  1. 2021.03–2025.08

    동국대학교

    경영정보학과 · 융합소프트웨어

  2. 2022.03–2022.12

    멋쟁이사자처럼 10기

    HTML · CSS · 자바스크립트 웹 프로젝트

  3. 2023.01–2023.02

    부스트코스 코칭스터디 9기

    인공지능 기초 다지기 · 6주 코칭스터디 수료

  4. 2023.03–2023.12

    IT 소모임장 'ProMIS'

    신입생 대상 프로그래밍 스터디 기획 및 운영

  5. 2023.03–2024.02

    GDSC(Google Developer Student Clubs) 1기

    앱 개발 프로젝트 · 팀 협업

  6. 2024.09–2025.02

    University of Lancashire

    영국 교환학생 · 최우수 성적

  7. 2025.03–2025.06

    구름톤 유니브 4기

    개발자 커뮤니케이션

  8. 2025.07–2026.06

    삼성청년SW·AI 아카데미 14기

    자바 · 스프링 기반 백엔드 개발

  9. 2026.08

    한화금융캠퍼스 15기

    금융 실무 교육 · 현직자 멘토링

APR

쌓아온 경험을,
에이피알에서 이어가겠습니다.

03

Selected work

Project Store

서비스의 핵심 흐름과 제가 맡은 범위를 간략히 정리했습니다.

CapSure 월 보험료 입력과 캡슐 구성이 움직이는 애니메이션 화면
CapSure 대시보드가 표시되는 애니메이션 화면

구독형 보험 프로세스 시뮬레이터

CapSure
01 / 04

결제와 계약의 상태를 끝까지 맞추다.

월 단위로 보험을 구성하고 구독하는 서비스입니다. 납입, 청구, 지급, 계약 유지가 한 흐름으로 이어지도록 설계했습니다.

  • Java 21
  • Spring Boot 3.5.11
  • MyBatis 3.0.5
  • PostgreSQL
  • React 19
  • Toss Payments SDK 2
팀 구성
5명, 백엔드 3명, 프론트엔드 1명, 인프라 1명
담당 범위
FE Lead. 상품 선택, 결제, 구독 확정
CapSure / PROBLEM 01결제 복구 · 멱등성

오류가 났다고, 결제를 다시 승인하지 않습니다.

외부 승인과 내부 저장을 구분하고, 같은 주문의 결과를 확인해 계약까지 복구했습니다.

같은 주문의 복구 과정 합성 PG 예외 주입 시험
  1. 01

    외부 승인 완료

    PG에서는 이미 승인된 주문

    승인 결과 존재
  2. 02

    내부 저장 실패

    증권 저장 예외 → HTTP 500

    APPROVING · 증권 0건
  3. 03

    조회 후 복구

    새 승인이 아닌 기존 주문 대사

    PAID / ACTIVE · 증권 1건
복구의 기준승인은 반복하지 않고,
끊긴 내부 처리를 이어갑니다.
별도 동일 confirm 100회외부 승인 1회증권·활성화 이벤트 각 1건
01 · PROBLEM

PG 승인 직후 증권 저장에 예외를 주입하자 HTTP 500이 반환됐습니다. 하지만 이미 끝난 외부 승인은 DB 롤백으로 취소되지 않았습니다.

02 · DECISION

오류 응답을 결제 실패로 단정하지 않고, 새 승인보다 기존 거래 확인을 우선했습니다.

03 · BUILD

승인 후 내부 실패는 APPROVING으로 유지합니다. 같은 주문을 조회·대사해 결제 상태, 계약 활성화, 증권과 Outbox를 함께 복구합니다.

04 · EVIDENCE대사 후 PAID / ACTIVE로 복구. 증권·활성화 이벤트 각각 1건.

합성 PG · 저장 예외 주입 · 기존 결제 통합 테스트 기록

APPLICATION

수납 오류의 복구 완료 기준을 응답 성공이 아니라 계약 반영까지 잡는 관점입니다.

검증 조건과 범위 보기

2026-09-13 PaymentPolicyIntegrationTest 10건 통과. 예외 직후 APPROVING / PENDING_INITIAL_PREMIUM / 증권 0건, 대사 후 PAID / ACTIVE / 증권 1건을 확인했습니다. 별도 동일 confirm 100회 시험에서도 외부 승인 호출·결제 시도·증권·활성화 이벤트는 각각 1회/1건이었습니다. 승인 여부를 모르는 timeout은 UNKNOWN으로 따로 처리합니다.

CapSure / PROBLEM 02계약 효력 · 시간 경계

배치가 늦어도, 계약 판단은 달라지지 않게.

입금 기록과 계약 효력을 분리하고, 수납 순간에도 같은 만료 규칙을 적용했습니다.

입금 시점으로 나눈 동일 정책 합성 상품의 유예 종료 기준
유예 마지막 날

기한 안에 완납

모든 미납 회차 해소

ACTIVE계약 활성 상태
유예 종료
다음 날 · 배치 실행 전

DB에는 아직 GRACE

수납 직전 만료 기준 재확인

LAPSED입금 기록 + 지연 검토 1건
배치와 수납이 공유하는 판단입금은 기록하되,
계약을 자동으로 되살리지 않습니다.

같은 실효 후 출금 결과를 2번 반영한 별도 시험에서도 수납·검토는 각각 1건.

01 · PROBLEM

유예 종료 다음 날, 실효 배치보다 입금이 먼저 도착하면 DB에는 아직 GRACE가 남습니다. 이 값만 보면 지난 계약이 다시 활성화될 수 있습니다.

02 · DECISION

“돈이 들어왔다”와 “보장이 유효하다”를 같은 조건으로 처리하지 않았습니다.

03 · BUILD

수납 전에 계약을 잠그고 beforeSettlement로 만료 여부를 다시 판단합니다. 실효 후 입금은 수납 기록과 지연 검토로 남기고 자동 활성화하지 않습니다.

04 · EVIDENCE마지막 날 완납은 ACTIVE. 다음 날 배치 전 입금은 LAPSED + 검토 1건.

합성 상품 정책 · 시험 시계 제어 · 기존 미납 통합 테스트 기록

APPLICATION

배치 실행 순서와 무관하게 같은 업무 기준으로 계약 상태를 판단하는 관점입니다.

검증 조건과 범위 보기

2026-09-13 미납 통합 테스트 18건 통과. 합성 상품의 유예 종료 기준과 시험 시계를 사용했습니다. 이미 실효된 계약에 같은 UNKNOWN 출금 결과를 두 번 반영해도 수납·지연 검토는 각각 1건이었습니다.

Roundy 온라인 로테이션 소개 랜딩 화면Roundy 로테이션 미팅 화면

얼굴 인증과 마스킹 기반 미팅

Roundy
02 / 04

얼굴 인증으로 신뢰를 더한 온라인 로테이션 매칭 서비스.

성향 퀴즈로 상대를 만나고, 실루엣으로 먼저 대화합니다. 서로 선택하면 시간이 흐를수록 마스킹이 풀리며 얼굴을 확인합니다.

  • Java 21
  • Spring Boot 3.5.9
  • Redis와 Lua
  • MySQL
  • React 19
  • TypeScript 5.9
  • OpenVidu 2.32
팀 구성
6명 · FE 1 · BE 3 · AI 1 · INFRA 1
담당 범위
매칭, 인증, 방 접근 권한 보강
Roundy / PROBLEM 01동시 요청 · 상태 정합성

이전 방의 종료 요청이 새 방을 지우고 있었습니다.

입장을 원자화하는 것만으로는 부족했습니다. 정리할 때도 현재 방과 대상 방을 비교했습니다.

동시성 제어와 부하 관측 ROUNDY LOAD DASHBOARD
Roundy 매칭 부하 테스트 관측 대시보드
AWS 서울 환경에서 합성 사용자 9,000명을 3회 실행한 관측 기록
  1. 현재 상태새 세션 B 배정
  2. 늦은 요청이전 세션 정리 요청
  3. 대상 세션 불일치현재 세션 B 유지

인증 소비 → 큐 등록 → 방 배정은 하나의 Lua 실행으로. 정리에는 roomId 비교 조건을 추가했습니다.

01 · PROBLEM

매칭 뒤 늦은 poll이 사용자를 다시 대기열에 넣고, 이전 방의 정리 요청이 새 currentRoom을 삭제하는 순서 문제를 재현했습니다.

02 · DECISION

입장 과정은 한 번에 처리하되, 삭제에는 “지금도 그 방인가?”라는 조건이 별도로 필요했습니다.

03 · BUILD

Redis Lua로 인증 소비·큐 등록·방 배정을 묶었습니다. cleanup-room.lua는 현재 매핑이 정리 대상 roomId와 같을 때만 삭제합니다.

04 · EVIDENCE새 방 유실 100/100 → 0/100. 늦은 poll의 재큐잉도 0/100.

격리 Redis 8.4.0 · 모의 JWT/DB · 조건별 100회 로컬 시험

APPLICATION

늦은 취소·재요청이 최신 신청 상태를 덮어쓰지 않도록 전이 조건을 확인하는 관점입니다.

검증 조건과 범위 보기

기존 → 원자적 입장만 적용 → 조건부 정리까지 적용한 세 버전을 비교했습니다. 재큐잉은 100/100 → 0/100 → 0/100, 새 배정 유실은 100/100 → 100/100 → 0/100이었습니다. 격리 Redis와 모의 JWT·DB를 사용해 Controller 수준에서 요청 순서를 제어한 시험입니다.

Roundy / PROBLEM 02인증 결과 · 소유권과 일회성

인증 성공은 본인만, 한 번만 사용할 수 있게.

성공 여부뿐 아니라 소유자·요청·상태를 묶고, 인증 결과 소비를 원자적으로 처리했습니다.

등록 사진과 실시간 촬영을 대조하는 라운디 얼굴 인증 화면
프라이버시를 위해 포트폴리오 화면은 모자이크 처리했습니다. 실제 서비스에서는 회원가입 시 등록한 사진과 실시간 촬영을 대조합니다.
CONCURRENT CONSUMPTION1/ 16 REQUESTS한 번만 소비 승인
  • 소유자의 VERIFIED만 소비
  • 타인 요청·재소비 차단
  • 늦은 완료로 재생성하지 않음
01 · PROBLEM

성공 여부만 검사하면 타인의 요청이나 겹친 요청이 같은 결과를 사용할 위험이 있습니다. 소비 후 늦은 완료 응답이 결과를 되살리는 조건도 점검했습니다.

02 · DECISION

PENDING은 소비하지 않고, VERIFIED만 한 번 사용하도록 제한했습니다.

03 · BUILD

verify:{userId}:{requestId}에 결과를 귀속시켰습니다. 완료는 PENDING에서만, 소비는 VERIFIED에서만 허용하는 Lua 전이로 재사용을 막았습니다.

04 · EVIDENCE16개 소비 요청 중 1개만 성공. 타인 소비와 재소비는 실패.

실제 Redis · 모의 DB · 8개 워커에 16개 소비 요청 제출

APPLICATION

일회성 승인 결과를 사용자와 요청에 귀속시키는 설계 관점입니다.

검증 조건과 범위 보기

VerificationRedisTest 6건 통과. 실제 Redis와 모의 DB 조건에서 소유자의 최초 소비 성공, 타인·재소비 실패, 소비 뒤 늦은 완료 결과의 재생성 차단을 확인했습니다. 8개 워커에 제출한 16개 소비 요청 중 1개만 성공했습니다.

01 자료를 익스텐션에 넣고02 지식 나무로 모아보기03 TIL로 정리하고04 마이페이지에서 돌아보기
텍스트, 이미지, 링크를 드래그해 지식을 저장하는 SAN 크롬 확장 프로그램 화면
저장한 자료가 카테고리별 지식 나무로 모인 SAN 화면

흩어진 자료가 하나의 지식 나무로

저장한 지식을 바탕으로 오늘의 학습을 정리하는 SAN TIL 화면

저장한 지식을 오늘의 TIL로

학습 기록과 활동을 한눈에 보는 SAN 마이페이지 화면

쌓인 기록을 마이페이지에서

크롬 확장 프로그램 기반 지식 관리

SAN
03 / 04

흩어진 자료를, 다시 쓰는 지식으로.

크롬 확장 프로그램으로 저장한 자료를 검색, TIL, 지식 카드로 연결하는 서비스입니다. AI 정리 기능도 원문 근거를 남긴 상태에서 검토할 수 있도록 설계했습니다.

  • Java 21
  • Spring Boot 3.5.14
  • Spring Data JPA
  • PostgreSQL
  • Redis
  • React 18.3
  • TypeScript 5.9
팀 구성
7명 · FE 1 · BE 3 · AI 2 · INFRA 1
담당 범위
서버 검색, AI 입력 보호, 작업 상태 관리
Chrome Web Store에서 SAN 보기
SAN / PROBLEM 01검색 성능 · 조회 범위

1만 건을 내려받는 대신, 필요한 50건만.

브라우저의 전체 목록 필터를 서버 검색으로 옮기고, 태그 집계와 정렬 기준을 정리했습니다.

검색 첫 50건 · p95 낮을수록 빠름 / 같은 축
전체 목록 → 브라우저 필터
133.67 ms
서버 검색 → 필요한 결과
19.04 ms
최신 50건의 응답 크기5.09 MB26.9 KB

전체 다운로드 대신 필요한 페이지를 반환합니다.

소유자 격리태그 조건 집계시간 + ID 안정 정렬
01 · PROBLEM

카드가 늘수록 전체 목록 전송·파싱·브라우저 필터 비용이 함께 커졌습니다. 검색을 서버로 옮겨도 태그 집계 경로를 함께 점검해야 했습니다.

02 · DECISION

응답 속도뿐 아니라 소유자 격리, 검색 조건, 페이지 순서도 유지하는 기준을 잡았습니다.

03 · BUILD

카드 ID별 태그를 집계하고 HAVING COUNT(DISTINCT tag)로 조건을 적용했습니다. createdAt과 cardId를 함께 정렬해 페이지 순서를 고정했습니다.

04 · EVIDENCE검색 첫 50건 p95 133.67 → 19.04ms. 최신 50건 응답 약 5.09MB → 26.9KB.

개발 브랜치 · 로컬 합성 1만 건 · 워밍업 3회 / 측정 20회

APPLICATION

업무 자료 조회에서 데이터 전송량과 검색 누락·권한·페이지 일관성을 함께 확인하는 관점입니다.

검증 조건과 범위 보기

개발 브랜치에서 HTTP 수신·JSON 파싱·기준선 클라이언트 필터를 포함해 측정했습니다. 최신 50건 p95는 128.15 → 28.50ms, 응답은 5,085,664 → 26,903B입니다. 작은 100건 조건에서는 최신 조회가 18.97 → 23.67ms로 느려져 데이터 규모에 따른 차이도 확인했습니다.

SAN / PROBLEM 02ASYNC AI · SOURCE SNAPSHOT

원문이 바뀌어도, AI가 읽은 입력은 그대로.

생성 요청 시 원문과 AI 전달문을 고정해, 비동기 작업이 나중의 수정본을 읽지 않도록 했습니다.

이번 생성의 입력과 현재 원문을 분리 SOURCE SNAPSHOT
01 · REQUEST

SOURCE A

카드·스크랩 ID
제목 · 원문 · URL · AI 입력

02 · SNAPSHOT

SNAPSHOT A

DailySummary에 보존

03 · AI RUN

INPUT A

저장된 aiInput 사용
현재 카드 재조회 없음

그사이 원문을 수정해도CURRENT SOURCE B이번 요청의 SNAPSHOT A는 유지
TRACEABLE INPUT최신 원문이 아니라,
생성 당시의 입력을 남깁니다.
01 · PROBLEM

요청과 AI 실행 사이에 원문을 수정하면, 생성에 쓴 내용과 나중에 확인하는 근거가 달라질 수 있습니다.

02 · DECISION

항상 최신 내용을 읽는 대신 “이번 생성에 무엇을 전달했는가”를 재현할 수 있게 했습니다.

03 · BUILD

captureSnapshots에 카드·스크랩 ID, 제목, 원문, URL과 AI 입력을 저장합니다. toAiContents는 현재 카드가 아니라 저장된 스냅샷으로 AI 요청을 구성합니다.

04 · EVIDENCE원문·정제 입력의 보존과 저장된 입력 반환을 단위 테스트의 검증문으로 확인.

입력 보존·반환 로직 및 단위 테스트 검증문 확인

APPLICATION

업무 보조 AI의 결과를 검토할 때, 생성 당시 입력을 추적할 수 있게 만드는 관점입니다.

검증 조건과 범위 보기

TilSourceService와 TilSourceServiceTest에서 원문·정제 입력 보존과 저장된 입력 반환 로직을 확인했습니다. 검증 범위는 코드와 테스트 검증문 확인이며, SRC 식별자로 생성에 사용한 입력을 연결합니다.

하루 한 번 자가 진단을 시작하는 다시봄 iPhone 목업 화면표정과 한쪽 눈 윙크를 안내하는 다시봄 iPhone 목업 화면가까운 병원 정보를 지도에 표시한 다시봄 iPhone 목업 화면

AI 기반 뇌졸중 위험 신호 확인 앱

다시봄
04 / 04

AI 분석 뒤, 결과와 가까운 병원 정보를 바로 확인합니다.

얼굴·음성·설문으로 뇌졸중 위험 신호를 확인하고, 결과와 병원 탐색으로 이어지는 모바일 앱입니다.

  • React Native
  • Spring Boot
  • MySQL
  • AI 분석 API
팀 구성
4명 · FE 1 · BE 1 · AI 2
담당 범위
서비스 기획·UI/UX, React Native 화면과 카메라·음성·지도·차트 연동
다시봄 / PROBLEM 01민감한 입력 · AI 응답 검증

분석에 쓴 원본과, 기록에 남길 결과를 분리했습니다.

프로젝트에서 원본 업로드 경로를 제거하고, 입력과 AI 응답을 각각 검사하는 경계를 검증했습니다.

호출 전 검사 → 저장 전 검사 서비스의 진단 처리 경로
  1. 01

    얼굴·음성 입력

    영상 ≤ 50MB / 음성 ≤ 20MB

    형식·용량 검사
  2. 02

    외부 AI 분석

    요청 메모리에서 원본 전달

    판정값·확률 검사
  3. 03

    파생 결과 기록

    서비스 저장소에 원본 업로드 안 함

    허용된 응답만 저장
호출 전용량 초과 · MIME 불일치AI 호출하지 않음
저장 전판정값 2 · 확률 1.3진단 기록 저장하지 않음
서비스 저장 기준원본 파일 대신,
검사한 파생 결과만 남깁니다.
01 · PROBLEM

기존 진단 경로는 AI 호출 전 얼굴·음성 파일을 S3에 올렸습니다. 분석 뒤에도 원본을 보관해야 하는 이유는 확인되지 않았습니다.

02 · DECISION

원본은 분석에 전달하되 서비스 저장소에는 남기지 않고, 허용 범위의 판정값·확률만 기록하는 기준입니다.

03 · BUILD

S3 업로드 의존을 제거했습니다. 형식·용량은 AI 호출 전에, 판정값 0/1과 유한한 확률 0~1은 저장 전에 검사합니다. 외부 오류는 일반화된 코드로 반환합니다.

04 · EVIDENCE잘못된 입력은 AI 호출 전 차단. 판정값 2·확률 1.3 응답은 기록 저장 차단.

Mockito · H2 · 전체 백엔드 테스트 11건 통과

APPLICATION

민감한 자료를 분석에 사용하는 목적과 서비스에 보관할 대상을 분리하는 관점입니다.

검증 조건과 범위 보기

2026-09-19 백엔드 테스트를 강제 재실행해 5개 클래스의 11건이 실패·오류·스킵 없이 통과했습니다. 영상 mp4/mov 최대 50MB, 음성 wav/pcm/m4a 최대 20MB, 전체 multipart 요청 75MB 기준으로 검사합니다. 검증 대상은 서비스의 입력·응답 처리와 저장 경로입니다.

다시봄 / PROBLEM 02기록 조회 · 소유권 검사

로그인했어도, 다른 사람의 기록은 열 수 없게.

진단 ID만 찾던 조회를 사용자 ID까지 함께 확인하도록 바꾸고, 타인 요청의 차단 범위를 검증했습니다.

기록 ID + 인증 사용자 ID 소유권 확인 후 상세 조회
이전진단 ID만 조회변경진단 ID AND 사용자 ID
기록 소유자와 요청자가 일치

본인 기록

상세 조회 진행

결과와 연관 정보로 연결

기록 소유자와 요청자가 불일치

타인 기록

404

연관 병원 조회도 중단

상세 조회의 완료 조건“있는 기록인가?”가 아니라
“내 기록인가?”까지 확인합니다.
01 · PROBLEM

진단 ID만 조회하면 요청자와 기록 소유자가 연결되지 않습니다. 다른 사람의 ID를 아는 요청이 상세 기록으로 이어질 여지가 있었습니다.

02 · DECISION

기록의 존재 여부보다 소유권을 먼저 확인합니다. 일치하지 않으면 연관 병원 정보 조회도 진행하지 않습니다.

03 · BUILD

인증 사용자 ID를 컨트롤러에서 서비스로 전달합니다. findByIdAndUserId로 기록을 조회하고, 일치하지 않으면 DIAGNOSIS_NOT_FOUND로 처리합니다.

04 · EVIDENCE타인 기록 요청은 404. 이때 연관 병원 저장소 조회도 호출되지 않음을 확인.

Mockito · 소유권 서비스·컨트롤러 테스트 각 1건

APPLICATION

개인별 청구·건강 관련 기록을 조회할 때 로그인 여부와 대상 데이터의 소유권을 따로 검사하는 관점입니다.

검증 조건과 범위 보기

DiagnosisQueryServiceTest에서 타인 진단 ID 요청의 404 응답과 병원 저장소 미호출을 확인했습니다. DiagnosisControllerTest에서는 인증 사용자 ID가 서비스로 전달되는지 검사했습니다. 서비스·컨트롤러 단위의 검증입니다.

병원 탐색 화면 보기
병원 탐색 원본 크게 보기 ↗
다시봄 지도, 병원 상세와 검색 목록 원본 캡처