JDBC driver마다 column alias의 대소문자를 다르게 반환할 수 있어
entryId → entry_id, tagName → tag_name 으로 소문자 통일.
NPE 방지를 위한 null 체크도 추가.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
list() 에서 항목마다 findTagNamesByEntryId() 를 개별 호출하던 N+1 을
findTagsByEntryIds() 배치 쿼리 1회로 대체.
항목 수가 많을 때 타임아웃/과부하 방지.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- budget 테이블에 year/month 추가, (member,category)→(member,category,year,month) 유니크 교체
기존 상시 예산은 현재 월로 1회 이관
- 예산 조회/생성/현황/기간차트를 월별로(findByMember에 year/month)
- copyMonth: 다른 월 예산을 대상 월로 복사(같은 분류 덮어씀) + POST /budgets/copy
- 백업 복구 시 예산은 현재 월로 등록
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- GET /board/my/posts, /board/my/comments (페이징)
- PostSummary 에 category 추가, MyCommentResponse(글 제목·카테고리 포함)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 만료 강등 스케줄러: 해지(자동갱신 off) 건만 강등(자동갱신은 마켓/RTDN 관리)
- POST /api/billing/restore: 최근 결제 기준 멤버십 복원(기기변경·재설치)
- POST /api/billing/google/rtdn: Google Play 실시간 알림 수신 스캐폴드(비인증, 로깅)
- 실연동 지점(영수증 검증·RTDN 처리)은 TODO 로 표시
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- DELETE /api/auth/me: 본인 계정과 모든 데이터 영구 삭제
- 게시판(글/댓글/추천/이미지)·가계부 전체·포인트·결제기록·세션 → 회원 순 삭제
- WithdrawMapper(게시판/포인트/결제/세션) + BackupMapper(가계부) 재사용
- AuthServiceTest 생성자 보강
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- member.plan_product, plan_auto_renew 컬럼(구독 상품·자동갱신)
- GET /api/billing/subscription: 플랜·만료일·다음결제일·자동갱신
- POST /api/billing/cancel: 자동갱신 중단(만료일까지 이용), /resume: 재개
- verify 시 상품·자동갱신 기록, 만료 강등·관리자 변경 시 구독정보 정리
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- member.plan_expires_at + iap_purchase 테이블(중복 결제 방지)
- POST /api/billing/google/verify: 구매 검증 후 PREMIUM 부여/갱신(만료 연장), 세션 plan 즉시 동기화
- GET /api/billing/products: 구독 상품(월간/연간)
- 테스트 모드(billing.test-mode=true): test- 토큰 검증 없이 승인 → 전 과정 테스트 가능
- GooglePlayVerifier 인터페이스 + 스텁(실연동 지점), 실연동 시 구현체 교체
- 관리자 수동 plan 변경은 만료일 없이(영구), 결제는 만료일 부여
- 만료 자동 강등 스케줄러(매시), MemberResponse.planExpiresAt 노출
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- BoardSettingMapper(+XML)/BoardSettingRequest/Response 삭제
- TagService board_setting 의존 제거, /admin/board-setting 엔드포인트 제거
- board_setting 테이블 DDL 제거
- 글 수정 시 전체 그룹 조회(기존 글 태그 유실 방지): listWritableGroups(blank)=전체
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- GET /api/auth/profile: 아바타·포인트 포함 전체 프로필(재로그인 없이 최신화)
- 자기 글/댓글 추천·비추천 차단(400)
- 인기 글: 등록 1일 이내 + 추천 50건 이상이면 목록 상단 최대 3건 노출(hot)
- 인기 댓글: 동일 조건으로 댓글 목록 상단 정렬(hot)
- PostSummary 에 downCount 추가(비추천 20+ 블라인드 판정용)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>
- POST /api/account/restore: 기존 데이터 전부 삭제 후 이름 기준 재생성
(계좌→태그→분류(대/소)→내역→고정→예산→자주내역), 한 트랜잭션(실패 시 롤백)
- 빈 데이터 안전장치, 투자 종목/매매는 복구 대상 외(삭제됨)
- BackupMapper(deleteByMember), RestoreRequest DTO, BackupService/Controller
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- post.notice 컬럼 추가(멱등 ALTER)
- 목록 정렬 ORDER BY notice DESC, id DESC (공지 최상단)
- 작성 시 공지 설정(관리자만 반영) + /posts/{id}/notice·unnotice 토글
- Post/PostSummary/PostDetail/PostRequest 에 notice 반영
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- member.google_id 컬럼 추가(멱등 ALTER) + 기존 GOOGLE 계정 sub 백필
- googleLogin: google_id 조회 → 없으면 검증된 동일 이메일 계정(LOCAL 우선)에
연결 → 그래도 없으면 신규 생성. provider 는 유지(아이디 로그인/프로필 편집 보존)
- MemberMapper: findByGoogleId/findByEmailForLink/linkGoogle 추가, google_id 매핑
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- AuthService.googleLogin: 구글 tokeninfo 로 ID 토큰 검증(aud==클라이언트 ID)
후 provider=GOOGLE 회원 조회/자동가입 → 세션 발급(login 과 동일 경로)
- GoogleLoginRequest DTO, /api/auth/google·/google-client-id 엔드포인트
- application.yml: app.google-client-id=${GOOGLE_CLIENT_ID:}
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- default_category 테이블(전체 공용) + 도메인/매퍼/서비스
- 관리자 API /api/admin/default-categories (CRUD·reorder, ADMIN 보호)
- 사용자 /account/categories/import: 기존 내역 기반 → 기본분류 복사로 변경
(대/소분류 계층 유지, 같은 이름은 건너뜀; CategoryMapper.findByMemberTypeName 추가)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- parent_id 추가(CREATE + ALTER IF NOT EXISTS 멱등 마이그레이션)
- 도메인/DTO/매퍼에 parentId 노출, 2단계 검증(대분류 아래만 소분류)
- 자식 있는 대분류는 소분류화·삭제 차단(countChildren)
- 통계/예산/내역은 소분류 이름 기준 그대로(무변경)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 앱은 출처가 localhost 라 /api/images/{id} 상대경로가 백엔드로 안 감 → 안 보임
- app.public-url(기본 https://app.sblog.kr) 기준 절대 URL 반환 → 웹/PC/APK 모두 로드
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- board_image 테이블 + BoardImageController/Service/Mapper
· POST /api/board/images(로그인) → {url:/api/images/{id}}
· GET /api/images/{id}(공개, img src 로 로드) — 1년 캐시
- 본문엔 짧은 URL 만 들어가 글이 비대해지지 않음
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- InvestController/Service/Mapper: updateTrade 추가
- 수정 결과를 시점별로 시뮬레이션해 보유수량이 음수가 되면 거부(매도 과다 방지)
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>
- 관리자 회원가입 허용 토글(app_setting), 공개 GET /auth/signup-enabled
- 회원가입 봇차단: 허니팟(website) + IP 레이트리밋(Redis, 1h 5회)
- 카드 알림: 현금 오선택 보정(카드 양방향 매칭+단일카드 자동), 광고 푸시 차단(승인신호 없는 광고성 표현 무시)
- @MapperScan 에 admin.mapper 추가
- account.sql: 매 기동 wallet MODIFY 제거(라이브 락 위험) — CREATE 정의에 255 반영됨
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- account_entry pending/notif_key 컬럼 추가(멱등 마이그레이션)
- CardNotificationParser: 카드사·금액·가맹점·승인/취소 파싱
- POST /entries/notification(미확인 지출 생성, 중복방지, 카드 자동매칭)
- POST /entries/{id}/confirm(확정), GET /entries/pending/count
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- VisionOcrService: 이미지→Google Vision DOCUMENT_TEXT_DETECTION 호출, 전체 텍스트 반환
- OcrController: POST /api/account/ocr/receipt (멀티파트, 로그인 필요)
- API 키는 GOOGLE_VISION_API_KEY 환경변수(.env)로만 주입 — 미설정 시 503
- multipart 업로드 10MB 허용
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- invest_trade.quantity BIGINT→DECIMAL(18,6): 평단·원가·평가/실현손익 계산을 BigDecimal로 전환 (금액은 원단위 정수 유지)
- account_entry.installment_months 추가: 카드 지출 2~24개월 할부 기록(일시불 null), 응답에 포함
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 예상 수입: budget_income(연·월별) 로 변경, GET/PUT 에 year·month
- 계좌: wallet.sort_order + reorder 엔드포인트, 생성 시 맨 뒤 배치
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>
@