「웹 서비스 보안 점검을 위한 CVE 기반 웹 취약점 진단 도구」로 2026 한국정보기술학회 하계 종합학술대회에 제2저자로 게재
백엔드 API 라우트와 OpenAPI 명세를 분석해 프론트엔드 관점의 데이터 전송 구조 설계서를 직접 작성하고, 각 필드의 역할·제약 조건·응답 구조를 정리
공통 입력 → 엔드포인트 → 실행 → 리포트로 이어지는 4단계 진단 흐름을 화면으로 설계하고, 각 단계에서 필요한 입력만 노출되도록 구성
인증이 필요한 대상과 그렇지 않은 대상을 구분해, 로그인 필요를 선택했을 때만 Cookie·Authorization 입력이 나타나도록 조건부 폼 설계
단일 화면에 대량 나열되던 진단 결과를, 설정 패널에서 엔드포인트를 선택하면 해당 결과만 필터링해 보여주는 구조로 리팩터링
기술 스택 진단과 엔드포인트 진단이 동시에 출력될 때 이전 결과가 남는 상태 오염 문제를 고유 식별 키 기반 초기화 로직으로 해결
문제 해결 · 동시 진단 결과의 상태 오염
기술 스택 진단과 엔드포인트 진단이 함께 출력될 때 이전 진단의 잔재가 화면에 남아, 사용자가 어떤 대상의 결과를 보고 있는지 알 수 없었습니다. 결과를 고유 식별 키 기준으로 관리하고 대상이 바뀌면 상태를 초기화하도록 바꿔 해결했습니다. 다만 검증은 테스트 환경에서만 이루어져, 실제 서비스 환경에서의 추가 검증은 과제로 남아 있습니다.
서버가 소유한 데이터는 React-Query, 새로고침에도 유지돼야 하는 여정 ID·설정은 Zustand persist로 소유 주체를 기준으로 분리
로컬에 저장한 여정 ID가 서버에서 사라졌을 때 화면이 빈 스켈레톤에 멈추는 문제를, 조회 실패를 감지해 ID를 비우고 탑승권 스캔 화면으로 되돌리는 공통 훅(useClearStaleJourney)으로 해결하고 조회 3곳에 적용
응답을 받지 못한 경우(네트워크·타임아웃)와 서버가 오류를 내려준 경우를 구분해 안내하도록 로그인 에러 분기를 순수 함수로 분리
공통 로딩·에러 컴포넌트(WakingScreen 17개 화면, ErrorState 14개 화면)를 설계해 실패 시 항상 재시도 경로를 노출
Vitest를 도입해 위 두 로직을 테스트 8개로 고정 (화면에서 재현하기 어려운 실패 경로 우선)
아이콘만으로 구성된 하단 네비게이션 등에 aria-label을 부여해 스크린리더에서 항목이 구분되도록 개선
문제 해결 · 로컬에 저장한 서버 상태가 무효화되는 문제
여정 ID를 localStorage에 저장해 새로고침에도 유지되게 했으나, 서버에서 해당 여정이 사라지면 조회가 계속 실패해 사용자에게는 앱이 멈춘 것처럼 보였습니다. 조회 실패를 감지해 저장된 ID를 비우고 첫 화면으로 되돌려, 사용자가 스스로 복구할 수 있는 흐름으로 만들었습니다. 로컬에 상태를 들고 있는 환경이라면 어디서든 생길 수 있는 문제라고 보고 있습니다.
상영 시간 조회부터 관람 인원 선택, 좌석 예매, 결제까지 이어지는 예매 플로우를 구현한 4인 팀 프로젝트
담당 역할 프론트엔드 (회원가입/로그인, 관람 인원 선택, 좌석 예매, 미니맵, 쿠폰, 외부 API 연동)
FlutterFirebase외부 API 4종
좌석 위치와 종류를 UI 코드에 하드코딩하지 않고 좌석 모델·레이아웃 데이터로 분리해, 상영관마다 배치가 달라도 같은 렌더링 구조를 재사용하도록 구성
SWEETBOX·우대석·Light Zone 등 좌석 종류에 따라 다른 에셋을 반환하도록 렌더링을 분기하고, Light Zone은 CustomPainter로 별도 구현
관람 인원 수를 기준으로 선택 가능한 좌석 수를 검증하고, 좌석 선택이 바뀔 때 총 금액이 함께 갱신되도록 상태 흐름을 연결
권종별 가격 계산을 화면에서 분리해 TicketPrice 모듈로 옮겨, 가격 정책이 바뀌어도 화면 코드를 수정하지 않도록 구성
상영 시간 조회를 Service로 분리하고 FutureBuilder로 로딩·오류·데이터 없음 상태를 각각 처리
예매 완료 시 잔여 좌석 감소를 Firestore Transaction으로 처리하고, 잔여 좌석보다 예약 인원이 많으면 음수가 되지 않도록 검증
영화, 주차, 교통 관련 4종 외부 API를 예매 플로우에 결합
문제 해결 · 동시 예매 시 잔여 좌석이 잘못 갱신될 수 있던 문제
잔여 좌석을 조회한 뒤 그 값을 빼서 다시 쓰는 방식이면, 두 사람이 동시에 예매할 때 한쪽의 감소가 덮어써질 수 있었습니다. Firestore Transaction 안에서 최신 좌석 수를 다시 읽고 감소시키도록 바꾸고, 예약 인원이 잔여 좌석보다 많은 경우를 먼저 막았습니다.
문제 해결 · 잘못된 병합 상태에서 작업 복구
여러 브랜치를 병합하다 충돌과 함께 의도하지 않은 커밋 상태가 만들어졌습니다. 충돌 파일만 고쳐서는 이전 상태로 돌아갈 수 없어, git reflog로 HEAD가 움직인 이력을 따라가며 병합 직전의 정상 커밋을 찾아 작업 상태를 되돌린 뒤 브랜치를 다시 정리했습니다.
Repository: https://github.com/hwkong7/KGV-Clone
Gift Picker
개인 프로젝트
선물 추천 웹 서비스
사용하던 외부 쇼핑 API의 서비스 종료로 기능이 중단되자, 대체 데이터 소스로 마이그레이션하며 호출 비용과 응답 지연까지 함께 개선한 프로젝트
담당 역할 1인 단독 개발 (기획, 프론트엔드, 서버리스 API, 배포)
React 19TypeScriptViteVercel FunctionsSupabase
기존 쇼핑 API 종료로 추천 기능이 중단되자, 검색 결과 기반 데이터 소스(SerpApi)로 파이프라인을 재구성
정제되지 않은 검색 결과가 그대로 노출되는 문제를 필수 키워드 필터링으로 1차 차단하고, 생성형 AI로 검색어를 정제해 추천 정확도 개선
동일 조건 재검색이 잦다는 점에 착안해 쿼리 기준 캐시(TTL 1시간)를 도입, 유료 API 중복 호출과 응답 지연을 감소
외부 API 의존은 언제든 끊길 수 있다는 전제로 데이터 소스를 교체 가능한 계층으로 분리
문제 해결 · 외부 API 서비스 종료로 인한 기능 중단
동일한 대체 API가 없어 데이터 소스 구조부터 다시 설계해야 했습니다. 검색 결과를 수집한 뒤 필터링과 AI 정제를 거치는 파이프라인으로 재구성하고, 캐시 레이어를 두어 비용과 지연을 함께 줄였습니다.
파일을 삭제하거나 옮긴 뒤에도 화면에는 이전 목록이 남아 있었습니다. 파일 작업의 성공 여부만 확인하고 화면 상태를 갱신하지 않은 것이 원인이라, 작업이 끝난 뒤 폴더 목록을 다시 조회해 반영하도록 바꿨습니다. 로컬 상태와 실제 상태가 갈라지면 사용자는 앱을 믿을 수 없게 된다고 생각합니다.
Repository: https://github.com/hwkong7/snaptidy
Troubleshooting
막혔던 순간들
Debugging
앱이 반복해서 종료되던 원인 찾기
실디바이스 테스트 중 앱이 계속 꺼졌지만 화면만으로는 원인을 알 수 없었습니다. Logcat 전체 로그를 모아 분석해 네트워크 요청 타이밍, 상태 초기화 누락, 잘못된 값 전달 예외 세 가지를 각각 확인하고 수정했습니다.
Git
잘못된 병합 상태에서 작업 복구하기
여러 브랜치를 병합하다 충돌과 함께 의도하지 않은 커밋 상태가 만들어졌습니다. 충돌 파일만 고쳐서는 이전 상태로 돌아갈 수 없어, git reflog로 HEAD가 움직인 이력을 따라가며 병합 직전의 정상 커밋을 찾았습니다. 그 시점으로 작업 상태를 되돌린 뒤 브랜치를 정리하고, 팀원들의 변경사항을 다시 확인하며 병합했습니다.
Data Consistency
동시에 예매하면 좌석 수가 어긋날 수 있던 문제
잔여 좌석을 읽고 그 값을 빼서 다시 쓰는 방식이면, 두 사람이 동시에 예매할 때 한쪽의 감소가 덮어써질 수 있었습니다. Firestore Transaction 안에서 최신 값을 다시 읽고 감소시키도록 바꾸고, 예약 인원이 잔여 좌석보다 많은 경우를 먼저 막았습니다.
Error Handling
장애 원인이 화면에서 구분되지 않던 문제
백엔드 콜드스타트로 첫 응답이 수십 초까지 지연되는 환경에서, 비밀번호 오류와 네트워크 타임아웃이 같은 문구로 표시됐습니다. 응답 status가 없는 경우와 서버가 반환한 오류를 나눠 안내하도록 분기하고, 그 로직을 순수 함수로 분리해 테스트로 고정했습니다.