Skip to content

Conversation

@pranalidhanavade
Copy link
Contributor

@pranalidhanavade pranalidhanavade commented Jan 5, 2026

What

  • feat: ecosystem service and create ecosystem invitation API route

Summary by CodeRabbit

  • New Features
    • Ecosystem management: create/manage ecosystems with names, descriptions, tags, logos, org associations, roles, and dashboard (members, endorsements, lead).
    • Invitations: invite users to create/join ecosystems with email notifications and tailored invite content.
  • Chores
    • Database schema, seed and migration updates to support ecosystems and roles; new ecosystem microservice registered; added environment sample entry for ecosystem key.

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

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
@pranalidhanavade pranalidhanavade self-assigned this Jan 5, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

Important

Review skipped

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

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

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

📝 Walkthrough

Walkthrough

Adds a new Ecosystem feature: API Gateway endpoints and wiring, a standalone Ecosystem microservice (NATS) with DTOs, repository, service, templates, Prisma schema + migrations/seed updates, enums/response messages, and an env var for NATS seed.

Changes

Cohort / File(s) Summary
Environment & CLI
\.env.sample, nest-cli.json
Added ECOSYSTEM_NKEY_SEED to env sample and registered new ecosystem NestJS project.
API Gateway Wiring
apps/api-gateway/src/app.module.ts, apps/api-gateway/src/ecosystem/*
Registered EcosystemModule and imports in AppModule; added gateway-side DTO, controller, service, and NATS client registration for gateway→microservice comms.
Ecosystem Microservice - Entry & Module
apps/ecosystem/src/main.ts, apps/ecosystem/src/ecosystem.module.ts, apps/ecosystem/tsconfig.app.json
New microservice bootstrap using Transport.NATS, NATS client registration with ECOSYSTEM_NKEY_SEED, module wiring and app tsconfig.
Ecosystem Microservice - Controller & Service
apps/ecosystem/src/ecosystem.controller.ts, apps/ecosystem/src/ecosystem.service.ts
New message-pattern handlers and service logic for invitations, creation, listing, dashboard; NATS proxy usage, email template sending, validation and error handling.
Ecosystem DTOs / Interfaces / Templates
apps/ecosystem/dtos/create-ecosystem-dto.ts, apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts, apps/ecosystem/interfaces/ecosystem.interfaces.ts, apps/ecosystem/templates/create-ecosystem.templates.ts
Added CreateEcosystem and SendEcosystem DTOs, typed interfaces for ecosystem payloads, and HTML invite template generator.
Ecosystem Repository & DB Access
apps/ecosystem/repositories/ecosystem.repository.ts
New repository implementing invitation creation, queries, transactional ecosystem creation, dashboard queries, and related helpers with Prisma.
Database Schema & Migrations
libs/prisma-service/prisma/schema.prisma, libs/prisma-service/prisma/migrations/.../migration.sql, libs/prisma-service/prisma/migrations/.../migration.sql
Added models: ecosystem, ecosystem_roles, ecosystem_users, ecosystem_orgs, ecosystem_invitations; SQL migrations to create tables and alter invitations; seed additions for ecosystem roles.
Seed & Tooling Enhancements
libs/prisma-service/prisma/seed.ts
Expanded seed flow: platform config caching, ecosystem role seeding, Keycloak helpers, encrypted credential updates, and exported helper functions.
Shared Libraries - Enums, Constants & Messages
libs/enum/src/enum.ts, libs/common/src/common.constant.ts, libs/common/src/response-messages/index.ts
Added ecosystem-related enums (roles, config settings, org status), ECOSYSTEM_SERVICE constant, and response message entries for ecosystem success/errors.
Miscellaneous
libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json
Added ecosystemRoleData seed entries (Ecosystem Lead, Ecosystem Member).

Sequence Diagram(s)

sequenceDiagram
    actor PlatformAdmin as Platform Admin
    participant AG as API Gateway
    participant EcoSvc as Ecosystem Microservice
    participant Repo as Ecosystem Repository
    participant DB as Database
    participant Email as Email Service

    PlatformAdmin->>AG: POST /ecosystem/invitations { email }
    AG->>EcoSvc: NATS -> invite-user-for-ecosystem-creation { email, platformAdminId }
    EcoSvc->>Repo: createEcosystemInvitation({ email, platformAdminId })
    Repo->>DB: INSERT ecosystem_invitations
    DB-->>Repo: invitation record
    Repo-->>EcoSvc: invitation
    EcoSvc->>EcoSvc: checkUserExistInPlatform(email) via NATS
    alt user exists
        EcoSvc->>Email: sendInviteEmailTemplate(email, true)
    else user not exists
        EcoSvc->>Email: sendInviteEmailTemplate(email, false)
    end
    EcoSvc-->>AG: invitation response
    AG-->>PlatformAdmin: 201 Created
Loading
sequenceDiagram
    actor User
    participant AG as API Gateway
    participant EcoSvc as Ecosystem Microservice
    participant Repo as Ecosystem Repository
    participant DB as Database

    User->>AG: POST /ecosystem/:orgId (CreateEcosystemDto)
    AG->>EcoSvc: NATS -> create-ecosystem { createEcosystemDto }
    EcoSvc->>Repo: checkEcosystemNameExist(name)
    Repo->>DB: SELECT ecosystem WHERE name=?
    alt name exists
        Repo-->>EcoSvc: existing record
        EcoSvc-->>AG: 409 Conflict
        AG-->>User: 409 Conflict
    else name available
        Repo-->>EcoSvc: null
        EcoSvc->>Repo: checkEcosystemOrgs(orgId)
        Repo->>DB: SELECT ecosystem_orgs WHERE orgId=?
        alt org already linked
            Repo-->>EcoSvc: existing record
            EcoSvc-->>AG: 400 Bad Request
            AG-->>User: 400 Bad Request
        else proceed
            EcoSvc->>Repo: createNewEcosystem(dto)
            Repo->>DB: BEGIN TRANSACTION / INSERT ecosystem, ecosystem_users, ecosystem_orgs
            DB-->>Repo: created ecosystem
            Repo-->>EcoSvc: IEcosystem
            EcoSvc-->>AG: IEcosystem
            AG-->>User: 201 Created
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

feature

Suggested reviewers

  • GHkrishna
  • RinkalBhojani
  • ankita-p17

Poem

🐇 I planted seeds for ecosystems anew,
NATS winds carried invites true.
Tables, roles, and templates in bloom,
Messages hop from queue to room.
Hop—our little forest found its tune.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 'feat: ecosystem service and create ecosystem invitation API route' directly and clearly summarizes the main changes in the changeset.

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


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

🧹 Nitpick comments (19)
nest-cli.json (1)

200-208: Consider alphabetical ordering for project entries.

The configuration is correct but is positioned between "organization" and "platform-service". For improved maintainability, consider placing project entries in alphabetical order.

🔎 Suggested placement

Move the ecosystem entry to appear before "geo-location" (line 110) to maintain alphabetical order:

    "enum": {
      "type": "library",
      "root": "libs/enum",
      "entryFile": "index",
      "sourceRoot": "libs/enum/src",
      "compilerOptions": {
        "tsConfigPath": "libs/enum/tsconfig.lib.json"
      }
    },
+    "ecosystem": {
+      "type": "application",
+      "root": "apps/ecosystem",
+      "entryFile": "main",
+      "sourceRoot": "apps/ecosystem/src",
+      "compilerOptions": {
+        "tsConfigPath": "apps/ecosystem/tsconfig.app.json"
+      }
+    },
    "geo-location": {
      "type": "application",
      "root": "apps/geo-location",
apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (1)

8-13: Consider removing redundant IsString decorator.

The @IsEmail decorator already validates that the value is a string, making @IsString redundant. However, keeping it can improve error message clarity for API consumers.

apps/ecosystem/templates/create-ecosystem.templates.ts (1)

32-34: Consider escaping environment variables used in HTML context.

While environment variables are typically controlled by administrators, applying escapeHtml to PLATFORM_NAME and other environment variables displayed in HTML would provide defense-in-depth against misconfiguration.

🔎 Example hardening
  const safeEmail = escapeHtml(email);
  const safeInviterName = escapeHtml(inviterName);
+  const safePlatformName = escapeHtml(process.env.PLATFORM_NAME);
+  const safePoweredBy = escapeHtml(process.env.POWERED_BY);

Then use safePlatformName and safePoweredBy in the template instead of direct process.env access.

libs/prisma-service/prisma/migrations/20251230074431_create_ecosystem_invitation_workflow_table/migration.sql (1)

2-17: Consider adding foreign keys for audit columns.

The createdBy and lastChangedBy columns store UUIDs but lack foreign key constraints to the user table. While this might be intentional for flexibility, adding foreign keys would enforce referential integrity.

🔎 Proposed addition
-- AddForeignKey
ALTER TABLE "ecosystem" ADD CONSTRAINT "ecosystem_createdBy_fkey" 
  FOREIGN KEY ("createdBy") REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ecosystem" ADD CONSTRAINT "ecosystem_lastChangedBy_fkey" 
  FOREIGN KEY ("lastChangedBy") REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

Apply similar constraints to other tables with audit columns. Note: If system users or deleted users need to be preserved in audit trails, consider using ON DELETE SET NULL instead of RESTRICT.

libs/prisma-service/prisma/schema.prisma (2)

802-817: Consider adding onDelete behavior for ecosystem_invitations relations.

The ecosystemId and userId are optional, which is appropriate for pending invitations. However, consider what should happen when the referenced ecosystem or user is deleted. Without explicit onDelete rules, the database default behavior applies, which may leave orphaned invitations.

🔎 Suggested improvement
-  ecosystem ecosystem? @relation(fields: [ecosystemId], references: [id])
-  user      user?      @relation(fields: [userId], references: [id])
+  ecosystem ecosystem? @relation(fields: [ecosystemId], references: [id], onDelete: SetNull)
+  user      user?      @relation(fields: [userId], references: [id], onDelete: SetNull)

781-800: Minor formatting: Remove extra blank line.

There's an extra blank line at line 798 before the @@unique constraint. This is a minor cosmetic issue.

🔎 Suggested fix
   ecosystem     ecosystem       @relation(fields: [ecosystemId], references: [id])
   ecosystemRole ecosystem_roles @relation(fields: [ecosystemRoleId], references: [id])
   organisation  organisation    @relation(fields: [orgId], references: [id])
-
-
+
   @@unique([orgId, ecosystemId])
 }
.env.sample (1)

121-121: Consider ordering and quoting for consistency.

Static analysis flagged two issues:

  1. Key ordering: ECOSYSTEM_NKEY_SEED should be placed before ISSUANCE_NKEY_SEED to maintain alphabetical ordering (E before I).

  2. Value quoting: While other NKEY_SEED values in this file also lack quotes, it's generally safer to quote environment variable values to prevent shell interpretation issues.

🔎 Suggested fix - reorder and quote

Move the line between CONNECTION_NKEY_SEED and CREDENTAILDEFINITION_NKEY_SEED (or before ISSUANCE_NKEY_SEED for alphabetical order):

 CONNECTION_NKEY_SEED=xxxxxxxxxxxxx // Please provide Nkeys secret for connection service
+ECOSYSTEM_NKEY_SEED='xxxxxxxxxxxxx' // Please provide Nkeys secret for ecosystem service
 CREDENTAILDEFINITION_NKEY_SEED=xxxxxxxxxxxxx // Please provide Nkeys secret for credential-definition service
-ECOSYSTEM_NKEY_SEED=xxxxxxxxxxxxx // Please provide Nkeys secret for ecosystem service
apps/ecosystem/src/main.ts (2)

9-9: Remove commented-out import.

The commented import // import { nkeyAuthenticator } from 'nats'; is unused and should be removed to keep the code clean.

🔎 Suggested fix
 import NestjsLoggerServiceAdapter from '@credebl/logger/nestjsLoggerServiceAdapter';
-// import { nkeyAuthenticator } from 'nats';
 import { getNatsOptions } from '@credebl/common/nats.config';

14-25: Consider adding error handling for bootstrap failures.

The bootstrap function doesn't catch or handle errors that may occur during startup. If NestFactory.createMicroservice or app.listen() fails, the process will exit without logging the error clearly.

🔎 Suggested improvement
 async function bootstrap(): Promise<void> {
-  const app = await NestFactory.createMicroservice<MicroserviceOptions>(EcosystemModule, {
-    transport: Transport.NATS,
-    options: getNatsOptions(CommonConstants.ECOSYSTEM_SERVICE, process.env.ECOSYSTEM_NKEY_SEED)
-  });
-  app.useLogger(app.get(NestjsLoggerServiceAdapter));
-  app.useGlobalFilters(new HttpExceptionFilter());
-
-  await app.listen();
-  logger.log('Ecosystem Microservice is listening to NATS ');
+  try {
+    const app = await NestFactory.createMicroservice<MicroserviceOptions>(EcosystemModule, {
+      transport: Transport.NATS,
+      options: getNatsOptions(CommonConstants.ECOSYSTEM_SERVICE, process.env.ECOSYSTEM_NKEY_SEED)
+    });
+    app.useLogger(app.get(NestjsLoggerServiceAdapter));
+    app.useGlobalFilters(new HttpExceptionFilter());
+
+    await app.listen();
+    logger.log('Ecosystem Microservice is listening to NATS');
+  } catch (error) {
+    logger.error('Failed to start Ecosystem Microservice', error);
+    process.exit(1);
+  }
 }
-bootstrap();
+bootstrap();
libs/enum/src/enum.ts (1)

108-110: Consider adding more status values to EcosystemOrgStatus.

The enum currently only defines ACTIVE, but organization status typically includes additional states such as INACTIVE, PENDING, SUSPENDED, etc. If other statuses are not needed in the current implementation, this is acceptable, but consider whether this enum will need expansion in the future.

apps/ecosystem/src/ecosystem.controller.ts (1)

23-32: Remove or implement the commented-out code.

The commented-out createEcosystem endpoint should either be implemented if needed or removed to reduce clutter.

apps/ecosystem/repositories/ecosystem.repository.ts (1)

32-147: Remove the commented-out code.

Large blocks of inactive code reduce maintainability. If this functionality is planned for future use, consider tracking it in an issue instead.

apps/ecosystem/src/ecosystem.service.ts (3)

33-38: Consider transactional consistency between database and email operations.

The invitation is created in the database (line 34) before sending the email (line 36). If email sending fails, the invitation record remains in the database with no notification sent to the user. Consider wrapping both operations or implementing a compensating action to delete the invitation if email sending fails.


39-42: Improve error handling specificity.

The catch block uses a generic invalidInvitationStatus message for all errors. This may not accurately reflect the actual failure (e.g., database errors, email sending failures, validation errors). Consider using more specific error messages based on the error type.


61-115: Remove the commented-out code.

Large blocks of inactive code reduce readability and maintainability. If this functionality is planned, track it in an issue instead.

apps/api-gateway/src/ecosystem/ecosystem.controller.ts (2)

52-67: Consider alternative to mutating the DTO.

Line 57 directly mutates sendEcosystemCreateDto.userId by assigning the path parameter. While functional, mutating request DTOs can lead to unexpected behavior in middleware or interceptors that operate on the original request body.

🔎 Alternative approach
   async createInvitation(
     @Body() sendEcosystemCreateDto: SendEcosystemCreateDto,
     @Param('userId') userId: string,
     @Res() res: Response
   ): Promise<Response> {
-    sendEcosystemCreateDto.userId = userId;
-
-    await this.ecosystemService.ecosystemCreateInvitation(sendEcosystemCreateDto);
+    await this.ecosystemService.ecosystemCreateInvitation({
+      ...sendEcosystemCreateDto,
+      userId
+    });

     const finalResponse: IResponse = {

69-100: Remove the commented-out code.

The commented-out createNewEcosystem endpoint should either be implemented if needed or removed to maintain code cleanliness.

apps/api-gateway/src/ecosystem/ecosystem.service.ts (1)

23-31: Consider removing commented code or adding a TODO.

The commented createEcosystem method appears to be placeholder code for future functionality. Consider either:

  • Adding a TODO comment with a tracking ticket reference, or
  • Removing it entirely and adding it when the functionality is ready to be implemented.

This helps keep the codebase clean and makes future intentions more explicit.

apps/ecosystem/dtos/create-ecosystem-dto.ts (1)

47-47: Consider adding validation for orgId when provided.

The orgId field is optional but has no validation decorators. If this field represents an organization identifier (likely a UUID based on patterns elsewhere in the codebase), consider adding validation when it's provided to ensure data integrity.

🔎 Example validation
   @ApiPropertyOptional()
+  @IsOptional()
+  @IsString({ message: 'orgId must be in string format.' })
+  @IsUUID('4', { message: 'orgId must be a valid UUID.' })
   orgId?: string;
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f71844 and 3eeb099.

📒 Files selected for processing (21)
  • .env.sample
  • apps/api-gateway/src/app.module.ts
  • apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts
  • apps/api-gateway/src/ecosystem/ecosystem.controller.ts
  • apps/api-gateway/src/ecosystem/ecosystem.module.ts
  • apps/api-gateway/src/ecosystem/ecosystem.service.ts
  • apps/ecosystem/dtos/create-ecosystem-dto.ts
  • apps/ecosystem/interfaces/ecosystem.intefaces.ts
  • apps/ecosystem/repositories/ecosystem.repository.ts
  • apps/ecosystem/src/ecosystem.controller.ts
  • apps/ecosystem/src/ecosystem.module.ts
  • apps/ecosystem/src/ecosystem.service.ts
  • apps/ecosystem/src/main.ts
  • apps/ecosystem/templates/create-ecosystem.templates.ts
  • apps/ecosystem/tsconfig.app.json
  • libs/common/src/common.constant.ts
  • libs/common/src/response-messages/index.ts
  • libs/enum/src/enum.ts
  • libs/prisma-service/prisma/migrations/20251230074431_create_ecosystem_invitation_workflow_table/migration.sql
  • libs/prisma-service/prisma/schema.prisma
  • nest-cli.json
🧰 Additional context used
🧬 Code graph analysis (7)
apps/api-gateway/src/ecosystem/ecosystem.module.ts (14)
apps/api-gateway/src/app.module.ts (1)
  • Module (40-123)
apps/ecosystem/src/ecosystem.module.ts (1)
  • Module (18-37)
apps/api-gateway/src/issuance/issuance.module.ts (1)
  • Module (12-26)
apps/api-gateway/src/authz/authz.module.ts (1)
  • Module (26-63)
apps/api-gateway/src/organization/organization.module.ts (1)
  • Module (13-29)
apps/api-gateway/src/verification/verification.module.ts (1)
  • Module (11-25)
apps/api-gateway/src/agent-service/agent-service.module.ts (1)
  • Module (13-30)
apps/api-gateway/src/credential-definition/credential-definition.module.ts (1)
  • Module (10-28)
apps/api-gateway/src/connection/connection.module.ts (1)
  • Module (9-25)
apps/api-gateway/src/fido/fido.module.ts (1)
  • Module (9-23)
apps/api-gateway/src/platform/platform.module.ts (1)
  • Module (9-23)
apps/api-gateway/src/schema/schema.module.ts (1)
  • Module (11-26)
apps/api-gateway/src/user/user.module.ts (1)
  • Module (13-29)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (1)
libs/common/src/cast.helper.ts (1)
  • trim (39-43)
apps/ecosystem/repositories/ecosystem.repository.ts (2)
apps/ecosystem/src/ecosystem.service.ts (1)
  • Injectable (13-59)
libs/common/src/interfaces/cloud-wallet.interface.ts (1)
  • Invitation (268-275)
apps/ecosystem/dtos/create-ecosystem-dto.ts (3)
libs/common/src/cast.helper.ts (2)
  • trim (39-43)
  • IsNotSQLInjection (96-127)
libs/validations/minLength.ts (1)
  • MinLength (3-28)
libs/validations/maxLength.ts (1)
  • MaxLength (3-28)
apps/ecosystem/interfaces/ecosystem.intefaces.ts (1)
apps/api-gateway/src/issuance/utils/helper.ts (1)
  • JsonValue (5-5)
apps/ecosystem/src/ecosystem.controller.ts (1)
apps/ecosystem/interfaces/ecosystem.intefaces.ts (1)
  • IEcosystemInvitations (65-73)
apps/ecosystem/templates/create-ecosystem.templates.ts (1)
libs/common/src/common.utils.ts (1)
  • escapeHtml (149-156)
🪛 dotenv-linter (4.0.0)
.env.sample

[warning] 121-121: [UnorderedKey] The ECOSYSTEM_NKEY_SEED key should go before the ISSUANCE_NKEY_SEED key

(UnorderedKey)


[warning] 121-121: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🔇 Additional comments (13)
apps/ecosystem/tsconfig.app.json (1)

1-9: LGTM!

The TypeScript configuration correctly extends the root configuration and follows standard NestJS monorepo conventions.

apps/ecosystem/templates/create-ecosystem.templates.ts (1)

17-18: LGTM!

Proper use of escapeHtml to prevent XSS attacks via user-provided email and inviter name.

libs/prisma-service/prisma/migrations/20251230074431_create_ecosystem_invitation_workflow_table/migration.sql (2)

86-105: LGTM!

Foreign key constraints are properly defined with appropriate ON DELETE and ON UPDATE actions. The use of RESTRICT for critical relationships and SET NULL for invitations provides good data integrity.


77-84: LGTM!

Unique indexes effectively prevent duplicate role names and duplicate user/organization associations within ecosystems.

libs/prisma-service/prisma/schema.prisma (2)

735-752: LGTM! Well-structured ecosystem model.

The ecosystem model is properly defined with UUID primary key, timestamps, and soft delete support. The autoEndorsement boolean with default false is a good safety default.

One consideration: The ledgers field is defined as Json?. If this will store references to ledger entities, consider whether a proper relation to the ledgers model would provide better type safety and referential integrity.


39-40: LGTM! Properly added ecosystem relations to existing models.

The relations ecosystemUsers, ecosystemInvitations on user, and ecosystemOrgs on organisation are correctly defined to support the new ecosystem feature.

Also applies to: 160-160

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

257-259: LGTM! Properly added ecosystem service constant.

The ECOSYSTEM_SERVICE = 'ecosystem' constant is correctly added and follows the existing naming conventions. The placement under a clear // ecosystem comment section is appropriate.

apps/api-gateway/src/ecosystem/ecosystem.module.ts (1)

10-23: LGTM! Module follows established patterns.

The EcosystemModule correctly follows the established pattern used by other API gateway modules (FidoModule, SchemaModule, PlatformModule, etc.):

  • Registers NATS client with appropriate service name and gateway seed
  • Declares controller and service providers
  • Uses NATSClient for inter-service communication
apps/api-gateway/src/app.module.ts (2)

68-68: LGTM! EcosystemModule properly integrated.

The EcosystemModule is correctly imported and added to the API gateway's module imports. The placement follows the alphabetical ordering pattern used by other modules.


87-122: Verify if any ecosystem routes should be excluded from AuthzMiddleware.

The EcosystemModule is added but no ecosystem routes are excluded from AuthzMiddleware. This means all ecosystem endpoints will require authorization, which is likely the correct behavior for ecosystem management operations.

If any ecosystem endpoints should be publicly accessible (e.g., invitation acceptance), they may need to be added to the exclusion list.

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

18-37: [Your rewritten review comment text here]
[Exactly ONE classification tag]

libs/common/src/response-messages/index.ts (1)

163-250: LGTM! Well-structured response messages.

The ecosystem response messages section is well-organized and consistent with the existing patterns in the codebase. The messages are clear, descriptive, and cover a comprehensive range of success and error scenarios for ecosystem operations.

apps/ecosystem/dtos/create-ecosystem-dto.ts (1)

33-33: No action required — userId is correctly set programmatically by the controller.

The userId field is assigned by the controller from the URL path parameter (@Post('/:userId/invitations')@Param('userId')) and then set directly on the DTO before validation (sendEcosystemCreateDto.userId = userId;). Since it is not populated from user input, it does not require input validation decorators like other user-provided string fields.

Comment on lines 30 to 43
async ecosystemCreateInvitation(invitationDto: SendEcosystemCreateDto): Promise<IEcosystemInvitations> {
const { email, userId } = invitationDto;

try {
const invitation = await this.ecosystemRepository.createSendInvitation(email, userId);

await this.sendInviteEmailTemplate(email);

return invitation;
} catch (error) {
this.logger.error(`ecosystemCreateInvitation error: ${JSON.stringify(error)}`);
throw new InternalServerErrorException(ResponseMessages.user.error.invalidInvitationStatus);
}
}
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

Add ecosystemId parameter to invitation creation.

The repository's createSendInvitation method is called without an ecosystemId, but the IEcosystemInvitations interface requires this field. This aligns with the issue identified in the repository file.

🔎 Proposed fix
-  async ecosystemCreateInvitation(invitationDto: SendEcosystemCreateDto): Promise<IEcosystemInvitations> {
-    const { email, userId } = invitationDto;
+  async ecosystemCreateInvitation(invitationDto: SendEcosystemCreateDto): Promise<IEcosystemInvitations> {
+    const { email, userId, ecosystemId } = invitationDto;

     try {
-      const invitation = await this.ecosystemRepository.createSendInvitation(email, userId);
+      const invitation = await this.ecosystemRepository.createSendInvitation(email, userId, ecosystemId);

       await this.sendInviteEmailTemplate(email);

       return invitation;

This requires that SendEcosystemCreateDto includes an ecosystemId field.

📝 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 ecosystemCreateInvitation(invitationDto: SendEcosystemCreateDto): Promise<IEcosystemInvitations> {
const { email, userId } = invitationDto;
try {
const invitation = await this.ecosystemRepository.createSendInvitation(email, userId);
await this.sendInviteEmailTemplate(email);
return invitation;
} catch (error) {
this.logger.error(`ecosystemCreateInvitation error: ${JSON.stringify(error)}`);
throw new InternalServerErrorException(ResponseMessages.user.error.invalidInvitationStatus);
}
}
async ecosystemCreateInvitation(invitationDto: SendEcosystemCreateDto): Promise<IEcosystemInvitations> {
const { email, userId, ecosystemId } = invitationDto;
try {
const invitation = await this.ecosystemRepository.createSendInvitation(email, userId, ecosystemId);
await this.sendInviteEmailTemplate(email);
return invitation;
} catch (error) {
this.logger.error(`ecosystemCreateInvitation error: ${JSON.stringify(error)}`);
throw new InternalServerErrorException(ResponseMessages.user.error.invalidInvitationStatus);
}
}
🤖 Prompt for AI Agents
In apps/ecosystem/src/ecosystem.service.ts around lines 30 to 43, the call to
createSendInvitation omits the required ecosystemId causing the returned
IEcosystemInvitations to miss that field; extract ecosystemId from
SendEcosystemCreateDto (const { email, userId, ecosystemId } = invitationDto),
pass ecosystemId into this.ecosystemRepository.createSendInvitation(email,
userId, ecosystemId), and ensure SendEcosystemCreateDto (and any callers) are
updated to include ecosystemId so the repository receives and persists it.

@pranalidhanavade pranalidhanavade changed the base branch from main to feat/platform_admin_and_ecosystem January 5, 2026 06:33
sujitaw and others added 6 commits January 6, 2026 15:46
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
…ation api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
@pranalidhanavade
Copy link
Contributor Author

@coderabbitai full-review

@coderabbitai
Copy link

coderabbitai bot commented Jan 8, 2026

@pranalidhanavade, I'll perform a comprehensive review of all the changes in this PR. Let me analyze the ecosystem service implementation, API routes, database schema changes, and overall architecture.

✅ Actions performed

Full review triggered.

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

Caution

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

⚠️ Outside diff range comments (2)
libs/prisma-service/prisma/seed.ts (2)

243-254: Critical: Inverted condition causes incorrect behavior.

The condition if (!userId && !orgId && !orgRoleId) will only enter the block when ALL values are null/undefined, but then immediately tries to access .id on null objects (lines 246-248), causing a runtime error. The logic should check if all values ARE defined before proceeding.

🐛 Proposed fix
-    if (!userId && !orgId && !orgRoleId) {
+    if (userId && orgId && orgRoleId) {
       const platformOrganization = await prisma.user_org_roles.create({
         data: {
           userId: userId.id,
           orgRoleId: orgRoleId.id,
           orgId: orgId.id
         }
       });
       logger.log(platformOrganization);
     } else {
-      logger.log('Already seeding in org_roles');
+      logger.log('Required entities not found for user_org_roles seeding');
     }

496-499: Security concern: Passing encrypted secrets via command line arguments.

Command line arguments can be visible in process listings (ps aux) and shell history. Consider using environment variables or piping the secrets via stdin instead.

🤖 Fix all issues with AI agents
In @apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts:
- Line 14: The userId field in the SendEcosystemInvitation DTO lacks validation;
update the DTO by adding class-validator decorators to ensure userId is a
required, non-empty string (e.g., annotate the userId property with @IsString()
and @IsNotEmpty(), or @IsUUID() if the app expects UUIDs) so incoming payloads
are validated before use.

In @apps/api-gateway/src/ecosystem/ecosystem.controller.ts:
- Around line 46-70: The @Roles(OrgRoles.PLATFORM_ADMIN) decorator on
createInvitation is not effective because OrgRolesGuard is not applied; update
the controller method to include the OrgRolesGuard so role checks run (e.g., add
UseGuards(AuthGuard('jwt'), OrgRolesGuard) or combine into a single decorator
that applies both guards), ensuring the OrgRolesGuard symbol is imported and
used alongside AuthGuard for the createInvitation route.
- Around line 119-127: The createNewEcosystem handler types the user param as
plain object which loses type safety; change the parameter type to the Prisma
user type used elsewhere (e.g., User from @prisma/client) and update the import
accordingly, then use dot-access (user?.id) rather than bracket notation when
assigning createEcosystemDto.userId; ensure the function signature for
createNewEcosystem and any other endpoints in this controller use the same
Prisma User type for consistency.

In @apps/api-gateway/src/ecosystem/ecosystem.module.ts:
- Around line 10-23: The getNatsOptions call in EcosystemModule uses the wrong
env var: replace process.env.API_GATEWAY_NKEY_SEED with
process.env.ECOSYSTEM_NKEY_SEED so the NATS options use the ecosystem seed like
main.ts does; update the ClientsModule.register entry (the object with name
'NATS_CLIENT' and transport Transport.NATS) to pass
process.env.ECOSYSTEM_NKEY_SEED into
getNatsOptions(CommonConstants.ECOSYSTEM_SERVICE, ...), leaving getNatsOptions,
CommonConstants.ECOSYSTEM_SERVICE, EcosystemService, EcosystemController and
NATSClient unchanged.

In @apps/ecosystem/dtos/create-ecosystem-dto.ts:
- Line 40: The orgId property in CreateEcosystemDto is optional but missing
validation decorators; update the orgId field in the CreateEcosystemDto class by
adding @IsOptional() and @IsUUID() from class-validator (and add those imports
if missing) so the DTO consistently enforces an optional UUID value for orgId.
- Line 32: The userId property in the CreateEcosystemDto lacks validation;
update the DTO by adding class-validator decorators such as @IsUUID() and
@IsNotEmpty() (and optionally @IsString()) to the userId property and add IsUUID
(and IsNotEmpty) to the existing imports from class-validator so the
CreateEcosystemDto.userId is validated as a required UUID.

In @apps/ecosystem/repositories/ecosystem.repository.ts:
- Around line 245-250: Replace the hardcoded membersCount and endorsementsCount
with real computed values (e.g., derive membersCount from ecosystem.members
length or the appropriate relation and endorsementsCount from
ecosystem.endorsements or the correct field) and guard access to
ecosystem.ecosystemOrgs[0] when building ecosystemLead by using optional
chaining/defaults so role and orgName are null or empty string if the array is
empty; reference the same symbols (membersCount, endorsementsCount,
ecosystem.ecosystemOrgs, ecosystemLead, ecosystemRole, organisation) when making
these changes so the code reads actual counts and safely handles missing
ecosystemOrgs.
- Around line 97-113: The code calls this.prisma.ecosystem_roles.findFirst
inside the transaction, which executes outside the transaction and can return
null; instead use the transaction-scoped prisma (the local prisma variable
passed into the $transaction callback) to query ecosystem_roles (e.g.,
prisma.ecosystem_roles.findFirst) and then check the result for null before
using ecosystemRoleDetails.id — if null, throw or handle an explicit error so
the transaction will rollback and avoid a null pointer when creating the
ecosystem_orgs record that references ecosystemRoleDetails.id.

In @apps/ecosystem/src/ecosystem.controller.ts:
- Around line 43-46: The createEcosystem @MessagePattern handler incorrectly
uses the HTTP-only @Body() decorator; remove @Body() from the createEcosystem
method signature so the handler accepts the message payload as the first
parameter directly (e.g., rename the parameter to payload: { createEcosystemDto
} or typed payload) and pass payload.createEcosystemDto to
ecosystemService.createEcosystem; update the method signature in the
createEcosystem function accordingly so it reflects a microservice
MessagePattern handler.

In @apps/ecosystem/src/ecosystem.module.ts:
- Around line 18-37: The module currently lets ClientsModule.register call
getNatsOptions with process.env.ECOSYSTEM_NKEY_SEED which can be undefined,
causing an unauthenticated NATS connection; update EcosystemModule to validate
ECOSYSTEM_NKEY_SEED at startup and fail fast: in the module
bootstrap/constructor (or before calling ClientsModule.register) check
process.env.ECOSYSTEM_NKEY_SEED (or use a ConfigService) and throw a clear error
if missing, or alternatively change the ClientsModule.register call for
NATS_CLIENT to only register when the env var exists and otherwise skip
registration while logging a clear message; reference getNatsOptions,
ECOSYSTEM_NKEY_SEED, ClientsModule.register, NATS_CLIENT and EcosystemModule
when making the change.

In @apps/ecosystem/src/ecosystem.service.ts:
- Around line 67-79: The code in sendInviteEmailTemplate calls
this.prisma.platform_config.findFirst() which can return null, then immediately
uses platformConfigData.emailFrom causing a potential runtime null dereference;
update sendInviteEmailTemplate to handle a missing platformConfigData by
checking if platformConfigData is null (or use a safe default) before reading
platformConfigData.emailFrom, e.g., compute a fallback sender value and assign
emailData.emailFrom from platformConfigData.emailFrom ?? fallback, and ensure
emailData is populated before calling this.emailService.sendEmail so
sendInviteEmailTemplate never accesses properties on a null platformConfigData.

In @libs/common/src/response-messages/index.ts:
- Line 205: Fix the typo in the response message for
signTransactionNotApplicable by changing the misspelled word "aapllicable" to
"applicable" in the signTransactionNotApplicable entry so the string reads
"Signing transaction for w3c schema is not applicable".
- Line 215: The message string for the response key credentialDefinitionNotFound
is incorrect; update the value associated with credentialDefinitionNotFound in
the response-messages export to "Credential definition not found" so the text
matches the error key name and intent (ensure you modify the entry named
credentialDefinitionNotFound in libs/common/src/response-messages/index.ts).

In
@libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json:
- Around line 178-188: In the ecosystemRoleData array, remove the trailing
whitespace character after the "description": "Ecosystem Lead" value (the object
whose "name" is "Ecosystem Lead") so the string ends exactly with "Ecosystem
Lead" without extra spaces; update that JSON entry to eliminate the stray
whitespace for consistency.

In
@libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql:
- Around line 62-74: The migration for CREATE TABLE "ecosystem_invitations" is
missing the optional ecosystemId column referenced by the interface; add a
nullable "ecosystemId" UUID column to the "ecosystem_invitations" table and
create a foreign key constraint referencing "ecosystem"("id") (e.g., CONSTRAINT
"ecosystem_invitations_ecosystemId_fkey" FOREIGN KEY ("ecosystemId") REFERENCES
"ecosystem"("id")), and optionally add an index on "ecosystemId" for lookups.

In @libs/prisma-service/prisma/schema.prisma:
- Around line 801-814: The Prisma model ecosystem_invitations is missing the
ecosystemId column that IEcosystemInvitations expects; add an optional
ecosystemId String? @db.Uuid field to the ecosystem_invitations model, create
the relation decorator (e.g., ecosystem ecosystem? @relation(fields:
[ecosystemId], references: [id])) and update the ecosystem model to include the
back-relation (e.g., invitations ecosystem_invitations[]). Alternatively, if
ecosystemId is not needed, remove it from the IEcosystemInvitations interface to
keep the schema and interface in sync.

In @libs/prisma-service/prisma/seed.ts:
- Around line 541-545: The loop in updateClientId accesses
cachedConfig.platformEmail but cachedConfig may be null because
getPlatformConfig() is called later in main(); fix by ensuring cachedConfig is
initialized before updateClientId runs (move the getPlatformConfig() call in
main() to occur before updateClientId()), or alternatively add a defensive null
check in updateClientId (guard on cachedConfig and skip the platform admin check
if cachedConfig is null) so cachedConfig.platformEmail is never dereferenced
when null.
🧹 Nitpick comments (17)
apps/ecosystem/src/main.ts (1)

9-9: Remove commented-out import.

The commented import // import { nkeyAuthenticator } from 'nats'; is unused and should be removed to keep the code clean.

🧹 Proposed fix
 import NestjsLoggerServiceAdapter from '@credebl/logger/nestjsLoggerServiceAdapter';
-// import { nkeyAuthenticator } from 'nats';
 import { getNatsOptions } from '@credebl/common/nats.config';
apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (2)

6-15: Clarify the naming inconsistency between class name and purpose.

The class is named SendEcosystemCreateDto (suggesting ecosystem creation) but the file is named send-ecosystem-invitation.ts (suggesting invitation sending). Consider renaming the class to SendEcosystemInvitationDto for consistency with the file name and apparent purpose.

♻️ Rename for consistency
-export class SendEcosystemCreateDto {
+export class SendEcosystemInvitationDto {
   @ApiProperty({ example: 'awqx@yopmail.com' })
   @IsEmail({}, { message: 'Please provide a valid email' })
   @IsNotEmpty({ message: 'Email is required' })
   @IsString({ message: 'Email should be a string' })
   @Transform(({ value }) => value?.trim())
   email: string;

   userId: string;
 }

7-7: Consider using an allowed domain for the API example.

The example email uses yopmail.com, which is listed in the DISALLOWED_EMAIL_DOMAIN array in common.constant.ts (line 898). While this might be intentional for testing purposes, it could be confusing in API documentation.

📝 Update example email
- @ApiProperty({ example: 'awqx@yopmail.com' })
+ @ApiProperty({ example: 'user@example.com' })
  @IsEmail({}, { message: 'Please provide a valid email' })
libs/enum/src/enum.ts (1)

108-110: Consider adding additional status values for EcosystemOrgStatus.

The enum only defines ACTIVE, but typical organization lifecycle workflows often require states like PENDING, INACTIVE, or SUSPENDED. Given the invitation flow being introduced, a PENDING state may be needed when an organization is invited but hasn't yet fully joined.

♻️ Suggested enhancement
 export enum EcosystemOrgStatus {
-  ACTIVE = 'ACTIVE'
+  ACTIVE = 'ACTIVE',
+  PENDING = 'PENDING',
+  INACTIVE = 'INACTIVE'
 }
libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql (1)

2-17: Consider adding a unique constraint on ecosystem.name.

The ecosystem table allows duplicate names. If ecosystem names should be unique across the platform, add a unique index. The repository method checkEcosystemNameExist suggests name uniqueness is expected.

♻️ Suggested addition
+-- CreateIndex
+CREATE UNIQUE INDEX "ecosystem_name_key" ON "ecosystem"("name");
apps/ecosystem/templates/create-ecosystem.templates.ts (1)

40-41: Add fallback fonts for better email client compatibility.

The template uses font-family: Montserrat without a fallback stack. Montserrat is a web font that may not be available in all email clients. Add generic fallback fonts.

♻️ Suggested fix
-    <div style="font-family: Montserrat; font-style: normal; font-weight: 500;
+    <div style="font-family: Montserrat, Arial, Helvetica, sans-serif; font-style: normal; font-weight: 500;
apps/ecosystem/src/ecosystem.controller.ts (2)

43-46: Add explicit type for createEcosystemDto in payload.

The payload type uses shorthand property syntax { createEcosystemDto } without an explicit type, making the expected structure unclear. Consider using an interface or inline type for better type safety.

♻️ Suggested fix
+import { CreateEcosystemDto } from '../dtos/create-ecosystem-dto';
...
   @MessagePattern({ cmd: 'create-ecosystem' })
-  async createEcosystem(@Body() payload: { createEcosystemDto }): Promise<IEcosystem> {
+  async createEcosystem(payload: { createEcosystemDto: CreateEcosystemDto }): Promise<IEcosystem> {
     return this.ecosystemService.createEcosystem(payload.createEcosystemDto);
   }

10-10: Unused logger instance.

The logger is instantiated but never used in this controller. Either utilize it for logging or remove it to avoid dead code.

♻️ Suggested: either remove or use the logger
 export class EcosystemController {
   constructor(private readonly ecosystemService: EcosystemService) {}
-  private readonly logger = new Logger('EcosystemController');
apps/ecosystem/repositories/ecosystem.repository.ts (2)

117-122: Avoid mutating the transaction result object.

Using delete to remove properties from the returned transaction object mutates the original Prisma model instance. This is a side effect that can cause unexpected behavior. Instead, create a new object with only the desired fields.

♻️ Suggested fix
-      // To return selective object data
-      delete transaction.lastChangedDateTime;
-      delete transaction.lastChangedBy;
-      delete transaction.deletedAt;
-
-      return transaction;
+      // Return selective object data
+      const { lastChangedDateTime, lastChangedBy, deletedAt, ...sanitizedEcosystem } = transaction;
+      return sanitizedEcosystem as ecosystem;

37-51: Invitation status is hardcoded to ACCEPTED.

The comment on Line 40 indicates this should be PENDING when the accept/reject flow is ready. Ensure this TODO is tracked and addressed before the feature is fully released, as invitations immediately marked as ACCEPTED bypass the approval workflow.

Would you like me to open an issue to track implementing the pending invitation workflow?

apps/api-gateway/src/ecosystem/ecosystem.service.ts (1)

20-28: Consider extracting NATS topic strings to constants.

The message pattern 'invite-user-for-ecosystem-creation' and similar patterns across methods are hardcoded strings. Extracting these to a shared constants file would improve maintainability and reduce the risk of typos causing silent failures.

♻️ Suggested refactor
// In a shared constants file (e.g., libs/common/src/ecosystem.constants.ts)
export const EcosystemMessagePatterns = {
  INVITE_USER_FOR_ECOSYSTEM_CREATION: 'invite-user-for-ecosystem-creation',
  GET_ECOSYSTEM_INVITATIONS_BY_USER: 'get-ecosystem-invitations-by-user',
  CREATE_ECOSYSTEM: 'create-ecosystem',
  GET_ALL_ECOSYSTEMS: 'get-all-ecosystems',
  GET_ECOSYSTEM_DASHBOARD: 'get-ecosystem-dashboard'
} as const;
libs/prisma-service/prisma/seed.ts (1)

635-646: Add timeout to Keycloak fetch calls to prevent hanging.

The fetch calls to Keycloak have no timeout configured. If Keycloak is unresponsive, this will block the seed process indefinitely.

♻️ Suggested fix using AbortController
+  const controller = new AbortController();
+  const timeout = setTimeout(() => controller.abort(), 30000);
+
   const res = await fetch(
     `${process.env.KEYCLOAK_DOMAIN}realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
     {
       method: 'POST',
       headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
       body: new URLSearchParams({
         grant_type: 'client_credentials',
         client_id: PLATFORM_ADMIN_KEYCLOAK_ID,
         client_secret: PLATFORM_ADMIN_KEYCLOAK_SECRET
-      })
+      }),
+      signal: controller.signal
     }
   );
+  clearTimeout(timeout);
apps/api-gateway/src/ecosystem/ecosystem.controller.ts (1)

172-204: Inconsistent indentation on @Get decorator.

The @Get decorator at line 172 has extra leading whitespace compared to other route decorators. This is a minor formatting issue.

♻️ Fix indentation
-    @Get('/:ecosystemId/:orgId/dashboard')
+  @Get('/:ecosystemId/:orgId/dashboard')
apps/ecosystem/src/ecosystem.service.ts (2)

81-102: Potentially unused method: checkUserExistInPlatform.

This method checks user existence via NATS messaging, but inviteUserToCreateEcosystem (lines 50-60) determines user existence directly via Prisma query. Consider removing this method if unused, or refactoring to use it consistently.

#!/bin/bash
# Description: Check if checkUserExistInPlatform is called anywhere
rg -n "checkUserExistInPlatform" --type ts

126-132: Inconsistent exception type for database errors.

When getInvitationsByUserId fails, it throws InternalServerErrorException with invitationNotFound message, but the actual error could be a database connection issue, not a "not found" scenario. Consider using a more appropriate error message or preserving the original error context.

♻️ Suggested improvement
     try {
       return await this.ecosystemRepository.getInvitationsByUserId(userId);
     } catch (error) {
       this.logger.error('getInvitationsByUserId error', error);
-      throw new InternalServerErrorException(ResponseMessages.ecosystem.error.invitationNotFound);
+      throw new InternalServerErrorException(ResponseMessages.ecosystem.error.fetch);
     }
apps/ecosystem/interfaces/ecosystem.interfaces.ts (2)

41-61: Duplicate interface definitions exist across the codebase.

OrgAgent and LedgerDetails are defined in multiple locations (apps/connection/src/interfaces, apps/issuance/interfaces, apps/ledger/src/interfaces). Consider consolidating these into a shared location like libs/common/src/interfaces to maintain a single source of truth.

#!/bin/bash
# Description: Find all OrgAgent interface definitions
rg -n "export interface OrgAgent" --type ts

3-16: Clarify the difference between logoUrl and logo fields.

ICreateEcosystem has both logoUrl (line 7) and logo (line 9) as optional fields. The distinction is unclear - consider documenting the purpose of each or consolidating if they serve the same purpose.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dc1fbe and 9c8425b.

📒 Files selected for processing (23)
  • .env.sample
  • apps/api-gateway/src/app.module.ts
  • apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts
  • apps/api-gateway/src/ecosystem/ecosystem.controller.ts
  • apps/api-gateway/src/ecosystem/ecosystem.module.ts
  • apps/api-gateway/src/ecosystem/ecosystem.service.ts
  • apps/ecosystem/dtos/create-ecosystem-dto.ts
  • apps/ecosystem/interfaces/ecosystem.interfaces.ts
  • apps/ecosystem/repositories/ecosystem.repository.ts
  • apps/ecosystem/src/ecosystem.controller.ts
  • apps/ecosystem/src/ecosystem.module.ts
  • apps/ecosystem/src/ecosystem.service.ts
  • apps/ecosystem/src/main.ts
  • apps/ecosystem/templates/create-ecosystem.templates.ts
  • apps/ecosystem/tsconfig.app.json
  • libs/common/src/common.constant.ts
  • libs/common/src/response-messages/index.ts
  • libs/enum/src/enum.ts
  • libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json
  • libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql
  • libs/prisma-service/prisma/schema.prisma
  • libs/prisma-service/prisma/seed.ts
  • nest-cli.json
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-17T08:03:16.180Z
Learnt from: KambleSahil3
Repo: credebl/platform PR: 1518
File: libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json:11-20
Timestamp: 2025-11-17T08:03:16.180Z
Learning: In the credebl/platform repository, seed data files like libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json intentionally contain empty strings for sensitive fields (email, username, passwords, API keys, etc.) because these values are populated from .env file at runtime, not hardcoded in the JSON.

Applied to files:

  • libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json
  • libs/prisma-service/prisma/seed.ts
🧬 Code graph analysis (9)
apps/api-gateway/src/ecosystem/ecosystem.module.ts (4)
apps/api-gateway/src/app.module.ts (1)
  • Module (40-123)
apps/ecosystem/src/ecosystem.module.ts (1)
  • Module (18-37)
apps/api-gateway/src/schema/schema.module.ts (1)
  • Module (11-26)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
apps/ecosystem/src/main.ts (3)
libs/logger/src/logger.interface.ts (1)
  • Logger (6-20)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
libs/logger/src/nestjsLoggerServiceAdapter.ts (1)
  • NestjsLoggerServiceAdapter (7-41)
apps/api-gateway/src/ecosystem/ecosystem.controller.ts (2)
apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (1)
  • SendEcosystemCreateDto (6-15)
libs/common/src/interfaces/response.interface.ts (1)
  • IResponse (8-13)
apps/ecosystem/dtos/create-ecosystem-dto.ts (3)
libs/common/src/cast.helper.ts (2)
  • trim (39-43)
  • IsNotSQLInjection (96-127)
libs/validations/minLength.ts (1)
  • MinLength (3-28)
libs/validations/maxLength.ts (1)
  • MaxLength (3-28)
apps/api-gateway/src/ecosystem/ecosystem.service.ts (2)
apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (1)
  • SendEcosystemCreateDto (6-15)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (3)
  • IEcosystemInvitations (63-71)
  • IEcosystem (18-26)
  • IEcosystemDashboard (87-95)
apps/ecosystem/src/ecosystem.service.ts (4)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (4)
  • IEcosystemInvitations (63-71)
  • ICreateEcosystem (3-16)
  • IEcosystem (18-26)
  • IEcosystemDashboard (87-95)
apps/ecosystem/templates/create-ecosystem.templates.ts (1)
  • CreateEcosystemInviteTemplate (2-84)
libs/common/src/dtos/email.dto.ts (1)
  • EmailDto (1-8)
libs/common/src/response-messages/index.ts (1)
  • ResponseMessages (1-727)
apps/ecosystem/repositories/ecosystem.repository.ts (2)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (2)
  • ICreateEcosystem (3-16)
  • IEcosystemDashboard (87-95)
libs/common/src/response-messages/index.ts (1)
  • ResponseMessages (1-727)
apps/ecosystem/src/ecosystem.controller.ts (1)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (3)
  • IEcosystemInvitations (63-71)
  • IEcosystem (18-26)
  • IEcosystemDashboard (87-95)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (4)
apps/api-gateway/src/issuance/utils/helper.ts (1)
  • JsonValue (5-5)
apps/connection/src/interfaces/connection.interfaces.ts (1)
  • OrgAgent (111-126)
apps/issuance/interfaces/issuance.interfaces.ts (1)
  • OrgAgent (269-284)
apps/ledger/src/interfaces/ledgers.interface.ts (1)
  • LedgerDetails (1-6)
🪛 dotenv-linter (4.0.0)
.env.sample

[warning] 121-121: [UnorderedKey] The ECOSYSTEM_NKEY_SEED key should go before the ISSUANCE_NKEY_SEED key

(UnorderedKey)


[warning] 121-121: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🔇 Additional comments (19)
apps/ecosystem/tsconfig.app.json (1)

1-9: LGTM! TypeScript configuration is properly set up.

The configuration correctly extends the base TypeScript config, sets appropriate compiler options, and includes/excludes the right paths for a NestJS microservice.

nest-cli.json (1)

200-208: LGTM! Ecosystem project configuration is properly added.

The ecosystem project configuration follows the same structure and conventions as other microservices in the monorepo. All required fields are correctly set.

.env.sample (1)

121-121: LGTM! Environment variable properly added.

The ECOSYSTEM_NKEY_SEED variable is correctly placed and follows the same naming convention and format as other NKEY_SEED variables in the file. The static analysis warnings about ordering and quotes are false positives—the current format is consistent with the existing pattern.

apps/ecosystem/src/main.ts (1)

14-24: LGTM! Microservice bootstrap is properly configured.

The bootstrap function correctly:

  • Creates a NATS-based microservice with the EcosystemModule
  • Configures NATS options using the ECOSYSTEM_NKEY_SEED environment variable
  • Applies the logger adapter and global exception filter
  • Starts listening with appropriate logging

The implementation follows the same pattern as other microservices in the monorepo.

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

257-259: LGTM! Ecosystem service constant added correctly.

The new ECOSYSTEM_SERVICE constant follows the established naming convention and is properly placed within the enum. This will be used for NATS queue configuration in the ecosystem microservice.

apps/api-gateway/src/app.module.ts (1)

17-17: LGTM! EcosystemModule integrated correctly.

The module is imported and registered following the established pattern used by other feature modules in the API gateway.

Also applies to: 68-68

libs/enum/src/enum.ts (1)

94-98: LGTM!

The EcosystemRoles enum is well-defined with clear semantic values that align with the ecosystem feature's role hierarchy.

apps/ecosystem/templates/create-ecosystem.templates.ts (1)

2-14: LGTM!

The environment variable validation at startup is a good defensive practice that fails fast with a clear error message listing all missing variables.

apps/ecosystem/dtos/create-ecosystem-dto.ts (1)

8-15: LGTM!

The name field has comprehensive validation with trimming, length constraints, and SQL injection protection.

libs/prisma-service/prisma/schema.prisma (1)

735-751: LGTM!

The ecosystem model is well-structured with proper relations to organizations and users, audit fields, and flexible JSON storage for ledgers configuration.

libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql (1)

62-74: Unique constraint on email may be too restrictive.

The ecosystem_invitations table has a unique constraint on email (Line 86). This prevents the same user from receiving multiple invitations over time (e.g., if an invitation expires and needs to be re-sent, or if they're invited to create different ecosystems). Consider if this constraint should be a composite unique on (email, status) or removed entirely in favor of application-level logic.

🔧 Suggested fix
 -- CreateIndex
-CREATE UNIQUE INDEX "ecosystem_invitations_email_key" ON "ecosystem_invitations"("email");
+-- Consider removing or adjusting this constraint based on business requirements
+-- CREATE UNIQUE INDEX "ecosystem_invitations_email_status_key" ON "ecosystem_invitations"("email", "status");

Likely an incorrect or invalid review comment.

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

1-13: LGTM! Service setup follows NestJS patterns correctly.

The service is properly injectable with appropriate dependency injection for NATS-based inter-service communication.


43-46: Payload structure is correct and aligns with the microservice handler.

The createEcosystem method correctly sends payload as { createEcosystemDto }, which matches the expected signature in the ecosystem microservice controller (line 44: payload: { createEcosystemDto }). While the structure differs from other methods in this service that pass properties directly, this is intentional and required for this specific handler. No changes needed.

libs/prisma-service/prisma/seed.ts (2)

139-165: LGTM! Ecosystem roles seeding follows established patterns.

The createEcosystemRoles function correctly follows the existing seed pattern: check if data exists, create if not, log appropriately, and handle errors.


812-817: Verify execution order dependencies between seed functions.

The new seed functions have interdependencies: updateClientId and updatePlatformUserRole both depend on cachedConfig being populated by getPlatformConfig. Ensure the order is correct (as noted in earlier comment, there's currently a bug).

apps/api-gateway/src/ecosystem/ecosystem.controller.ts (1)

77-99: LGTM! Endpoint correctly uses both guards for role enforcement.

The getInvitations endpoint properly applies both AuthGuard('jwt') and OrgRolesGuard to enforce the PLATFORM_ADMIN role requirement.

apps/ecosystem/src/ecosystem.service.ts (1)

40-65: LGTM! Invitation creation flow is well-structured.

The method properly validates inputs, checks user existence, creates the invitation record, and sends the email notification. Good use of the repository pattern for data access.

apps/ecosystem/interfaces/ecosystem.interfaces.ts (1)

63-71: LGTM! Well-defined interfaces for ecosystem domain.

The interfaces IEcosystemInvitations, IEcosystemDetails, and IEcosystemDashboard are clearly structured and align with the Prisma schema and service layer requirements.

Also applies to: 73-95

libs/common/src/response-messages/index.ts (1)

163-248: LGTM! Comprehensive response messages for ecosystem feature.

The ecosystem message block covers all necessary success and error scenarios for the new feature. The structure is consistent with existing message patterns in the file.

Comment on lines +18 to +37
@Module({
imports: [
ClientsModule.register([
{
name: 'NATS_CLIENT',
transport: Transport.NATS,
options: getNatsOptions(CommonConstants.ECOSYSTEM_SERVICE, process.env.ECOSYSTEM_NKEY_SEED)
}
]),
CommonModule,
GlobalConfigModule,
LoggerModule,
PlatformConfig,
ContextInterceptorModule,
CacheModule.register()
],
controllers: [EcosystemController],
providers: [EcosystemService, EcosystemRepository, PrismaService, Logger, NATSClient]
})
export class EcosystemModule {}
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check all references to ECOSYSTEM_NKEY_SEED and surrounding context
rg "ECOSYSTEM_NKEY_SEED" -A 5 -B 5

# Check for getNatsOptions function implementation
rg "getNatsOptions" -A 10 -B 2

# Check for environment variable validation patterns
rg "process\.env\." | head -20

Repository: credebl/platform

Length of output: 50373


🏁 Script executed:

cat -n libs/common/src/nats.config.ts

Repository: credebl/platform

Length of output: 991


🏁 Script executed:

# Search for .env files and environment validation
fd -name ".env*" | head -20

# Check for environment validation in GlobalConfigModule or startup
rg "ECOSYSTEM_NKEY_SEED|GlobalConfigModule" -A 5 --type ts | grep -A 5 -B 5 -i "valid\|throw\|error" | head -50

# Check for any startup validation
rg "bootstrap|startup" -A 10 --type ts | grep -i "nkey\|validate" | head -20

Repository: credebl/platform

Length of output: 2469


🏁 Script executed:

# Search for GlobalConfigModule implementation
rg -l "GlobalConfigModule" | head -5 | xargs rg -A 20 "export.*GlobalConfigModule|class GlobalConfigModule"

# Search for environment variable validation
rg "process\.env\." | grep -i "require\|validate\|throw\|error" | head -20

# Find .env files using git
git ls-files | grep -E "\.env" | head -20

Repository: credebl/platform

Length of output: 166


🏁 Script executed:

# Check .env.sample for ECOSYSTEM_NKEY_SEED and related docs
rg "ECOSYSTEM_NKEY_SEED|NKEY_SEED" -B 2 -A 2 .env.sample

# Also check general structure and comments about required vs optional
head -100 .env.sample

Repository: credebl/platform

Length of output: 5426


The application silently attempts unauthenticated NATS connection when ECOSYSTEM_NKEY_SEED is missing.

When ECOSYSTEM_NKEY_SEED is undefined, getNatsOptions gracefully returns options without an authenticator (see libs/common/src/nats.config.ts). The microservice will still attempt to connect to NATS but without authentication—there is no startup error or validation. While .env.sample documents this variable as required, there is no runtime enforcement. Consider adding startup validation to fail fast with a clear error if this required environment variable is missing, or explicitly document that unauthenticated connection is acceptable for your setup.

🤖 Prompt for AI Agents
In @apps/ecosystem/src/ecosystem.module.ts around lines 18 - 37, The module
currently lets ClientsModule.register call getNatsOptions with
process.env.ECOSYSTEM_NKEY_SEED which can be undefined, causing an
unauthenticated NATS connection; update EcosystemModule to validate
ECOSYSTEM_NKEY_SEED at startup and fail fast: in the module
bootstrap/constructor (or before calling ClientsModule.register) check
process.env.ECOSYSTEM_NKEY_SEED (or use a ConfigService) and throw a clear error
if missing, or alternatively change the ClientsModule.register call for
NATS_CLIENT to only register when the env var exists and otherwise skip
registration while logging a clear message; reference getNatsOptions,
ECOSYSTEM_NKEY_SEED, ClientsModule.register, NATS_CLIENT and EcosystemModule
when making the change.

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
@pranalidhanavade
Copy link
Contributor Author

@coderabbitai full-review

@coderabbitai
Copy link

coderabbitai bot commented Jan 8, 2026

@pranalidhanavade, I'll perform a comprehensive review of all the changes in this PR, analyzing:

  • Ecosystem service implementation - The new microservice architecture and NATS integration
  • API routes - All new endpoints in the ecosystem controller
  • Database schema changes - New tables and relationships for ecosystem entities
  • DTOs and validation - Request/response data structures
  • Repository layer - Database operations and transactions
  • Service layer logic - Business logic and error handling
  • Email templates - Invitation email generation
  • Configuration - Environment variables and module setup

I'll review the entire PR and provide detailed feedback on each component.

✅ Actions performed

Full review triggered.

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

Caution

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

⚠️ Outside diff range comments (1)
libs/prisma-service/prisma/seed.ts (1)

243-254: Inverted condition prevents user_org_roles creation.

The condition if (!userId && !orgId && !orgRoleId) will only evaluate to true when all three are null/undefined. However, the code inside tries to access .id on these values, which would throw. The intended logic appears to be the opposite: create the record when all entities exist.

🐛 Proposed fix
-    if (!userId && !orgId && !orgRoleId) {
+    if (userId && orgId && orgRoleId) {
+      const existingRole = await prisma.user_org_roles.findFirst({
+        where: {
+          userId: userId.id,
+          orgId: orgId.id,
+          orgRoleId: orgRoleId.id
+        }
+      });
+      if (existingRole) {
+        logger.log('Already seeding in org_roles');
+        return;
+      }
       const platformOrganization = await prisma.user_org_roles.create({
🤖 Fix all issues with AI agents
In @apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts:
- Line 7: The ApiProperty example email in send-ecosystem-invitation.ts uses a
disallowed domain (awqx@yopmail.com) which conflicts with
DISALLOWED_EMAIL_DOMAIN in common.constant.ts; update the @ApiProperty({
example: ... }) value on the email field in the SendEcosystemInvitation DTO to
use a neutral allowed domain (e.g., example.com or example.org) so the example
passes domain validation and aligns with DISALLOWED_EMAIL_DOMAIN rules.

In @apps/api-gateway/src/ecosystem/ecosystem.service.ts:
- Around line 52-54: getAllEcosystems currently sends a payload with userId but
the downstream microservice method getAllEcosystems in
apps/ecosystem/src/ecosystem.service.ts does not accept or use it; either remove
the unused userId parameter from the API gateway method signature and stop
sending it in the NATS payload (update ecosystem.service.ts method
getAllEcosystems in apps/api-gateway to accept no args and call sendNatsMessage
with { } or no payload), or update the microservice getAllEcosystems to accept a
userId param and apply user-specific filtering (modify
apps/ecosystem/src/ecosystem.service.ts getAllEcosystems to accept userId and
filter results accordingly) and ensure the gateway continues sending { userId }.

In @apps/ecosystem/dtos/create-ecosystem-dto.ts:
- Around line 17-23: The description property lacks the SQL-injection guard
present on name; add the same validation decorator (e.g., @IsNotSQLInjection())
to the description field in create-ecosystem-dto.ts so both user-provided
strings have consistent SQL injection protection, keeping the existing
@Transform(trim), @IsNotEmpty, @MinLength, @MaxLength, and @IsString decorators
intact.

In @apps/ecosystem/interfaces/ecosystem.interfaces.ts:
- Around line 87-95: The IEcosystemDashboard interface declares
ecosystemLead.role and ecosystemLead.orgName as string but runtime code returns
null for missing values; update the interface so those properties accept null
(e.g., change role: string and orgName: string to role: string | null and
orgName: string | null on IEcosystemDashboard) and then fix any TypeScript
consumer errors by handling the nullable values where
IEcosystemDashboard.ecosystemLead is used.

In @apps/ecosystem/repositories/ecosystem.repository.ts:
- Around line 97-113: Replace the call to this.prisma with the
transaction-scoped prisma parameter when fetching the role (use
prisma.ecosystem_roles.findFirst with where: { name:
EcosystemRoles.ECOSYSTEM_LEAD }) so the lookup is part of the same transaction,
and add a null check for ecosystemRoleDetails before using
ecosystemRoleDetails.id (e.g., throw a descriptive error or create the missing
role) to avoid a null dereference when calling prisma.ecosystem_orgs.create.
- Around line 229-254: The variable ecosystemLeadOrg is misleading because the
code takes ecosystem.ecosystemOrgs[0] (which is the requesting org due to the
query filter) rather than the true ecosystem lead; either (A) change the query
that populates ecosystem.ecosystemOrgs so it selects the org with
ecosystemRole.name === 'ECOSYSTEM_LEAD' (or the ECOSYSTEM_LEAD constant) and
then keep the ecosystemLead mapping using ecosystemLeadOrg, or (B) if the
intention is to return the requesting org, rename ecosystemLeadOrg to
requestingOrg (or similar) and update the ecosystemLead output key to a
different name (e.g., requestingOrg) to avoid implying leadership; locate and
update the symbol ecosystemLeadOrg in ecosystem.repository.ts and adjust the
mapping that builds ecosystemLead accordingly.

In @apps/ecosystem/src/ecosystem.controller.ts:
- Around line 43-46: The payload parameter in createEcosystem is typed as {
createEcosystemDto } without a concrete type; import or define the DTO type
(e.g., CreateEcosystemDto) and change the signature to async
createEcosystem(payload: { createEcosystemDto: CreateEcosystemDto }):
Promise<IEcosystem> (or create a named interface for the message shape) so the
method and this.ecosystemService.createEcosystem receive a strongly typed DTO;
update imports accordingly and adjust any callers/tests if needed.

In @apps/ecosystem/templates/create-ecosystem.templates.ts:
- Line 15: The constructed validUrl (variable validUrl) currently points only to
generic sign-in/sign-up pages and must include identification so the invitation
can be validated; update the logic that builds validUrl to append either an
invitation token or the invitee's email as a query parameter (e.g.,
?invitationToken=<token> or ?email=<encodedEmail>) depending on what is
available, ensuring you URL-encode the email (use encodeURIComponent) and use
the token variable when present; keep using process.env.FRONT_END_URL and the
isUserExist branch but add the query param so the frontend sign-in/sign-up flows
can consume and validate the invitation.

In
@libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql:
- Around line 62-74: The migration is missing the ecosystemId column and its FK;
add a nullable UUID column named ecosystemId to the ecosystem_invitations CREATE
TABLE (place it after "lastChangedBy" UUID NOT NULL) and then add an ALTER TABLE
to create the foreign key constraint named
ecosystem_invitations_ecosystemId_fkey referencing ecosystem(id) with ON DELETE
SET NULL ON UPDATE CASCADE so the DB matches the Prisma relation.

In @libs/prisma-service/prisma/schema.prisma:
- Around line 803-817: The email field in model ecosystem_invitations is
currently marked @unique which prevents the same email from being invited to
multiple ecosystems; replace the single-field uniqueness by either removing the
@unique on email and adding a composite unique on (email, ecosystemId) via an
@@unique([email, ecosystemId]) declaration on model ecosystem_invitations, or
simply remove the uniqueness entirely if duplicates are acceptable; also review
whether ecosystemId should be nullable—if orphaned invitations are undesired,
make ecosystemId non-optional (String without ?) so invitations always link to
an ecosystem.

In @libs/prisma-service/prisma/seed.ts:
- Around line 717-720: The early return when res.status === 409 prevents filling
local fields keycloakUserId, clientId, and clientSecret for user
(user.username); instead of returning, call the Keycloak API to fetch the
existing user by username (or use the same Keycloak client logic used to create
users) to obtain the Keycloak user id and any client credentials, then update
the local DB record (e.g., via prisma.user.update or your existing updateUser
logic) to set keycloakUserId, clientId, and clientSecret; replace the logger.log
+ return path with this fetch-and-update flow and log success or any errors.
🧹 Nitpick comments (14)
nest-cli.json (1)

200-208: Inconsistent JSON indentation.

The nested properties inside the ecosystem project use 4-space indentation while all other projects in this file use 6-space indentation. This doesn't affect functionality but breaks formatting consistency.

🔧 Suggested fix for consistent formatting
     "ecosystem": {
-    "type": "application",
-    "root": "apps/ecosystem",
-    "entryFile": "main",
-    "sourceRoot": "apps/ecosystem/src",
-    "compilerOptions": {
-      "tsConfigPath": "apps/ecosystem/tsconfig.app.json"
-    }
+      "type": "application",
+      "root": "apps/ecosystem",
+      "entryFile": "main",
+      "sourceRoot": "apps/ecosystem/src",
+      "compilerOptions": {
+        "tsConfigPath": "apps/ecosystem/tsconfig.app.json"
+      }
     },
libs/enum/src/enum.ts (1)

108-110: Consider adding additional status values.

EcosystemOrgStatus only defines ACTIVE. Typically, status enums include additional states like INACTIVE, PENDING, or SUSPENDED to handle lifecycle transitions. If these are planned for future iterations, this is fine for now.

apps/ecosystem/src/main.ts (1)

9-9: Remove commented-out import.

Dead commented code should be removed. The nkeyAuthenticator import is unused since authentication is handled internally by getNatsOptions.

🧹 Remove dead code
-// import { nkeyAuthenticator } from 'nats';
libs/common/src/response-messages/index.ts (1)

170-170: Minor inconsistency in error message terminology.

The error message uses "organization Id" while similar messages elsewhere (e.g., line 122) use "orgId". Consider aligning with the existing pattern for consistency.

♻️ Suggested terminology alignment
-      invalidOrgId: 'Invalid organization Id',
+      invalidOrgId: 'Invalid format for organization id',
apps/ecosystem/dtos/create-ecosystem-dto.ts (2)

32-32: Consider adding validation to userId and orgId fields.

The userId and orgId fields lack any validation decorators, yet they appear to be critical identifiers used in business logic. Without validation, invalid or malicious values could cause runtime errors or security issues downstream.

Consider adding appropriate validation such as:

  • @IsNotEmpty() to ensure they are provided
  • @IsString() or @IsUUID() depending on the expected format
  • Input sanitization if needed

Alternatively, if these fields are populated internally (not from user input), document this clearly or make them readonly.

Also applies to: 40-40


29-29: Remove redundant @type decorator.

The @Type(() => String) decorator on line 29 is redundant since tags is already declared as string and @IsString() validates the type. The @Type decorator is typically used for complex type transformations.

♻️ Remove redundant decorator
 @ApiPropertyOptional()
 @IsOptional()
 @Transform(({ value }) => trim(value))
 @IsString({ message: 'tag must be in string format.' })
-@Type(() => String)
 tags?: string;
apps/ecosystem/templates/create-ecosystem.templates.ts (2)

3-14: Add validation for the email parameter.

The email parameter is accepted but never validated before being used in the email template. Invalid email formats could cause issues with the email delivery system or potentially be exploited.

Consider adding email format validation at the beginning of the method:

if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
  throw new Error('Invalid email format provided');
}

17-21: Improve message flow for existing users.

When isUserExist is true, the message variable is set to an empty string (line 18), which results in an awkward sentence structure on line 48: "...to create a new ecosystem on Platform. Please log in to the platform..." followed immediately by an empty <p>${message}</p> tag on line 52.

♻️ Improve message flow
 const message = isUserExist
-  ? ``
+  ? `Please use the button below to log in and get started.`
   : `To get started, kindly register on ${process.env.PLATFORM_NAME} platform using this link:`;

-const secondaryMessage = isUserExist ? `Please log in to the platform to start creating your ecosystem.` : ``;
+const secondaryMessage = isUserExist ? `` : ``;

This provides a smoother narrative flow for existing users.

Also applies to: 48-50

apps/ecosystem/src/ecosystem.controller.ts (1)

10-10: Logger is initialized but not used.

The logger is initialized on line 10 but doesn't appear to be used in any of the controller methods. If logging is planned for future error handling or debugging, this is fine. Otherwise, consider removing it to reduce noise.

If the logger is intended for future use, consider adding log statements for key operations:

@MessagePattern({ cmd: 'create-ecosystem' })
async createEcosystem(payload: { createEcosystemDto: CreateEcosystemDto }): Promise<IEcosystem> {
  this.logger.log(`Creating ecosystem: ${payload.createEcosystemDto.name}`);
  return this.ecosystemService.createEcosystem(payload.createEcosystemDto);
}
apps/ecosystem/repositories/ecosystem.repository.ts (1)

117-122: Consider using Prisma's omit or explicit select instead of mutating the result.

Mutating the returned object with delete works but is less idiomatic. Using Prisma's field selection at query time is cleaner and avoids potential issues if the object is used elsewhere.

♻️ Alternative approach using select
         const createdEcosystem = await prisma.ecosystem.create({
           data: {
             name,
             description,
             tags,
             autoEndorsement,
             logoUrl: logo,
             createdBy: userId,
             lastChangedBy: userId
-          }
+          },
+          select: {
+            id: true,
+            name: true,
+            description: true,
+            tags: true,
+            autoEndorsement: true,
+            logoUrl: true,
+            createdBy: true,
+            createDateTime: true
+          }
         });

Then remove lines 118-120.

libs/prisma-service/prisma/seed.ts (1)

541-545: Add null check for cachedConfig before accessing properties.

If updateClientId is called before getPlatformConfig, accessing cachedConfig.platformEmail will throw. While the current main() order is correct, adding a defensive check improves robustness.

♻️ Proposed fix
   for (const user of users) {
+    if (!cachedConfig) {
+      throw new Error('Platform config not loaded. Call getPlatformConfig first.');
+    }
     if (user.email === cachedConfig.platformEmail) {
       logger.log('⚠️ Skipping update of clientId for platform admin');
       continue;
     }
apps/ecosystem/src/ecosystem.service.ts (1)

160-164: Consider using dot notation for type safety.

The bracket notation organization['ecosystemRole']['name'] works but bypasses TypeScript's type checking. If the ecosystemRole relationship is properly typed, dot notation provides better IDE support and compile-time safety.

♻️ Cleaner approach
       for (const organization of ecoOrganizationList) {
-        if (organization['ecosystemRole']['name'] === EcosystemRoles.ECOSYSTEM_MEMBER) {
+        if (organization.ecosystemRole?.name === EcosystemRoles.ECOSYSTEM_MEMBER) {
           throw new ConflictException(ResponseMessages.ecosystem.error.ecosystemOrgAlready);
         }
       }
apps/api-gateway/src/ecosystem/ecosystem.controller.ts (1)

125-127: Unusual bracket notation for property access.

user?.['id'] is functionally equivalent to user?.id but less conventional. If there's a TypeScript typing issue with the user object, consider extending the type definition instead.

♻️ Cleaner approach
     createEcosystemDto.orgId = orgId;
-    createEcosystemDto.userId = user?.['id'];
+    createEcosystemDto.userId = user?.id;
apps/ecosystem/interfaces/ecosystem.interfaces.ts (1)

73-85: Consider nullable type for deletedAt.

The deletedAt property is typed as Date, but for active (non-deleted) records, this value will be null. Consider using Date | null to accurately represent the data model.

♻️ Proposed fix
 export interface IEcosystemDetails {
   id: string;
   name: string;
   description: string;
   tags: string;
   createDateTime: Date;
   createdBy: string;
   lastChangedDateTime: Date;
   lastChangedBy: string;
-  deletedAt: Date;
+  deletedAt: Date | null;
   logoUrl: string;
   ledgers: string[];
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dc1fbe and 64b2088.

📒 Files selected for processing (23)
  • .env.sample
  • apps/api-gateway/src/app.module.ts
  • apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts
  • apps/api-gateway/src/ecosystem/ecosystem.controller.ts
  • apps/api-gateway/src/ecosystem/ecosystem.module.ts
  • apps/api-gateway/src/ecosystem/ecosystem.service.ts
  • apps/ecosystem/dtos/create-ecosystem-dto.ts
  • apps/ecosystem/interfaces/ecosystem.interfaces.ts
  • apps/ecosystem/repositories/ecosystem.repository.ts
  • apps/ecosystem/src/ecosystem.controller.ts
  • apps/ecosystem/src/ecosystem.module.ts
  • apps/ecosystem/src/ecosystem.service.ts
  • apps/ecosystem/src/main.ts
  • apps/ecosystem/templates/create-ecosystem.templates.ts
  • apps/ecosystem/tsconfig.app.json
  • libs/common/src/common.constant.ts
  • libs/common/src/response-messages/index.ts
  • libs/enum/src/enum.ts
  • libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json
  • libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql
  • libs/prisma-service/prisma/schema.prisma
  • libs/prisma-service/prisma/seed.ts
  • nest-cli.json
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-17T08:03:16.180Z
Learnt from: KambleSahil3
Repo: credebl/platform PR: 1518
File: libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json:11-20
Timestamp: 2025-11-17T08:03:16.180Z
Learning: In the credebl/platform repository, seed data files like libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json intentionally contain empty strings for sensitive fields (email, username, passwords, API keys, etc.) because these values are populated from .env file at runtime, not hardcoded in the JSON.

Applied to files:

  • libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json
  • apps/ecosystem/src/ecosystem.module.ts
  • libs/prisma-service/prisma/seed.ts
🧬 Code graph analysis (8)
apps/api-gateway/src/ecosystem/ecosystem.module.ts (3)
apps/api-gateway/src/app.module.ts (1)
  • Module (40-123)
apps/ecosystem/src/ecosystem.module.ts (1)
  • Module (18-37)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
apps/ecosystem/src/ecosystem.module.ts (1)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
apps/ecosystem/dtos/create-ecosystem-dto.ts (3)
libs/common/src/cast.helper.ts (2)
  • trim (39-43)
  • IsNotSQLInjection (96-127)
libs/validations/minLength.ts (1)
  • MinLength (3-28)
libs/validations/maxLength.ts (1)
  • MaxLength (3-28)
apps/api-gateway/src/ecosystem/ecosystem.service.ts (2)
apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (1)
  • SendEcosystemCreateDto (6-13)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (3)
  • IEcosystemInvitations (63-71)
  • IEcosystem (18-26)
  • IEcosystemDashboard (87-95)
apps/ecosystem/repositories/ecosystem.repository.ts (2)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (2)
  • ICreateEcosystem (3-16)
  • IEcosystemDashboard (87-95)
libs/common/src/response-messages/index.ts (1)
  • ResponseMessages (1-659)
apps/ecosystem/src/main.ts (3)
libs/logger/src/logger.interface.ts (1)
  • Logger (6-20)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
libs/logger/src/nestjsLoggerServiceAdapter.ts (1)
  • NestjsLoggerServiceAdapter (7-41)
apps/api-gateway/src/ecosystem/ecosystem.controller.ts (2)
apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (1)
  • SendEcosystemCreateDto (6-13)
libs/common/src/interfaces/response.interface.ts (1)
  • IResponse (8-13)
apps/ecosystem/src/ecosystem.controller.ts (1)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (3)
  • IEcosystemInvitations (63-71)
  • IEcosystem (18-26)
  • IEcosystemDashboard (87-95)
🪛 dotenv-linter (4.0.0)
.env.sample

[warning] 121-121: [UnorderedKey] The ECOSYSTEM_NKEY_SEED key should go before the ISSUANCE_NKEY_SEED key

(UnorderedKey)


[warning] 121-121: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🔇 Additional comments (31)
libs/enum/src/enum.ts (2)

94-98: LGTM!

The EcosystemRoles enum is well-defined with clear role hierarchy (Owner, Lead, Member).


100-106: LGTM!

The EcosystemConfigSettings enum provides appropriate configuration keys for ecosystem feature toggles.

libs/prisma-service/prisma/schema.prisma (6)

39-40: LGTM!

User model relations properly added for ecosystem feature integration.


160-160: LGTM!

Organisation model relation properly added for ecosystem integration.


735-753: LGTM!

The ecosystem model is well-structured with appropriate audit fields, optional soft-delete via deletedAt, and properly defined relations.


755-764: LGTM!

The ecosystem_roles model follows the established pattern with unique name constraint.


766-780: LGTM!

The ecosystem_users model correctly enforces a unique constraint on (userId, ecosystemId) to prevent duplicate user-ecosystem associations.


782-801: LGTM!

The ecosystem_orgs model correctly enforces a unique constraint on (orgId, ecosystemId) to prevent duplicate organization-ecosystem associations.

libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql (5)

85-86: Verify global uniqueness on email is intended.

The unique index on ecosystem_invitations.email prevents the same email from being invited to multiple ecosystems. If this is intentional (e.g., invitations are tied to a single ecosystem creation flow), this is fine. Otherwise, consider a composite unique index.


1-17: LGTM!

The ecosystem table is well-structured with appropriate columns, data types, and constraints.


19-29: LGTM!

The ecosystem_roles table is properly defined with a unique constraint on name.


31-43: LGTM!

The ecosystem_users table correctly defines the user-ecosystem association.


45-60: LGTM!

The ecosystem_orgs table properly links organizations to ecosystems with role associations.

.env.sample (1)

121-121: LGTM!

The ECOSYSTEM_NKEY_SEED environment variable is correctly added following the pattern of other NKEY_SEED variables.

Static analysis flagged ordering (should be before ISSUANCE_NKEY_SEED alphabetically) and missing quotes, but the existing NKEY_SEED variables don't follow strict alphabetical ordering and also lack quotes, so this maintains consistency with the current style.

apps/ecosystem/src/main.ts (1)

14-24: LGTM!

The bootstrap function correctly initializes the ecosystem microservice with NATS transport, configures logging via NestjsLoggerServiceAdapter, and applies the global exception filter. The pattern is consistent with other microservices in the codebase.

apps/ecosystem/tsconfig.app.json (1)

1-9: LGTM!

The TypeScript configuration correctly extends the root config, sets the appropriate output directory, and follows the established pattern used by other applications in the monorepo.

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

257-259: LGTM! Clean addition of ecosystem service constant.

The new ECOSYSTEM_SERVICE constant follows the established pattern and is correctly placed in the enum. The value 'ecosystem' is used consistently across the ecosystem module configurations for NATS transport setup.

apps/api-gateway/src/ecosystem/ecosystem.module.ts (1)

10-22: LGTM! Well-structured API gateway client module.

The module configuration is correct:

  • Uses ECOSYSTEM_SERVICE as the queue name for routing messages to the ecosystem microservice
  • Uses API_GATEWAY_NKEY_SEED for authentication (appropriate since this is the API gateway)
  • Minimal provider set is appropriate for a client-side gateway module
apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (1)

8-12: Good validation implementation.

The validation decorators are properly configured with clear error messages, and the Transform decorator ensures the email is trimmed before validation.

libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json (1)

178-187: LGTM! Ecosystem role seed data is properly structured.

The new ecosystemRoleData follows the same pattern as orgRoleData and provides clear role definitions for the ecosystem feature. The structure is consistent with the existing seed data format.

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

18-36: LGTM! Well-architected ecosystem microservice module.

The module configuration is correct for a standalone microservice:

  • Uses ECOSYSTEM_SERVICE as the queue name (this service listens on this queue)
  • Uses ECOSYSTEM_NKEY_SEED for authentication (appropriate for the ecosystem service)
  • Includes comprehensive data access layers (EcosystemRepository, PrismaService) which are necessary for the service implementation
  • Proper separation of concerns compared to the API gateway client module
apps/api-gateway/src/app.module.ts (1)

1-76: LGTM! Module wiring is correct.

The addition of EcosystemModule and related imports follows the established pattern in this module. All necessary imports are present, and the module is properly registered in the imports array.

apps/ecosystem/repositories/ecosystem.repository.ts (1)

30-51: LGTM!

The invitation creation logic is straightforward and correctly handles the nullable invitedUserId.

apps/api-gateway/src/ecosystem/ecosystem.service.ts (1)

1-63: LGTM!

The gateway service correctly proxies requests to the microservice via NATS. The structure follows the established patterns in the codebase.

libs/prisma-service/prisma/seed.ts (2)

139-165: LGTM!

The createEcosystemRoles function follows the established pattern for seeding data with proper existence checks.


812-817: LGTM on seed execution order.

The ordering of new seed steps is correct: getPlatformConfig populates cachedConfig before functions that depend on it (updateClientId, updatePlatformUserRole, createKeycloakUser).

apps/ecosystem/src/ecosystem.service.ts (2)

45-70: LGTM!

The inviteUserToCreateEcosystem method has proper validation, correctly handles both existing and new users, and triggers email notification.


90-128: Remove unused methods: checkUserExistInPlatform and getUserUserId.

These methods are defined in the ecosystem service but are never called. The same methods exist and are actively used in organization.service.ts, indicating these are duplicate, dead code.

apps/api-gateway/src/ecosystem/ecosystem.controller.ts (2)

41-70: LGTM!

The invitation endpoint is well-structured with appropriate authorization (PLATFORM_ADMIN only), proper HTTP status codes, and consistent response format.


106-137: LGTM!

The ecosystem creation endpoint correctly extracts orgId from path parameters and userId from the authenticated user, then delegates to the service layer.

apps/ecosystem/interfaces/ecosystem.interfaces.ts (1)

3-16: LGTM!

The ICreateEcosystem interface appropriately marks ledgers as required while keeping other fields optional for flexible ecosystem creation scenarios.

Comment on lines 229 to 254
const ecosystemLeadOrg = ecosystem.ecosystemOrgs?.length ? ecosystem.ecosystemOrgs[0] : null;

return {
ecosystem: [
{
id: ecosystem.id,
name: ecosystem.name,
description: ecosystem.description,
tags: ecosystem.tags,
createDateTime: ecosystem.createDateTime,
createdBy: ecosystem.createdBy,
lastChangedDateTime: ecosystem.lastChangedDateTime,
lastChangedBy: ecosystem.lastChangedBy,
deletedAt: ecosystem.deletedAt,
logoUrl: ecosystem.logoUrl,
ledgers: ecosystem.ledgers as string[]
}
],
membersCount: 0,
endorsementsCount: 0,
ecosystemLead: ecosystemLeadOrg
? {
role: ecosystemLeadOrg.ecosystemRole?.name ?? null,
orgName: ecosystemLeadOrg.organisation?.name ?? null
}
: null
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 variable name: ecosystemLeadOrg may not be the actual ecosystem lead.

The query filters ecosystemOrgs by the provided orgId, so ecosystemOrgs[0] returns the requesting organization's data, not necessarily the ecosystem lead. If the intent is to show the actual ecosystem lead, the query should filter by ECOSYSTEM_LEAD role instead.

🔧 If you need the actual ecosystem lead
-    const ecosystemLeadOrg = ecosystem.ecosystemOrgs?.length ? ecosystem.ecosystemOrgs[0] : null;
+    // Fetch the actual ecosystem lead separately
+    const ecosystemLeadOrg = await this.prisma.ecosystem_orgs.findFirst({
+      where: {
+        ecosystemId,
+        deletedAt: null,
+        ecosystemRole: { name: EcosystemRoles.ECOSYSTEM_LEAD }
+      },
+      include: {
+        ecosystemRole: true,
+        organisation: { select: { name: true } }
+      }
+    });

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

🤖 Prompt for AI Agents
In @apps/ecosystem/repositories/ecosystem.repository.ts around lines 229 - 254,
The variable ecosystemLeadOrg is misleading because the code takes
ecosystem.ecosystemOrgs[0] (which is the requesting org due to the query filter)
rather than the true ecosystem lead; either (A) change the query that populates
ecosystem.ecosystemOrgs so it selects the org with ecosystemRole.name ===
'ECOSYSTEM_LEAD' (or the ECOSYSTEM_LEAD constant) and then keep the
ecosystemLead mapping using ecosystemLeadOrg, or (B) if the intention is to
return the requesting org, rename ecosystemLeadOrg to requestingOrg (or similar)
and update the ecosystemLead output key to a different name (e.g.,
requestingOrg) to avoid implying leadership; locate and update the symbol
ecosystemLeadOrg in ecosystem.repository.ts and adjust the mapping that builds
ecosystemLead accordingly.

Comment on lines 43 to 46
@MessagePattern({ cmd: 'create-ecosystem' })
async createEcosystem(payload: { createEcosystemDto }): Promise<IEcosystem> {
return this.ecosystemService.createEcosystem(payload.createEcosystemDto);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add type annotation for createEcosystemDto.

The payload parameter on line 44 has an object type with an untyped createEcosystemDto property. This reduces type safety and IDE support.

🔧 Add proper type annotation
+import { CreateEcosystemDto } from '../dtos/create-ecosystem-dto';
+
 @MessagePattern({ cmd: 'create-ecosystem' })
-async createEcosystem(payload: { createEcosystemDto }): Promise<IEcosystem> {
+async createEcosystem(payload: { createEcosystemDto: CreateEcosystemDto }): Promise<IEcosystem> {
   return this.ecosystemService.createEcosystem(payload.createEcosystemDto);
 }
📝 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
@MessagePattern({ cmd: 'create-ecosystem' })
async createEcosystem(payload: { createEcosystemDto }): Promise<IEcosystem> {
return this.ecosystemService.createEcosystem(payload.createEcosystemDto);
}
import { CreateEcosystemDto } from '../dtos/create-ecosystem-dto';
@MessagePattern({ cmd: 'create-ecosystem' })
async createEcosystem(payload: { createEcosystemDto: CreateEcosystemDto }): Promise<IEcosystem> {
return this.ecosystemService.createEcosystem(payload.createEcosystemDto);
}
🤖 Prompt for AI Agents
In @apps/ecosystem/src/ecosystem.controller.ts around lines 43 - 46, The payload
parameter in createEcosystem is typed as { createEcosystemDto } without a
concrete type; import or define the DTO type (e.g., CreateEcosystemDto) and
change the signature to async createEcosystem(payload: { createEcosystemDto:
CreateEcosystemDto }): Promise<IEcosystem> (or create a named interface for the
message shape) so the method and this.ecosystemService.createEcosystem receive a
strongly typed DTO; update imports accordingly and adjust any callers/tests if
needed.

Comment on lines 717 to 720
if (409 === res.status) {
logger.log(`⚠️ User ${user.username} already exists`);
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 | 🟠 Major

Early return on 409 may leave local user record incomplete.

When Keycloak returns 409 (user exists), the function returns without updating the local database user's keycloakUserId, clientId, and clientSecret. If a previous seed run created the Keycloak user but failed before updating the local DB, subsequent runs won't fix the incomplete state.

🔧 Consider fetching the existing Keycloak user ID and updating local DB
   if (409 === res.status) {
     logger.log(`⚠️ User ${user.username} already exists`);
-    return;
+    // Fetch existing user ID from Keycloak and update local DB
+    const searchRes = await fetch(
+      `${KEYCLOAK_DOMAIN}admin/realms/${KEYCLOAK_REALM}/users?email=${encodeURIComponent(user.email)}`,
+      {
+        headers: { Authorization: `Bearer ${token}` }
+      }
+    );
+    const existingUsers = await searchRes.json();
+    if (existingUsers?.length > 0) {
+      const keycloakUserId = existingUsers[0].id;
+      // Continue to update local DB with existing Keycloak user ID
+      // (move lines 745-759 to a shared helper)
+    }
+    return;
   }

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

🤖 Prompt for AI Agents
In @libs/prisma-service/prisma/seed.ts around lines 717 - 720, The early return
when res.status === 409 prevents filling local fields keycloakUserId, clientId,
and clientSecret for user (user.username); instead of returning, call the
Keycloak API to fetch the existing user by username (or use the same Keycloak
client logic used to create users) to obtain the Keycloak user id and any client
credentials, then update the local DB record (e.g., via prisma.user.update or
your existing updateUser logic) to set keycloakUserId, clientId, and
clientSecret; replace the logger.log + return path with this fetch-and-update
flow and log success or any errors.

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
@pranalidhanavade
Copy link
Contributor Author

@coderabbitai full-review

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

@pranalidhanavade, I'll perform a comprehensive review of all the changes in this PR, analyzing:

  • Ecosystem service implementation - The new microservice architecture and NATS integration
  • API routes - All new endpoints in the ecosystem controller
  • Database schema changes - New tables and relationships for ecosystem entities
  • DTOs and validation - Request/response data structures
  • Repository layer - Database operations and transactions
  • Service layer logic - Business logic and error handling
  • Email templates - Invitation email generation
  • Configuration - Environment variables and module setup

I'll review the entire PR and provide detailed feedback on each component.

✅ Actions performed

Full review triggered.

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

Caution

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

⚠️ Outside diff range comments (1)
apps/api-gateway/src/app.module.ts (1)

46-52: Fail fast if process.env.API_GATEWAY_NKEY_SEED is missing (prevents opaque NATS startup failures).
Right now getNatsOptions(..., undefined) can silently propagate to the NATS client config.

Proposed fix
@@
     ClientsModule.register([
       {
         name: 'NATS_CLIENT',
         transport: Transport.NATS,
-        options: getNatsOptions(CommonConstants.API_GATEWAY_SERVICE, process.env.API_GATEWAY_NKEY_SEED)
+        options: getNatsOptions(
+          CommonConstants.API_GATEWAY_SERVICE,
+          (() => {
+            const seed = process.env.API_GATEWAY_NKEY_SEED;
+            if (!seed) throw new Error('Missing env: API_GATEWAY_NKEY_SEED');
+            return seed;
+          })()
+        )
       }
     ]),
🤖 Fix all issues with AI agents
In @apps/api-gateway/src/ecosystem/ecosystem.controller.ts:
- Around line 119-137: The controller mutates the incoming DTO
(createEcosystemDto) before calling ecosystemService.createEcosystem which can
break validation/transform and cause side effects; instead construct a new
payload object (e.g., const payload = { ...createEcosystemDto, orgId, userId:
user?.['id'] }) inside createNewEcosystem and pass that to
ecosystemService.createEcosystem, leaving the original createEcosystemDto
untouched and preserving intent in the response building that follows.

In @apps/ecosystem/interfaces/ecosystem.interfaces.ts:
- Around line 63-71: The IEcosystemInvitations interface has incorrect
nullability: change userId to allow null (e.g., userId?: string | null) to match
persisted data, and any soft-delete timestamp fields (deletedAt) in this file’s
interfaces (including the other interface around lines 73-85) should be typed as
Date | null (e.g., deletedAt?: Date | null); update IEcosystemInvitations and
the other interface(s) accordingly so the optional/nullable types align with
Prisma’s persisted shapes.

In @apps/ecosystem/repositories/ecosystem.repository.ts:
- Around line 131-143: The method checkEcosystemNameExist assumes
prisma.ecosystem.findFirst always returns an ecosystem but findFirst can return
null; change its return type from Promise<ecosystem> to Promise<ecosystem |
null> (or Nullable<ecosystem> depending on your types) and update any callers to
handle a possible null result; locate the method by name checkEcosystemNameExist
and the prisma call this.prisma.ecosystem.findFirst and adjust the signature and
any dependent usages accordingly.
- Around line 234-292: The return is unsafely casting ecosystem.ledgers to
string[] in getEcosystemDashboard which can produce runtime shape bugs; validate
and normalize ecosystem.ledgers before returning by checking
Array.isArray(ecosystem.ledgers) and that every item is a string (or coerce
items to strings) and default to an empty array if validation fails, then use
that normalized array instead of ecosystem.ledgers as string[].
- Around line 30-51: The createEcosystemInvitation function currently sets
status to Invitation.ACCEPTED which bypasses invite/accept flow; change the
initial status to the pending enum value (e.g., Invitation.PENDING or
equivalent) so invitations are created in a pending state and only move to
ACCEPTED when the accept flow runs; update any tests or callers expecting
ACCEPTED if needed and keep references to createEcosystemInvitation and
Invitation to locate the change.
- Around line 70-129: The code calls createNewEcosystem and then mutates the
returned Prisma object with delete statements; instead of deleting properties,
modify the prisma.$transaction flow to use prisma.ecosystem.create({ data: ...,
select: { /* only include fields to expose: id, name, description, tags,
autoEndorsement, logoUrl, createdBy, createdDateTime, ... */ } }) (and similarly
adjust any subsequent reads) so the returned value already matches the public
ecosystem shape, remove the delete
transaction.lastChangedDateTime/lastChangedBy/deletedAt lines, and ensure the
function signature or returned type aligns with the selected fields (or map the
selected result to the ecosystem type) to keep results type-safe and consistent.

In @apps/ecosystem/src/ecosystem.controller.ts:
- Around line 18-24: The createEcosystem handler’s parameter is untyped: add the
proper DTO type to the createEcosystem(createEcosystemDto) parameter (use the
existing CreateEcosystemDto type used elsewhere) so the method signature is
async createEcosystem(createEcosystemDto: CreateEcosystemDto):
Promise<IEcosystem> and update any imports; also enable global ValidationPipe
for NATS payloads in the microservice bootstrap (instantiate and apply
ValidationPipe when creating the microservice) so DTO class-validator rules are
enforced for NATS messages.

In @apps/ecosystem/src/ecosystem.service.ts:
- Around line 90-111: The catch block in checkUserExistInPlatform (and the
similar block around lines 113-128) assumes error.status exists; change it to
derive a numeric status with a safe default (e.g., const status = error?.status
?? 500) and a safe message (e.g., const message = error?.message ??
String(error)), then throw new HttpException({ status, error: message }, status)
so the HttpException always receives a valid status and a meaningful message.
- Around line 45-70: The method inviteUserToCreateEcosystem writes
invitedUser?.id ?? null into the DB but IEcosystemInvitations.userId is declared
non-null string, causing a type-contract mismatch; either make
IEcosystemInvitations.userId nullable (string | null) and update the
createEcosystemInvitation return type and any callers to handle null, or ensure
inviteUserToCreateEcosystem always supplies a non-null userId (e.g., create or
fetch a user first) and adjust createEcosystemInvitation signatures; update the
types for IEcosystemInvitations and the createEcosystemInvitation method to stay
consistent with the actual stored value.
- Around line 30-37: The constructor currently injects Logger which will fail
unless a Logger provider exists; remove Logger from the constructor parameters
and instead instantiate it inside the service class (e.g., add a private
readonly logger = new Logger(EcosystemService.name) field) and import Logger
from @nestjs/common; update references to the injected logger to use the new
class field and remove Logger from the constructor signature.
- Around line 72-88: The email subject in sendInviteEmailTemplate currently uses
process.env.PLATFORM_NAME which can be undefined; update the logic to derive a
safe platform name (e.g., use platformConfigData.platformName if available,
otherwise fall back to a sensible default like "Platform" or an empty string)
and construct emailSubject from that safe value so it never becomes "undefined"
— modify the assignment to emailData.emailSubject in sendInviteEmailTemplate to
reference this fallback.

In @apps/ecosystem/templates/create-ecosystem.templates.ts:
- Line 4: The sendInviteEmailTemplate function currently declares an unused
email parameter; either remove the unused parameter or use it in the returned
template. To fix, update sendInviteEmailTemplate(email: string, isUserExist:
boolean) to interpolate the email into the template body (e.g., include a line
like “Invited email: {email}” or personalize the greeting with the recipient
address) and ensure any conditional text that depends on isUserExist still
renders correctly, or if the email is truly unnecessary, remove the email
parameter and callers should stop passing it.
- Line 21: The FRONT_END_URL is used directly when building validUrl, so
escape/sanitize it like the other environment values to prevent potential XSS;
update the validUrl assignment (the const validUrl variable) to use the same
escaping helper used for lines where other env vars are sanitized (e.g., pass
process.env.FRONT_END_URL through the existing escape/sanitize function or use
encodeURI on it) before concatenating the path (/sign-in or /sign-up).

In
@libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json:
- Around line 178-187: The seed data is missing the "Ecosystem Owner" role
referenced by the EcosystemRoles enum (ECOSYSTEM_OWNER); update the
ecosystemRoleData array to include an object for the missing role (e.g., name
"Ecosystem Owner" and an appropriate description) so all enum members have
corresponding seed entries and avoid runtime lookups failing.

In
@libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql:
- Around line 62-74: Add a nullable deletedAt TIMESTAMPTZ(6) column to the
ecosystem_invitations table to match the soft-delete pattern used elsewhere:
update the CREATE TABLE "ecosystem_invitations" statement to include "deletedAt"
TIMESTAMPTZ(6) NULL (default NULL) alongside the other timestamp columns so
invitations follow the same soft-delete convention as other ecosystem tables.

In @libs/prisma-service/prisma/schema.prisma:
- Around line 803-819: The model ecosystem_invitations currently has a global
@unique on email which prevents multiple invites per email across ecosystems;
replace that with a composite unique index @@unique([email, ecosystemId]) in the
ecosystem_invitations model, update the createEcosystemInvitation function to
accept an ecosystemId parameter and set ecosystemId when creating the invitation
record, propagate the new parameter to all callers of createEcosystemInvitation
so the field is populated, and wrap the Prisma create call in a try-catch to
handle and translate unique-constraint errors (e.g., detect
PrismaUniqueConstraintError or error.code) into a graceful application error.
🧹 Nitpick comments (12)
.env.sample (1)

121-121: LGTM! Environment variable added consistently.

The ECOSYSTEM_NKEY_SEED variable follows the same pattern as other NKEY_SEED variables in the file.

Note: Static analysis suggests reordering (placing before ISSUANCE_NKEY_SEED) and adding quotes around the value for consistency, but these are optional style preferences.

libs/prisma-service/prisma/seed.ts (1)

660-764: Keycloak user creation is well-implemented with minor clarification needed.

The createKeycloakUser function properly handles user creation, conflict scenarios, and credential encryption. It correctly depends on cachedConfig being populated before execution.

Minor observation: Line 705 checks user.password but the password always comes from PLATFORM_ADMIN_USER_PASSWORD env var (line 690). Consider simplifying this to directly check the env var for clarity.

♻️ Optional clarification
-      credentials: user.password
-        ? [
+      credentials: PLATFORM_ADMIN_USER_PASSWORD
+        ? [
             {
               type: 'password',
-              value: user.password,
+              value: PLATFORM_ADMIN_USER_PASSWORD,
               temporary: false
             }
           ]
         : []
libs/prisma-service/prisma/schema.prisma (1)

766-801: LGTM! Ecosystem membership models are well-structured.

Both ecosystem_users and ecosystem_orgs models properly prevent duplicate memberships with unique composite constraints and establish correct relations.

Optional: Consider using an enum for the status field (line 785) instead of String to ensure type safety and prevent invalid status values.

apps/ecosystem/src/main.ts (1)

9-9: Remove commented-out import.

The commented-out nkeyAuthenticator import is unused since getNatsOptions handles NATS authentication internally. Remove this dead code to keep the file clean.

♻️ Suggested fix
 import NestjsLoggerServiceAdapter from '@credebl/logger/nestjsLoggerServiceAdapter';
-// import { nkeyAuthenticator } from 'nats';
 import { getNatsOptions } from '@credebl/common/nats.config';
libs/enum/src/enum.ts (1)

108-110: Consider expanding the ecosystem organization status enum.

The enum currently only defines ACTIVE status. Consider whether additional states are needed such as PENDING, INACTIVE, SUSPENDED, or REJECTED to support the full lifecycle of ecosystem organizations.

libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql (1)

45-60: Consider adding a constraint or enum for the status field.

The status field is defined as TEXT without any constraints. Consider adding a CHECK constraint or using a PostgreSQL enum type to enforce valid status values and prevent invalid data entry.

💡 Example with CHECK constraint
 CREATE TABLE "ecosystem_orgs" (
     "id" UUID NOT NULL,
     "orgId" UUID NOT NULL,
     "status" TEXT NOT NULL,
+    CONSTRAINT "ecosystem_orgs_status_check" CHECK (status IN ('ACTIVE', 'PENDING', 'INACTIVE')),
     "deploymentMode" TEXT,
apps/ecosystem/templates/create-ecosystem.templates.ts (2)

5-20: Consider using a utility function for environment variable validation.

Based on learnings, the team prefers creating utilities for validating required environment variables rather than implementing inline validation. This approach promotes reusability across different parts of the application.

Consider extracting this validation logic into a shared utility function that can be reused by other template classes.


18-18: Use conventional comparison syntax.

The condition 0 < missingVars.length is unconventional. The idiomatic way to write this is missingVars.length > 0.

♻️ Proposed fix
-    if (0 < missingVars.length) {
+    if (missingVars.length > 0) {
       throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
     }
apps/ecosystem/dtos/create-ecosystem-dto.ts (2)

26-31: Remove redundant @type decorator.

The @Type(() => String) decorator on line 30 is redundant since @Transform(({ value }) => trim(value)) on line 28 already handles type transformation, and @IsString() on line 29 validates the type.

♻️ Proposed fix
   @ApiPropertyOptional()
   @IsOptional()
   @Transform(({ value }) => trim(value))
   @IsString({ message: 'tag must be in string format.' })
-  @Type(() => String)
   tags?: string;

33-33: Consider adding validation for userId and orgId fields.

The userId and orgId fields lack validation decorators. If these values are set by the controller or service layer, consider adding appropriate validation decorators (@IsNotEmpty(), @IsUUID(), etc.) to ensure data integrity at the DTO level.

If these fields are intentionally excluded from validation because they're set programmatically, consider adding comments to clarify this design decision.

Also applies to: 41-41

apps/api-gateway/src/ecosystem/ecosystem.service.ts (1)

19-59: Centralize NATS cmd strings (prevents gateway ↔ microservice drift).
Right now the contract is duplicated as raw strings in multiple places.

Example direction
+// e.g. libs/common/src/nats/ecosystem.cmd.ts
+export const ECOSYSTEM_CMDS = {
+  INVITE_CREATE: 'invite-user-for-ecosystem-creation',
+  GET_INVITES_BY_USER: 'get-ecosystem-invitations-by-user',
+  CREATE: 'create-ecosystem',
+  GET_ALL: 'get-all-ecosystems',
+  DASHBOARD: 'get-ecosystem-dashboard'
+} as const;
-    return this.natsClient.sendNatsMessage(this.serviceProxy, 'create-ecosystem', payload);
+    return this.natsClient.sendNatsMessage(this.serviceProxy, ECOSYSTEM_CMDS.CREATE, payload);
apps/ecosystem/interfaces/ecosystem.interfaces.ts (1)

27-61: Avoid re-defining OrgAgent / LedgerDetails in multiple domains (drift risk).
There are already similar OrgAgent interfaces elsewhere (per provided snippets). Prefer a shared type from a common lib (or re-export) so changes don’t desync.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dc1fbe and 3991bab.

📒 Files selected for processing (24)
  • .env.sample
  • apps/api-gateway/src/app.module.ts
  • apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts
  • apps/api-gateway/src/ecosystem/ecosystem.controller.ts
  • apps/api-gateway/src/ecosystem/ecosystem.module.ts
  • apps/api-gateway/src/ecosystem/ecosystem.service.ts
  • apps/ecosystem/dtos/create-ecosystem-dto.ts
  • apps/ecosystem/interfaces/ecosystem.interfaces.ts
  • apps/ecosystem/repositories/ecosystem.repository.ts
  • apps/ecosystem/src/ecosystem.controller.ts
  • apps/ecosystem/src/ecosystem.module.ts
  • apps/ecosystem/src/ecosystem.service.ts
  • apps/ecosystem/src/main.ts
  • apps/ecosystem/templates/create-ecosystem.templates.ts
  • apps/ecosystem/tsconfig.app.json
  • libs/common/src/common.constant.ts
  • libs/common/src/response-messages/index.ts
  • libs/enum/src/enum.ts
  • libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json
  • libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql
  • libs/prisma-service/prisma/migrations/20260108141409_added_deleted_at_parameter_in_ecosystem_invitation/migration.sql
  • libs/prisma-service/prisma/schema.prisma
  • libs/prisma-service/prisma/seed.ts
  • nest-cli.json
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-17T08:03:16.180Z
Learnt from: KambleSahil3
Repo: credebl/platform PR: 1518
File: libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json:11-20
Timestamp: 2025-11-17T08:03:16.180Z
Learning: In the credebl/platform repository, seed data files like libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json intentionally contain empty strings for sensitive fields (email, username, passwords, API keys, etc.) because these values are populated from .env file at runtime, not hardcoded in the JSON.

Applied to files:

  • libs/prisma-service/prisma/data/credebl-master-table/credebl-master-table.json
  • apps/ecosystem/templates/create-ecosystem.templates.ts
  • libs/prisma-service/prisma/seed.ts
  • apps/ecosystem/src/ecosystem.module.ts
📚 Learning: 2025-06-24T11:15:29.468Z
Learnt from: tipusinghaw
Repo: credebl/platform PR: 1297
File: apps/api-gateway/src/tracer.ts:24-28
Timestamp: 2025-06-24T11:15:29.468Z
Learning: In the credebl/platform repository, the team prefers to create utilities for validating required environment variables rather than implementing inline validation. This approach promotes reusability across different parts of the application.

Applied to files:

  • apps/ecosystem/templates/create-ecosystem.templates.ts
🧬 Code graph analysis (8)
apps/ecosystem/src/main.ts (3)
libs/logger/src/logger.interface.ts (1)
  • Logger (6-20)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
libs/logger/src/nestjsLoggerServiceAdapter.ts (1)
  • NestjsLoggerServiceAdapter (7-41)
apps/ecosystem/templates/create-ecosystem.templates.ts (1)
libs/common/src/common.utils.ts (1)
  • escapeHtml (149-156)
apps/api-gateway/src/ecosystem/ecosystem.module.ts (3)
apps/api-gateway/src/app.module.ts (1)
  • Module (40-123)
apps/ecosystem/src/ecosystem.module.ts (1)
  • Module (18-37)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
apps/ecosystem/dtos/create-ecosystem-dto.ts (3)
libs/common/src/cast.helper.ts (2)
  • trim (39-43)
  • IsNotSQLInjection (96-127)
libs/validations/minLength.ts (1)
  • MinLength (3-28)
libs/validations/maxLength.ts (1)
  • MaxLength (3-28)
apps/api-gateway/src/ecosystem/ecosystem.service.ts (1)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (3)
  • IEcosystemInvitations (63-71)
  • IEcosystem (18-26)
  • IEcosystemDashboard (87-95)
apps/ecosystem/src/ecosystem.controller.ts (1)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (3)
  • IEcosystemInvitations (63-71)
  • IEcosystem (18-26)
  • IEcosystemDashboard (87-95)
apps/ecosystem/src/ecosystem.module.ts (2)
apps/api-gateway/src/ecosystem/ecosystem.module.ts (1)
  • Module (10-23)
libs/common/src/nats.config.ts (1)
  • getNatsOptions (4-28)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (4)
apps/api-gateway/src/issuance/utils/helper.ts (1)
  • JsonValue (5-5)
apps/connection/src/interfaces/connection.interfaces.ts (1)
  • OrgAgent (111-126)
apps/issuance/interfaces/issuance.interfaces.ts (1)
  • OrgAgent (269-284)
apps/ledger/src/interfaces/ledgers.interface.ts (1)
  • LedgerDetails (1-6)
🪛 dotenv-linter (4.0.0)
.env.sample

[warning] 121-121: [UnorderedKey] The ECOSYSTEM_NKEY_SEED key should go before the ISSUANCE_NKEY_SEED key

(UnorderedKey)


[warning] 121-121: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🔇 Additional comments (30)
nest-cli.json (1)

200-208: LGTM! Ecosystem project configuration follows monorepo conventions.

The configuration properly defines the new ecosystem microservice with all required fields matching the pattern used by other services in the monorepo.

libs/common/src/response-messages/index.ts (1)

163-186: LGTM! Comprehensive ecosystem response messages.

The ecosystem response messages follow the established pattern and provide clear, actionable feedback for both success and error scenarios. The messages cover a wide range of use cases including validation, not found errors, duplicates, and missing required fields.

libs/prisma-service/prisma/seed.ts (7)

1-31: LGTM! New imports and caching mechanism added appropriately.

The new imports support encryption (CryptoJS), promise utilities (util), and platform constants. The module-level cachedConfig variable provides an in-memory cache for platform configuration to avoid repeated database queries.


139-165: LGTM! Ecosystem roles seeding follows established patterns.

The createEcosystemRoles function properly checks for existing records before creating new ones and follows the same pattern as other seeding functions in this file.


515-571: LGTM! Client ID migration logic is well-structured.

The updateClientId function properly:

  • Validates required environment variables
  • Encrypts the new client ID once for efficiency
  • Skips platform admin users
  • Handles decryption errors gracefully
  • Only updates users with the old client ID

The dependency on cachedConfig.platformEmail (line 542) is safe because getPlatformConfig() is called before this function in the main sequence (line 814).


573-626: LGTM! Platform user role update is properly validated.

The updatePlatformUserRole function ensures the platform admin has the correct organization role with proper validation and idempotent behavior. The dependency on cachedConfig is safe as it's called after getPlatformConfig() in the main sequence.


628-658: LGTM! Keycloak token retrieval is properly implemented.

The getKeycloakToken function includes comprehensive validation, proper error handling with descriptive messages, and validates the response structure before returning the access token.


772-795: LGTM! Platform config retrieval with efficient caching.

The getPlatformConfig function implements a simple but effective caching mechanism to avoid repeated database queries, with proper validation of required fields.


797-818: LGTM! Main seeding sequence properly orchestrated.

The main function correctly orders the seeding operations, ensuring getPlatformConfig() (line 814) is called before functions that depend on cachedConfig (lines 815-817). The new ecosystem roles seeding (line 804) and platform config creation (line 812) are properly integrated into the sequence.

libs/prisma-service/prisma/schema.prisma (3)

39-40: LGTM! Ecosystem relations properly added to existing models.

The new relations on the user and organisation models establish proper bidirectional links to the new ecosystem entities, following Prisma conventions.

Also applies to: 160-160


755-764: LGTM! Ecosystem roles model follows established patterns.

The ecosystem_roles model is properly structured as a lookup table with a unique constraint on the role name, following the same pattern as the org_roles model.


735-753: Clarify the intentional design of the ledgers field.

The ecosystem model defines ledgers as Json? (line 752), which differs from other models in the schema that reference the ledgers table through foreign key relations (e.g., ledgers ledgers? @relation(fields: [ledgerId], references: [id])). The ecosystem service code casts this field as string[], suggesting it stores ledger IDs as JSON.

Is this design intentional, or should the ecosystem model use a relational reference like other models? If storing ledger data as JSON is required for ecosystem-specific flexibility, consider documenting this design choice.

libs/prisma-service/prisma/migrations/20260108141409_added_deleted_at_parameter_in_ecosystem_invitation/migration.sql (1)

1-6: LGTM!

The migration correctly adds soft-delete support (deletedAt) and establishes the ecosystem relationship with appropriate cascade behavior (ON DELETE SET NULL preserves invitation history when an ecosystem is deleted).

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

257-259: LGTM!

The ECOSYSTEM_SERVICE constant follows the established naming convention and is correctly placed within the constants file. It aligns with existing microservice identifiers used throughout the codebase.

apps/api-gateway/src/ecosystem/ecosystem.module.ts (1)

10-23: LGTM!

The module correctly configures the NATS client to target the ECOSYSTEM_SERVICE queue while using the API gateway's own authentication credentials (API_GATEWAY_NKEY_SEED). This follows the established service-to-service communication pattern in the codebase.

apps/ecosystem/tsconfig.app.json (1)

1-9: LGTM!

The TypeScript configuration follows the established conventions for NestJS applications in this monorepo, with appropriate output directory and exclusion patterns.

apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts (1)

6-13: LGTM!

The DTO has proper validation with meaningful error messages. The Transform decorator correctly trims whitespace before validation occurs (class-transformer runs before class-validator).

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

18-37: LGTM!

The module is well-structured with appropriate dependencies for a NestJS microservice. The NATS configuration correctly uses ECOSYSTEM_NKEY_SEED for this service's authentication.

Note: CacheModule.register() uses the default in-memory cache, which is consistent with most microservices in the codebase. If persistent or distributed caching is needed across instances in the future, consider configuring a Redis-backed cache store (e.g., CacheModule.register({ host: process.env.REDIS_HOST, port: process.env.REDIS_PORT })), as demonstrated in the notification module.

apps/ecosystem/src/main.ts (1)

14-24: Bootstrap implementation looks correct.

The microservice bootstrap follows the established pattern. Note that if ECOSYSTEM_NKEY_SEED is undefined, NATS will connect without authentication per getNatsOptions behavior—ensure this is intentional for your deployment environment.

libs/enum/src/enum.ts (2)

94-98: LGTM!

The ecosystem roles enum is well-defined with clear naming conventions.


100-106: LGTM!

The ecosystem configuration settings enum comprehensively covers the necessary configuration options.

libs/prisma-service/prisma/migrations/20260106131405_send_invitation_to_create_ecosystem/migration.sql (4)

2-17: LGTM!

The ecosystem table structure is well-designed with appropriate fields, constraints, and audit columns.


19-29: LGTM!

The ecosystem_roles table structure is appropriate with a unique constraint on the name field.


31-43: LGTM!

The ecosystem_users junction table correctly implements a many-to-many relationship with appropriate unique constraints and audit fields.


76-104: LGTM!

The indexes and foreign key constraints are well-designed. The use of ON DELETE SET NULL for ecosystem_invitations.userId is appropriate since invitations should remain for audit purposes even if the user is deleted.

apps/ecosystem/templates/create-ecosystem.templates.ts (1)

29-86: LGTM!

The HTML email template is well-structured with proper styling, responsive design considerations, and appropriate use of escaped variables for security.

apps/ecosystem/dtos/create-ecosystem-dto.ts (2)

8-15: LGTM!

The name field validation is comprehensive and includes appropriate guards against SQL injection, length constraints, and type validation.


17-24: LGTM!

The description field validation is thorough with appropriate constraints and security checks.

apps/api-gateway/src/ecosystem/ecosystem.controller.ts (1)

106-118: No changes needed. The OrgRolesGuard correctly binds authorization to the :orgId route parameter. The implementation validates that the user has membership in the specific organization (line 60 matches orgId to user's userOrgRoles), and enforces access denial if the user is not a member of that org (lines 63-65). Role validation is org-scoped (line 47 retrieves roles for the specific orgId).

apps/api-gateway/src/app.module.ts (1)

1-4: No action needed. ConditionalModule.registerWhen is a fully supported API in @nestjs/config v4.0.2 and is correctly implemented in your codebase (lines 73–75). The NATS seed configuration also handles the optional API_GATEWAY_NKEY_SEED parameter gracefully—if absent, the client is initialized without authentication.

Comment on lines 119 to 137
async createNewEcosystem(
@Body() createEcosystemDto: CreateEcosystemDto,
@Param('orgId') orgId: string,
@User() user: user,
@Res() res: Response
): Promise<Response> {
createEcosystemDto.orgId = orgId;
createEcosystemDto.userId = user?.['id'];

const ecosystem = await this.ecosystemService.createEcosystem(createEcosystemDto);

const finalResponse: IResponse = {
statusCode: HttpStatus.CREATED,
message: ResponseMessages.ecosystem.success.create,
data: ecosystem
};

return res.status(HttpStatus.CREATED).json(finalResponse);
}
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

Avoid mutating request DTOs; build a new payload object for service call.
Mutating createEcosystemDto can cause surprises with validation/transform and makes the controller harder to reason about.

Proposed fix
@@
   ): Promise<Response> {
-    createEcosystemDto.orgId = orgId;
-    createEcosystemDto.userId = user?.['id'];
-
-    const ecosystem = await this.ecosystemService.createEcosystem(createEcosystemDto);
+    const ecosystem = await this.ecosystemService.createEcosystem({
+      ...createEcosystemDto,
+      orgId,
+      userId: user?.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
async createNewEcosystem(
@Body() createEcosystemDto: CreateEcosystemDto,
@Param('orgId') orgId: string,
@User() user: user,
@Res() res: Response
): Promise<Response> {
createEcosystemDto.orgId = orgId;
createEcosystemDto.userId = user?.['id'];
const ecosystem = await this.ecosystemService.createEcosystem(createEcosystemDto);
const finalResponse: IResponse = {
statusCode: HttpStatus.CREATED,
message: ResponseMessages.ecosystem.success.create,
data: ecosystem
};
return res.status(HttpStatus.CREATED).json(finalResponse);
}
async createNewEcosystem(
@Body() createEcosystemDto: CreateEcosystemDto,
@Param('orgId') orgId: string,
@User() user: user,
@Res() res: Response
): Promise<Response> {
const ecosystem = await this.ecosystemService.createEcosystem({
...createEcosystemDto,
orgId,
userId: user?.id
});
const finalResponse: IResponse = {
statusCode: HttpStatus.CREATED,
message: ResponseMessages.ecosystem.success.create,
data: ecosystem
};
return res.status(HttpStatus.CREATED).json(finalResponse);
}
🤖 Prompt for AI Agents
In @apps/api-gateway/src/ecosystem/ecosystem.controller.ts around lines 119 -
137, The controller mutates the incoming DTO (createEcosystemDto) before calling
ecosystemService.createEcosystem which can break validation/transform and cause
side effects; instead construct a new payload object (e.g., const payload = {
...createEcosystemDto, orgId, userId: user?.['id'] }) inside createNewEcosystem
and pass that to ecosystemService.createEcosystem, leaving the original
createEcosystemDto untouched and preserving intent in the response building that
follows.

Comment on lines 63 to 71
export interface IEcosystemInvitations {
id: string;
email: string;
status: string;
ecosystemId?: string;
userId: string;
createDateTime: Date;
createdBy: string;
}
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

Fix nullability mismatches (userId, deletedAt) to match persisted data.
Repository writes userId nullable; Prisma soft-delete fields are typically Date | null.

Proposed fix
 export interface IEcosystemInvitations {
@@
-  userId: string;
+  userId: string | null;
@@
 export interface IEcosystemDetails {
@@
-  deletedAt: Date;
+  deletedAt: Date | null;

Also applies to: 73-85

🤖 Prompt for AI Agents
In @apps/ecosystem/interfaces/ecosystem.interfaces.ts around lines 63 - 71, The
IEcosystemInvitations interface has incorrect nullability: change userId to
allow null (e.g., userId?: string | null) to match persisted data, and any
soft-delete timestamp fields (deletedAt) in this file’s interfaces (including
the other interface around lines 73-85) should be typed as Date | null (e.g.,
deletedAt?: Date | null); update IEcosystemInvitations and the other
interface(s) accordingly so the optional/nullable types align with Prisma’s
persisted shapes.

Comment on lines 30 to 51
async createEcosystemInvitation(payload: {
email: string;
invitedUserId: string | null;
platformAdminId: string;
}): Promise<ecosystem_invitations> {
const { email, invitedUserId, platformAdminId } = payload;

return this.prisma.ecosystem_invitations.create({
data: {
email,
// Change to PENDING when accept/reject flow is ready
status: Invitation.ACCEPTED,

// invited user (nullable)
userId: invitedUserId,

// platform admin
createdBy: platformAdminId,
lastChangedBy: platformAdminId
}
});
}
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

Invitation status is set to ACCEPTED at creation (likely bypasses accept/reject semantics).
If this is intentional for MVP, fine; otherwise it breaks expected “invite then accept” flow and weakens the “invitationRequired” check later.

Proposed fix (if enum supports it)
@@
-        // Change to PENDING when accept/reject flow is ready
-        status: Invitation.ACCEPTED,
+        status: Invitation.PENDING,
📝 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 createEcosystemInvitation(payload: {
email: string;
invitedUserId: string | null;
platformAdminId: string;
}): Promise<ecosystem_invitations> {
const { email, invitedUserId, platformAdminId } = payload;
return this.prisma.ecosystem_invitations.create({
data: {
email,
// Change to PENDING when accept/reject flow is ready
status: Invitation.ACCEPTED,
// invited user (nullable)
userId: invitedUserId,
// platform admin
createdBy: platformAdminId,
lastChangedBy: platformAdminId
}
});
}
async createEcosystemInvitation(payload: {
email: string;
invitedUserId: string | null;
platformAdminId: string;
}): Promise<ecosystem_invitations> {
const { email, invitedUserId, platformAdminId } = payload;
return this.prisma.ecosystem_invitations.create({
data: {
email,
status: Invitation.PENDING,
// invited user (nullable)
userId: invitedUserId,
// platform admin
createdBy: platformAdminId,
lastChangedBy: platformAdminId
}
});
}
🤖 Prompt for AI Agents
In @apps/ecosystem/repositories/ecosystem.repository.ts around lines 30 - 51,
The createEcosystemInvitation function currently sets status to
Invitation.ACCEPTED which bypasses invite/accept flow; change the initial status
to the pending enum value (e.g., Invitation.PENDING or equivalent) so
invitations are created in a pending state and only move to ACCEPTED when the
accept flow runs; update any tests or callers expecting ACCEPTED if needed and
keep references to createEcosystemInvitation and Invitation to locate the
change.

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
@sonarqubecloud
Copy link

@pranalidhanavade pranalidhanavade merged commit 788869f into feat/platform_admin_and_ecosystem Jan 12, 2026
5 checks passed
pranalidhanavade added a commit that referenced this pull request Jan 30, 2026
)

* feat/add script to add platform admin keycloak and role

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/eslint issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/coderabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/changes to fetch value from db

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: ecosystem service and create ecosystem invitation API route

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: get all invitations api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: removed userId parameter from send invitation and get invitation api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: create and get ecosystem api routes

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warning

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings and suggestions

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings resolved

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolved comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolve comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolve comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Co-authored-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
pranalidhanavade added a commit that referenced this pull request Jan 30, 2026
)

* feat/add script to add platform admin keycloak and role

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/eslint issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/coderabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/changes to fetch value from db

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: ecosystem service and create ecosystem invitation API route

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: get all invitations api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: removed userId parameter from send invitation and get invitation api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: create and get ecosystem api routes

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warning

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings and suggestions

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings resolved

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolved comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolve comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolve comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Co-authored-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
pranalidhanavade added a commit that referenced this pull request Jan 31, 2026
* feat: ecosystem service and create ecosystem invitation API route (#1540)

* feat/add script to add platform admin keycloak and role

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/eslint issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/coderabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/changes to fetch value from db

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: ecosystem service and create ecosystem invitation API route

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: get all invitations api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: removed userId parameter from send invitation and get invitation api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: create and get ecosystem api routes

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warning

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings and suggestions

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings resolved

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolved comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolve comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolve comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Co-authored-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: Add script to add platform admin to keycloak and create user org roles (#1538)

* feat/add script to add platform admin keycloak and role

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/eslint issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/coderabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/changes to fetch value from db

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix pr comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix pr comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: ecosystem member invitation and management API's (#1545)

* feat/add script to add platform admin keycloak and role

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/eslint issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/coderabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: ecosystem service and create ecosystem invitation API route

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: get all invitations api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* wip

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* wip completed invite member and update status for invitation

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* wip

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* wip

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat/added ecosystem invitation workflow apis

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/code rabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/minor typo issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/ pr comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/pr comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Co-authored-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix/version for nest-cli

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: add dockerfile for ecosystem

Signed-off-by: sahil.kamble@ayanworks.com <sahil.kamble@ayanworks.com>

* feat: add ecosystemt in github actions workflow

Signed-off-by: sahil.kamble@ayanworks.com <sahil.kamble@ayanworks.com>

* feat: create intent API endpoints and intent template mapping APIs (#1547)

* feat: create intent APIs

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: create intent mapping and create intent APIs

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: sonarlint issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: move validations from ecosystem repository to ecosystem service

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: sonarlint issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: sonarlint issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: sonarlint issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit suggestions

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

---------

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: resloved issue for docker build (#1549)

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: Enable/disable ecosystem (#1550)

* refactor: added isEcosystemEnabled flag in database in platform_config table

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: enable/disable ecosystem feature from database

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit suggestions

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: enable/disable ecosystem feature and delete intent API issue

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* coderabbit comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

---------

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix/code rabbit issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/code rabbit issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: sahil.kamble@ayanworks.com <sahil.kamble@ayanworks.com>
Co-authored-by: sujitaw <sujit.sutar@ayanworks.com>
Co-authored-by: sahil.kamble@ayanworks.com <sahil.kamble@ayanworks.com>
shitrerohit pushed a commit that referenced this pull request Jan 31, 2026
* feat: ecosystem service and create ecosystem invitation API route (#1540)

* feat/add script to add platform admin keycloak and role

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/eslint issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/coderabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/changes to fetch value from db

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: ecosystem service and create ecosystem invitation API route

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: get all invitations api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: removed userId parameter from send invitation and get invitation api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: create and get ecosystem api routes

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warning

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings and suggestions

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings resolved

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolved comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolve comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* resolve comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Co-authored-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: Add script to add platform admin to keycloak and create user org roles (#1538)

* feat/add script to add platform admin keycloak and role

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/eslint issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/coderabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/changes to fetch value from db

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix pr comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix pr comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: ecosystem member invitation and management API's (#1545)

* feat/add script to add platform admin keycloak and role

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/eslint issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/coderabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: ecosystem service and create ecosystem invitation API route

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit warnings

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: get all invitations api

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* wip

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* wip completed invite member and update status for invitation

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* wip

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* wip

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat/added ecosystem invitation workflow apis

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/code rabbit comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/minor typo issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/ pr comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/pr comments

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Co-authored-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix/version for nest-cli

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* feat: add dockerfile for ecosystem

Signed-off-by: sahil.kamble@ayanworks.com <sahil.kamble@ayanworks.com>

* feat: add ecosystemt in github actions workflow

Signed-off-by: sahil.kamble@ayanworks.com <sahil.kamble@ayanworks.com>

* feat: create intent API endpoints and intent template mapping APIs (#1547)

* feat: create intent APIs

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* feat: create intent mapping and create intent APIs

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: sonarlint issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: move validations from ecosystem repository to ecosystem service

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: sonarlint issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: sonarlint issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: sonarlint issues

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit suggestions

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

---------

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: resloved issue for docker build (#1549)

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: Enable/disable ecosystem (#1550)

* refactor: added isEcosystemEnabled flag in database in platform_config table

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: enable/disable ecosystem feature from database

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix: coderabbit suggestions

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* refactor: enable/disable ecosystem feature and delete intent API issue

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* coderabbit comments on PR

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

---------

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>

* fix/code rabbit issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

* fix/code rabbit issue

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>

---------

Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: sahil.kamble@ayanworks.com <sahil.kamble@ayanworks.com>
Co-authored-by: sujitaw <sujit.sutar@ayanworks.com>
Co-authored-by: sahil.kamble@ayanworks.com <sahil.kamble@ayanworks.com>
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.

5 participants