계좌 인증과 포인트 충전 페이지 신규 추가
목차
계좌 인증과 포인트 충전 페이지, 두 기능을 한 커밋에서 같이 붙였다. 신규 페이지라서 기존 코드를 건드리지 않는 게 핵심이었는데, 그게 생각보다 신경 쓸 게 많았다.
슬랙 메시지 한 줄로 끝날 것 같은 작업인데 실제로 건드린 레이어가 빌드 설정부터 컨트롤러, 비즈니스 로직, SQL 매퍼까지 전방위였고, 파일 수는 6개. 규모는 작지만 여러 레이어가 다 걸쳐 있으니 흐름 전체를 머릿속에 그려두고 시작하지 않으면 한 군데 빠뜨리기 쉬운 구조였다.
왜 계좌 인증이 포인트 충전과 묶이나
포인트 충전 요청이 들어왔을 때 "이 계좌가 실제로 본인 것인지" 먼저 검증하지 않으면, 이후 정산이나 환급 로직에서 허점이 생긴다. 충전 신청 자체는 받을 수 있어도 출금 처리나 실패 환불 흐름에서 계좌 귀속이 불명확해지는 상황이 나온다. 두 기능이 별개 페이지처럼 보여도 순서가 있는 플로우고, 계좌 인증이 선행 조건이었기 때문에 같은 타임라인에서 함께 붙이는 게 맞았다.
UI 레벨에서도 사용자 동선이 연결되어야 했다. 인증 없이 충전 페이지로 바로 진입하는 경로를 막고, 인증 완료 상태에 따라 충전 폼의 활성화 여부가 바뀌는 구조. 컨트롤러 두 개가 서로 상태를 공유하지 않고도 이걸 처리할 수 있도록 설계하는 게 주된 고민이었다.
기존 패턴을 따르되, 완전히 격리
slecs 레포는 전형적인 Java MVC 구조다. 컨트롤러에서 요청을 받고, 유틸/서비스 레이어에서 비즈니스 로직을 처리하고, SQL 매퍼로 DB를 찌르고, JSP나 JSON 응답으로 결과를 돌려주는 흐름. 이 패턴이 코드베이스 전반에 이미 자리 잡혀 있어서, 신규 기능도 같은 결대로 짰다.
가장 신경 쓴 원칙은 "격리"였다. 기존 엔드포인트에 파라미터 하나 얹거나 기존 쿼리 ID를 조건분기로 재사용하면 단기적으로 편하다. 하지만 나중에 어느 기능이 어느 조건에서 이 코드를 타는지 추적이 어려워지고, 기존 쿼리를 수정할 때 사이드 이펙트가 어디까지 퍼지는지 가늠하기도 힘들어진다. 그래서 새 엔드포인트, 새 쿼리 ID를 각각 분리해서 만들었다.
<!-- SQL 매퍼 네이밍 예시 (실제 ID는 내부 규칙) -->
<!-- 기존 잔액 조회 -->
<select id="selectUserBalance" ...>
SELECT balance FROM user_account WHERE user_id = #{userId}
</select>
<!-- 신규: 계좌 인증 상태 조회 - 별도 ID로 분리 -->
<select id="selectAccountVerifyStatus" ...>
SELECT verify_yn, verify_dt FROM user_account_verify WHERE user_id = #{userId}
</select>
<!-- 신규: 포인트 충전 요청 등록 -->
<insert id="insertPointChargeRequest" ...>
INSERT INTO point_charge_log (user_id, amount, status, reg_dt)
VALUES (#{userId}, #{amount}, 'PENDING', NOW())
</insert>
쿼리 ID 네이밍은 기존 코드베이스의 prefix 규칙을 맞추면서, 기능 단위로 읽히도록 했다. 매퍼 파일 전체를 검색해서 기존 ID와 충돌 없는지 확인하는 게 선행이었다. 이름이 비슷하게 생겼으면 MyBatis가 어떤 걸 실행하는지 디버깅이 복잡해진다.
컨트롤러 레벨에서는 권한 체크 로직이 빠지면 안 됐다. 기존 컨트롤러들이 어노테이션 기반이든 세션 검증 방식이든 이미 패턴을 가지고 있으면, 새로 만든 진입점에서도 같은 방식을 그대로 따르는 게 원칙이다. 신규 기능에서만 권한 체크가 누락되는 일이 생각보다 흔하다. 새 파일을 만들다 보면 "이 로직은 공통이니 알아서 적용되겠지" 하고 건너뛰는 순간이 온다. 기존 컨트롤러 한두 개를 옆에 열어두고 비교하면서 작업한 이유가 그거였다.
| 체크 항목 | 접근 방식 |
|---|---|
| 엔드포인트 권한 | 기존 컨트롤러 패턴 그대로 적용 |
| SQL 쿼리 ID 충돌 | 매퍼 파일 전체 검색 후 신규 ID 확정 |
| 빌드 설정 변경 | 최소 변경, 기존 설정 불개입 |
| 기존 기능 영향 | 작업 전/후로 기존 화면·API 전체 재확인 |
| 엣지 케이스 | 빈 결과, 미인증 상태 접근 직접 체크 |
빌드 설정 파일은 최소한으로만 손댔다. 새 기능에 필요한 것만 추가하고, 기존 설정 블록은 건드리지 않는 게 원칙이었다. 빌드 설정 하나 잘못 바꿔서 전체가 깨지는 상황은 만들기 싫었고, 그게 가장 고칩쪽이 좁은 영역이기도 하다.
검증 루틴
기능을 붙이기 전에 기존 화면과 API가 정상 동작하는 걸 먼저 확인하고 시작했다. 당연해 보이지만 바쁠 때 이 순서를 건너뛰고 개발하다 보면 "내가 깬 건지 원래 깨진 건지" 불명확한 상황이 생긴다. 기준선을 잡는 게 먼저다.
새 기능 붙인 다음에는 브라우저 직접 접근이랑 API 툴로 실제 요청을 날려봤다. DB 쪽은 실행 결과를 직접 조회해서 기대값과 맞는지 눈으로 확인했다. 엣지 케이스는 크게 두 가지였다.
- 계좌 인증 전 상태에서 충전 페이지에 접근했을 때 응답이 의도대로 막히는지
- 인증은 됐지만 충전 요청 금액이 0이거나 음수일 때 서버가 제대로 거르는지
자동화 테스트가 없는 환경에서 신규 기능을 붙일 때 이 정도 수작업 체크는 최소 루틴이다. 회귀는 없었다. 기존 기능이 영향 없이 그대로 돌아가는 걸 확인하고 커밋했다.
작업 자체가 어렵다기보다는, 신규 기능 추가가 오히려 더 꼼꼼하게 봐야 하는 작업이라는 걸 다시 확인한 커밋이었다. 기존 기능을 수정하면 변경 범위가 명확하지만, 새로 추가하는 건 "잘 붙었는지"뿐 아니라 "기존을 안 건드렸는지"까지 동시에 검증해야 한다. 격리 원칙을 처음부터 지키면 그 검증이 훨씬 단순해진다. 공유 쿼리나 공유 엔드포인트를 건드리는 순간부터 검증 범위가 기하급수적으로 늘어나기 때문에, 조금 더 코드가 길어지더라도 분리하는 쪽이 낫다.
댓글 0
첫 댓글 달아줘.