fix/changes required for platform admin UI#1571
Conversation
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds platform-admin dashboard and ecosystem-status endpoints; paginates and enriches invitation listings; updates controllers, services, repository interfaces and Prisma schema; and adds response messages for dashboard counts and ecosystem enablement. (27 words) Changes
Sequence Diagram(s)sequenceDiagram
actor Client
participant AGW as API Gateway
participant NATS
participant EcoSvc as Ecosystem Service
participant Repo as Repository
participant DB as Database
rect rgba(100, 200, 255, 0.5)
Note over Client,DB: Dashboard Count Flow
Client->>AGW: GET /dashboard/summary
AGW->>NATS: publish get-dashboard-count-platform-admin
NATS->>EcoSvc: deliver message
EcoSvc->>Repo: getDashBoardCountPlatformAdmin()
Repo->>DB: query ecosystems, invitations, active orgs
DB-->>Repo: aggregated counts
Repo-->>EcoSvc: IPlatformDashboardCount
EcoSvc-->>NATS: reply with result
NATS-->>AGW: relay response
AGW-->>Client: HTTP 200 {statusCode, message, data}
end
rect rgba(200, 150, 255, 0.5)
Note over Client,DB: Ecosystem Status Flow
Client->>AGW: GET /ecosystem/status
AGW->>NATS: publish get-ecosystem-enable-status
NATS->>EcoSvc: deliver message
EcoSvc->>Repo: getEcosystemEnableStatus()
Repo->>DB: query enable flag
DB-->>Repo: boolean
Repo-->>EcoSvc: boolean
EcoSvc-->>NATS: reply with result
NATS-->>AGW: relay response
AGW-->>Client: HTTP 200 {statusCode, message, data}
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/ecosystem/src/ecosystem.service.ts (1)
168-185:⚠️ Potential issue | 🟡 MinorCatch-all swallows typed exceptions — the explicit
throw new Error(...)on line 171 and any upstream exceptions all become a generic 500.The
try/catchon lines 168–185 catches every error (including the intentional validation throw on line 171) and unconditionally re-throws asInternalServerErrorException. If the repository itself throws a more specific exception (e.g.,BadRequestException), it will also be masked.Consider re-throwing known/typed exceptions before falling through to the generic handler:
Proposed fix
} catch (error) { this.logger.error('getInvitationsByUserId error', error); + if (error instanceof HttpException) { + throw error; + } throw new InternalServerErrorException(ResponseMessages.ecosystem.error.invitationNotFound); }🤖 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 168 - 185, The catch-all in getInvitationsByUserId is masking intentional and repository-thrown exceptions by always logging and throwing InternalServerErrorException; update the catch block in ecosystem.service.ts (the try around this.ecosystemRepository.getInvitationsByUserId / enrichedData mapping) to re-throw known/typed exceptions (e.g., if error is an instance of HttpException or has a status/property used by your framework) before converting to InternalServerErrorException, and for the local validation error (the explicit throw new Error('failed to fetch invitations')) replace it with a specific exception type (e.g., BadRequestException or NotFoundException) so callers receive the correct status; preserve logging with this.logger.error(error) but only wrap unknown errors into InternalServerErrorException.
🧹 Nitpick comments (3)
apps/ecosystem/repositories/ecosystem.repository.ts (1)
1518-1518: Typo in method name:Platfrom→Platform
getDashBoardCountPlatfromAdminshould begetDashBoardCountPlatformAdmin. The typo propagates through the call chain (service method name inapps/ecosystem/src/ecosystem.service.ts).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/repositories/ecosystem.repository.ts` at line 1518, Rename the misspelled repository method getDashBoardCountPlatfromAdmin to getDashBoardCountPlatformAdmin and update all usages and declarations (including the service method in ecosystem.service.ts) to the corrected name; ensure the function signature and return type IPlatformDashboardCount remain unchanged, update any interface/exports and imports that reference getDashBoardCountPlatfromAdmin, and run/adjust tests and type references to reflect the new identifier so compilation and call sites are consistent.apps/api-gateway/src/platform/platform.controller.ts (1)
330-338: Missing@ApiTagsdecorator on the new endpoint.All other endpoints in this controller are grouped under
@ApiTags(e.g.,'schemas','ledgers','credential-definitions'). This endpoint lacks one, so it will appear ungrouped in the Swagger UI.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api-gateway/src/platform/platform.controller.ts` around lines 330 - 338, The new endpoint method getEcosystemEnableStatus is missing an `@ApiTags` decorator so it will show up ungrouped in Swagger; add the appropriate `@ApiTags`('ecosystem') (or the existing group name used in this controller) to the controller or annotate the getEcosystemEnableStatus route so it is grouped consistently with other endpoints (use the `@ApiTags` decorator import from `@nestjs/swagger` and apply it alongside the controller/class or immediately above the getEcosystemEnableStatus method).apps/ecosystem/src/ecosystem.service.ts (1)
173-180: Unnecessary DB query when there are no org/ecosystem IDs to look up, and magic string'NOT_FOUND'for missing status.When
invitedOrgIdsandecosystemIdsare both empty (e.g., for invitations that haven't been assigned to orgs yet),getEcosystemOrgsByOrgIdAndEcosystemId([], [])still fires a database query that will always return an empty result. Guard with an early-return.Also,
'NOT_FOUND'on line 179 is a magic string. Consider using a constant or an enum value for consistency with the rest of the codebase (e.g.,EcosystemOrgStatus).Proposed improvement
const invitedOrgIds = [...new Set(invitations?.data.map((i) => i.invitedOrg).filter(Boolean))]; const ecosystemIds = [...new Set(invitations?.data.map((i) => i.ecosystemId).filter(Boolean))]; - const orgs = await this.ecosystemRepository.getEcosystemOrgsByOrgIdAndEcosystemId(invitedOrgIds, ecosystemIds); - const statusMap = new Map(orgs.map((org) => [`${org.orgId}-${org.ecosystemId}`, org.status])); + let statusMap = new Map<string, string>(); + if (invitedOrgIds.length && ecosystemIds.length) { + const orgs = await this.ecosystemRepository.getEcosystemOrgsByOrgIdAndEcosystemId(invitedOrgIds, ecosystemIds); + statusMap = new Map(orgs.map((org) => [`${org.orgId}-${org.ecosystemId}`, org.status])); + }🤖 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 173 - 180, Guard against calling getEcosystemOrgsByOrgIdAndEcosystemId when invitedOrgIds and ecosystemIds are empty by checking their lengths first and skipping the DB call (set orgs = [] or early-return where appropriate) so you don't run a pointless query; build the statusMap from orgs as before and populate enrichedData via the existing mapping. Replace the magic string 'NOT_FOUND' with the canonical enum/constant (e.g., EcosystemOrgStatus.NOT_FOUND or a suitable value from EcosystemOrgStatus) so enrichedData uses that constant for missing statuses. Ensure you reference getEcosystemOrgsByOrgIdAndEcosystemId, statusMap, and enrichedData when making the change.
🤖 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 956-958: The `@ApiResponse` decorator on the dashboard count
endpoint has a stale description string ('Template details fetched
successfully'); update the description to accurately describe the dashboard
count response (e.g., 'Dashboard counts fetched successfully') by editing the
`@ApiResponse`(...) attached to the dashboard count controller method in
ecosystem.controller.ts so Swagger reflects the correct endpoint behavior.
In `@apps/ecosystem/repositories/ecosystem.repository.ts`:
- Around line 103-105: The whereClause in getInvitationsByUserId currently only
filters by createdBy (const whereClause) and thus includes soft-deleted
invitations; update the whereClause used in getInvitationsByUserId to also
include deletedAt: null (matching the pattern used in
findAcceptedInvitationByUserId and findEcosystemInvitationByEmail) so paginated
results exclude soft-deleted records, and ensure any pagination/count queries
use the same whereClause variable.
- Line 1521: The dashboard count is including soft-deleted ecosystems because
the call to this.prisma.ecosystem.count() lacks a soft-delete filter; update the
count call to pass a where filter that excludes deleted records (e.g., where: {
deletedAt: null }) so it matches the other queries like
getAllEcosystems/getAllEcosystemsByOrgId; locate the usage of
this.prisma.ecosystem.count() in the repository and add the same deletedAt: null
condition to the count's where clause.
- Around line 1541-1551: getEcosystemEnableStatus currently calls
prisma.platform_config.findFirst and dereferences data.isEcosystemEnabled which
will throw if findFirst returns null; update the method to either call the
existing getPlatformConfig() and read isEcosystemEnabled safely or check for
null after prisma.platform_config.findFirst before accessing isEcosystemEnabled,
returning false when no config exists; preserve the try/catch and logger.error
semantics (method name: getEcosystemEnableStatus, helper: getPlatformConfig, DB
call: prisma.platform_config.findFirst).
- Around line 1499-1516: The try/catch in getEcosystemOrgsByOrgIdAndEcosystemId
is ineffective because the function is not async; make the method async and
await the prisma.ecosystem_orgs.findMany(...) call so runtime DB errors are
caught, log the caught error via this.logger.error(...) inside the catch, then
rethrow the error (or throw a wrapped error) to preserve behavior; update the
method signature (getEcosystemOrgsByOrgIdAndEcosystemId) and ensure you return
the awaited result.
---
Outside diff comments:
In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 168-185: The catch-all in getInvitationsByUserId is masking
intentional and repository-thrown exceptions by always logging and throwing
InternalServerErrorException; update the catch block in ecosystem.service.ts
(the try around this.ecosystemRepository.getInvitationsByUserId / enrichedData
mapping) to re-throw known/typed exceptions (e.g., if error is an instance of
HttpException or has a status/property used by your framework) before converting
to InternalServerErrorException, and for the local validation error (the
explicit throw new Error('failed to fetch invitations')) replace it with a
specific exception type (e.g., BadRequestException or NotFoundException) so
callers receive the correct status; preserve logging with
this.logger.error(error) but only wrap unknown errors into
InternalServerErrorException.
---
Nitpick comments:
In `@apps/api-gateway/src/platform/platform.controller.ts`:
- Around line 330-338: The new endpoint method getEcosystemEnableStatus is
missing an `@ApiTags` decorator so it will show up ungrouped in Swagger; add the
appropriate `@ApiTags`('ecosystem') (or the existing group name used in this
controller) to the controller or annotate the getEcosystemEnableStatus route so
it is grouped consistently with other endpoints (use the `@ApiTags` decorator
import from `@nestjs/swagger` and apply it alongside the controller/class or
immediately above the getEcosystemEnableStatus method).
In `@apps/ecosystem/repositories/ecosystem.repository.ts`:
- Line 1518: Rename the misspelled repository method
getDashBoardCountPlatfromAdmin to getDashBoardCountPlatformAdmin and update all
usages and declarations (including the service method in ecosystem.service.ts)
to the corrected name; ensure the function signature and return type
IPlatformDashboardCount remain unchanged, update any interface/exports and
imports that reference getDashBoardCountPlatfromAdmin, and run/adjust tests and
type references to reflect the new identifier so compilation and call sites are
consistent.
In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 173-180: Guard against calling
getEcosystemOrgsByOrgIdAndEcosystemId when invitedOrgIds and ecosystemIds are
empty by checking their lengths first and skipping the DB call (set orgs = [] or
early-return where appropriate) so you don't run a pointless query; build the
statusMap from orgs as before and populate enrichedData via the existing
mapping. Replace the magic string 'NOT_FOUND' with the canonical enum/constant
(e.g., EcosystemOrgStatus.NOT_FOUND or a suitable value from EcosystemOrgStatus)
so enrichedData uses that constant for missing statuses. Ensure you reference
getEcosystemOrgsByOrgIdAndEcosystemId, statusMap, and enrichedData when making
the change.
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/ecosystem/repositories/ecosystem.repository.ts`:
- Line 1522: Rename the incorrectly spelled method
getDashBoardCountPlatfromAdmin to getDashBoardCountPlatformAdmin in the
repository class (method implementation in ecosystem.repository:
getDashBoardCountPlatfromAdmin) and update all references (service layer
methods, controllers, message pattern handlers, imports/exports, and any tests
or interfaces calling it) to the new name so callers compile; perform a
project-wide search/replace for the exact symbol
"getDashBoardCountPlatfromAdmin" and run tests/TypeScript build to catch and fix
any remaining usages.
- Around line 1526-1535: The count queries for prisma.ecosystem_invitations and
prisma.ecosystem_orgs are including soft-deleted rows; update the where clauses
used in the prisma.ecosystem_invitations.count and prisma.ecosystem_orgs.count
calls to include deletedAt: null so only non-deleted records are counted (i.e.,
add deletedAt: null to the where filter for the two count calls in this
repository method).
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/ecosystem/src/ecosystem.service.ts (1)
176-179: Use a collision-safe key separator and replace the'NOT_FOUND'magic string.Two minor issues:
Key collision risk: The composite key
${org.orgId}-${org.ecosystemId}uses-as a separator, but UUIDs already contain-. Two distinct(orgId, ecosystemId)pairs can in theory produce the same string. Use|or another character absent from UUID format.Magic string
'NOT_FOUND': The fallback value is a raw string literal rather than an enum orundefined. SinceorgStatusis typed asstring | undefinedinIEcosystemInvitations, using?? undefined(or a dedicated enum constant) is cleaner. Also, prefer??over||to avoid replacing a legitimate empty-string status.♻️ Proposed fix
- const statusMap = new Map(orgs.map((org) => [`${org.orgId}-${org.ecosystemId}`, org.status])); + const statusMap = new Map(orgs.map((org) => [`${org.orgId}|${org.ecosystemId}`, org.status])); const enrichedData: IEcosystemInvitations[] = invitations.data.map((invitation) => ({ ...invitation, - orgStatus: statusMap.get(`${invitation.invitedOrg}-${invitation.ecosystemId}`) || 'NOT_FOUND' + orgStatus: statusMap.get(`${invitation.invitedOrg}|${invitation.ecosystemId}`) ?? undefined }));🤖 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 176 - 179, The composite key construction in statusMap (built from orgs.map using `${org.orgId}-${org.ecosystemId}`) is collision-prone and the enrichedData mapping uses a magic string 'NOT_FOUND'; change the separator to a collision-safe character (e.g., `|`) when creating keys and lookups, and replace the fallback `'NOT_FOUND'` with undefined by using the nullish coalescing operator (?? undefined) so IEcosystemInvitations.orgStatus stays typed as string | undefined; update both the statusMap key creation and the lookup inside the invitations.data.map accordingly.
🤖 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/ecosystem/repositories/ecosystem.repository.ts`:
- Around line 1500-1520: The query in getEcosystemOrgsByOrgIdAndEcosystemId is
missing the soft-delete filter so soft-deleted rows leak into the status map;
update the where clause used in this.prisma.ecosystem_orgs.findMany to include
deletedAt: null alongside orgId: { in: orgId } and ecosystemId: { in:
ecosystemId } so only non-deleted memberships are returned, and keep the same
select block and error handling.
In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 170-172: The check if (!invitations.data) is unreachable because
PaginatedResponse.data comes from findMany and is always an array; remove the
guard and thrown Error. Update the code around the invitations variable (the
PaginatedResponse returned by findMany) to treat an empty invitations.data array
as a valid result (or explicitly handle empty via invitations.data.length === 0
if you need a special case), and ensure TypeScript types reflect that
PaginatedResponse.data is an array so no null/undefined guard is required.
---
Nitpick comments:
In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 176-179: The composite key construction in statusMap (built from
orgs.map using `${org.orgId}-${org.ecosystemId}`) is collision-prone and the
enrichedData mapping uses a magic string 'NOT_FOUND'; change the separator to a
collision-safe character (e.g., `|`) when creating keys and lookups, and replace
the fallback `'NOT_FOUND'` with undefined by using the nullish coalescing
operator (?? undefined) so IEcosystemInvitations.orgStatus stays typed as string
| undefined; update both the statusMap key creation and the lookup inside the
invitations.data.map accordingly.
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/ecosystem/repositories/ecosystem.repository.ts (2)
101-101: Return typePaginatedResponse<ecosystem_invitations>is narrower than the actual query result.The
findManyusesincludeto attachecosystemandorganisationfields. The inferred Prisma type is(ecosystem_invitations & { ecosystem: ..., organisation: ... })[], but the declared return type advertises only bareecosystem_invitations. Callers relying on the TypeScript type won't see the enriched fields via the compiler, even though they're present at runtime.Consider either a dedicated response interface or using the Prisma-generated
Prisma.ecosystem_invitationsGetPayload<...>utility to make the contract explicit.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ecosystem/repositories/ecosystem.repository.ts` at line 101, The declared return type Promise<PaginatedResponse<ecosystem_invitations>> is too narrow because the findMany includes ecosystem and organisation; update the method's return contract to reflect the enriched payload (either by creating a dedicated response interface or using Prisma's utility). Concretely, change the generic on PaginatedResponse to use Prisma.ecosystem_invitationsGetPayload with the same include shape (e.g., Prisma.ecosystem_invitationsGetPayload<{ include: { ecosystem: true; organisation: true } }>) or replace with a new interface like EcosystemInvitationWithRelations and use PaginatedResponse<EcosystemInvitationWithRelations>; adjust any callers/types accordingly.
1523-1546: All previously flagged issues addressed — one minor naming nit.Line 1540: the destructured variable
ecosystem(anumber) shadows theecosystemPrisma model type imported at line 30. While harmless here, it can confuse readers who seeecosystemand expect a model instance.🔧 Suggested rename
- const [ecosystem, invitations, activeOrgs] = data; - return { ecosystem, invitations, activeOrgs }; + const [ecosystemCount, invitations, activeOrgs] = data; + return { ecosystem: ecosystemCount, invitations, activeOrgs };🤖 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 1523 - 1546, The local destructured variable named "ecosystem" in getDashBoardCountPlatformAdmin shadows the imported Prisma model "ecosystem"; rename the destructured binding to something like "ecosystemCount" (e.g., change const [ecosystem, invitations, activeOrgs] = data; to const [ecosystemCount, invitations, activeOrgs] = data;) and then use that new name in the return (return { ecosystem: ecosystemCount, invitations, activeOrgs }) so the external IPlatformDashboardCount shape stays the same while avoiding the shadowing of the Prisma model.
🤖 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/ecosystem/src/ecosystem.service.ts`:
- Around line 170-178: The code uses optional chaining on invitations
(invitedOrgIds and ecosystemIds computed from invitations?.data) even though
invitations is always a PaginatedResponse; remove the unnecessary ?. so both
lines consistently access invitations.data directly; update the lines that build
invitedOrgIds and ecosystemIds (which feed
getEcosystemOrgsByOrgIdAndEcosystemId), leaving orgs, statusMap and enrichedData
logic unchanged.
---
Nitpick comments:
In `@apps/ecosystem/repositories/ecosystem.repository.ts`:
- Line 101: The declared return type
Promise<PaginatedResponse<ecosystem_invitations>> is too narrow because the
findMany includes ecosystem and organisation; update the method's return
contract to reflect the enriched payload (either by creating a dedicated
response interface or using Prisma's utility). Concretely, change the generic on
PaginatedResponse to use Prisma.ecosystem_invitationsGetPayload with the same
include shape (e.g., Prisma.ecosystem_invitationsGetPayload<{ include: {
ecosystem: true; organisation: true } }>) or replace with a new interface like
EcosystemInvitationWithRelations and use
PaginatedResponse<EcosystemInvitationWithRelations>; adjust any callers/types
accordingly.
- Around line 1523-1546: The local destructured variable named "ecosystem" in
getDashBoardCountPlatformAdmin shadows the imported Prisma model "ecosystem";
rename the destructured binding to something like "ecosystemCount" (e.g., change
const [ecosystem, invitations, activeOrgs] = data; to const [ecosystemCount,
invitations, activeOrgs] = data;) and then use that new name in the return
(return { ecosystem: ecosystemCount, invitations, activeOrgs }) so the external
IPlatformDashboardCount shape stays the same while avoiding the shadowing of the
Prisma model.
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/ecosystem/src/ecosystem.service.ts`:
- Around line 174-177: The mapping currently sets orgStatus to 'NOT_FOUND' for
any missing statusMap entry, which incorrectly labels legitimate "create
ecosystem later" invitations as errors; update the enrichedData mapping in
ecosystem.service.ts (the invitations.data.map callback building
IEcosystemInvitations with orgStatus and using statusMap) to first detect the
nullable workflow (if invitation.invitedOrg === undefined ||
invitation.ecosystemId == null) and set orgStatus to a clear non-error value
like 'UNASSIGNED' (or 'PENDING_ASSIGNMENT'), otherwise compute the key
`${invitation.invitedOrg}-${invitation.ecosystemId}` and use statusMap.get(key)
with a true fallback of 'NOT_FOUND' only when both ids were present but no entry
exists; keep the rest of the object spread and types unchanged.
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
Signed-off-by: sujitaw <sujit.sutar@ayanworks.com>
|



What
Summary by CodeRabbit
New Features
Chores