Skip to content

Fix Phase 3 + Phase 4 create payload shapes to match backend schemas - #12

Closed
KDwevedi wants to merge 9 commits into
ChakshuGautam:feat/web-configuratorfrom
theflywheel:fix/onboarding-payload-shapes
Closed

Fix Phase 3 + Phase 4 create payload shapes to match backend schemas#12
KDwevedi wants to merge 9 commits into
ChakshuGautam:feat/web-configuratorfrom
theflywheel:fix/onboarding-payload-shapes

Conversation

@KDwevedi

Copy link
Copy Markdown
Collaborator

Summary

Walked the configurator onboarding flow end-to-end against a live naipepea backend on 2026-04-21. Phase 1 (Tenant) and Phase 2 (Boundaries) worked. Phase 3 (Departments / Designations / Complaint Types) and Phase 4 (Employees) were broken — the FE was sending payloads that the backend rejected.

All four bugs are FE-only. The backend schemas are the source of truth; the FE just needs to match them.

Fixes (4 commits, one per bug)

Commit Issue What
a7782a17 #1 RAINMAKER_PGR.ServiceDefsRAINMAKER-PGR.ServiceDefs (1-line config)
11004e05 #2 Designation payload: add required description, change department to string[]
36213af3 #3 ServiceDefs payload: rename serviceNamename, add required keywords
dd309bda #4 Employee payload: populate user.dob (HRMS Java @NotNull)

Each commit is self-contained and reviewable in under 5 minutes.

Reproduction (before this PR)

# Phase 3 Designation:
POST /mdms-v2/v2/_create/common-masters.Designation
→ {"Errors":[
    {"code":"INVALID_REQUEST_TYPE1","message":"expected type: JSONArray, found: String"},
    {"code":"INVALID_REQUEST_REQUIRED2","message":"required key [description] not found"}
  ]}

# Phase 3 ComplaintType (after fixing the schema-code typo):
POST /mdms-v2/v2/_create/RAINMAKER-PGR.ServiceDefs
→ {"Errors":[
    {"code":"INVALID_REQUEST_REQUIRED2","message":"required key [keywords] not found"},
    {"code":"INVALID_REQUEST_REQUIRED1","message":"required key [name] not found"},
    {"code":"INVALID_REQUEST_ADDITIONALPROPERTIES3","message":"extraneous key [serviceName] is not permitted"}
  ]}

# Phase 4 Employee:
POST /egov-hrms/employees/_create
→ {"Errors":[{"code":"NotNull.employeeRequest.employees[0].user.dob","message":"must not be null"}]}

Verification

Will re-walk the full onboarding flow with a disposable tenant (ke.bananaland-<timestamp>) against naipepea after merge to confirm all four phases complete end-to-end. Dummy data cleanup via the same SQL pattern used in the pre-PR verification (available on request).

Test plan

  • Phase 1 (Tenant) — unaffected, re-verify passes
  • Phase 2 (Boundaries) — unaffected, re-verify passes
  • Phase 3 upload with an Excel sheet containing Department + Designation + ComplaintType rows → creates succeed
  • Phase 3 Designation row with no description column → falls back to name (backwards compat)
  • Phase 3 ComplaintType row with no keywords column → auto-generated from name.toLowerCase().split(/\s+/).join(',')
  • Phase 3 ComplaintType row with legacy serviceName column header → parser falls back, still works
  • Phase 4 upload with Employee rows (no DOB column) → uses 1990-01-01 default, HRMS accepts
  • Phase 4 with explicit dob column → parsed and threaded through

Follow-ups (out of scope here)

  • Schema-driven payload construction (proper fix): drive mdmsService.create* off the live MDMS schema definition via /mdms-v2/schema/v1/_search instead of hand-written field lists. Design in Nai Pepea/issues/FIX-PLAN.md (Layer B). Would have caught all three of Add local-setup: Docker Compose dev environment #1-feat: add Keycloak auth adapter for Google SSO #3 at FE-build time.
  • Surface DOB in the UI as a proper employee form field or a required Excel column, instead of defaulting to 1990.
  • generateUsername() in hrmsService is effectively dead code — HRMS overrides userName with employee.code on create. Worth a docstring note or removal.

Closes #1, closes #2, closes #3, closes #4.

KDwevedi and others added 4 commits April 21, 2026 12:14
Backend schema is registered as RAINMAKER-PGR.ServiceDefs (dash).
Verified on naipepea, bomet — no underscore variant exists.

Fixes #1

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…yload

common-masters.Designation requires description and expects
department as string[]. Configurator was sending neither — creation
returned INVALID_REQUEST_TYPE1 and INVALID_REQUEST_REQUIRED2.

- Designation / DesignationExcelRow: add description, change
  department to string[] to match schema
- createDesignation: pass description through
- parseDesignationExcel: accept description column (fallback to
  name), split department on commas to allow multi-department
  assignments

Fixes #2

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
RAINMAKER-PGR.ServiceDefs schema requires `name` (not `serviceName`)
and `keywords`. Configurator was sending `serviceName` (rejected as
extraneous) and no `keywords` — creation returned
INVALID_REQUEST_ADDITIONALPROPERTIES3 and REQUIRED1/2 errors.

- ComplaintType / ComplaintTypeExcelRow: rename serviceName→name, add keywords
- createComplaintType / getComplaintTypes: swap field names in payloads
- parseComplaintTypeExcel: accept name column (fallback to legacy
  serviceName alias for existing templates), accept keywords column
  (default to name.toLowerCase() comma-split)
- Phase3Page preview + progress list: use type.name
- localization service: rename serviceName param to name for consistency

Fixes #3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HRMS service rejects any _create payload without user.dob with
NotNull.employeeRequest.employees[0].user.dob. Configurator's
buildEmployee omitted it entirely, so every Phase 4 employee import
failed on the first row.

- EmployeeExcelRow: add optional dob column
- buildEmployee: accept dob input; default to 1990-01-01 UTC when
  neither form nor sheet provided one, with a comment explaining why
- parseEmployeeExcel: accept dob/DOB/dateOfBirth columns
- Phase4Page: thread dob from Excel row into buildEmployee

Future cleanup: surface dob as a proper form field / optional-per-employee
in the Excel template generator.

Fixes #4

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee8934e3-915a-4b63-bcdb-a8a1f55d95ad

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ 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 and usage tips.

tenant.tenants schema requires `tenantId` in the `data` object (in
addition to the MDMS wrapper's tenantId). It stores the parent/root
tenant the city lives under — for `ke.testzone` that's `ke`.

Configurator was omitting it, so every Phase 1 upload returned:
  {"code":"INVALID_REQUEST_REQUIRED1","message":"required key [tenantId] not found"}

Set tenantId = stateTenantId (the session tenant, which is the root).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@KDwevedi

Copy link
Copy Markdown
Collaborator Author

Adding a 5th fix: createTenant also omits the required tenantId field inside the data payload. Surfaced during a self-walk of the configurator UI (my initial walk used hand-built curl with tenantId already in it, so Phase 1 looked fine).

Backend response pre-fix:

{"Errors":[{"code":"INVALID_REQUEST_REQUIRED1","message":"required key [tenantId] not found"}]}

Commit f6fbe39a adds tenantId: stateTenantId to the tenantData object. Closes #5.

Rebuilt + redeployed on naipepea — new bundle index-DNbpYGcp.js. Re-verified Phase 1 via the UI (with the test assets in Nai Pepea/onboarding-test-assets/) works now.

/boundary/_search returns boundary *entities* by code and doesn't walk the
hierarchy. Phase 4 called it expecting a full tree and got 0 results even
though boundaries were present.

The correct endpoint is /boundary-relationships/_search with query params
(tenantId, hierarchyType, includeChildren=true). Swap to it.

Side effects:
- flattenBoundaries: dedupe by code because the relationships endpoint
  returns each child twice under its parent (known backend quirk)
- carry hierarchyType down from the TenantBoundary wrapper into each
  flattened boundary, since the children don't always have it set

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@KDwevedi

Copy link
Copy Markdown
Collaborator Author

6th commit added: f3e2a40dsearchBoundaries was calling /boundary-service/boundary/_search which doesn't return the hierarchy tree, so Phase 4 reported 0 boundaries even when they existed. Swapped to /boundary-service/boundary-relationships/_search with query-string params. Closes #6.

Verified on naipepea: post-fix bundle index-BqA9OCiL.js now loads all 4 test boundaries into Phase 4's jurisdiction picker.

KDwevedi and others added 3 commits April 21, 2026 14:23
The previous fix (11004e0) updated parseDesignationExcel + service +
types to include description, but Phase3Page was still mapping the
parsed row to a subset {code, name, department, active} — stripping
description before handing to createDesignations. Result: designation
creates kept silently 4xx'ing with "required key [description] not
found" even on the latest bundle.

Adding description to the shape sent into createDesignations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The boundary-service sometimes returns "already exists" / "DUPLICATE"
errors for rows that never actually persisted (stale cache between the
boundary-service and the eventually-consistent Kafka persister). The
current FE catches any error string containing "already exists" and
returns true, which makes Phase 2 silently claim success while leaving
nothing in the DB — Phase 4 then reports "Boundaries: 0 loaded" on a
tree the user thought they just built.

Swap the blanket swallow for verify-then-swallow: on "already exists"
errors, search for the record. If found, swallow (idempotent re-run is
fine). If not, throw a clearer error so the UI can surface the real
problem.

Same treatment for createBoundaryEntity and createBoundaryRelationship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2 never fired /boundary-relationships/_create calls in the most
recent live walk — root cause is createHierarchy casting the backend
response to a single BoundaryHierarchy when it's actually an array.
selectedHierarchy.hierarchyType then came out undefined, and
createBoundary's `if (boundary.hierarchyType && boundary.boundaryType)`
guard skipped the relationship call for all 4 boundaries. Unwrap the
array before returning.

Phase 3 is still silently 400'ing "required key [description] not found"
even with the f897c97 fix in place. The bundle has the right code path,
but the live request somehow lacks the field. Add a console.log of the
payload handed to createDesignations so the next failed walk surfaces
exactly what the browser is sending — will remove once diagnosed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@KDwevedi

Copy link
Copy Markdown
Collaborator Author

Superseded by work targeting the extracted ChakshuGautam/digit-configurator repo. The configurator moved out of the CCRS monorepo today — porting these fixes there instead. See Nai Pepea/issues/FIX-PLAN.md for the underlying 9 issues (#1-#6 filed on theflywheel fork; #7-#9 uncovered during live walk on 2026-04-21). Branch theflywheel/fix/onboarding-payload-shapes preserved for the diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant