Skip to content

[FEAT/REFACTOR] 회원가입·로그인 구현, 사용자 도메인 구조 개선 및 미사용 모듈 제거#6

Merged
Takch02 merged 19 commits intomainfrom
feat/sign
Apr 28, 2026
Merged

[FEAT/REFACTOR] 회원가입·로그인 구현, 사용자 도메인 구조 개선 및 미사용 모듈 제거#6
Takch02 merged 19 commits intomainfrom
feat/sign

Conversation

@Takch02
Copy link
Copy Markdown
Contributor

@Takch02 Takch02 commented Apr 28, 2026

개요 #4

buyer/seller 회원가입, 로그인, 로그아웃 기능을 구현하고 관련 보안 이슈를 수정합니다.

주요 변경사항

기능 구현

  • buyer/seller 회원가입 API 구현 (XRPL 지갑 자동 생성 및 백그라운드 활성화)
  • Redis 세션 기반 로그인/로그아웃 구현

리팩터링

  • buyer/company 스키마를 users 도메인으로 통합 (discriminator 패턴 적용)
  • buyer 모듈에서 직접 생성/수정/삭제 제거 — 회원가입으로 대체
  • 미사용 모듈 제거 (admin, insights, consultants)

버그 수정

  • CompanyDocument / BuyerDocument에 Document 믹스인 누락 및 _id: any 타입 약화 수정
  • aggregate 파이프라인에 discriminator 필터(type: "seller") 누락 → Buyer 문서가 검색 결과에 포함되던 문제 수정

보안

  • wallet.seed 필드 select: false 적용 — API 응답에 시드 노출 방지
  • ENCRYPTION_KEY 프로덕션 환경 미설정 시 명시적 예외 처리
  • 세션 쿠키 sameSite: none / secure: true 적용
  • 로그아웃 시 connect.sid 쿠키 명시적 제거

기타

  • 회원가입 비동기 활성화 오류 핸들링 추가 (void + .catch)
  • websiteUrl URL 형식 및 길이 유효성 검사 강화
  • XRPL 중복 WebSocket 연결 방지
  • e2e 테스트 타임아웃 명시 (60s)

Summary by CodeRabbit

릴리스 노트

  • 새 기능

    • 구매자/판매자 등록·로그인 API 추가 (세션 기반 인증)
    • Redis 세션 저장 및 세션 만료 관리 도입
    • 가입 시 XRPL 지갑 자동 생성·자금 지원 및 암호화 저장
  • 제거됨

    • 관리자 대시보드/분석/감사 API 및 관련 관리자 엔드포인트 삭제
    • 컨설턴트 요청 기능 및 회사 이미지 업로드 API 제거
    • 일부 구매자/회사 CRUD 엔드포인트 축소
  • 개선

    • 사용자/회사 데이터 모델에 회사소개·상품소개·웹사이트 필드 추가
    • 매칭 로직 업데이트(요구·수출 항목 기반)

@Takch02 Takch02 changed the title [FEAT/REFACTOR] 회원가입·로그인 구현, 사용자 도메인 구조 개선 및 미사용 모듈 제거 #4 [FEAT/REFACTOR] 회원가입·로그인 구현, 사용자 도메인 구조 개선 및 미사용 모듈 제거 Apr 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Warning

Rate limit exceeded

@Takch02 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 20 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f2b447fc-b2fb-4af1-be65-d7db21db5bf2

📥 Commits

Reviewing files that changed from the base of the PR and between ea3f1ea and 04dc6e0.

📒 Files selected for processing (3)
  • src/common/guards/session.guard.ts
  • src/config/env.config.ts
  • src/modules/payments/xrpl.service.ts
📝 Walkthrough

Walkthrough

인증(회원가입/로그인) 및 XRPL 지갑/암호화 기능과 Redis 세션이 추가되고, Buyer/Company 스키마가 users 모듈로 통합되며 Admin/Insights/Consultants 관련 모듈·컨트롤러·서비스·테스트가 제거됩니다. 여러 컨트롤러/서비스/스키마 경로와 테스트가 대규모로 변경되었습니다.

Changes

Cohort / File(s) Summary
인증(Auth) 및 관련 DTO/테스트
src/modules/auth/... (auth.service.ts, auth.controller.ts, auth.module.ts, dto/*.ts, *.spec.ts)
새 AuthModule 추가: 판매자/구매자 등록, 로그인/로그아웃, bcrypt 해싱, XRPL 지갑 생성·암호화, 30분 간격 재시도 스케줄 및 관련 단위 테스트 추가.
XRPL 및 결제 지원
src/modules/payments/xrpl.service.ts, test/xrpl.e2e-spec.ts
XrplService에 지갑 생성, 계정 펀딩, AES-256-GCM 암호화/복호화, 연결 관리 변경 및 E2E 테스트 추가.
세션/인증 보조
src/main.ts, src/common/decorators/current-user.decorator.ts, src/common/guards/session.guard.ts, src/types/express-session.d.ts, docker-compose.yml, package.json
express-session + RedisStore 구성, Session 타입 정의, CurrentUser 데코레이터와 SessionGuard 추가, docker-compose에 redis 서비스 및 package.json에 세션/redis/schedule 등 의존성 추가.
사용자 스키마 통합 (users 모듈)
src/modules/users/schemas/*.ts, src/modules/users/users.module.ts
User 기본 스키마 추가 및 Mongoose discriminator로 Buyer/Company 하위 타입 등록; 기존 buyers/companies 스키마·경로 대비 재배치.
기존 buyers/companies/partners/matches 변경
src/modules/buyers/*, src/modules/companies/*, src/modules/partners/*, src/modules/matches/*
CRUD(create/update/remove) 엔드포인트·메서드 제거, 스키마 임포트 경로 users로 재지향, 투영 필드 및 필드명(exportItems, companyIntroduction, productIntroduction 등) 업데이트.
Admin/Insights/Consultants 제거
src/modules/admin/*, src/modules/insights/*, src/modules/consultants/*
관련 모듈, 컨트롤러, 서비스, DTO, 스키마 및 다수의 테스트 파일을 완전히 삭제.
회사 이미지 기능 제거
src/modules/companies/company-images.*
CompanyImagesController 및 CompanyImagesService와 관련 테스트 삭제.
환경·구성·도커·검토 설정
.env.example, .gitignore, docker-compose.yml, .coderabbit.yaml, src/config/env.config.ts, src/app.module.ts
.env.example 내용 삭제, .env.test 추가 무시, redis volume 추가, env 구성 확장(Redis/session/security/embeddings/OpenAI 등), AppModule에서 Config envFilePath 순서 조정, CodeRabbit 검토 설정 변경.
테스트 구성 변경
test/jest-e2e.json, 여러 *.spec.ts 추가/삭제
E2E jest 설정 변경(경로/타임아웃), XRPL E2E 및 Auth/Service 단위테스트 대규모 추가/삭제.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant AuthController
    participant AuthService
    participant XrplService
    participant Database
    participant Scheduler

    Client->>AuthController: POST /auth/register/seller (DTO)
    AuthController->>AuthService: registerSeller(dto)
    AuthService->>Database: check User.exists(email)
    Database-->>AuthService: available
    AuthService->>XrplService: generateWallet()
    XrplService-->>AuthService: wallet {address, seed, publicKey}
    AuthService->>XrplService: encrypt(seed)
    XrplService-->>AuthService: encryptedSeed
    AuthService->>Database: save user/company (PENDING_ACTIVATION)
    AuthService-->>AuthController: respond created

    par Async funding
        AuthService->>XrplService: fundAccount(wallet)
        XrplService->>XrplService: ensure connected
        alt success
            XrplService-->>AuthService: ok
            AuthService->>Database: update status ACTIVE
        else failure
            XrplService-->>AuthService: error
            AuthService->>Database: update status FAILED_ACTIVATION
        end
    end

    Scheduler->>AuthService: retryFailedActivations()
    AuthService->>Database: find FAILED_ACTIVATION docs
    Database-->>AuthService: [docs]
    AuthService->>XrplService: decrypt(encryptedSeed)
    XrplService-->>AuthService: seed
    AuthService->>XrplService: fundAccount(wallet)
    XrplService-->>AuthService: result
    AuthService->>Database: update status accordingly

    Client->>AuthController: POST /auth/login (email,password)
    AuthController->>AuthService: login(dto)
    AuthService->>Database: find user (include password)
    Database-->>AuthService: user with hashed password
    AuthService->>AuthService: bcrypt.compare
    alt match
        AuthService-->>AuthController: user info
        AuthController->>Client: set session {userId,type}, respond 200
    else mismatch
        AuthService-->>AuthController: UnauthorizedException
        AuthController-->>Client: 401
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

🐰 지갑은 깡총, 키는 안전히 감추고,
세션은 붉은 실로 살며시 묶었네.
스키마는 모여 하나가 되고,
모듈은 가벼워져 길을 열었구나.
춤추며 배포를 축하하노라! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 주요 변경 사항인 회원가입·로그인 기능 구현, 사용자 도메인 구조 개선, 미사용 모듈 제거를 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sign

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/modules/matches/matches.service.ts (1)

50-70: ⚠️ Potential issue | 🟠 Major

필드 전환 과도기 호환성이 빠져 매칭 점수가 왜곡될 수 있습니다.

현재는 company.exportItems만 사용합니다. 그런데 기존 데이터/테스트 픽스처(src/modules/matches/matches.service.spec.ts Line 32-41)는 offerings를 사용하고 있어, 백필 완료 전까지 needs 매칭이 과소평가될 수 있습니다.

수정 예시 (과도기 호환)
-  const companyExportItems = toSet(company.exportItems);
+  const companyExportItems = toSet(
+    Array.isArray(company.exportItems) && company.exportItems.length > 0
+      ? company.exportItems
+      : company.offerings,
+  );
@@
-    reasons.push(`needs-exportItems overlap x${needMatches}`);
+    reasons.push(`needs-exportItems overlap x${needMatches}`);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/matches/matches.service.ts` around lines 50 - 70, The matching
logic only uses company.exportItems (variable companyExportItems) when computing
needMatches against buyerNeeds via intersectCount, but legacy fixtures/tests use
company.offerings so needs matches are undercounted; update the code that builds
companyExportItems (or the place where intersectCount is called) to include both
sources (exportItems and offerings) by normalizing/merging them into a single
set before calling intersectCount (reference symbols: companyExportItems,
company.exportItems, company.offerings, intersectCount, buyerNeeds) so the score
and reasons correctly account for both old and new fields during the migration.
src/modules/buyers/buyers.service.ts (1)

27-30: ⚠️ Potential issue | 🟡 Minor

profileText 필드는 스키마에 존재하지 않음

User 및 Buyer 스키마에 profileText 필드가 정의되어 있지 않습니다. 이 검색 조건은 어떤 문서도 매칭하지 않습니다. companyIntroduction 또는 productIntroduction 필드를 사용해야 합니다.

수정 제안
      filter.$or = [
        { name: { $regex: q, $options: "i" } },
-       { profileText: { $regex: q, $options: "i" } },
+       { companyIntroduction: { $regex: q, $options: "i" } },
+       { productIntroduction: { $regex: q, $options: "i" } },
      ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/buyers/buyers.service.ts` around lines 27 - 30, The search filter
currently uses a non-existent field profileText in the filter.$or clause inside
buyers.service.ts, so replace that clause to search actual schema fields; update
the $or array to use companyIntroduction and productIntroduction (e.g., {
companyIntroduction: { $regex: q, $options: "i" } } and { productIntroduction: {
$regex: q, $options: "i" } }) alongside the existing name regex so the
filter.$or (and any function that builds it) matches real Buyer/User schema
fields.
src/modules/companies/dto/create-company.dto.ts (1)

43-48: ⚠️ Potential issue | 🟠 Major

CreateCompanyDto의 optionality가 스키마와 맞지 않습니다.

exportItems, companyIntroduction, productIntroduction는 스키마에서 required인데 DTO에서는 optional이라 요청이 validator를 통과한 뒤 Mongoose 단계에서야 실패할 수 있습니다. 생성 DTO라면 여기서도 필수로 막아 400 응답으로 일관되게 처리하는 편이 낫습니다.

Also applies to: 57-67

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/companies/dto/create-company.dto.ts` around lines 43 - 48, The
DTO marks exportItems, companyIntroduction, and productIntroduction as optional
but the Mongoose schema requires them; update CreateCompanyDto to make these
properties required by removing `@IsOptional`() and ensuring their validation
decorators reflect required fields (keep `@IsArray/`@IsString/@IsString as
appropriate and keep `@Transform` on exportItems), so validation fails early with
a 400 instead of deferring to Mongoose; specifically modify the exportItems,
companyIntroduction, and productIntroduction properties in CreateCompanyDto to
be non-optional and validated accordingly.
🧹 Nitpick comments (4)
src/main.ts (2)

24-30: Redis 설정 접근 방식 불일치.

env.config.tsredis.host, redis.port, redis.password 설정이 정의되어 있지만, 여기서는 process.env를 직접 읽고 있습니다. ConfigService를 통해 일관되게 접근하는 것이 좋습니다.

♻️ ConfigService 사용 제안
   const redisClient = createClient({
     socket: {
-      host: process.env.REDIS_HOST || "localhost",
-      port: Number(process.env.REDIS_PORT) || 6379,
+      host: configService.get<string>("redis.host") || "localhost",
+      port: configService.get<number>("redis.port") || 6379,
     },
-    password: process.env.REDIS_PASSWORD || "",
+    password: configService.get<string>("redis.password") || undefined,
   });

참고: password가 빈 문자열일 경우 일부 Redis 설정에서 인증 오류가 발생할 수 있으므로, 비밀번호가 없을 때는 undefined를 전달하는 것이 안전합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main.ts` around lines 24 - 30, The Redis client is created by reading
process.env directly; switch to using the ConfigService (or the existing
env.config.ts values) to keep configuration consistent: replace direct env
access in the createClient call (where redisClient is created) with calls to
ConfigService.get('redis.host'), ConfigService.get('redis.port'), and
ConfigService.get('redis.password') (or the corresponding keys from
env.config.ts), and ensure you pass undefined for password when the config value
is an empty string so an empty password is not sent to createClient.

40-45: 로컬 개발 환경에서 secure: true 주의.

secure: true는 HTTPS 연결에서만 쿠키가 전송되므로, 로컬 HTTP 개발 환경에서는 세션이 동작하지 않습니다. 환경에 따라 조건부로 설정하는 것이 좋습니다.

♻️ 환경별 조건부 설정 제안
+  const isProduction = configService.get<string>("NODE_ENV") === "production";
+
   app.use(
     session({
       store: new RedisStore({ client: redisClient, ttl: sessionTtl }),
       secret: sessionSecret,
       resave: false,
       saveUninitialized: false,
       cookie: {
         httpOnly: true,
-        secure: true,
-        sameSite: "none",
+        secure: isProduction,
+        sameSite: isProduction ? "none" : "lax",
         maxAge: sessionTtl * 1000,
       },
     }),
   );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main.ts` around lines 40 - 45, The cookie configuration currently forces
secure: true which breaks sessions on local HTTP; update the session cookie
object (the cookie: { ... } in your session setup where sessionTtl is used) to
set secure conditionally (e.g. secure = process.env.NODE_ENV === 'production' or
an isProduction flag) and, if your app is behind a proxy in production, ensure
the Express app trust proxy setting is enabled (e.g. app.set('trust proxy', 1))
so secure cookies work correctly; keep maxAge and sameSite behavior but only
force secure in production.
src/modules/users/schemas/company.schema.ts (1)

18-19: location 서브도큐먼트의 타입 안전성 개선 권장

location 필드의 기본값이 빈 객체 {}이지만, TypeScript 타입은 city, state, country가 모두 필수 string으로 정의되어 있습니다. 실제 런타임에서는 이 필드들이 undefined일 수 있어 타입 불일치가 발생할 수 있습니다.

♻️ 타입 안전성을 위한 수정 제안
-  `@Prop`({ type: { city: String, state: String, country: String }, default: {} })
-  location: { city: string; state: string; country: string };
+  `@Prop`({ type: { city: String, state: String, country: String }, default: {} })
+  location?: { city?: string; state?: string; country?: string };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/users/schemas/company.schema.ts` around lines 18 - 19, The Prop
for 'location' uses default: {} but TypeScript declares required
city/state/country strings, causing a type mismatch; update the schema so
runtime defaults match the TS type by either (A) making the TS type
optional/partial (e.g. change the property to location?: { city?: string;
state?: string; country?: string } and/or mark fields optional) or (B) provide
concrete defaults for each subfield via the decorator (e.g. set default: { city:
'', state: '', country: '' } or use per-field defaults) so that the '@Prop({
type: { city: String, state: String, country: String }, default: {} })' and the
'location' property are consistent.
src/modules/auth/auth.service.spec.ts (1)

167-174: DTO 타입 캐스팅 확인 필요

SELLER_DTO as any 타입 캐스팅이 사용되고 있습니다. 실제 RegisterSellerDto에 필수 필드가 누락된 것인지, 아니면 테스트 목적상 의도적인 것인지 확인이 필요합니다.

테스트 DTO가 실제 DTO 타입과 일치하도록 수정하거나, 의도적인 캐스팅이라면 주석으로 명시하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/auth/auth.service.spec.ts` around lines 167 - 174, The test is
casting SELLER_DTO as any when calling service.registerSeller which hides
missing required fields from the real RegisterSellerDto; update the test to
supply a SELLER_DTO that matches the RegisterSellerDto shape (add any missing
required properties) and remove the unsafe "as any" cast, or if the cast is
intentional for a negative/partial test, replace it with an explicit comment
above the test explaining why the DTO is partial and keep assertions around
userModel.exists and companyModel._instance.save unchanged; ensure the test
calls service.registerSeller with a correctly-typed DTO so TypeScript will catch
mismatches.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.coderabbit.yaml:
- Line 7: The config key is wrong: replace the singular auto_review.draft with
the schema-correct plural auto_review.drafts; open the .coderabbit.yaml and
rename the property from "draft" to "drafts" (keeping the boolean value true) so
the validator recognizes it and draft PRs are included by the auto_review logic.
- Around line 9-12: The YAML contains an unsupported field
reviews.review_instructions; remove or relocate it by deleting the
review_instructions node under reviews and adding its text under a top-level
tone_instructions key instead (ensure you preserve the multi-line string value);
update any schema/validation logic that expects reviews to only contain allowed
child fields so the file validates correctly and consumers read the new
tone_instructions value.

In `@src/app.module.ts`:
- Line 17: 현재 app.module.ts의 envFilePath 설정이 process.env.NODE_ENV ||
"development"로 기본값을 "development"로 두어 NODE_ENV 미설정 시 `.env.development`가 우선
로드됩니다; 수정하려면 envFilePath 설정을 조건문으로 바꿔 process.env.NODE_ENV가 정의된 경우에만
[`.env.${process.env.NODE_ENV}`, '.env']를 사용하고, 미정의일 때는 단독으로 ['.env']만 사용하도록
변경하여 잘못된 운영 설정 로드를 방지하세요; 관련 위치는 app.module.ts의 envFilePath 배열 설정을 수정하면 됩니다.

In `@src/common/decorators/current-user.decorator.ts`:
- Around line 10-12: current-user.decorator.ts currently assumes req.session
exists (ctx.switchToHttp().getRequest()) and returns { userId:
req.session.userId, type: req.session.type }; update the decorator to first
check req.session (and req.session.userId) and if missing throw an
UnauthorizedException instead of allowing a TypeError/500; otherwise return the
same object so callers of the decorator receive { userId, type } as before.

In `@src/common/guards/session.guard.ts`:
- Around line 12-14: The guard currently only checks req.session?.userId and
allows sessions with a missing session.type; update the validation in the
session guard to require both req.session?.userId and req.session?.type (or
equivalent role/type field) before allowing access and throw the same
UnauthorizedException("Login required") when either is missing so downstream
authorization logic has a stable authenticated session shape.

In `@src/config/env.config.ts`:
- Around line 72-76: The redis.port value is left as a string from process.env
and should be converted to a number like the other numeric env vars; update the
redis.port assignment in env.config.ts (the redis object) to use
Number(process.env.REDIS_PORT) with a fallback of 6379 so the final type is a
number (e.g., replace the current process.env.REDIS_PORT || 6379 with
Number(process.env.REDIS_PORT) || 6379).
- Around line 5-8: The default MongoDB URI in mongodb.uri is missing the
protocol prefix; update the default value used in src config (mongodb.uri in
env.config.ts) from "localhost:27017" to include the MongoDB protocol (e.g.,
"mongodb://localhost:27017") so any fallback connection string is valid when
process.env.MONGODB_URI is unset.

In `@src/main.ts`:
- Around line 20-21: Remove the non-null assertions on sessionSecret and
sessionTtl returned by configService.get and add explicit validation: call
configService.get for "session.secret" and "session.ttl", check if either is
undefined/null (or invalid type), and if so throw a clear startup Error
indicating which config key(s) are missing; otherwise continue using the
validated values. Reference the variables sessionSecret and sessionTtl and the
call site using configService.get to implement the guard and descriptive error.

In `@src/modules/auth/auth.controller.spec.ts`:
- Around line 122-127: The logout test fails because it doesn't pass a mocked
response object into controller.logout and asserts the wrong success message;
update the test to call controller.logout with both req and a mocked res that
has clearCookie as a jest.fn and ensure req.session.destroy is a jest.fn calling
its callback, then assert that req.session.destroy and res.clearCookie have been
called and that the returned value (or response behavior) matches the
controller.logout implementation (use the actual success message returned by
logout).

In `@src/modules/auth/auth.controller.ts`:
- Around line 24-27: Update the Swagger ApiResponse for
duplicate-email/validation failures in auth.controller.ts to match the actual
exception: change the status code from 400 to 409 for the responses documenting
ConflictException thrown by registerSeller() and registerBuyer(); locate the
`@ApiResponse` blocks associated with registerSeller and registerBuyer and replace
the 400 status (and adjust description text if needed) so the documented status
code (409) matches the service behavior.
- Around line 62-71: 로그아웃 핸들러 logout(`@Req`() req, `@Res`({ passthrough: true })
res: Response)에서 req.session.destroy 콜백 후 res가 undefined일 경우
res.clearCookie("connect.sid")에서 TypeError가 발생하므로, 콜백 내부에서 res가 존재하고
clearCookie가 함수인지 안전검사한 뒤에만 호출하도록 방어 코드를 추가하고(예: if (res && typeof
res.clearCookie === "function") ...), 세션 파기 실패와 성공 경로 모두에서 적절히 resolve/reject
하도록 유지하여 직접 호출하는 테스트나 호출부에서 res를 넘기지 않아도 안전하게 동작하도록 수정하세요.
- Around line 51-55: In the login method of AuthController (async login in
src/modules/auth/auth.controller.ts) replace the direct writes to req.session
with a session regeneration flow: after successful authentication call
req.session.regenerate (or await a promisified regenerate) to create a new
session, then set req.session.userId = user._id.toString() and req.session.type
= user.type, and only then return the success response; ensure you handle errors
from regenerate (reject/throw or return a 500) so failures don’t leave the user
in an inconsistent state.

In `@src/modules/auth/auth.service.ts`:
- Around line 174-187: The queries that populate failedSellers and failedBuyers
use .lean() but do not include the non-selected wallet.seed field, so retryOne
(which calls this.xrplService.decrypt(doc.wallet.seed)) receives undefined;
update the two queries (this.companyModel.find and this.buyerModel.find) to
explicitly include the hidden field by chaining .select("+wallet.seed") before
.lean(), and add a small defensive check inside retryOne (e.g., verify
doc.wallet?.seed exists) to skip/log and avoid calling this.xrplService.decrypt
when seed is missing.

In `@src/modules/auth/dto/register.dto.ts`:
- Around line 114-117: RegisterSellerDto's websiteUrl property only has
`@IsString`() so invalid URLs and overly long values can be saved; update the
websiteUrl field to match RegisterBuyerDto.websiteUrl by replacing/augmenting
`@IsString`() with the same URL and length validators used in RegisterBuyerDto
(e.g., add `@IsUrl`(...) with the same protocols/options and `@MaxLength`(...) used
there) so protocol and max-length checks are consistent across buyer and seller
DTOs.

In `@src/modules/partners/partners.service.ts`:
- Around line 385-387: The code maps the source body to companyIntroduction
(location/companyIntroduction/websiteUrl) but the country keyword re-scoring
logic still reads item.profileText, causing the rescoring to fail; update the
code so the rescoring uses the same field (use item.content or
companyIntroduction) instead of item.profileText — i.e., either set
item.profileText = item.content before the country-keyword logic or change the
rescoring references from item.profileText to item.content/companyIntroduction;
apply the same fix for the other occurrence referenced (the block around lines
393-401).
- Line 179: The code uses process.env.ATLAS_VECTOR_INDEX directly for the vector
index (the index: property in the vector search options in partners.service.ts),
causing a runtime error if the env var is missing; change it to use a safe
fallback like process.env.ATLAS_VECTOR_INDEX || "vector_index" (same pattern as
matches.service.ts) so the vector search still has a default index value when
the environment variable is unset.

In `@src/modules/payments/xrpl.service.ts`:
- Around line 63-72: The connect() method can be called concurrently (e.g., from
retryFailedActivations() when multiple fundAccount() calls run in parallel)
which can create duplicate websocket connections; fix by introducing an
in-flight connect promise (e.g., this.connectPromise) inside the XRPL service so
connect() first returns/awaits an existing this.connectPromise if present,
otherwise sets this.connectPromise = (async () => { create client if missing,
await client.connect(), log, return client })(); ensure you clear or reset
this.connectPromise on success or failure (and propagate errors) so subsequent
calls can retry; update references to this.client/isConnected() accordingly to
rely on the serialized connect() behavior.

In `@test/xrpl.e2e-spec.ts`:
- Around line 23-37: The test currently depends on the live XRPL testnet because
beforeAll builds a Test.createTestingModule with ConfigModule.forRoot providing
real xrpl.wsUrl and XrplService, which makes CI flaky; modify the test to avoid
external network calls by making it opt-in or mocked: either gate the beforeAll
with an environment flag (e.g., process.env.RUN_XRPL_E2E) and call
jest.skip/return early when not set, or replace the real XrplService with a
mocked provider in the Test.createTestingModule (provide a mock for XrplService
or override the xrpl.wsUrl to a local stub) so CI runs stable; apply same change
to the other E2E blocks referenced (lines ~92-122) that construct the module or
call live faucet.

---

Outside diff comments:
In `@src/modules/buyers/buyers.service.ts`:
- Around line 27-30: The search filter currently uses a non-existent field
profileText in the filter.$or clause inside buyers.service.ts, so replace that
clause to search actual schema fields; update the $or array to use
companyIntroduction and productIntroduction (e.g., { companyIntroduction: {
$regex: q, $options: "i" } } and { productIntroduction: { $regex: q, $options:
"i" } }) alongside the existing name regex so the filter.$or (and any function
that builds it) matches real Buyer/User schema fields.

In `@src/modules/companies/dto/create-company.dto.ts`:
- Around line 43-48: The DTO marks exportItems, companyIntroduction, and
productIntroduction as optional but the Mongoose schema requires them; update
CreateCompanyDto to make these properties required by removing `@IsOptional`() and
ensuring their validation decorators reflect required fields (keep
`@IsArray/`@IsString/@IsString as appropriate and keep `@Transform` on exportItems),
so validation fails early with a 400 instead of deferring to Mongoose;
specifically modify the exportItems, companyIntroduction, and
productIntroduction properties in CreateCompanyDto to be non-optional and
validated accordingly.

In `@src/modules/matches/matches.service.ts`:
- Around line 50-70: The matching logic only uses company.exportItems (variable
companyExportItems) when computing needMatches against buyerNeeds via
intersectCount, but legacy fixtures/tests use company.offerings so needs matches
are undercounted; update the code that builds companyExportItems (or the place
where intersectCount is called) to include both sources (exportItems and
offerings) by normalizing/merging them into a single set before calling
intersectCount (reference symbols: companyExportItems, company.exportItems,
company.offerings, intersectCount, buyerNeeds) so the score and reasons
correctly account for both old and new fields during the migration.

---

Nitpick comments:
In `@src/main.ts`:
- Around line 24-30: The Redis client is created by reading process.env
directly; switch to using the ConfigService (or the existing env.config.ts
values) to keep configuration consistent: replace direct env access in the
createClient call (where redisClient is created) with calls to
ConfigService.get('redis.host'), ConfigService.get('redis.port'), and
ConfigService.get('redis.password') (or the corresponding keys from
env.config.ts), and ensure you pass undefined for password when the config value
is an empty string so an empty password is not sent to createClient.
- Around line 40-45: The cookie configuration currently forces secure: true
which breaks sessions on local HTTP; update the session cookie object (the
cookie: { ... } in your session setup where sessionTtl is used) to set secure
conditionally (e.g. secure = process.env.NODE_ENV === 'production' or an
isProduction flag) and, if your app is behind a proxy in production, ensure the
Express app trust proxy setting is enabled (e.g. app.set('trust proxy', 1)) so
secure cookies work correctly; keep maxAge and sameSite behavior but only force
secure in production.

In `@src/modules/auth/auth.service.spec.ts`:
- Around line 167-174: The test is casting SELLER_DTO as any when calling
service.registerSeller which hides missing required fields from the real
RegisterSellerDto; update the test to supply a SELLER_DTO that matches the
RegisterSellerDto shape (add any missing required properties) and remove the
unsafe "as any" cast, or if the cast is intentional for a negative/partial test,
replace it with an explicit comment above the test explaining why the DTO is
partial and keep assertions around userModel.exists and
companyModel._instance.save unchanged; ensure the test calls
service.registerSeller with a correctly-typed DTO so TypeScript will catch
mismatches.

In `@src/modules/users/schemas/company.schema.ts`:
- Around line 18-19: The Prop for 'location' uses default: {} but TypeScript
declares required city/state/country strings, causing a type mismatch; update
the schema so runtime defaults match the TS type by either (A) making the TS
type optional/partial (e.g. change the property to location?: { city?: string;
state?: string; country?: string } and/or mark fields optional) or (B) provide
concrete defaults for each subfield via the decorator (e.g. set default: { city:
'', state: '', country: '' } or use per-field defaults) so that the '@Prop({
type: { city: String, state: String, country: String }, default: {} })' and the
'location' property are consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2032ce31-c2cc-4d7e-a795-b39b71cfb497

📥 Commits

Reviewing files that changed from the base of the PR and between 00a7032 and 352745f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (74)
  • .coderabbit.yaml
  • .env.example
  • .gitignore
  • docker-compose.yml
  • package.json
  • src/app.module.ts
  • src/common/decorators/current-user.decorator.ts
  • src/common/guards/session.guard.ts
  • src/common/schemas/wallet-info.schema.ts
  • src/config/env.config.ts
  • src/main.ts
  • src/modules/admin/admin.controller.spec.ts
  • src/modules/admin/admin.controller.ts
  • src/modules/admin/admin.module.ts
  • src/modules/admin/admin.service.spec.ts
  • src/modules/admin/admin.service.ts
  • src/modules/admin/dto/audit-logs-query.dto.ts
  • src/modules/admin/dto/list-payments-query.dto.ts
  • src/modules/admin/dto/match-logs-query.dto.ts
  • src/modules/admin/dto/payment-stats-query.dto.ts
  • src/modules/admin/guards/admin-token.guard.spec.ts
  • src/modules/admin/guards/admin-token.guard.ts
  • src/modules/admin/schemas/audit-log.schema.ts
  • src/modules/auth/auth.controller.spec.ts
  • src/modules/auth/auth.controller.ts
  • src/modules/auth/auth.module.ts
  • src/modules/auth/auth.service.spec.ts
  • src/modules/auth/auth.service.ts
  • src/modules/auth/dto/login.dto.ts
  • src/modules/auth/dto/register.dto.ts
  • src/modules/buyers/buyers.controller.spec.ts
  • src/modules/buyers/buyers.controller.ts
  • src/modules/buyers/buyers.module.ts
  • src/modules/buyers/buyers.service.spec.ts
  • src/modules/buyers/buyers.service.ts
  • src/modules/buyers/dto/create-buyer.dto.ts
  • src/modules/buyers/dto/update-buyer.dto.ts
  • src/modules/buyers/schemas/buyer.schema.ts
  • src/modules/companies/companies.module.ts
  • src/modules/companies/companies.service.spec.ts
  • src/modules/companies/companies.service.ts
  • src/modules/companies/company-images.controller.spec.ts
  • src/modules/companies/company-images.controller.ts
  • src/modules/companies/company-images.service.spec.ts
  • src/modules/companies/company-images.service.ts
  • src/modules/companies/dto/create-company.dto.ts
  • src/modules/companies/dto/upload-image.dto.ts
  • src/modules/companies/schemas/company.schema.ts
  • src/modules/consultants/consultants.controller.spec.ts
  • src/modules/consultants/consultants.controller.ts
  • src/modules/consultants/consultants.module.ts
  • src/modules/consultants/consultants.service.spec.ts
  • src/modules/consultants/consultants.service.ts
  • src/modules/consultants/dto/create-consultant-request.dto.ts
  • src/modules/consultants/schemas/consultant-request.schema.ts
  • src/modules/consultations/consultations.service.ts
  • src/modules/insights/insights.controller.spec.ts
  • src/modules/insights/insights.controller.ts
  • src/modules/insights/insights.module.ts
  • src/modules/insights/insights.service.spec.ts
  • src/modules/insights/insights.service.ts
  • src/modules/matches/matches.service.spec.ts
  • src/modules/matches/matches.service.ts
  • src/modules/partners/partners.module.ts
  • src/modules/partners/partners.service.spec.ts
  • src/modules/partners/partners.service.ts
  • src/modules/payments/xrpl.service.ts
  • src/modules/users/schemas/buyer.schema.ts
  • src/modules/users/schemas/company.schema.ts
  • src/modules/users/schemas/user.schema.ts
  • src/modules/users/users.module.ts
  • src/types/express-session.d.ts
  • test/jest-e2e.json
  • test/xrpl.e2e-spec.ts
💤 Files with no reviewable changes (34)
  • src/modules/admin/guards/admin-token.guard.ts
  • src/modules/buyers/dto/update-buyer.dto.ts
  • src/modules/companies/dto/upload-image.dto.ts
  • src/modules/admin/dto/audit-logs-query.dto.ts
  • .env.example
  • src/modules/insights/insights.controller.ts
  • src/modules/consultants/consultants.module.ts
  • src/modules/admin/admin.controller.spec.ts
  • src/modules/admin/schemas/audit-log.schema.ts
  • src/modules/admin/dto/match-logs-query.dto.ts
  • src/modules/buyers/schemas/buyer.schema.ts
  • src/modules/admin/dto/payment-stats-query.dto.ts
  • src/modules/consultants/consultants.service.spec.ts
  • src/modules/companies/company-images.controller.ts
  • src/modules/buyers/dto/create-buyer.dto.ts
  • src/modules/admin/admin.module.ts
  • src/modules/companies/company-images.controller.spec.ts
  • src/modules/consultants/consultants.controller.ts
  • src/modules/insights/insights.controller.spec.ts
  • src/modules/consultants/dto/create-consultant-request.dto.ts
  • src/modules/admin/dto/list-payments-query.dto.ts
  • src/modules/admin/guards/admin-token.guard.spec.ts
  • src/modules/companies/schemas/company.schema.ts
  • src/modules/consultants/consultants.controller.spec.ts
  • src/modules/admin/admin.service.spec.ts
  • src/modules/consultants/consultants.service.ts
  • src/modules/admin/admin.controller.ts
  • src/modules/companies/company-images.service.ts
  • src/modules/companies/company-images.service.spec.ts
  • src/modules/insights/insights.service.spec.ts
  • src/modules/insights/insights.service.ts
  • src/modules/admin/admin.service.ts
  • src/modules/consultants/schemas/consultant-request.schema.ts
  • src/modules/insights/insights.module.ts

Comment thread .coderabbit.yaml Outdated
Comment thread .coderabbit.yaml Outdated
Comment thread src/app.module.ts
Comment thread src/common/decorators/current-user.decorator.ts
Comment thread src/common/guards/session.guard.ts Outdated
Comment thread src/modules/auth/dto/register.dto.ts
Comment thread src/modules/partners/partners.service.ts Outdated
Comment thread src/modules/partners/partners.service.ts
Comment thread src/modules/payments/xrpl.service.ts Outdated
Comment thread test/xrpl.e2e-spec.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/modules/payments/xrpl.service.ts (1)

184-186: ⚠️ Potential issue | 🟠 Major

checkPayment()도 끊긴 연결을 복구하도록 맞춰 주세요.

fundAccount()는 필요하면 connect()를 다시 타는데, checkPayment()는 같은 상황에서 바로 실패합니다. 운영 중 일시적인 WebSocket 끊김만으로 결제 확인이 영구 실패 상태가 되는 건 너무 취약합니다.

🔄 수정 예시
   async checkPayment(
     destTag: number,
     expectedAmountXrp: number,
   ): Promise<PaymentCheckResult> {
-    if (!this.client?.isConnected()) {
-      throw new Error("XRPL client is not connected");
-    }
+    if (!this.client?.isConnected()) {
+      await this.connect();
+    }
 
     const expectedDrops = BigInt(xrpToDrops(expectedAmountXrp));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/payments/xrpl.service.ts` around lines 184 - 186, checkPayment()
currently throws immediately when this.client?.isConnected() is false; change it
to mirror fundAccount() by attempting to recover the WebSocket: call await
this.connect() (or the existing connection routine used by fundAccount()) when
the client is not connected, re-check this.client?.isConnected(), and only then
throw an Error if still disconnected; update references in checkPayment() around
the this.client?.isConnected() check so transient disconnects are retried rather
than failing instantly.
src/modules/partners/partners.service.ts (2)

381-390: ⚠️ Potential issue | 🟡 Minor

웹 검색 결과에도 productIntroduction를 채워서 응답 형태를 맞춰 주세요.

같은 서비스의 DB 경로는 SEARCH_PROJECTIONproductIntroduction를 포함하는데, 웹 폴백은 이 필드를 아예 생략하고 있습니다. provider에 따라 payload shape가 달라져 클라이언트가 분기 처리를 강제당합니다.

🧩 수정 예시
         return {
           _id: `web_${index}`,
           name: item.title,
           industry: "Web Result",
           location: { country: "Global", city: "", state: "" },
           companyIntroduction: item.content,
+          productIntroduction: "",
           websiteUrl: item.url,
           tags: ["Web"],
           score: Math.min(1.0, Math.max(0.1, score)),
         };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/partners/partners.service.ts` around lines 381 - 390, The
web-fallback return object in partners.service.ts omits productIntroduction
causing inconsistent payload shapes compared to SEARCH_PROJECTION; update the
object constructed for web results (the block that returns _id: `web_${index}`,
name: item.title, etc.) to include productIntroduction (e.g., set it from
item.content or a trimmed snippet) so web provider responses match other
providers' shape and avoid client-side branching.

176-215: ⚠️ Potential issue | 🟠 Major

$vectorSearch.filter로 필터를 벡터 검색 단계 내부로 이동하세요.

현재는 type: "seller"와 기타 필터가 벡터 후보를 뽑은 뒤 $match에서 적용되어, 벡터 단계의 numCandidateslimit 슬롯을 매칭되지 않는 문서가 먼저 소모합니다. MongoDB Atlas $vectorSearchfilter 옵션을 지원하므로, 이 필터들을 벡터 검색 단계에서 직접 적용하면 recall 손실 없이 더 효율적으로 동작합니다. 특히 이 PR의 목적이 Buyer가 Seller 결과에 섞이는 문제를 해결하는 것이라면, 해당 필터는 벡터 단계 자체에서 걸어야 합니다.

수정 방향
+      const vectorFilter: Record<string, any> = { type: "seller" };
       const pipeline: any[] = [
         {
           $vectorSearch: {
             index: process.env.ATLAS_VECTOR_INDEX || "vector_index",
             path: "embedding",
             queryVector: vector,
             numCandidates: 100,
             limit: Number(limit) * 2,
+            filter: vectorFilter,
           },
         },
       ];
-      const matchStage: Record<string, any> = { type: "seller" };

필터 필드들(type, industry, country 등)이 vectorSearch 인덱스에서 filter 타입으로 인덱싱되어 있는지 확인하세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/partners/partners.service.ts` around lines 176 - 215, The
pipeline currently builds matchStage and pushes a subsequent {$match} after the
$vectorSearch, which wastes numCandidates/limit on non-matching docs; move the
matchStage into the $vectorSearch filter option so filtering is applied during
candidate retrieval. Concretely, update the pipeline construction so the
$vectorSearch stage (the object using index/process.env.ATLAS_VECTOR_INDEX,
queryVector `vector`, `numCandidates`, and `limit`) includes a `filter:
matchStage` property (after you build matchStage using INDUSTRY_MAPPING and
predictedIndustry logic), and remove the later pipeline.push({ $match:
matchStage }) call; also ensure the fields used (type, industry,
location.country, tags, sizeBucket, name) are indexed as vectorSearch filters in
your Atlas index before deploying.
🧹 Nitpick comments (1)
src/common/decorators/current-user.decorator.ts (1)

14-18: getRequest()을 타입 지정해서 any 기반 세션 접근을 제거해 주세요.

Line 14에서 reqany로 타입되어 Line 15/18의 session 접근이 unsafe 경고를 냅니다. 런타임 동작은 그대로 두고 타입만 고정하는 쪽이 안전합니다.

🔧 제안 수정안
 import {
   createParamDecorator,
   ExecutionContext,
   UnauthorizedException,
 } from "@nestjs/common";
+import type { Request } from "express";
@@
 export const CurrentUser = createParamDecorator(
   (_: unknown, ctx: ExecutionContext): SessionUser => {
-    const req = ctx.switchToHttp().getRequest();
+    const req = ctx.switchToHttp().getRequest<Request>();
     if (!req.session?.userId || !req.session?.type) {
       throw new UnauthorizedException("User not authenticated");
     }
     return { userId: req.session.userId, type: req.session.type };
   },
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/common/decorators/current-user.decorator.ts` around lines 14 - 18, The
current code reads req via ctx.switchToHttp().getRequest() and treats it as any,
causing unsafe session access; create a typed request interface (e.g.,
AuthenticatedRequest or extend Express.Request) that includes session: {
userId?: string; type?: string } and use it when assigning req (replace the any
inference on ctx.switchToHttp().getRequest() with this typed request) so the
checks and return { userId: req.session.userId, type: req.session.type } are
type-safe; update the declaration where req is obtained in
current-user.decorator (the getRequest() call) to use that interface.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/common/guards/session.guard.ts`:
- Around line 12-13: The guard currently only checks presence of
req.session?.type and accepts any truthy value; update the session guard (e.g.,
in the canActivate logic in session.guard.ts where it checks req.session?.userId
and req.session?.type) to validate that req.session.type is one of the allowed
literal values ("buyer" or "seller") before permitting access; if it is missing
or not one of these values, throw the same UnauthorizedException("User not
authenticated") so malformed or poisoned sessions are rejected.

In `@src/config/env.config.ts`:
- Around line 78-80: The session secret currently falls back to a weak default;
update the session config so that when NODE_ENV === "production" and
process.env.SESSION_SECRET is missing/empty the application fails fast (throw an
Error) instead of using "dev-secret-change-in-production"; modify the
session.secret resolution logic in env.config.ts (the session object /
session.secret) to mirror how ENCRYPTION_KEY is handled: validate presence in
production and throw a clear error including the symbol SESSION_SECRET if
absent.

In `@src/modules/payments/xrpl.service.ts`:
- Around line 96-103: In fundAccount, before calling
Wallet.fromSeed(wallet.seed) and client.fundWallet, derive the XRPL address from
the seed (using Wallet.fromSeed(...).address) and compare it to the stored
wallet.address; if they differ, abort the operation (throw or return an
error/exception) and log a clear message so you don't fund the wrong account.
Ensure this check happens after ensuring the client is connected (connect) and
before client.fundWallet is invoked so Wallet.fromSeed, wallet.address,
fundAccount, and client.fundWallet are the primary symbols to locate and update.
- Around line 54-56: The onModuleInit() currently awaits this.connect(), which
blocks application boot if XRPL connection fails; change it to start connection
asynchronously and never throw during startup: call this.connect() without await
(or schedule it via setImmediate/void Promise) and ensure connect() errors are
caught and handled inside (or attach .catch() to log a warning via the service
logger and optionally schedule retries), so onModuleInit() returns immediately
while XRPL connection proceeds in background; refer to the onModuleInit and
connect methods to implement the non-blocking startup and robust error
logging/retry.

---

Outside diff comments:
In `@src/modules/partners/partners.service.ts`:
- Around line 381-390: The web-fallback return object in partners.service.ts
omits productIntroduction causing inconsistent payload shapes compared to
SEARCH_PROJECTION; update the object constructed for web results (the block that
returns _id: `web_${index}`, name: item.title, etc.) to include
productIntroduction (e.g., set it from item.content or a trimmed snippet) so web
provider responses match other providers' shape and avoid client-side branching.
- Around line 176-215: The pipeline currently builds matchStage and pushes a
subsequent {$match} after the $vectorSearch, which wastes numCandidates/limit on
non-matching docs; move the matchStage into the $vectorSearch filter option so
filtering is applied during candidate retrieval. Concretely, update the pipeline
construction so the $vectorSearch stage (the object using
index/process.env.ATLAS_VECTOR_INDEX, queryVector `vector`, `numCandidates`, and
`limit`) includes a `filter: matchStage` property (after you build matchStage
using INDUSTRY_MAPPING and predictedIndustry logic), and remove the later
pipeline.push({ $match: matchStage }) call; also ensure the fields used (type,
industry, location.country, tags, sizeBucket, name) are indexed as vectorSearch
filters in your Atlas index before deploying.

In `@src/modules/payments/xrpl.service.ts`:
- Around line 184-186: checkPayment() currently throws immediately when
this.client?.isConnected() is false; change it to mirror fundAccount() by
attempting to recover the WebSocket: call await this.connect() (or the existing
connection routine used by fundAccount()) when the client is not connected,
re-check this.client?.isConnected(), and only then throw an Error if still
disconnected; update references in checkPayment() around the
this.client?.isConnected() check so transient disconnects are retried rather
than failing instantly.

---

Nitpick comments:
In `@src/common/decorators/current-user.decorator.ts`:
- Around line 14-18: The current code reads req via
ctx.switchToHttp().getRequest() and treats it as any, causing unsafe session
access; create a typed request interface (e.g., AuthenticatedRequest or extend
Express.Request) that includes session: { userId?: string; type?: string } and
use it when assigning req (replace the any inference on
ctx.switchToHttp().getRequest() with this typed request) so the checks and
return { userId: req.session.userId, type: req.session.type } are type-safe;
update the declaration where req is obtained in current-user.decorator (the
getRequest() call) to use that interface.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e2cb40b5-8abb-4129-bfec-c5a3aecec4bb

📥 Commits

Reviewing files that changed from the base of the PR and between 352745f and ea3f1ea.

📒 Files selected for processing (10)
  • .coderabbit.yaml
  • src/common/decorators/current-user.decorator.ts
  • src/common/guards/session.guard.ts
  • src/config/env.config.ts
  • src/main.ts
  • src/modules/auth/auth.controller.spec.ts
  • src/modules/auth/auth.controller.ts
  • src/modules/auth/dto/register.dto.ts
  • src/modules/partners/partners.service.ts
  • src/modules/payments/xrpl.service.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • .coderabbit.yaml
  • src/main.ts
  • src/modules/auth/auth.controller.ts
  • src/modules/auth/auth.controller.spec.ts
  • src/modules/auth/dto/register.dto.ts

Comment thread src/common/guards/session.guard.ts Outdated
Comment thread src/config/env.config.ts
Comment thread src/modules/payments/xrpl.service.ts
Comment thread src/modules/payments/xrpl.service.ts
@Takch02 Takch02 merged commit 42941d3 into main Apr 28, 2026
3 checks passed
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