refactor: Update API's for better integration with UI#1574
Conversation
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
📝 WalkthroughWalkthroughAdds org-scoped ecosystem listing and an invitation-status check: makes Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant APIGateway as API Gateway
participant EcoSvc as Ecosystem Service
participant Repo as Ecosystem Repository
Client->>APIGateway: GET /ecosystem?orgId={uuid}&page...
APIGateway->>EcoSvc: getEcosystemOrgs(orgId, pageDetail)
EcoSvc->>Repo: getEcosystemOrgs(orgId, pageDetail)
Repo-->>EcoSvc: Paginated IGetEcosystemOrgs
EcoSvc-->>APIGateway: formatted Paginated response
APIGateway-->>Client: 200 OK (members list)
Client->>APIGateway: GET /invitation/status (auth)
APIGateway->>EcoSvc: getCreateEcosystemInvitationStatus(email, status)
EcoSvc->>Repo: getCreateEcosystemInvitationStatus(email, status)
Repo-->>EcoSvc: boolean
EcoSvc-->>APIGateway: { status: boolean }
APIGateway-->>Client: 200 OK (invitation status)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts`:
- Around line 472-474: Replace the generic throw new Error('Email not Found')
check for missing reqUser.email with a NestJS BadRequestException so the
controller returns a 400 instead of a 500; import BadRequestException from
`@nestjs/common` and change the throw to throw new BadRequestException('Email not
Found') in the method on EcosystemController where the reqUser.email presence is
validated, and add the BadRequestException to the file's imports if not already
present.
In `@apps/ecosystem/repositories/ecosystem.repository.ts`:
- Around line 866-878: The queries building Prisma.ecosystem_orgsWhereInput (the
whereClause variable) and the other similar blocks at the other occurrences must
explicitly exclude soft-deleted rows by adding deletedAt: null to the
appropriate where filters; update the whereClause (and the analogous where
inputs around the other reported locations) to include deletedAt: null for the
org record and any membership/ecosystem relation filters so Prisma will only
return non-deleted rows (e.g., add deletedAt: null alongside ecosystemId and
inside the membership/ecosystem role filters where applicable).
- Around line 875-877: Replace uses of the auth enum `EcosystemRoles` with the
DB-facing enum `OrgRoles` in repository role filters: update the `ecosystemRole:
{ name: EcosystemRoles.ECOSYSTEM_MEMBER }` checks (and the similar occurrences
around lines noted) to use `OrgRoles` instead (e.g., `ecosystemRole.name` should
be compared against `OrgRoles.*`). Locate these occurrences by searching for
`ecosystemRole` and `EcosystemRoles` within this repository file (and the
similar blocks at the other mentioned lines) and swap the enum reference so
repository queries filter against `OrgRoles`.
- Around line 1654-1663: In getCreateEcosystemInvitationStatus validate the
incoming email before running the Prisma lookup: if email is falsy or blank
return false immediately (or reject) to avoid Prisma evaluating a broad filter;
then only call this.prisma.ecosystem_invitations.findFirst(...) when email is a
non-empty string so the query (in getCreateEcosystemInvitationStatus) reliably
checks Invitation.ACCEPTED, invitedOrg/ecosystemId/deletedAt nulls for that
specific email.
In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 909-910: The destructuring "const [leadData] =
item?.ecosystem?.ecosystemOrgs" can throw when ecosystemOrgs is undefined;
update this to safely handle missing data by either defaulting ecosystemOrgs to
an empty array before destructuring (use nullish-coalescing or an explicit
guard) or by directly accessing the first element via optional chaining (e.g.,
get ecosystemOrgs?.[0]) so that leadData becomes undefined instead of causing a
TypeError; modify the line that declares leadData and keep subsequent
ternary/null checks intact.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/api-gateway/src/ecosystem/ecosystem.controller.tsapps/api-gateway/src/ecosystem/ecosystem.service.tsapps/ecosystem/interfaces/ecosystem.interfaces.tsapps/ecosystem/repositories/ecosystem.repository.tsapps/ecosystem/src/ecosystem.controller.tsapps/ecosystem/src/ecosystem.service.tslibs/common/src/response-messages/index.ts
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
There was a problem hiding this comment.
♻️ Duplicate comments (2)
apps/ecosystem/repositories/ecosystem.repository.ts (2)
1621-1624:⚠️ Potential issue | 🟠 MajorUse
OrgRolesfor repository role filtering.Line 1623 is a DB-facing role comparison; this should use
OrgRoles, notEcosystemRoles.🔧 Proposed fix
ecosystemOrgs: { where: { + deletedAt: null, ecosystemRole: { - name: EcosystemRoles.ECOSYSTEM_LEAD + name: OrgRoles.ECOSYSTEM_LEAD } },Based on learnings: In the credebl/platform codebase,
OrgRolesenum is used for actual database role values (e.g., in repository queries checkingecosystemRole.name), whileEcosystemRolesenum is used for authorization guards.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/repositories/ecosystem.repository.ts` around lines 1621 - 1624, The DB-facing role comparison is using the authorization enum EcosystemRoles; update the query to use the DB enum OrgRoles instead (replace EcosystemRoles.ECOSYSTEM_LEAD with OrgRoles.ECOSYSTEM_LEAD in the where: { ecosystemRole: { name: ... } } clause), and adjust imports in ecosystem.repository.ts to import OrgRoles (and remove unused EcosystemRoles if no longer referenced) so repository role filtering uses the correct DB enum.
1592-1603:⚠️ Potential issue | 🟠 MajorExclude soft-deleted rows in the new org-scoped ecosystem query.
This new
whereClausepath can still return archived membership/ecosystem records because it does not enforcedeletedAt: nullon both layers.🔧 Proposed fix
const whereClause: Prisma.ecosystem_orgsWhereInput = { orgId, - ...(pageDetail.search && { - ecosystem: { - is: { - name: { - contains: pageDetail.search, - mode: 'insensitive' - } - } - } - }) + deletedAt: null, + ecosystem: { + is: { + deletedAt: null, + ...(pageDetail.search && { + name: { + contains: pageDetail.search, + mode: 'insensitive' + } + }) + } + } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/repositories/ecosystem.repository.ts` around lines 1592 - 1603, The whereClause (Prisma.ecosystem_orgsWhereInput) can return soft-deleted rows; update it to require deletedAt: null on the membership record and on the related ecosystem record by adding deletedAt: null at the top-level whereClause and inside ecosystem.is (alongside name.contains) so both the org-scoped ecosystem_orgs row and the joined ecosystem row exclude archived entries.
🧹 Nitpick comments (2)
apps/api-gateway/src/ecosystem/ecosystem.controller.ts (1)
219-221: AlignorgIdtyping with the required query contract.
orgIdis required and UUID-validated, so keeping it optional and sendingnullis unnecessary.🔧 Proposed refactor
- orgId?: string + orgId: string ): Promise<Response> { - const ecosystems = await this.ecosystemService.getEcosystemOrgs(orgId ?? null, paginationDto); + const ecosystems = await this.ecosystemService.getEcosystemOrgs(orgId, paginationDto);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts` around lines 219 - 221, The orgId parameter on the controller method is declared optional and passed as orgId ?? null to getEcosystemOrgs, but the query contract requires a UUID and orgId is required; change the method signature to accept orgId: string (remove the optional '?'), stop passing null and call this.ecosystemService.getEcosystemOrgs(orgId, paginationDto), and update any related validation/decorators on the controller method (e.g., `@Query` or DTO usage) so the UUID validation and required constraint are enforced.apps/ecosystem/src/ecosystem.service.ts (1)
915-915: HardenmemberCountagainst partial/null payloads.If ecosystem payload is partial, this can produce
NaN. A defensive default keeps the response stable.🔧 Proposed refactor
- memberCount: item?.ecosystem?._count.ecosystemOrgs - 1, + memberCount: Math.max((item?.ecosystem?._count?.ecosystemOrgs ?? 0) - 1, 0),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/src/ecosystem.service.ts` at line 915, The memberCount calculation can produce NaN when parts of the payload are missing; update the expression that computes memberCount (currently using item?.ecosystem?._count.ecosystemOrgs - 1) to defensively read ecosystemOrgs via optional chaining and a numeric default, then subtract 1 and clamp to a non-negative integer; locate the memberCount assignment in ecosystem.service.ts and replace the expression with a safe fallback (e.g., use item?.ecosystem?._count?.ecosystemOrgs ?? 0, subtract 1, and Math.max(0, ...) to avoid negative/NaN results).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@apps/ecosystem/repositories/ecosystem.repository.ts`:
- Around line 1621-1624: The DB-facing role comparison is using the
authorization enum EcosystemRoles; update the query to use the DB enum OrgRoles
instead (replace EcosystemRoles.ECOSYSTEM_LEAD with OrgRoles.ECOSYSTEM_LEAD in
the where: { ecosystemRole: { name: ... } } clause), and adjust imports in
ecosystem.repository.ts to import OrgRoles (and remove unused EcosystemRoles if
no longer referenced) so repository role filtering uses the correct DB enum.
- Around line 1592-1603: The whereClause (Prisma.ecosystem_orgsWhereInput) can
return soft-deleted rows; update it to require deletedAt: null on the membership
record and on the related ecosystem record by adding deletedAt: null at the
top-level whereClause and inside ecosystem.is (alongside name.contains) so both
the org-scoped ecosystem_orgs row and the joined ecosystem row exclude archived
entries.
---
Nitpick comments:
In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts`:
- Around line 219-221: The orgId parameter on the controller method is declared
optional and passed as orgId ?? null to getEcosystemOrgs, but the query contract
requires a UUID and orgId is required; change the method signature to accept
orgId: string (remove the optional '?'), stop passing null and call
this.ecosystemService.getEcosystemOrgs(orgId, paginationDto), and update any
related validation/decorators on the controller method (e.g., `@Query` or DTO
usage) so the UUID validation and required constraint are enforced.
In `@apps/ecosystem/src/ecosystem.service.ts`:
- Line 915: The memberCount calculation can produce NaN when parts of the
payload are missing; update the expression that computes memberCount (currently
using item?.ecosystem?._count.ecosystemOrgs - 1) to defensively read
ecosystemOrgs via optional chaining and a numeric default, then subtract 1 and
clamp to a non-negative integer; locate the memberCount assignment in
ecosystem.service.ts and replace the expression with a safe fallback (e.g., use
item?.ecosystem?._count?.ecosystemOrgs ?? 0, subtract 1, and Math.max(0, ...) to
avoid negative/NaN results).
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/api-gateway/src/ecosystem/ecosystem.controller.tsapps/ecosystem/repositories/ecosystem.repository.tsapps/ecosystem/src/ecosystem.service.ts
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
|
There was a problem hiding this comment.
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)
208-228:⚠️ Potential issue | 🟡 MinorInconsistency between
required: trueand optional parameter type.Line 210 declares
orgIdas required, but line 226 types it asorgId?: string(optional). Additionally, line 228 usesorgId ?? nullwhich is unnecessary iforgIdis truly required. Align the API contract with the TypeScript type.🔧 Proposed fix
`@ApiQuery`({ name: 'orgId', required: true, type: String }) `@Roles`(OrgRoles.PLATFORM_ADMIN, OrgRoles.ECOSYSTEM_LEAD) async getEcosystems( `@User`() reqUser: user, `@Res`() res: Response, `@Query`() paginationDto: PaginationGetAllEcosystem, `@Query`( 'orgId', new ParseUUIDPipe({ exceptionFactory: (): Error => { throw new BadRequestException(ResponseMessages.ecosystem.error.invalidOrgId); } }) ) - orgId?: string + orgId: string ): Promise<Response> { - const ecosystems = await this.ecosystemService.getEcosystemOrgs(orgId ?? null, paginationDto); + const ecosystems = await this.ecosystemService.getEcosystemOrgs(orgId, paginationDto);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts` around lines 208 - 228, The API docs mark orgId as required but the handler types it optional and passes orgId ?? null; update getEcosystems so the orgId parameter is non-optional and consistent with `@ApiQuery`: remove the optional marker on the orgId parameter (change orgId?: string to orgId: string), keep the ParseUUIDPipe validation, and remove the fallback orgId ?? null when calling this.ecosystemService.getEcosystemOrgs so you pass the validated orgId directly; ensure any downstream method (getEcosystemOrgs) signature accepts a non-null string or update that signature if needed.
♻️ Duplicate comments (3)
apps/ecosystem/repositories/ecosystem.repository.ts (2)
1595-1600:⚠️ Potential issue | 🟠 MajorUse
OrgRolesinstead ofEcosystemRolesin repository role filter.This repository query filters by persisted role names; using the auth enum
EcosystemRolesrisks mismatched database filtering.🔧 Proposed fix
ecosystemOrgs: { where: { + deletedAt: null, ecosystemRole: { - name: EcosystemRoles.ECOSYSTEM_LEAD + name: OrgRoles.ECOSYSTEM_LEAD } },Based on learnings: In the credebl/platform codebase,
OrgRolesenum is used for actual database role values (e.g., in repository queries checkingecosystemRole.name), whileEcosystemRolesenum is used for authorization guards to control API access.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/repositories/ecosystem.repository.ts` around lines 1595 - 1600, The repository query currently filters organization roles using the authorization enum EcosystemRoles; replace that with the persisted database enum OrgRoles so the where clause compares ecosystemRole.name to OrgRoles.ECOSYSTEM_LEAD (or the equivalent member) instead of EcosystemRoles, updating the filter inside the ecosystemOrgs -> where -> ecosystemRole block to reference OrgRoles to ensure the DB query uses actual stored role values.
1567-1579:⚠️ Potential issue | 🟠 MajorExclude soft-deleted records in
getEcosystemOrgsquery.The
whereClauseis missingdeletedAt: null, which could return soft-deleted ecosystem org records.🔧 Proposed fix
const whereClause: Prisma.ecosystem_orgsWhereInput = { orgId, + deletedAt: null, ...(pageDetail.search && { ecosystem: { is: { + deletedAt: null, name: { contains: pageDetail.search, mode: 'insensitive' } } } }) };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/repositories/ecosystem.repository.ts` around lines 1567 - 1579, The whereClause in getEcosystemOrgs (Prisma.ecosystem_orgsWhereInput) is missing a filter to exclude soft-deleted records; update the whereClause (the variable named whereClause used in getEcosystemOrgs) to include deletedAt: null at the appropriate level so only non-deleted ecosystem_orgs are returned while preserving the existing orgId and pageDetail.search ecosystem.name contains filter.apps/ecosystem/src/ecosystem.service.ts (1)
892-915:⚠️ Potential issue | 🟡 MinorGuard against undefined
_countto preventNaNinmemberCount.If
item?.ecosystem?._countis undefined, the subtraction at line 904 producesNaN. The destructuring fix at line 898 is correct.🛡️ Proposed fix
return { id: item?.ecosystem?.id, name: item?.ecosystem?.name, description: item?.ecosystem?.description, - memberCount: item?.ecosystem?._count.ecosystemOrgs - 1, + memberCount: (item?.ecosystem?._count?.ecosystemOrgs ?? 1) - 1, role: item?.ecosystemRole?.name, leadOrg: leadData🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/src/ecosystem.service.ts` around lines 892 - 915, In getEcosystemOrgs, the mapping computes memberCount using item?.ecosystem?._count.ecosystemOrgs - 1 which yields NaN when _count is undefined; change it to safely read the nested count (use item?.ecosystem?._count?.ecosystemOrgs ?? 0), then compute memberCount as Math.max(0, count - 1) to avoid negative or NaN results. Update the memberCount computation inside the data.map in getEcosystemOrgs so it references the guarded count variable before subtracting.
🧹 Nitpick comments (2)
apps/ecosystem/interfaces/ecosystem.interfaces.ts (1)
172-181: Typo in interface name:IFromattedGetAllOrgsshould beIFormattedGetAllOrgs.The interface name has a typo ("Fromatted" instead of "Formatted"). Consider renaming for consistency and readability.
✏️ Proposed fix
-export interface IFromattedGetAllOrgs { +export interface IFormattedGetAllOrgs { id: string; email: string | null; status: string; createDateTime: Date; organisation: string | null; orgId: string; ecosystemName: string; ecosystemId: string; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/interfaces/ecosystem.interfaces.ts` around lines 172 - 181, Rename the malformed interface IFromattedGetAllOrgs to IFormattedGetAllOrgs across the codebase: update the declaration in ecosystem.interfaces.ts and any imports/usages (e.g., type annotations, exports) that reference IFromattedGetAllOrgs so they use the corrected name IFormattedGetAllOrgs to maintain consistency and avoid compile/type errors.apps/api-gateway/src/ecosystem/ecosystem.controller.ts (1)
117-124: Linebreak in arrow function triggers ESLint warning.The static analysis indicates an implicit-arrow-linebreak issue. Consider inlining or restructuring.
✨ Proposed fix
`@Query`( 'status', new ParseEnumPipe(Invitation, { - exceptionFactory: () => - new BadRequestException(`Status must be one of: ${[Invitation.REJECTED, Invitation.ACCEPTED].join(', ')}`) + exceptionFactory: () => new BadRequestException(`Status must be one of: ${[Invitation.REJECTED, Invitation.ACCEPTED].join(', ')}`) }) ) status: Invitation🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts` around lines 117 - 124, The implicit-arrow-linebreak ESLint warning comes from the multi-line exceptionFactory arrow in the ParseEnumPipe options; change the exceptionFactory to a single-line arrow or a named function to remove the line break. Locate the ParseEnumPipe usage in the decorator for the status parameter (symbols: ParseEnumPipe, Invitation, exceptionFactory, BadRequestException, status) and replace the multi-line exceptionFactory with a single-line expression (or extract a const/function that returns new BadRequestException(...)) so the arrow body is not split across lines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts`:
- Around line 208-228: The API docs mark orgId as required but the handler types
it optional and passes orgId ?? null; update getEcosystems so the orgId
parameter is non-optional and consistent with `@ApiQuery`: remove the optional
marker on the orgId parameter (change orgId?: string to orgId: string), keep the
ParseUUIDPipe validation, and remove the fallback orgId ?? null when calling
this.ecosystemService.getEcosystemOrgs so you pass the validated orgId directly;
ensure any downstream method (getEcosystemOrgs) signature accepts a non-null
string or update that signature if needed.
---
Duplicate comments:
In `@apps/ecosystem/repositories/ecosystem.repository.ts`:
- Around line 1595-1600: The repository query currently filters organization
roles using the authorization enum EcosystemRoles; replace that with the
persisted database enum OrgRoles so the where clause compares ecosystemRole.name
to OrgRoles.ECOSYSTEM_LEAD (or the equivalent member) instead of EcosystemRoles,
updating the filter inside the ecosystemOrgs -> where -> ecosystemRole block to
reference OrgRoles to ensure the DB query uses actual stored role values.
- Around line 1567-1579: The whereClause in getEcosystemOrgs
(Prisma.ecosystem_orgsWhereInput) is missing a filter to exclude soft-deleted
records; update the whereClause (the variable named whereClause used in
getEcosystemOrgs) to include deletedAt: null at the appropriate level so only
non-deleted ecosystem_orgs are returned while preserving the existing orgId and
pageDetail.search ecosystem.name contains filter.
In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 892-915: In getEcosystemOrgs, the mapping computes memberCount
using item?.ecosystem?._count.ecosystemOrgs - 1 which yields NaN when _count is
undefined; change it to safely read the nested count (use
item?.ecosystem?._count?.ecosystemOrgs ?? 0), then compute memberCount as
Math.max(0, count - 1) to avoid negative or NaN results. Update the memberCount
computation inside the data.map in getEcosystemOrgs so it references the guarded
count variable before subtracting.
---
Nitpick comments:
In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts`:
- Around line 117-124: The implicit-arrow-linebreak ESLint warning comes from
the multi-line exceptionFactory arrow in the ParseEnumPipe options; change the
exceptionFactory to a single-line arrow or a named function to remove the line
break. Locate the ParseEnumPipe usage in the decorator for the status parameter
(symbols: ParseEnumPipe, Invitation, exceptionFactory, BadRequestException,
status) and replace the multi-line exceptionFactory with a single-line
expression (or extract a const/function that returns new
BadRequestException(...)) so the arrow body is not split across lines.
In `@apps/ecosystem/interfaces/ecosystem.interfaces.ts`:
- Around line 172-181: Rename the malformed interface IFromattedGetAllOrgs to
IFormattedGetAllOrgs across the codebase: update the declaration in
ecosystem.interfaces.ts and any imports/usages (e.g., type annotations, exports)
that reference IFromattedGetAllOrgs so they use the corrected name
IFormattedGetAllOrgs to maintain consistency and avoid compile/type errors.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/api-gateway/src/ecosystem/ecosystem.controller.tsapps/api-gateway/src/ecosystem/ecosystem.service.tsapps/ecosystem/interfaces/ecosystem.interfaces.tsapps/ecosystem/repositories/ecosystem.repository.tsapps/ecosystem/src/ecosystem.controller.tsapps/ecosystem/src/ecosystem.service.ts



What
Summary by CodeRabbit
New Features
Breaking Changes
Improvements
Chores