Skip to content

[Customer Portal] Add cases search and remove unused methods - #11

Merged
shayanmalinda merged 8 commits into
wso2-open-operations:customer-portal-milestone-1from
Rashmika998:customer-portal-milestone-1
Jan 16, 2026
Merged

shayanmalinda merged 8 commits into
wso2-open-operations:customer-portal-milestone-1from
Rashmika998:customer-portal-milestone-1

Conversation

@Rashmika998

@Rashmika998 Rashmika998 commented Jan 13, 2026 •

Copy link
Copy Markdown
Contributor

Description

  • Add cases resource method to search the cases of a project.
  • Remove unused methods.
  • Remove cache configs.
  • Remove group access temporary.

Closes #34, #37

Related PRs

Summary by CodeRabbit

Release Notes

  • Breaking Changes

    • Removed endpoints for project details, project overview, case filters, and individual case details
    • Updated case search payload structure with new parameters (caseTypes, filters, sortBy, pagination)
    • Modified case response fields and added pagination support
  • API Updates

    • Case search endpoint consolidated to single, payload-based approach

✏️ Tip: You can customize this high-level summary in your review settings.

@Rashmika998 Rashmika998 self-assigned this Jan 13, 2026
@Rashmika998 Rashmika998 added Type/Improvement Marks enhancements or improvements to existing features App/Customer Portal Area/Backend labels Jan 13, 2026
@coderabbitai

coderabbitai Bot commented Jan 13, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This pull request consolidates case and project retrieval functionality in the customer portal backend. It removes separate endpoints for project details, overview, case filters, and individual case details, replacing them with a unified searchCases function and updated payload structure using CaseSearchPayload and CaseRequestBody types. The Case record is restructured with new canonical fields while removing obsolete response types.

Changes

Cohort / File(s) Summary
Core Entity Functions
apps/customer-portal/backend/modules/entity/entity.bal
Removed four public functions: fetchCasesFilters, fetchProjectOverview, fetchProjectDetails, fetchCaseDetails. Replaced fetchCases with searchCases(string idToken, string projectId, CaseSearchPayload payload) with new internal request body structure including projectIds and integrated CaseSearchPayload fields. Updated endpoint path from /projects/[projectId]/cases/search.post to /cases/search.post.
Type Definitions Restructuring
apps/customer-portal/backend/modules/entity/types.bal
Updated Case record with new fields (caseId, projectId, caseType, state, stateLabel, priority, priorityLabel, deployment, deploymentId) while removing old fields. Removed 11 public types: CaseDetailsResponse, CaseComment, CaseAttachment, CallRequest, KbArticle, ProjectStatistics, RecentActivity, ProjectOverviewResponse, CommentAuthor, IncidentCount, ActiveCaseCount. Added three new public types: CaseSearchFilters, CaseSearchPayload, CaseRequestBody. Updated CasesResponse to include totalRecords and *Pagination.
Service Endpoint Consolidation
apps/customer-portal/backend/service.bal
Removed four public GET endpoints: projects/[id], projects/[id]/overview, projects/[id]/cases/filters, projects/[id]/cases/[caseId]. Updated POST projects/[id]/cases/search endpoint to use CaseSearchPayload instead of CaseFiltersRequest. Changed internal call from fetchCases to searchCases. Removed pagination validation logic.
Test Updates
apps/customer-portal/backend/tests/service_test.bal
Renamed test function from testGetProjectDetails to testSearchCasesOfProject. Replaced GET request to /projects/[1].get(...) with POST request to /projects/[1]/cases/search.post(...). Updated request payloads and assertions accordingly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested reviewers

  • shayanmalinda

Poem

🐰 Cases bundled, filters gone,
Search now unified and strong,
New payloads dance so fine,
Types refined on every line,
Endpoints consolidated bright,
API flows just right! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is minimal and lacks required sections. It provides only a brief bulleted list without proper context, rationale, or structured information. Add required sections from the template: Purpose with issue links, Goals, Approach, User stories, Release note, Documentation, Training, Certification, Marketing, Automation tests, Security checks, Samples, Migrations, Test environment, and Learning sections.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding a cases search capability and removing unused methods from the customer portal backend.
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 docstrings

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.

@Rashmika998

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jan 13, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

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

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2f4875 and e6f8ae0.

📒 Files selected for processing (4)
  • apps/customer-portal/backend/modules/entity/entity.bal
  • apps/customer-portal/backend/modules/entity/types.bal
  • apps/customer-portal/backend/service.bal
  • apps/customer-portal/backend/tests/service_test.bal
🔇 Additional comments (6)
apps/customer-portal/backend/modules/entity/types.bal (3)

104-134: LGTM! Well-structured Case record with proper field documentation.

The restructured Case record with canonical fields (caseId, projectId, caseType, state, stateLabel) and optional detail fields (priority, priorityLabel, deployment, deploymentId) provides a clean, unified model.


136-144: Consider consistency in filter field types.

status and severity are int while deployment is string. This is likely intentional based on backend data model, but verify that this aligns with the actual filter values expected by the downstream service.


146-172: LGTM! Clean composition using record spreading.

The use of *Pagination in CasesResponse and *CaseSearchPayload in CaseRequestBody provides clean type composition. Optional pagination field allows clients to rely on defaults.

apps/customer-portal/backend/modules/entity/entity.bal (1)

35-52: LGTM! Clean refactoring of case search functionality.

The searchCases function properly:

  1. Accepts CaseSearchPayload as input, providing a clean API for callers
  2. Internally constructs CaseRequestBody with projectIds array wrapping the single project ID
  3. Spreads all payload fields (caseTypes, pagination, filters, sortBy) into the request body

The endpoint change from /projects/[projectId]/cases/search.post to /cases/search.post with projectIds in the body aligns with a more flexible multi-project search architecture.

apps/customer-portal/backend/service.bal (1)

140-178: LGTM! Well-implemented case search endpoint with proper validation.

The implementation correctly:

  1. Validates authorization before processing
  2. Validates project ID is not empty or whitespace (line 157-165)
  3. Delegates to entity:searchCases with proper parameters
  4. Follows consistent error handling pattern with other endpoints
apps/customer-portal/backend/tests/service_test.bal (1)

36-45: LGTM!

The formatting adjustment improves readability.

Comment thread apps/customer-portal/backend/tests/service_test.bal
@Rashmika998
Rashmika998 force-pushed the customer-portal-milestone-1 branch from 3969fa5 to f022abc Compare January 13, 2026 05:35
@Rashmika998
Rashmika998 force-pushed the customer-portal-milestone-1 branch from 48d98ac to 2377f24 Compare January 13, 2026 13:05
Comment thread apps/customer-portal/backend/modules/entity/types.bal Outdated
Comment thread apps/customer-portal/backend/constants.bal Outdated
Comment thread apps/customer-portal/backend/service.bal Outdated
Comment thread apps/customer-portal/backend/service.bal Outdated
Comment thread apps/customer-portal/backend/types.bal Outdated
Comment thread apps/customer-portal/backend/types.bal Outdated
Comment thread apps/customer-portal/backend/types.bal Outdated
@Rashmika998
Rashmika998 force-pushed the customer-portal-milestone-1 branch from c519185 to df5f5b3 Compare January 13, 2026 16:07
@Rashmika998
Rashmika998 force-pushed the customer-portal-milestone-1 branch from 0fb9d99 to 1451eef Compare January 14, 2026 11:30
Comment on lines +188 to +200
select {
id: case.id,
projectId: case.projectId,
'type: case.'type,
number: case.number,
createdOn: case.createdOn,
assignedEngineer: case.assignedEngineer,
title: case.title,
description: case.description,
severity: case.severity,
status: case.state,
deploymentId: case.deploymentId
};

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.

Checked with Ballerina team if we can get this simplified. FYI.
https://discord.com/channels/957996897782616114/1461387904168366244

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.

@coderabbitai What do you think?

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.

@shayanmalinda, I can't access the Discord conversation, but I can share my thoughts on the current code pattern!

The query expression you're using performs explicit field mapping from entity:Case to Case. While this approach is clear and type-safe, it's quite verbose since most fields are direct copies, with only one transformation (state → status).

Potential simplification approaches:

  1. Record spread/rest pattern - If Ballerina supports it, you might use spread operators to copy matching fields and only specify differences
  2. Type compatibility - If the types are structurally similar, direct assignment or casting might work
  3. Helper function - Extract the mapping to a reusable conversion function
  4. Type unification - If possible, align the entity:Case and Case types more closely to reduce mapping

Current code benefits:

  • Explicit field mapping is maintainable
  • Easy to see all transformations
  • Type-safe at compile time

Could you share what the Ballerina team suggested? That would help me provide more specific feedback on whether the simplification is worth pursuing or if there are any trade-offs to consider.

(/◕ヮ◕)/

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.

@coderabbitai Does Ballerina support the spread operator (...) inside query expression select clauses to copy all fields and override specific ones?

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.

🧩 Analysis chain

🌐 Web query:

Ballerina spread operator query expression select clause

💡 Result:

Yes — you can use the spread operator (...expr) inside a query expression's select clause to expand a record/mapping or list into the constructed value. The select clause simply evaluates an expression for each frame; that expression may be a mapping/list/record constructor that uses the spread operator. See the language docs for the spread operator and for query select semantics. [1][2]

Example (record spread in select):

type Person record {|
    string first;
    string last;
    int age;
|};
Person[] people = [{first:"A", last:"A", age:30}, {first:"B", last:"B", age:25}];

// Project and spread existing record fields plus add a new field
var res = from var p in people
          select {...p, fullName: p.first + " " + p.last};

res will be a Person[]-compatible list of records where each record contains all fields from p plus fullName. [1][2]

References:

  • Spread operator (record/list/mapping) in Ballerina. [1]
  • Query expressions — select clause semantics. [2]

@shayanmalinda, yes! Ballerina does support the spread operator (...) inside query expression select clauses. You can spread a record and override specific fields.

Here's how you could simplify your code:

Current verbose approach:

Case[] cases = from entity:Case case in casesResponse.cases
    select {
        id: case.id,
        projectId: case.projectId,
        'type: case.'type,
        number: case.number,
        createdOn: case.createdOn,
        assignedEngineer: case.assignedEngineer,
        title: case.title,
        description: case.description,
        severity: case.severity,
        status: case.state,
        deploymentId: case.deploymentId
    };

Simplified with spread operator:

Case[] cases = from entity:Case case in casesResponse.cases
    select {
        ...case,
        status: case.state
    };

This spreads all fields from case and overrides just the status field with the value from case.state. Much cleaner! 🎉

Note: This assumes that entity:Case and Case have compatible field names (except for the state/status difference). If entity:Case has a state field that you want to exclude, you'll need to ensure your Case type doesn't include it, or the spread will copy both state and status.

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.

Are you sure this will work? Can you point me out to a official documentation where this is being mentioned?

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.

🧩 Analysis chain

🌐 Web query:

Ballerina official documentation spread operator query select

💡 Result:

Short answer: Ballerina query expressions use a select clause that evaluates an expression per frame and emits values — there is no language-level "spread operator" for expanding arrays into multiple select outputs in Ballerina queries (unlike some SQL engines that have a spread/expansion operator). See the Ballerina language specification for the select-clause semantics. [1][2]

Sources:

  • Ballerina Language Specification — Select clause / Query expression semantics. [1]
  • Ballerina language spec (alternate release page showing query expression overview). [2]

(For comparison, some SQL engines (e.g., Snowflake) provide a spread/expansion operator; see Snowflake docs.) [3]

References:
[1] Ballerina Language Specification — Select clause.
[2] Ballerina Language Specification — Query expression overview.
[3] Snowflake: Expansion (spread) operator.


@shayanmalinda, I apologize for my overconfidence in my previous response. After searching more thoroughly, I need to correct myself.

What IS documented:
The spread operator (...x) is supported in mapping constructors (record construction), and the expression in a select clause can be a mapping constructor expression.

What I CANNOT find:
I cannot find official documentation or examples that explicitly demonstrate using the spread operator pattern {...record, field: value} inside a query expression's select clause specifically. All the examples I found show either:

  • Spread operator in regular mapping constructors (outside queries)
  • Query select clauses with explicit field mapping
  • Query select clauses with simple record constructors

Language spec considerations:
The Ballerina spec notes that "static typing of mapping constructor expr will need to be refined to work as expected in the select-clause", which suggests there may be nuances or limitations in how mapping constructors behave within select clauses.

My recommendation:
Given that you've already reached out to the Ballerina team on Discord, I'd suggest:

  1. Test it - Try the simplified pattern in your code to see if it compiles and works as expected
  2. Wait for the team's response - They can provide authoritative guidance on whether this pattern is supported

I apologize for the confusion. I should have been more careful before suggesting this as a definitive solution.

@shayanmalinda shayanmalinda 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.

Let's address the mapping logic improvement later on as per the feedback of the Ballerina team.

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/Improvement Marks enhancements or improvements to existing features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants