Skip to content

Conversation

@pranalidhanavade
Copy link
Contributor

@pranalidhanavade pranalidhanavade commented Oct 9, 2025

What

  • Refactor: fetch api-key from .env and call agent token API.
  • Removed token extraction logic from container logs.

Summary by CodeRabbit

  • Refactor

    • Provisioning/startup flows no longer extract, print, save, or return API tokens; responses now include only the agent endpoint and endpoint handling simplified/validated.
  • New Features

    • Added DB alerting for ledger-null events with automated alert emails and retry logic.
    • Added DB trigger to notify on ledger-null updates.
  • Chores

    • dotenv enabled; sample/demo env cleaned of token path and new DB alert env vars added.
    • Email payload accepts one or multiple recipients.

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

@coderabbitai
Copy link

coderabbitai bot commented Oct 9, 2025

Walkthrough

Removed AFJ token capture, extraction, file creation, printing, and cleanup across provisioning scripts and services; agent endpoint (CONTROLLER_ENDPOINT) is now the single persisted artifact. Added DB-alerting feature (Postgres trigger, listener, NATS email alert flow), updated Prisma module wiring, tweaked DTOs/constants, and bumped pg dependency.

Changes

Cohort / File(s) Summary of Changes
Provisioning scripts
apps/agent-provisioning/AFJ/scripts/start_agent.sh, apps/agent-provisioning/AFJ/scripts/docker_start_agent.sh, apps/agent-provisioning/AFJ/scripts/fargate.sh, apps/agent-provisioning/AFJ/scripts/start_agent_ecs.sh
Removed log-parsing/token-extraction loops and all creation/writing/printing/deletion of token JSON files; scripts now produce/read only endpoint JSON and continue provisioning without token persistence.
Provisioning service
apps/agent-provisioning/src/agent-provisioning.service.ts
Removed agent-token file logic; consolidated to check/read endpoint JSON, parse/validate CONTROLLER_ENDPOINT, and return only agentEndPoint; added explicit JSON parse and NotFound/validation error paths.
Agent service
apps/agent-service/src/agent-service.service.ts
Switched to obtaining base token via getBaseAgentToken(agentEndPoint, apiKey from AGENT_API_KEY); removed AFJ token-file cleanup and fs usage.
Common utilities
libs/common/src/common.service.ts, libs/common/src/common.constant.ts, libs/common/src/dtos/email.dto.ts, libs/common/src/resend-helper-file.ts
Added dotenv.config() at module load; getBaseAgentToken includes Authorization: Bearer <AGENT_API_KEY> header; added AFFECTED_RECORDS_THRESHOLD_PERCENTAGE_FOR_DB_ALERT = 30 constant; EmailDto.emailTo now `string
Env samples
.env.demo, .env.sample
Removed AFJ_AGENT_TOKEN_PATH entries and added HIDE_EXPERIMENTAL_OIDC_CONTROLLERS, DB_ALERT_ENABLE, and DB_ALERT_EMAILS entries (and blank/related lines).
API gateway / Utilities (DB alerting)
apps/api-gateway/src/main.ts, apps/api-gateway/src/utilities/utilities.service.ts
main.ts: enhanced startup logs and conditional DB_ALERT_ENABLE message. utilities.service.ts (api-gateway): added PostgreSQL client integration, LISTEN on ledger_null, handler to compute affected records %, and publish alert payload to NATS when threshold exceeded; includes connection lifecycle handling.
Utility microservice
apps/utility/src/utilities.controller.ts, apps/utility/src/utilities.service.ts, apps/utility/src/utilities.repository.ts
Controller: added alert-db-ledgerId-null message handler. Repository: added getPlatformConfigDetails() and restored getShorteningUrl. Service: refactored to extend BaseService, added storeObject, handleLedgerAlert with deduping/rate-limit, sendWithRetry retry/backoff, email integration, and internal state (lastAlertTime/isSendingAlert).
Prisma / modules
apps/ledger/src/ledger.module.ts, libs/org-roles/src/org-roles.module.ts, libs/prisma-service/src/prisma-service.module.ts, libs/prisma-service/src/prisma-service.service.ts
Switched to providing Prisma via PrismaServiceModule (added to imports) and removed direct PrismaService provider entries; prisma-service.module now imports CommonModule; removed a public UserDevicesRepository field from PrismaService.
DB migration
libs/prisma-service/prisma/migrations/.../migration.sql
New Postgres function alert_ledger_null() and trigger ledger_null_trigger on org_agents to pg_notify ledger_null when ledgerId becomes NULL.
Package
package.json
Bumped pg dependency from ^8.11.2 to ^8.16.3.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Postgres
  participant PrismaTrigger as DB Trigger
  participant ApiGateway as Api-Gateway UtilitiesService
  participant Repo as UtilitiesRepository
  participant NATS
  participant UtilitySvc as Utility Service (handleLedgerAlert)
  participant EmailSvc as EmailService

  Postgres->>PrismaTrigger: org_agents UPDATE (ledgerId becomes NULL)
  PrismaTrigger->>Postgres: pg_notify('ledger_null', payload)
  Postgres->>ApiGateway: notification on channel 'ledger_null'
  ApiGateway->>Repo: count total org_agents / count ledgerId IS NULL
  Repo-->>ApiGateway: counts
  ApiGateway->>NATS: publish alert payload (subject: utilities.alert-db-ledgerId-null)
  NATS->>UtilitySvc: message delivered (alert-db-ledgerId-null)
  UtilitySvc->>Repo: getPlatformConfigDetails()
  Repo-->>UtilitySvc: platform config (emailFrom etc.)
  UtilitySvc->>EmailSvc: sendWithRetry(emailDto)
  EmailSvc-->>UtilitySvc: send result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • apps/api-gateway/src/utilities/utilities.service.ts — Postgres LISTEN handling, query correctness, async guard (isSendingAlert) and NATS publish subject/payload.
    • apps/utility/src/utilities.service.ts — retry/backoff logic, rate-limiting, concurrency guards, and interaction with EmailService and AwsService.
    • libs/common/src/common.service.ts — initialization order of dotenv and header injection for token requests.
    • Shell scripts in apps/agent-provisioning/AFJ/scripts/ — ensuring removed token waits didn't remove necessary synchronization.

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • tipusinghaw
  • GHkrishna
  • shitrerohit

Poem

I hopped through scripts where tokens used to hide,
Endpoints stand alone now — neat and dignified.
Triggers whisper to listeners, alerts take flight,
Emails chase the ledger through the quiet night.
🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
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.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main refactoring: replacing token extraction from container logs with fetching the API key from environment variables and calling an agent token API endpoint.
✨ 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 fetch-agent-token-via-api-in-credo-controller

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

Caution

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

⚠️ Outside diff range comments (1)
libs/common/src/common.service.ts (1)

311-325: Validate AGENT_API_KEY before use.

The AGENT_API_KEY is read from the environment without validation. If it's undefined or empty, it will be passed to the Authorization header, potentially causing unclear failures downstream.

Apply this diff to add validation:

 async getBaseAgentToken(agentEndPoint: string): Promise<string> {
   const normalizedBaseUrl = await this.normalizeUrlWithProtocol(agentEndPoint);
   this.logger.log(`Fetching base agent token from ${normalizedBaseUrl}`);
   const apikey = process.env.AGENT_API_KEY;
+  if (!apikey) {
+    throw new BadRequestException('AGENT_API_KEY environment variable is not configured');
+  }
   const agentBaseWalletDetils = await this.httpPost(`${normalizedBaseUrl}${CommonConstants.URL_AGENT_TOKEN}`, '', {
     headers: {
       Accept: 'application/json',
       Authorization: apikey
     }
   });
   if (!agentBaseWalletDetils) {
     throw new NotFoundException(ResponseMessages.common.error.fetchBaseWalletToken);
   }
   return agentBaseWalletDetils.token;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f4be27 and b023d21.

📒 Files selected for processing (4)
  • apps/agent-provisioning/AFJ/scripts/start_agent.sh (0 hunks)
  • apps/agent-provisioning/src/agent-provisioning.service.ts (2 hunks)
  • apps/agent-service/src/agent-service.service.ts (1 hunks)
  • libs/common/src/common.service.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/agent-provisioning/AFJ/scripts/start_agent.sh
🔇 Additional comments (1)
apps/agent-service/src/agent-service.service.ts (1)

529-529: LGTM! Token retrieval now environment-based.

The updated call to getBaseAgentToken with a single argument correctly aligns with the refactored signature that retrieves the API key from environment variables.

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

Caution

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

⚠️ Outside diff range comments (1)
apps/agent-provisioning/src/agent-provisioning.service.ts (1)

45-45: Validate AGENT_API_KEY before use
In apps/agent-provisioning/src/agent-provisioning.service.ts (line 45), add a guard to throw a clear error if process.env.AGENT_API_KEY is undefined instead of passing "undefined" to the shell script.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b023d21 and 117068f.

📒 Files selected for processing (1)
  • apps/agent-provisioning/src/agent-provisioning.service.ts (2 hunks)
🔇 Additional comments (1)
apps/agent-provisioning/src/agent-provisioning.service.ts (1)

1-11: LGTM!

The import reorganization and dotenv configuration are clean and follow standard practices.

@pranalidhanavade pranalidhanavade force-pushed the fetch-agent-token-via-api-in-credo-controller branch from 117068f to 3ef3ca2 Compare October 10, 2025 11:38
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: 0

🧹 Nitpick comments (1)
libs/common/src/common.service.ts (1)

8-18: Prefer NestJS ConfigModule over dotenv for better DI and testing.

While dotenv.config() works, NestJS applications typically use @nestjs/config's ConfigModule for environment variable management. This provides better dependency injection, type safety, and testability.

Consider refactoring to use ConfigModule:

  1. Install @nestjs/config if not already present:
npm install @nestjs/config
  1. Import ConfigModule in your root module (e.g., app.module.ts):
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      cache: true,
    }),
    // other imports
  ],
})
export class AppModule {}
  1. Inject ConfigService in CommonService:
import { ConfigService } from '@nestjs/config';

@Injectable()
export class CommonService {
  constructor(
    private readonly httpService: HttpService,
    private readonly configService: ConfigService
  ) {}
  
  // Use this.configService.get<string>('AGENT_API_KEY') instead of process.env.AGENT_API_KEY
}

This approach centralizes configuration, improves testing (easier to mock), and provides better type safety.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 117068f and 3ef3ca2.

📒 Files selected for processing (9)
  • .env.demo (0 hunks)
  • .env.sample (0 hunks)
  • apps/agent-provisioning/AFJ/scripts/docker_start_agent.sh (1 hunks)
  • apps/agent-provisioning/AFJ/scripts/fargate.sh (0 hunks)
  • apps/agent-provisioning/AFJ/scripts/start_agent.sh (1 hunks)
  • apps/agent-provisioning/AFJ/scripts/start_agent_ecs.sh (0 hunks)
  • apps/agent-provisioning/src/agent-provisioning.service.ts (2 hunks)
  • apps/agent-service/src/agent-service.service.ts (1 hunks)
  • libs/common/src/common.service.ts (2 hunks)
💤 Files with no reviewable changes (4)
  • apps/agent-provisioning/AFJ/scripts/start_agent_ecs.sh
  • apps/agent-provisioning/AFJ/scripts/fargate.sh
  • .env.sample
  • .env.demo
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/agent-service/src/agent-service.service.ts
🔇 Additional comments (3)
apps/agent-provisioning/AFJ/scripts/docker_start_agent.sh (1)

228-240: Clean refactoring: token extraction removed successfully.

The endpoint file now contains only CONTROLLER_ENDPOINT, and all token-related logic has been removed. The refactoring aligns well with the PR objectives.

apps/agent-provisioning/src/agent-provisioning.service.ts (1)

59-79: Well done: addresses all previous review comments.

The implementation now includes:

  1. Clear error messages with proper grammar
  2. JSON parsing wrapped in try-catch with specific error handling
  3. Validation for the presence of CONTROLLER_ENDPOINT
  4. Appropriate logging at each step

The refactoring successfully removes token handling while maintaining robust endpoint parsing.

apps/agent-provisioning/AFJ/scripts/start_agent.sh (1)

231-243: Retain endpoint file creation—it's consumed by the service
The TypeScript service (apps/agent-provisioning/src/agent-provisioning.service.ts) reads and parses this JSON to extract CONTROLLER_ENDPOINT and will error if it’s missing. Removing this logic will break endpoint discovery.

@sonarqubecloud
Copy link

@pranalidhanavade pranalidhanavade force-pushed the fetch-agent-token-via-api-in-credo-controller branch from a2d3986 to c50995b Compare December 1, 2025 05:28
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: 0

Caution

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

⚠️ Outside diff range comments (2)
apps/agent-provisioning/AFJ/scripts/docker_start_agent.sh (1)

28-37: Avoid logging wallet and storage passwords to stdout.

WALLET_PASSWORD and WALLET_STORAGE_PASSWORD are echoed, which will end up in logs and expose secrets. This is a security risk even if it predates this refactor.

Drop these two echo statements (or mask the values) while keeping the rest of the debug logging.

apps/agent-provisioning/src/agent-provisioning.service.ts (1)

45-66: Fix async error handling in spinUpResponse Promise.

The spinUpResponse Promise is initialized with only resolve and no reject parameter, while errors are thrown inside the exec callback. These thrown errors won't reject the outer Promise and will result in uncaught exceptions or hung callers when the endpoint file is missing, unparseable, or lacks the required CONTROLLER_ENDPOINT key. Additionally, the err parameter from exec is silently ignored.

Refactor to use both resolve and reject, route all failure paths through reject, and handle exec errors:

-        const spinUpResponse: object = new Promise(async (resolve) => {
-          await exec(walletProvision, async (err, stdout, stderr) => {
+        const spinUpResponse: object = new Promise((resolve, reject) => {
+          exec(walletProvision, (err, stdout, stderr) => {
             this.logger.log(`shell script output: ${stdout}`);
             if (stderr) {
               this.logger.log(`shell script error: ${stderr}`);
             }
+
+            if (err) {
+              this.logger.error(`[walletProvision] - shell script failed: ${err.message}`);
+              return reject(err);
+            }

             const agentEndpointPath = `${process.cwd()}${process.env.AFJ_AGENT_ENDPOINT_PATH}${orgId}_${containerName}.json`;
             const agentEndPointExists = await this.checkFileExistence(agentEndpointPath);
             let agentEndPoint;

             if (agentEndPointExists) {
               this.logger.log('Agent endpoint file exists');
               agentEndPoint = await fs.readFileSync(agentEndpointPath, 'utf8');
             } else {
               this.logger.log('Agent endpoint file does not exist');
-              throw new NotFoundException(`Agent endpoint file does not exist: ${agentEndpointPath}`);
+              return reject(
+                new NotFoundException(`Agent endpoint file does not exist: ${agentEndpointPath}`)
+              );
             }

             let parsedEndpoint;
             try {
               parsedEndpoint = JSON.parse(agentEndPoint);
             } catch (parseError) {
               this.logger.error(`Failed to parse agent endpoint file: ${parseError.message}`);
-              throw new Error(`Invalid JSON in agent endpoint file: ${agentEndpointPath}`);
+              return reject(
+                new Error(`Invalid JSON in agent endpoint file: ${agentEndpointPath}`)
+              );
             }

             if (!parsedEndpoint.CONTROLLER_ENDPOINT) {
               this.logger.error('CONTROLLER_ENDPOINT key missing in agent endpoint file');
-              throw new Error(`Missing CONTROLLER_ENDPOINT in: ${agentEndpointPath}`);
+              return reject(
+                new Error(`Missing CONTROLLER_ENDPOINT in: ${agentEndpointPath}`)
+              );
             }

-            resolve({
-              agentEndPoint: parsedEndpoint.CONTROLLER_ENDPOINT
-            });
+            return resolve({
+              agentEndPoint: parsedEndpoint.CONTROLLER_ENDPOINT
+            });
           });
         });

This ensures callers receive a rejected Promise on any failure rather than an uncaught exception.

🧹 Nitpick comments (3)
apps/agent-provisioning/AFJ/scripts/docker_start_agent.sh (1)

92-104: Align endpoint directory with file path used by the TS service.

You create the endpoints directory under ${PWD}/agent-provisioning/AFJ/endpoints, but the JSON file is written to ${PWD}/endpoints/${AGENCY}_${CONTAINER_NAME}.json. The Node service reads from ${process.cwd()}${process.env.AFJ_AGENT_ENDPOINT_PATH}${orgId}_${containerName}.json, so if AFJ_AGENT_ENDPOINT_PATH points at agent-provisioning/AFJ/endpoints, the current script will never produce the expected file.

Consider deriving the directory and file path from a single base (e.g., ${PWD}/agent-provisioning/AFJ/endpoints) to avoid drift and ensure the path matches AFJ_AGENT_ENDPOINT_PATH.

Also applies to: 229-240

apps/agent-service/src/agent-service.service.ts (1)

531-540: Validate AGENT_API_KEY before calling getBaseAgentToken.

You now rely on process.env.AGENT_API_KEY for the base wallet token, but if this env var is unset/empty you’ll end up making a failing HTTP call and only see a generic baseWalletToken error.

Add an explicit check (and log) for a missing/empty AGENT_API_KEY here and fail fast with a clear configuration error before invoking getBaseAgentToken.

apps/agent-provisioning/src/agent-provisioning.service.ts (1)

45-46: Consider validating AGENT_API_KEY before composing the shell command.

walletProvision now passes ${process.env.AGENT_API_KEY} into the spin‑up script, but if this env var is missing, the agent config will either have an empty apiKey or the shell command may not be what you expect.

Adding a simple check (and clear log) for a missing/empty AGENT_API_KEY before building walletProvision would make configuration errors much easier to diagnose.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2d3986 and c50995b.

📒 Files selected for processing (9)
  • .env.demo (0 hunks)
  • .env.sample (0 hunks)
  • apps/agent-provisioning/AFJ/scripts/docker_start_agent.sh (1 hunks)
  • apps/agent-provisioning/AFJ/scripts/fargate.sh (0 hunks)
  • apps/agent-provisioning/AFJ/scripts/start_agent.sh (1 hunks)
  • apps/agent-provisioning/AFJ/scripts/start_agent_ecs.sh (0 hunks)
  • apps/agent-provisioning/src/agent-provisioning.service.ts (2 hunks)
  • apps/agent-service/src/agent-service.service.ts (1 hunks)
  • libs/common/src/common.service.ts (2 hunks)
💤 Files with no reviewable changes (4)
  • apps/agent-provisioning/AFJ/scripts/fargate.sh
  • apps/agent-provisioning/AFJ/scripts/start_agent_ecs.sh
  • .env.sample
  • .env.demo
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/agent-provisioning/AFJ/scripts/start_agent.sh
  • libs/common/src/common.service.ts

@KambleSahil3 KambleSahil3 force-pushed the fetch-agent-token-via-api-in-credo-controller branch from e7e2f31 to c50995b Compare December 1, 2025 10:30
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: 4

Caution

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

⚠️ Outside diff range comments (1)
libs/common/src/resend-helper-file.ts (1)

7-12: Consider lazy initialization instead of module-level validation.

The module-level error throw will crash any service that imports this file if RESEND_API_KEY is missing, even if Resend functionality is never used. Since this is in a shared library (libs/common), it affects all consumers.

Consider deferring initialization until sendWithResend is actually called:

-dotenv.config();
-
-const apiKey = process.env.RESEND_API_KEY;
-if (!apiKey) {
-  throw new Error('Missing RESEND_API_KEY in environment variables.');
-}
-const resend = new Resend(apiKey);
+dotenv.config();
+
+let resend: Resend | null = null;
+
+const getResendClient = (): Resend => {
+  if (!resend) {
+    const apiKey = process.env.RESEND_API_KEY;
+    if (!apiKey) {
+      throw new Error('Missing RESEND_API_KEY in environment variables.');
+    }
+    resend = new Resend(apiKey);
+  }
+  return resend;
+};
 
 export const sendWithResend = async (emailDto: EmailDto): Promise<boolean> => {
   try {
-    const response = await resend.emails.send({
+    const response = await getResendClient().emails.send({

This allows services to import the module without requiring the API key unless they actually call the function.

🧹 Nitpick comments (7)
libs/prisma-service/prisma/migrations/20251125062851_add_ledger_null_trigger/migration.sql (1)

2-14: Remove redundant NULL check in trigger function.

The function's IF NEW."ledgerId" IS NULL THEN check (line 5) is redundant because the trigger's WHEN clause (line 20) already guarantees this condition. The trigger only executes when NEW."ledgerId" IS NULL AND OLD."ledgerId" IS NOT NULL, so the inner IF is unnecessary.

Apply this diff to simplify:

 CREATE OR REPLACE FUNCTION alert_ledger_null()
 RETURNS trigger AS $$
 BEGIN
-    IF NEW."ledgerId" IS NULL THEN
-        PERFORM pg_notify('ledger_null', json_build_object(
-            'agentId', NEW.id,
-            'orgId', NEW."orgId",
-            'timestamp', now()
-        )::text);
-    END IF;
+    PERFORM pg_notify('ledger_null', json_build_object(
+        'agentId', NEW.id,
+        'orgId', NEW."orgId",
+        'timestamp', now()
+    )::text);
     RETURN NEW;
 END;
apps/utility/src/utilities.repository.ts (2)

13-13: Add type annotation for payload parameter.

The payload parameter lacks a type annotation, reducing type safety. Consider defining an interface or inline type.

-  async saveShorteningUrl(payload): Promise<object> {
+  async saveShorteningUrl(payload: { referenceId: string; invitationPayload: string }): Promise<object> {

31-31: Add type annotation for referenceId parameter.

-  async getShorteningUrl(referenceId): Promise<shortening_url> {
+  async getShorteningUrl(referenceId: string): Promise<shortening_url> {
apps/api-gateway/src/utilities/utilities.service.ts (2)

9-10: Consider implementing lifecycle hook interfaces explicitly.

The class defines onModuleInit and onModuleDestroy methods but doesn't implement the OnModuleInit and OnModuleDestroy interfaces. While NestJS will still call these methods, implementing the interfaces provides type safety and makes the intent explicit.

-import { Inject, Injectable } from '@nestjs/common';
+import { Inject, Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
...
 @Injectable()
-export class UtilitiesService extends BaseService {
+export class UtilitiesService extends BaseService implements OnModuleInit, OnModuleDestroy {

30-30: Good observation in the TODO comment.

The TODO comment raises a valid architectural concern. Consider creating an issue to track consolidating the DB alerting logic into a shared library.

Would you like me to open an issue to track this refactoring task?

apps/utility/src/utilities.service.ts (2)

25-25: Add type annotation for payload parameter.

The payload parameter lacks a type annotation, reducing type safety. Define an interface or DTO for the expected shape.

-  async createAndStoreShorteningUrl(payload): Promise<string> {
+  async createAndStoreShorteningUrl(payload: {
+    credentialId: string;
+    schemaId: string;
+    credDefId: string;
+    invitationUrl: string;
+    attributes: unknown;
+  }): Promise<string> {

117-119: Simplify the boolean check.

The if (true !== result) comparison is unconventional. Consider using the more idiomatic form.

-        if (true !== result) {
+        if (result !== true) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f745f4 and e27a4d0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • .env.demo (1 hunks)
  • .env.sample (1 hunks)
  • apps/api-gateway/src/main.ts (1 hunks)
  • apps/api-gateway/src/utilities/utilities.service.ts (1 hunks)
  • apps/ledger/src/ledger.module.ts (2 hunks)
  • apps/utility/src/utilities.controller.ts (2 hunks)
  • apps/utility/src/utilities.repository.ts (1 hunks)
  • apps/utility/src/utilities.service.ts (1 hunks)
  • libs/common/src/common.constant.ts (1 hunks)
  • libs/common/src/dtos/email.dto.ts (1 hunks)
  • libs/common/src/resend-helper-file.ts (1 hunks)
  • libs/org-roles/src/org-roles.module.ts (1 hunks)
  • libs/prisma-service/prisma/migrations/20251125062851_add_ledger_null_trigger/migration.sql (1 hunks)
  • libs/prisma-service/src/prisma-service.module.ts (1 hunks)
  • libs/prisma-service/src/prisma-service.service.ts (0 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (1)
  • libs/prisma-service/src/prisma-service.service.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • .env.sample
  • .env.demo
🧰 Additional context used
🧬 Code graph analysis (5)
apps/api-gateway/src/main.ts (1)
libs/logger/src/logger.interface.ts (1)
  • Logger (6-20)
apps/utility/src/utilities.controller.ts (1)
libs/common/src/dtos/email.dto.ts (1)
  • EmailDto (1-8)
libs/prisma-service/src/prisma-service.module.ts (2)
apps/ledger/src/ledger.module.ts (1)
  • Module (16-36)
libs/org-roles/src/org-roles.module.ts (1)
  • Module (7-12)
apps/utility/src/utilities.repository.ts (2)
libs/prisma-service/src/prisma-service.service.ts (1)
  • Injectable (5-54)
libs/logger/src/logger.interface.ts (1)
  • Logger (6-20)
apps/api-gateway/src/utilities/utilities.service.ts (1)
libs/service/base.service.ts (1)
  • BaseService (2-9)
🔇 Additional comments (14)
libs/common/src/resend-helper-file.ts (1)

13-13: Good: Using validated constant for Resend initialization.

The change to use a validated apiKey constant instead of directly accessing process.env.RESEND_API_KEY improves code clarity and ensures the key is validated before use.

libs/prisma-service/src/prisma-service.module.ts (1)

3-6: PrismaServiceModule wiring with CommonModule looks consistent

Importing CommonModule and adding it to imports cleanly exposes shared providers/utilities to anything using PrismaServiceModule. The DI surface remains simple and consistent with the rest of the app.

libs/org-roles/src/org-roles.module.ts (1)

1-9: Good migration to using PrismaServiceModule for Prisma DI

Switching from a direct PrismaService provider to importing PrismaServiceModule is the right NestJS pattern and matches other modules in the repo. Providers list is now focused on OrgRoles concerns while still getting Prisma via the imported module.

apps/ledger/src/ledger.module.ts (1)

5-35: LedgerModule’s Prisma wiring is now aligned with the shared module pattern

Importing PrismaServiceModule and dropping PrismaService from providers is the correct NestJS approach and keeps this module’s providers focused on ledger concerns while still enabling Prisma injection in services/repositories.

apps/api-gateway/src/main.ts (1)

122-130: LGTM!

The logging changes are appropriate. The conditional check for DB_ALERT_ENABLE is defensive with optional chaining and string normalization.

apps/utility/src/utilities.controller.ts (1)

35-46: LGTM!

The new message handler follows the established pattern in this controller. The error handling is appropriate.

libs/common/src/common.constant.ts (1)

386-388: LGTM!

The new threshold constant is well-named and centralized for reuse. The 30% default is a reasonable starting point for alerting.

libs/common/src/dtos/email.dto.ts (1)

1-8: LGTM!

The emailTo type expansion to string | string[] is backwards compatible and enables multi-recipient support needed for the DB alerting feature.

apps/api-gateway/src/utilities/utilities.service.ts (2)

61-72: LGTM on the query logic.

The COUNT queries are safe (no user input), and the division-by-zero case is properly handled by checking total === 0 before computing the percentage.


77-80: Threshold comparison mismatch with comment.

The comment says "> 30% for now" but the condition >= means alerts trigger only when percent is strictly greater than 30%. If exactly 30%, no alert is sent. Consider clarifying the intent or updating the comment.

If the intent is to alert at exactly 30% or above:

-          // Condition: > 30% for now
-          if (CommonConstants.AFFECTED_RECORDS_THRESHOLD_PERCENTAGE_FOR_DB_ALERT >= percent) {
+          // Condition: >= 30%
+          if (CommonConstants.AFFECTED_RECORDS_THRESHOLD_PERCENTAGE_FOR_DB_ALERT > percent) {

Likely an incorrect or invalid review comment.

package.json (1)

109-109: The pg package version 8.16.3 is valid and compatible.

Version 8.16.3 exists on npm and introduces only minor features and improvements over 8.11.2 (e.g., queryMode, per-query timeouts, ESM support). No breaking changes exist between these versions, so the bump is safe.

apps/utility/src/utilities.service.ts (3)

45-63: LGTM!

Proper null check with NotFoundException for missing data, and consistent error propagation via RpcException.


65-81: LGTM!

Clean S3 upload implementation. Note: This method throws a plain Error rather than RpcException used elsewhere—verify this is intentional for the call sites consuming this method.


83-110: LGTM!

The fire-and-forget pattern with rate limiting and concurrency guard is appropriate for non-blocking alert dispatch. The finally() cleanup ensures isSendingAlert resets regardless of outcome.

Comment on lines 95 to 103
const emailDto = {
emailFrom: '',
emailTo: alertEmails,
emailSubject: '[ALERT] More than 30% org_agents ledgerId is NULL',
emailText: `ALERT: ${percent.toFixed(2)}% of org_agents records currently have ledgerId = NULL.`,
emailHtml: `<p><strong>ALERT:</strong> ${percent.toFixed(
2
)}% of <code>org_agents</code> have <code>ledgerId</code> = NULL.</p>`
};
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

Empty emailFrom may cause email delivery failures.

The emailFrom is set to an empty string. Many email services require a valid sender address. Consider using a configured default sender from environment variables.

           const emailDto = {
-            emailFrom: '',
+            emailFrom: process.env.DB_ALERT_EMAIL_FROM || process.env.DEFAULT_EMAIL_FROM || '',
             emailTo: alertEmails,
📝 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 emailDto = {
emailFrom: '',
emailTo: alertEmails,
emailSubject: '[ALERT] More than 30% org_agents ledgerId is NULL',
emailText: `ALERT: ${percent.toFixed(2)}% of org_agents records currently have ledgerId = NULL.`,
emailHtml: `<p><strong>ALERT:</strong> ${percent.toFixed(
2
)}% of <code>org_agents</code> have <code>ledgerId</code> = NULL.</p>`
};
const emailDto = {
emailFrom: process.env.DB_ALERT_EMAIL_FROM || process.env.DEFAULT_EMAIL_FROM || '',
emailTo: alertEmails,
emailSubject: '[ALERT] More than 30% org_agents ledgerId is NULL',
emailText: `ALERT: ${percent.toFixed(2)}% of org_agents records currently have ledgerId = NULL.`,
emailHtml: `<p><strong>ALERT:</strong> ${percent.toFixed(
2
)}% of <code>org_agents</code> have <code>ledgerId</code> = NULL.</p>`
};
🤖 Prompt for AI Agents
In apps/api-gateway/src/utilities/utilities.service.ts around lines 95 to 103,
the emailDto.emailFrom is set to an empty string which can cause delivery
failures; replace the empty string with a valid default sender pulled from
configuration/environment (e.g., process.env.DEFAULT_EMAIL_SENDER or your app
config) and fall back to a safe no-reply address if the env var is missing;
ensure the value is a valid email (or formatted display name <email>) and update
any related tests or callers expecting the previous empty value.

Comment on lines 52 to 59
async getPlatformConfigDetails(): Promise<platform_config> {
try {
return this.prisma.platform_config.findFirst();
} catch (error) {
this.logger.error(`[getPlatformConfigDetails] - error: ${JSON.stringify(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

Missing await causes error handling to be bypassed.

The findFirst() call is not awaited, so any database errors will not be caught by the catch block. The promise rejection will propagate uncaught.

Apply this diff to fix the issue:

   // eslint-disable-next-line camelcase
   async getPlatformConfigDetails(): Promise<platform_config> {
     try {
-      return this.prisma.platform_config.findFirst();
+      return await this.prisma.platform_config.findFirst();
     } catch (error) {
       this.logger.error(`[getPlatformConfigDetails] - error: ${JSON.stringify(error)}`);
       throw error;
     }
   }
📝 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
async getPlatformConfigDetails(): Promise<platform_config> {
try {
return this.prisma.platform_config.findFirst();
} catch (error) {
this.logger.error(`[getPlatformConfigDetails] - error: ${JSON.stringify(error)}`);
throw error;
}
}
\ No newline at end of file
}
async getPlatformConfigDetails(): Promise<platform_config> {
try {
return await this.prisma.platform_config.findFirst();
} catch (error) {
this.logger.error(`[getPlatformConfigDetails] - error: ${JSON.stringify(error)}`);
throw error;
}
}
🤖 Prompt for AI Agents
In apps/utility/src/utilities.repository.ts around lines 52 to 59, the call to
this.prisma.platform_config.findFirst() is missing an await so thrown DB errors
bypass the try/catch; update the method to await the promise (e.g., assign or
return await this.prisma.platform_config.findFirst()) so exceptions are caught
by the catch block and logged, preserving the existing error logging and rethrow
behavior.

Comment on lines 14 to 15
private lastAlertTime: number | null = null;
private isSendingAlert = false; // Prevent concurrent retries
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

Instance-level rate limiting won't work across multiple service instances.

When this service scales horizontally, each instance maintains its own lastAlertTime and isSendingAlert state, allowing duplicate alerts to be sent from different instances. For production reliability, consider using a distributed store (e.g., Redis) to coordinate alert throttling across instances.

🤖 Prompt for AI Agents
In apps/utility/src/utilities.service.ts around lines 14-15, the current
instance-level variables lastAlertTime and isSendingAlert cannot prevent
duplicate alerts when the service is scaled horizontally; replace them with a
distributed coordination mechanism (e.g., Redis) by storing a single alert key
with an expiry and using an atomic check-and-set (SETNX or a Redis lock/LUA
script) to determine whether an alert may be sent, update the timestamp TTL
atomically when sending succeeds, and fall back to renewing or releasing the
lock on failure; ensure all code paths consult the distributed key instead of
the in-memory fields and handle Redis errors gracefully (e.g., conservative
allow/deny policy) so throttling is enforced across all instances.

Comment on lines 131 to 134
// If last attempt → throw
if (attempt === retries) {
this.logger.error('All email retry attempts failed.');
return;
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

Misleading comment: code returns, not throws.

The comment says "throw" but the implementation returns on final failure. Update the comment to match the behavior.

-        // If last attempt → throw
+        // If last attempt → stop retrying
         if (attempt === retries) {
           this.logger.error('All email retry attempts failed.');
           return;
         }
📝 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
// If last attempt → throw
if (attempt === retries) {
this.logger.error('All email retry attempts failed.');
return;
// If last attempt → stop retrying
if (attempt === retries) {
this.logger.error('All email retry attempts failed.');
return;
🤖 Prompt for AI Agents
In apps/utility/src/utilities.service.ts around lines 131 to 134, the inline
comment says "If last attempt → throw" but the code returns instead of throwing;
update the comment to accurately reflect behavior (e.g., "If last attempt →
return" or "If last attempt → stop retrying and return") so the comment matches
the implementation and avoid confusion.

@pranalidhanavade pranalidhanavade force-pushed the fetch-agent-token-via-api-in-credo-controller branch from e27a4d0 to 9f745f4 Compare December 2, 2025 06:17
@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 2, 2025

@pranalidhanavade pranalidhanavade merged commit 5137cc8 into main Dec 2, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants