대표 프로젝트 여섯 개를 골라 배경 → 부딪힌 문제 → 어떻게 판단했나 → 무엇이 남았나 순서로 적었습니다.

한 일을 빠짐없이 보시려면 경력기술서를, 일하는 방식을 보시려면 자기소개서를 보시면 됩니다.

01 레거시 ERP 전환과 운영 흐름 설계

구분 내용
배경 사내 ERP가 Ruby on Rails와 ASP 두 스택에 나뉘어 오래 운영되고 있었습니다. 운영을 멈출 수 없는 상태에서 도메인 단위로 순차 이식해야 했습니다.
부딪힌 문제 오래 운영된 화면에는 문서화되지 않은 기준이 묻혀 있었습니다. 정가·할인 산정이 여러 화면에 흩어져 같은 주문이 보는 위치에 따라 다르게 더해졌고, 검사 카운트는 집계 컬럼 하나로만 관리돼 잔여 수량이 왜 그 값인지 되짚을 수 없었습니다.
어떻게 판단했나 영속성 기술을 관성대로 고르지 않았습니다. 이 시스템이 도메인 엔티티를 영속화하는 앱이라기보다 연도별로 분리된 레거시 DB를 정확히 조회·가공하는 관리자 앱에 가깝다고 보고, JPA 대신 MyBatis와 Spring JDBC를 주 축으로 삼았습니다. 원본 로직에서 규칙을 먼저 드러낸 뒤 단일 기준으로 정리하며 옮겼고, 카운트는 증감 원장 구조로 다시 세웠습니다.
무엇이 남았나 전환을 마치고 Rails 원본 앱을 제거했습니다. 여기서 끝내지 않고 별도로 돌던 출퇴근 시스템을 통합하면서 사람이 실제로 일하는 순서를 하나의 운영 흐름으로 다시 만들었습니다. 근무계획을 월 단위로 확정·잠그되 확정 이후 변경은 요청과 승인을 거치게 했고, 지문 기록과 근무계획의 대조는 보관하되 열 때마다 현재 계획으로 다시 재도록 해 계획이 바뀐 뒤에도 과거 판정이 굳지 않게 했습니다. 이후에는 화면을 보는 사람 기준으로 다시 갈랐습니다. 직원이 오가던 출퇴근·근무계획·근태 기록 세 화면을 한 표로 합쳐 같은 것을 두 번 묻지 않게 하고, 관리자 쪽은 근태 현황·근무계획 관리·지문 대조·운영 설정 네 묶음으로 나눠 권한 규칙을 그 구조에 맞추었습니다. 확정된 달의 변경과 외근 시간 정정은 요청·승인 경로 하나로 모으되, 승인·반려 결과를 그 요청이 처음 올라온 알림 스레드로 되돌려 요청한 사람이 결과를 따로 찾지 않게 했습니다.
기술 Java, Kotlin, Spring Boot, Thymeleaf, MyBatis, Spring JDBC, MS-SQL

02 요구사항 반영 파이프라인 자동화

구분 내용
배경 이관을 마치고 나니 다음 병목이 보였습니다. 요구사항은 개발자가 아닌 팀에서 올라오는데, 그것이 코드에 닿으려면 매번 같은 사람을 거쳐야 했습니다. 속도의 문제가 아니라 경로의 문제였습니다.
부딪힌 문제 자동화를 어디까지 맡길 것인가가 실제 어려움이었습니다. 범위를 넓히면 코드베이스에 무엇이 남을지 사람이 통제할 수 없고, 너무 좁히면 병목이 그대로 남습니다.
어떻게 판단했나 범위를 넓히는 대신 멈추는 지점을 설계했습니다. 요구사항을 읽어 구현하고 빌드·스타일 검증을 통과한 경우에만 PR을 여는 절차를 에이전트 스킬로 정의해 레포에 두었습니다. PR까지만 열고 머지는 반드시 사람이 하도록 못 박았고, 기본 브랜치 직접 푸시와 자동 머지는 원천 금지했습니다. 결제·개인정보·권한 체계·스키마 변경처럼 위험이 큰 건은 구현하지 않고 사유와 함께 보류로 돌립니다. 자동화가 스스로 판단할 수 있는 범위를 좁게 정의하는 것이 오히려 그 자동화를 계속 쓸 수 있게 만드는 조건이라고 봤습니다.
무엇이 남았나 실행에 코드 수정이 필요 없으므로 담당자가 자리에 없어도, 스킬을 만든 사람이 아니어도 같은 절차가 돌아갑니다. 요구사항 본문은 PR 이후에도 바뀔 수 있어 머지 후 현재 본문을 다시 읽어 실제 반영 여부를 대조하는 단계를 넣었고, "PR을 열었다"가 아니라 "지금의 요구가 반영됐다"를 완료 기준으로 삼았습니다. 기능이 바뀌면 비개발자용 매뉴얼까지 갱신되도록 별도 스킬을 두었습니다.
기술 에이전트 스킬 정의, 요구사항 관리 도구 연동, GitHub PR 워크플로우, 빌드·스타일 검증 관문

03 검사 도메인 — 공통 스택 통합과 정본 대조

구분 내용
배경 같은 성격의 검사가 각기 다른 스택에서 자기 방식으로 채점되고 결과를 내고 있었습니다. 검사가 하나 늘 때마다 실시·채점·결과 경로가 통으로 하나씩 늘어나는 구조였습니다.
부딪힌 문제 옮기는 것 자체보다, 옮길 원본이 맞는지가 문제였습니다. 오래 돌아온 코드라 당연히 맞을 것이라 여기기 쉬웠습니다.
어떻게 판단했나 이관은 원본을 그대로 옮기는 일이 아니라 원본이 맞는지 확인하는 일이라고 보고, 연구소 수기채점표·검사설계도와 한 항목씩 대조했습니다. 그러자 반응일관성처럼 판정 자체가 동작하지 않던 지표가 있었고, 강점과 약점이 서로 뒤바뀌어 저장되는 곳도 있었습니다. 오류를 내지 않고 결과지가 그럴듯하게 채워져 나오기 때문에 그동안 드러나지 않았던 것입니다.
무엇이 남았나 학습·진로 검사 네 종을 공통 검사 스택 하나로 옮기고 과거 결과까지 공통 저장소로 이전 적재해, 조회하는 쪽은 그 결과가 어느 시절에 만들어졌는지 알 필요가 없게 됐습니다. 죽어 있던 판정을 복원했고, 이후로는 이관 대상을 받으면 동작부터 보지 않고 정본 기준을 먼저 놓고 대조합니다. 기관별로 따로 만들어지던 진입 경로도 표준 게이트웨이 하나로 일반화했습니다.
기술 Java, Kotlin, Spring Boot, JPA, QueryDSL, JDBC, MS-SQL, React, TypeScript

04 인쇄 시스템 재설계 — 온프레미스와 클라우드 사이

구분 내용
배경 검사 결과표는 현장에서 대량으로 인쇄됩니다. 기존에는 현장 서버 하나가 PDF 렌더링과 프린터 스풀을 모두 맡고 있어, 그 서버가 멈추면 인쇄가 통째로 멈췄습니다.
부딪힌 문제 렌더링을 클라우드로 옮기는 것은 쉬운데, 프린터는 현장에만 있습니다. 클라우드가 현장 PC로 인쇄 잡을 밀어 넣으려면 현장마다 외부에서 들어올 길을 열어야 하고, 그러면 현장 수만큼 방화벽 구멍이 생깁니다.
어떻게 판단했나 방향을 뒤집었습니다. 클라우드가 밀어 넣는 대신, 현장의 얇은 에이전트가 아웃바운드로 잡을 가져오게 했습니다. 이런 방향이면 현장에 인바운드 포트를 하나도 열지 않아도 됩니다. 대량 인쇄의 병목이었던 드라이버 렌더링은 건너뛰고, 이미 완성된 PDF를 그대로 보내면서 제어 헤더로 급지함·양면·용지를 직접 지정했습니다. 이 방향은 되돌리면 안 되는 결정이라 설계 문서에 그렇게 명시해 두었습니다.
무엇이 남았나 하나였던 현장 서버가 클라우드 렌더 + 현장 에이전트 + 웹 콘솔 세 조각으로 나뉘었습니다. 렌더링 부하는 클라우드에서 확장할 수 있게 됐고, 현장에 남은 것은 스풀만 하는 얇은 프로세스뿐입니다. 잡 하나가 실패해도 에이전트가 내려가지 않게 하고 실패한 입력을 따로 남겨, 무인으로 도는 상주 프로세스가 한 건 때문에 멈추지 않게 했습니다. 출력물이 원본 크기 그대로 나가도록 축소를 끄고, 현장 실측으로 좌표가 어긋나던 원인을 확인해 규격을 고정했습니다.
기술 Go (Windows 서비스·크로스 컴파일), Java·PDFBox, AWS ECS, 프린터 제어 언어

05 케어테이블 — 만성질환 식이관리 서비스

기획·백엔드·모바일/웹 앱·인프라·배포를 1인 개발해 api.kcalai.link로 실제 운영 중입니다.

구분 내용
배경 사진 한 장으로 음식을 인식해 기록하는 서비스로 시작했습니다. 쓰면서 분명해진 것은 이 앱이 필요한 사람이 체중 관리를 원하는 사람보다 식이요법이 필요한 만성질환군이라는 점이었습니다.
부딪힌 문제 AI를 제품에 넣을 때 가장 많이 고민한 것은 성능이 아니라 어디까지 맡길 것인가였습니다. 인식은 AI가 낫지만, 영양값처럼 같은 질문에 같은 답이 나와야 하는 자리도 있었습니다.
어떻게 판단했나 경로를 갈랐습니다. 사진에서 음식을 알아보는 일은 비전 모델에 맡기되 영양값 조회 경로에서는 LLM을 배제하고 식약처 공식 DB만 씁니다. DB에 없는 음식만 1회 추정해 값을 동결 적재해, "같은 음식은 항상 같은 값"이 깨지지 않게 했습니다. 질환별 경고도 모델이 정하게 두지 않고 학회 지침을 근거로 삼아 판정 근거가 된 수치를 함께 노출했습니다. 돈이 오가는 구독 자동결제는 안 되는 것보다 잘못 동작하는 것이 위험하다고 보고, 이미 낸 기간에 다시 청구하지 않는 방어를 먼저 넣었습니다. 이후 유료 플랜을 앱 내 구독으로 옮길 때도 같은 기준으로, 앱이 넘긴 결제 정보는 조회 키로만 쓰고 서버가 스토어에 거래를 다시 물어 확인하게 했습니다.
무엇이 남았나 섭취 기록만으로는 관리가 되는지 알 수 없어 검사 수치를 결과 축으로 두고, 식단·검사 수치·진료 일정을 한 축에 놓는 케어 루프를 만들었습니다. 신장질환 병기, 고혈압 나트륨, 당뇨 첨가당처럼 질환마다 다른 축을 누적해 진료 지참용 리포트로 묶어 냅니다. 초기 자체 비전 모델을 단일 API 백엔드로 바꿔 배포 용량을 1.3GB에서 약 200MB로 줄였고, 방향이 굳은 뒤에는 범용 다이어트성 기능을 실제로 걷어냈습니다. 생성형 AI를 쓰는 화면에는 사전고지와 결과물 표시를 넣되, 인식은 모델이 하고 영양값과 질환 기준은 공식 DB와 지침에서 온다는 점을 갈라 적었습니다. 둘을 뭉뚱그려 "AI가 분석했다"고 적으면 사용자가 그 숫자를 어디까지 믿어도 되는지 판단할 근거를 잃기 때문입니다. 앱 스토어 출시를 준비하며 로그인을 이메일까지 넓힐 때는 만성질환 앱은 가입 사실 자체가 건강 정보라고 보고, 코드 요청·로그인 실패·닉네임 중복확인 어느 응답도 가입 여부를 드러내지 않게 했습니다. 사진을 외부 AI로 보내기 전에는 무엇을 어디로 보내는지 밝혀 동의를 받고, 촬영 위치 같은 부가 정보를 지운 뒤 보냅니다.
기술 Python, FastAPI, SQLAlchemy, Alembic, PostgreSQL, React Native/Expo, TypeScript, AWS Lightsail, Caddy

06 investment — AI 에이전트 권한 설계

한국투자증권 오픈API 기반 매매 터미널입니다. AI에게 개발 과정을 맡기되 돈을 움직이는 권한은 어디까지 줄 것인가를 구조로 답한 프로젝트입니다.

구분 내용
배경 시세 모니터링에서 시작해 실계좌 주문과 자동매매까지 범위를 넓히면서, 개발 과정을 여러 AI 에이전트에게 나눠 맡기게 됐습니다.
부딪힌 문제 한 에이전트의 오판이 곧바로 체결로 이어질 수 있었습니다. 또 전략 성적을 재는 쪽과 그 성적을 해석해 판단하는 쪽이 같으면 유리한 쪽으로 기울기 쉽다는 문제가 있었습니다.
어떻게 판단했나 역할이 다른 에이전트 다섯을 나누고 실주문을 낼 수 있는 것은 하나뿐으로 두었습니다. 구현하는 쪽은 주문을 낼 수 없고 판단하는 쪽은 코드를 고칠 수 없게 해 경계를 그었습니다. 값을 재는 역할과 해석하는 역할도 일부러 갈라, 측정 결과와 그 해석을 서로 다른 컨텍스트에서 만들게 했습니다.
무엇이 남았나 그 판단이 옳았다는 것은 얼마 뒤 확인했습니다. 전략 성적을 재는 도구에서 매수 수수료가 빠져 승률이 후하게 나오고, 표본이 코드 순서 앞쪽으로 쓸려 있던 것을 발견해 이미 적어 둔 결론을 전부 되돌렸습니다. 이후 생존 편향·미래 참조·누락된 거래비용을 차례로 걷어내고 시장 국면별로 다시 측정했습니다. 지금은 시세 수집·판단·손절·체결 반영을 상주 스케줄러로 상시 운영하며, 판단 재료를 가격 하나에서 투자자별 수급과 장중 뉴스까지 넓혔습니다. 국내에 이어 해외 주문 경로를 열 때는 지정가만 허용하고, 장시간·환율 환산처럼 통화와 시간대가 얽히는 조건을 보내기 전 규칙으로 못 박았습니다. 경계를 그은 뒤에는 반대 방향의 구멍도 보였습니다. 정식 회차가 거절한 근거를 다른 에이전트가 보지 못해 같은 종목을 모른 채 사는 일이 생겨, 그 근거를 이어 쓰지 않는 참고 줄로만 건네 판단은 섞지 않되 정보는 건너가게 했습니다.
기술 TypeScript, Node.js, Fastify, WebSocket, React, Vite, 한국투자증권 오픈API

07 그 외 개인 프로젝트

프로젝트 내용
db-studio
데스크톱 DB 클라이언트 연도별로 분리된 레거시 DB를 매일 오가며 조회하다 겪은 불편을 직접 도구로 만들었습니다. 다중 DB 트리 탐색과 speed-search, 그리드 셀 편집, SQL 자동완성과 구문 오류 위치 표시, 외래키 추적을 갖췄습니다. 확정 전에 어느 행이 어떻게 바뀌는지 먼저 보여 쓰기가 무엇을 남길지 확인한 뒤 진행하게 했고, 기본키가 없는 테이블은 다중 매칭 시 롤백해 의도하지 않은 갱신을 막습니다. macOS 코드사이닝과 자동 업데이트까지 붙여 배포했습니다. (Tauri · React · TypeScript)
dispatch
현장 인력 배차 운영 도구 현장과 인력이 매일 바뀌는 용역 업무에서 배차 판단이 엑셀과 전화에 흩어져 있는 문제를 다룹니다. 기존 업무를 바꾸라고 요구하지 않고 쓰던 시트를 그대로 받아 초안으로 바꾸는 것을 진입점으로 잡았습니다. 중복·자격·근로시간을 배차 시점에 검사하고, 기상 예보와 이동시간을 붙여 일일 브리핑을 조립합니다. 작업자 응답을 공개 링크로 받아 노쇼를 당일 새벽이 아니라 전날 밤에 알 수 있게 했습니다. (Next.js · Drizzle · PostgreSQL)
OpenJarvis
Commerce Automation 네이버 쇼핑 검색·DataLab 수집 도구, 인사이트 에이전트 라우팅, 스마트스토어 수집 파이프라인, 상품 후보 점수화. 로컬 에이전트를 실제 업무에 적용해 본 실험입니다. (Python · httpx · pytest)

기술 스택