알리자
주식회사 코어소프트 · 2024.04 – 2026.01
매장 예약과 상품 판매, 그 뒤의 정산까지 한 번에 도는 커머스 플랫폼입니다.
소비자 앱·매장용 앱·샵관리자·본사 어드민 네 개 화면을 오가며 개발했습니다.
Spring 4.3 과 MyBatis 로 된 오래된 코드 위에서 2년 가까이 일했습니다.
느린 건 데이터가 아니라 쿼리의 모양이었다
관리자 업체 목록이 4초 걸렸습니다. 데이터가 많아서라고 생각하기 쉬운데, 쿼리를 뜯어
보니 회원 수·재방문율·결제 금액을 구하는 집계가 업체 한 줄마다 따로 돌고 있었습니다.
목록에 업체가 100개면 집계도 100번 돌았습니다. 대표 이미지 한 장을 고르는 부분도
min(sort) 서브쿼리로 매번 전체를 훑었습니다.
집계를 CTE 세 개로 미리 한 번에 만들어 조인으로 붙이고, 이미지는 정렬 후 하나만 가져오는
LATERAL 조인으로 바꿨습니다. 4초가 0.2초가 됐습니다. 제품 관리 목록도 같은 모양이었습니다
— 브랜드명·사진 경로·대분류·중분류를 각각 스칼라 서브쿼리로 꺼내고 있어서, 조인으로 펴고
인덱스를 얹어 10배 줄였습니다.
같은 데이터, 같은 인덱스인데 쿼리를 어떻게 쓰느냐로 스무 배가 갈렸습니다. 그 뒤로는
느리다는 말을 들으면 데이터 양보다 실행 계획의 모양을 먼저 봅니다.
발송 속도와 실패율은 다른 문제였다
알림을 HTTP 로 한 건씩 보내고 있어 대량 발송이 느렸습니다. Firebase Admin SDK 로 옮겨
토큰 500개씩 묶어 보내니 시간 문제는 풀렸습니다.
남은 건 실패율이었는데, 이건 속도와 다른 원인이었습니다. 배치 응답을 토큰 단위로 훑어
보니 실패의 상당수가 앱을 지운 기기의 죽은 토큰이었습니다. 계속 보내니 계속 실패하는
구조였습니다. UNREGISTERED 로 돌아온 토큰을 따로 모아 무효 처리하고 나서야 실패율이
떨어졌습니다.
묶어 보내는 것으로 끝냈다면 숫자는 좋아 보여도 실패는 그대로였을 겁니다. 응답을 한 건씩
확인하지 않았으면 몰랐을 일입니다.
용량을 줄이기 전에 저장하는 방식이 문제였다
이미지가 무겁다는 이야기가 나왔을 때, 처음 본 것은 변환이 아니라 저장 방식이었습니다.
HTML 에디터에 이미지를 붙여넣으면 Base64 로 본문 안에 통째로 박혀 DB 에 들어가고
있었습니다. 글 한 줄을 불러오는데 이미지가 딸려 오는 셈이었습니다.
붙여넣는 순간 파일 서버에 저장하고 본문에는 URL 만 남기도록 먼저 바꿨습니다. 그다음
업로드 시점에 WebP 로 자동 변환하게 만들어 평균 용량을 약 70% 줄였고, 상품 상세에는
지연 로딩을 붙여 스크롤이 닿기 전에는 내려받지 않게 했습니다.
순서를 반대로 했다면 WebP 로 줄인 이미지를 여전히 Base64 로 본문에 박고 있었을 겁니다.
그 밖에
- 전문가용·사업자용 모바일 웹을 V2 로 새로 만들며 화면 대부분을 맡았습니다.
- 손으로 맞추던 매장·BC 정산을 신청·승인·조회 흐름으로 옮기고 집계 쿼리를 최적화했습니다.
- 쇼핑몰 상품 목록·상세의 초기 API 호출을 걷어내 체감 속도를 끌어올렸습니다.
- Cordova 앱 2종의 카메라 권한·iOS QR 스캐너·스토어 배포를 맡았습니다.
- 공통 UI 컴포넌트 약 30종을 표준화하고 디자인 가이드를 만들었습니다.
- Java 11 업그레이드에 대응하고 p6spy 로 SQL 로그를 정리했습니다.
- 개발 언어 · Java 11, Spring 4.3, JSP, JavaScript, Vue 2
- 사용 툴 · PostgreSQL, MyBatis, Firebase Admin SDK, Cordova
LawPilot
주식회사 코어소프트 · 2025.06 – 2026.01
생성형 AI 로 법률 업무를 돕는 SaaS 입니다. 저장소를 처음 만들어 백엔드·프런트·배포까지
서비스 전체를 맡았고, AI 모델은 Python 개발자가 맡았습니다.
몇 분 걸리는 일을 기다리게 만드는 법
사건 정보를 넣으면 인터뷰·서면·심리·판결 순으로 AI 가 재판을 따라갑니다. 한 단계에 몇
분씩 걸리는데, 그동안 화면이 아무 말도 하지 않으면 사용자는 멈춘 줄 압니다. 더 큰 문제는
그 사이에 새로고침하거나 창을 닫으면 진행하던 것이 사라진다는 것이었습니다.
진행 상태를 클라이언트가 아니라 서버가 들고 있게 했습니다. 어느 단계인지, 지금까지 나온
중간 결과가 무엇인지를 서버에 두고 WebSocket 으로 흘려보냈습니다. 다시 접속하면 서버에
남은 진행 중인 작업을 찾아 그 지점부터 이어 붙입니다.
오래 걸리는 작업은 빨리 만드는 것보다 중간에 끊겨도 괜찮게 만드는 편이 낫다고 봤습니다.
AI 응답 시간은 우리가 줄일 수 있는 것이 아니었습니다.
돈이 걸린 자리에선 되돌릴 수 있어야 했다
기관이 쓰는 서비스라 계정만으로는 팔 수 없었습니다. 기관을 먼저 등록하고 그 아이디로
소속 사용자를 만드는 흐름을 세우고, 가입 때 국세청 사업자등록 상태 조회 API 로 실제
사업자인지 확인했습니다. 결제는 토스페이먼츠 빌링키로 정기결제를 붙였습니다.
까다로웠던 것은 사용량이었습니다. AI 를 부를 때마다 회사 토큰을 차감하는데, AI 호출은
실패할 수 있습니다. 차감만 하고 결과를 못 주면 돈을 받고 아무것도 안 준 것이 됩니다.
차감을 기록으로 남기고 호출이 실패하면 되돌리도록 맞췄습니다.
기능이 실패하는 것보다 실패한 흔적이 잘못 남는 것이 더 큰 문제인 자리가 있다는 걸
배웠습니다.
법조계는 아직 HWP 를 쓴다
기술 선택이 아니라 사용자가 쓰는 형식에 맞춰야 하는 일이었습니다. PDFBox 로 PDF 에서
글을 뽑고, docx4j 로 목차와 제목 서식을 갖춘 DOCX 를 만들고, hwplib 으로 HWP 를 읽었습니다.
처음에는 문서를 프런트에서 만들었는데, 화면마다 만드는 코드가 갈라져 같은 검토서인데
받는 곳에 따라 서식이 달랐습니다. 문서 생성을 전부 백엔드로 옮겨 어디서 받아도 같은
파일이 나오게 했습니다.
그 밖에
- 법률 검토서를 정식판과 lite 판으로 나눠 만들고, 이후 대화형 채팅으로 확장했습니다.
- 답변 스트리밍, 파일 첨부, 판례·법령 하이퍼링크, 문서 내려받기, 답변 피드백을 붙였습니다.
- Python 벡터 검색 API 를 연동해 사건과 비슷한 판례·법령을 추천했습니다.
- Docker Compose 로 개발·운영 구성을 나누고 nginx·HTTPS 를 붙였습니다.
- 개발 언어 · Java 17, Spring Boot 3.5, JavaScript, Vue 3
- 사용 툴 · PostgreSQL, JPA, WebSocket, Docker, nginx, 토스페이먼츠, PDFBox·docx4j·hwplib