feat(customer-portal): add change request and call request modules - #1314
Conversation
Adds 9 more endpoints to backend-v2 (35 total), both ServiceNow-only:
- Change requests: POST /change-requests, POST /change-requests/search,
GET /change-requests/{id}, PATCH /change-requests/{id},
GET /change-requests/{id}/approvals,
POST /change-requests/{id}/approvals/decision.
- Call requests: POST /call-requests, POST /call-requests/search,
PATCH /call-requests/{id}.
Both create/update endpoints use restricted portal request DTOs,
continuing the pattern from case updates:
- ChangeRequestCreateRequest excludes groupId/assignedEngineerId
(support team/engineer assignment), requestedById (an arbitrary
"on behalf of" WSO2 user id), and workNote (internal annotation).
- ChangeRequestUpdateRequest excludes case/project/deployment relinking,
assignedEngineerId/assignedTeamId, and state — state transitions go
through the dedicated isCustomerApproved/isCustomerReviewed/
requestApproval fields instead, which are the customer's own approval
actions and are kept.
- CallRequestUpdateRequest excludes meetingDate/assignee/notes/plan/
attendees/actionItems/actualDurationMin — entity-service's own doc
comment labels these "agent-side fields, set when an engineer
schedules or concludes the call." Still exposed on the read side
(CallRequestSummary) so the customer can see the outcome.
PATCH /deployed-products/{id}'s deploymentId field is the deliberate
counter-example already in this backend: it looks similar (an id
referencing another resource) but isn't restricted, since
entity-service documents it as an IDOR-style scope guard, not a
relinking field — CLAUDE.md now calls this distinction out explicitly
so it isn't misapplied by pattern-matching on field shape alone.
PATCH /cases/{id} requires exactly one primary field (entity-service's
own doc comment says so); PATCH /change-requests/{id} requires at least
one (its own doc comment says that instead) — CLAUDE.md now flags that
these validation rules are per-entity, not a shared convention to copy
blindly.
Also updates openapi.yaml (9 new paths, ~24 new schemas), README.md,
and CLAUDE.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 50 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughBackend-v2 now supports nine authenticated change-request and call-request routes. The change includes typed entity models, portal DTO mappings, validation, handlers, route registration, OpenAPI schemas, and documentation. ChangesCustomer request API integration
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant ChangeRequestHandler
participant EntityClient
participant ServiceNow
Client->>ChangeRequestHandler: Send change-request operation
ChangeRequestHandler->>EntityClient: Validate and delegate request
EntityClient->>ServiceNow: Send typed HTTP request
ServiceNow-->>EntityClient: Return typed response
EntityClient-->>ChangeRequestHandler: Return entity result
ChangeRequestHandler-->>Client: Return mapped portal response
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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 |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/customer-portal/backend-v2/internal/handler/change_requests.go (1)
30-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding handler tests for the new endpoints.
The local interface makes the handler easy to fake. Table-driven tests for the 401 path, the UUID guard, the "at least one field" guard, the decision-value guard, and the upstream-error mapping would lock in the validation cardinality described in
CLAUDE.md. The same gap exists ininternal/handler/call_requests.go.🤖 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/handler/change_requests.go` around lines 30 - 52, The new change-request endpoints lack handler coverage for validation and error behavior. Add table-driven tests using a fake entityChangeRequestClient to cover the 401 path, UUID validation, at-least-one-field validation, decision-value validation, and upstream-error mapping; add equivalent coverage for the corresponding handlers in call_requests.go, following the cardinality requirements in CLAUDE.md.
🤖 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/entity/types.go`:
- Around line 969-984: The SearchChangeRequestsFilters fields ClosedStartDate
and ClosedEndDate currently decode directly as time.Time and reject non-RFC3339
client values. Change these fields to string-compatible optional representations
that preserve absent, null, and provided-value states, while keeping
SearchChangeRequestsRequest decoding successful for client-supplied date
strings.
In `@apps/customer-portal/backend-v2/internal/handler/call_requests.go`:
- Around line 64-70: The call-request handlers must enforce the required OpenAPI
body fields before invoking the entity service. In CreateCallRequest, validate
caseId with uuidRe, require a non-empty reason and utcTimes, and require
durationInMinutes to be positive; in SearchCallRequests, validate caseId with
uuidRe before calling the service. Reject invalid payloads using the existing
bad-request response pattern.
---
Nitpick comments:
In `@apps/customer-portal/backend-v2/internal/handler/change_requests.go`:
- Around line 30-52: The new change-request endpoints lack handler coverage for
validation and error behavior. Add table-driven tests using a fake
entityChangeRequestClient to cover the 401 path, UUID validation,
at-least-one-field validation, decision-value validation, and upstream-error
mapping; add equivalent coverage for the corresponding handlers in
call_requests.go, following the cardinality requirements in CLAUDE.md.
🪄 Autofix (Beta)
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: a733a3e9-2584-4034-94e0-75fe5e57bc30
📒 Files selected for processing (11)
apps/customer-portal/backend-v2/CLAUDE.mdapps/customer-portal/backend-v2/README.mdapps/customer-portal/backend-v2/cmd/server/main.goapps/customer-portal/backend-v2/internal/dto/call_request.goapps/customer-portal/backend-v2/internal/dto/change_request.goapps/customer-portal/backend-v2/internal/entity/call_requests.goapps/customer-portal/backend-v2/internal/entity/change_requests.goapps/customer-portal/backend-v2/internal/entity/types.goapps/customer-portal/backend-v2/internal/handler/call_requests.goapps/customer-portal/backend-v2/internal/handler/change_requests.goapps/customer-portal/backend-v2/openapi.yaml
…ation Address CodeRabbit findings on PR wso2-open-operations#1314: - SearchChangeRequestsFilters.ClosedStartDate/ClosedEndDate were *time.Time, causing json.Unmarshal to reject non-RFC3339 client values before reaching entity-service; changed to *string per this file's established convention for filter/date fields. - CreateCallRequest and SearchCallRequests didn't validate required body fields (caseId UUID, reason, utcTimes, durationInMinutes), unlike the change-request handlers which already guard Subject/Decision. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
9a76e25
into
wso2-open-operations:dev-app-csm-portal
Summary
Adds 9 more endpoints to
apps/customer-portal/backend-v2(35 total), both ServiceNow-only:POST /change-requests,POST /change-requests/search,GET /change-requests/{id},PATCH /change-requests/{id},GET /change-requests/{id}/approvals,POST /change-requests/{id}/approvals/decision.POST /call-requests,POST /call-requests/search,PATCH /call-requests/{id}.Both create/update endpoints use restricted portal request DTOs, continuing the case-update pattern:
ChangeRequestCreateRequestexcludesgroupId/assignedEngineerId(support assignment),requestedById(an arbitrary "on behalf of" WSO2 user id), andworkNote(internal annotation).ChangeRequestUpdateRequestexcludes case/project/deployment relinking andassignedEngineerId/assignedTeamId, plusstateitself — state transitions go throughisCustomerApproved/isCustomerReviewed/requestApprovalinstead, which are kept since they're the customer's own approval actions.CallRequestUpdateRequestexcludesmeetingDate/assignee/notes/plan/attendees/actionItems/actualDurationMin— entity-service's own doc comment calls these "agent-side fields, set when an engineer schedules or concludes the call." Still exposed on the read side so the customer can see the outcome.Two design notes now called out explicitly in CLAUDE.md so they don't get misapplied later:
PATCH /deployed-products/{id}'sdeploymentIdfield looks similar to the excluded relinking fields above but isn't restricted — entity-service documents it as an IDOR-style scope guard the caller supplies voluntarily, not a relinking mechanism. Read the entity-service doc comment before restricting a field, don't pattern-match on field shape alone.PATCH /cases/{id}requires exactly one primary field;PATCH /change-requests/{id}requires at least one — both per entity-service's own doc comments, which differ. Verified in testing below that both validation rules are enforced correctly and independently.Also updates
openapi.yaml(9 new paths, ~24 new schemas),README.md, andCLAUDE.md.Test plan
go build ./...,go vet ./...,gofmt -l .all cleangosec -fmt=text ./...reports 0 issuesopenapi.yamlvalidated as well-formed YAML with all 9 new paths/schemas presentLinked issues
Closes wso2-enterprise/wso2-digital-team-project-management#863
Closes wso2-enterprise/wso2-digital-team-project-management#864
Closes wso2-enterprise/wso2-digital-team-project-management#865
Closes wso2-enterprise/wso2-digital-team-project-management#866
Closes wso2-enterprise/wso2-digital-team-project-management#867
Closes wso2-enterprise/wso2-digital-team-project-management#868
Closes wso2-enterprise/wso2-digital-team-project-management#869
Closes wso2-enterprise/wso2-digital-team-project-management#870
Closes wso2-enterprise/wso2-digital-team-project-management#871
🤖 Generated with Claude Code
Summary by CodeRabbit