Conversation
…nd problem creation Adds a request-approval action to the change request patch flow (with the resulting legal next states surfaced on the detail response) and a new create endpoint for problems, matching the existing passthrough conventions in this service. Both are pure forwarding with no added business logic; all validation remains in the backing data source.
…em creation Extends the change request patch endpoint to forward the request-approval action and the resulting legal next states, and adds a new POST /problems endpoint mirroring the existing problem read handlers' auth pattern (no per-record access check, since problems aren't project-scoped). Documents both in openapi.yaml, including the previously undocumented customer/review approval flags on the same patch schema.
…reation flow Adds a data-driven "Request approval" button on the change request detail page, rendered only when the backend's legal-next-states list includes that transition (mirrors CaseActionBar's pattern — no hardcoded from-state check). Adds a full problem creation flow: a create page, a "New problem" entry point on the problems tab, and the supporting API hook/types, matching the existing change request/incident create flows. No priority field on the create form since it isn't settable on create.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughThe PR adds ServiceNow problem creation across the entity service, portal backend, API contract, and webapp. It enriches problem search results and adds async selectors. Change requests now expose legal transitions and support a Request approval action. ChangesProblem lifecycle
Change-request approval
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: Sequence Diagram(s)sequenceDiagram
participant CreateProblemPage
participant PortalBackend
participant EntityService
participant ServiceNow
CreateProblemPage->>PortalBackend: POST /problems
PortalBackend->>EntityService: Forward problem payload
EntityService->>ServiceNow: Create problem
ServiceNow-->>EntityService: ProblemDetail
EntityService-->>PortalBackend: ProblemDetail
PortalBackend-->>CreateProblemPage: 201 Created
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8)apps/csm-portal/backend/openapi.yamlTraceback (most recent call last): 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" 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 |
The problem search response now includes state, assignment group, and assigned-to alongside id/number/subject (pure passthrough from the upstream data source, now that it returns these fields too). Plumb the extra fields through the entity-service domain type and into the problems table, which gains State/Assignment group/Assigned to columns following the same chip/em-dash conventions the incidents list already uses.
Category/Subcategory were plain text inputs even though they're a fixed, dependent choice list; Origin case and Primary incident were raw UUID text fields with no way to find the right record. Replace them: Category/Subcategory become a dependent pair of Selects, and Origin case/Primary incident become type-ahead AsyncEntitySelect pickers backed by two new (query, enabled) search hooks for cases and incidents, following the same pattern already used on the change request create form.
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
CreateProblem was unmarshaling the create endpoint's wrapped
{message, problem} response directly into the flat problem-detail
struct, so fields like id came back empty and the post-create
redirect failed. Unwrap the envelope first, mirroring the existing
pattern already used for change request creation.
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
entity-service/internal/service/sn_change_request_service.go (1)
645-653: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMissing validation:
requestApprovaldocumented as mutually exclusive withisCustomerApproved/isCustomerReviewed, but nothing enforces it.The OpenAPI contract states
requestApprovalis "Mutually exclusive with isCustomerApproved and isCustomerReviewed," butPatchChangeRequestonly checks that at least one field is set — it never rejects a request that setsRequestApprovalalongsideIsCustomerApproved/IsCustomerReviewed. Such a request would currently be forwarded to ServiceNow unchecked.🛡️ Proposed fix
if req.PlannedEndOn != nil { if _, err := time.Parse(snCreatedOnLayout, *req.PlannedEndOn); err != nil { return domain.PatchChangeRequestResponse{}, &apierror.ValidationError{Msg: "plannedEndOn must follow the format: YYYY-MM-DD HH:mm:ss"} } } + if req.RequestApproval != nil && (req.IsCustomerApproved != nil || req.IsCustomerReviewed != nil) { + return domain.PatchChangeRequestResponse{}, &apierror.ValidationError{Msg: "requestApproval cannot be combined with isCustomerApproved or isCustomerReviewed"} + }As per coding guidelines, "Validate all input before calling the repository and return *apierror.ValidationError for invalid input."
Also applies to: 700-714
🤖 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 `@entity-service/internal/service/sn_change_request_service.go` around lines 645 - 653, The PatchChangeRequest validation must reject requests that set RequestApproval together with IsCustomerApproved or IsCustomerReviewed. Update the validation in PatchChangeRequest, including the corresponding checks around the later validation block, to return an apierror.ValidationError before invoking the repository while preserving valid combinations.Source: Coding guidelines
🧹 Nitpick comments (1)
apps/csm-portal/backend/openapi.yaml (1)
6100-6106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider marking
legalNextStatesread-only for consistency withCase.nextStates.
Case.nextStates(a server-computed transition list) is markedreadOnly: true;legalNextStatesserves the identical purpose for change requests but omits it.🤖 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/csm-portal/backend/openapi.yaml` around lines 6100 - 6106, Update the legalNextStates schema property to include readOnly: true, matching the server-computed Case.nextStates schema while preserving its existing array type, items, and description.
🤖 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/csm-portal/backend/internal/handler/problems.go`:
- Around line 103-108: Update the create handler around the JSON validation
before entity.CreateProblem to decode a required object into the strict
create-request type, reject unknown fields and non-object JSON, require subject,
and validate optional UUID link fields. Return bad-request responses for
malformed JSON, missing subject, and invalid linking IDs, and only forward the
validated payload to CreateProblem.
In `@apps/csm-portal/backend/openapi.yaml`:
- Around line 3490-3505: Enforce mutual exclusivity for isCustomerApproved,
isCustomerReviewed, and requestApproval in the PatchChangeRequest schema and
validation flow, rejecting any PATCH that sets more than one of these fields.
Add the appropriate oneOf/not constraint in openapi.yaml and ensure the
corresponding implementation rejects contradictory combinations before
forwarding the request upstream.
In `@entity-service/internal/service/interfaces.go`:
- Around line 378-381: The CreateProblem documentation in the service interface
incorrectly declares OriginCaseID as required. Reconcile the comment with the
established optional contract in domain.CreateProblemRequest, the OpenAPI
payload, and sn_problem_service.go by documenting only Subject as required; do
not add validation unless the API contract is intentionally being changed.
In `@entity-service/internal/service/sn_problem_service.go`:
- Around line 186-225: Update CreateProblem to validate req.Subject before
constructing or sending the ServiceNow payload, rejecting empty or
whitespace-only values with the package’s existing apierror.ValidationError
pattern used by PatchChangeRequest. Return the validation error immediately and
preserve the existing UUID validation and outbound request flow for valid
subjects.
---
Outside diff comments:
In `@entity-service/internal/service/sn_change_request_service.go`:
- Around line 645-653: The PatchChangeRequest validation must reject requests
that set RequestApproval together with IsCustomerApproved or IsCustomerReviewed.
Update the validation in PatchChangeRequest, including the corresponding checks
around the later validation block, to return an apierror.ValidationError before
invoking the repository while preserving valid combinations.
---
Nitpick comments:
In `@apps/csm-portal/backend/openapi.yaml`:
- Around line 6100-6106: Update the legalNextStates schema property to include
readOnly: true, matching the server-computed Case.nextStates schema while
preserving its existing array type, items, and description.
🪄 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
Run ID: 68e21bc5-0a8b-4ad7-ac6c-0f007e8597e4
📒 Files selected for processing (24)
apps/csm-portal/backend/cmd/server/main.goapps/csm-portal/backend/internal/entity/entity.goapps/csm-portal/backend/internal/handler/change_requests_test.goapps/csm-portal/backend/internal/handler/helpers_test.goapps/csm-portal/backend/internal/handler/problems.goapps/csm-portal/backend/internal/handler/problems_test.goapps/csm-portal/backend/openapi.yamlapps/csm-portal/webapp/src/App.tsxapps/csm-portal/webapp/src/api/backend/types.tsapps/csm-portal/webapp/src/constants/apiConstants.tsapps/csm-portal/webapp/src/features/csm-operations/api/usePostProblem.tsapps/csm-portal/webapp/src/features/csm-operations/api/useSearchCasesForSelect.tsapps/csm-portal/webapp/src/features/csm-operations/api/useSearchIncidentsForSelect.tsapps/csm-portal/webapp/src/features/csm-operations/components/ProblemsTab.tsxapps/csm-portal/webapp/src/features/csm-operations/pages/CreateProblemPage.test.tsxapps/csm-portal/webapp/src/features/csm-operations/pages/CreateProblemPage.tsxapps/csm-portal/webapp/src/features/csm-operations/pages/CsmChangeRequestDetailPage.test.tsxapps/csm-portal/webapp/src/features/csm-operations/pages/CsmChangeRequestDetailPage.tsxentity-service/internal/domain/entity.goentity-service/internal/handler/problem_handler.goentity-service/internal/server/routes.goentity-service/internal/service/interfaces.goentity-service/internal/service/sn_change_request_service.goentity-service/internal/service/sn_problem_service.go
Decode the problem-create request into a strict typed struct (rejecting unknown fields) instead of only checking json.Valid, which let through malformed payloads like null, arrays, and objects with unexpected shape. Require a non-blank subject and validate the optional UUID-formatted linking fields, matching the existing create-incident validation pattern.
The change-request patch handler documented isCustomerApproved, isCustomerReviewed, and requestApproval as mutually exclusive but never rejected a request that set more than one. Add the check to the service layer and encode the same constraint in the OpenAPI schema so it's enforced, not just described.
The interface comment claimed the origin-case link was required alongside the subject, but the domain type, the OpenAPI schema, and the actual implementation all treat it as optional. Doc-only fix, no behavior change.
CreateProblem forwarded the subject straight to the backing data source without checking it was non-blank, unlike sibling validation elsewhere in this service (e.g. change-request title). Reject blank/whitespace-only subjects with a validation error before making the call.
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
Purpose
Change requests had no path for a regular user to move a request out of its initial state — only a raw, unchecked field-level patch existed, and the existing approve/reject actions only appear once a request already reaches a later stage. Separately, problem records could only be searched and viewed — there was no way to create one anywhere in the stack. This PR adds both capabilities, propagated through the entity service, the CSM portal backend, and the webapp.
Goals
Approach
Change request approval action
PatchChangeRequestRequestgainsRequestApproval *bool; the change request detail type gainsLegalNextStates []string. Both are pure passthrough — the data source performs all transition validation.openapi.yamland adding direct handler test coverage for the patch endpoint (which had none before).legalNextStatesincludes"assess"— mirrors the existingCaseActionBarpattern of rendering off a backend-provided list rather than a hardcoded from-state check. Uses the existing patch mutation hook, which already invalidates the detail query on success, so the page updates without a manual reload. Errors surface through the existing error-banner pattern.Problem creation
CreateProblemmethod on the problem service, new request domain type, reusing the existing problem-detail type for the created-record response. Origin-case and primary-incident IDs are converted between the public UUID and the data source's native id the same way every other cross-link in this file is.POST /problemshandler mirroring the existing problem read handlers' auth pattern (401 with no authenticated user, no per-record access check since problems aren't project-scoped), a new entity-service client method, route registration, andopenapi.yamlcoverage including all four standard error responses.User stories
Release note
Added a "Request approval" action for change requests and a problem-creation flow, including entity-service, backend, and webapp support.
Documentation
N/A — internal CS-engineer portal feature, no external product documentation is maintained for this workflow.
Training
N/A — no training content is maintained for this internal portal.
Certification
N/A — no certification exam covers this internal portal.
Marketing
N/A — internal-only feature, not customer facing.
Automation tests
Security checks
go vetandeslintwere run clean insteadSamples
N/A — no sample projects reference this API.
Related PRs
None.
Migrations (if applicable)
N/A — no schema or data migration involved.
Test environment
Verified locally:
go build/go test/go vet(entity service),make build/make test/make vet(CSM portal backend),pnpm build/pnpm test/pnpm lint(webapp).Learning
Followed this codebase's existing conventions throughout: the sibling boolean action-flag fields already on the change request patch type, the existing case-detail action-bar pattern for backend-driven legal-transition buttons, and the existing change-request/incident create-page structure for the new problem create page.
Summary by CodeRabbit
/operations/problems/new.