Skip to content

[Fix] 요일 없는 주간 복습 알림 검증을 앱 버전으로 가른다 - #321

Merged
KiSeungMin merged 1 commit into
developfrom
fix/weekday-validation-version-gate
Sep 19, 2026
Merged

KiSeungMin merged 1 commit into
developfrom
fix/weekday-validation-version-gate

Conversation

@KiSeungMin

Copy link
Copy Markdown
Contributor

✔️ 연관 이슈

📝 작업 내용

  • 구버전 앱이 보낸 요청은 예전처럼 받아 주고, 신버전 앱 요청만 400(6003)으로 막습니다. [Fix] 주간 반복 알림에 요일이 비면 400 으로 거절한다 - 지금은 매일 발송으로 폴백한다 #302 로 들어간 검증이 스토어에 나가 있는 구버전 사용자를 가뒀습니다. 구버전 앱에는 요일을 고르라는 클라이언트 검증이 없어서 "매주" 만 고른 저장이 그대로 올라오고, 예전 서버는 그 요청을 매일 크론으로 받아 줬습니다. 그래서 요일이 빈 주간 알림 행을 가진 복습 세트는 제목만 바꿔도 계속 400 이 나서, 앱을 올리기 전에는 수정할 방법이 없었습니다.
  • 판정은 PracticeNotificationWeekDayPolicy 한 곳에 뒀습니다. X-App-Version 이 기준 버전 이상이면 막고, 헤더가 없거나 읽을 수 없는 값이면 구버전으로 봅니다. 기존 버전 판정과 같은 기준입니다.
  • PracticeNotificationScheduler.convertDtoToCron 의 매일 폴백을 되살렸습니다. 구버전 요청은 예전 서버와 같게 매일 크론으로 저장됩니다.
  • POST(registerPractice)와 PATCH(updatePracticeInfo) 두 경로 모두에 적용했습니다.

🤔 주요 고민 및 해결 과정

1. 미션의 LegacyAccrualPolicy 를 그대로 쓰지 않았습니다

2. 기준 버전 기본값을 4.0.0 으로 뒀습니다

  • 헤더 자체가 4.0.0 라인에서 처음 붙습니다. 스토어에 나간 4.0.0 빌드는 헤더를 보내지 않아서 기준값이 무엇이든 구버전으로 떨어집니다. 그래서 이 값은 헤더를 보내는 앱 중 어디까지를 새 앱으로 볼지만 가릅니다.
  • 헤더를 붙인 커밋과 요일을 강제하는 프론트 검증이 같은 빌드에 있습니다. 프론트 pubspec.yaml 이 4.0.0+70 이고, 이 빌드는 이 조합을 만들 수 없습니다.
  • ono.practice-note.week-days-required-version 으로 옮길 수 있습니다. 요일 강제가 빠진 빌드가 뒤늦게 드러나면 배포 없이 기준을 올릴 수 있습니다.

3. 스케줄러에 있던 검증은 뺐습니다

  • 진입부 하나만 남겼습니다. PracticeNoteService 에서 이미 걸러지고, 거기서 막아야 복습노트 저장과 Quartz 잡 삭제가 아예 일어나지 않습니다. Quartz 삭제는 서비스 트랜잭션과 함께 롤백되지 않습니다.
  • 스케줄러까지 버전을 보게 하면 판정이 둘이 됩니다. Quartz 를 다루는 자리에 요청 스코프 값을 하나 더 들여올 이유가 없다고 봤습니다.

👤 사용자 영향

  • 구버전 앱에서 "매주" 만 고르고 저장하면 다시 성공합니다. 예전과 같이 매일 알림으로 등록됩니다.
  • 레거시 행을 가진 복습 세트를 구버전 앱에서 수정할 수 있게 됩니다.
  • 신버전 앱 요청은 지금처럼 400(6003)으로 거절됩니다. 프론트가 이미 요일을 강제하고 있어서 정상 경로에서는 나오지 않습니다.

🔌 API 호환성

  • 요청/응답 DTO 변경 없음
  • 기존 Flutter 앱 버전과 호환 확인 (헤더를 안 보내는 빌드는 구버전으로 떨어져 예전 동작 그대로입니다)
  • breaking change 있음

🗄️ DB migration

  • 없음
  • 있음

🔐 인증/권한

  • 영향 없음

✅ 검증 결과

  • test --tests "com.aisip.OnO.backend.practicenote.*" --tests "com.aisip.OnO.backend.common.web.*" 132개 통과
  • 전체 test 3487개 통과, 실패 0
  • 버전 조합(헤더 없음, 구버전 3.6.0+67, 신버전 4.0.0+70) × POST/PATCH 를 PracticeNoteIntegrationTest 에 고정했습니다. 신버전은 400/6003 이고 아무것도 저장되지 않으며, 구버전과 헤더 없음은 저장에 성공하고 스케줄러까지 그 설정 그대로 닿습니다.
  • 요일이 빈 주간 반복이 매일 크론(0 0 7 ? * *)이 되는지는 PracticeNotificationSchedulerTest 에서 실제 구현으로 확인했습니다.

🚀 배포 리스크

  • 운영 DB 의 레거시 행은 건드리지 않습니다. 버전 분기로 동작이 깨지지 않기 때문에 이번 작업에서는 그대로 뒀습니다.
  • 구버전 요청이 이 분기로 들어오면 log.info 로 남습니다. 이 분기를 언제 걷어낼지는 그 로그가 얼마나 줄어드는지로 판단할 수 있습니다.

↩️ 롤백/대응 방법

  • revert 만으로 충분합니다. 스키마 변경이 없습니다.
  • 기준 버전만 되돌리려면 ono.practice-note.week-days-required-version 을 올리면 됩니다. 값을 아주 높게 두면 사실상 아무도 막지 않습니다.

- #302 로 들어간 검증이 스토어에 나가 있는 구버전 앱 사용자를 막았다. 구버전 앱에는 요일을 고르라는 클라이언트 검증이 없어서 "매주" 만 고른 저장이 그대로 올라오고, 예전 서버는 그 요청을 매일 크론으로 받아 줬다. 그래서 요일이 빈 주간 알림 행을 가진 복습 세트는 제목만 바꿔도 계속 400 이 나 수정할 방법이 없었다
- PracticeNotificationWeekDayPolicy 를 새로 두고 X-App-Version 이 기준 버전(ono.practice-note.week-days-required-version, 기본 4.0.0) 이상인 요청만 400/6003 으로 막는다. 헤더가 없거나 읽을 수 없는 값이면 구버전으로 본다
- 미션의 LegacyAccrualPolicy 는 읽기만 하고 그대로 쓰지 않았다. 거기 붙은 비상 스위치(ono.mission.legacy-accrual.enabled)를 내리면 복습 알림 검증까지 같이 움직이기 때문이다. 공용으로 뺀 것은 AppVersionResolver.isAtLeast 의 버전 비교까지다
- PracticeNotificationScheduler.convertDtoToCron 의 매일 폴백을 되살렸다. 구버전 요청은 예전 서버와 같게 매일로 저장된다. 스케줄러에 있던 검증은 뺐다. 진입부인 PracticeNoteService 에서 이미 걸러지고, 거기서 막아야 Quartz 잡 삭제가 일어나지 않는다
- POST(registerPractice)와 PATCH(updatePracticeInfo) 두 경로 모두에 적용했다

Closes #317
@KiSeungMin KiSeungMin added the fix 버그, 오류 수정 label Sep 19, 2026
@KiSeungMin KiSeungMin self-assigned this Sep 19, 2026
@KiSeungMin
KiSeungMin merged commit 1aa1b8f into develop Sep 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix 버그, 오류 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant