Skip to content

fix(customer-portal-backend-v2): align response/request types with the frontend and old Ballerina backend - #1393

Merged
Rashmika998 merged 2 commits into
wso2-open-operations:dev-app-csm-portalfrom
Rashmika998:fix/customer-portal-v2-align-response-types
Aug 7, 2026
Merged

Rashmika998 merged 2 commits into
wso2-open-operations:dev-app-csm-portalfrom
Rashmika998:fix/customer-portal-v2-align-response-types

Conversation

@Rashmika998

@Rashmika998 Rashmika998 commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Continues the type-alignment audit started in #1388 (case search / call requests) to cover every remaining customer-portal-backend-v2 endpoint, cross-checked against the live frontend TypeScript and the old Ballerina backend (apps/customer-portal/backend) as the reference contract.

  • total → totalRecords renamed across deployments, deployed products, instances (search + 2 stats variants), products, product versions, product vulnerabilities, catalogs, change requests, time cards, conversations, comments, and case activities — matching the frontend's shared PaginationResponse type.
  • Numeric-id ⇄ enum translation added for change-request state/impact, conversation state, deployment type, and product-vulnerability severity (mirroring entity-service's own private ServiceNow/Choreo numeric-choice-list tables), following the same two-file pattern established for case fields in fix(customer-portal-backend-v2): add case attachments search, scope call-requests under /cases/{caseId} #1388.
  • Route re-scoping — deployments, deployed-products (now under /deployments/{deploymentId}/products), catalogs (now under /deployments/products/{deployedProductId}/catalogs), time-cards, and change-requests search/mutation routes now scope to their owning path parameter instead of trusting a client-supplied body field.
  • Response reshapes — case details, change request, time card, and deployed product responses rewritten to match the frontend's IdLabelRef-based contract ({id, label} instead of plain strings or {id, name} refs).
  • Missing fields added where entity-service's own domain type already carried the data but this backend's mirror struct didn't: project.startDate, project.account.{hasAgent,hasKbReferences,activationDate}, case.{watchList,changeRequests}, users/me.lastPasswordUpdateTime, registry token name.
  • Type fixes — registry token id/expiresAt now decode as numbers (previously strings, which didn't match either the real upstream response or the frontend's own type).
  • New routes — GET /products (frontend's live product-browsing flow, translated to entity-service's POST /products/search) and POST /cases/{id}/attachments.

Everywhere a field genuinely doesn't exist on entity-service's own domain type (verified against cs-tools/entity-service/internal/domain/entity.go, not assumed), it's left out rather than fabricated — those gaps are documented with doc comments at each call site.

Test plan

  • go build ./...
  • go vet ./...
  • gofmt -l — clean
  • go test ./... — all existing tests pass, plus 16 new tests added covering the translation logic introduced in this PR (internal/dto/type_alignment_test.go)
  • gosec -fmt=text ./... — 0 issues
  • openapi.yaml, README.md, CLAUDE.md updated to match every route/schema change
  • Manual smoke test against a running frontend (not done in this session — recommend before merge)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added product browsing through GET /products.
    • Added case attachment creation.
    • Added project- and deployment-scoped operations for deployments, deployed products, catalogs, change requests, and time cards.
    • Added richer case, project, account, comment, conversation, vulnerability, and registry-token details.
  • Improvements

    • Standardized pagination responses with totalRecords.
    • Updated API responses with clearer labels, references, dates, and numeric choice values.
    • User profile responses now include the last password update time.
  • Documentation

    • Updated API documentation and examples to reflect 104 available routes and the revised endpoint structure.

…e frontend and old Ballerina backend

Audits and fixes every remaining endpoint's request/response shape against the
live frontend TypeScript and the old Ballerina backend, the same pass applied
to case-search/call-requests in PR wso2-open-operations#1388: rename total->totalRecords across
deployments, deployed products, instances, products, product versions,
product vulnerabilities, catalogs, change requests, time cards, conversations,
comments, and case activities; translate ServiceNow/Choreo numeric ids <->
entity-service enums for change-request state/impact, conversation state,
deployment type, and product-vulnerability severity; scope
deployments/deployed-products/catalogs/time-cards/change-requests search and
mutation routes under their owning path parameter instead of trusting a
client-supplied body field; rewrite case details, change request, time card,
and deployed product response shapes to match the frontend's IdLabelRef-based
contract; add missing fields (project.startDate, project.account.hasAgent/
hasKbReferences/activationDate, case.watchList/changeRequests,
users/me.lastPasswordUpdateTime, registry token name); fix registry token
id/expiresAt to decode as numbers; add GET /products and
POST /cases/{id}/attachments.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Rashmika998, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 36 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4239099a-3b5f-4956-a9a7-6e6baeb6b968

📥 Commits

Reviewing files that changed from the base of the PR and between 712094f and 5266789.

📒 Files selected for processing (7)
  • apps/customer-portal/backend-v2/internal/dto/case.go
  • apps/customer-portal/backend-v2/internal/dto/deployment.go
  • apps/customer-portal/backend-v2/internal/dto/product.go
  • apps/customer-portal/backend-v2/internal/dto/product_vulnerability.go
  • apps/customer-portal/backend-v2/internal/dto/type_alignment_test.go
  • apps/customer-portal/backend-v2/internal/handler/products.go
  • apps/customer-portal/backend-v2/openapi.yaml
📝 Walkthrough

Walkthrough

The customer portal backend now uses scoped resource routes, frontend-aligned DTOs, numeric enum mappings, totalRecords pagination, product browsing, case attachment creation, and updated OpenAPI documentation. Request handlers inject path-based project or deployment scope before calling the entity service.

Changes

Customer portal API alignment

Layer / File(s) Summary
Routes and API contract
apps/customer-portal/backend-v2/cmd/server/main.go, apps/customer-portal/backend-v2/openapi.yaml, apps/customer-portal/backend-v2/README.md, apps/customer-portal/backend-v2/CLAUDE.md
Deployment, deployed-product, catalog, change-request, and time-card routes now use project or deployment scope. GET /products and POST /cases/{id}/attachments were added. OpenAPI schemas and examples reflect the updated request and response shapes.
DTO contracts and mappings
apps/customer-portal/backend-v2/internal/dto/*, apps/customer-portal/backend-v2/internal/entity/types.go, apps/customer-portal/backend-v2/internal/registry/types.go
DTOs now use IDLabelRef, numeric choice-list keys, totalRecords, nested filters, frontend field names, and path-scoped request builders. Case, conversation, change-request, deployment, time-card, vulnerability, project, catalog, instance, registry, and user mappings were updated.
Handler and client wiring
apps/customer-portal/backend-v2/internal/handler/*
Handlers validate path UUIDs, translate DTO requests, inject project or deployment identifiers, add product browsing and case attachment creation, narrow case updates, and map the SCIM password-update timestamp.
Alignment validation
apps/customer-portal/backend-v2/internal/dto/type_alignment_test.go
Tests cover enum translation, scoped request construction, response mapping, numeric parsing, nested filters, catalog labels, and registry token values.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: cloby99

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description gives a detailed summary and test plan, but it omits most sections required by the repository template. Add the missing template sections, including purpose, goals, user stories, release note, documentation, security checks, automation details, migrations, test environment, and learning.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: aligning customer portal request and response types with frontend and legacy backend contracts.
Docstring Coverage ✅ Passed Docstring coverage is 91.38% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@Rashmika998
Rashmika998 changed the base branch from main to dev-app-csm-portal August 7, 2026 02:25
@Rashmika998

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
apps/customer-portal/backend-v2/openapi.yaml (1)

6887-6904: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the base64 field name across the two attachment-create contracts.

CreateCaseAttachmentRequest names the base64 payload content. CreateAttachmentRequest (line 6920) names the same payload file. Two names for one concept increase client error risk. If the frontend requires content on the case route, keep it and add a note here that the difference is deliberate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/customer-portal/backend-v2/openapi.yaml` around lines 6887 - 6904, The
attachment-create request schemas use inconsistent names for the base64 payload.
Align CreateCaseAttachmentRequest and CreateAttachmentRequest on one field name,
preferably content if required by the frontend; if the contracts must differ,
retain content for the case route and document the deliberate difference in its
schema description.
apps/customer-portal/backend-v2/internal/dto/deployed_product.go (1)

112-134: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider omitting empty deployment and product references.

entityRefToIDLabel(&d.Deployment) and entityRefToIDLabel(&d.Product) always receive a non-nil pointer. If the upstream reference is zero-valued, the mapper emits {"label":""} instead of omitting the field, because IDLabelRef.Label has no omitempty. The frontend then renders an empty label rather than treating the reference as absent. Add a zero-value check if the frontend distinguishes the two cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/customer-portal/backend-v2/internal/dto/deployed_product.go` around
lines 112 - 134, Update MapSearchDeployedProducts to detect zero-valued
d.Deployment and d.Product references before calling entityRefToIDLabel, passing
nil or otherwise leaving the corresponding fields absent when references are
empty. Preserve the existing mapping for non-zero references so the frontend
distinguishes absent references from empty labels.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/customer-portal/backend-v2/internal/dto/deployed_product.go`:
- Around line 156-178: Update BuildEntityCreateDeployedProductRequest so
ProjectID is derived from the path-mounted deployment rather than copied from
DeployedProductCreateRequest.ProjectID. Resolve the deployment’s owning project
before constructing entity.CreateDeployedProductRequest, and use that value
while preserving DeploymentID from the path; do not trust or forward the
body-supplied project ID.

In `@apps/customer-portal/backend-v2/internal/dto/deployment.go`:
- Around line 105-128: Update DeploymentUpdateRequest.Description to use
json.RawMessage so absent and explicit null remain distinguishable, and modify
BuildEntityUpdateDeploymentRequest to copy non-empty raw bytes into
entity.UpdateDeploymentRequest.Description while preserving string values. Add
tests covering an absent description, explicit null, and a string description.

In `@apps/customer-portal/backend-v2/internal/dto/product_vulnerability.go`:
- Around line 91-128: Remove StatusID from SearchProductVulnerabilitiesFilters
and remove the corresponding statusId definition from openapi.yaml, since
BuildEntitySearchProductVulnerabilitiesRequest cannot forward it. Ensure the
portal contract no longer advertises status filtering until entity-service
supports it.

In `@apps/customer-portal/backend-v2/internal/handler/cases.go`:
- Around line 244-253: Update UpdateCaseRequest so WatchList is a pointer to a
string slice, allowing absent and explicitly empty watch lists to be
distinguished. In the handler’s primary-field validation, check WatchList for
non-nil rather than using len, and update BuildEntityUpdateCaseRequest to
dereference it when present; preserve any entity-service restriction on empty
lists and document it in openapi.yaml if applicable.

In `@apps/customer-portal/backend-v2/internal/handler/deployed_products.go`:
- Around line 108-114: The nested deployment operations must enforce project
ownership server-side. In deployed_products.go, update CreateDeployedProduct and
BuildEntityCreateDeployedProductRequest usage so the project comes from the
deployment identified by deploymentID, or reject requests when ownership cannot
be derived instead of trusting req.ProjectID. In deployments.go lines 128-156,
update PatchDeployment to accept and validate a projectId path parameter before
UpdateDeployment, or expose the endpoint only as explicitly unscoped if the
parent project scope is not authoritative.

In `@apps/customer-portal/backend-v2/internal/handler/products.go`:
- Around line 52-86: Update ProductHandler.GetProducts to inspect the class
query parameter instead of silently discarding it; return a 400 response when
class is supplied, until entity-service supports class filtering. Preserve the
existing offset and limit validation and search flow for requests without class.

---

Nitpick comments:
In `@apps/customer-portal/backend-v2/internal/dto/deployed_product.go`:
- Around line 112-134: Update MapSearchDeployedProducts to detect zero-valued
d.Deployment and d.Product references before calling entityRefToIDLabel, passing
nil or otherwise leaving the corresponding fields absent when references are
empty. Preserve the existing mapping for non-zero references so the frontend
distinguishes absent references from empty labels.

In `@apps/customer-portal/backend-v2/openapi.yaml`:
- Around line 6887-6904: The attachment-create request schemas use inconsistent
names for the base64 payload. Align CreateCaseAttachmentRequest and
CreateAttachmentRequest on one field name, preferably content if required by the
frontend; if the contracts must differ, retain content for the case route and
document the deliberate difference in its schema description.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d32ba0c6-880b-49f6-8930-4408fef3af4e

📥 Commits

Reviewing files that changed from the base of the PR and between bf69991 and 712094f.

📒 Files selected for processing (39)
  • apps/customer-portal/backend-v2/CLAUDE.md
  • apps/customer-portal/backend-v2/README.md
  • apps/customer-portal/backend-v2/cmd/server/main.go
  • apps/customer-portal/backend-v2/internal/dto/ai_chat.go
  • apps/customer-portal/backend-v2/internal/dto/attachment.go
  • apps/customer-portal/backend-v2/internal/dto/case.go
  • apps/customer-portal/backend-v2/internal/dto/case_time_cards.go
  • apps/customer-portal/backend-v2/internal/dto/catalog.go
  • apps/customer-portal/backend-v2/internal/dto/change_request.go
  • apps/customer-portal/backend-v2/internal/dto/change_request_enum_mapping.go
  • apps/customer-portal/backend-v2/internal/dto/comment.go
  • apps/customer-portal/backend-v2/internal/dto/conversation_enum_mapping.go
  • apps/customer-portal/backend-v2/internal/dto/deployed_product.go
  • apps/customer-portal/backend-v2/internal/dto/deployment.go
  • apps/customer-portal/backend-v2/internal/dto/deployment_enum_mapping.go
  • apps/customer-portal/backend-v2/internal/dto/instance.go
  • apps/customer-portal/backend-v2/internal/dto/product.go
  • apps/customer-portal/backend-v2/internal/dto/product_vulnerability.go
  • apps/customer-portal/backend-v2/internal/dto/product_vulnerability_enum_mapping.go
  • apps/customer-portal/backend-v2/internal/dto/project.go
  • apps/customer-portal/backend-v2/internal/dto/registry.go
  • apps/customer-portal/backend-v2/internal/dto/time_card.go
  • apps/customer-portal/backend-v2/internal/dto/type_alignment_test.go
  • apps/customer-portal/backend-v2/internal/dto/user.go
  • apps/customer-portal/backend-v2/internal/entity/types.go
  • apps/customer-portal/backend-v2/internal/handler/ai_chat.go
  • apps/customer-portal/backend-v2/internal/handler/cases.go
  • apps/customer-portal/backend-v2/internal/handler/catalogs.go
  • apps/customer-portal/backend-v2/internal/handler/change_requests.go
  • apps/customer-portal/backend-v2/internal/handler/deployed_products.go
  • apps/customer-portal/backend-v2/internal/handler/deployments.go
  • apps/customer-portal/backend-v2/internal/handler/instances.go
  • apps/customer-portal/backend-v2/internal/handler/product_vulnerabilities.go
  • apps/customer-portal/backend-v2/internal/handler/products.go
  • apps/customer-portal/backend-v2/internal/handler/projects.go
  • apps/customer-portal/backend-v2/internal/handler/time_cards.go
  • apps/customer-portal/backend-v2/internal/handler/users.go
  • apps/customer-portal/backend-v2/internal/registry/types.go
  • apps/customer-portal/backend-v2/openapi.yaml

Comment thread apps/customer-portal/backend-v2/internal/dto/deployed_product.go
Comment thread apps/customer-portal/backend-v2/internal/dto/deployment.go
Comment thread apps/customer-portal/backend-v2/internal/handler/cases.go
Comment thread apps/customer-portal/backend-v2/internal/handler/products.go
…n PR wso2-open-operations#1393

- Preserve explicit description:null on PATCH /projects/{id}/deployments/{id}
  by switching DeploymentUpdateRequest.Description from *string to
  json.RawMessage, matching the three-state absent/null/value convention
  entity-service's own request type already requires.
- Apply GET /products' class filter server-side (post-fetch, since
  entity-service has no class request parameter) instead of silently
  ignoring it, with documented pagination/data-source caveats.
- Remove statusId from the product-vulnerabilities search filter contract
  instead of accepting and silently dropping it — entity-service's
  ProductVulnerabilityView has no status data anywhere to filter by.
- Document (rather than "fix") the watchList empty-array limitation on
  PATCH /cases/{id}: entity-service's own ServiceNow implementation only
  forwards watchList upstream when non-empty, so no layer of this stack can
  currently honor an explicit "clear all watchers" request.
- Two other findings (deployed-product/deployment project-scoping) were
  reviewed and left as-is: every write in this backend already authorizes
  through the caller's own forwarded ID token at the ServiceNow/Choreo
  integration layer, the same pattern used throughout this codebase — see
  PR review replies for the entity-service source confirming this.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Rashmika998
Rashmika998 merged commit 19da50e into wso2-open-operations:dev-app-csm-portal Aug 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants