- member.google_picture(구글 아바타 URL), profile_image(사용자 지정 data URL) 컬럼 추가(멱등)
- 구글 로그인 시 picture 클레임 추출 → 신규 저장, 기존은 변경 시 동기화
- PUT /api/auth/profile-image: 사용자 지정 사진 설정/해제(빈값=해제→구글 폴백), data URL·용량 검증
- MemberResponse 에 googlePicture/profileImage 노출(표시 우선순위 프론트 처리)
- 관리자 목록(findAll)은 무거운 profile_image 제외해 가볍게 조회
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- member.plan(FREE/PREMIUM) 컬럼 추가 + SessionUser/MemberResponse 노출
- auth_session 백업에 plan 저장(세션 복원 시 유료 상태 유지)
- 관리자 회원 plan 변경 API (PUT /api/admin/members/{id}/plan)
- PremiumInterceptor 로 유료 전용 경로 차단(통계/예산/고정지출/태그/OCR/투자/카드알림/백업)
· 관리자는 플랜과 무관하게 허용, 무료 회원은 403 PREMIUM_REQUIRED
- WebConfigTest: 유료 경로 등록 회귀 가드 추가
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 기존 광고 차단(if !strong && AD_HINT)은 강신호가 보장된 지점이라
항상 false → 한 번도 실행되지 않는 죽은 코드였음. 광고어가 섞여도
승인/입금 등 신호가 있으면 그대로 등록되던 원인.
- 광고어를 2단계로 분리:
- AD_BLOCK(이벤트·쿠폰·혜택·당첨 등): 거래신호가 있어도 무조건 제외
- AD_WEAK(적립·포인트·할인 등): '결제'만 있고 명확한 거래신호가 없을 때 제외
(실거래 영수증의 '포인트 적립'은 보존)
- '결제'는 광고 문구에도 흔해 약신호(weakApproval)로 강등
- 파서 단위테스트 +4 (광고+강신호 차단, 실거래 포인트 보존, 결제단독 광고/정상)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 파서: 입금→수입, 출금/이체→지출, 카드 승인→지출, 카드 취소/환불→수입(환불)
은행 거래는 은행(BANK) 지갑에, 카드는 카드(CARD) 지갑에 매칭(matchWalletId 일반화)
- createFromNotification: 파싱된 수입/지출 타입·지갑종류로 생성
- 파서 테스트 갱신(은행 입금/출금 케이스 포함)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- CardIssuerMatcher: 공백·접미사(카드/은행/페이/뱅크) 제거 + 별칭 통합(KB↔국민, 농협↔NH, 비씨↔BC, 씨티↔시티)
· KB카드/국민카드/KB국민/국민 어떻게 등록해도 KB국민카드 알림에 자동 매칭
- AccountService.overlaps 가 CardIssuerMatcher 사용
- 단위테스트 4 추가
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 로그인/비밀번호 재인증에 실패 기반 레이트리밋(Redis 슬라이딩 윈도우)
· 로그인 IP당 10회/10분, 비밀번호 게이트 회원당 5회/10분, 초과 시 429
· 성공 시 실패 카운터 초기화, Redis 장애 시 통과(가용성 우선)
· 회원가입 레이트리밋도 공통 enforceRateLimit 으로 일원화
- GlobalExceptionHandler: 미처리 500 로그에 메서드+경로 기록(추적성), 잘못된 JSON은 400
- 테스트: 레이트리밋 429 케이스 2개 추가 (백엔드 총 34)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- AuthControllerWebMvcTest(@WebMvcTest): 실제 인터셉터·경로매핑 로드해 검증
· 보호 경로(verify-password/profile/me) 토큰 없으면 401(500 아님)
· 유효 토큰이면 컨트롤러 도달(CURRENT_MEMBER 주입), 공개 경로(signup-enabled) 200
· 단위테스트가 못 잡은 인터셉터 와이어링 누락(이번 500 버그)을 잡는 계층
· @MapperScan 매퍼는 DB 없는 경량 SqlSessionFactory로 빈 생성만 통과
- deploy.yaml: clean build 가 @SpringBootTest(SbBtApplicationTests) 포함 →
CI와 동일한 MariaDB/Redis 서비스+env 추가
(없으면 배포 게이트가 DB 못 붙어 실패 → 직전 게이트 변경이 배포를 깨뜨렸던 문제 수정)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- WebConfig authInterceptor 경로에 /api/auth/verify-password, /api/auth/profile 추가
(누락 시 CURRENT_MEMBER 미설정 → 로그인 사용자도 NPE 500)
- WebConfigTest: 인증 필수 auth 엔드포인트 보호 경로 등록 회귀 가드
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- POST /auth/verify-password, PUT /auth/profile(세션 표시 이름 동기화)
- MemberMapper.updateProfile, AuthSessionMapper.updateName
- 단위테스트(24): CardNotificationParser(8), AuthService(16, Mockito)
- CI(.gitea): 테스트 리포트 아티팩트 업로드(clean build가 곧 테스트 게이트)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Initial commit: SB 백엔드 (Spring Boot + MyBatis)
- 사용자 CRUD REST API (/api/users)
- MariaDB(MyBatis) + Redis 캐싱 구성
- CORS 설정 및 헬스 체크 엔드포인트
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@