Skip to content

Conversation

@chrisgacsal
Copy link
Collaborator

@chrisgacsal chrisgacsal commented Oct 28, 2025

Overview

Use models.NamespacedID for notification resource entities.

Summary by CodeRabbit

  • Refactor
    • Streamlined notification system data structures by consolidating identifier handling across channels, rules, events, and delivery statuses.
    • Simplified the delivery status update process to use a more efficient single-operation approach.
    • Improved internal consistency of namespaced entity identification patterns.

@chrisgacsal chrisgacsal self-assigned this Oct 28, 2025
@chrisgacsal chrisgacsal requested a review from a team as a code owner October 28, 2025 12:50
@chrisgacsal chrisgacsal added the release-note/ignore Ignore this change when generating release notes label Oct 28, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 28, 2025

📝 Walkthrough

Walkthrough

The PR refactors the notification system to replace the NamespacedModel embedded type with NamespacedID across multiple public entities (Channel, Rule, Event, EventDeliveryStatus), removes redundant ID fields, and simplifies UpdateEventDeliveryStatusInput to contain only namespace-scoped identifiers. The adapter layer consolidates the delivery status update into a single operation with combined queries.

Changes

Cohort / File(s) Summary
Entity Type Definitions
openmeter/notification/channel.go, openmeter/notification/event.go, openmeter/notification/rule.go, openmeter/notification/deliverystatus.go
Replaced embedded models.NamespacedModel with models.NamespacedID in Channel, Event, Rule, and EventDeliveryStatus structs; removed duplicate ID fields. Updated validation logic in UpdateEventDeliveryStatusInput to delegate to NamespacedID.Validate().
Adapter Entity Mapping
openmeter/notification/adapter/entitymapping.go
Updated ChannelFromDBEntity, RuleFromDBEntity, EventFromDBEntity, and EventDeliveryStatusFromDBEntity to construct NamespacedID with Namespace and ID, removing top-level ID field assignments.
Adapter Delivery Status Update
openmeter/notification/adapter/deliverystatus.go
Reworked UpdateEventDeliveryStatus to use a single ID-based update path with UpdateOneID and Where clause for namespace. Changed error handling to use returned row directly and map not-found errors to NamespacedID from params.
Event Handler Webhook Dispatch
openmeter/notification/eventhandler/dispatch.go
Introduced filtering of delivery statuses against webhook channel IDs using map-based lookup. Updated UpdateEventDeliveryStatusInput construction to use deliveryStatus.NamespacedID and Annotations instead of separate fields. Expanded logging attributes for delivery status tracking.
Event Handler Reconciliation
openmeter/notification/eventhandler/reconcile.go
Renamed loop iteration variable from event to deliveryStatus and updated error message references accordingly.
Test Updates
test/notification/event.go
Updated UpdateEventDeliveryStatusInput construction to use NamespacedID with embedded Namespace and ID. Removed test subcase variant using EventID and ChannelID together.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • openmeter/notification/adapter/deliverystatus.go: Verify the consolidated single-operation update logic correctly replaces the prior two-step approach and that error handling properly maps not-found cases.
  • openmeter/notification/eventhandler/dispatch.go: Cross-verify the new filtering logic against webhook channels and confirm the Annotations flow is correctly wired from delivery status entities.
  • Cascading type changes: Confirm all NamespacedModel-to-NamespacedID substitutions are consistently applied across entity definitions, mappings, and usage sites.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "refactor: use namespacedID for notification resources" is clear, specific, and directly aligned with the main changes in the pull request. The changeset consistently replaces the embedded models.NamespacedModel with models.NamespacedID across all notification resource entities (Channel, Rule, Event, EventDeliveryStatus), which is exactly what the title communicates. The title uses descriptive language without vague terms or noise, and a teammate reviewing the commit history would immediately understand that this PR refactors notification resources to use NamespacedID.
✨ 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 refactor/namespacedid

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.

Copy link
Contributor

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

🧹 Nitpick comments (5)
openmeter/notification/channel.go (1)

192-207: Delegate identifier validation to NamespacedID.Validate for consistency.

Reuse the shared validator instead of manual checks.

Apply these diffs:

 func (i UpdateChannelInput) Validate() error {
   var errs []error

-  if i.Namespace == "" {
-    errs = append(errs, errors.New("namespace is required"))
-  }
-
-  if i.ID == "" {
-    errs = append(errs, errors.New("id is required"))
-  }
+  if err := i.NamespacedID.Validate(); err != nil {
+    errs = append(errs, err)
+  }
 func (i GetChannelInput) Validate() error {
   var errs []error
-
-  if i.Namespace == "" {
-    errs = append(errs, errors.New("namespace is required"))
-  }
-
-  if i.ID == "" {
-    errs = append(errs, errors.New("id is required"))
-  }
+  if err := (models.NamespacedID)(i).Validate(); err != nil {
+    errs = append(errs, err)
+  }
 
   return models.NewNillableGenericValidationError(errors.Join(errs...))
 }

Also applies to: 213-236, 250-261

openmeter/notification/eventhandler/reconcile.go (1)

111-113: Clarify variable naming; fix misleading error text.

We iterate events, not delivery statuses. Rename the loop var and adjust the earlier error message.

Apply:

-        if err != nil {
-          return fmt.Errorf("failed to fetch notification delivery statuses for reconciliation: %w", err)
-        }
+        if err != nil {
+          return fmt.Errorf("failed to fetch notification events for reconciliation: %w", err)
+        }
-        for _, deliveryStatus := range out.Items {
-          if err = h.reconcileEvent(ctx, &deliveryStatus); err != nil {
+        for _, event := range out.Items {
+          if err = h.reconcileEvent(ctx, &event); err != nil {
             errs = append(errs,
               fmt.Errorf("failed to reconcile notification event [namespace=%s event.id=%s]: %w",
-                deliveryStatus.Namespace, deliveryStatus.ID, err),
+                event.Namespace, event.ID, err),
             )
           }
         }

Also applies to: 119-124

openmeter/notification/adapter/entitymapping.go (1)

85-87: NIT: "deserialize" instead of "serialize".

We are unmarshalling JSON.

-    return nil, fmt.Errorf("failed to serialize notification event payload: %w", err)
+    return nil, fmt.Errorf("failed to deserialize notification event payload: %w", err)
openmeter/notification/eventhandler/dispatch.go (1)

104-111: Align sent channel IDs with filtered webhook channels.

We filter delivery statuses to webhook channels but still send with event.Rule.ID. Likely mismatch. Prefer sending to the actual webhook channel IDs we’ve computed.

Apply after building the map:

   webhookChannelIDMap := lo.FilterSliceToMap(event.Rule.Channels, func(item notification.Channel) (string, struct{}, bool) {
     if item.Type == notification.ChannelTypeWebhook {
       return item.ID, struct{}{}, true
     }
     return "", struct{}{}, false
   })
+
+  // Use the same set for sending
+  sendIn.Channels = lo.Keys(webhookChannelIDMap)
+  if len(sendIn.Channels) == 0 {
+    return nil // nothing to dispatch via webhook
+  }

Please confirm webhook.SendMessageInput.Channels expects channel IDs (not rule IDs). If it does expect rule IDs, consider renaming the field or adding a comment to avoid confusion.

Also applies to: 112-121, 123-128

openmeter/notification/rule.go (1)

42-44: Refactor UpdateRuleInput.Validate() to use NamespacedID.Validate() for consistency.

Verification confirms NamespacedID.Validate() is available and Rule.Validate() uses it correctly. However, UpdateRuleInput.Validate() still contains duplicate manual checks (lines 250–256, openmeter/notification/rule.go) instead of delegating to the embedded NamespacedID.Validate() method. This creates inconsistency. Replace the manual Namespace and ID validation with a call to i.NamespacedID.Validate() to align with Rule's approach.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34c7573 and b0f858b.

📒 Files selected for processing (9)
  • openmeter/notification/adapter/deliverystatus.go (1 hunks)
  • openmeter/notification/adapter/entitymapping.go (4 hunks)
  • openmeter/notification/channel.go (1 hunks)
  • openmeter/notification/deliverystatus.go (3 hunks)
  • openmeter/notification/event.go (1 hunks)
  • openmeter/notification/eventhandler/dispatch.go (2 hunks)
  • openmeter/notification/eventhandler/reconcile.go (1 hunks)
  • openmeter/notification/rule.go (2 hunks)
  • test/notification/event.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
openmeter/notification/channel.go (1)
pkg/models/id.go (1)
  • NamespacedID (7-10)
openmeter/notification/event.go (1)
pkg/models/id.go (1)
  • NamespacedID (7-10)
test/notification/event.go (1)
pkg/models/id.go (1)
  • NamespacedID (7-10)
openmeter/notification/adapter/entitymapping.go (5)
pkg/models/id.go (1)
  • NamespacedID (7-10)
openmeter/ent/db/notificationchannel/where.go (2)
  • Namespace (70-72)
  • ID (15-17)
openmeter/ent/db/notificationevent/where.go (2)
  • Namespace (70-72)
  • ID (15-17)
openmeter/ent/db/notificationeventdeliverystatus/where.go (2)
  • Namespace (70-72)
  • ID (15-17)
openmeter/ent/db/notificationrule/where.go (2)
  • Namespace (70-72)
  • ID (15-17)
openmeter/notification/adapter/deliverystatus.go (3)
openmeter/ent/db/notificationeventdeliverystatus.go (2)
  • NotificationEventDeliveryStatus (19-43)
  • NotificationEventDeliveryStatus (64-79)
pkg/models/id.go (1)
  • NamespacedID (7-10)
openmeter/notification/adapter/entitymapping.go (1)
  • EventDeliveryStatusFromDBEntity (121-136)
openmeter/notification/rule.go (1)
pkg/models/id.go (1)
  • NamespacedID (7-10)
openmeter/notification/eventhandler/dispatch.go (4)
openmeter/notification/rule.go (1)
  • Rule (17-33)
openmeter/notification/channel.go (2)
  • Channel (37-51)
  • ChannelTypeWebhook (14-14)
openmeter/notification/deliverystatus.go (1)
  • UpdateEventDeliveryStatusInput (148-157)
pkg/models/id.go (1)
  • NamespacedID (7-10)
openmeter/notification/deliverystatus.go (1)
pkg/models/id.go (1)
  • NamespacedID (7-10)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Artifacts / Container image
  • GitHub Check: Lint
  • GitHub Check: Code Generators
  • GitHub Check: Build
  • GitHub Check: Test
  • GitHub Check: Migration Checks
  • GitHub Check: Analyze (go)
🔇 Additional comments (5)
test/notification/event.go (1)

344-347: LGTM on switching to NamespacedID in test input.

Matches the new update path and mapping.

openmeter/notification/event.go (1)

51-53: LGTM on embedding NamespacedID in Event.

Public model is now consistent across notification entities.

openmeter/notification/deliverystatus.go (3)

49-49: LGTM! Clean refactoring to NamespacedID.

The change from models.NamespacedModel to models.NamespacedID simplifies the struct while maintaining all necessary identification fields.


166-168: LGTM! Cleaner validation approach.

Delegating to NamespacedID.Validate() centralizes the validation logic and eliminates redundant manual checks. This is a cleaner and more maintainable approach.


148-157: No issues found—all callers properly use the ID field.

Verification confirms both instantiations of UpdateEventDeliveryStatusInput in the codebase correctly set the ID field through the embedded NamespacedID:

  • test/notification/event.go:343: Sets NamespacedID with delivery status ID
  • openmeter/notification/eventhandler/dispatch.go:123: Sets NamespacedID from existing delivery status

No lingering references to the old EventID or ChannelID pattern exist. All interface signatures and implementations are consistent. The refactoring is complete.

@chrisgacsal chrisgacsal merged commit f420775 into main Oct 28, 2025
33 checks passed
@chrisgacsal chrisgacsal deleted the refactor/namespacedid branch October 28, 2025 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/ignore Ignore this change when generating release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants