From 0780546d4f1f5420e7e346c1a44313d6b9fdbeb6 Mon Sep 17 00:00:00 2001 From: sb Date: Tue, 7 Jul 2026 21:22:31 +0900 Subject: [PATCH] =?UTF-8?q?feat(recurring):=20=EA=B3=A0=EC=A0=95=EC=A7=80?= =?UTF-8?q?=EC=B6=9C=20=EB=AC=B4=EB=A3=8C=202=EA=B1=B4=20=ED=97=88?= =?UTF-8?q?=EC=9A=A9(=EC=8D=A8=EB=B3=B4=EA=B3=A0=20=EC=97=85=EC=85=80)=20?= =?UTF-8?q?=E2=80=94=20=EC=9C=A0=EB=A3=8C=EC=A0=84=EC=9A=A9=20=ED=95=B4?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WebConfig에서 /recurrings 유료 게이트 제거, 무료는 생성 시 종류무관 2건 한도(초과 400). 유료·관리자 무제한, 복원은 한도 미적용. RecurringMapper.countByMember 추가. Co-Authored-By: Claude Opus 4.8 --- .../sb/web/account/controller/RecurringController.java | 4 +++- .../java/com/sb/web/account/mapper/RecurringMapper.java | 3 +++ .../java/com/sb/web/account/service/BackupService.java | 3 ++- .../com/sb/web/account/service/RecurringService.java | 9 ++++++++- src/main/java/com/sb/web/common/config/WebConfig.java | 1 - src/main/resources/mapper/RecurringMapper.xml | 4 ++++ 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/sb/web/account/controller/RecurringController.java b/src/main/java/com/sb/web/account/controller/RecurringController.java index 2a42458..1f6c28c 100644 --- a/src/main/java/com/sb/web/account/controller/RecurringController.java +++ b/src/main/java/com/sb/web/account/controller/RecurringController.java @@ -34,7 +34,9 @@ public class RecurringController { public ResponseEntity create( @Valid @RequestBody RecurringRequest req, @RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) { - return ResponseEntity.status(HttpStatus.CREATED).body(recurringService.create(req, current.getId())); + boolean premium = "ADMIN".equals(current.getRole()) || "PREMIUM".equals(current.getPlan()); + return ResponseEntity.status(HttpStatus.CREATED) + .body(recurringService.create(req, current.getId(), premium)); } @PutMapping("/{id}") diff --git a/src/main/java/com/sb/web/account/mapper/RecurringMapper.java b/src/main/java/com/sb/web/account/mapper/RecurringMapper.java index 163e619..c812729 100644 --- a/src/main/java/com/sb/web/account/mapper/RecurringMapper.java +++ b/src/main/java/com/sb/web/account/mapper/RecurringMapper.java @@ -15,6 +15,9 @@ public interface RecurringMapper { List findByMember(@Param("memberId") Long memberId); + /** 회원의 정기 거래 개수 (무료 회원 등록 한도 판정용) */ + int countByMember(@Param("memberId") Long memberId); + /** 활성 규칙 (자동 생성용) */ List findActiveByMember(@Param("memberId") Long memberId); diff --git a/src/main/java/com/sb/web/account/service/BackupService.java b/src/main/java/com/sb/web/account/service/BackupService.java index f32e929..f47d1b5 100644 --- a/src/main/java/com/sb/web/account/service/BackupService.java +++ b/src/main/java/com/sb/web/account/service/BackupService.java @@ -153,7 +153,8 @@ public class BackupService { rr.setStartDate(r.getStartDate()); rr.setEndDate(r.getEndDate()); rr.setActive(r.getActive() == null || r.getActive()); - recurringService.create(rr, memberId); + // 복원은 본인 데이터 복구이므로 무료 한도 미적용 + recurringService.create(rr, memberId, true); } } diff --git a/src/main/java/com/sb/web/account/service/RecurringService.java b/src/main/java/com/sb/web/account/service/RecurringService.java index 1fa63e8..2f449c9 100644 --- a/src/main/java/com/sb/web/account/service/RecurringService.java +++ b/src/main/java/com/sb/web/account/service/RecurringService.java @@ -30,8 +30,15 @@ public class RecurringService { return recurringMapper.findByMember(memberId).stream().map(this::toResponse).toList(); } + // 무료 회원 고정지출 등록 한도(써보고 → 결제 유도). 유료·관리자는 무제한. + public static final int FREE_RECURRING_LIMIT = 2; + @Transactional - public RecurringResponse create(RecurringRequest req, Long memberId) { + public RecurringResponse create(RecurringRequest req, Long memberId, boolean premium) { + if (!premium && recurringMapper.countByMember(memberId) >= FREE_RECURRING_LIMIT) { + throw new ApiException(HttpStatus.BAD_REQUEST, + "무료 회원은 고정 지출을 " + FREE_RECURRING_LIMIT + "개까지 등록할 수 있어요. 유료로 업그레이드하면 무제한이에요."); + } Recurring r = toEntity(req); r.setMemberId(memberId); recurringMapper.insert(r); diff --git a/src/main/java/com/sb/web/common/config/WebConfig.java b/src/main/java/com/sb/web/common/config/WebConfig.java index a2754ff..1da8afe 100644 --- a/src/main/java/com/sb/web/common/config/WebConfig.java +++ b/src/main/java/com/sb/web/common/config/WebConfig.java @@ -42,7 +42,6 @@ public class WebConfig implements WebMvcConfigurer { "/api/account/ai-comment", "/api/account/networth/trend", "/api/account/budgets", "/api/account/budgets/**", - "/api/account/recurrings", "/api/account/recurrings/**", "/api/account/ocr", "/api/account/ocr/**", "/api/account/invest", "/api/account/invest/**", "/api/account/tags", "/api/account/tags/**", diff --git a/src/main/resources/mapper/RecurringMapper.xml b/src/main/resources/mapper/RecurringMapper.xml index 08b5c7f..357c60d 100644 --- a/src/main/resources/mapper/RecurringMapper.xml +++ b/src/main/resources/mapper/RecurringMapper.xml @@ -78,4 +78,8 @@ UPDATE recurring SET last_run_date = #{lastRunDate} WHERE id = #{id} + +