비즈니스 로직 버그 수정과 코드 정리할 때 자주 나오는 패턴
나닮에서 페르소나 진화, 구독 정책 변경, UI 레이어를 건드리면서 겪었던 버그와 정리 패턴을 정리해 봤다. "기준점 초기화", "dead code 정리", "z-index" 세 가지를 중심으로 쓴다.
페르소나 업그레이드 직후 진화가 바로 뜨는 버그
페르소나를 처음 만들거나 레벨을 올릴 때 diary_count_at_last_evolution을 안 넣어서 기본값 0으로 남아 있었다. 진화 조건은 "마지막 진화 이후 새 일기 5개"인데, 기준이 0이면 현재 일기 수 전체가 새 일기로 잡혀서, 업그레이드 직후에 진화 버튼이 켜지는 문제가 있었다.
예를 들어 일기 10개 쓴 뒤 페르소나를 complete로 업그레이드하면, 새 일기 수 = 10 - 0 = 10이 되어 5개 조건을 그대로 만족해 버린다.
원인은 단순하다. generate_persona와 upgrade_persona 둘 다에서 이 필드를 설정하지 않은 것. 진화 서비스에서 "새 일기 수"를 구하는 로직 자체는 맞는데, 기준점이 잘못돼서 결과가 틀렸다.
수정은 생성 시와 업그레이드 시 모두 현재 일기 수를 기준점으로 넣어 주는 것이다.
# 생성 시
diary_count = self.db.query(Diary).filter(Diary.user_id == user.id).count()
persona = Persona(..., diary_count_at_last_evolution=diary_count)
# 업그레이드 시
persona.diary_count_at_last_evolution = diary_count교훈이라면, 차이(delta)를 쓰는 기준점 필드는 0이 "아직 없음"이 아니라 "처음부터 전부"로 해석될 수 있다는 점. 마지막 진화 시점 일기 수, 마지막 로그인 시각 같은 건 생성/변경 시점에 꼭 초기화해야 하고, 그 모델을 만지는 모든 경로(최초 생성, 업그레이드, 관리자 수정 등)를 한 번씩은 훑어보는 게 좋다.
Dead code 정리 — 구독 정책이 바뀐 뒤
프리미엄 전면 무료(v1.16.0) 이후에도, 진화 서비스에는 "오늘 진화 N회 제한" 같은 구독 기반 로직이 그대로 남아 있었다. 실제로 타는 경로는 없는데 SubscriptionService, FREE_PLAN_LIMITS, PREMIUM_PLAN_LIMITS를 끌어 쓰고 있고, 프론트에는 monthly_used/monthly_limit UI와 cooldown_days_remaining 스키마가 남아 있는 상태.
정책이 바뀔 때 관련 코드를 같이 정리하지 않으면, 나중에 "이거 왜 있지?", "지워도 되나?" 판단이 점점 어려워진다. 이번도 v1.16에서 무료 전환했는데 진화 제한 코드는 v1.24 근처까지 남아 있었다.
한 번 정리할 때:
- 백엔드:
_get_today_evolution_count()제거, 구독 관련 import·스키마 필드 제거 - 프론트:
EvolutionStatus타입에서 해당 필드 제거, PersonaPage의 "오늘 N/M회" UI 제거
TypeScript strict 쓰면 타입에서 필드만 지워도 참조하는 곳이 다 나와서 누락을 막기 좋다. API 스키마를 바꿀 때는 백엔드·프론트를 같이 손대는 것이 중요하다.
z-index — 탭 배지가 옆 탭에 가려질 때
친구 페이지 탭("친구", "요청", "찾기") 중 "요청"에 미수신 요청 개수 배지가 붙어 있는데, absolute로 버튼 밖으로 나가 있어서 DOM 순서상 다음에 오는 "찾기" 버튼 뒤에 가려지는 이슈가 있었다.
원인은 z-index 미지정. 스택 컨텍스트에서 명시하지 않으면 DOM 순서대로 쌓이니까, 배지에 z-10만 줘도 인접 탭보다 위로 올라온다.
<span className="absolute -top-1 -right-1 z-10 ...">
{receivedRequestCount}
</span>absolute로 형제와 겹치는 요소(배지, 툴팁, 드롭다운)는 z-index를 명시해 두는 게 안전하다. 개발할 때는 배지가 있는 데이터·화면에서만 보이니까 놓치기 쉽고, 실제 디바이스에서 한 번 확인하는 게 좋다.
정리할 때 갖춰두면 좋은 습관
- 기준점 필드: 생성/업그레이드 등 모든 변경 경로에서 초기화 여부 확인. 0이 "없음"인지 "전체"인지 한 번 생각해 보기.
- 정책 변경 시: 유료→무료, 기능 제거 같은 걸 바꿀 때마다 관련 dead code와 스키마/UI를 같이 정리. 시점이 멀어질수록 심리적 저항만 커진다.
- 백엔드·프론트 동시 정리: 스키마 필드 제거 시 타입과 UI까지 같이 정리해서
undefined참조나 의미 없는 UI가 남지 않게. - absolute + 겹침: 오버레이 성격 요소는 z-index를 의도적으로 관리. 프로젝트에서 배지 10, 드롭다운 20, 모달 30처럼 단계만 정해 둬도 충돌을 많이 줄일 수 있다.
이번에 손본 건 페르소나·진화·친구 탭 쪽이지만, 다른 도메인에서도 "기준점 초기화", "정책 변경 후 정리", "레이어 겹침" 세 가지는 자주 나오는 패턴이라 정리해 두었다.