경력기술서
강윤수 (lomong) · Backend & DevOps Engineer
- GitHub: https://github.com/lomong7807
- Blog: https://lomong7807.tistory.com/
- 작성일: 2026-09-11
1. 경력 요약
| 회사 | 기간 | 직함 · 팀 규모 | 담당 영역 |
|---|---|---|---|
| 라인업코리아 | 2024.09 ~ 재직 중 (2년 1개월) | 솔루션연구소 선임 개발자 · 개발팀 8-10명 | 데이터센터 모니터링 솔루션 개발 리드, 공공기관 기록관리시스템 고도화·보안 조치, 개발팀 인프라와 개발 프로세스 구축 |
| 에듀에듀 | 2023.12 ~ 2024.08 (9개월) | 개발사업팀 연구원 · 개발팀 15-20명 | 고객사 웹 플랫폼 핵심 기능 개발, 레거시 시스템 현대화 |
총 경력 2년 9개월 (2023.12 ~ 2026.09)
2. 핵심 역량 요약
- 백엔드 End-to-End: 요구 정리와 설계 문서 작성부터 구현, 테스트, 배포, 운영 대응까지 맡아 진행합니다. Java/Spring Boot를 주력으로 Spring Boot 1.5 레거시부터 Spring Boot 3까지, Oracle·PostgreSQL·MySQL을 다뤘습니다.
- 인프라·CI/CD 자동화: Docker 환경 표준화, GitLab·Jenkins 온프레미스 구축, MR 검증 CI와 배포 파이프라인(헬스체크, 실패 시 자동 롤백, 배포 이력 기록, 알림) 구성을 직접 했습니다. 수동 배포 20분-1시간을 10분으로 줄였습니다.
- 레거시·보안 대응: 약 20만 LOC 레거시 시스템을 고도화하고, 테스트가 없던 코드베이스에 단위테스트를 도입했습니다. 외부 보안 진단 지적 사항을 조치해 재진단을 통과했고, 주력 언어가 아닌 C 수집기를 인수해 안정화했습니다.
- AI 협업 워크플로우: 커밋 컨벤션 문서와 MR 템플릿, 이를 강제하는 Claude Code hook, 프로젝트 rules·skill을 구성해 팀이 같은 방식으로 개발하도록 했습니다. 스펙 문서를 먼저 쓰고 구현한 뒤 여러 관점으로 검증하며, 설계 근거와 기각한 대안을 문서로 남깁니다.
주요 기술: Java, Spring Boot, JPA, QueryDSL, MyBatis, Thymeleaf, JSP · Oracle, PostgreSQL, MySQL, Redis · Docker, Jenkins, GitLab, nginx, Apache, Linux · Claude Code
3. 프로젝트별 상세
3.1 Rainbow Monitoring (데이터센터 모니터링 솔루션)
| 항목 | 내용 |
|---|---|
| 기간 | 2025.06 ~ 진행 중 |
| 소속 | 라인업코리아 솔루션연구소 |
| 역할 | 프로젝트 리드 (설계·개발, 배포 파이프라인, 개발 프로세스 정립). 2026년 6월 이후 단독 개발 |
| 사용 기술 | Java 17, Spring Boot 3, Spring Security, JPA, QueryDSL, PostgreSQL, Thymeleaf, Three.js, Apache POI, Apache MINA SSHD, Jenkins, GitLab, Prometheus, Claude Code |
프로젝트 설명
대학 고객사 약 30곳에서 사용하는 데이터센터 모니터링 웹입니다. 서버실, 랙, 장비를 3단 계층으로 등록·관리하고(고객사당 장비 1-30대), 별도의 수집 프로그램이 SNMP로 모아 적재한 네트워크·스위치 장비 데이터와 상태 정보를 대시보드로 보여줍니다. 이 웹의 설계와 개발을 리드하면서 배포 파이프라인 구성과 개발 프로세스 정립까지 맡았습니다. 2025년 하반기 프로토타입과 요구 정리를 거쳐 2026년 1월부터 본 개발을 진행하고 있습니다.
배경과 문제
기존 사내 NMS는 화면이 전부 영어였고 각 데이터가 무엇을 뜻하는지 분명하지 않았으며, 메뉴를 눌러 들어가야만 정보를 볼 수 있었습니다. 개발을 진행하면서 더 근본적인 문제도 발견했습니다. 장비 유형별로 상태 데이터의 출처가 달라 대시보드와 목록, 상세 화면이 서로 다른 장비 수를 보여주고 있었고, 팀은 “SNMP로 장비 상태를 확인한다”고 알고 있었지만 화면에 표시되는 ‘정상’은 실제로는 ICMP 응답 여부였습니다. 이 차이를 분석 문서로 정리해 공유했습니다.
기술 선택과 근거
- 상태 판정 기준 단일화: 판정 기준을 기준 문서 한 곳에 정의하고 모든 화면이 같은 경로를 따르게 했습니다. 화면마다 기준이 다르면 같은 장비가 화면마다 다른 상태로 보이기 때문입니다. 대신 상태를 SQL에서 바로 필터링할 수 없게 되어 Java 쪽에서 페이징하는 비용을 감수했고, 장비 수가 늘어나면 재검토한다는 조건을 문서에 남겼습니다.
- 장비와 에이전트 데이터 매칭을 IP 기준으로: 에이전트가 수집한 장비명과 웹에 등록한 장비명이 다를 수 있어 이름은 매칭 조건에서 빼고 IP만 사용했습니다. 매칭은 5분 주기로 반복 실행해도 결과가 같도록(idempotent) 동기화합니다.
- CI와 배포를 분리하되 같은 gradle 명령 사용: MR 검증 CI와 배포 파이프라인을 분리했지만 빌드·테스트는 동일한 gradle 명령을 쓰게 했습니다. 두 파이프라인이 다른 명령을 쓰면 “CI는 통과했는데 배포에서 빌드가 깨지는” 상황이 생깁니다.
- 배포 파이프라인에만 대기 시간을 둠: 배포는 여러 MR을 연달아 머지하는 상황이라 이벤트를 묶을 필요가 있지만, CI는 push 간격이 분 단위라 묶을 이유가 없습니다.
- AI 협업 워크플로우: 커밋 컨벤션 문서와 MR 템플릿을 만들고 이를 강제하는 Claude Code hook, 프로젝트 rules·skill을 구성했습니다. 스펙 문서를 먼저 쓰고 구현한 뒤 여러 관점으로 검증하는 흐름입니다.
수행 내용
- 서버실·랙·장비 3단 계층 등록·관리 화면과 상태 대시보드 개발
- 대시보드, 장비, 랙, 서버실, 사용자, SSH, 자산 도메인을 같은 계층 구조로 백엔드 구성
- 브라우저 SSH 터미널, 서버실 3D 배치 편집기, 엑셀 일괄 등록, 모니터링 지표 노출(Actuator, Prometheus) 구현
- 배포 파이프라인: 빌드·테스트, WAR 전송, Tomcat 재기동, 헬스체크, 실패 시 최신 백업 WAR로 자동 롤백, 변경 내역 수집, Notion 배포 이력 기록, Teams 알림
- MR 검증 CI: 빌드·테스트와 Gemini API 기반 AI 코드 리뷰를 MR 코멘트로 게시
업무 성과
- 화면마다 달랐던 장비 상태·장비 수 표시를 단일 판정 경로로 통일
- “SNMP 상태 확인”으로 알려졌던 판정이 실제로는 ICMP 응답임을 확인해 기능 설명과 화면 기준을 실제 동작에 일치
- 머지 이후 빌드·전송·재기동·헬스체크·롤백·이력 기록·알림까지 사람 개입 없는 배포 자동화
- MR 단위 빌드·테스트·AI 코드 리뷰 자동화로 리뷰 없이 머지되는 변경 0건
- 커밋 컨벤션·MR 템플릿·강제 훅 도입으로 팀 개발 규칙 통일
3.2 Rainbow 수집기(C) 인수 · 안정화
| 항목 | 내용 |
|---|---|
| 기간 | 2026.08 |
| 소속 | 라인업코리아 솔루션연구소 |
| 역할 | 인수 판단, 결함 분석, 수정 단독 수행 |
| 사용 기술 | C, CMake, PostgreSQL, ICMP, HMAC-SHA256, AES-GCM, Claude Code |
프로젝트 설명
외주로 개발된 장비 상태 수집기(C로 작성된 클라이언트·서버·상태 확인 프로세스 3종)를 인수해 운영 가능한 수준으로 안정화했습니다. Java가 주력이라 C에 익숙하지 않았지만 AI로 코드베이스의 구조와 데이터 흐름을 분석해 결함을 파악하고 직접 수정했습니다.
배경과 문제
1월 전달본을 검토해 지적한 12건 중 3월 최신본에서 고쳐진 것은 1건, 부분 수정 1건이었고 나머지는 그대로였습니다. 특히 실제 장애를 냈던 결함을 새로 추가된 컴포넌트가 그대로 반복하고 있었습니다. 개별 결함의 문제가 아니라 지적 사항이 개발 과정에 반영되지 않고 있다고 판단해 인수를 결정했습니다. 작업에 앞서 개발 DB와 설정 파일을 대조해 지금 운영 중인 버전이 무엇인지부터 확정했습니다.
기술 선택과 근거
- C 유지 (언어 전환하지 않음): 고객사 장비에 설치되는 클라이언트가 91KB 단일 바이너리에 런타임 의존성이 없다는 점은 설치 환경을 가리지 않아야 하는 제품에서 포기하기 어려운 이점입니다. 이번 작업의 목적은 언어 전환이 아니라 코드 소유권을 내부로 가져오고 안정화하는 것이었습니다.
- 검증 로직을 수신 진입점 한 곳으로 집중: 우선순위가 높은 결함 3건(인증 없는 패킷으로 서버가 중단, 검증 없는 길이 값으로 메모리 밖을 읽은 뒤 DB에 적재, 클라이언트 소유권 미확인)을 처리하면서 검증을 메시지 처리 진입점 한 곳에 모았습니다. 케이스마다 나눠 두면 메시지 유형을 추가할 때 검증이 누락되기 쉽기 때문입니다. 수정은 전부 TDD로 진행했습니다.
- 중복 기동 방지에 PostgreSQL advisory lock: 지켜야 할 대상이 데이터 행이 아니라 프로세스 자리이고 lock 수명이 데몬 수명(수 시간에서 수 일)이라 트랜잭션 lock은 맞지 않았습니다. SELECT FOR UPDATE를 장기 유지하면 VACUUM이 오래된 행을 정리하지 못해 테이블이 부풀고 XID 소진 위험이 생깁니다. flock이나 pidfile은 같은 호스트에서만 유효한데 충돌 자원이 DB라 맞지 않았습니다.
- CMake 기반 재현 가능한 빌드: 빌드 대상에서 제외한 항목은 사유와 함께 문서로 남겼습니다.
수행 내용
- 지적 사항 12건의 처리 현황 대조, 인수 판단 근거 정리, 운영 중인 버전 확정
- 안정성 결함 3건 TDD 수정, advisory lock 기반 중복 기동 방지 구현
- 상태 표시가 5초 주기로 바뀌던 현상의 원인 규명: 상태 확인 프로세스 2개가 동시에 떠 서로 상태를 덮어쓰고 있었습니다. 실제 운영에서 관측된 장애입니다.
- CMake 재현 빌드 구성
업무 성과
- 외주 의존이던 수집기 코드를 인수해 내부 수정·빌드 체계 확보
- 외주 미수정 결함 10건 포함 검토 후 서버가 중단될 수 있는 안정성 결함 3건 수정, 테스트로 고정
- 5초 주기로 상태가 뒤바뀌던 운영 장애를 advisory lock으로 제거
- 실행파일 3종 CMake 재현 빌드 구성으로 환경 무관 동일 산출물 확보
3.3 서울기록원 기록관리시스템 웹 취약점 조치
| 항목 | 내용 |
|---|---|
| 기간 | 2026.08 |
| 소속 | 라인업코리아 (서울기록원 영구기록물관리시스템) |
| 역할 | 웹 애플리케이션 영역 취약점 조치 전담, 단위테스트 78건 작성 |
| 사용 기술 | Java 8, Spring MVC, Spring Security, JUnit, Claude Code |
프로젝트 설명
외부 보안 진단에서 지적된 항목 중 웹 애플리케이션 영역 5건(불충분한 인가 2건, 경로 추적, 파일 업로드, Stored XSS)을 조치했고, 단위테스트 78건을 함께 작성했습니다. 조치 후 재진단을 통과했습니다.
배경과 문제
지적된 항목 대부분이 UI에서 버튼만 숨기고 서버는 막지 않는 패턴이었습니다. 게시판은 여러 컨트롤러가 각자 권한 검사를 갖고 있으면서도 그 결과를 버튼 숨김에만 쓰고 있어, API를 직접 호출하면 권한 없이 저장이 되었습니다.
기술 선택과 근거
진단보고서의 권고를 그대로 따르지 않고 근거를 들어 다르게 처리한 지점이 세 곳 있습니다.
- Stored XSS: 입력 이스케이프(권고) 대신 출력 인코딩. 렌더링이 안전하다면 저장값을 이스케이프해도 보안에 도움이 되지 않고, ’&’ 같은 평범한 문자가 깨지며, 수정 화면에서 원문을 복구할 수 없기 때문입니다. 실제 원인은 벤더 JS가 내용이 비어 있으면 innerHTML 경로를 타는 분기였고, textContent로 수정했습니다. 같은 방식의 바인딩을 전부 확인해 서버가 HTML을 주입하는 곳이 한 곳뿐임을 확인한 뒤 적용했습니다.
- 파일 업로드: 차단목록 대신 허용목록. jsp, jspx, jspf 같은 변종이 계속 생기기 때문에 차단목록은 하나만 빠져도 우회됩니다. 허용 확장자는 개발 DB에 실제로 저장된 첨부 파일의 확장자를 조사해 정했습니다.
- 경로 추적: 문자 필터링 대신 정규화 후 차단. 정상 요청에도 슬래시와 점이 들어가므로 문자 필터링은 정상 기능을 막거나 우회를 허용하게 됩니다.
그 밖의 판단은 다음과 같습니다.
- 인가 검사 기준을 요청 URL 문자열이 아니라 Spring 라우팅 결과로: 요청 문자열을 그대로 비교하면 실제 라우팅 결과와 달라집니다. 이 과정에서 우회 경로 3종(퍼센트 인코딩, path parameter, 더블 슬래시)을 직접 찾아 차단하고 각각을 테스트로 고정했습니다.
- 과차단 방지를 테스트로 고정: 공격 케이스만 고정하면 정상 업무가 막히는 것을 잡을 수 없어, 한글 파일명(NFC/NFD 조합)이나 이름에 점이 여러 개 들어간 정상 업무 파일이 통과하는 것도 함께 테스트로 남겼습니다.
수행 내용
- 인가 검사 재구성과 우회 경로 3종 차단, 파일 업로드 허용목록 전환, 경로 추적 정규화 차단, Stored XSS 출력 인코딩 처리
- 연쇄 문제 수정: 403을 반환하도록 바꾸자 공통 예외 핸들러가 403을 일반 오류로 처리해 화면에 전달되지 않았고, 그것을 고치자 프론트 공통 ajax 래퍼가 403을 success 콜백으로 전달해 화면에 표시되지 않았습니다. 세 지점을 모두 수정했습니다.
- 테스트가 없던 코드베이스에 단위테스트 78건 작성 (공격 케이스와 정상 업무 케이스 양쪽)
- 조치 과정에서 요청받지 않은 취약점 2건을 추가로 발견해 보고
업무 성과
- 웹 취약점 5건 조치, 재진단 통과
- 진단에 없던 인가 우회 경로 3종 추가 차단
- 단위테스트 0건에서 78건으로 확대, 보안 조치 회귀 여부를 자동으로 검증
- 파일 업로드 허용 확장자 21종 실측 기반 도출로 정상 업무 파일 과차단 0건
- 미신고 취약점 2건 추가 발견·보고
3.4 서울기록원 기록관리시스템 기능 개발 및 유지보수
| 항목 | 내용 |
|---|---|
| 기간 | 2026.02 ~ 진행 중 (데이터 추출 기능은 검수 대기) |
| 소속 | 라인업코리아 (서울기록원 영구기록물관리시스템) |
| 역할 | 정리기술 모듈 설계·개발, 대용량 엑셀 다운로드 개선 등 기능 개발·유지보수 담당. 대상 시스템은 2017년부터 운영된 약 20만 LOC 규모의 레거시 |
| 사용 기술 | Java 8, Spring Boot 1.5, Oracle 19c, MyBatis, JPA, QueryDSL, Apache POI(SXSSF), Gradle 멀티모듈, Claude Code |
프로젝트 설명
2017년부터 운영된 약 20만 LOC 레거시 기록관리시스템의 기능 개발과 유지보수를 담당했습니다. 기존 “전거 관리” 메뉴 그룹을 “정리 기술(Arrangement & Description)“로 재편하고, 개발한 화면들을 그 아래로 모아 전용 역할을 부여했습니다. 화면은 전거 등록부(기존), 전거 일괄 등록, 신청 관리, 철·건 일괄 수정, 데이터 추출로 구성되며, 승인 관리와 헤더 알림으로 이루어진 승인 인프라를 네 화면이 공유합니다. 이와 별도로 공개재분류 화면의 대용량 엑셀 다운로드가 실패하던 운영 문제를 원인부터 추적해 구조를 바꿨습니다.
배경과 문제
업무프로세스 정의서 두 건이 동일하게 “대량 메타데이터 수정은 개발자가 직접 SQL 쿼리로 처리하고 있다”고 적고 있었습니다. 목표는 세 가지였습니다. 개발자 의존도 제거, 현재값과 변경값을 diff로 미리 보여 주어 실수 방지, 검증에서 미리보기를 거쳐 확정에 이르는 3단계로 잘못된 수정 차단입니다.
데이터 추출은 성격이 조금 다른 문제였습니다. 약 44만 건 규모의 기록물 DB에서 담당자는 상세 조건이 걸린 데이터 추출을 웹에서 스스로 할 수 없어 개발자에게 구두나 문서로 요청하고, 개발자가 쿼리를 작성해 파일로 전달하는 흐름이었습니다. 담당자가 생각한 데이터와 개발자가 만든 데이터가 달라 재작업이 반복됐습니다. 실제 사례에서는 요청서에 적히지 않은 조건 3가지(기간 조건 불필요, 분권 포함, 분권을 부모 철 기준으로 정렬)가 뒤늦게 드러나 쿼리를 두세 번 다시 고쳤습니다. 그때그때 만든 일회성 SQL이 여러 개 남아 있었습니다. 담당자가 직접 조건을 정해 추출할 수 있는 기능이 필요했습니다.
엑셀 다운로드 문제는 운영 중 접수된 장애였습니다. 공개재분류 검토의견 등록 화면에서 규모가 큰 연도 계획의 일괄처리 엑셀을 받으면 서버 오류 페이지가 표시됐고, 새로고침하면 파일이 받아졌습니다. 처음에는 운영 서버에 남아 있던 깨진 파일명(JVM 기본 인코딩)을 원인으로 봤지만, 새로고침 시 정상 동작하는 현상과 맞지 않아 제외했습니다. 네트워크 응답 헤더를 확인하니 실패한 요청의 응답 서버가 WAS가 아니라 앞단 장비였습니다. 엑셀 생성 요청이 30초를 넘기면(건 목록 쿼리 하나가 운영에서 18초) 앞단 장비가 연결을 끊고 500을 반환했고, 화면 공통 ajax는 이를 성공 콜백으로 전달하며, 화면 콜백은 오류 여부를 확인하지 않고 아직 생성되지 않은 파일의 다운로드로 이동하고 있었습니다. 서버 스레드는 계속 실행되어 파일을 완성하므로 새로고침하면 받아진 것입니다. 정리하면, 화면이 생성 완료로 잘못 판단해 아직 없는 파일을 요청한 문제였습니다.
기술 선택과 근거
공통 승인 파이프라인
- 신청, 승인, 반영의 3단계 분리: 신청 단계에서는 신청 내용만 저장하고 실제 INSERT/UPDATE는 승인 시점에 단일 트랜잭션으로 처리해 실패 시 전체가 롤백되게 했습니다.
- 승인 유형별 처리기 연결: 승인 유형을 enum으로 정의해 유형별 처리기를 연결하고, 신규 유형을 추가할 때 분기 한 줄로 끝나도록 했습니다. 순환 의존은 지연 주입(@Lazy)으로 피했습니다. 세 기능(일괄 등록, 일괄 수정, 데이터 추출)에 재사용해 검증했습니다.
- 승인 시점 optimistic lock: 신청 시점의 값과 승인 시점의 현재값을 비교해 충돌을 검출합니다. 충돌은 toast로 하나씩 알리지 않고 전부 모아 표 모달로 한 번에 보여 줍니다. 일괄 등록과 일괄 수정이 공유합니다.
- 대량 처리 대응: 3,000행 상한을 두고, Oracle IN 절의 1,000개 제한은 900개 단위로 나눠 조회하며, 식별자 자릿수가 섞여 있어 자릿수에 관계없이 매칭되게 했습니다.
데이터 추출
- 모든 추출을 백그라운드 잡으로 통일: 설계 인터뷰에서 예상 소요 시간에 따라 동기와 비동기로 분기하는 안 대신 전부 백그라운드로 통일하자고 제안해 확정했습니다. 분기 로직과 이중 경로가 사라지고, 앱에 이미 있던 비동기 스레드풀과 알림 시스템을 재사용할 수 있기 때문입니다. 소량 추출은 수 초 내에 끝나 알림 폴링 주기(최대 60초) 안에 도달합니다. 실제로 이후 동기로 남겨 둔 건수 확인 구간이 대용량 테이블 full scan으로 60초 statement timeout에 걸리는 일이 있었습니다.
- 상한 20만 건: 계산으로 유도한 값이 아니라 실제 요청 사례 약 11.5만 건의 약 2배를 여유로 잡은 운영 상한입니다. 목적은 스레드풀과 DB 보호입니다. 시트별 상한을 쓰고 합산 상한을 기각한 데에는 근거가 있습니다. 최대 루트 하나만 선택해도 약 236만 행으로 전개되기 때문에, 합산 상한은 정상적인 선택까지 차단합니다. hard stop은 상한의 110%인 22만 건입니다.
- 영구 워크테이블과 INSERT…SELECT 안의 Oracle CONNECT BY: 전역 임시 테이블(GTT)은 커넥션 풀이 세션을 고정하지 않아 기각했고, 자바에서 트리를 순회하는 안은 전체 전개가 실측 약 3.5초라 필요하지 않았습니다. 스트리밍 대신 적재를 택한 핵심 이유는 정렬입니다. “철 분류번호 순서, 그 철 아래에 분권을 인터리브”하는 순서는 CONNECT BY의 행 산출 순서로 보장할 수 없어, 적재한 뒤 ROW_NUMBER()로 일괄 채번했습니다.
- SXSSF와 1만 행 청크, .tmp 후 rename: 기존 공통 엑셀 헬퍼는 고정 템플릿과 전량 List를 전제로 해서 쓸 수 없었습니다. 기존의 대량 처리 사례도 전량 List 적재 방식이라, 19개 이상 컬럼에 20만 건이면 수백 MB heap을 점유해 WAR로 올라가는 Tomcat에서 위험합니다. 1만이라는 청크 크기는 관례적으로 쓰는 값입니다. ROWNUM 페이징 대신 순번 범위 조회를 쓴 이유는 순번이 워크테이블에 고정되어 순서와 중복 문제가 없기 때문입니다. .tmp로 쓰고 완료 후 rename하는 것은 쓰다가 죽은 파일이 정상 완료 파일로 오인되는 것을 막기 위해서입니다.
- 전용 스레드풀 분리: 공용 스레드풀은 다른 리스너와 공유되기 때문입니다. “동시 1건” unique index guard와 함께 묶은 보호 장치 중 하나입니다.
- 모든 상태 전이를 CAS로 처리: 이 규칙이 없으면 사용자가 취소한 잡이 뒤늦게 완료 상태로 바뀔 수 있습니다. 취소도 조회 후 UPDATE가 아니라 단일 CAS 문으로 처리했습니다. 조회와 UPDATE 사이에 워커가 상태를 실행 중으로 바꾸면, 취소됐다고 표시되지만 실제로는 실행되는 상태가 되기 때문입니다.
- 복구 수단: 1시간을 넘긴 실행 중 작업을 실패로 돌리는 sweeper는 기존 배치의 방식을 따랐고, 주 복구 수단은 애플리케이션 기동 시 동작하는 리스너입니다. 30일 경과 파일 삭제는 저장 볼륨 문제에 대한 대응이며 30일이라는 값은 관례적으로 정했습니다.
대용량 엑셀 다운로드
- 비동기 생성 + 짧은 상태 확인(폴링) 채택: 대안 네 가지를 비교했습니다. 앞단 장비 타임아웃 연장은 공공기관 특성상 변경 절차가 길고 값을 알 수도 바꿀 수도 없으며 계획이 커지면 다시 걸리는 임시 조치라 제외했고, 쿼리 튜닝은 18초짜리 쿼리를 줄여도 데이터가 늘면 다시 30초를 넘기므로 제외했으며, 메시지큐 도입은 폐쇄망에 새 미들웨어를 들이는 비용이 커 제외했고, WebSocket/SSE는 앞단 장비 통과 여부를 확인할 수 없어 제외했습니다. 설계 원칙은 세 가지로 정했습니다. 어떤 HTTP 요청도 30초를 넘기지 않는다, 새 미들웨어와 새 테이블을 만들지 않는다, 앞단 장비 설정을 몰라도 동작한다.
- 상태를 파일 이름으로만 표현: 접수(.tmp) → 생성 중(같은 파일에 내용 누적) → 완성(.xlsx, 원자적 rename) → 실패(.err). 파일이 .xlsx 이름을 갖는 시점이 완성 시점이므로 완성되지 않은 파일이 노출되지 않고, 별도 상태 테이블이 필요 없습니다.
- 폴링 비용 검토: 상태 확인 요청은 파일 존재 여부만 확인하므로 10-40ms에 끝납니다. 기존 방식은 요청 스레드 하나를 1-2분 점유했으므로 새 구조가 서버 부하 면에서도 더 낮습니다.
- 엑셀 전용 스레드풀 분리: 워크플로우용 기존 풀을 같이 쓰면 1-2분짜리 엑셀 작업이 스레드를 점유해 배치 작업이 실행되지 못하기 때문입니다.
- 접수 표시 파일을 요청 스레드가 만들고, 원자적 파일 생성을 잠금으로 사용: 생성 스레드가 표시 파일을 만들면 큐에서 대기하는 동안 디스크에 아무 파일이 없어 화면이 시작되지 않은 것으로 잘못 판단했습니다. 또 파일 이름이 초 단위 시각이라 같은 초에 두 사람이 요청하면 파일이 겹쳐 다른 사람의 엑셀을 받을 수 있었습니다. 요청 접수 즉시 표시 파일을 만들고 그 생성 자체를 잠금으로 사용해 두 문제를 함께 막았습니다.
- 예상 완료 시간 기능을 구현했다가 제거: 계획별 지난 소요 시간으로 남은 시간을 보여주는 기능을 검증까지 마쳤지만, 같은 계획이 환경에 따라 18초에서 6분까지 차이가 나 예측이 자주 빗나가고, 그 한 줄을 위해 오래 남는 파일이 쌓여 운영자가 관리할 대상이 늘어난다고 판단해 제거했습니다. 대기 중 상태는 단계 진행 표시와 경과 시간, 15분 상한 안내로 대신했습니다.
수행 내용
- 신청, 승인, 반영 공통 파이프라인 설계와 구현
- 전거 일괄 등록, 철·건 일괄 수정, 신청 관리, 승인 관리, 헤더 알림 화면 개발
- 관계전거를 즉시 반영에서 승인제로 전환, 6개 유형별 팝업을 반복하던 흐름을 다중선택 1회로 변경, 헤더 알림에서 해당 행으로 자동 이동
- 데이터 추출: 조건 필터, 계층 트리 추출, 백그라운드 잡 큐, SXSSF 청크 엑셀 생성
- 성능 진단: 8건 추출에 245초가 걸리던 문제를 로그로 분해해 거의 전부가 단일 쿼리에서 발생함을 확인했고, 신규 워크테이블의 통계가 없어 대용량 테이블 full scan이 일어나고 있었습니다. 통계 수집 후 1-3초로 떨어졌고 통계를 고정해 자동 수집에 의존하지 않게 했습니다. 이 과정에서 대형 테이블의 통계가 수년간 갱신되지 않은 상태임을 확인했습니다.
- 기록건 미리보기 응답 개선: 키를 정렬한 뒤 본문을 조회하는 2단계로 분리
- 데이터 상태 문제 대응: 핵심 테이블의 soft delete 컬럼이 전부 NULL이었고 계층이 끊어진 행이 있어 INNER JOIN을 쓰면 해당 행이 누락됐습니다. LEFT JOIN을 강제했습니다.
- 타입 변환 오류로 생긴 세 가지 증상 수정: 공통코드 캐시가 UUID를 코드 문자열로 변환해 역방향 행에 잘못된 값이 INSERT되고, 중복검사가 동작하지 않아 승인할 때마다 잘못된 데이터가 쌓이며, 삭제는 항상 0행이 처리됐습니다. 일괄 경로는 정상이고 단건 팝업만 문제가 있어 둘을 비교해 원인을 찾았습니다. 잘못된 데이터 정리 SQL(백업, 조사, 매핑, 조건부 UPDATE, 대조 검증)을 작성했으며 실행은 하지 않은 상태입니다.
- 대용량 엑셀 다운로드: 생성 시작·상태 확인·내려받기 API 3개와 화면 공통 함수를 만들어 공개재분류 화면 6개에 적용. 앞단 500을 성공 콜백으로 전달하는 공통 ajax 동작은 다른 화면 수십 개가 의존하므로 수정하지 않고 콜백에서 오류를 확인하도록 처리. 진행 단계 표시(4단계, 단계가 바뀔 때만 기록), 파일명 규칙으로 경로 이탈 차단, 한글 파일명은 응답 헤더로 처리해 JVM 인코딩과 무관하게 함, 예외를 무시하고 정상 응답하던 기존 코드 수정, 24시간 경과 파일 정리 스케줄
- 검증 중 발견해 수정한 결함: 스레드풀 빈을 추가하자 워크플로우 매니저가 타입으로 풀을 조회하면서 후보가 둘이 되어 모든 배치 실행이 실패할 수 있었던 문제(기존 풀에 @Primary 지정, 이름 기준 조회, 재발 방지 테스트), 오류 메시지에 서버 경로와 DB 오류 원문이 노출되던 문제(화면에는 예외 이름만 표시), 대기열 20이 화면 상한 15분과 맞지 않던 문제(대기열 4로 줄여 일찍 거부)
업무 성과
- 개발자 SQL로 처리하던 전거·기록물 대량 수정을 담당자 신청·관리자 승인 구조로 전환, 개발자 개입 0건화
- 승인 구조 재사용으로 후속 화면을 신규 SQL·매퍼 0건, 설정 1줄로 구현
- 기존 수작업 추출의 누락 4,074건 정정
- 데이터 추출 245초에서 1-3초로 약 99% 개선 (통계 부재 full scan 진단·고정)
- 기록건 미리보기 27.9초에서 2.3초로 약 92% 개선
- 단위테스트 34건에서 64건으로 확대
- 30초 제한에 실패하던 대용량 엑셀 다운로드 정상화 (철 11,400·건 73,239, 21MB, 생성 6분)
- 모든 HTTP 요청 2초 미만으로 앞단 장비 타임아웃과 무관한 구조 확보, 새 미들웨어·테이블 0개
- 동시 요청 9건 중 8건 접수·1건 즉시 거부로 서버 보호, 동시 클릭 시 타인 파일 수신 가능성 제거
- 배포 전 워크플로우 전체 중단 결함 사전 발견·차단, 단위테스트 132건 통과
- 데이터 추출 기능은 검수 대기 (운영 미반영), 데이터 정리 SQL은 작성 완료·실행 전, 엑셀 다운로드 개선은 검증 완료·운영 배포 대기
3.5 한양대학교 학과평가 시스템 구축
| 항목 | 내용 |
|---|---|
| 기간 | 2025.08 ~ 2025.12 |
| 소속 | 라인업코리아 솔루션연구소 |
| 역할 | 화면과 통계 설계·개발 |
| 사용 기술 | FineReport, PostgreSQL, JavaScript, HTML, CSS |
프로젝트 설명
학부와 대학원의 학과평가 자료를 업로드하고 보관·관리하며, 약 6년치 학교 전체 데이터를 기반으로 연도별 평가와 학생 수 통계를 조회하는 시스템을 구축했습니다.
기술 선택과 근거
- FineReport: 회사의 파트너 솔루션입니다. 리포팅 엔진을 직접 만드는 대신 검증된 제품 위에서 화면과 통계 설계에 집중했습니다.
- 집계 쿼리 중심 설계: 약 6년치 학교 전체 데이터를 리포트에서 다뤄야 했기 때문에 원자료를 그대로 불러오는 대신 집계 쿼리를 중심으로 설계했습니다.
수행 내용
- 평가 자료 업로드·보관·관리 화면 구축
- 연도별 평가와 학생 수 통계 리포트 구축
- 약 6년치 데이터 집계용 PostgreSQL 쿼리 설계·작성
- 리포트 화면의 조회와 동적 표시 기능 구현
업무 성과
- 학부·대학원 학과평가 자료 업로드·보관·관리 시스템 구축
- 약 6년치 학교 전체 데이터의 연도별 평가·학생 수 통계 리포트화
- 2025년 12월 구축 완료
3.6 개발 · 인프라 서버 구축 및 운영
| 항목 | 내용 |
|---|---|
| 기간 | 2025.04 ~ 2025.06 |
| 소속 | 라인업코리아 솔루션연구소 |
| 역할 | 개발팀 배포·소스 관리 환경 구축 및 운영 |
| 사용 기술 | Docker, GitLab, Jenkins, Linux, nginx, MS Teams |
프로젝트 설명
개발팀의 배포 방식과 소스 관리 환경을 재구축했습니다.
배경과 문제
배포가 수동이라 한 번에 20분에서 1시간이 걸렸고 휴먼 에러가 잦았습니다. 개발 환경은 로컬에 묶여 있었고, 소스 백업 체계가 없었습니다.
기술 선택과 근거
- Docker 표준화: 로컬 의존성 때문에 개발, 스테이징, 프로덕션 환경이 서로 달라지는 문제를 없애기 위해서입니다.
- GitLab과 Jenkins 온프레미스 자체 구축: 하드웨어 유통과 솔루션을 다루는 회사라 사내 서버를 확보하기 쉬웠습니다. 클라우드 비용 없이 내부망에서 소스와 빌드를 관리할 수 있었습니다.
- MS Teams 알림: 회사 표준 협업 도구라 별도 도구를 추가하지 않았습니다.
- 표준 문서화: 프레임워크·애플리케이션 문서와 개발 환경 설정 매뉴얼로 온보딩 시간을 줄였고, Git 브랜치 전략과 커밋 메시지, DB 네이밍 컨벤션을 정해 컨벤션이 없어서 생기던 작업 복잡도와 커뮤니케이션 문제를 줄였습니다.
수행 내용
- Docker 컨테이너 환경 표준화
- GitLab과 Jenkins 온프레미스 구축, Webhook 기반 CI/CD 파이프라인으로 빌드·배포 자동화
- 저장소 자동 백업·모니터링과 MS Teams 알림 연동
- 표준 문서화 프로세스와 Git·DB 컨벤션 정립
업무 성과
- 수동 배포 20분-1시간에서 10분으로 단축
- 개발·스테이징·프로덕션 환경 Docker 표준화로 환경 차이 이슈 제거
- 소스 저장소 자동 백업·모니터링 도입, 보존율 99.9% 유지
- 표준 문서화·Git·DB 컨벤션 정립으로 신규 입사자 온보딩 시간 단축
3.7 통계 모니터링 웹 개발 · 운영
| 항목 | 내용 |
|---|---|
| 기간 | 2024.09 ~ 2025.03 |
| 소속 | 라인업코리아 솔루션연구소 |
| 역할 | 개발과 운영 |
| 사용 기술 | Java, Spring, JSP, JavaScript, MySQL |
프로젝트 설명
외부 인터넷이 차단된 온프레미스 내부망에서 통계 데이터를 집계하고 시각화하는 모니터링 웹을 개발하고 운영했습니다.
기술 선택과 근거
- Java, Spring, JSP: 내부망에서 이미 운영 중이던 시스템의 스택에 맞춘 선택입니다. 호환성과 유지보수 연속성을 우선했습니다.
수행 내용
- RESTful 설계 원칙에 따른 CRUD 구현
- JavaScript 라이브러리 기반 동적 모니터링 화면 구현
- 내부망 서버 이슈 진단과 해결 등 운영 대응
업무 성과
- 내부망 통계 모니터링 웹 가동률 99.5% 운영
- 내부망 서버 이슈 직접 진단·해결로 무중단 운영 유지
3.8 대학교 웹 솔루션 개발
| 항목 | 내용 |
|---|---|
| 기간 | 2024.05 ~ 2024.08 |
| 소속 | 에듀에듀 개발사업팀 |
| 역할 | 인증 체계와 성능 개선 담당 |
| 사용 기술 | Java, Spring, JSP, MyBatis, JWT, Redis, MySQL |
프로젝트 설명
대학 웹 플랫폼의 인증 체계와 성능을 개선했습니다.
배경과 문제
인증이 단일 토큰 방식이라 토큰이 탈취되면 만료 전까지 대응할 방법이 없었습니다. 또 반복적인 DB 조회 때문에 페이지 로드가 1초를 넘었습니다.
기술 선택과 근거
- JWT Access + Refresh Token: 수명이 짧은 Access 토큰과 재발급용 Refresh 토큰으로 분리해 탈취 시 피해 범위를 제한했습니다.
- Refresh Token을 Redis에 보관: 이후 서버를 스케일 아웃할 때 인스턴스 간에 토큰을 공유할 수 있어야 했습니다.
- 정적 데이터 Redis 캐싱: 반복적인 DB 조회가 로드 지연의 원인이었습니다.
- AOP 기반 로깅: 각 화면 코드를 수정하지 않고 CRUD 이벤트와 방문 기록을 일괄 수집하기 위해서입니다.
- RESTful API 구조: 20건 이상의 신규 요구사항을 구조 변경 없이 반영할 수 있었습니다.
수행 내용
JWT Access와 Refresh Token 이중 인증·인가, Redis 기반 토큰 관리와 정적 데이터 캐싱, AOP 기반 전사 페이지 로깅 시스템을 구현했고, RESTful API 구조로 신규 요구사항 20건 이상을 반영했습니다.
업무 성과
- 페이지 로드 1,000ms에서 300-400ms로 약 65% 개선
- 단일 토큰 인증을 Access·Refresh 이중 구조로 전환해 토큰 탈취 피해 범위 제한
- AOP 로깅으로 화면 코드 수정 없이 전사 페이지 이벤트 수집 체계 구축
- 신규 요구사항 20건 이상 구조 변경 없이 반영
3.9 LMS 웹 서비스 유지보수
| 항목 | 내용 |
|---|---|
| 기간 | 2023.12 ~ 2024.04 |
| 소속 | 에듀에듀 개발사업팀 |
| 역할 | 유지보수와 운영 기능 개발 |
| 사용 기술 | PHP, JavaScript, jQuery, MySQL, Apache |
프로젝트 설명
PHP 기반 LMS를 유지보수하면서 관리자용 퀴즈 관리와 강의 설문·예약 기능을 개발했습니다.
배경과 문제
퀴즈 생성과 관리가 개발자에게 의존하고 있어 운영 요청이 들어올 때마다 개발 리소스가 소모됐습니다.
수행 내용
- 관리자 퀴즈 생성·관리 기능 구현 (합격 기준, 재시험 횟수 커스터마이징)
- 강의 수강 완료자만 응시할 수 있는 권한 체계 구현
- 강의 설문조사와 예약 서비스 구현
업무 성과
- 퀴즈 생성·합격 기준·재시험 정책 변경을 개발 배포 없이 관리자 화면 처리로 전환
- 수강 완료자 한정 퀴즈 응시 권한 체계 구축
- 강의 설문조사·예약 기능 추가
4. 부록
4.1 사이드 프로젝트
LotteON (2023.10 ~ 2023.11)
여러 입점 업체의 상품을 검색·비교하고 장바구니에 담아 구매하는 멀티 벤더 커머스 플랫폼입니다. 4인 팀 프로젝트의 팀장을 맡아 상품 도메인(상세, 검색, 장바구니, 주문)을 전담했습니다. JPA와 MyBatis를 역할별로 분리해 병행 사용했습니다. 사용 기술: Java 17, Spring Boot 3, Spring Security, JPA, MyBatis, Thymeleaf, MySQL
HelloWorld (2023.11 ~ 2023.12)
지식 공유 게시판과 채용 공고, 강의 수강을 묶은 개발자 커뮤니티 플랫폼입니다. 4인 팀 프로젝트에서 커뮤니티 도메인(게시물 상세, 댓글·대댓글, 글 검색)을 담당했습니다. 댓글과 대댓글은 자기참조 구조와 soft delete로 트리가 끊기지 않게 설계했습니다. 사용 기술: Java 17, Spring Boot 3, JPA, QueryDSL, JWT, React, TypeScript
4.2 학력
| 기간 | 학교 | 내용 |
|---|---|---|
| 2026.03 ~ 재학 중 | 한국방송통신대학교 | 컴퓨터과학과 편입 |
| 2016.03 ~ 2022.02 | 동서대학교 | 국제물류학 학사 졸업 |
4.3 교육 · 활동
| 기간 | 내용 | 비고 |
|---|---|---|
| 2024.12 ~ 2025.01 | Toss Learners High 서버 1기 | Toss에서 진행한 멘토링, 업무 몰입과 역량 점검 |
| 2023.06 ~ 2023.12 | 그린컴퓨터학원 백엔드 개발자 과정 수료 | 롯데ON 실무 개발자 멘토 과정 |
| 2017.06 ~ 2019.03 | 해병대 병장 만기 전역 | 운전병 |