약관 관리 서비스
지마켓 · 옥션 · ESMPLUS 세 사이트에 따로 흩어져 있던 약관을 한 서비스에서 관리하게 만든 프로젝트입니다. 약관을 코드 · 버전 · 시행일자로 다루는 모델부터, 세 사이트의 공개 약관 페이지, HTML 에디터가 붙은 어드민까지 한 묶음으로 만들었고, 뒤이어 약관 동의 서비스로 확장해 지금도 운영 중입니다.
- 기간
- 2024.06 — 2024.12
- 팀
- 4인 팀
- 역할
- 약관 모델 · 구조 결정, 주요 개발 · 사내 리뷰 발표
- 기술
지금 운영 중인 약관 페이지
만든 것
약관을 다루는 쪽(어드민)과 보여주는 쪽(공개 페이지)이 같은 약관 서비스와 저장소를 쓴다는 것을 그린 개념도입니다.
- 약관 모델사이트 · 약관코드 · 버전 · 시행일자 · 필수 · 노출 여부
- 약관그룹 · 매핑화면 하나에 묶이는 약관들과 순서, 매핑 변경 이력
- 시행일자 버저닝미래 시행일로 미리 등록, 시점이 되면 자동 노출
- 공개 약관 페이지세 사이트 각각의 약관 페이지, 약관코드로 URL이 정해짐
- 어드민 · 에디터목록 · 이력 · 등록 · 갱신 · 외부 약관 링크 · 그룹 매핑
- 약관 동의 서비스회원별 동의 내역 · 가입 · 전환 시 동의 API — 후속 과제로 개발해 운영 중
약관은 회원 데이터의 바닥공사
지마켓과 옥션의 약관은 서로 다른 어드민에서 따로 관리되고 있었습니다. 본문 HTML을 DB에 그대로 넣거나 iframe으로 끼워 넣는 구조라 어떤 약관인지 URL로 알 수 없었고, 수정한 내용은 실시간이 아니라 다음 날 0시에 반영됐습니다. 버전과 시행일자를 관리하기 어렵다 보니 어떤 회원이 어떤 약관에 동의했는지도 믿기 어려운 상태였습니다. 실제로 화면에 보이지 않는 약관이 동의 기록에 남거나, 동의값이 비어 있는데 필수 약관이라 티가 나지 않는 경우가 있었습니다.
고지와 동의는 약관 위에 쌓입니다. 약관이 흔들리면 그 위의 회원 데이터도 믿을 수 없다는 뜻이라, 이 프로젝트를 "회원 데이터의 바닥공사"라고 불렀습니다. 4인 팀에서 백엔드와 어드민을 주로 개발했고, 완성 후 사내 리뷰에서 과거 · 현재 · 미래편으로 나눠 발표했습니다.
약관을 세 가지로 나눠서 보기
먼저 용어와 모델을 제가 정했습니다. 약관은 약관코드 하나로 관리되는 본체이고, 약관그룹은 화면 하나에 함께 노출되는 약관들의 묶음이며, 그룹 매핑은 그 둘을 실제로 잇는 관계입니다. 예를 들어 지마켓 개인 구매회원 가입 화면 하나에 약관 여섯 개가 매핑되어 있는 식입니다.
약관 테이블은 식별 정보, 기본 정보(코드 · 이름 · 언어 · 버전 · 시행일자 · 필수 여부), 상태(노출 · 폐기), 링크(본문 · 요약 · 외부 약관), 법령 대응(재동의 · 대체동의 · 선동의), 고지와 동의 연동 정보로 영역을 나눠 설계했습니다. 그룹 매핑은 바뀔 때마다 이력이 남도록 그룹 ID를 올려 가며 기록해서, 나중에 "언제 누가 어떤 약관을 뺐는지" 추적할 수 있게 했습니다.
시행일자가 버전을 움직인다
약관 갱신은 새 버전을 미래 시행일자로 미리 등록해 두면 그 시점부터 자동으로 노출되는 방식입니다. 이전 버전보다 과거의 시행일자나 더 작은 버전은 등록할 수 없게 막았고, 개발자 배포 없이 운영에서 바로 반영됩니다. 다음 날 0시 일괄 반영이던 것이 시행일자 기준 즉시 반영으로 바뀐 셈입니다.
본문은 HTML 에디터로 편집합니다. 에디터의 편집 데이터(JSON)와 생성된 HTML을 함께 Blob 저장소에 두고, 메타 정보만 RDB에 둡니다. 다른 사이트의 약관을 그대로 가져다 쓰는 "외부 약관 링크"도 지원해서, 예를 들어 판매자 사이트에서 지마켓 · 옥션 약관을 다시 만들지 않고 연결할 수 있습니다.
어드민 조회는 Querydsl로
어드민은 사이트, 약관코드, 버전, 노출 여부 같은 조건을 조합해 조회하는 화면이 대부분입니다. JPQL 문자열로 분기하면 조건이 늘 때마다 무한히 갈라질 게 보여서 Querydsl로 동적 쿼리를 구성했습니다. 그룹에 매핑된 약관 목록 페이징처럼 조인이 섞인 조회도 같은 방식으로 다뤘습니다.
프론트는 Spring + Thymeleaf 위에 NPM으로 JS 모듈을 관리하는 구조를 잡았고, 공개 약관 페이지는 약관코드와 사이트 코드가 URL에 드러나 어떤 약관인지 바로 알 수 있게 했습니다.
세 사이트를 한 서비스로
지마켓 · 옥션에 이어 ESMPLUS 약관까지 같은 서비스로 통합하면서, 사이트별로 테이블과 시퀀스 이름이 다른 문제를 만났습니다. 다행히 규칙이 있게 달라서, Hibernate 네이밍 전략으로 접두사를 바꾸고 profile · config만 나누면 코드 수정 없이 사이트를 추가할 수 있게 했습니다. Querydsl도 JPA 네이밍을 따르기 때문에 그대로 동작했습니다. 지금 지마켓 · 옥션 · ESMPLUS의 개인정보 처리방침과 이용약관 페이지는 모두 이 서비스에서 나갑니다.
한 번에 끝나지 않은 과제
완성 후 사내 리뷰에서 이 프로젝트를 과거 · 현재 · 미래편으로 나눠 발표했습니다. 과거편은 두 어드민에 흩어져 있던 시절, 현재편은 위의 모델과 구조, 미래편은 다음 단계였습니다. 그 미래편의 핵심이 약관 동의 서비스입니다. 약관을 관리하는 것과 "이 회원이 어떤 버전의 약관에 언제 동의했는가"를 관리하는 것은 다른 문제라서, 회원가입 · 전환 흐름에 동의 API를 붙이고 사이트별로 따로 있던 동의 테이블을 정리하는 일을 다음 과제로 잡았습니다.
이 약관 동의 서비스는 이후 개발을 이어 가 지금 운영 중입니다. 약관 관리 → 약관 동의로 이어지는 연속 과제였고, 그래서 처음 모델을 설계할 때 동의 코드와 재동의 · 선동의 · 대체동의 필드를 미리 둔 것이 뒤에 그대로 쓰였습니다. 발표 자료는 사내용이라 공개하지 않습니다.
남아 있는 것도 있습니다. 버전 번호 자동 증가는 등록 실수를 직접 고칠 수 있도록 일부러 수동으로 두었고, 노출 스타일(팝업 · 폴딩) 속성을 약관 테이블에 둘지 그룹 매핑에 둘지는 정리 중입니다. 대응 시간이 얼마나 줄었는지는 비교 집계가 없어 수치로 말하지 않습니다.
돌아보면
약관은 눈에 잘 띄지 않지만 회원 데이터 전체가 그 위에 서 있습니다. 코드 · 버전 · 시행일자라는 단순한 규칙을 세우고, 그 규칙을 운영자가 배포 없이 다룰 수 있게 만드는 것이 이 프로젝트의 핵심이었습니다.
회사 업무는 공개 가능한 수준으로만 적었습니다. 내부 코드, 시스템 이름, 고객 정보와 운영 수치는 넣지 않았고, 팀이 함께 한 일과 제가 한 일을 구분했습니다.


