Skip to content

Adopt old/new event payloads and replace change-sets with extractDelta#837

Merged
nevil-mathew merged 8 commits intodevelopfrom
update-events
Oct 14, 2025
Merged

Adopt old/new event payloads and replace change-sets with extractDelta#837
nevil-mathew merged 8 commits intodevelopfrom
update-events

Conversation

@nevil-mathew
Copy link
Collaborator

@nevil-mathew nevil-mathew commented Oct 6, 2025

Summary by CodeRabbit

  • New Features

    • Update events now include explicit oldValues and newValues for organizations, tenants, and users; related-organization details added conditionally when updated.
    • Organization deactivation events include richer fields and deactivated_users_count.
    • Tenant domain changes and role updates emit structured update events only when deltas exist.
    • Added utilities to compute precise deltas and a new sharded table for registration codes by tenant.
  • Bug Fixes

    • Expanded redaction: organization update events now redact the code field.

@coderabbitai
Copy link

coderabbitai bot commented Oct 6, 2025

Walkthrough

Replaces flat changedValues with oldValues/newValues across event flows; adds utils.extractDelta and flattenLeafPaths; updates DTO signatures; tenant/tenant-query now use raw: true; admin.deactivate eventType/payload changed; adds distributed organization_registration_codes table; adds 'code' to organization.update blacklist; adds broadcaster debug log.

Changes

Cohort / File(s) Summary
Diff utilities & exports
src/generics/utils.js
Added flattenLeafPaths and extractDelta; exported extractDelta to compute deltas based on updateData.
DTOs: event payload signatures
src/dtos/organizationDTO.js, src/dtos/tenantDTO.js, src/dtos/userDTO.js
Replaced changedValues parameter with oldValues/newValues; DTOs now conditionally include oldValues/newValues and removed prior changes construction.
Organization service
src/services/organization.js
Switched to extractDelta, deep-cloned old state, early-return when no changes, conditional fetch of related_orgs details, emit events with oldValues/newValues.
Tenant service & DB query
src/services/tenant.js, src/database/queries/tenants.js
Tenant fetch/update use raw: true; update flows modified to use extractDelta, rename emitter params, and emit oldValues/newValues for update/addDomain/removeDomain.
Admin service (deactivation)
src/services/admin.js
deactivateOrg now emits eventType "deactivate" and expanded payload including id, code, audit fields, tenant_code, and deactivated_users_count.
Org-admin role flow & events
src/services/org-admin.js
updateRoleForApprovedRequest refactored to async, enforces role existence, computes user delta, and emits structured user update events only when changes exist.
Event broadcaster debug log
src/helpers/eventBroadcasterMain.js
Added util.inspect debug logging of requestBody before broadcasting.
Distribution columns
src/distributionColumns.sql
Added distributed table declaration for organization_registration_codes sharded by tenant_code.
Blacklist config
src/constants/blacklistConfig.js
Added 'code' to organization.update blacklist.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant OrgSvc as Organization Service
  participant DB as Database
  participant Utils as Utils.extractDelta
  participant Broadcaster as Event Broadcaster

  Client->>OrgSvc: updateOrganization(bodyData)
  OrgSvc->>DB: fetch orgDetails (before, raw)
  OrgSvc->>DB: update organization
  DB-->>OrgSvc: orgDetailsAfter (raw/plain)
  OrgSvc->>Utils: extractDelta(old=before, new=after, updateData=bodyData)
  Utils-->>OrgSvc: newValues / {}
  alt No changes
    OrgSvc-->>Client: 200 OK (no-op)
  else Changes detected
    note right of OrgSvc: oldValues (deep clone) + newValues\n(optional related_org_details fetched when present)
    OrgSvc->>Broadcaster: broadcast(org.update with oldValues/newValues)
    Broadcaster-->>OrgSvc: ack
    OrgSvc-->>Client: 200 OK (updated)
  end
Loading
sequenceDiagram
  autonumber
  participant Admin
  participant AdminSvc as Admin Service
  participant DB as Database
  participant Broadcaster as Event Broadcaster

  Admin->>AdminSvc: deactivateOrg(orgId)
  AdminSvc->>DB: deactivate org + users
  DB-->>AdminSvc: rowsAffected, orgAfter
  note right of AdminSvc: Build eventType "deactivate"\nPayload: id, code, audit fields, tenant_code,\ndeactivated_users_count
  AdminSvc->>Broadcaster: broadcast(deactivate event)
  Broadcaster-->>AdminSvc: ack
  AdminSvc-->>Admin: 200 OK (deactivated_users count)
Loading
sequenceDiagram
  autonumber
  participant Client
  participant TenantSvc as Tenant Service
  participant DB as Database
  participant Utils as Utils.extractDelta
  participant Broadcaster as Event Broadcaster

  Client->>TenantSvc: updateTenant(bodyData)
  TenantSvc->>DB: findOne(tenant, raw: true)
  DB-->>TenantSvc: tenantBefore
  TenantSvc->>DB: update tenant (bodyData)
  DB-->>TenantSvc: tenantAfter (raw)
  TenantSvc->>Utils: extractDelta(tenantBefore, tenantAfter, bodyData)
  Utils-->>TenantSvc: newValues / {}
  alt No changes
    TenantSvc-->>Client: 200 OK (no-op)
  else Changes detected
    note right of TenantSvc: event includes oldValues (deep clone) and newValues
    TenantSvc->>Broadcaster: broadcast(tenant.update)
    Broadcaster-->>TenantSvc: ack
    TenantSvc-->>Client: 200 OK
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

I nibble leaves of old and new,
I map each path and chase the clue.
Events hop out with tidy tracks,
Blacklisted bits tucked in my sacks.
Hooray for deltas, small and true 🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and concisely summarizes the primary change of migrating event payloads to use old/new value structures and integrating the extractDelta utility instead of the previous change-set approach, which aligns with the extensive updates in DTOs and services. It focuses on the main functional shift without unnecessary detail.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch update-events

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 changed the title @coderabbitai Adopt old/new event payloads and replace change-sets with extractDelta Oct 6, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd08237 and ada71ae.

📒 Files selected for processing (9)
  • src/constants/blacklistConfig.js (1 hunks)
  • src/database/queries/tenants.js (1 hunks)
  • src/distributionColumns.sql (1 hunks)
  • src/dtos/organizationDTO.js (1 hunks)
  • src/generics/utils.js (2 hunks)
  • src/helpers/eventBroadcasterMain.js (2 hunks)
  • src/services/admin.js (1 hunks)
  • src/services/organization.js (1 hunks)
  • src/services/tenant.js (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/services/**

⚙️ CodeRabbit configuration file

This is core business logic. Please check for correctness, efficiency, and potential edge cases.

Files:

  • src/services/organization.js
  • src/services/admin.js
  • src/services/tenant.js
src/database/queries/**

⚙️ CodeRabbit configuration file

Review database queries for performance. Check for N+1 problems and ensure indexes can be used.

Files:

  • src/database/queries/tenants.js
🧠 Learnings (6)
📚 Learning: 2025-09-12T10:40:34.860Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/services/organization.js:831-0
Timestamp: 2025-09-12T10:40:34.860Z
Learning: In the ELEVATE-Project/user codebase, the organizationDTO.eventBodyDTO is designed to handle empty changes arrays properly, so organization update events should always be emitted even when changedValues is empty. The DTO handles this scenario correctly and there may be other reasons to emit events beyond just field changes (like metadata updates).

Applied to files:

  • src/services/organization.js
  • src/dtos/organizationDTO.js
📚 Learning: 2025-09-12T11:02:51.008Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/dtos/organizationDTO.js:14-43
Timestamp: 2025-09-12T11:02:51.008Z
Learning: In the ELEVATE-Project/user codebase, oldValue and newValue in the changedValues array for organizationDTO.eventBodyDTO are guaranteed to not be undefined by the business logic, and filtering out falsy values (0, false, '') from changes is the intended behavior.

Applied to files:

  • src/services/organization.js
  • src/dtos/organizationDTO.js
📚 Learning: 2025-09-12T11:02:51.008Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/dtos/organizationDTO.js:14-43
Timestamp: 2025-09-12T11:02:51.008Z
Learning: In the ELEVATE-Project/user codebase, the changedValues parameter in organizationDTO.eventBodyDTO is guaranteed to always be an array by the calling code, so additional Array.isArray validation is not needed.

Applied to files:

  • src/dtos/organizationDTO.js
📚 Learning: 2025-09-12T10:36:43.529Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/dtos/organizationDTO.js:26-29
Timestamp: 2025-09-12T10:36:43.529Z
Learning: In the ELEVATE-Project/user codebase, the changedValues array passed to organizationDTO.eventBodyDTO and tenantDTO.eventBodyDTO always contains a fieldName property when oldValue or newValue are present, so additional fieldName validation is not needed according to the business logic.

Applied to files:

  • src/dtos/organizationDTO.js
📚 Learning: 2025-09-12T10:35:28.285Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/services/admin.js:704-704
Timestamp: 2025-09-12T10:35:28.285Z
Learning: In ELEVATE-Project/user admin.js, there's an inconsistency in organizationQueries.update usage: addOrgAdmin calls it without options (returns number), while deactivateOrg calls it with { returning: true, raw: true } (returns object). The validation logic 'if (orgRowsAffected === 0)' only works for the first case - the second case needs 'if (orgRowsAffected.rowsAffected === 0)' to properly validate updates.

Applied to files:

  • src/services/admin.js
📚 Learning: 2025-09-12T10:35:28.285Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/services/admin.js:704-704
Timestamp: 2025-09-12T10:35:28.285Z
Learning: In the ELEVATE-Project/user codebase, when organizationQueries.update is called with { returning: true, raw: true }, it returns an object { rowsAffected, updatedRows }, not just a number. The validation logic in admin.js deactivateOrg method checking 'if (orgRowsAffected === 0)' is incorrect and should be 'if (orgRowsAffected.rowsAffected === 0)' to properly validate successful updates.

Applied to files:

  • src/services/admin.js
🧬 Code graph analysis (6)
src/services/organization.js (4)
src/services/tenant.js (7)
  • newValues (854-854)
  • utils (29-29)
  • oldValues (860-860)
  • _ (30-30)
  • eventBodyData (545-562)
  • eventBodyData (678-695)
  • eventBodyData (862-870)
src/services/admin.js (6)
  • utils (17-17)
  • updatedOrgDetails (724-724)
  • _ (10-10)
  • organizationQueries (20-20)
  • eventBodyData (726-742)
  • organizationDTO (43-43)
src/services/user.js (4)
  • utils (12-12)
  • oldValues (164-165)
  • _ (18-18)
  • organizationQueries (16-16)
src/generics/utils.js (1)
  • _ (23-23)
src/generics/utils.js (1)
src/services/user.js (1)
  • _ (18-18)
src/dtos/organizationDTO.js (5)
src/migrations/pushDataToKafka/pushUserDataToKafka.js (1)
  • eventType (182-182)
src/dtos/eventBody.js (1)
  • disallowedArgs (8-8)
src/helpers/userInvite.js (1)
  • args (1133-1147)
src/services/tenant.js (2)
  • oldValues (860-860)
  • newValues (854-854)
src/services/organization.js (2)
  • oldValues (839-839)
  • newValues (833-833)
src/helpers/eventBroadcasterMain.js (5)
src/services/tenant.js (2)
  • require (32-32)
  • require (33-33)
src/services/admin.js (5)
  • require (11-11)
  • require (27-27)
  • require (34-34)
  • require (36-36)
  • require (37-37)
src/services/organization.js (4)
  • require (12-12)
  • require (14-14)
  • require (15-15)
  • require (18-18)
src/helpers/userInvite.js (6)
  • require (18-18)
  • require (23-23)
  • require (27-27)
  • require (28-28)
  • require (29-29)
  • requestBody (969-973)
src/services/userInvite.js (1)
  • requestBody (379-383)
src/services/admin.js (1)
src/services/organization.js (5)
  • eventBodyData (151-169)
  • eventBodyData (874-894)
  • organizationDTO (19-19)
  • common (2-2)
  • tenantCode (281-281)
src/services/tenant.js (2)
src/helpers/userInvite.js (5)
  • tenantDetails (510-510)
  • tenantQueries (34-34)
  • utils (3-3)
  • oldValues (842-844)
  • _ (2-2)
src/services/organization.js (6)
  • newValues (833-833)
  • utils (5-5)
  • oldValues (839-839)
  • _ (13-13)
  • eventBodyData (151-169)
  • eventBodyData (874-894)
🔇 Additional comments (3)
src/services/tenant.js (3)

435-442: LGTM! Consistent with codebase patterns.

Using raw: true aligns with similar queries in the codebase (e.g., src/helpers/userInvite.js:509) and is appropriate when model instance methods aren't needed.


545-563: LGTM! Domain event payload structure is clear.

The use of singular oldValue and newValue (vs. oldValues/newValues in the main update) appropriately distinguishes domain-specific events from general field updates. The logic correctly captures the before/after state of the domains array.


678-696: LGTM! Consistent with addDomain event structure.

The event payload correctly tracks the domain removal using oldValue/newValue fields, maintaining consistency with the addDomain event pattern.

…leForApprovedRequest to broadcast user update events
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/services/org-admin.js (1)

661-671: Document the asymmetry between oldValues and newValues parameters.

The current implementation passes the entire old user object as oldValues but only the delta (changed fields) as newValues. While this pattern appears intentional based on similar usage in src/services/organization.js, the parameter names suggest symmetry that doesn't exist.

Consider one of the following:

  1. Rename parameters to better reflect their content (e.g., oldSnapshot and changedFields)
  2. Extract only the relevant old values to match the changed fields in newValues
  3. Add a comment explaining the intentional asymmetry

Based on learnings about similar DTOs accepting full objects with guaranteed defined values.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65b4262 and c4cde5b.

📒 Files selected for processing (3)
  • src/dtos/userDTO.js (2 hunks)
  • src/generics/utils.js (2 hunks)
  • src/services/org-admin.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/generics/utils.js
🧰 Additional context used
📓 Path-based instructions (1)
src/services/**

⚙️ CodeRabbit configuration file

This is core business logic. Please check for correctness, efficiency, and potential edge cases.

Files:

  • src/services/org-admin.js
🧠 Learnings (4)
📓 Common learnings
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/services/organization.js:831-0
Timestamp: 2025-09-12T10:40:34.860Z
Learning: In the ELEVATE-Project/user codebase, the organizationDTO.eventBodyDTO is designed to handle empty changes arrays properly, so organization update events should always be emitted even when changedValues is empty. The DTO handles this scenario correctly and there may be other reasons to emit events beyond just field changes (like metadata updates).
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/dtos/organizationDTO.js:14-43
Timestamp: 2025-09-12T11:02:51.008Z
Learning: In the ELEVATE-Project/user codebase, oldValue and newValue in the changedValues array for organizationDTO.eventBodyDTO are guaranteed to not be undefined by the business logic, and filtering out falsy values (0, false, '') from changes is the intended behavior.
📚 Learning: 2025-09-12T11:02:51.008Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/dtos/organizationDTO.js:14-43
Timestamp: 2025-09-12T11:02:51.008Z
Learning: In the ELEVATE-Project/user codebase, oldValue and newValue in the changedValues array for organizationDTO.eventBodyDTO are guaranteed to not be undefined by the business logic, and filtering out falsy values (0, false, '') from changes is the intended behavior.

Applied to files:

  • src/dtos/userDTO.js
📚 Learning: 2025-09-12T10:40:34.860Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/services/organization.js:831-0
Timestamp: 2025-09-12T10:40:34.860Z
Learning: In the ELEVATE-Project/user codebase, the organizationDTO.eventBodyDTO is designed to handle empty changes arrays properly, so organization update events should always be emitted even when changedValues is empty. The DTO handles this scenario correctly and there may be other reasons to emit events beyond just field changes (like metadata updates).

Applied to files:

  • src/dtos/userDTO.js
📚 Learning: 2025-09-12T11:03:00.543Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/dtos/tenantDTO.js:23-0
Timestamp: 2025-09-12T11:03:00.543Z
Learning: In the ELEVATE-Project/user codebase, the oldValue and newValue properties in changedValues objects passed to tenantDTO.eventBodyDTO are guaranteed to be defined when present, so undefined checks are not necessary according to the data contracts.

Applied to files:

  • src/dtos/userDTO.js
🧬 Code graph analysis (2)
src/dtos/userDTO.js (5)
src/dtos/eventBody.js (1)
  • disallowedArgs (8-8)
src/services/organization.js (2)
  • oldValues (839-839)
  • newValues (833-833)
src/services/user.js (1)
  • oldValues (164-165)
src/helpers/userInvite.js (2)
  • oldValues (842-844)
  • args (1133-1147)
src/services/org-admin.js (1)
  • newValues (656-656)
src/services/org-admin.js (3)
src/services/admin.js (12)
  • require (11-11)
  • require (27-27)
  • require (34-34)
  • require (36-36)
  • require (37-37)
  • user (55-55)
  • user (201-204)
  • user (339-339)
  • user (450-450)
  • utils (17-17)
  • eventBody (64-81)
  • eventBody (208-219)
src/helpers/userInvite.js (9)
  • require (18-18)
  • require (23-23)
  • require (27-27)
  • require (28-28)
  • require (29-29)
  • user (664-668)
  • utils (3-3)
  • eventBody (910-924)
  • eventBody (1153-1158)
src/database/queries/users.js (1)
  • user (225-270)
🔇 Additional comments (4)
src/services/org-admin.js (4)

31-32: LGTM!

The new imports support the delta-based event broadcasting pattern introduced in this PR.


635-642: LGTM!

The explicit null check and error throw provide clear fail-fast behavior when the role is not found.


633-683: LGTM! Well-structured refactor with clear error handling.

The async refactor with delta-based event generation is well-implemented:

  • Clear fail-fast behavior with explicit null checks
  • Conditional event broadcasting based on deltas prevents emitting empty events
  • Proper error propagation through try-catch
  • Clean separation of concerns

675-676: Redis key pattern is consistent. All occurrences use common.redisUserPrefix + tenantCode + '_' + id (with or without .toString()), so no changes needed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/services/tenant.js (2)

864-869: Add null check for tenantAfter parameter.

The function passes tenantAfter directly to utils.extractDelta at line 866 without validating it's defined. If the update query didn't return data (despite the validation at lines 460-466, edge cases could exist), this will cause extractDelta to fail.

Apply this diff to add validation:

 async function tenantEventEmitter(tenantBefore, tenantAfter, bodyData) {
+	if (!tenantAfter) {
+		console.error('tenantEventEmitter called with undefined tenantAfter')
+		return
+	}
+	
 	// compute delta based on attempted update fields
 	const newValues = utils.extractDelta(tenantBefore, tenantAfter, bodyData)

874-882: Inconsistent event payload structure still exists.

The main tenant update event (via tenantEventEmitter) doesn't include the args wrapper, but addDomain (lines 552-569) and removeDomain (lines 690-707) events still have the args wrapper. This inconsistency could break event consumers expecting uniform structure.

Apply this diff to add the args wrapper for consistency:

 	const eventBodyData = {
 		entity: 'tenant',
 		eventType: 'update',
 		entityId: tenantBefore.code,
 		oldValues,
 		newValues,
-		created_at: tenantBefore?.created_at || new Date(),
-		updated_at: tenantAfter?.updated_at || new Date(),
+		args: {
+			created_by: tenantBefore.created_by,
+			name: tenantBefore.name,
+			code: tenantBefore.code,
+			created_at: tenantBefore?.created_at || new Date(),
+			updated_at: tenantAfter?.updated_at || new Date(),
+			status: tenantBefore?.status || common.ACTIVE_STATUS,
+			meta: tenantBefore?.meta || {},
+			deleted: false,
+			description: tenantBefore.description,
+			logo: tenantBefore.logo,
+		},
 	}
🧹 Nitpick comments (1)
src/services/tenant.js (1)

460-470: Good validation, but optional chaining is now redundant.

The validation at lines 460-466 correctly ensures updatedRows contains data before proceeding, addressing the previous review concern. However, line 468 still uses optional chaining (updatedRows?.[0]) even though we've already confirmed updatedRows is not empty.

Apply this diff to simplify line 468:

-			let updatedTenantDetails = updatedRows?.[0]
+			const updatedTenantDetails = updatedRows[0]
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4cde5b and 1503ff2.

📒 Files selected for processing (1)
  • src/services/tenant.js (7 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/services/**

⚙️ CodeRabbit configuration file

This is core business logic. Please check for correctness, efficiency, and potential edge cases.

Files:

  • src/services/tenant.js
🧠 Learnings (1)
📚 Learning: 2025-09-12T10:35:28.285Z
Learnt from: praveenKDass
PR: ELEVATE-Project/user#816
File: src/services/admin.js:704-704
Timestamp: 2025-09-12T10:35:28.285Z
Learning: In the ELEVATE-Project/user codebase, when using organizationQueries.update with { returning: true, raw: true } options, the method consistently returns a structured result with updatedRows property when successful. The initial check for orgRowsAffected === 0 already handles failed updates, so additional null checking for updatedRows is redundant when the code execution reaches the event emission logic.

Applied to files:

  • src/services/tenant.js
🧬 Code graph analysis (1)
src/services/tenant.js (1)
src/services/organization.js (6)
  • eventBodyData (151-169)
  • eventBodyData (874-894)
  • newValues (833-833)
  • utils (5-5)
  • oldValues (839-839)
  • _ (13-13)
🔇 Additional comments (4)
src/services/tenant.js (4)

435-442: LGTM! Consistent query pattern.

Using raw: true ensures the query returns a plain object instead of a Sequelize instance, which is appropriate for event emission and avoids potential serialization issues.


494-494: LGTM! Consistent pattern for domain events.

The changes align with the new event payload structure using oldValues/newValues. Line 550 intentionally adds the domains field to tenantDetails before creating the event payload, ensuring the old state includes domain information.

Also applies to: 550-550, 556-557


596-601: LGTM! Consistent with addDomain pattern.

The removeDomain implementation mirrors the addDomain changes, maintaining consistency across domain management operations.

Also applies to: 688-688, 694-695


866-866: extractDelta edge-case behavior is correct

  • Flattens nested fields via flattenLeafPaths and uses _.isEqual for deep comparisons → nested objects, null values and unchanged fields are skipped as expected
  • Strict type equality means 1 !== "1" will show up in the delta (adjust only if you need coercion)

@nevil-mathew nevil-mathew merged commit 485d9d0 into develop Oct 14, 2025
1 of 2 checks passed
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