Skip to content

refactor(common): common 경계 룰 정리 + IP/UA 추출 단일화 (P1-4)#119

Open
chanwoo7 wants to merge 1 commit into
developfrom
refactor/common-boundary-and-ip-extraction
Open

refactor(common): common 경계 룰 정리 + IP/UA 추출 단일화 (P1-4)#119
chanwoo7 wants to merge 1 commit into
developfrom
refactor/common-boundary-and-ip-extraction

Conversation

@chanwoo7
Copy link
Copy Markdown
Member

Summary

P1-4 (common/ 경계 룰 정리) 와 함께, 작업 중 발견한 IP/UA 추출 로직 2 구현 분기 + auth 흐름이 naive 쪽 사용 문제도 함께 정리.

  • common/utils/: 순수 함수, 외부 DI 0 — 룰 명문화
  • common/helpers/: NestJS 서비스/Config 를 매개변수로 받는 헬퍼만 잔존 (현재 config.helper.ts 만 해당)
  • IP/UA 단일화: refresh session / audit log 의 ip_addressX-Forwarded-For 기반 정확 IP 로 정상화 (운영에서 TRUST_PROXY_HOPS 설정 시)

Scope

1. common 경계 룰 — 파일 재배치 (helpers/ → utils/)

Before After 사유
common/helpers/crypto.helper.ts common/utils/crypto.ts node:crypto 만 사용. NestJS DI 매개변수 0. 순수 함수
common/helpers/url-query.helper.ts common/utils/url-query.ts qs 타입만 사용. 순수 함수
common/helpers/error.helper.ts common/utils/error.ts HttpException 클래스만 사용 (값 클래스, DI 아님). 순수 함수
(유지) common/helpers/config.helper.ts (유지) ConfigService 를 매개변수로 받음 → helpers/ 룰 일치

spec 도 동일하게 이동 (git mv 사용 — diff 가독성 보존). 모든 import site 갱신.

2. crypto 중복 제거 — TokenService → utils/crypto 사용

  • TokenService.sha256Hex 내부 구현 createHash('sha256').update(raw).digest('hex')sha256HexUtil(raw) 호출로 교체
  • TokenService.generateRefreshToken 내부 구현 randomBytes(32).toString('hex')generateRandomToken(32) 호출로 교체
  • public API (TokenService.sha256Hex, interface) 는 유지 — 외부 caller 영향 0

3. IP/UA 추출 단일화

Before — 2 구현 분기

  • common/utils/http-meta.tsclientIpOf / userAgentOf: 정밀 (X-Forwarded-For → X-Real-IP → req.ip → socket 순), 로깅에만 사용
  • features/auth/helpers/auth-request-meta.helper.tsgetIp / getUserAgent: naive (req.ip 만), refresh session / audit log persistence 에 사용

After — utils/http-meta.ts 단일

  • tryClientIp(req): string | undefined 추가 — DB persistence 용 (undefined fallback)
  • tryUserAgent(req): string | undefined 추가 — DB persistence 용 (raw UA, 512 자 슬라이스)
  • 기존 clientIpOf / userAgentOf 는 try* 위에 'Unknown *' fallback 적용 (로깅용, DRY)
  • token.service.ts / seller-credential.service.ts: naive getIp / getUserAgent → 정밀 tryClientIp / tryUserAgent 로 교체
  • features/auth/helpers/auth-request-meta.helper.ts 삭제 (callsite 0)

결과: refresh session ip_address / user_agent, audit log ip_address / user_agent 가 reverse proxy 환경에서 정확한 client IP 로 기록 (단, TRUST_PROXY_HOPS 설정 필요 — 아래 4번)

4. trust proxy 환경 변수 추가

  • main.ts 에 env-based 추가: TRUST_PROXY_HOPS
    • 미설정 / 0: 비활성 (Express 기본 동작, 현 상태 유지)
    • 1: ELB 1 대 또는 Nginx 1 대
    • 2+: ELB + CloudFront 등 다단 hop
  • 잘못 설정 시 IP spoofing 위험 → 운영 인프라 실제 hop 수와 정확히 맞춰야 함
  • Express getHttpAdapter().getInstance().set('trust proxy', hops) 으로 적용

Impact

  • FE: 없음 (응답 형태/내용 불변)
  • DB:
    • 스키마 변경 0
    • 운영 데이터 영향: TRUST_PROXY_HOPS 설정 시점부터 refresh_session.ip_address, audit_log.ip_address 가 정확한 client IP 로 기록. 그 전 기록된 row 는 그대로 (회고용 가치만 변동).
  • Coverage: pre-push validate gate 통과 (전체 1199 테스트, 신규 +8 케이스 — http-meta tryClientIp / tryUserAgent)
  • 운영 액션 필요:
    • 운영 환경 reverse proxy 구성 확인 (ELB hop 수 등)
    • TRUST_PROXY_HOPS ENV 추가 후 재배포

Test plan

  • common/utils/crypto.spec / url-query.spec / error.spec — 이동 후 통과
  • common/utils/http-meta.spec — 신규 tryClientIp / tryUserAgent 8 케이스 추가, 모두 통과
  • features/auth/services/token.service.specutils/crypto + utils/http-meta 교체 후 통과
  • features/auth/services/seller-credential.service.specutils/http-meta 교체 후 통과
  • global/filters/global-exception.filter.spec / graphql-exception.filter.specutils/error import 갱신 후 통과
  • pre-push gate (yarn validate) 로컬 통과 (1199 테스트)
  • CI 통과 확인
  • 운영 배포 시 TRUST_PROXY_HOPS 환경변수 설정 (별도 운영 작업)

P1-4 본 작업과 함께, IP/UA 추출 로직이 두 곳으로 분기되어 운영에서
audit log / refresh session 의 IP 가 proxy IP 로 기록되던 문제도 함께 정리.

common 경계 룰 정리:
- crypto.helper.ts → utils/crypto.ts (순수 함수, NestJS DI 없음)
- url-query.helper.ts → utils/url-query.ts (순수 함수)
- error.helper.ts → utils/error.ts (HttpException 클래스만 사용, DI 매개변수 없음)
- helpers/ 는 ConfigService 등 NestJS 서비스를 매개변수로 받는 경우만 잔존
  (현재 config.helper.ts 만 해당)

IP/UA 추출 단일화:
- 기존 2 구현 분기 (utils/http-meta 의 정밀 + auth helper 의 naive) → utils/http-meta 단일
- utils/http-meta.ts 에 tryClientIp / tryUserAgent 추가 (DB persistence 용, undefined fallback)
- 기존 clientIpOf / userAgentOf 는 try* 위에 'Unknown *' fallback 적용 (로깅용)
- token.service / seller-credential.service: auth-request-meta 의 naive getIp/getUserAgent
  → utils/http-meta 의 tryClientIp/tryUserAgent 로 교체. audit log / refresh session 의 IP
  가 X-Forwarded-For 기반으로 정확하게 기록되도록 정상화.
- src/features/auth/helpers/auth-request-meta.helper.ts 삭제 (callsite 0)

trust proxy 설정:
- main.ts 에 env-based 적용 (TRUST_PROXY_HOPS).
- 미설정 / 0: 비활성 (현 동작 그대로).
- 운영에서 실제 reverse proxy hop 수 (ELB=1, ELB+CloudFront=2 등) 와 맞춰 설정해야
  X-Forwarded-For 가 정상 신뢰됨. 잘못 설정 시 IP spoofing 위험이므로 인프라 검증 필요.

기타:
- TokenService 의 sha256Hex / generateRefreshToken 인라인 구현 → utils/crypto 호출로 교체.
  외부 API (TokenService.sha256Hex public method) 는 유지, 내부만 delegation.

부수 효과:
- 신규 코드는 utils/ 에서 import (helpers/ → utils/ 경로 변경)
- audit log / refresh session 의 ip_address 가 proxy 환경에서 실제 client IP 로 기록
  (TRUST_PROXY_HOPS 활성화 시)
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fee32151-7c8b-4802-acc6-6345e41b8695

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/common-boundary-and-ip-extraction

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions
Copy link
Copy Markdown

Coverage report

St.
Category Percentage Covered / Total
🟢 Statements 97.33% 3541/3638
🟢 Branches 93.68% 1126/1202
🟢 Functions 93.62% 646/690
🟢 Lines 97.56% 3241/3322

Test suite run success

1199 tests passing in 143 suites.

Report generated by 🧪jest coverage report action from d474525

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant