개발 slecs

파트너 목록에 잠금 표기

목차

partner 영역에 기능 하나를 추가했다. 파트너 목록에서 잠금 상태를 표기하고, 하위 항목까지 cascade로 잠금을 토글하는 기능이다. 변경 파일은 뷰/스타일 2개, 내부 클래스 1개, SQL 매퍼 1개. 숫자만 보면 소소한 작업인데 실제로는 쿼리 레벨부터 다시 설계해야 했다.

왜 쿼리부터 손댔나

기존 partner 목록 API는 잠금 여부 컬럼을 내려주지 않았다. 화면 쪽에서 별도 요청을 쏘거나, 호출 타이밍을 맞추거나, 아니면 매퍼를 고쳐서 기존 쿼리에 끼워 넣는 세 가지 선택지가 있었다. 별도 요청은 N+1 냄새가 나고, 호출 타이밍 맞추기는 화면 로직에 상태 동기화 코드를 심어야 한다. 그래서 매퍼에서 JOIN으로 같이 끌어오는 방향으로 결론 냈다.

cascade 잠금은 조금 더 고민이 필요했다. "하위 포함"이라는 게 단순히 UI에서 체크박스 여러 개를 묶어서 보여주는 게 아니라, 저장 시점에 하위 레코드 전부를 한 번에 업데이트해야 한다는 의미다. 트랜잭션 범위를 어디까지 잡을지, 실패했을 때 부분 적용된 상태로 남겨둘 건지 아니면 전체 롤백할 건지를 먼저 결정했다. 어중간하게 일부만 잠기면 데이터 정합성이 깨지고, 운영팀에서 직접 DB를 뒤져야 하는 상황이 된다. 그래서 전체 성공 아니면 전체 롤백으로 정했다.

쿼리 실행 계획도 미리 확인했다. 하위 계층을 한 번에 업데이트하는 쿼리가 인덱스를 타는지, 파트너 수가 늘어났을 때 풀스캔이 발생하지 않는지. 지금 데이터 규모에서는 문제없지만 미리 실행 계획 떠놓고 코멘트로 달아뒀다.

-- 예시: 하위 파트너 cascade 잠금 업데이트
UPDATE partner
SET locked = #{locked},
    updated_at = NOW()
WHERE parent_id = #{partnerId}
   OR id = #{partnerId}

실제 쿼리는 계층 구조에 맞게 더 복잡하지만, 핵심은 parent_id 기준으로 한 번에 묶어서 처리한다는 것이다. 애플리케이션 레벨에서 루프 돌면서 한 건씩 업데이트하는 방식은 트랜잭션 내에서도 락 충돌 가능성이 있고, 쿼리 횟수가 늘어나서 쓰지 않았다.

화면 렌더링에서 신경 쓴 것들

잠금 표기 자체는 간단하다. 컬럼 하나 추가하고 아이콘 붙이면 된다. 근데 cascade 토글은 상태가 조금 복잡하다.

상황 표기 방식
상위 잠김, 하위 전체 잠김 상위 아이콘 solid, 하위 아이콘 solid
상위 잠김, 하위 일부만 잠김 발생 불가 (cascade 강제)
상위 미잠금, 하위 개별 잠금 있음 상위 아이콘 없음, 하위 아이콘 solid

cascade를 강제하기 때문에 "상위는 잠겼는데 하위 일부만 풀린" 상태가 DB에 존재할 수 없다. 근데 레거시 데이터에는 이 전제가 성립하지 않을 수 있다. 그래서 기존 데이터 검증도 작업 전에 한 번 돌렸다. 이상한 케이스가 있으면 마이그레이션이 필요했을 텐데, 다행히 깨끗했다.

NULL 처리도 방어했다. 잠금 컬럼이 NULL인 레코드를 "미잠금"으로 취급할 건지 명시적으로 false인 레코드와 구분할 건지. 화면에서 아이콘을 보여주는 조건이 locked === truelocked냐에 따라 동작이 달라지기 때문이다. 매퍼에서 COALESCE(locked, false)로 NULL을 false로 정규화해서 올려줬다.

검증하면서 느낀 것

구현 후 화면에서 직접 동작 확인했다. 잠금 토글 → 목록 새로고침 → 하위 항목 상태 확인 → 관련 화면에서 숫자 cross-check. 이 루틴을 돌리면서 케이스 하나가 빠졌다는 걸 발견했다. 하위 파트너가 아예 없는 파트너를 잠글 때 cascade 쿼리가 WHERE 조건으로 0건을 업데이트하는데, 이게 에러 없이 조용히 통과한다. 기능상 문제는 없지만 처음 보면 "업데이트가 안 된 건가?" 싶어서 로그에 영향 행 수를 남겨두도록 처리했다.

사내 서비스를 계속 만들다 보면 기능 하나가 단순히 화면에 버튼 하나 추가하는 것으로 끝나지 않는다는 걸 계속 체감한다. SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크가 모두 엮여 있어서 어느 하나만 빠뜨려도 숫자가 맞지 않거나 특정 사용자에게 이상한 화면이 나타난다. 특히 금융/결제 도메인은 숫자 하나가 틀리면 신뢰가 무너지기 때문에 "대충 맞는 것 같다"로 넘어가는 게 허용이 안 된다. 그 감각을 유지하는 게 이 도메인에서는 기본값이어야 한다고 생각한다.

커밋은 논리 단위로 쪼갰다. 매퍼 추가 → 내부 클래스 메서드 추가 → 뷰 연동 순서로. 문제가 생겼을 때 어느 변경에서 깨졌는지 찾기 훨씬 쉽고, 커밋 메시지도 "무엇을" 보다 "왜"를 담으려고 노력했다. 파트너 잠금 상태 표기 추가보다 cascade 범위 보장을 위해 매퍼에서 일괄 업데이트로 변경이 나중에 git log 볼 때 훨씬 더 유용하다.

댓글 0

첫 댓글 달아줘.