Skip to content

Conversation

@AndrewHanasiro
Copy link
Member

@AndrewHanasiro AndrewHanasiro commented Dec 9, 2025

Proposal

Links

Summary by CodeRabbit

Release Notes

  • New Features

    • Implemented email-based password reset flow for improved security and user experience.
    • Enhanced MFA handling with better error reporting for authentication failures.
  • Improvements

    • Updated Node.js to version 24.10 for improved performance and security.
    • Simplified service architecture by removing unnecessary dependencies.
    • Upgraded PostgreSQL to 17.6 and Redis to 7.4.6 for better stability and features.
  • Bug Fixes

    • Fixed async handling in MFA code delivery for more reliable authentication.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2025

Walkthrough

Multiple dependency upgrades including Node.js 24.10, OpenTelemetry packages, and core libraries. Configuration changes include removing Kafka services, updating container images, and converting ESLint configuration to TypeScript. Several type aliases converted to interfaces, and significant refactoring of JWT middleware, reset password flow, and tracing initialization with NodeSDK.

Changes

Cohort / File(s) Summary
Configuration & Versioning
.nvmrc, package.json
Node.js version updated from 22.12 to 24.10; engine requirement updated to 24.x. Broad dependency updates across OpenTelemetry packages, core libraries (axios, bcrypt, express, pg, redis, etc.), and dev tooling (ESLint, TypeScript, Jest). Lint and format scripts consolidated.
ESLint Configuration
eslint.config.mjs, eslint.config.mts
Removed legacy JavaScript ESLint config (mjs) and added new TypeScript-based configuration (mts) with simplified plugin setup, TypeScript parser, and import sorting via defineConfig.
Docker & Services
docker-compose.yml
Removed top-level version, Kafka and Zookeeper services entirely. Updated database image from postgres:15.1 to postgres:17.6 and cache from redis:7.0.5 to redis:7.4.6. Removed Kafka/Zipkin environment variables from api service.
Prettier Configuration
.prettierignore
Added negated ignore rule !*.mts to explicitly include TypeScript module files for Prettier processing.
Type & Interface Changes
src/core/entities/credentials.ts, src/core/entities/mfa.ts, src/config/enviroment_config.ts, src/presentation/http/middlewares/jwt.ts, test/fixtures/user.ts
Converted type aliases to interfaces for Credential, Enviroment, and JwtPayloadContent. Added optional secret?: string field to Mfa interface. Introduced internal EnvVar type in environment config.
Array Type Syntax Normalization
src/core/providers/mfa.repository.ts, src/core/providers/organization.repository.ts, src/core/providers/user.repository.ts, test/fixtures/multi_factor_authentication.ts, test/fixtures/organization.ts, test/fixtures/user_info.ts
Changed array type annotations from Array<{ id: string }> to { id: string }[] for consistency across repository and fixture files.
Redis Client Type
src/core/config/cache.ts
Simplified getRedis function by removing else branch; updated RedisClient type alias from explicit type union to ReturnType<typeof createClient>. Reduced import footprint to only createClient.
JWT Middleware Refactoring
src/presentation/http/middlewares/jwt.ts
Reworked imports to include NextFunction, Request, Response; switched JWT option type from SignOptions to VerifyOptions. Introduced internal helpers isJwt and extractPayload for payload normalization. Updated token creation to include explicit exp claim. Refactored removeJwtAttr to use new extraction flow.
OpenTelemetry Tracing
src/presentation/tracing.ts
Replaced legacy Resource+NodeTracerProvider+BatchSpanProcessor setup with NodeSDK-based configuration. Introduced getNodeAutoInstrumentations for automatic Node instrumentation; switched to resourceFromAttributes and SimpleSpanProcessor for exporter setup.
UUID Service
src/core/services/uuid.service.ts
Replaced uuid library with Node's crypto.randomUUID(). Removed validate method and version-related logic; generateHash now returns UUID directly via crypto.randomUUID().
Reset Password Flow
src/core/usecases/reset_password.usecase.ts, src/core/usecases/driven/sending_mfa_code.driven.ts
Complete redesign from token-based to email-based password reset. Added forget(email) and recover(newPassword, hash) methods. Introduced new interfaces CreatingResetPassword, FindingResetPassword, SendingResetEmail, UpdatingUser. Removed token-related entities. Added GA_SENT_CODE to SendingMfaCodeErrorsTypes.
MFA & Notification Updates
src/core/providers/notification.provider.ts
Added await for async calls to sendCodeByEmail and sendCodeByPhone in sendCodeByStrategy. Updated Kafka payloads to use object property shorthand. Default case now throws error with GA_SENT_CODE.
Import Ordering & Formatting
src/core/index.ts, src/core/usecases/login.usecase.ts, src/core/usecases/logout.usecase.ts, src/core/usecases/mfa.usecase.ts, src/core/usecases/mfa_choose.usecase.ts, src/core/usecases/mfa_code.usecase.ts, src/core/usecases/organization.usecase.ts, src/core/usecases/token.usecase.ts, src/core/usecases/user.usecase.ts, src/core/usecases/reset_password.usecase.ts, src/presentation/http/app.ts, src/presentation/http/server.ts, src/core/services/password.service.ts, src/core/config/metric.ts, src/core/config/kafka.ts, src/core/usecases/driven/finding_user.driven.ts, src/core/usecases/driver/refresh_token.driver.ts, src/presentation/http/middlewares/metric.ts, src/presentation/http/middlewares/trace.ts
Removed extraneous blank lines between imports; reordered import specifiers for consistency (e.g., NextFunction moved to front in Express imports). No functional changes.
Route & Handler Updates
src/presentation/http/routes/login.route.ts, src/presentation/http/routes/logout.route.ts, src/presentation/http/routes/mfa.route.ts, src/presentation/http/routes/organization.route.ts, src/presentation/http/routes/reset_password.route.ts, src/presentation/http/routes/user.route.ts
Reordered destructured imports from express (moved NextFunction, RequestHandler, etc.). Added destructuring for token parameter in login route. Updated import handling for consistency across route files.
Login & MFA Usecase Logic
src/core/usecases/login.usecase.ts, src/core/usecases/mfa_code.usecase.ts
Simplified MFA/no-MFA branching by removing else blocks and restructuring token return paths. Updated phone and GA handling with conditional mocking and shorthand properties.
User & Organization Repository Updates
src/core/providers/user.repository.ts, src/core/providers/organization.repository.ts
Removed per-branch else blocks in update logic for phone, deviceId, and ga paths. Changed type annotations for insert results to { id: string }[] format.
Test Fixtures
test/fixtures/generators.ts, test/fixtures/user.ts
Converted jsonGenerator to concise arrow function with implicit return. Changed UserFixture from type to interface. Updated array type annotations throughout.
Integration Tests
test/integration/http/login.route.test.ts, test/integration/http/logout.route.test.ts, test/integration/http/mfa.route.test.ts, test/integration/http/organization.route.test.ts, test/integration/http/reset_password.route.test.ts, test/integration/http/user.route.test.ts
Pinned PostgreSQL (postgres:15.1) and Redis (redis:7.0.5) container images. Added Redis readiness checks and auto-connect. Introduced environment mocks for getEnv with app config, jwt secret, database, and cache settings. Simplified Kafka mock implementations. Updated test syntax to arrow functions.
Unit Tests - Providers
test/unit/providers/mfa.repository.test.ts, test/unit/providers/mfa_choose.repository.test.ts, test/unit/providers/mfa_code.repository.test.ts, test/unit/providers/notification.provider.test.ts, test/unit/providers/organization.repository.test.ts, test/unit/providers/user.repository.test.ts
Specified container images (postgres:15.1, redis:7.0.5). Added new test cases for error paths in notification provider. Reordered imports and removed intermediate variable declarations. Updated mock implementations.
Unit Tests - Services
test/unit/services/password.services.test.ts, test/unit/services/uuid.services.test.ts
Replaced destructuring patterns for casual data. Updated UUID validation test to use regex pattern matching instead of validate method call.
Unit Tests - Usecases
test/unit/usecases/login.usecase.test.ts, test/unit/usecases/logout.usecase.test.ts, test/unit/usecases/mfa.usecase.test.ts, test/unit/usecases/mfa_choose.usecase.test.ts, test/unit/usecases/mfa_code.usecase.test.ts, test/unit/usecases/organization.usecase.test.ts, test/unit/usecases/reset_password.usecase.test.ts, test/unit/usecases/token.usecase.test.ts, test/unit/usecases/user.usecase.test.ts
Converted describe callbacks to arrow functions. Reordered ts-mockito imports (instance, mock, verify, when pattern). Added destructuring for casual data (phone, password). Consolidated mock/instance boilerplate. Updated UserUsecase constructor to require four dependencies. Refactored reset password test suite to reflect new email-based flow.
Load Testing
test/loading/k6.js
Reordered imports from k6 library; no functional changes.
Coverage & Generated
coverage/lcov.info
Updated code coverage metadata reflecting line/branch coverage redistribution due to source changes.

Sequence Diagram

sequenceDiagram
    participant User
    participant App
    participant Email Service
    participant Database
    participant User Email

    User->>App: POST /password/recover (email)
    activate App
    App->>Database: Find user by email
    Database-->>App: User found
    App->>Database: Create reset token
    Database-->>App: Reset hash
    App->>Email Service: Send reset email with hash
    Email Service->>User Email: Email sent
    deactivate App
    
    User->>User Email: Click reset link (hash)
    activate User
    User->>App: POST /password/reset (newPassword, hash)
    activate App
    App->>Database: Find reset by hash
    Database-->>App: Reset record
    App->>Database: Update user password
    Database-->>App: Success
    App-->>User: Password updated
    deactivate App
    deactivate User
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring extra attention:

  • Reset Password Flow Redesign (src/core/usecases/reset_password.usecase.ts, related driven interfaces): Complete architectural change from token-based to email-based recovery requires thorough validation of new flow semantics, hash generation, and error handling.
  • JWT Middleware Refactoring (src/presentation/http/middlewares/jwt.ts): New extractPayload and isJwt helpers introduce internal API changes; verify payload normalization logic handles all JWT claim shapes correctly.
  • OpenTelemetry Tracing (src/presentation/tracing.ts): Migration from legacy Resource+Provider pattern to NodeSDK with auto-instrumentation—verify span processor configuration and that automatic instrumentation covers expected operations.
  • Type Alias to Interface Conversions: Multiple files (credentials, mfa, enviroment_config, jwt.ts) converted from type to interface—verify no structural type incompatibilities arise in consumers.
  • Kafka Service Removal (docker-compose.yml, integration tests): Verify all Kafka-dependent code paths have mocks in place and no orphaned references remain.
  • Array Type Syntax Changes: While mostly cosmetic, verify linting and type-checking pass across all Array<T>T[] conversions in repositories and fixtures.

Poem

🐰 A flutter of hopping through code so bright,
From tokens to hashes, we've set things right,
With NodeSDK tracing and passwords anew,
Refactored in style with interfaces too,
The warren rejoices—our journey's complete!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Feature/update package' is vague and generic, using non-descriptive terms that don't convey specific information about the main changes in the changeset. Use a more specific title that highlights the primary change, such as 'Update Node.js to 24.x LTS and refresh dependencies' or 'Upgrade Node.js version and package dependencies'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description follows the required template structure with both Proposal and Links sections properly filled. It covers the main objectives including Node version update, package updates, ESLint configuration changes, and UUID removal.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/update-package

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

@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: 7

Caution

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

⚠️ Outside diff range comments (3)
src/presentation/tracing.ts (1)

18-21: Remove redundant registerInstrumentations call.

This call with an empty instrumentations array is now redundant since instrumentations are passed directly to NodeSDK on line 33. It can be safely removed along with the import on line 4.

-import { registerInstrumentations } from '@opentelemetry/instrumentation'
-// Optionally register instrumentation libraries
-registerInstrumentations({
-  instrumentations: [],
-})
src/core/providers/notification.provider.ts (1)

73-88: Async strategy methods fire‑and‑forget; add await to avoid unhandled rejections

The shorthand { email, hash } in sendEmail is fine, but both strategy helpers invoke async methods without await:

  • sendCodeByStrategythis.sendCodeByEmail / this.sendCodeByPhone
  • sendMfaHashByStrategythis.sendMfaHashByEmail / this.sendMfaHashByPhone

This means:

  • Callers of the strategy methods can resolve before Kafka sends complete.
  • Any rejection inside those async methods becomes an unhandled promise rejection, which can be fatal on newer Node versions.

Recommend awaiting the inner calls so errors propagate and the contract “send completes when this promise resolves” holds:

   async sendCodeByStrategy(
@@
-    switch (strategy) {
-      case Strategy.EMAIL:
-        this.sendCodeByEmail(userId, code)
-        break
-      case Strategy.PHONE:
-        this.sendCodeByPhone(userId, code)
-        break
-      default:
-        break
-    }
+    switch (strategy) {
+      case Strategy.EMAIL:
+        await this.sendCodeByEmail(userId, code)
+        break
+      case Strategy.PHONE:
+        await this.sendCodeByPhone(userId, code)
+        break
+      default:
+        break
+    }
@@
   async sendMfaHashByStrategy(
@@
-    switch (strategy) {
-      case Strategy.EMAIL:
-        this.sendMfaHashByEmail(userId, hash)
-        break
-      case Strategy.PHONE:
-        this.sendMfaHashByPhone(userId, hash)
-        break
-      default:
-        break
-    }
+    switch (strategy) {
+      case Strategy.EMAIL:
+        await this.sendMfaHashByEmail(userId, hash)
+        break
+      case Strategy.PHONE:
+        await this.sendMfaHashByPhone(userId, hash)
+        break
+      default:
+        break
+    }

This aligns better with the rest of your async API and reduces the risk of unhandled rejections around Kafka I/O.

Also applies to: 132-147, 149-158

src/core/usecases/reset_password.usecase.ts (1)

29-36: Await reset email sending to avoid unhandled rejections

The refactor in recover to declare email and user in one const is fine. However, in forget you call an async dependency without awaiting it:

const hash = await this.creatingResetPassword.create(email)
this.sendingResetEmail.sendEmail(email, hash)

If sendEmail rejects (Kafka/network issues, etc.), the error will not be caught by this try/catch and can become an unhandled rejection, especially problematic after upgrading Node.

Recommend awaiting it:

   async forget(email: string): Promise<void> {
     try {
       const hash = await this.creatingResetPassword.create(email)
-      this.sendingResetEmail.sendEmail(email, hash)
+      await this.sendingResetEmail.sendEmail(email, hash)

This way callers only see success once the reset email enqueue/send has actually succeeded, and dependency errors map cleanly to ForgetPasswordErrorsTypes.DEPENDECY_ERROR.

Also applies to: 39-44

🧹 Nitpick comments (30)
src/core/usecases/token.usecase.ts (1)

27-28: Comma-separated declarations reduce readability.

While syntactically correct, merging const declarations with mixed async/sync assignments on consecutive lines can be harder to read and debug. Consider keeping separate declarations:

const user = await this.findingUser.findById(userId)
const token = this.creatingToken.create(user)

If this pattern is enforced by your updated linter configuration, feel free to disregard.

src/core/providers/mfa_code.repository.ts (1)

40-42: Same readability concern with comma-separated declarations.

While correct, multi-line comma-separated declarations can be harder to scan. Consider separate declarations for clarity:

const hash = this.uuidService.generateHash()
const code = this.codeService.generateRandomNumber()
const content: CacheCode = { userId, code, strategy }

If this is a linter-enforced pattern, feel free to disregard.

test/fixtures/generators.ts (1)

9-15: jsonGenerator refactor keeps output shape; slight change in construction style

The concise reduce form still produces an object whose keys come from keyList and whose values are casual.sentence. The only difference is that it now creates a fresh object on each iteration with spread, which is fine for tests but does change property insertion order compared to an in‑place mutation pattern.

test/fixtures/user.ts (1)

29-40: Consider splitting consolidated declarations for readability.

While the consolidated comma-separated declarations are functionally correct, combining 12 lines of logic—including input defaulting, cryptographic operations, and database insertion—into a single statement reduces readability and makes debugging more difficult.

Consider breaking this into logical groups:

-  const name = input?.name ?? casual.full_name,
-    email = input?.email ?? casual.email.toLowerCase(),
-    password = input?.password ?? passwordGenerator(),
-    salt = genSaltSync(12),
-    hashPw = await hashFunc(password, salt),
-    row: { id: string }[] = await database('user')
-      .insert({
-        name,
-        email,
-        password_hash: hashPw,
-      })
-      .returning('id')
+  const name = input?.name ?? casual.full_name
+  const email = input?.email ?? casual.email.toLowerCase()
+  const password = input?.password ?? passwordGenerator()
+  
+  const salt = genSaltSync(12)
+  const hashPw = await hashFunc(password, salt)
+  
+  const row: { id: string }[] = await database('user')
+    .insert({
+      name,
+      email,
+      password_hash: hashPw,
+    })
+    .returning('id')
src/core/providers/user.repository.ts (2)

105-114: Consider splitting consolidated declarations for clarity.

Consolidating hash generation, insert object creation, and the database operation into a single multi-variable declaration reduces readability and makes debugging more difficult.

Consider separating the concerns:

-    const hash = await this.passwordService.generateHash(password),
-      insertLine = {
-        name,
-        email,
-        password_hash: hash,
-      },
-      response: { id: string }[] = await this.database<UserRow>('user')
-        .insert(insertLine)
-        .returning('id')
+    const hash = await this.passwordService.generateHash(password)
+    const insertLine = {
+      name,
+      email,
+      password_hash: hash,
+    }
+    const response: { id: string }[] = await this.database<UserRow>('user')
+      .insert(insertLine)
+      .returning('id')

125-129: Consider splitting async operations.

Combining password hash generation and the database update in a single declaration makes it harder to debug and understand the flow.

Consider:

-    const hash = await this.passwordService.generateHash(password),
-      response = await this.database<UserRow>('user')
-        .update({ password_hash: hash })
-        .where('id', user.id)
+    const hash = await this.passwordService.generateHash(password)
+    const response = await this.database<UserRow>('user')
+      .update({ password_hash: hash })
+      .where('id', user.id)
src/core/providers/mfa.repository.ts (1)

46-54: Awkward multi-declaration formatting reduces readability.

The comma-separated const declaration combining insertLine and resp is valid but the indentation is misleading—the object properties are indented further than the opening brace, and the resp declaration appears as if it's part of the object literal. Consider using separate const statements for clarity:

-    const insertLine = {
-        user_id: user.id,
-        strategy,
-        //If GA, is_enable must be true. No way to validate the authenticity
-        is_enable: strategy === Strategy.GA,
-      },
-      resp: { id: string }[] = await this.database(this.tableName)
-        .insert(insertLine)
-        .returning('id')
+    const insertLine = {
+      user_id: user.id,
+      strategy,
+      // If GA, is_enable must be true. No way to validate the authenticity
+      is_enable: strategy === Strategy.GA,
+    }
+    const resp: { id: string }[] = await this.database(this.tableName)
+      .insert(insertLine)
+      .returning('id')
src/presentation/tracing.ts (1)

32-32: Consider BatchSpanProcessor for production environments.

SimpleSpanProcessor exports spans synchronously, which can add latency to requests. For production use, BatchSpanProcessor is recommended as it batches and exports spans asynchronously, reducing performance impact.

-import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
+import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
-    spanProcessors: [new SimpleSpanProcessor(exporter)],
+    spanProcessors: [new BatchSpanProcessor(exporter)],
test/fixtures/multi_factor_authentication.ts (1)

11-28: Row typing is fine; consider safer destructuring

const row: { id: string }[] = await ...returning('id') matches Knex’s return shape, and existing logic is preserved. For slightly safer code in tests, you could destructure and guard against unexpected empty results:

-  const row: { id: string }[] = await database('multi_factor_authentication')
+  const rows: { id: string }[] = await database('multi_factor_authentication')
     .insert({
       user_id: input?.userId,
       strategy: input?.strategy,
       is_enable: input?.isEnable ?? true,
     })
     .returning('id')
+  const [row] = rows
+
+  if (!row) {
+    throw new Error('insertMfaIntoDatabase: insert did not return an id')
+  }
@@
-      id: row[0].id,
+      id: row.id,

Not required, but makes failures easier to diagnose in fixtures.

src/presentation/http/routes/reset_password.route.ts (1)

12-21: Handlers are correct but multi‑await const declarations hurt readability

The use of Joi.types() with destructured object/string is fine, and the validation logic looks sound. The chained const declarations with multiple awaits in each route make the handlers harder to read and debug, though.

Consider reverting to one const per logical step:

-  try {
-    const { email }: ForgetPasswordInput = await schema.validateAsync(req.body),
-      core = await getCore(),
-      resp = await core.reset.forget(email)
+  try {
+    const { email }: ForgetPasswordInput = await schema.validateAsync(req.body)
+    const core = await getCore()
+    const resp = await core.reset.forget(email)
@@
-  try {
-    const { password, hash }: RecoverPasswordInput =
-        await schema2.validateAsync(req.body),
-      core = await getCore(),
-      resp = await core.reset.recover(password, hash)
+  try {
+    const { password, hash }: RecoverPasswordInput =
+      await schema2.validateAsync(req.body)
+    const core = await getCore()
+    const resp = await core.reset.recover(password, hash)

Same behavior, but clearer stack traces and easier future edits.

Also applies to: 23-36, 43-46, 48-62

src/core/index.ts (1)

51-173: Consider readability implications of 123-line const block.

While this consolidation aligns with the PR's formatting objectives and maintains functional equivalence, a single 123-line comma-separated const declaration may impact:

  • Debugging: Setting breakpoints or adding logging mid-chain requires restructuring
  • Readability: The long chain can be harder to scan than grouped declarations
  • Error messages: Stack traces may be less precise for initialization failures

If this style is a deliberate project convention, consider adding inline comments to mark major sections (services, providers, usecases) for easier navigation.

src/core/services/uuid.service.ts (1)

4-4: Optional: Consider removing unused version field.

The version field is no longer used after migrating to crypto.randomUUID().

Apply this diff to remove the unused field:

 export class UuidService {
-  private version = 4
   generateHash(): string {
     return randomUUID()
   }
 }
src/presentation/http/routes/logout.route.ts (1)

20-21: Consolidated declarations work but consider readability.

The comma-separated variable declarations are syntactically correct and follow a pattern used consistently across the route files in this PR. However, separating async operations onto individual lines can improve debuggability and readability.

If preferred, you could separate these for clarity:

-    const token = retriveToken(req),
-      core = await getCore()
+    const token = retriveToken(req)
+    const core = await getCore()
src/presentation/http/routes/organization.route.ts (1)

30-34: Consolidated declarations are consistent but consider readability.

The comma-separated variable declarations follow the pattern established across route files in this PR. While syntactically correct, separating async operations can improve debugging and stacktrace readability, especially when validation and core initialization might fail.

For improved debugging, consider separating these:

 try {
   const { name, parentId }: OrganizationInput = await schema.validateAsync(
-      req.body
-    ),
-    core = await getCore(),
-    id = await core.organization.create(name, parentId)
+      req.body
+    )
+  const core = await getCore()
+  const id = await core.organization.create(name, parentId)
   res.status(200).send({ id })

Also applies to: 57-59, 84-86

src/presentation/http/routes/login.route.ts (1)

32-36: Consolidated declarations follow PR pattern; consider readability.

The comma-separated declarations are consistent with other route files in this PR. As with the other routes, separating async operations can improve debugging and error tracking.

For clarity in error stacktraces:

-    const { email, password }: LoginInput = await schema.validateAsync(
-        req.body
-      ),
-      core = await getCore(),
-      resp = await core.login.login(email, password)
+    const { email, password }: LoginInput = await schema.validateAsync(
+        req.body
+      )
+    const core = await getCore()
+    const resp = await core.login.login(email, password)

Also applies to: 49-51

src/presentation/http/routes/user.route.ts (1)

32-36: Consolidated declarations are consistent; consider readability.

The comma-separated variable declarations follow the established pattern throughout this PR. Separating async operations can help with debugging, particularly in the PATCH handler where multiple optional fields are processed.

For improved debugging:

-    const { name, email, password }: UserInput = await schema.validateAsync(
-        req.body
-      ),
-      core = await getCore(),
-      id = await core.user.create(name, email, password)
+    const { name, email, password }: UserInput = await schema.validateAsync(
+        req.body
+      )
+    const core = await getCore()
+    const id = await core.user.create(name, email, password)

Also applies to: 67-76, 85-86

src/core/usecases/login.usecase.ts (1)

30-34: LGTM! Consolidated declarations follow PR pattern.

The comma-separated declarations for user and mfaList are consistent with the refactoring pattern across the codebase. As with the route files, separating these can improve debuggability.

For improved debugging:

-      const user = await this.findingUser.findUserByEmailAndPassword(
-          email,
-          password
-        ),
-        mfaList = await this.findingMFA.findMfaListByUserId(user.id)
+      const user = await this.findingUser.findUserByEmailAndPassword(
+          email,
+          password
+        )
+      const mfaList = await this.findingMFA.findMfaListByUserId(user.id)
test/unit/providers/notification.provider.test.ts (1)

22-39: Consider removing the redundant client variable.

The client object (lines 31-39) duplicates the structure already returned by the jest.spyOn(kafka, 'getKafka') mock (lines 22-30). If NotificationProvider uses getKafka() internally, this local client variable may be unnecessary.

test/unit/usecases/organization.usecase.test.ts (1)

46-85: Consider extracting repetitive mock setup into a helper function.

Each test case repeats the same mock instantiation pattern for CreatingOrganization, FindingUser, AddingUserToOrganization, UpdatingOrganization, and FindingOrganization. A factory helper would reduce boilerplate and improve maintainability.

Example helper pattern:

function createMocks() {
  const mockCreatingOrganization = mock(OrganizationRepository)
  const mockFindingUser = mock(UserRepository)
  // ... other mocks
  return {
    mockCreatingOrganization,
    creatingOrganization: instance(mockCreatingOrganization),
    // ... other instances
  }
}
src/presentation/http/middlewares/trace.ts (1)

12-15: Misplaced comment reduces readability.

The comment // Override the json function is awkwardly positioned within the comma-separated declaration, followed by a blank line. Consider moving the comment above the const block or removing it since the code is self-explanatory.

-  const originalJson = res.send,
-    // Override the json function
-
-    tracer = trace.getTracer(getEnv().app.name)
+  const originalJson = res.send
+  const tracer = trace.getTracer(getEnv().app.name)
test/integration/http/reset_password.route.test.ts (1)

19-26: Pinned containers and mock refactor look correct

Explicit Postgres/Redis image tags, the simplified getKafka mock, and the grouped const declarations keep the reset‑password flow and its assertions intact while improving test determinism and readability. If you ever revisit this file, you might optionally await redis.del('*') in beforeEach to align with the async Redis API and avoid subtle timing issues.

Also applies to: 28-30, 61-69, 88-95, 99-112, 118-125

test/integration/http/organization.route.test.ts (1)

19-25: Organization integration tests: infra refactor is safe

Explicit container images, consolidated test variables, and the inline Kafka mock all keep the create/update organization flows and DB assertions the same as before. Optionally, consider await redis.del('*') in beforeEach for stricter cleanup in async Redis.

Also applies to: 27-28, 60-68, 88-101, 107-121

src/presentation/http/middlewares/jwt.ts (2)

1-1: JWT options and exp claim look consistent; confirm 1‑hour TTL is desired

Restricting verify to algorithms: ['HS256'] and adding an explicit exp to the payload in createToken tighten security and make expiry explicit. However, createToken now hard‑codes a 1‑hour lifetime (now + 60 * 60), which may differ from any previous, configurable TTL. Please confirm that this fixed duration matches your auth requirements (and any existing documentation/config); if not, consider deriving the lifetime from configuration or a parameter.

Also applies to: 3-3, 8-10, 33-38, 40-53


27-31: extractPayload’s Jwt branch is likely unused with current verify options

removeJwtAttr calls verify(token, secret, option) where option is just VerifyOptions (no complete: true), so at runtime the result is typically a string or JwtPayload, not a full Jwt object. That makes the isJwt/payload.payload branch in extractPayload effectively unreachable in current usage. You could either:

  • simplify extractPayload to handle only string | JwtPayload, or
  • extend the verify options to request complete: true (and adjust the type accordingly) if you want to rely on the Jwt shape.

Either way, behavior of existing callers stays clearer and the intent of this helper becomes more explicit.

Also applies to: 56-75

test/integration/http/login.route.test.ts (1)

22-27: Login/MFA integration tests stay robust after setup refactor

The consolidated variable declarations, explicit Postgres/Redis images, simplified Kafka mock, and the typed CacheCode parsing all keep the login + MFA (EMAIL/PHONE) and refresh‑token flows behaving as before, while making the tests clearer. As a small follow‑up, if you see any intermittent issues, consider changing redis.del('*') in beforeEach to await redis.del('*') (and mirroring that in other integration tests) so cleanup is guaranteed before each test body runs.

Also applies to: 29-30, 62-70, 85-95, 97-105, 107-139, 141-179, 181-203

test/unit/providers/organization.repository.test.ts (3)

123-149: Consider extracting the inline database insert for better readability.

The inline database insertion within the comma-separated declaration (lines 128-135) makes the code harder to debug and understand. Breaking this into separate statements would improve clarity without changing behavior.

For example:

-  const userFixture = await insertUserIntoDatabase(database),
-    userId = userFixture.output.id,
-    orgFixture = await insertOrgIntoDatabase(database),
-    orgId = orgFixture.output.id,
-    relationId: string = (
-      await database('organization_user')
-        .insert({
-          organization_id: orgId,
-          user_id: userId,
-        })
-        .returning('id')
-    )[0].id,
-    orgRepository = new OrganizationRepository(database)
+  const userFixture = await insertUserIntoDatabase(database)
+  const userId = userFixture.output.id
+  const orgFixture = await insertOrgIntoDatabase(database)
+  const orgId = orgFixture.output.id
+  
+  const relationResult = await database('organization_user')
+    .insert({
+      organization_id: orgId,
+      user_id: userId,
+    })
+    .returning('id')
+  const relationId = relationResult[0].id
+  
+  const orgRepository = new OrganizationRepository(database)

184-211: Recommend splitting the lengthy comma-separated declaration for maintainability.

This single declaration spans 22 lines with ~12 variables, mixing async fixture creation, object construction, and repository method calls. This makes debugging difficult and git diffs harder to review.

Consider breaking into separate const statements:

-  const orgFixtureC = await insertOrgIntoDatabase(database),
-    currentParentOrgId = orgFixtureC.output.id,
-    orgFixtureT = await insertOrgIntoDatabase(database),
-    targetParentOrgId = orgFixtureT.output.id,
-    orgFixture = await insertOrgIntoDatabase(database),
-    orgId = orgFixture.output.id,
-    organization: Organization = {
-      id: orgId,
-      name: orgFixture.input.name,
-      parentOrganizationId: currentParentOrgId,
-    },
-    targetOrganization: Organization = {
-      id: targetParentOrgId,
-      name: orgFixtureT.input.name,
-      parentOrganizationId: null,
-    },
-    orgRepository = new OrganizationRepository(database),
-    result = await orgRepository.checkCyclicRelationship(
-      organization,
-      targetOrganization
-    )
+  const orgFixtureC = await insertOrgIntoDatabase(database)
+  const currentParentOrgId = orgFixtureC.output.id
+  const orgFixtureT = await insertOrgIntoDatabase(database)
+  const targetParentOrgId = orgFixtureT.output.id
+  const orgFixture = await insertOrgIntoDatabase(database)
+  const orgId = orgFixture.output.id
+  
+  const organization: Organization = {
+    id: orgId,
+    name: orgFixture.input.name,
+    parentOrganizationId: currentParentOrgId,
+  }
+  const targetOrganization: Organization = {
+    id: targetParentOrgId,
+    name: orgFixtureT.input.name,
+    parentOrganizationId: null,
+  }
+  
+  const orgRepository = new OrganizationRepository(database)
+  const result = await orgRepository.checkCyclicRelationship(
+    organization,
+    targetOrganization
+  )

212-241: Same recommendation: split lengthy declaration for better maintainability.

Similar to the previous test case, this 21-line declaration with ~12 variables mixing async operations and object construction impacts readability and debugging. Consider the same refactoring approach of using separate const statements.

test/unit/providers/mfa.repository.test.ts (1)

108-120: Consider simplifying the declaration that mixes async operations, destructuring, and mocking.

Lines 109-117 combine fixture creation, object destructuring, mock setup, and repository method invocation in a single declaration. The destructuring pattern { id } = mfaFixture.output within a comma-separated list is particularly hard to parse.

Breaking this into separate statements would improve clarity:

-  const mfaFixture = await insertMfaIntoDatabase(database, {
-      userId: mockUserId,
-      strategy: Strategy.EMAIL,
-    }),
-    { id } = mfaFixture.output,
-    mockUpdatingUser: UpdatingUser = mock(UserRepository),
-    updatingUser: UpdatingUser = instance(mockUpdatingUser),
-    mFARepository = new MFARepository(database, updatingUser),
-    result = await mFARepository.findMfaListByUserId(mockUserId)
+  const mfaFixture = await insertMfaIntoDatabase(database, {
+    userId: mockUserId,
+    strategy: Strategy.EMAIL,
+  })
+  const { id } = mfaFixture.output
+  
+  const mockUpdatingUser: UpdatingUser = mock(UserRepository)
+  const updatingUser: UpdatingUser = instance(mockUpdatingUser)
+  const mFARepository = new MFARepository(database, updatingUser)
+  const result = await mFARepository.findMfaListByUserId(mockUserId)
test/integration/http/user.route.test.ts (1)

86-107: Recommend separating async operations from variable declarations.

Lines 87-97 embed an async HTTP request within a comma-separated declaration, and lines 99-102 mix an async database query with synchronous array access. This makes debugging harder and obscures the test flow.

Consider separating the operations:

-  const employeeName = casual.full_name,
-    employeeEmail = casual.email.toLowerCase(),
-    employeePassword = passwordGenerator(),
-    response = await request(server)
-      .post('/user')
-      .set('Authorization', `Bearer ${token}`)
-      .send({
-        name: employeeName,
-        email: employeeEmail,
-        password: employeePassword,
-      })
+  const employeeName = casual.full_name
+  const employeeEmail = casual.email.toLowerCase()
+  const employeePassword = passwordGenerator()
+  
+  const response = await request(server)
+    .post('/user')
+    .set('Authorization', `Bearer ${token}`)
+    .send({
+      name: employeeName,
+      email: employeeEmail,
+      password: employeePassword,
+    })
+    
   expect(response.status).toEqual(201)
-  const tuples = await database('user')
-      .select('*')
-      .where('id', response.body.id),
-    row = tuples[0]
+  
+  const tuples = await database('user')
+    .select('*')
+    .where('id', response.body.id)
+  const row = tuples[0]
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d46e1db and 4513276.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (75)
  • .nvmrc (1 hunks)
  • .prettierignore (1 hunks)
  • coverage/lcov.info (39 hunks)
  • docker-compose.yml (2 hunks)
  • eslint.config.mjs (0 hunks)
  • eslint.config.mts (1 hunks)
  • package.json (2 hunks)
  • src/config/enviroment_config.ts (2 hunks)
  • src/config/metric.ts (1 hunks)
  • src/core/config/cache.ts (1 hunks)
  • src/core/config/kafka.ts (1 hunks)
  • src/core/entities/credentials.ts (1 hunks)
  • src/core/entities/mfa.ts (1 hunks)
  • src/core/index.ts (1 hunks)
  • src/core/providers/mfa.repository.ts (2 hunks)
  • src/core/providers/mfa_code.repository.ts (1 hunks)
  • src/core/providers/notification.provider.ts (1 hunks)
  • src/core/providers/organization.repository.ts (3 hunks)
  • src/core/providers/token.repository.ts (1 hunks)
  • src/core/providers/user.repository.ts (6 hunks)
  • src/core/services/password.service.ts (1 hunks)
  • src/core/services/uuid.service.ts (1 hunks)
  • src/core/usecases/driven/finding_user.driven.ts (1 hunks)
  • src/core/usecases/driver/refresh_token.driver.ts (1 hunks)
  • src/core/usecases/login.usecase.ts (1 hunks)
  • src/core/usecases/logout.usecase.ts (0 hunks)
  • src/core/usecases/mfa.usecase.ts (2 hunks)
  • src/core/usecases/mfa_choose.usecase.ts (0 hunks)
  • src/core/usecases/mfa_code.usecase.ts (1 hunks)
  • src/core/usecases/organization.usecase.ts (0 hunks)
  • src/core/usecases/reset_password.usecase.ts (1 hunks)
  • src/core/usecases/token.usecase.ts (1 hunks)
  • src/core/usecases/user.usecase.ts (2 hunks)
  • src/presentation/http/app.ts (1 hunks)
  • src/presentation/http/middlewares/jwt.ts (3 hunks)
  • src/presentation/http/middlewares/metric.ts (2 hunks)
  • src/presentation/http/middlewares/trace.ts (2 hunks)
  • src/presentation/http/routes/login.route.ts (3 hunks)
  • src/presentation/http/routes/logout.route.ts (2 hunks)
  • src/presentation/http/routes/mfa.route.ts (5 hunks)
  • src/presentation/http/routes/organization.route.ts (4 hunks)
  • src/presentation/http/routes/reset_password.route.ts (3 hunks)
  • src/presentation/http/routes/user.route.ts (4 hunks)
  • src/presentation/http/server.ts (1 hunks)
  • src/presentation/tracing.ts (2 hunks)
  • test/fixtures/generators.ts (1 hunks)
  • test/fixtures/multi_factor_authentication.ts (1 hunks)
  • test/fixtures/organization.ts (1 hunks)
  • test/fixtures/setup_migration.ts (1 hunks)
  • test/fixtures/user.ts (2 hunks)
  • test/fixtures/user_info.ts (1 hunks)
  • test/integration/http/login.route.test.ts (6 hunks)
  • test/integration/http/logout.route.test.ts (2 hunks)
  • test/integration/http/mfa.route.test.ts (3 hunks)
  • test/integration/http/organization.route.test.ts (3 hunks)
  • test/integration/http/reset_password.route.test.ts (3 hunks)
  • test/integration/http/user.route.test.ts (3 hunks)
  • test/unit/providers/mfa.repository.test.ts (5 hunks)
  • test/unit/providers/mfa_choose.repository.test.ts (2 hunks)
  • test/unit/providers/mfa_code.repository.test.ts (4 hunks)
  • test/unit/providers/notification.provider.test.ts (2 hunks)
  • test/unit/providers/organization.repository.test.ts (10 hunks)
  • test/unit/providers/user.repository.test.ts (16 hunks)
  • test/unit/services/code.services.test.ts (1 hunks)
  • test/unit/services/password.services.test.ts (1 hunks)
  • test/unit/services/uuid.services.test.ts (1 hunks)
  • test/unit/usecases/login.usecase.test.ts (4 hunks)
  • test/unit/usecases/logout.usecase.test.ts (2 hunks)
  • test/unit/usecases/mfa.usecase.test.ts (9 hunks)
  • test/unit/usecases/mfa_choose.usecase.test.ts (5 hunks)
  • test/unit/usecases/mfa_code.usecase.test.ts (4 hunks)
  • test/unit/usecases/organization.usecase.test.ts (18 hunks)
  • test/unit/usecases/reset_password.usecase.test.ts (2 hunks)
  • test/unit/usecases/token.usecase.test.ts (2 hunks)
  • test/unit/usecases/user.usecase.test.ts (3 hunks)
💤 Files with no reviewable changes (4)
  • eslint.config.mjs
  • src/core/usecases/mfa_choose.usecase.ts
  • src/core/usecases/logout.usecase.ts
  • src/core/usecases/organization.usecase.ts
🧰 Additional context used
🧬 Code graph analysis (33)
src/presentation/http/routes/reset_password.route.ts (1)
src/core/index.ts (1)
  • getCore (50-186)
test/unit/services/password.services.test.ts (2)
src/core/services/password.service.ts (1)
  • PasswordService (4-19)
test/fixtures/generators.ts (1)
  • passwordGenerator (39-51)
test/unit/usecases/mfa.usecase.test.ts (5)
src/core/usecases/driven/finding_user.driven.ts (1)
  • FindingUser (3-8)
src/core/usecases/driven/finding_mfa.driven.ts (1)
  • FindingMFA (3-16)
src/core/usecases/driven/creating_mfa.driven.ts (2)
  • CreatingMFA (5-7)
  • CreatingMFAError (14-19)
src/core/usecases/driven/sending_mfa_hash.driven.ts (1)
  • SendingMfaHash (3-11)
src/core/usecases/mfa.usecase.ts (1)
  • MFA (27-88)
test/integration/http/reset_password.route.test.ts (6)
src/core/config/database.ts (1)
  • Knex (26-26)
test/fixtures/user.ts (1)
  • UserFixture (13-23)
src/core/config/cache.ts (1)
  • RedisClient (6-6)
test/loading/k6.js (1)
  • token (60-60)
test/fixtures/generators.ts (1)
  • passwordGenerator (39-51)
src/core/services/password.service.ts (1)
  • compare (11-13)
test/unit/usecases/token.usecase.test.ts (5)
src/core/entities/user.ts (1)
  • User (1-6)
src/core/usecases/driven/decoding_token.driven.ts (1)
  • DecodingToken (1-3)
src/core/usecases/driven/finding_user.driven.ts (1)
  • FindingUser (3-8)
src/core/usecases/driven/creating_token.driven.ts (1)
  • CreatingToken (3-5)
src/core/usecases/driven/invalidating_token.driven.ts (1)
  • InvalidatingToken (1-3)
test/unit/services/code.services.test.ts (1)
src/core/services/code.service.ts (1)
  • CodeService (3-14)
test/unit/usecases/logout.usecase.test.ts (3)
src/core/usecases/driven/invalidating_token.driven.ts (1)
  • InvalidatingToken (1-3)
src/core/providers/token.repository.ts (1)
  • TokenRepository (11-35)
src/core/usecases/logout.usecase.ts (1)
  • Logout (9-20)
test/unit/usecases/user.usecase.test.ts (4)
src/core/usecases/driven/finding_user.driven.ts (1)
  • FindingUser (3-8)
src/core/usecases/driven/creating_user.driven.ts (2)
  • CreatingUser (1-3)
  • CreatingUserErrors (9-14)
src/core/usecases/driven/updating_user.driven.ts (2)
  • UpdatingUser (3-10)
  • UpdatingUserErrors (16-21)
src/core/usecases/user.usecase.ts (2)
  • UserUsecase (23-86)
  • list (83-85)
src/presentation/http/routes/organization.route.ts (1)
src/core/index.ts (1)
  • getCore (50-186)
test/unit/usecases/organization.usecase.test.ts (8)
src/core/usecases/driven/creating_organization.driven.ts (1)
  • CreatingOrganization (1-3)
src/core/providers/organization.repository.ts (1)
  • OrganizationRepository (37-156)
src/core/usecases/driven/finding_user.driven.ts (2)
  • FindingUser (3-8)
  • FindingUserErrors (16-21)
src/core/providers/user.repository.ts (1)
  • UserRepository (35-247)
src/core/usecases/driven/adding_user_to_organization.driven.ts (2)
  • AddingUserToOrganization (1-3)
  • AddingUserToOrganizationErrors (10-15)
src/core/usecases/driven/updating_organization.driven.ts (1)
  • UpdatingOrganization (3-13)
src/core/usecases/driven/finding_organization.driven.ts (2)
  • FindingOrganization (3-5)
  • FindingOrganizationErrors (11-16)
src/core/usecases/organization.usecase.ts (1)
  • OrganizationUseCase (38-126)
test/integration/http/logout.route.test.ts (3)
src/core/config/cache.ts (1)
  • RedisClient (6-6)
test/loading/k6.js (1)
  • token (60-60)
test/fixtures/generators.ts (1)
  • tokenGenerator (18-29)
src/presentation/http/routes/logout.route.ts (2)
src/presentation/http/middlewares/jwt.ts (1)
  • retriveToken (17-25)
src/core/index.ts (1)
  • getCore (50-186)
test/unit/providers/notification.provider.test.ts (4)
src/core/config/database.ts (1)
  • Knex (26-26)
test/fixtures/setup_migration.ts (1)
  • setupDB (4-74)
test/fixtures/user.ts (1)
  • insertUserIntoDatabase (25-52)
test/fixtures/user_info.ts (1)
  • insertUserInfoIntoDatabase (12-35)
test/integration/http/login.route.test.ts (4)
src/core/config/database.ts (1)
  • Knex (26-26)
src/core/config/cache.ts (1)
  • RedisClient (6-6)
test/fixtures/user.ts (1)
  • UserFixture (13-23)
src/core/providers/mfa_code.repository.ts (1)
  • CacheCode (19-23)
src/presentation/http/routes/user.route.ts (1)
src/core/index.ts (1)
  • getCore (50-186)
test/unit/providers/organization.repository.test.ts (4)
src/core/config/database.ts (1)
  • Knex (26-26)
test/fixtures/organization.ts (1)
  • insertOrgIntoDatabase (9-29)
test/fixtures/user.ts (1)
  • insertUserIntoDatabase (25-52)
src/core/entities/organization.ts (1)
  • Organization (1-5)
src/presentation/http/middlewares/jwt.ts (1)
src/config/enviroment_config.ts (1)
  • getEnv (50-78)
test/unit/providers/mfa_choose.repository.test.ts (3)
src/core/config/cache.ts (1)
  • RedisClient (6-6)
src/core/services/uuid.service.ts (1)
  • UuidService (3-8)
src/core/providers/mfa_choose.repository.ts (1)
  • MFAChooseRepository (11-41)
test/unit/services/uuid.services.test.ts (1)
src/core/services/uuid.service.ts (1)
  • UuidService (3-8)
src/core/usecases/mfa.usecase.ts (1)
src/core/usecases/user.usecase.ts (1)
  • list (83-85)
src/core/config/cache.ts (1)
src/config/enviroment_config.ts (1)
  • getEnv (50-78)
test/integration/http/mfa.route.test.ts (3)
src/core/config/database.ts (1)
  • Knex (26-26)
src/core/config/cache.ts (1)
  • RedisClient (6-6)
test/fixtures/multi_factor_authentication.ts (1)
  • insertMfaIntoDatabase (11-29)
test/unit/usecases/reset_password.usecase.test.ts (6)
test/fixtures/generators.ts (1)
  • tokenGenerator (18-29)
src/core/usecases/driven/decoding_token.driven.ts (1)
  • DecodingToken (1-3)
src/core/usecases/driven/finding_user.driven.ts (1)
  • FindingUser (3-8)
src/core/usecases/driven/creating_token.driven.ts (1)
  • CreatingToken (3-5)
src/core/usecases/driven/invalidating_token.driven.ts (1)
  • InvalidatingToken (1-3)
src/core/usecases/token.usecase.ts (1)
  • TokenUsecase (13-42)
src/presentation/tracing.ts (1)
src/config/enviroment_config.ts (1)
  • getEnv (50-78)
test/integration/http/organization.route.test.ts (5)
src/core/config/database.ts (1)
  • Knex (26-26)
test/fixtures/user.ts (1)
  • UserFixture (13-23)
src/core/config/cache.ts (1)
  • RedisClient (6-6)
test/loading/k6.js (1)
  • token (60-60)
test/fixtures/organization.ts (1)
  • insertOrgIntoDatabase (9-29)
test/unit/providers/mfa_code.repository.test.ts (4)
src/core/config/cache.ts (1)
  • RedisClient (6-6)
src/core/services/uuid.service.ts (1)
  • UuidService (3-8)
src/core/services/code.service.ts (1)
  • CodeService (3-14)
src/core/providers/mfa_code.repository.ts (1)
  • MFACodeRepository (25-73)
test/unit/providers/user.repository.test.ts (3)
test/fixtures/generators.ts (1)
  • passwordGenerator (39-51)
test/fixtures/user.ts (1)
  • insertUserIntoDatabase (25-52)
test/fixtures/user_info.ts (1)
  • insertUserInfoIntoDatabase (12-35)
src/core/index.ts (6)
src/config/enviroment_config.ts (1)
  • getEnv (50-78)
src/core/usecases/driven/invalidating_token.driven.ts (1)
  • InvalidatingToken (1-3)
src/core/usecases/driven/creating_token.driven.ts (1)
  • CreatingToken (3-5)
src/core/usecases/login.usecase.ts (2)
  • login (25-61)
  • Login (17-62)
src/core/usecases/organization.usecase.ts (1)
  • OrganizationUseCase (38-126)
src/core/usecases/token.usecase.ts (1)
  • TokenUsecase (13-42)
src/presentation/http/routes/login.route.ts (1)
src/core/index.ts (1)
  • getCore (50-186)
test/fixtures/user.ts (1)
test/fixtures/generators.ts (1)
  • passwordGenerator (39-51)
src/presentation/http/middlewares/trace.ts (1)
src/config/enviroment_config.ts (1)
  • getEnv (50-78)
src/presentation/http/routes/mfa.route.ts (1)
src/core/index.ts (1)
  • getCore (50-186)
src/core/providers/organization.repository.ts (1)
src/core/entities/organization.ts (1)
  • Organization (1-5)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis

"joi": "17.13.3",
"jsonwebtoken": "9.0.2",
"dotenv": "17.2.3",
"express": "5.2.1",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Express.js 5 breaking changes from Express 4 migration guide

💡 Result:

Here are the main breaking changes when migrating from Express 4 → Express 5 (summary of the official migration guide):

  1. Removed / changed APIs
  • app.del() removed — use app.delete(). [1]
  • app.param(fn) and router.param(fn) signatures removed; leading-colon name in app.param(name, fn) deprecated. [1]
  • req.param(name) removed. [1]
  • res.json(obj, status) signature removed (use res.status(...).json(...)). [1]
  • res.sendfile() renamed to res.sendFile() and uses mime-types (several Content-Type values changed). [1]
  • Pluralized accept* methods removed: use req.acceptsCharsets(), req.acceptsEncodings(), req.acceptsLanguages(). [1]
  • express.static.mime no longer exported; use mime-types. [1]
  1. Path matching / routing changes
  • Wildcard * must be named (use /*splat or /{*splat}); optional ? in path strings no longer supported — use brace syntax. [1]
  1. Behavior / defaults changed
  • express.urlencoded() now defaults extended: false. [1]
  • express.static dotfiles option now defaults to "ignore" (dotfiles served by default in v4). [1]
  • req.body is undefined when body not parsed (was {} in v4). [1]
  • req.query is now a getter (not writable); default query parser changed to "simple". [1]
  • req.host retains port now (v4 stripped port). [1]
  • res.clearCookie ignores maxAge/expires options. [1]
  • res.status only accepts integers 100–999 and errors on non-integers. [1]
  • res.vary throws when field argument is missing (was console warning). [1]
  • app.listen callback now receives an error on server 'error' events instead of throwing. [1]
  • app.router exists again as reference to base router. [1]
  1. Platform / runtime
  • Minimum Node.js requirement raised (Node 18+). [2]

Notes:

  • The Express team provides codemods to automate many changes. Test your app and run the official codemods linked in the migration guide. [1]

Sources: Express official “Migrating to Express 5” and v5 release notes. [1][2]

References
[1] Express — Migrating to Express 5 (official guide).
[2] Express — v5 release announcement / requirements.


Express 5.x includes significant breaking changes from Express 4.x.

Key breaking changes to address include:

  • Removed methods: app.del() (use app.delete()), req.param(), pluralized accept* methods
  • Modified signatures: res.json(obj, status)res.status(...).json(...), res.sendfile()res.sendFile()
  • Routing changes: Wildcard * must be named (e.g., /*splat), optional ? syntax no longer supported
  • Behavior changes: express.urlencoded() defaults to extended: false, express.static now ignores dotfiles by default, req.query is now read-only, req.body is undefined (not {}) when not parsed
  • Runtime requirement: Node.js 18+ is now required

Review all route handlers, middleware, and request/response usage for compatibility. The Express team provides codemods to automate many migrations.

🤖 Prompt for AI Agents
In package.json around line 42, Express is pinned to 5.2.1 but our codebase
likely uses Express 4.x APIs; update code for Express 5 compatibility or revert
to a 4.x release. Either: (A) change package.json to an Express 4.x compatible
version to avoid breaking changes, or (B) migrate the codebase: replace
app.del() with app.delete(), remove req.param() usages, update res.json(obj,
status) to res.status(...).json(...), change res.sendfile() to res.sendFile(),
update wildcard routes to named params (e.g., /*splat), stop using optional ?
routing syntax, explicitly set express.urlencoded({ extended: true/false }) as
needed, adjust express.static options for dotfiles if required, treat req.query
as read-only and ensure body parsers are registered so req.body is not
undefined, and ensure package.json engines or CI use Node.js 18+. Run the
Express 5 codemods to automate changes and run full tests to validate behavior.

Comment on lines 146 to 153
const grandParentRow = await this.database<OrganizationRow>(
'organization'
).where('id', parent.parentOrganizationId)
const grandParent: Organization = {
id: grandParentRow[0].id,
name: grandParentRow[0].name,
parentOrganizationId: grandParentRow[0].parent_organization_id,
}
'organization'
).where('id', parent.parentOrganizationId),
grandParent: Organization = {
id: grandParentRow[0].id,
name: grandParentRow[0].name,
parentOrganizationId: grandParentRow[0].parent_organization_id,
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing existence check for grandParentRow before array access.

If the database query returns an empty array (e.g., due to data inconsistency or a race condition where the grandparent was deleted), accessing grandParentRow[0].id will cause a runtime error.

Apply this diff to add defensive error handling:

     const grandParentRow = await this.database<OrganizationRow>(
         'organization'
-      ).where('id', parent.parentOrganizationId),
-      grandParent: Organization = {
+      ).where('id', parent.parentOrganizationId)
+    if (grandParentRow.length === 0) {
+      throw new FindingOrganizationErrors(
+        FindingOrganizationErrorsTypes.ORGANIZATION_NOT_FOUND
+      )
+    }
+    const grandParent: Organization = {
         id: grandParentRow[0].id,
         name: grandParentRow[0].name,
         parentOrganizationId: grandParentRow[0].parent_organization_id,
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const grandParentRow = await this.database<OrganizationRow>(
'organization'
).where('id', parent.parentOrganizationId)
const grandParent: Organization = {
id: grandParentRow[0].id,
name: grandParentRow[0].name,
parentOrganizationId: grandParentRow[0].parent_organization_id,
}
'organization'
).where('id', parent.parentOrganizationId),
grandParent: Organization = {
id: grandParentRow[0].id,
name: grandParentRow[0].name,
parentOrganizationId: grandParentRow[0].parent_organization_id,
}
const grandParentRow = await this.database<OrganizationRow>(
'organization'
).where('id', parent.parentOrganizationId)
if (grandParentRow.length === 0) {
throw new FindingOrganizationErrors(
FindingOrganizationErrorsTypes.ORGANIZATION_NOT_FOUND
)
}
const grandParent: Organization = {
id: grandParentRow[0].id,
name: grandParentRow[0].name,
parentOrganizationId: grandParentRow[0].parent_organization_id,
}
🤖 Prompt for AI Agents
In src/core/providers/organization.repository.ts around lines 146 to 153, the
code assumes grandParentRow[0] exists and will crash if the query returns an
empty array; add a defensive existence check immediately after the DB query
(e.g., if (!grandParentRow || grandParentRow.length === 0) throw a controlled
error or return null/undefined per repository convention), then map fields from
grandParentRow[0] to the grandParent object (id, name, parent_organization_id ->
parentOrganizationId) only after confirming the row exists so you avoid runtime
array-access errors.


beforeAll(async () => {
redisContainer = await new RedisContainer().start()
redisContainer = await new RedisContainer('redis:7.0.5').start()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check Redis versions used across test files
rg -n "RedisContainer\(['\"]redis:" --type=ts

# Also check for any other redis image references
rg -n "redis:" --type=ts | head -20

# Check package.json for redis-related dependencies
cat package.json | grep -A 5 -B 5 "redis" || echo "No redis found in package.json"

# Check if there's documentation about Redis version requirements
fd -e md . -x grep -l "redis" {} \; 2>/dev/null

Repository: auth-plus/auth-plus-authentication

Length of output: 3396


🏁 Script executed:

#!/bin/bash
# Check for documentation mentioning Redis version
fd -e md . -x grep -l "redis" {} \; 2>/dev/null

# Check docker-related files
find . -name "docker*" -o -name "*compose*" 2>/dev/null | head -20

# Check README and contribution guidelines
cat README.md 2>/dev/null | grep -i redis -A 3 -B 3 || echo "No redis info in README"

# Check if there's a .env or config file specifying Redis
fd -e env . -x grep -i redis {} \; 2>/dev/null | head -10

Repository: auth-plus/auth-plus-authentication

Length of output: 122


🏁 Script executed:

cat docker-compose.yml

Repository: auth-plus/auth-plus-authentication

Length of output: 1623


Update Redis container version in tests to match docker-compose configuration.

Tests are pinned to redis:7.0.5, but docker-compose.yml specifies redis:7.4.6 for the development environment. Update all test Redis containers to redis:7.4.6 to ensure tests run against the actual development and production Redis version.

Affected test files:

  • test/integration/http/logout.route.test.ts
  • test/integration/http/login.route.test.ts
  • test/integration/http/user.route.test.ts
  • test/integration/http/organization.route.test.ts
  • test/integration/http/reset_password.route.test.ts
  • test/integration/http/mfa.route.test.ts
  • test/unit/providers/mfa_code.repository.test.ts
  • test/unit/providers/mfa_choose.repository.test.ts
🤖 Prompt for AI Agents
In test/integration/http/logout.route.test.ts around line 12, change the
RedisContainer image tag from 'redis:7.0.5' to 'redis:7.4.6' to match
docker-compose; do the same replacement in the other affected test files listed
(test/integration/http/login.route.test.ts,
test/integration/http/user.route.test.ts,
test/integration/http/organization.route.test.ts,
test/integration/http/reset_password.route.test.ts,
test/integration/http/mfa.route.test.ts,
test/unit/providers/mfa_code.repository.test.ts,
test/unit/providers/mfa_choose.repository.test.ts), and then run the test suite
to verify everything starts correctly with redis:7.4.6.

Copy link

@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: 1

🧹 Nitpick comments (6)
src/core/usecases/reset_password.usecase.ts (1)

41-42: Consider separate declarations for clarity.

The comma-separated variable declarations are valid but could be more readable with separate const statements:

-      const email = await this.findingResetPassword.findByHash(hash),
-        user = await this.findingUser.findByEmail(email)
+      const email = await this.findingResetPassword.findByHash(hash)
+      const user = await this.findingUser.findByEmail(email)
test/unit/usecases/reset_password.usecase.test.ts (1)

16-17: Consider separate declarations for consistency and clarity.

Similar to the main code, these comma-separated declarations could be split for improved readability.

-  const hash = casual.uuid,
-    userId = casual.uuid,
-    user: User = {
+  const hash = casual.uuid
+  const userId = casual.uuid
+  const user: User = {
src/core/providers/notification.provider.ts (2)

73-87: Async handling in sendCodeByStrategy is improved; consider explicit GA case

Awaiting sendCodeByEmail and sendCodeByPhone is a good fix — callers now reliably wait for completion and see errors from the underlying produce calls.

For readability and future-proofing, you might consider handling Strategy.GA explicitly instead of using the default branch for GA and any future strategies. That would avoid accidentally throwing GA_SENT_CODE if a new strategy is added but this switch isn’t updated.

   switch (strategy) {
     case Strategy.EMAIL:
       await this.sendCodeByEmail(userId, code)
       break
     case Strategy.PHONE:
       await this.sendCodeByPhone(userId, code)
       break
+    case Strategy.GA:
+      throw new SendingMfaCodeErrors(SendingMfaCodeErrorsTypes.GA_SENT_CODE)
     default:
-      throw new SendingMfaCodeErrors(SendingMfaCodeErrorsTypes.GA_SENT_CODE)
+      // optionally: no-op or a more generic "unknown strategy" error
+      break
   }

132-147: Align sendMfaHashByStrategy async behavior with sendCodeByStrategy

sendMfaHashByStrategy is async but never awaits or returns the calls to sendMfaHashByEmail / sendMfaHashByPhone. As a result:

  • The method resolves immediately, even if the underlying send fails or is still in flight.
  • Errors from the inner async calls can surface as unhandled rejections.

To match the improved pattern in sendCodeByStrategy and make the behavior less surprising for callers that await this method, consider:

  async sendMfaHashByStrategy(
    userId: string,
    hash: string,
    strategy: Strategy
  ): Promise<void> {
    switch (strategy) {
      case Strategy.EMAIL:
-        this.sendMfaHashByEmail(userId, hash)
-        break
+        await this.sendMfaHashByEmail(userId, hash)
+        break
      case Strategy.PHONE:
-        this.sendMfaHashByPhone(userId, hash)
-        break
+        await this.sendMfaHashByPhone(userId, hash)
+        break
      default:
        break
    }
  }
test/unit/providers/notification.provider.test.ts (2)

10-14: Test setup updates look good; consider restoring the Kafka spy

The added imports for Strategy and SendingMfaHashErrorsTypes align with the new test cases, and pinning PostgreSqlContainer to postgres:15.1 plus the simplified getKafka spy make the environment more deterministic and easier to reason about.

One small improvement: since jest.spyOn(kafka, 'getKafka') is set up in beforeAll, you may want to restore it in afterAll (or use jest.restoreAllMocks() there) to avoid leaking this mock into other test files that might rely on the real implementation.

Also applies to: 19-32


99-109: New GA and hash error tests provide useful coverage; consider adding strategy-hash tests

The new tests:

  • should fail when send code by GA (expecting SendingMfaCodeErrorsTypes.GA_SENT_CODE),
  • should fail when send hash by email but user not found (expecting USER_EMAIL_HASH_NOT_FOUND), and
  • should fail when send hash by Phone (expecting USER_PHONE_HASH_NOT_FOUND),

correctly validate the new/error paths introduced in NotificationProvider and the hash-related enums.

As a follow-up, you might also add tests around sendMfaHashByStrategy itself (EMAIL/PHONE/GA) to mirror the sendCodeByStrategy coverage and catch regressions in that dispatcher logic.

Also applies to: 111-117, 119-125

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4513276 and 59f3e7d.

📒 Files selected for processing (8)
  • coverage/lcov.info (44 hunks)
  • src/core/providers/notification.provider.ts (2 hunks)
  • src/core/services/uuid.service.ts (1 hunks)
  • src/core/usecases/driven/sending_mfa_code.driven.ts (1 hunks)
  • src/core/usecases/reset_password.usecase.ts (2 hunks)
  • test/unit/providers/notification.provider.test.ts (2 hunks)
  • test/unit/usecases/reset_password.usecase.test.ts (1 hunks)
  • test/unit/usecases/token.usecase.test.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • coverage/lcov.info
  • test/unit/usecases/token.usecase.test.ts
  • src/core/services/uuid.service.ts
🧰 Additional context used
🧬 Code graph analysis (2)
src/core/providers/notification.provider.ts (1)
src/core/usecases/driven/sending_mfa_code.driven.ts (1)
  • SendingMfaCodeErrors (19-24)
test/unit/usecases/reset_password.usecase.test.ts (8)
src/core/entities/user.ts (1)
  • User (1-6)
src/core/usecases/driven/creating_reset_password.driven.ts (1)
  • CreatingResetPassword (1-3)
src/core/providers/reset_password.repository.ts (1)
  • ResetPasswordRepository (10-35)
src/core/usecases/driven/sending_reset_email.driven.ts (1)
  • SendingResetEmail (1-3)
src/core/providers/notification.provider.ts (1)
  • NotificationProvider (19-169)
src/core/usecases/driven/finding_reset_password.driven.ts (1)
  • FindingResetPassword (1-3)
src/core/providers/user.repository.ts (1)
  • UserRepository (35-247)
src/core/usecases/reset_password.usecase.ts (1)
  • ResetPasswordUseCase (18-51)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (4)
src/core/usecases/reset_password.usecase.ts (1)

32-32: Good improvement: awaiting the email operation.

Changing from fire-and-forget to awaited ensures the email-sending operation completes and any errors are properly caught by the try-catch block.

src/core/usecases/driven/sending_mfa_code.driven.ts (1)

13-17: Enum extension for GA_SENT_CODE looks consistent

Adding GA_SENT_CODE to SendingMfaCodeErrorsTypes is type-safe and integrates cleanly with SendingMfaCodeErrors. Downstream usage in NotificationProvider and tests makes the intent clear.

src/core/providers/notification.provider.ts (1)

149-155: RESET_PASSWORD payload shorthand is fine

Using object property shorthand for { email, hash } keeps sendEmail consistent with other producers and has no behavioral impact.

test/unit/providers/notification.provider.test.ts (1)

53-60: Refactored email/phone tests remain clear and correct

The refactoring to chained const declarations doesn’t change behavior, and the tests for:

  • successful email send,
  • email user not found,
  • successful SMS send, and
  • missing phone,

still correctly exercise NotificationProvider’s email/phone code paths and the corresponding SendingMfaCodeErrorsTypes values.

Also applies to: 65-67, 72-76, 82-87, 91-97

@AndrewHanasiro AndrewHanasiro merged commit cea5cc4 into main Dec 10, 2025
4 of 7 checks passed
@AndrewHanasiro AndrewHanasiro deleted the feature/update-package branch December 10, 2025 00:17
Copy link

@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: 7

Caution

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

⚠️ Outside diff range comments (4)
test/loading/k6.js (1)

47-61: Guard JSON.parse with a status check to avoid brittle failures

JSON.parse(resLogin.body) runs before verifying resLogin.status, so a failed or non‑JSON response will throw and abort the whole script before the check runs.

Consider checking the status first and only parsing on success, e.g.:

-  const resLogin = http.post(
+  const resLogin = http.post(
@@
-  )
-  const token = JSON.parse(resLogin.body).token
-  check(resLogin, { 'Login status was 200': (r) => r.status == 200 })
+  )
+  const loginOk = check(resLogin, {
+    'Login status was 200': (r) => r.status === 200,
+  })
+  if (!loginOk) {
+    throw new Error(`Login failed with status ${resLogin.status}`)
+  }
+  const token = JSON.parse(resLogin.body).token
test/integration/http/user.route.test.ts (1)

83-83: redis.del('*') does not delete keys by pattern.

Same issue as other integration tests. Use flushDb() to clear the cache.

  beforeEach(async () => {
-   redis.del('*')
+   await redis.flushDb()
  })
test/integration/http/reset_password.route.test.ts (1)

84-84: redis.del('*') does not delete keys by pattern.

Same issue as other integration tests. Use flushDb() to clear the cache.

  beforeEach(async () => {
-   redis.del('*')
+   await redis.flushDb()
  })
test/integration/http/organization.route.test.ts (1)

20-35: Redis cache cleanup needs correction

The container setup and Redis client wiring look solid. However, cache cleanup in beforeEach is incorrect:

  • redis.del('*') deletes only the literal key "*", not all keys. It does not clear the cache between tests.
  • Even if it worked, the operation is not awaited, so cleanup may not complete before the next test starts.

Use await redis.flushDb() instead to clear the current database asynchronously:

beforeEach(async () => {
  await database('organization').del()
-  redis.del('*')
+  await redis.flushDb()
})

This ensures deterministic test isolation and prevents cross-test cache interference.

Also applies to: 60-68, 82-85

♻️ Duplicate comments (2)
package.json (1)

42-42: ⚠️ Express 5.2.1 requires extensive codebase verification for breaking changes.

Express 5 maintains the same basic API as Express 4, but there are changes that break compatibility; applications built with Express 4 might not work if updated to Express 5. Key breaking changes include removal of res.json(obj, status) signature (use res.status(status).json(obj) instead), changed express.static dotfiles default from served to "ignore", and routing changes using [email protected] that remove sub-expression regex patterns for security.

This is a duplicate of a previously flagged critical issue. Verify full test suite passes and review route handlers, middleware, and request/response usage for compatibility before merge.

test/unit/usecases/reset_password.usecase.test.ts (1)

28-101: Error scenario test coverage still missing.

While test coverage for the recover method has been added, the test suite still lacks error scenario tests for both forget and recover methods (e.g., when dependencies throw errors). Both methods catch errors and throw custom error types (ForgetPasswordErrors and RecoverPasswordErrors) that should be validated.

🧹 Nitpick comments (7)
test/unit/services/password.services.test.ts (1)

8-8: Consider consistent property access style.

This line uses destructuring (const { password } = casual), while Lines 16-17 use direct property access (casual.full_name, casual.email). For consistency and readability, consider using the same approach throughout the file.

Apply this diff to make the style consistent with the rest of the file:

-    const { password } = casual
+    const password = casual.password

Alternatively, update Lines 16-17 to also use destructuring for consistency.

test/loading/k6.js (1)

47-79: Avoid unnecessary async/await and meaningless Promise.all

setup and the default export are marked async, but there are no real async operations; listUser is an array of response bodies (strings), so await Promise.all(listUser) is effectively a no‑op and can confuse readers.

You can simplify and better match k6’s synchronous execution model like this:

-export async function setup() {
+export function setup() {
@@
-  const listUser = USERS.map((u) => {
-    const resUser = http.post(`${BASE_URL}/user`, JSON.stringify(u), {
-      headers: {
-        'Content-Type': 'application/json',
-        Authorization: `Bearer ${token}`,
-      },
-    })
-    check(resUser, { 'Create status was 200': (r) => r.status == 200 })
-    return resUser.body
-  })
-  await Promise.all(listUser)
+  USERS.forEach((u) => {
+    const resUser = http.post(`${BASE_URL}/user`, JSON.stringify(u), {
+      headers: {
+        'Content-Type': 'application/json',
+        Authorization: `Bearer ${token}`,
+      },
+    })
+    check(resUser, { 'Create status was 200': (r) => r.status == 200 })
+  })
 }
 
-export default async function () {
+export default function () {
   const resHealth = http.get(`${BASE_URL}/health`)
   check(resHealth, { 'health status is 200': (r) => r.status == 200 })
   sleep(1)
 }

If you’re relying on any newer k6 features that explicitly support async/await, double‑check the current k6 docs to ensure this refactor aligns with your runtime expectations.

test/unit/providers/mfa_choose.repository.test.ts (2)

17-23: Pinned Redis image improves test determinism

Using new RedisContainer('redis:7.0.5') is a good move for keeping the test environment stable across machines/CI. If other tests also hardcode the same image string, consider centralizing this tag in a shared test config to avoid divergence later, but not required for this PR.


30-50: MFAChooseRepository tests correctly exercise UUID and Redis behavior

Both tests are well-structured:

  • create test correctly stubs UuidService.generateHash(), verifies it's called once, and asserts the returned hash.
  • findByHash seeds Redis directly, ensures generateHash() is never called, and validates the deserialized payload.

This gives good coverage of the happy paths for both methods and aligns with the updated UuidService implementation. If you want to DRY things up later, you could extract a small helper to construct MFAChooseRepository(redis) to reduce duplication across tests.

src/presentation/tracing.ts (3)

19-21: Consider removing the empty registerInstrumentations call.

Since instrumentations are now configured directly in the NodeSDK setup (line 33), this empty registration appears redundant and can be removed for clarity.

Apply this diff to remove the dead code:

-// Optionally register instrumentation libraries
-registerInstrumentations({
-  instrumentations: [],
-})
-

23-26: Consider sourcing the service version dynamically.

The version is currently hardcoded as '0.1.0'. For better maintainability, consider reading it from package.json or an environment variable to keep it in sync with releases.

Example approach:

import packageJson from '../../package.json'

const resource = resourceFromAttributes({
  [ATTR_SERVICE_NAME]: getEnv().app.name,
  [ATTR_SERVICE_VERSION]: packageJson.version,
})

36-36: Add error handling for SDK initialization.

Consider adding error handling around sdk.start() to catch and log initialization failures. This improves observability when tracing setup encounters issues.

-sdk.start()
+sdk
+  .start()
+  .catch((error) => {
+    console.error('Error initializing OpenTelemetry SDK:', error)
+  })
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 59f3e7d and 55935d6.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (50)
  • eslint.config.mts (1 hunks)
  • package.json (2 hunks)
  • src/core/config/cache.ts (1 hunks)
  • src/core/index.ts (0 hunks)
  • src/core/providers/mfa.repository.ts (2 hunks)
  • src/core/providers/organization.repository.ts (2 hunks)
  • src/core/providers/user.repository.ts (5 hunks)
  • src/core/usecases/login.usecase.ts (1 hunks)
  • src/core/usecases/mfa.usecase.ts (0 hunks)
  • src/core/usecases/mfa_code.usecase.ts (0 hunks)
  • src/core/usecases/reset_password.usecase.ts (1 hunks)
  • src/core/usecases/token.usecase.ts (0 hunks)
  • src/core/usecases/user.usecase.ts (2 hunks)
  • src/presentation/http/middlewares/jwt.ts (3 hunks)
  • src/presentation/http/middlewares/trace.ts (1 hunks)
  • src/presentation/http/routes/login.route.ts (2 hunks)
  • src/presentation/http/routes/logout.route.ts (1 hunks)
  • src/presentation/http/routes/mfa.route.ts (1 hunks)
  • src/presentation/http/routes/organization.route.ts (1 hunks)
  • src/presentation/http/routes/reset_password.route.ts (1 hunks)
  • src/presentation/http/routes/user.route.ts (1 hunks)
  • src/presentation/tracing.ts (2 hunks)
  • test/fixtures/generators.ts (1 hunks)
  • test/fixtures/organization.ts (1 hunks)
  • test/fixtures/user.ts (2 hunks)
  • test/fixtures/user_info.ts (1 hunks)
  • test/integration/http/login.route.test.ts (7 hunks)
  • test/integration/http/logout.route.test.ts (2 hunks)
  • test/integration/http/mfa.route.test.ts (3 hunks)
  • test/integration/http/organization.route.test.ts (2 hunks)
  • test/integration/http/reset_password.route.test.ts (3 hunks)
  • test/integration/http/user.route.test.ts (2 hunks)
  • test/loading/k6.js (1 hunks)
  • test/unit/providers/mfa.repository.test.ts (3 hunks)
  • test/unit/providers/mfa_choose.repository.test.ts (3 hunks)
  • test/unit/providers/mfa_code.repository.test.ts (2 hunks)
  • test/unit/providers/notification.provider.test.ts (2 hunks)
  • test/unit/providers/organization.repository.test.ts (2 hunks)
  • test/unit/providers/user.repository.test.ts (4 hunks)
  • test/unit/services/password.services.test.ts (1 hunks)
  • test/unit/services/uuid.services.test.ts (1 hunks)
  • test/unit/usecases/login.usecase.test.ts (2 hunks)
  • test/unit/usecases/logout.usecase.test.ts (1 hunks)
  • test/unit/usecases/mfa.usecase.test.ts (2 hunks)
  • test/unit/usecases/mfa_choose.usecase.test.ts (2 hunks)
  • test/unit/usecases/mfa_code.usecase.test.ts (3 hunks)
  • test/unit/usecases/organization.usecase.test.ts (2 hunks)
  • test/unit/usecases/reset_password.usecase.test.ts (2 hunks)
  • test/unit/usecases/token.usecase.test.ts (2 hunks)
  • test/unit/usecases/user.usecase.test.ts (4 hunks)
💤 Files with no reviewable changes (4)
  • src/core/usecases/mfa.usecase.ts
  • src/core/usecases/mfa_code.usecase.ts
  • src/core/index.ts
  • src/core/usecases/token.usecase.ts
🚧 Files skipped from review as they are similar to previous changes (21)
  • test/unit/services/uuid.services.test.ts
  • src/core/providers/mfa.repository.ts
  • test/unit/usecases/logout.usecase.test.ts
  • test/unit/usecases/mfa_code.usecase.test.ts
  • test/fixtures/generators.ts
  • src/core/providers/user.repository.ts
  • test/unit/providers/mfa_code.repository.test.ts
  • test/unit/usecases/token.usecase.test.ts
  • src/presentation/http/middlewares/trace.ts
  • test/unit/usecases/organization.usecase.test.ts
  • src/core/usecases/login.usecase.ts
  • eslint.config.mts
  • test/integration/http/logout.route.test.ts
  • src/core/usecases/user.usecase.ts
  • test/unit/usecases/mfa_choose.usecase.test.ts
  • test/fixtures/user.ts
  • src/presentation/http/routes/login.route.ts
  • src/core/providers/organization.repository.ts
  • src/presentation/http/routes/organization.route.ts
  • test/unit/usecases/mfa.usecase.test.ts
  • test/unit/providers/mfa.repository.test.ts
🧰 Additional context used
🧬 Code graph analysis (11)
test/integration/http/user.route.test.ts (3)
test/fixtures/user.ts (1)
  • UserFixture (13-23)
src/core/config/cache.ts (1)
  • RedisClient (5-5)
test/loading/k6.js (1)
  • token (60-60)
test/integration/http/login.route.test.ts (2)
src/core/config/cache.ts (1)
  • RedisClient (5-5)
test/fixtures/user.ts (1)
  • UserFixture (13-23)
test/integration/http/organization.route.test.ts (3)
test/fixtures/user.ts (1)
  • UserFixture (13-23)
src/core/config/cache.ts (1)
  • RedisClient (5-5)
test/loading/k6.js (1)
  • token (60-60)
test/unit/providers/organization.repository.test.ts (2)
src/core/entities/organization.ts (1)
  • Organization (1-5)
src/core/providers/organization.repository.ts (1)
  • OrganizationRepository (37-156)
src/presentation/tracing.ts (1)
src/config/enviroment_config.ts (1)
  • getEnv (50-78)
test/unit/providers/notification.provider.test.ts (3)
src/core/config/database.ts (1)
  • Knex (26-26)
test/fixtures/setup_migration.ts (1)
  • setupDB (4-74)
src/core/providers/notification.provider.ts (1)
  • NotificationProvider (19-169)
test/integration/http/mfa.route.test.ts (1)
src/core/config/cache.ts (1)
  • RedisClient (5-5)
test/unit/usecases/reset_password.usecase.test.ts (8)
src/core/usecases/driven/creating_reset_password.driven.ts (1)
  • CreatingResetPassword (1-3)
src/core/providers/reset_password.repository.ts (1)
  • ResetPasswordRepository (10-35)
src/core/usecases/driven/sending_reset_email.driven.ts (1)
  • SendingResetEmail (1-3)
src/core/providers/notification.provider.ts (1)
  • NotificationProvider (19-169)
src/core/usecases/driven/finding_reset_password.driven.ts (1)
  • FindingResetPassword (1-3)
src/core/usecases/driven/finding_user.driven.ts (1)
  • FindingUser (3-8)
src/core/usecases/driven/updating_user.driven.ts (1)
  • UpdatingUser (3-10)
src/core/usecases/reset_password.usecase.ts (1)
  • ResetPasswordUseCase (18-51)
src/presentation/http/middlewares/jwt.ts (2)
test/loading/k6.js (1)
  • token (60-60)
src/config/enviroment_config.ts (1)
  • getEnv (50-78)
test/unit/providers/mfa_choose.repository.test.ts (2)
src/core/services/uuid.service.ts (1)
  • UuidService (3-7)
src/core/providers/mfa_choose.repository.ts (1)
  • MFAChooseRepository (11-41)
test/integration/http/reset_password.route.test.ts (3)
test/fixtures/user.ts (1)
  • UserFixture (13-23)
src/core/config/cache.ts (1)
  • RedisClient (5-5)
test/loading/k6.js (1)
  • token (60-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (36)
test/unit/usecases/user.usecase.test.ts (3)

2-2: LGTM!

The import reordering to alphabetical order aligns with the eslint-plugin-simple-import-sort configuration mentioned in the PR objectives.


31-31: LGTM!

Using an arrow function for the describe callback is consistent with modern JavaScript conventions and the updated ESLint configuration.


131-131: LGTM!

Destructuring { phone } from casual works correctly since the casual library uses getters for value generation. The destructuring accesses the property once and stores the generated value, maintaining the same behavior as direct property access.

Also applies to: 174-174

test/unit/usecases/login.usecase.test.ts (2)

2-2: LGTM! Import ordering improvement.

The ts-mockito imports are now alphabetically sorted, aligning with the project's adoption of eslint-plugin-simple-import-sort as mentioned in the PR objectives.


29-29: LGTM! Modernized describe block syntax.

The conversion to arrow function syntax is consistent with the project-wide formatting improvements. Since the test suite doesn't rely on this context, this change is safe and improves code consistency.

package.json (4)

10-11: Lint scripts properly consolidated with ESLint then Prettier.

Aligns well with the PR objective to update lint configuration. The order (ESLint --fix first, then Prettier --write) follows best practices by allowing ESLint fixes to settle before formatting.


27-27: Node.js engine correctly updated to 24.x LTS.

Aligns with PR objective and current LTS versions. Ensure .nvmrc is also updated (as noted in AI summary, this appears to be done).


38-38: Verify test suite passes with major dependency version bumps.

Multiple critical dependencies are being updated to major versions: bcrypt 6.0.0, jsonwebtoken 9.0.3, helmet 8.1.0, pg 8.16.3, redis 5.10.0, winston 3.19.0, jest 30.2.0, typescript 5.9.3, and typescript-eslint 8.49.0. Each major version bump can introduce breaking changes. The consolidated dependency updates are appropriate for a package refresh PR, but verification is critical.

Run the full test suite (npm run test and npm run stryker) to confirm all tests pass with the new dependency versions before merge. Additionally, spot-check any usage of jsonwebtoken and bcrypt APIs against the latest docs to ensure compatibility.

Also applies to: 44-44, 45-45, 49-49, 51-51, 53-53, 79-79, 86-86, 92-92, 95-95, 96-96


29-55: UUID npm package has been properly removed from dependencies.

The uuid npm package is confirmed absent from package.json. The UuidService references appearing in the codebase (imports in repositories and exports in core/index.ts) are for an internal custom service class, not the external npm package. The dependency removal aligns with the PR objective and is complete.

src/core/config/cache.ts (1)

1-5: LGTM on simplified import and type alias.

Using ReturnType<typeof createClient> is more maintainable—it automatically stays in sync with the redis library's return type without requiring manual updates when the library changes.

src/core/usecases/reset_password.usecase.ts (1)

32-32: LGTM!

Awaiting the email-sending operation ensures it completes before the method returns, improving error handling and reliability. This is a good change from fire-and-forget behavior.

test/unit/usecases/reset_password.usecase.test.ts (1)

28-62: LGTM!

The test correctly validates the forget flow by ensuring that only create and sendEmail are called, while recovery-related methods are not invoked.

test/loading/k6.js (1)

1-1: Import order change is safe and purely stylistic

Reordering { sleep, check } to { check, sleep } from 'k6' doesn’t affect behavior and aligns fine with typical import-sorting rules.

test/unit/providers/user.repository.test.ts (3)

8-8: LGTM! Import reordering aligns with ESLint configuration updates.

The alphabetical ordering of ts-mockito imports is consistent with the eslint-plugin-simple-import-sort mentioned in the PR objectives.


213-213: LGTM! Variable declaration improves code organization.

Declaring newPhone before the test setup improves readability and follows good practice of defining variables before use.


292-292: LGTM! Variable declaration improves code organization.

Declaring newGA before the test setup improves readability and maintains consistency with similar test patterns in this file.

test/unit/providers/mfa_choose.repository.test.ts (1)

1-8: Imports and explicit RedisClient typing look good

Reordered ts-mockito imports and the explicit RedisClient import/annotation keep things clear and consistent with the rest of the codebase. No functional concerns here.

src/presentation/tracing.ts (1)

2-7: LGTM! Clean migration to NodeSDK pattern.

The import changes correctly support the migration from manual TracerProvider setup to the recommended NodeSDK approach, including auto-instrumentations and streamlined resource construction.

test/fixtures/organization.ts (1)

14-27: Type annotation update for row is correct and consistent

row being typed as { id: string }[] matches the returning('id') usage and the later access row[0].id; no behavioral change, clearer typing.

test/fixtures/user_info.ts (1)

17-33: value generation now respects input.value and fixes precedence bug

const value = input?.value ?? (type === 'phone' ? casual.phone : casual.uuid) correctly prefers a provided input.value and only generates a fallback when it’s nullish; combined with the { id: string }[] typing for row, this aligns with how the result is used (row[0].id).

test/unit/providers/organization.repository.test.ts (2)

26-28: Explicit PostgreSQL image tag improves test reproducibility

Using new PostgreSqlContainer('postgres:15.1') pins the DB version for tests, which should make runs more deterministic, assuming this version matches what you intend to support.


229-237: Renamed grandChildOrg variable keeps cyclic check test behavior intact

The grandChildOrg object structure is unchanged and passing it to checkCyclicRelationship(rootOrg, grandChildOrg) still exercises the intended root–child–grandchild cycle scenario; this is a naming/clarity improvement only.

test/unit/providers/notification.provider.test.ts (2)

24-34: LGTM - Container image pinning and simplified mock.

Pinning the PostgreSQL container to postgres:15.1 ensures reproducible test environments. The Kafka mock simplification maintains the same behavior with cleaner syntax.


100-127: Good addition of error path coverage.

These new test cases properly cover:

  1. GA strategy rejection (which shouldn't send codes externally)
  2. Email hash sending when user not found
  3. Phone hash sending when user not found

The tests correctly verify that the provider throws the appropriate error types.

test/integration/http/mfa.route.test.ts (2)

27-35: LGTM - Container setup and Redis readiness handling.

Good improvements:

  • Explicit image tags ensure reproducible test environments
  • Redis readiness check prevents race conditions during setup
  • Extracting userId from fixture improves test readability

60-68: LGTM - Kafka mock simplification.

The inline mock object is cleaner while maintaining the same mock behavior.

test/integration/http/login.route.test.ts (2)

29-36: LGTM - Container setup and Redis readiness handling.

Consistent with other integration tests - explicit image tags and Redis readiness check.


141-142: LGTM - Clean destructuring.

Using const { phone } = casual is more idiomatic than casual.phone when the value needs to be reused.

test/integration/http/user.route.test.ts (1)

27-34: LGTM - Container setup and Redis readiness handling.

Consistent pattern with other integration tests.

test/integration/http/reset_password.route.test.ts (2)

28-35: LGTM - Container setup and Redis readiness handling.

Consistent pattern with other integration tests.


107-107: LGTM - ES6 shorthand property.

Using shorthand hash instead of hash: hash is cleaner.

src/presentation/http/routes/logout.route.ts (1)

1-7: Express import reordering only; behavior unchanged

This is just a normalization of the express import order/typing. The logout route handler and its error handling remain unchanged and correct.

src/presentation/http/routes/reset_password.route.ts (1)

1-7: Import normalization; reset‑password behavior unaffected

The express import reorder keeps the existing /forget and /recover handlers and Joi validation intact. No behavioral changes here.

src/presentation/http/routes/user.route.ts (1)

1-7: Express import cleanup for user routes

Pulling NextFunction and RequestHandler into the primary express import keeps the file consistent with other routes; handler typing and behavior are unchanged.

src/presentation/http/routes/mfa.route.ts (1)

1-7: MFA route import reordering only

The updated express import ordering is consistent with the rest of the routes; all MFA endpoints and Joi validation logic remain unchanged.

src/presentation/http/middlewares/jwt.ts (1)

1-15: JWT refactor looks solid; verify no legacy string-payload tokens exist

The changes here are coherent:

  • Constraining verification via VerifyOptions with algorithms: ['HS256'] aligns with the default algorithm used by sign when given a symmetric secret.
  • createToken explicitly sets exp and extractPayload strips standard claims (iat, exp, iss, sub, aud, jti, nbf), so callers of removeJwtAttr only see your domain fields (userId, now, etc.).

Important behavioral change to validate:

  • extractPayload now throws when verify returns a string. In jsonwebtoken, the return type is determined by what was signed: object payloads return objects, string payloads return strings. If this service previously signed any tokens with raw string payloads (rather than object payloads), those tokens will now fail when passed through removeJwtAttr.

Before deploying, confirm that all tokens in your system were signed with object payloads (as in createToken). If legacy string-payload tokens exist, either migrate them, add runtime type handling, or provide a clearer error message to identify problematic tokens.

Comment on lines +11 to +13
client = await createClient({
url: url.includes('redis') ? url : `redis://${url}`,
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Weak URL scheme detection.

url.includes('redis') matches any URL containing "redis" anywhere (e.g., my-redis-server.example.com), potentially skipping the prefix when it's actually needed. Check for the scheme prefix instead:

  client = await createClient({
-   url: url.includes('redis') ? url : `redis://${url}`,
+   url: url.startsWith('redis://') || url.startsWith('rediss://') ? url : `redis://${url}`,
  })
🤖 Prompt for AI Agents
In src/core/config/cache.ts around lines 11 to 13, the current check uses
url.includes('redis') which can falsely match hostnames and skip adding the
scheme; instead detect the actual scheme by trimming the input and checking for
known prefixes (e.g., startsWith('redis://') or startsWith('rediss://')) or by
parsing the string as a URL, and only prepend 'redis://' when no valid redis
scheme is present; update the createClient call to normalize the url
accordingly.

Comment on lines +14 to +17
.on('error', (error: Error) => {
logger.error('error on connecting:', error)
throw error
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Throwing in event handler causes unhandled exceptions.

The error event fires for both connection failures and runtime errors after connection. Throwing inside an event handler doesn't propagate to the await—it becomes an unhandled exception. For connection failures, connect() already rejects the promise.

Remove the throw and rely on connect() rejection for connection errors:

    .on('error', (error: Error) => {
      logger.error('error on connecting:', error)
-     throw error
    })

Alternatively, if you need to handle post-connection errors differently, consider using process.on('unhandledRejection', ...) or a dedicated error recovery strategy.

🤖 Prompt for AI Agents
In src/core/config/cache.ts around lines 14 to 17, the 'error' event handler
currently logs the error and then throws it, which causes unhandled exceptions
because throwing inside an event handler doesn't reject the original connect()
promise; remove the throw so the handler only logs the error (or performs
recovery) and rely on connect() to reject on connection failures; if you need to
treat post-connection runtime errors differently, replace the throw with a
dedicated recovery/reconnect strategy or register a global handler (e.g.,
process.on('unhandledRejection' / custom error recovery) ) to handle those
cases.

Comment on lines +30 to +34
const sdk = new NodeSDK({
resource,
spanProcessors: [new SimpleSpanProcessor(exporter)],
instrumentations: [getNodeAutoInstrumentations()],
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n src/presentation/tracing.ts | head -50

Repository: auth-plus/auth-plus-authentication

Length of output: 1549


🏁 Script executed:

# Search for other tracing or SDK configurations
fd -t f "tracing\|trace\|sdk" --extension ts --extension js | head -20

Repository: auth-plus/auth-plus-authentication

Length of output: 60


🏁 Script executed:

# Check if there's environment-specific configuration
grep -r "SimpleSpanProcessor\|BatchSpanProcessor" --include="*.ts" --include="*.js"

Repository: auth-plus/auth-plus-authentication

Length of output: 256


🏁 Script executed:

# Look for production-related configuration
grep -r "production\|PRODUCTION\|NODE_ENV" src/presentation/tracing.ts

Repository: auth-plus/auth-plus-authentication

Length of output: 60


🏁 Script executed:

# Check git history for this file
git log --oneline src/presentation/tracing.ts 2>/dev/null | head -10

Repository: auth-plus/auth-plus-authentication

Length of output: 103


🏁 Script executed:

# Look for any documentation or comments about tracing strategy
grep -r "SimpleSpanProcessor\|BatchSpanProcessor\|span.*processor" --include="*.md" --include="*.txt" src/ 2>/dev/null

Repository: auth-plus/auth-plus-authentication

Length of output: 60


🌐 Web query:

OpenTelemetry SimpleSpanProcessor BatchSpanProcessor production performance best practices

💡 Result:

Brief summary + production best practices:

  • Use BatchSpanProcessor in production; SimpleSpanProcessor exports each finished span immediately and is intended for debugging (high CPU/network overhead). [1][5]

  • Tune BSP core knobs (defaults shown): max_queue_size (default 2048), max_export_batch_size (default 512), scheduled_delay_millis (default 5000 ms), export_timeout_millis (default 30000 ms). Adjust based on throughput, memory, and desired visibility latency. [1][4][5]

  • Sizing guidance:

    • Increase max_queue_size for large burst tolerance (but watch memory). Decrease if you must bound memory. [1][4]
    • Set max_export_batch_size to balance network payload size vs. export frequency (larger reduces calls, but increases per-export latency/CPU). [1][4]
    • Reduce scheduled_delay_millis for fresher spans (higher export frequency → more traffic). [1][4]
  • Reliability and shutdown:

    • Always call force_flush()/shutdown() on app exit to avoid losing buffered spans. BSP buffers are in-memory and can be lost on abrupt termination. [1][5]
  • Backpressure & failures:

    • Configure export timeouts, retries/backoff, and queue limits so failures don’t cause unbounded memory growth; prefer dropping spans (load-shedding) to OOM. Use exporter helper / collector queue controls when using a Collector. [4][1]
  • Reduce volume before export:

    • Apply sampling, attribute/span filtering, and aggregation to lower telemetry volume (reduces required queue size and export work). [4]
  • Use a local/sidecar Collector (or batching at exporter) to offload exporting work from app processes and enable buffering, retry, compression. Enable OTLP compression (gzip) where supported. [4][3]

  • Monitor and profile:

    • Measure exporter latency, queue fill rate, dropped spans, and CPU/memory impact. If exporter is slow, BSP settings should be adjusted or move to a Collector to avoid tail latency. Coralogix/field reports show switching from Simple→Batch can drastically reduce CPU/memory and latency. [3][2]
  • When to use SimpleSpanProcessor:

    • Local development, debugging, CI, or when immediate visibility per-span is required and volume is tiny. Not recommended for production. [1][5]

References

  • OpenTelemetry tracing SDK (Batch & Simple processor details). [1]
  • CNCF OpenTelemetry best-practices overview. [2]
  • Coralogix / field experience on Collector performance and impact of switching to BSP. [3]
  • OpenTelemetry config / Collector best-practices (queue, compression, timeouts). [4]
  • Vendor/guide docs on Simple vs Batch and tuning knobs. [5]

SimpleSpanProcessor is not suitable for production environments.

SimpleSpanProcessor exports each span synchronously as it finishes, causing significant performance degradation under load. OpenTelemetry documentation explicitly recommends BatchSpanProcessor for production use, which batches spans and exports them asynchronously. Using SimpleSpanProcessor with ZipkinExporter (network-based) is a performance anti-pattern.

Replace with BatchSpanProcessor for production:

-import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
+import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'

 const sdk = new NodeSDK({
   resource,
-  spanProcessors: [new SimpleSpanProcessor(exporter)],
+  spanProcessors: [new BatchSpanProcessor(exporter)],
   instrumentations: [getNodeAutoInstrumentations()],
 })

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/presentation/tracing.ts around lines 30 to 34, the code uses
SimpleSpanProcessor which exports spans synchronously and is unsuitable for
production; replace it with BatchSpanProcessor (and import it) so spans are
batched and exported asynchronously via the ZipkinExporter, and instantiate
NodeSDK with spanProcessors: [new BatchSpanProcessor(exporter)]; optionally
configure BatchSpanProcessor parameters (scheduledDelayMillis,
maxExportBatchSize, maxQueueSize, exportTimeoutMillis) to appropriate
production-tuned values.

beforeEach(async () => {
await database('multi_factor_authentication').del()
await database('user_info').del()
redis.del('*')
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

redis.del('*') does not delete keys by pattern.

Same issue as in mfa.route.test.ts. Use flushDb() to clear the cache between tests.

  beforeEach(async () => {
    await database('multi_factor_authentication').del()
    await database('user_info').del()
-   redis.del('*')
+   await redis.flushDb()
  })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
redis.del('*')
beforeEach(async () => {
await database('multi_factor_authentication').del()
await database('user_info').del()
await redis.flushDb()
})
🤖 Prompt for AI Agents
In test/integration/http/login.route.test.ts around line 82, the test calls
redis.del('*') which does not delete keys by pattern; replace this with await
redis.flushDb() (or the appropriate async flushDb call on your redis client) to
clear the test database between tests, and ensure the call is awaited so cleanup
completes before proceeding.

beforeEach(async () => {
await database('multi_factor_authentication').del()
await database('user_info').del()
redis.del('*')
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

redis.del('*') does not delete keys by pattern.

The Redis DEL command requires explicit key names, not glob patterns. This call likely returns 0 and deletes nothing. To clear keys, use flushDb() or retrieve keys first.

  beforeEach(async () => {
    await database('multi_factor_authentication').del()
    await database('user_info').del()
-   redis.del('*')
+   await redis.flushDb()
  })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
redis.del('*')
beforeEach(async () => {
await database('multi_factor_authentication').del()
await database('user_info').del()
await redis.flushDb()
})
🤖 Prompt for AI Agents
In test/integration/http/mfa.route.test.ts around line 78, the call
redis.del('*') is incorrect because DEL does not accept glob patterns and will
not remove matching keys; replace it with a proper Redis clear operation —
either call redis.flushDb() to clear the test DB, or first fetch matching keys
(e.g., redis.keys or scan) and then pass the explicit key list to redis.del so
the keys are actually deleted before the test.


beforeAll(async () => {
pgSqlContainer = await new PostgreSqlContainer().start()
pgSqlContainer = await new PostgreSqlContainer('postgres:15.1').start()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

PostgreSQL 15.1 security vulnerabilities CVE

💡 Result:

Which CVEs affect PostgreSQL 15.1 (summary)

  • PostgreSQL’s official security tracker (filterable to major version 15) lists all CVEs and the minor release in which each was fixed — use that to see which CVEs apply to 15.1 and which minor release fixes them. [1]

  • Third‑party aggregated lists (example: CVE Details) show the CVEs reported against PostgreSQL 15.1 (22 items on that page). For a per‑CVE view you can open each entry to see description, severity and affected versions. [2]

Recommendation: upgrade 15.1 to the latest 15.x minor release for your platform (the PostgreSQL project releases security fixes only in minor updates). See the PostgreSQL security page for the authoritative, up‑to‑date CVE/fix mapping and individual CVE details. [1][2]

Sources:
[1] PostgreSQL — Security information / Known vulnerabilities (PostgreSQL 15 filter).
[2] CVE Details — PostgreSQL 15.1 vulnerability list.


🌐 Web query:

PostgreSQL 15 latest stable version 2025

💡 Result:

The latest PostgreSQL 15 stable minor release is PostgreSQL 15.15, released November 13, 2025. [1][2]

Sources:
[1] PostgreSQL 15.15 release notes (docs).
[2] PostgreSQL project release announcement (Nov 13, 2025).


Upgrade PostgreSQL container to version 15.15.

PostgreSQL 15.1 has 22 known security vulnerabilities. Upgrade to PostgreSQL 15.15 (the latest stable version in the 15.x series, released November 2025) to patch these CVEs while maintaining reproducibility.

🤖 Prompt for AI Agents
In test/unit/providers/user.repository.test.ts around line 31 the test starts a
PostgreSQL container pinned to image 'postgres:15.1' which has known CVEs;
update the image tag to 'postgres:15.15' to use the patched 15.x release. Change
the new PostgreSqlContainer(...) invocation to reference 'postgres:15.15' and
run the tests to verify compatibility; if any container startup settings or
tests rely on image-specific behavior, adjust them accordingly.

Comment on lines +96 to +100
verify(mockCreatingResetPassword.create(anything())).never()
verify(mockSendingResetEmail.sendEmail(anything(), anything())).never()
verify(mockFindingResetPassword.findByHash(anything())).never()
verify(mockFindingUser.findByEmail(anything())).never()
verify(mockUpdatingUser.updatePassword(anything(), anything())).never()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical test bug: Incorrect verifications for recover flow.

The test verifies that findByHash, findByEmail, and updatePassword were never called, but according to the recover implementation, these methods should be called once. This test will pass even if the recover method does nothing, defeating its purpose.

Apply this diff to fix the verifications:

     verify(mockCreatingResetPassword.create(anything())).never()
     verify(mockSendingResetEmail.sendEmail(anything(), anything())).never()
-    verify(mockFindingResetPassword.findByHash(anything())).never()
-    verify(mockFindingUser.findByEmail(anything())).never()
-    verify(mockUpdatingUser.updatePassword(anything(), anything())).never()
+    verify(mockFindingResetPassword.findByHash(hash)).once()
+    verify(mockFindingUser.findByEmail(user.email)).once()
+    verify(mockUpdatingUser.updatePassword(user, newPassword)).once()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
verify(mockCreatingResetPassword.create(anything())).never()
verify(mockSendingResetEmail.sendEmail(anything(), anything())).never()
verify(mockFindingResetPassword.findByHash(anything())).never()
verify(mockFindingUser.findByEmail(anything())).never()
verify(mockUpdatingUser.updatePassword(anything(), anything())).never()
verify(mockCreatingResetPassword.create(anything())).never()
verify(mockSendingResetEmail.sendEmail(anything(), anything())).never()
verify(mockFindingResetPassword.findByHash(hash)).once()
verify(mockFindingUser.findByEmail(user.email)).once()
verify(mockUpdatingUser.updatePassword(user, newPassword)).once()
🤖 Prompt for AI Agents
In test/unit/usecases/reset_password.usecase.test.ts around lines 96 to 100, the
test incorrectly asserts that findByHash, findByEmail, and updatePassword are
never called; change the verifications so that
mockFindingResetPassword.findByHash(...), mockFindingUser.findByEmail(...), and
mockUpdatingUser.updatePassword(...) are verified to have been called once (use
.once()), while keeping mockCreatingResetPassword.create(...) and
mockSendingResetEmail.sendEmail(...) verified as never called.

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.

3 participants