콘텐츠로 이동

알려진 이슈

인수인계 시점(2026-05-11)에 존재하는 알려진 이슈·한계의 통합 목록. 각 기능 페이지(03-features/*.md)의 "알려진 이슈" 섹션을 카테고리별로 재정렬하고, 운영·인프라 한계와 인수인계 결정 미정 항목을 합쳤다.

각 항목 형식: 이슈 / 코드 위치 / 영향도 / 해결 방안 / 담당 PR·Issue.


1. 보안 우려

# 이슈 위치 영향도 해결 방안 담당
S1 RDS Security Group sg-09b20a06663fcfa010.0.0.0/0:3306 인터넷 노출 AWS SG HIGH (prod DB가 노출됨) Hard cutover 후 잠금 — MyIP/32 + Lightsail VPC peer CIDR만 허용 Issue #151 (cutover 후)
S2 /auth/test profile-gate 미적용 AuthController.kt /auth/test MED (운영 노출 시 임의 번호 SMS 발송 가능) @Profile("local") 또는 SecurityConfig 단에서 prod 차단 별도 PR (#170은 /accounts/test/**만 처리)
S3 카드사 심사 백도어 (01099999999999999) AuthService.issuePhoneAuthentication() //TODO - 카드사 심사 통과시 제거 MED (PG 심사 완료 후 제거 예정) TODO 주석대로 코드 삭제 PG 심사 후
S4 시크릿이 일부 yaml에 하드코딩 (Langfuse local, RDS password 등) application-prod.yml, application.yml 사용자 수락됨 (CLAUDE.md feedback_accepted_repo_secrets) 별도 rotation 예정 — hard cutover 시점 hard cutover 시
S5 Toss webhook signature 검증 부재 TossWebhookController LOW (DoS 가능성) Toss V2는 서명 미지원 — paymentKey re-fetch로 차단 중. 추가 대책 미정
S6 인증코드 무제한 재시도 (rate limit 부재) PhoneAuthentication.verify() LOW (코드 6자리 → 시도 100만 회 brute force 가능) rate limit 미구현 추후
S7 어드민 작업 audit log 부재 (회원 권한/상태 변경, 쿠폰 발급, 결제 승인) AdminService 전반 MED (사후 추적 불가) AdminAuditLogController 확장 추후

2. 백엔드 코드 이슈 (기능 페이지에서 발견된 TODO 집약)

인증 / 회원

  • OAuth2 도메인 코드 존재하나 미사용: OAuth2Account, OAuth2Provider 등. 카카오/네이버 로그인 도입 시 활용 예정.

멤버십 / 결제

  • 만료 후 grace period 없음: 자동 갱신 실패 시 즉시 isSubscriptionPaused=true. 사용자 재시도 안내·재충전 유예 미구현 (SubscriptionRenewalScheduler.processRenewals()).
  • 취소 시 잔여 일수 비례 환불 미구현: cancelTossPayment는 전액 취소만. 부분 환불 없음.
  • 결제 WAITING_DEPOSIT 정리 cron 부재: 가상계좌 미입금 PENDING이 누적 가능.
  • 단일 활성 결제수단 가정: paymentMethodRepository.findActivatedAndDeactivatedByAccountId(accountId)가 single-row 반환 가정. 멀티 카드 시 비정상.
  • PortOne V1 잔재: PaymentStatusPRE_VERIFICATION, POST_VERIFICATION, ADDITIONAL_VERIFICATION 등 미사용 가능성 있는 상태값. 정리 필요 (Issue #109 카리오버).
  • registerPayment recommender 검증 없음: 추천인 코드가 free-form. 실재/중복 검증 없음.
  • 테스트 전용 메서드가 production 서비스 클래스에 혼재 (switchTierForTest, injectCycleUsageForTest, grantTokenPackForTest): profile gate 검증 필요.

쿠폰

  • 5자리 PK birthday collision (가장 시급): Coupon.createRandom() UUID hex 앞 5자리만 사용 → 16^5 ≈ 1M 공간. ~1200건 발급 시 birthday paradox 임계 도달. couponRepository.saveAll() 단일 트랜잭션이라 1건 충돌 시 전체 rollback. 6-8자리 확장 또는 retry 로직 필요.
  • TOKEN_PACK 쿠폰 런타임 깨짐: Coupon.productType=TOKEN_PACK일 때 Membership.byCouponMembershipType.valueOf("TOKEN_PACK") 시도 → enum에 없어 IllegalArgumentException. 어드민 발급 폼에는 선택지로 노출됨.
  • 만료일 부재: 발급 쿠폰은 영구 유효. 캠페인 종료 후 차단 메커니즘 없음.
  • 할인율·금액쿠폰 미지원: 1쿠폰 = 1개월 멤버십 발급만 지원.
  • 응답이 enum (OK/USED/INVALID)인데 status는 200: 클라이언트가 body 파싱해야 분기. RESTful하게 4xx로 변경 여지.

RAG / 카테고리 / 리포트

  • TaxCategoryInferenceService가 Langfuse temperature/maxTokens 무시: KeywordExtractionService는 fix됐으나 analyzeQuestionWithLlm()은 여전히 ChatCompletionRequest에 전달 안 함 (Issue #148 carryover).
  • 백필 API 동기 처리 → ALB 60s timeout 위험: POST /admin/conversations/backfill-keywords LLM 1건당 ~500ms. limit=500이면 ~4분 — ALB/Cloudflare 기본 timeout 60s 초과 시 클라이언트가 응답 못 받음 (백엔드는 계속 실행). prod에서는 limit=100으로 chunk 또는 비동기 job 전환 권장 (Issue #148 미해결).
  • HyDE prod 설정 미명시: application.ymltrue로 활성화돼 있으나 application-prod.yml에 override 없음. prod에서 끄려면 명시 필요.
  • intent-router.unified.enabled prod 미설정: prod yaml에 명시 없음 — 기본 false(Phase 0, LLM 3회) 동작. Phase 1(단일 호출) 원하면 prod에서 명시 true 필요.
  • SSE 3분 hardcoded: SSE_TIMEOUT = 180_000L. 매우 긴 답변 잘릴 수 있음.
  • Citation tag 누락 시: LLM이 <citations>...</citations>를 안 붙이면 parseCitedIds()가 빈 리스트 → 필터링 비활성. 프롬프트 변경 시 회귀 주의.
  • Migration 미적용 환경의 isArchiveEligible=null: Issue #148 이전 세션은 NULL. infra/sql/...V20260430_1...을 수동 적용해야 게시판에 노출됨.
  • COMMERCIAL_LAW/ACCOUNTING 카테고리 검증 필요: LawCategory.values() 동적 노출. 클라이언트 의도와 일치 여부 별도 확인.
  • Keyword 재추출 트리거 부재: keywords != null 가드로 추가 turn 와도 재추출 안 됨. 강제 갱신은 백필 endpoint만.
  • Legacy Report 도메인 미사용: Report/ReferenceData/SimilarData 테이블은 admin 조회 + ReportCleaner cron만 남음. 신규 코드는 안 씀 — schema cleanup 후보.

관리자 콘솔

  • 감사 로그 보존 정책 미정: elasticsearch_audit_log 만료/삭제 cron 없음 → 무기한 누적.
  • /admin/payments v1 / /admin/payments/v2 병행: Issue #109 잔재. Toss V2 안정화 후 v1 정리 필요.
  • 소프트 삭제만: AdminService.deleteReport()는 entity delete() 호출 — 물리 삭제 아님. 조회 쿼리에서 deleted flag 필터링 필요.

팝업 / 공지

  • 기능 자체가 미구현: 사용자 공지 채널 + 점검 모드 toggle 모두 부재. 점검은 현재 시스템 다운으로 처리.

3. 인프라 한계

# 이슈 영향도 해결 방안
I1 Flyway 미사용 HIGH (마이그레이션 수동 적용 — 누락 위험) 마이그레이션 파일을 infra/sql/2026-05-11-prod-init.sql 패턴으로 수동 적용. Flyway 도입은 별도 이슈
I2 백엔드 Sentry 미설치 MED (런타임 예외 추적이 journalctl만) sentry-spring-boot-starter 도입 별도 이슈
I3 prod Toss live keys 사용자 제공 대기 HIGH (Issue #151 blocker) user 제공 후 prod env-var 주입
I4 PR 미리보기 (Cloudflare Pages) — Phase 3 발견 LOW 다음 PR부터 정상 동작 예상. 현재까지는 Cloudflare Pages 프로젝트 생성 후에 만들어진 PR만 preview 가능 ⚠️ (검증 필요)
I5 외부 reachability pinger 부재 MED (사용자 보고가 1차 채널) UptimeRobot 등 SaaS 연동 별도 이슈
I6 CloudWatch 알람 미설정 (RDS FreeStorageSpace, ALB 5xx 등) MED CloudWatch Alarm + SNS → Slack 연동 별도 이슈
I7 Prod Lightsail에 disk-alarm/health-monitor 미배포 MED semugpt-prod box 생성 시 dev와 동일 패턴 복제 (Issue #151 Phase 5)
I8 RDS storage 17 GB free / autoscaling to 1000 GB LOW (당장 여유) 모니터링만
I9 RDS max_connections=60 (현재 13 사용) LOW 신규 backend Hikari maximum-pool-size: 10 권장
I10 Lightsail 8 GB RAM 충분한지 미검증 LOW 모니터링 후 부족 시 xlarge_3_0 (16 GB, $84/mo) 승급

4. 인수인계 결정 미정

cutover 전·후로 stakeholder 결정이 필요한 항목.

# 항목 현재 상태 결정 시점
D1 사용자 재가입 안내 Soft launch라 무관 (legacy 사용자는 계속 legacy 사용) Hard cutover 시점
D2 Backend secret rotation 현재 legacy + 신규 app이 같은 secret 공유 Hard cutover 시점
D3 백필 endpoint 비동기 전환 동기 처리 (60s timeout 위험) Issue #148 후속
D4 Hard cutover 시점 (apex/www/api/pro → 새 인프라) 무기한 연기 클라이언트 의사결정 대기
D5 Legacy EC2 decommission hard cutover 1주 후 terminate 예정 hard cutover 후
D6 Toss webhook URL prod 등록 미등록 — Toss 콘솔에서 https://api-new.semugpt.co.kr/webhooks/tosspayments 추가 필요 Phase 5 deploy 시

5. 위키 자체의 한계

  • Phase 3 fact-check audit에서 18개 사실 오류 catch — 8개 기능 페이지 작성 시 SMS 구현체 오인용(AWS SNS → 실제는 Naver Cloud SENS), Toss webhook path, coupon delete 정책, LawCategory 갯수, 존재하지 않는 application-dev.yml 참조 등. 자세한 prior incidents는 docs/wiki/CLAUDE.md Chapter 10 참조.
  • 코드 변경 시 wiki와 drift 가능 — 정기적 audit 권장. wiki는 진실의 소스가 아니라 스냅샷 — 의심스러우면 코드를 1차 출처로 확인.
  • 일부 ⚠️ Uncertain 항목 남아있음 — Phase 3 PR description의 "남은 ⚠️ Uncertain" 섹션 참조. 본 페이지의 표에도 ⚠️ (검증 필요) 마킹으로 표시.
  • OpenAPI 페이지의 schema anchor 링크 불안정 — 직접 anchor 링크 사용 금지, endpoint별 검색 유도 (CLAUDE.md Chapter 6).

관련 문서