Skip to content

Conversation

@hekike
Copy link
Contributor

@hekike hekike commented Dec 27, 2025

Currently, we only allow filtering the customer list by plan key, and also allow filtering by plan ID to be able to filter for specific plan versions.

Summary by CodeRabbit

  • New Features

    • Customers can be filtered by plan ID (ULID) in addition to plan key; listing can optionally expand active subscription details.
  • Validation / Error Handling

    • Plan ID and plan key filters are mutually exclusive; empty values are rejected. Nonexistent plan IDs/keys return a clear precondition error.
  • Bug Fixes / Docs

    • Corrected typo in plan key description and clarified filter behavior.
  • Tests

    • Added tests and helpers covering listing with subscriptions, PlanID/PlanKey filtering, unknown keys, and validation cases.

✏️ Tip: You can customize this high-level summary in your review settings.

@hekike hekike requested a review from tothandras December 27, 2025 08:15
@hekike hekike added the release-note/feature Release note: Exciting New Features label Dec 27, 2025
@hekike hekike requested a review from a team as a code owner December 27, 2025 08:15
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

📝 Walkthrough

Walkthrough

Adds an optional planId ULID filter to customer listing (mutually exclusive with planKey), threads validation and plan-existence checks through HTTP → service → adapter, centralizes active-subscription predicate construction, and extends tests with subscription lifecycle helpers and listing scenarios.

Changes

Cohort / File(s) Summary
API spec
api/spec/src/customer/customer.tsp
Added planId?: ULID to ListCustomersParams; updated planKey docs (case‑sensitive exact match, mutually exclusive with planId) and fixed a typo.
Service input
openmeter/customer/customer.go
Added PlanID *string to ListCustomersInput and a Validate() method enforcing mutual exclusivity and validating provided fields.
HTTP driver (handler & endpoint)
openmeter/customer/httpdriver/customer.go, openmeter/customer/httpdriver/handler.go
Validate plan existence by ID or key via planService; propagate params.PlanIdListCustomers request; handler constructor now accepts planService.
Customer adapter
openmeter/customer/adapter/customer.go
Added activeSubscriptionFilterPredicates(at time.Time) []predicate.Subscription; unified active-subscription predicate construction and apply subscription predicates (including PlanID/PlanKey) via HasSubscriptionWith(...); consolidated expansion gating.
Router / wiring
openmeter/server/router/router.go
Validates Plan service presence; updated customerhttpdriver.New call sites to include planService and reordered args.
Tests & helpers
test/customer/customer.go, test/customer/customer_test.go
Added createMockPlan, startSubscriptionFromPlan, startMockSubscription; added TestListWithSubscription (PlanID/PlanKey filters, not-found and validation cases); updated tests to use helpers.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant HTTP as HTTP Driver
  participant Service
  participant Adapter
  participant DB as Database

  Client->>HTTP: GET /customers?planId=<ULID>
  HTTP->>Service: ListCustomersRequest{PlanID:<ULID>, ...}
  Service->>Adapter: ListCustomersInput{PlanID, PlanKey, Expands, ...}
  Adapter->>Adapter: build activeSubscriptionFilterPredicates(now)
  alt PlanID provided
    Adapter->>Adapter: append predicate: subscription.ID == PlanID
  else PlanKey provided
    Adapter->>Adapter: append predicate: subscription.PlanKey == PlanKey
  end
  Adapter->>DB: query customers with HasSubscriptionWith(predicate set)
  DB-->>Adapter: matching customers (+ optional expanded subscriptions)
  Adapter-->>Service: result set
  Service-->>HTTP: formatted response
  HTTP-->>Client: 200 OK with customers
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

area/api

Suggested reviewers

  • tothandras
  • turip
  • chrisgacsal

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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 clearly summarizes the main change: adding plan ID filtering to the customer list endpoint, which aligns with the core feature added across all modified files.
✨ 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 feat/customer-list-by-plan-id

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 (1)
test/customer/customer.go (1)

558-625: Good test coverage for the new feature!

The test covers the key scenarios: filtering by plan ID, filtering by plan key, unknown plan key returning empty results, and the mutual exclusivity validation.

A couple of small nits:

  • Line 563: cService is redundant – you already have service from line 562.
  • Line 566: Typo testCutomertestCustomer.
🔎 Suggested cleanup
 func (s *CustomerHandlerTestSuite) TestListWithSubscription(ctx context.Context, t *testing.T) {
 	s.setupNamespace(t)
 
 	service := s.Env.Customer()
-	cService := s.Env.Customer()
 
 	// Create a customer with mandatory fields
-	testCutomer, err := cService.CreateCustomer(ctx, customer.CreateCustomerInput{
+	testCustomer, err := service.CreateCustomer(ctx, customer.CreateCustomerInput{
 		Namespace: s.namespace,
 		CustomerMutate: customer.CustomerMutate{
 			Name: TestName,
 			UsageAttribution: &customer.CustomerUsageAttribution{
 				SubjectKeys: TestSubjectKeys,
 			},
 		},
 	})
 
 	require.NoError(t, err, "Creating customer must not return error")
-	require.NotNil(t, testCutomer, "Customer must not be nil")
-	require.Equal(t, TestName, testCutomer.Name, "Customer name must match")
-	require.Equal(t, TestSubjectKeys, testCutomer.UsageAttribution.SubjectKeys, "Customer usage attribution subject keys must match")
+	require.NotNil(t, testCustomer, "Customer must not be nil")
+	require.Equal(t, TestName, testCustomer.Name, "Customer name must match")
+	require.Equal(t, TestSubjectKeys, testCustomer.UsageAttribution.SubjectKeys, "Customer usage attribution subject keys must match")
 
-	plan, _ := s.startMockSubscription(ctx, t, testCutomer.GetID())
+	plan, _ := s.startMockSubscription(ctx, t, testCustomer.GetID())

And update the remaining references to testCutomertestCustomer in the assertions.

📜 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 84bb51c and 27c474e.

⛔ Files ignored due to path filters (7)
  • api/client/go/client.gen.go is excluded by !api/client/**
  • api/client/javascript/src/client/schemas.ts is excluded by !api/client/**
  • api/client/javascript/src/zod/index.ts is excluded by !api/client/**
  • api/client/python/openmeter/_generated/aio/operations/_operations.py is excluded by !**/_generated/**, !api/client/**
  • api/client/python/openmeter/_generated/operations/_operations.py is excluded by !**/_generated/**, !api/client/**
  • api/openapi.cloud.yaml is excluded by !**/openapi.cloud.yaml
  • api/openapi.yaml is excluded by !**/openapi.yaml
📒 Files selected for processing (7)
  • api/api.gen.go
  • api/spec/src/customer/customer.tsp
  • openmeter/customer/adapter/customer.go
  • openmeter/customer/customer.go
  • openmeter/customer/httpdriver/customer.go
  • test/customer/customer.go
  • test/customer/customer_test.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: In general when reviewing the Golang code make readability and maintainability a priority, even potentially suggest restructuring the code to improve them.

Performance should be a priority in critical code paths. Anything related to event ingestion, message processing, database operations (regardless of database) should be vetted for potential performance bottlenecks.

Files:

  • openmeter/customer/customer.go
  • test/customer/customer_test.go
  • openmeter/customer/adapter/customer.go
  • test/customer/customer.go
  • openmeter/customer/httpdriver/customer.go
**/*_test.go

⚙️ CodeRabbit configuration file

**/*_test.go: Make sure the tests are comprehensive and cover the changes. Keep a strong focus on unit tests and in-code integration tests.
When appropriate, recommend e2e tests for critical changes.

Files:

  • test/customer/customer_test.go
**/*.tsp

⚙️ CodeRabbit configuration file

**/*.tsp: Review the TypeSpec code for conformity with TypeSpec best practices. When recommending changes also consider the fact that multiple codegeneration toolchains depend on the TypeSpec code, each of which have their idiosyncrasies and bugs.

The declared API should be accurate, in parity with the actual implementation, and easy to understand for the user.

Files:

  • api/spec/src/customer/customer.tsp
🧠 Learnings (1)
📚 Learning: 2025-03-25T09:13:03.300Z
Learnt from: chrisgacsal
Repo: openmeterio/openmeter PR: 2522
File: api/spec/src/productcatalog/routes.tsp:163-314
Timestamp: 2025-03-25T09:13:03.300Z
Learning: ULIDOrKey is defined in api/spec/src/types.tsp as a scalar type with a pattern that validates against both ULID and Key formats, not as a type alias like PlanIdOrKey.

Applied to files:

  • api/spec/src/customer/customer.tsp
🧬 Code graph analysis (3)
openmeter/customer/customer.go (3)
openmeter/productcatalog/plan/plan.go (1)
  • Plan (18-30)
e2e/productcatalog_test.go (1)
  • PlanKey (22-22)
pkg/models/errors.go (1)
  • NewGenericValidationError (138-140)
openmeter/customer/adapter/customer.go (1)
openmeter/customer/customer.go (2)
  • Expands (20-20)
  • ExpandSubscriptions (24-24)
test/customer/customer.go (2)
openmeter/productcatalog/subscription/plan.go (2)
  • Plan (50-53)
  • Phase (100-104)
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). (9)
  • GitHub Check: Artifacts / Container image
  • GitHub Check: Test
  • GitHub Check: Artifacts / Benthos Collector Container image
  • GitHub Check: Code Generators
  • GitHub Check: Lint
  • GitHub Check: Build
  • GitHub Check: Repository Scan
  • GitHub Check: SAST (semgrep)
  • GitHub Check: Analyze (go)
🔇 Additional comments (8)
openmeter/customer/httpdriver/customer.go (1)

59-59: Looks good!

The Plan filter is correctly mapped from the API params to the request input. The mutual exclusivity validation with PlanKey is handled in ListCustomersInput.Validate(), so no additional checks are needed here.

api/spec/src/customer/customer.tsp (1)

166-180: Nice addition to the API!

The spec clearly documents both filter options with their mutual exclusivity. Using ULID type for the plan ID is appropriate here, and the documentation makes it clear that planKey uses case-sensitive exact matching while plan filters by the specific plan version ID.

openmeter/customer/adapter/customer.go (1)

756-769: Clean refactoring!

Extracting activeSubscriptionFilterPredicates into a reusable helper is a solid improvement. It centralizes the active subscription logic and makes it easier to maintain consistency across WithActiveSubscriptions and the new subscription-based filters.

test/customer/customer_test.go (1)

38-40: LGTM!

The new test case is properly integrated into the test suite, following the established pattern.

openmeter/customer/customer.go (2)

311-311: Field addition looks good.

The Plan field is correctly added as *string to match the existing PlanKey pattern.


328-330: Validation is solid.

The mutual exclusivity check is appropriately placed in Validate() and provides a clear error message. This aligns with the API spec documentation.

test/customer/customer.go (2)

981-1070: Nice helper functions!

The startMockSubscription, createMockPlan, and startSubscriptionFromPlan helpers are well-structured and will make it easier to set up subscription scenarios in future tests. Good use of the existing PlanFromPlan utility.


373-373: Good refactor to use the new helper!

Replacing the inline subscription setup with startMockSubscription keeps the test focused on its actual purpose.

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 (1)
test/customer/customer.go (1)

562-563: Redundant variable: Use a single variable name.

Both service and cService are assigned to s.Env.Customer(), but only cService is used in the test. You can remove the service declaration and just use cService (or rename it to service for consistency with other tests).

🔎 Proposed fix
-	service := s.Env.Customer()
-	cService := s.Env.Customer()
+	service := s.Env.Customer()

Then update line 585 and 596:

-	list, err := service.ListCustomers(ctx, customer.ListCustomersInput{
+	list, err := service.ListCustomers(ctx, customer.ListCustomersInput{

(Already using service, so no change needed for those lines if you remove cService and update line 566 to use service instead)

Or simply remove the unused service declaration and keep cService.

📜 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 ecd1a86 and 6279e76.

⛔ Files ignored due to path filters (7)
  • api/client/go/client.gen.go is excluded by !api/client/**
  • api/client/javascript/src/client/schemas.ts is excluded by !api/client/**
  • api/client/javascript/src/zod/index.ts is excluded by !api/client/**
  • api/client/python/openmeter/_generated/aio/operations/_operations.py is excluded by !**/_generated/**, !api/client/**
  • api/client/python/openmeter/_generated/operations/_operations.py is excluded by !**/_generated/**, !api/client/**
  • api/openapi.cloud.yaml is excluded by !**/openapi.cloud.yaml
  • api/openapi.yaml is excluded by !**/openapi.yaml
📒 Files selected for processing (6)
  • api/api.gen.go
  • api/spec/src/customer/customer.tsp
  • openmeter/customer/adapter/customer.go
  • openmeter/customer/customer.go
  • openmeter/customer/httpdriver/customer.go
  • test/customer/customer.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • openmeter/customer/httpdriver/customer.go
  • openmeter/customer/customer.go
  • api/spec/src/customer/customer.tsp
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: In general when reviewing the Golang code make readability and maintainability a priority, even potentially suggest restructuring the code to improve them.

Performance should be a priority in critical code paths. Anything related to event ingestion, message processing, database operations (regardless of database) should be vetted for potential performance bottlenecks.

Files:

  • test/customer/customer.go
  • openmeter/customer/adapter/customer.go
🧬 Code graph analysis (2)
test/customer/customer.go (3)
openmeter/productcatalog/plan.go (2)
  • Plan (41-46)
  • PlanMeta (198-224)
openmeter/productcatalog/subscription/plan.go (3)
  • Plan (50-53)
  • Phase (100-104)
  • RateCard (134-137)
openmeter/subscription/subscriptionspec.go (2)
  • NewSpecFromPlan (1033-1125)
  • CreateSubscriptionCustomerInput (42-52)
openmeter/customer/adapter/customer.go (1)
openmeter/customer/customer.go (2)
  • Expands (20-20)
  • ExpandSubscriptions (24-24)
⏰ 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). (8)
  • GitHub Check: Artifacts / Container image
  • GitHub Check: Build
  • GitHub Check: Test
  • GitHub Check: Lint
  • GitHub Check: Migration Checks
  • GitHub Check: Code Generators
  • GitHub Check: SAST (semgrep)
  • GitHub Check: Analyze (go)
🔇 Additional comments (7)
openmeter/customer/adapter/customer.go (4)

36-36: Nice readability improvement!

Extracting the expandSubscriptions flag makes the intent clearer and avoids repeating the slices.Contains check. Good call!


81-102: Looking good – the subscription filter logic is solid!

The predicate-based filtering approach is clean, and I see the query assignment issue from the previous review (line 99) has been properly fixed. The logic correctly applies both Plan ID and Plan Key filters when present, and based on the test coverage, mutual exclusivity is enforced at the validation layer (as it should be).


756-770: Great refactoring – centralized predicate logic!

Extracting the active subscription predicates into a reusable function is a solid move. The logic correctly handles the time-based filtering (active from/to, deleted at, created at), and using it consistently for both filtering and expansion keeps things DRY.


749-754: Clean update to use the centralized predicates!

WithActiveSubscriptions now leverages the shared activeSubscriptionFilterPredicates function, which makes the codebase more maintainable and consistent.

test/customer/customer.go (3)

373-373: Nice cleanup – helper usage simplifies the test!

Using startMockSubscription here keeps the test focused on the update logic rather than subscription setup details.


981-1043: Great test helpers – clean and reusable!

The startMockSubscription and createMockPlan helpers significantly reduce duplication and make the tests more maintainable. The plan creation includes proper error checks and a realistic structure.


1045-1070: Solid helper for subscription lifecycle testing!

startSubscriptionFromPlan encapsulates the subscription creation flow nicely. The clock advancement is a good touch for ensuring time-based logic is properly tested.

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 (1)
openmeter/customer/httpdriver/customer.go (1)

42-78: Consider adding mutual exclusivity check for PlanId and PlanKey

According to the PR description and AI summary, planId and planKey should be mutually exclusive filters. Right now both validations run independently, so if a caller provides both params, the code will make two plan lookups before proceeding.

While this might be enforced at the OpenAPI validation layer, adding a defensive check here would make the intent clear and prevent unnecessary database calls if both are somehow provided.

🔎 Proposed fix
+			// Check mutual exclusivity of PlanId and PlanKey
+			if params.PlanId != nil && params.PlanKey != nil {
+				return ListCustomersRequest{}, models.NewGenericValidationError(
+					fmt.Errorf("planId and planKey are mutually exclusive"),
+				)
+			}
+
 			// Check if the plan by ID exists
 			if params.PlanId != nil {
📜 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 6279e76 and c4cc219.

📒 Files selected for processing (3)
  • openmeter/customer/httpdriver/customer.go
  • openmeter/customer/httpdriver/handler.go
  • openmeter/server/router/router.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: In general when reviewing the Golang code make readability and maintainability a priority, even potentially suggest restructuring the code to improve them.

Performance should be a priority in critical code paths. Anything related to event ingestion, message processing, database operations (regardless of database) should be vetted for potential performance bottlenecks.

Files:

  • openmeter/customer/httpdriver/handler.go
  • openmeter/customer/httpdriver/customer.go
  • openmeter/server/router/router.go
🧬 Code graph analysis (1)
openmeter/customer/httpdriver/customer.go (5)
openmeter/productcatalog/plan/service.go (1)
  • GetPlanInput (304-319)
pkg/models/id.go (1)
  • NamespacedID (7-10)
pkg/models/errors.go (2)
  • IsGenericNotFoundError (57-65)
  • NewGenericPreConditionFailedError (233-235)
api/v3/handlers/customers/list.go (1)
  • ListCustomersRequest (22-22)
e2e/productcatalog_test.go (1)
  • PlanKey (22-22)
⏰ 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). (10)
  • GitHub Check: E2E
  • GitHub Check: Quickstart
  • GitHub Check: Build
  • GitHub Check: Test
  • GitHub Check: Code Generators
  • GitHub Check: Lint
  • GitHub Check: Migration Checks
  • GitHub Check: Repository Scan
  • GitHub Check: SAST (semgrep)
  • GitHub Check: Analyze (go)
🔇 Additional comments (5)
openmeter/customer/httpdriver/customer.go (3)

42-59: LGTM on plan ID validation logic

The validation correctly checks for plan existence and returns a precondition failed error with a clear message when not found. Other errors are properly propagated. Nice and clean!


61-78: LGTM on plan key validation logic

Same pattern as the ID check - consistent error handling approach. 👍


99-100: LGTM - PlanID correctly wired into request

The new PlanID field is properly mapped from params.PlanId alongside the existing PlanKey field.

openmeter/customer/httpdriver/handler.go (2)

33-40: LGTM - Handler struct updated correctly

Clean addition of the planService field. The struct field ordering matches the constructor parameter order nicely.


51-66: LGTM - Constructor updated with new dependency

The planService is properly injected and initialized. Everything lines up correctly with the struct definition.

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: 0

🧹 Nitpick comments (3)
openmeter/server/router/router.go (1)

400-402: Remove redundant nil check.

Since Config.Validate() now checks for nil Plan (lines 189-191) and is called at the start of NewRouter (line 257), this check is redundant and can be removed.

🔎 Proposed cleanup
-	// Product Catalog
-	if config.Plan == nil {
-		return nil, errors.New("plan service is required")
-	}
-
 	router.planHandler = planhttpdriver.New(
test/customer/customer.go (2)

562-563: Remove redundant variable declaration.

Both service and cService are assigned to s.Env.Customer(). You can just use one variable throughout the test.

🔎 Proposed fix
-	service := s.Env.Customer()
-	cService := s.Env.Customer()
+	service := s.Env.Customer()

Then use service consistently throughout (e.g., line 566).


1000-1078: Great test helpers!

Both createMockPlan and startSubscriptionFromPlan are well-structured and will be reusable across tests. The time advancement (line 1072) is a nice touch to simulate realistic subscription lifecycle.

Minor style note: Consider using require.NoError() instead of require.Nil() for error checks (lines 1037, 1047, 1070, 1075) for more idiomatic Go test assertions.

🔎 Optional style improvement
-	require.Nil(t, err)
+	require.NoError(t, err, "Creating plan must not return error")

Apply similar changes to lines 1047, 1070, and 1075 for consistency with the rest of the test suite.

📜 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 c4cc219 and c27a95b.

📒 Files selected for processing (3)
  • openmeter/customer/customer.go
  • openmeter/server/router/router.go
  • test/customer/customer.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: In general when reviewing the Golang code make readability and maintainability a priority, even potentially suggest restructuring the code to improve them.

Performance should be a priority in critical code paths. Anything related to event ingestion, message processing, database operations (regardless of database) should be vetted for potential performance bottlenecks.

Files:

  • test/customer/customer.go
  • openmeter/server/router/router.go
  • openmeter/customer/customer.go
🧬 Code graph analysis (2)
test/customer/customer.go (4)
pkg/models/errors.go (1)
  • IsGenericValidationError (160-168)
openmeter/productcatalog/plan/service.go (1)
  • CreatePlanInput (105-110)
pkg/clock/clock.go (2)
  • Now (14-21)
  • SetTime (23-27)
openmeter/productcatalog/subscription/service/plan.go (1)
  • PlanFromPlan (76-81)
openmeter/server/router/router.go (6)
openmeter/productcatalog/plan.go (1)
  • Plan (41-46)
openmeter/subscription/plan.go (1)
  • Plan (59-69)
openmeter/productcatalog/subscription/plan.go (1)
  • Plan (50-53)
openmeter/productcatalog/plan/plan.go (1)
  • Plan (18-30)
app/common/productcatalog.go (1)
  • Plan (37-39)
openmeter/customer/httpdriver/handler.go (1)
  • New (51-67)
⏰ 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). (9)
  • GitHub Check: Artifacts / Container image
  • GitHub Check: Code Generators
  • GitHub Check: Lint
  • GitHub Check: Migration Checks
  • GitHub Check: Build
  • GitHub Check: Test
  • GitHub Check: SAST (semgrep)
  • GitHub Check: Repository Scan
  • GitHub Check: Analyze (go)
🔇 Additional comments (7)
openmeter/server/router/router.go (2)

189-191: Nice fix! Plan service validation is now in the right place.

Moving the Plan nil-check into Config.Validate() ensures it's caught early, before any handler construction. This addresses the previous review concern cleanly.


352-359: Customer handler wiring looks good!

The Plan service is properly threaded through to the customer handler, and since Config.Validate() now checks for nil Plan, this is safe.

openmeter/customer/customer.go (2)

311-311: PlanID field addition looks good.

The new field is properly typed as an optional pointer and positioned logically next to the PlanKey filter.


319-376: Solid validation implementation!

The new Validate() method is comprehensive and covers all the important cases:

  • Mutual exclusivity between PlanID and PlanKey (which makes sense since they serve different filtering purposes)
  • Empty string checks for all optional filters
  • Clear, descriptive error messages

The validation is a bit verbose, but that's fine—explicit validation is better than clever shortcuts here.

test/customer/customer.go (3)

373-373: Nice cleanup using the new helper!

Replacing the inline subscription setup with startMockSubscription makes the test much more readable.


581-633: Excellent test coverage!

The test scenarios are thorough and cover all the important cases:

  • Filtering by PlanID works ✓
  • Filtering by PlanKey works ✓
  • Empty string validation for both filters ✓
  • Mutual exclusivity validation ✓

The assertions are clear and use appropriate error-checking helpers.


989-998: Clean helper composition!

The startMockSubscription helper nicely orchestrates plan creation and subscription lifecycle for tests.

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

Labels

area/customers release-note/feature Release note: Exciting New Features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants