Skip to content

fix: allow multiple orgs of lead to be member of his own ecosystem#1562

Merged
sujitaw merged 6 commits intorefactor/ecosystem_apis_for_ui_requirementsfrom
fix/issues_for_ecosystem_invitation
Feb 11, 2026
Merged

fix: allow multiple orgs of lead to be member of his own ecosystem#1562
sujitaw merged 6 commits intorefactor/ecosystem_apis_for_ui_requirementsfrom
fix/issues_for_ecosystem_invitation

Conversation

@sujitaw
Copy link
Contributor

@sujitaw sujitaw commented Feb 11, 2026

What

  • allow multiple orgs of lead to be member of his own ecosystem
  • minor bug fixes

Summary by CodeRabbit

  • New Features

    • Added pagination and search across ecosystem and organization listings.
    • New endpoint to browse all organisations with filtering.
  • Improvements

    • Invitations now include organization context for clearer tracking.
    • API docs include root server entry.
  • API Changes

    • List endpoints return paginated responses (totalPages + data).
    • New query options for status, role and org-scoped operations.
    • Invitation uniqueness tightened to consider organisation scope.

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

coderabbitai bot commented Feb 11, 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.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds pagination types and pages through ecosystem and organization APIs, propagates page details across gateway, microservices, and repositories, introduces org-scoped invitation handling (invitedOrg/orgId), adds InvitationViewRole enum, restructures organization interfaces, and updates Prisma schema and migrations to link invitations to organisations.

Changes

Cohort / File(s) Summary
Pagination types
apps/api-gateway/common/interface.ts
Added IPageDetail and generic PaginatedResponse<T> to public API surface.
API Gateway — Ecosystem DTOs
apps/api-gateway/src/ecosystem/dtos/ecosystem.ts, apps/api-gateway/src/ecosystem/dtos/send-ecosystem-invitation.ts
Removed several query fields (status/role/email/userId) in DTOs; replaced invitation status field with orgId in update DTO.
API Gateway — Ecosystem Controller/Service
apps/api-gateway/src/ecosystem/ecosystem.controller.ts, apps/api-gateway/src/ecosystem/ecosystem.service.ts
Controller actions and service methods now accept pagination DTOs and enum query params; service signatures updated to accept IPageDetail and return PaginatedResponse<T>; orgId threaded into invitation status updates; user type adjusted to user.
Microservice — Ecosystem controller/service
apps/ecosystem/src/ecosystem.controller.ts, apps/ecosystem/src/ecosystem.service.ts
Synchronized payloads to include pageDetail, return PaginatedResponse<T>, propagate orgId for invitation updates, and switch role checks to InvitationViewRole.
Repository — Ecosystem
apps/ecosystem/repositories/ecosystem.repository.ts
Refactored query methods to accept IPageDetail, return PaginatedResponse<T> (count + data via Prisma transactions), added ICreateEcosystemOrg, getEcosystemByRole, and org-scoped invitation update paths.
Interfaces — Ecosystem
apps/ecosystem/interfaces/ecosystem.interfaces.ts
Extended IEcosystemOrg, added ICreateEcosystemOrg, added invitedOrg/organization to invitations, changed member role type to InvitationViewRole.
Organization — API Gateway
apps/api-gateway/src/organization/organization.controller.ts, apps/api-gateway/src/organization/organization.service.ts
Added GET /search/get-all-organisations endpoint accepting pagination; delegates to organization service.
Organization — Microservice & Repo
apps/organization/src/organization.controller.ts, apps/organization/src/organization.service.ts, apps/organization/repositories/organization.repository.ts
Added getAllOrganisations handler/service; repository implements paginated, case-insensitive org search with totalPages computation and error handling.
Common interfaces — Organization
libs/common/src/interfaces/organization.interface.ts
Reworked monolithic org types into many exported interfaces (UserOrgRole, User, IOrgRoles, IOrganizations, IAllOrgsNameId, IGetAllOrgsPayload, etc.).
Enums
libs/enum/src/enum.ts
Added InvitationViewRole enum (ECOSYSTEM_MEMBER, ECOSYSTEM_LEAD).
Swagger
apps/api-gateway/src/main.ts
Added root server entry '/' to OpenAPI servers.
Prisma schema & migrations
libs/prisma-service/prisma/schema.prisma, .../migrations/*
Added invitedOrg FK on ecosystem_invitations referencing organisation.id; added relation array on organisation; changed unique constraint to (email, ecosystemId, invitedOrg); new migrations included.
Data fixtures
libs/prisma-service/prisma/data/credebl-master-table.json
Removed static JSON fixture file.

Sequence Diagram(s)

sequenceDiagram
  actor Client
  participant APIGW as API-Gateway
  participant EcosystemMS as Ecosystem-Service
  participant Repo as Ecosystem-Repository
  participant DB as Database

  Client->>APIGW: GET /ecosystems?pageNumber=1&pageSize=20
  APIGW->>EcosystemMS: request { userId, pageDetail }
  EcosystemMS->>Repo: getAllEcosystems(pageDetail, userId)
  Repo->>DB: SELECT ... LIMIT/OFFSET, COUNT(...)
  DB-->>Repo: rows + totalCount
  Repo-->>EcosystemMS: { totalPages, data[] }
  EcosystemMS-->>APIGW: PaginatedResponse
  APIGW-->>Client: 200 { totalPages, data[] }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

bug

Suggested reviewers

  • shitrerohit

Poem

🐰 Hopping through pages I scout,

Invitations scoped, sorted out,
OrgId tucked in every call,
Relations linked — I hop and sprawl,
Paginated carrots for all!

🚥 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 accurately reflects the main change: allowing multiple organizations of a lead to be members of their own ecosystem.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issues_for_ecosystem_invitation

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

Caution

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

⚠️ Outside diff range comments (2)
apps/ecosystem/src/ecosystem.service.ts (1)

351-365: ⚠️ Potential issue | 🔴 Critical

Critical bug: getEcosystemOrg called with userId instead of orgId — prevents creating ecosystem_orgs entries for a lead's additional organizations.

At line 361, the method is called as getEcosystemOrg(result.ecosystemId, result.userId), but the repository method signature expects (ecosystemId: string, orgId: string). The second parameter should be result.invitedOrg to match the orgId in the ecosystemOrgPayload (line 351).

When a lead's second organization accepts an invitation, the existing check will incorrectly find the first org's entry (since it searches by userId instead of orgId), causing createEcosystemOrg to be skipped. This directly breaks the PR's goal of supporting multiple orgs per lead in an ecosystem.

Proposed fix
-        const existingOrg = await this.ecosystemRepository.getEcosystemOrg(result.ecosystemId, result.userId);
+        const existingOrg = await this.ecosystemRepository.getEcosystemOrg(result.ecosystemId, result.invitedOrg);
apps/api-gateway/src/ecosystem/ecosystem.controller.ts (1)

114-119: ⚠️ Potential issue | 🔴 Critical

Bug: Returns HTTP 200 for internal server errors.

The catch block sets statusCode: HttpStatus.INTERNAL_SERVER_ERROR in the response body but sends it with res.status(HttpStatus.OK). Clients relying on HTTP status codes will treat server errors as successful responses.

🐛 Proposed fix
-      return res.status(HttpStatus.OK).json(finalResponse);
+      return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json(finalResponse);
🤖 Fix all issues with AI agents
In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts`:
- Around line 304-315: The status query parameter for updateEcosystemOrgStatus
is not validated against the EcosystemOrgStatus enum; add validation by using
Nest's ParseEnumPipe with EcosystemOrgStatus on the `@Query`('status') parameter
so the framework rejects invalid values before reaching updateEcosystemOrgStatus
and downstream services (i.e., apply ParseEnumPipe(EcosystemOrgStatus) to the
status query param definition and keep the parameter type as
EcosystemOrgStatus).

In `@apps/api-gateway/src/organization/organization.controller.ts`:
- Around line 806-837: The endpoint currently allows JWT auth only and uses
British spelling inconsistently; update the controller method
getAllOrganisations to use the same authorization stack as the root GET by
adding UserAccessGuard alongside AuthGuard('jwt') (i.e.,
`@UseGuards`(AuthGuard('jwt'), UserAccessGuard)) so service accounts and 'holder'
role checks are enforced, and rename the route/metadata and method identifier to
American spelling to match organizationService.getAllOrganizations and
ResponseMessages.organisation.success.getOrganizations (e.g., change
'search/get-all-organisations' to 'search/get-all-organizations', ApiOperation
summary/description to "Get all organizations", and rename the controller method
to getAllOrganizations) to keep API naming consistent.

In `@apps/ecosystem/repositories/ecosystem.repository.ts`:
- Around line 1351-1372: The method getEcosystemByRole uses
prisma.ecosystem_orgs.findFirst which can return null, but the signature
currently declares a non-nullable Promise<{ ecosystemRole: { name: string } }>,
so update the implementation to handle the null case: either change the return
type to Promise<{ ecosystemRole: { name: string } } | null> to reflect
findFirst’s possible null return, or keep the non-nullable signature and
explicitly throw a descriptive error when the result is null (and adjust callers
accordingly); locate this logic around getEcosystemByRole and the
prisma.ecosystem_orgs.findFirst call to apply the change.
- Around line 830-895: The whereClause in getAllEcosystemOrgsByEcosystemId only
filters by ecosystemId and may return soft-deleted rows; update the whereClause
used by prisma.ecosystem_orgs.findMany and prisma.ecosystem_orgs.count to
include deletedAt: null so both the data and count exclude soft-deleted records
(i.e., add deletedAt: null alongside ecosystemId in the existing whereClause).
- Around line 299-334: getAllEcosystems (and the other paginated methods
getAllEcosystemOrgsByEcosystemId, getIntents, getEcosystemsForEcosystemLead)
ignore the optional IPageDetail.search field; update each method to incorporate
pageDetail.search into the Prisma whereClause when present by adding a
case-insensitive "contains"/OR filter on the relevant text fields (e.g.,
ecosystem.name, ecosystem.description, related organisation.name or intent.name)
so results are filtered by the search term while preserving deletedAt/null and
existing pagination; implement this by conditionally building the whereClause
(merge the search OR filter only if pageDetail.search is truthy) and keep the
same transaction/count logic.
🧹 Nitpick comments (7)
libs/common/src/interfaces/organization.interface.ts (1)

111-119: IGetAllOrgsPayload.search is non-optional but may receive empty strings.

The search field is typed as string (not optional), which is fine since PaginationDto defaults it to ''. However, consider marking it as optional (search?: string) to be consistent with the optional nature of search across the codebase and to avoid confusion for future callers.

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

1227-1260: No guard against pageSize = 0 — division by zero and Prisma errors.

Math.ceil(totalCount / pageSize) yields Infinity when pageSize is 0, and (pageNumber - 1) * pageSize with pageNumber = 0 yields a negative skip. This is the same pattern used elsewhere in this file (e.g., getOrgInvitationsPagination), but it's worth noting for robustness. Consider adding a guard or ensuring callers always validate.

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

107-107: Fragile error type check.

error instanceof ConflictException || HttpStatus.CONFLICT === error.statusCode — the second branch accesses .statusCode on an untyped error. If the caught error is a plain Error, this reads undefined and silently falls through. This works today but is fragile. Consider narrowing the type or using optional chaining (error?.statusCode).

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

22-22: Cross-layer import: microservice imports from the API gateway module.

IPageDetail and PaginatedResponse are imported from apps/api-gateway/common/interface. The ecosystem microservice should not depend on the API gateway — this inverts the dependency direction. These shared types belong in a common library (e.g., @credebl/common/interfaces).


163-167: Confusing payload.payload nesting.

The message handler receives payload: { payload: IEcosystemMemberInvitations; pageDetail: IPageDetail }, leading to payload.payload on Line 167. Consider renaming the inner field (e.g., invitationQuery or filter) to improve clarity.

♻️ Suggested improvement
   async getEcosystemMemberInvitations(payload: {
-    payload: IEcosystemMemberInvitations;
+    filter: IEcosystemMemberInvitations;
     pageDetail: IPageDetail;
   }): Promise<PaginatedResponse<IEcosystemInvitation>> {
-    return this.ecosystemService.getEcosystemMemberInvitations(payload.payload, payload.pageDetail);
+    return this.ecosystemService.getEcosystemMemberInvitations(payload.filter, payload.pageDetail);
   }
apps/ecosystem/repositories/ecosystem.repository.ts (2)

42-42: Cross-layer import: repository imports from the API gateway module.

Same issue as in the ecosystem microservice controller — IPageDetail and PaginatedResponse are imported from apps/api-gateway/common/interface. The repository layer should never depend on the gateway. Move these interfaces to a shared library like @credebl/common.


388-392: Throwing plain Error instead of a domain-specific exception.

Line 391 throws new Error('Invitation not found for this specific organization'). Since this repository is called from a microservice context, this should probably be a NotFoundException or RpcException for consistent error handling up the call stack. The plain Error will be caught by the outer catch and re-thrown, but upstream handlers may not map it to the correct HTTP status.

♻️ Suggested improvement
        if (!record) {
-          throw new Error('Invitation not found for this specific organization');
+          throw new NotFoundException('Invitation not found for this specific organization');
        }

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

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

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

114-119: ⚠️ Potential issue | 🟠 Major

Bug: HTTP 200 response for internal server error.

The response body reports statusCode: HttpStatus.INTERNAL_SERVER_ERROR but the actual HTTP status sent is HttpStatus.OK (200). This misleads clients and monitoring systems into treating server errors as successful responses.

🐛 Proposed fix
-      return res.status(HttpStatus.OK).json(finalResponse);
+      return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json(finalResponse);
🤖 Fix all issues with AI agents
In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts`:
- Around line 154-159: The response body and actual HTTP status are
inconsistent: finalResponse.statusCode is HttpStatus.OK (200) but the controller
uses res.status(HttpStatus.CREATED) (201); update the controller to use the same
status for both (change res.status(HttpStatus.CREATED) to
res.status(HttpStatus.OK)) so finalResponse, HttpStatus.OK, res.status(...), and
the message built from ResponseMessages.ecosystem.success.updateInvitation and
status are aligned.
- Line 410: Add enum validation to the role query param by using Nest's
ParseEnumPipe: update the decorator for the role parameter (the one currently
declared as "@Query('role') role: InvitationViewRole =
InvitationViewRole.ECOSYSTEM_LEAD") to include "new
ParseEnumPipe(InvitationViewRole)". Also consider removing the default
assignment so the parameter is required to match the `@ApiQuery`(required: true)
declaration; if you want a default, validate first with ParseEnumPipe and then
apply the default in the method body. Ensure you reference the
InvitationViewRole enum and the role parameter when making the change.

@sujitaw sujitaw changed the base branch from main to refactor/ecosystem_apis_for_ui_requirements February 11, 2026 13:19
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
@sonarqubecloud
Copy link

@sujitaw sujitaw merged commit 5d6b814 into refactor/ecosystem_apis_for_ui_requirements Feb 11, 2026
5 checks passed
sujitaw added a commit that referenced this pull request Feb 11, 2026
* refactor/update api with suggested fixes

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

* fix/code rabbit issue

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

* fix/pr comments

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

* fix/code rabbit comments

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

* fix: allow multiple orgs of lead to be member of his own ecosystem (#1562)

* wip

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

* fix/update to allow multiple orgs of lead as member in ecosystem

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

* fix/code rabbit issues

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

---------

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

---------

Signed-off-by: sujitaw <sujit.sutar@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.

2 participants