Skip to content

[Customer Portal][BE] Add case create endpoint and update case response - #114

Merged
Rashmika998 merged 4 commits into
wso2-open-operations:customer-portal-milestone-1from
Rashmika998:customer-portal-milestone-1-cases
Feb 10, 2026
Merged

Rashmika998 merged 4 commits into
wso2-open-operations:customer-portal-milestone-1from
Rashmika998:customer-portal-milestone-1-cases

Conversation

@Rashmika998

@Rashmika998 Rashmika998 commented Feb 10, 2026 •

Copy link
Copy Markdown
Contributor

Description

This PR introduces a new endpoint for case creation and updates the case response structure.

Changes

  • Added API endpoint to create cases (POST /cases)
  • Updated case response model
  • Improved response consistency and validation

Testing

  • Tested case creation endpoint with valid and invalid payloads
  • Verified updated response format across consumers

Related Issues

Related PRs

Checklist

  • API tested locally

Summary by CodeRabbit

  • New Features

    • Users can now create support cases directly through the application.
  • Bug Fixes

    • Fixed spacing in the unauthorized access error message.
  • Updates

    • Case details and search results now show deployed product and issue type for clearer context.

@coderabbitai

coderabbitai Bot commented Feb 10, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds case-creation: new CaseCreate types and CreatedCase, replaces Case.'type with deployedProduct and issueType across types and mappings, adds entity.createCase and a POST /cases resource that authenticates and forwards requests, fixes an auth message spacing, and removes customer_portal.types from Dependencies.toml.

Changes

Cohort / File(s) Summary
Entity module
apps/customer-portal/backend/modules/entity/entity.bal
Added public isolated function createCase(string idToken, CaseCreatePayload payload) that posts to /cases using the csEntityClient and auth headers.
Service / HTTP endpoint
apps/customer-portal/backend/service.bal
Added resource function post cases(...) that extracts auth, calls entity:createCase, and maps 201/401/403/500 responses with logging (note: function appears duplicated in file).
Entity types
apps/customer-portal/backend/modules/entity/types.bal, apps/customer-portal/backend/types.bal
Introduced CaseCreatePayload, CaseCreateResponse, CreatedCase; removed ReferenceItem? 'type and added deployedProduct and issueType to Case.
Utilities / Mapping
apps/customer-portal/backend/utils.bal
Replaced emitted type field with deployedProduct and issueType in searchCases mapping and updated local mappings accordingly.
Config & constants
apps/customer-portal/backend/Dependencies.toml, apps/customer-portal/backend/constants.bal
Removed customer_portal.types from modules list; fixed spacing in ERR_MSG_UNAUTHORIZED_ACCESS string literal.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Service as "Service Layer"
    participant Entity as "Entity Module"
    participant Backend as "Backend API"

    Client->>Service: POST /cases (CaseCreatePayload)
    Service->>Service: Extract auth token (HEADER_USER_INFO)
    Service->>Entity: createCase(idToken, payload)
    Entity->>Backend: POST /cases (with auth headers)
    Backend-->>Entity: 201 Created / 401 / 403 / error

    alt 201 Created
        Entity-->>Service: CaseCreateResponse
        Service-->>Client: 201 Created + case data
    else 401 Unauthorized
        Entity-->>Service: 401 Error
        Service-->>Client: 401 Unauthorized
    else 403 Forbidden
        Entity-->>Service: 403 Error
        Service-->>Client: 403 Forbidden
    else Other Error
        Entity-->>Service: Error
        Service-->>Client: 500 Internal Server Error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

Type/Task

Suggested reviewers

  • cloby99
  • shayanmalinda

Poem

🐰 I hopped a payload on its way,
New fields to name the product-play,
A token snug, a POST so bright,
Cases blossom in morning light,
Hooray — the portal hops to life! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete compared to the repository template. It lacks critical sections including Purpose, Goals, Approach, User stories, Release notes, Documentation, Security checks, and other required sections. Complete the PR description by filling in all required template sections, particularly Purpose, Goals, Approach, Release notes, and Documentation impact assessment.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main changes: adding a case creation endpoint and updating the case response structure, which aligns with the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
apps/customer-portal/backend/service.bal (1)

637-686: Hardcoded forbidden error message — extract to a constant for consistency.

Every other endpoint in this file uses predefined constants for error messages (e.g., ERR_MSG_UNAUTHORIZED_ACCESS, ERR_MSG_CASE_ACCESS_FORBIDDEN, ERR_MSG_PROJECT_ACCESS_FORBIDDEN). The forbidden response on lines 669–670 uses an inline string instead. Extract it to a constant in constants.bal for consistency and easier future maintenance.

♻️ Suggested refactor

In constants.bal, add:

+const string ERR_MSG_CASE_CREATE_FORBIDDEN = "You're not authorized to create a case for the selected project. " +
+    "Please check your access permissions or contact support.";

Then in service.bal:

             if getStatusCode(createdCaseResponse) == http:STATUS_FORBIDDEN {
                 log:printWarn(string `User: ${userInfo.userId} is forbidden to create a case for project: ${
                     payload.projectId}!`);
                 return <http:Forbidden>{
                     body: {
-                        message: "You're not authorized to create a case for the selected project. " +
-                        "Please check your access permissions or contact support."
+                        message: ERR_MSG_CASE_CREATE_FORBIDDEN
                     }
                 };
             }

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

@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: 2

🤖 Fix all issues with AI agents
In `@apps/customer-portal/backend/modules/entity/entity.bal`:
- Around line 91-98: The doc comment for the function addCase is wrong: it
states "Nil or error" but the function returns CaseCreateResponse|error. Update
the doc comment for addCase to accurately describe parameters and the return
type (CaseCreateResponse|error) and adjust the "return" line to mention
CaseCreateResponse or error; ensure the parameter descriptions for idToken and
payload remain correct and consistent with the function signature.

In `@apps/customer-portal/backend/modules/entity/types.bal`:
- Around line 119-138: The CaseCreatePayload definition is missing string
validation for title and description; update the record type (CaseCreatePayload)
to add `@constraint`:String {minLength: 1} annotations to the title and
description fields so they cannot be empty or blank, mirroring the existing
constraints on projectId, deploymentId, and productId.
🧹 Nitpick comments (2)
apps/customer-portal/backend/types.bal (1)

70-73: Public Case type updates are consistent with the entity layer.

The deployedProduct and issueType fields correctly use ReferenceItem? (string-based id), aligning with the int → string conversion done in utils.bal.

Nit: Line 72 comment # issueType of the case should be capitalized for consistency with other field comments (e.g., # Deployed product information).

Proposed fix
-    # issueType of the case
+    # Issue type of the case
     ReferenceItem? issueType;
apps/customer-portal/backend/service.bal (1)

641-642: Public endpoint directly exposes entity:CaseCreatePayload — inconsistent with other endpoints.

Other endpoints (e.g., case search) define a public-facing payload type in types.bal that maps to the entity type. Here, entity:CaseCreatePayload is used directly as the API input, coupling the public API contract to the entity layer. If the entity API adds internal-only fields, they'd be exposed to clients.

Consider introducing a public CaseCreatePayload in types.bal (similar to CaseSearchPayload) and mapping it to entity:CaseCreatePayload before calling entity:addCase.

Comment thread apps/customer-portal/backend/modules/entity/entity.bal Outdated
Comment thread apps/customer-portal/backend/modules/entity/types.bal
@Rashmika998 Rashmika998 moved this from Todo to In Progress in Customer Portal Development Feb 10, 2026

authorization:UserInfoPayload|error userInfo = ctx.getWithType(authorization:HEADER_USER_INFO);
if userInfo is error {
return <http:InternalServerError>{

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.

USER_INFO_HEADER_NOT_FOUND should not be 500. This is not a server error IMO it’s a client/auth issue. Should be;
<http:Unauthorized>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We (@shayanmalinda, @sacheeramesh, and I) already had a discussion in the past about whether this should return <http:Unauthorized>. I think, all our backends currently use a http:InternalServerError error for this case.

Should we revisit this? I also personally believe this should be a <http:Unauthorized> as well(including few errors in authorization.bal file).

Adding @yuk7hi and @kasunsiyambalapitiya as well

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.

IMO, HEADER_USER_INFO is not a header passed from the consumer (e.g., the web app).
It is an internal attribute introduced in the request interceptor to pass logged-in user information (email, groups, idToken) to service.bal via the http:RequestContext.

If this attribute is missing, or if there is an issue deriving it in service.bal (for example, setting it with one name and reading it using a different name), it should be treated as an implementation issue and the correct response should be an InternalServerError.

Authorization is handled at the gateway level, not by the backend service.
If a request reaches the backend, it is already authorized. Therefore, the backend should not ideally return any Unauthorized responses.

@Rashmika998 Rashmika998 Feb 10, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks @shayanmalinda. Agree that HEADER_USER_INFO is an internal context attribute and should be treated as an implementation issue (500) if missing.

One clarification here is that this behavior is specific to our setup. In Choreo, the gateway validates the Authorization: Bearer header and converts it into x-jwt-assertion before forwarding the request to the backend.

This conversion is platform-specific and not something all API gateways do by default.

Because of this, the backend currently depends on this contract with the gateway. If x-jwt-assertion is missing, it usually indicates an issue with the authentication flow at the gateway level (missing/invalid bearer token or routing/config issue), rather than something the consumer can directly fix.

We can add a comment in the interceptor to document this dependency on the gateway behavior, so it’s clear why this is treated as an internal error and mapped accordingly.

However I believe I need to fix the error returned when the custom header(x-user-id-token) is not found while checking it. Currently it returns 500.

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.

Let's have a seperate revisit on this later. Will approve the PR due to the urgency.

if userInfo is error {
return <http:InternalServerError>{
body: {
message: ERR_MSG_USER_INFO_HEADER_NOT_FOUND

@shayanmalinda shayanmalinda Feb 10, 2026 •

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.

I think returning ERR_MSG_USER_INFO_HEADER_NOT_FOUND is incorrect, since the user has no control over fixing this issue. As per the previous reply, this is an internal implementation problem, so it would be more appropriate to return a generic error such as Something went wrong while processing the request.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Shall we have an offline discussion regarding this? Anyway the fix will be in a separate PR.

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.

Yes, +1

Comment thread apps/customer-portal/backend/modules/entity/entity.bal Outdated
Comment thread apps/customer-portal/backend/modules/entity/entity.bal Outdated
Comment thread apps/customer-portal/backend/service.bal Outdated
Comment thread apps/customer-portal/backend/service.bal
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

App/Customer Portal Area/Backend Type/New Feature Represents a request or task for a new feature

Projects

Status: Staging Deployed

Development

Successfully merging this pull request may close these issues.

3 participants