-
Notifications
You must be signed in to change notification settings - Fork 146
refactor(customer): make usageattribution optional #3682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
📝 WalkthroughWalkthroughThis PR makes the Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this 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 (17)
openmeter/entitlement/driver/parser.go (1)
34-40: Nice nil‑safety; consider centralizing the pattern and being explicit about error handlingThe new guards around
UsageAttributionlook good and should prevent panics now that the field can be nil. A couple of thoughts:
- You’re intentionally treating both “no
UsageAttribution” and “GetFirstSubjectKeyfailed” asSubjectKey == "". If that’s the desired contract, maybe add a short comment to make it clear this is a best‑effort field and errors are intentionally swallowed, so future refactors don’t “fix” it by accident.- Since the same pattern now appears in
ToMetered,ToStatic, andToBoolean, you might want a tiny helper (even private to this file) to keep it in one place and avoid drift if the behavior ever changes.Nothing blocking here, just opportunities to make the intent and behavior a bit more self‑documenting.
Also applies to: 79-85, 114-120
test/app/stripe/fixture.go (1)
138-145: Consider using the newer rand/v2 or crypto/rand for seeding.
rand.Seedis deprecated since Go 1.20. The global random source is now auto-seeded. You can simply remove line 140, or switch torand/v2for explicit seeding.This is a minor nit - totally fine to address later.
func getStripeAccountId() string { length := 6 - rand.Seed(uint64(time.Now().UnixNano())) b := make([]byte, length+2) _, _ = rand.Read(b) s := fmt.Sprintf("%x", b)[2 : length+2] return "acct_" + s }openmeter/subscription/workflow/service/addon_test.go (1)
395-406: CreateCustomer test input now matches pointer-based UsageAttributionThe switch to
UsageAttribution: &customer.CustomerUsageAttribution{SubjectKeys: []string{"another"}}lines up with the new optional field shape and keeps the test behavior intact. Also looks consistent with the broader pattern of pointer vs non-pointer usage in productcatalog types. Based on learnings, this is aligned.openmeter/subscription/validators/customer/validator.go (1)
54-95: Nice nil-safety improvement around UsageAttributionThe new guard
if input.CustomerMutate.UsageAttribution != nil && input.CustomerMutate.UsageAttribution.SubjectKeys != nil { ... if hasSub { var currentSubjectKeys []string if currentCustomer.UsageAttribution != nil { currentSubjectKeys = currentCustomer.UsageAttribution.SubjectKeys } ... } }handles both
inputandcurrentCustomerhaving nilUsageAttributionwithout panicking, while still enforcing “no subject key changes when there are active subscriptions” via the len + element-wise comparison. That’s exactly what we need now that attribution is optional.The only subtle case to keep in mind is when an update sets
UsageAttributionbut leavesSubjectKeysnil (e.g.usageAttribution: {}over the wire): this path will treat it as “no subject key update” and skip the comparison, so whether that can clear existing keys depends on howUpdateCustomerInputis applied in the service layer. Worth a quick sanity check but the validator itself looks solid.openmeter/entitlement/snapshot/event.go (1)
126-171: SnapshotEvent now handles “no subject” cases without blowing upMaking
NewSnapshotEventacceptsubj *subject.Subjectand normalizing it like:var s subject.Subject if subj != nil { s = *subj } ... Subject: s,lets you emit snapshot events for customers without usage attribution while keeping the wire schema (value-typed
Subject) stable. Pairing that with skippingSubjectvalidation inValidate()is consistent with the deprecation comment and avoids false negatives when there’s legitimately no subject.One thing to keep an eye on:
EventMetadata()still always callsmetadata.ComposeResourcePath( e.Namespace.ID, metadata.EntityCustomer, e.Customer.ID, metadata.EntitySubjectKey, e.Subject.Key, )so for events created with
subj == nilyou’ll end up with an empty subject-key segment. If downstream consumers ever rely on that segment being non-empty, we may eventually want to special-case the “no subject” case and omit that piece entirely whene.Subject.Key == "". For now though, this is a reasonable incremental step toward fully phasing outSubject. Based on learnings, this also aligns with the direction of loosening strict subject requirements in newer paths.api/spec/src/customer/customer.tsp (1)
211-226: Clarify the key / usageAttribution constraint vs actual behaviorMaking
usageAttributionoptional here is consistent with the rest of the PR. A couple of small clarity points you might want to address:
- The new doc lines say “Either key or usageAttribution.subjectKeys must be provided”, but this isn’t enforced by the model itself, and both fields are optional. If this is a hard invariant, consider calling out that it’s enforced server‑side (or adding explicit validation) so clients don’t over‑trust the schema alone.
CustomerUsageAttribution.subjectKeysstill says “Can be empty when no subjects are associated with the customer,” while the current Go mapping omitsusageAttributionentirely when there are no subject keys. Might be worth tightening the wording to describe how responses behave (likely “field omitted when there are no subjects”) vs what’s allowed in requests.Nothing blocking, just potential doc/API‑contract polish.
e2e/helpers.go (1)
22-37: Consider asserting UsageAttribution is non‑nil in the e2e helperSwitching to
&api.CustomerUsageAttribution{...}is the right adaptation to the pointer field. To tighten the e2e safety net, you could add:require.NotNil(t, resp.JSON201.UsageAttribution) require.Equal(t, []string{subjectKey}, resp.JSON201.UsageAttribution.SubjectKeys)That way if the API ever stops returning
usageAttributionfor this flow, the test fails with a clear message instead of a nil‑pointer panic.openmeter/streaming/clickhouse/event_query_test.go (1)
96-131: Customer filter test correctly updated for pointer UsageAttributionThe test data now uses
&customer.CustomerUsageAttribution{...}for both customers, which lines up with the new type and keeps thesubject_to_customer_idmapping behavior intact. Looks solid.If you ever want to harden this further, an additional test case where a customer has
UsageAttribution == nil(or no subject keys) could help catch regressions around optional attribution, but not required for this PR.openmeter/subject/service/hooks/customersubject_test.go (1)
85-85: Consider adding a nil check before accessing UsageAttribution.Line 85 accesses
cus.UsageAttribution.SubjectKeysdirectly. While this works since the test explicitly setsUsageAttribution, adding arequire.NotNil(t, cus.UsageAttribution)before the loop would make the test more resilient and self-documenting.Same applies to lines 115 and 160.
openmeter/subscription/testutils/customer.go (1)
83-91: Optional: Add nil guard for robustness.The code at line 83 accesses
ExampleCreateCustomerInput.UsageAttribution.SubjectKeysdirectly. While currently safe (sinceExampleCustomerEntity.UsageAttributionis always initialized), adding a nil check would make this test utility more defensive against future changes:func (a *testCustomerRepo) CreateExampleCustomer(t *testing.T) *customer.Customer { t.Helper() // Create the subjects first + if ExampleCreateCustomerInput.UsageAttribution == nil { + t.Fatal("ExampleCreateCustomerInput.UsageAttribution must not be nil") + } for _, subjectKey := range ExampleCreateCustomerInput.UsageAttribution.SubjectKeys {test/customer/customer.go (1)
75-109: Create‑flow UsageAttribution behavior matches the new optional semanticsUsing
&customer.CustomerUsageAttribution{SubjectKeys: ...}in the happy‑path create tests, and assertingUsageAttributionbecomesnilwhenSubjectKeysis empty, nicely encodes the intended “optional” behavior in the service contract. That gives a clear spec for how the backend should normalize empty subject attribution.One small robustness tweak you might consider in these core tests: before doing
createdCustomer.UsageAttribution.SubjectKeys(and similar in this file), add arequire.NotNil(t, createdCustomer.UsageAttribution, ...)so failures show up as clean assertion errors instead of panics if anything ever regresses around optionality. Same pattern could apply tooriginalCustomer.UsageAttribution/updatedCustomer.UsageAttributionin the update tests, but it’s entirely a nicety, not a blocker.Also applies to: 124-201
e2e/multisubject_test.go (1)
36-63: E2E customer creation now matches pointer‑based APIPassing
UsageAttribution: &api.CustomerUsageAttribution{SubjectKeys: subjectKeys}in the E2E test lines up with the updated client model and still validates that the created customer comes back with both subjects wired. If you ever want slightly clearer failures here, you could add a quickrequire.NotNil(t, customer1.UsageAttribution)before asserting onSubjectKeys, but the current form is fine and will still catch regressions.openmeter/customer/customer.go (1)
166-178: Consider extracting shared validation logic.The validation logic here (lines 166-178) is nearly identical to
Customer.Validate()(lines 121-134). You could extract this into a helper function to reduce duplication and ensure both stay in sync.Something like:
func validateUsageAttributionRequirement(key *string, usageAttr *CustomerUsageAttribution) error { hasKey := key != nil && *key != "" hasSubjectKeys := usageAttr != nil && len(usageAttr.SubjectKeys) > 0 if !hasKey && !hasSubjectKeys { return models.NewGenericValidationError(errors.New("either key or usageAttribution.subjectKeys must be provided")) } if usageAttr != nil { if err := usageAttr.Validate(); err != nil { return err } } return nil }Not a blocker, but would make maintenance easier down the road.
openmeter/customer/service/hooks/subjectcustomer.go (1)
101-119: PostDelete nil‑safety looks good; consider tiny cleanupsThe new
mut.UsageAttribution != nilguard andsubjectKeysStrhandling make the delete flow safe when usage attribution is absent, which is exactly what we want now that it’s optional.Couple of small optional tweaks you might consider:
- If filtering leaves
SubjectKeysempty, you could setmut.UsageAttribution = nilto encode “no attribution” consistently and avoid carrying empty snapshots around.- The
"updated customer usage attribution"span event is emitted whenevercus != nil, even iferr != nilfromUpdateCustomer. Emitting it only whenerr == nilwould keep tracing more accurate.Nothing blocking here, just polish.
Also applies to: 120-128
test/billing/invoice_test.go (2)
59-80: Pointer UsageAttribution in tests looks right; one tiny robustness tweakUsing
UsageAttribution: &customer.CustomerUsageAttribution{...}on customer creation and matching it with an&billing.CustomerUsageAttribution{...}expectation keeps the tests aligned with the new pointer type and still verifies that invoice snapshots carry subject keys through.If you want slightly clearer failures in case the service ever stops returning attribution, you could add:
require.NotNil(s.T(), customerEntity.UsageAttribution)right before you read
customerEntity.UsageAttribution.SubjectKeysin the expected invoice; that way you’ll get a direct signal that attribution disappeared instead of a nil‑pointer panic.Also applies to: 295-307
2696-2715: UsageAttribution pointers in customer fixtures are consistent; consider a nil‑case testSwitching these customer fixtures to use
UsageAttribution: &customer.CustomerUsageAttribution{...}keeps them in sync with the new pointer type and continues to cover subject‑based customer scenarios end‑to‑end, which is great.If you want to really lock in the new behavior, you might add a focused test where:
- A customer is created with
UsageAttribution: nil(and onlyKeyset), and- You assert that invoice creation and
InvoiceCustomer.GetUsageAttribution()behave correctly (ID+Key populated,SubjectKeysempty, no panics).That would explicitly exercise the nil paths you just added in the production code.
Also applies to: 3217-3227, 3386-3395, 3506-3515
openmeter/billing/invoice.go (1)
623-649: NewInvoiceCustomer matches optional attribution, but consider cloning SubjectKeysThe new
NewInvoiceCustomernicely lines up with the optionalUsageAttributionchange: you only setic.UsageAttributionwhen the source customer has it, and the struct now uses a pointer withomitempty, which is what we want.One thing to be aware of: assigning
ic.UsageAttribution = &CustomerUsageAttribution{ SubjectKeys: cust.UsageAttribution.SubjectKeys, }copies the slice header but not the backing array, so if any code ever mutates
ic.UsageAttribution.SubjectKeys, it will also mutatecust.UsageAttribution.SubjectKeys. Given this is meant to be a snapshot, you might prefer to defensively deep‑copy:ic.UsageAttribution = &CustomerUsageAttribution{ SubjectKeys: slices.Clone(cust.UsageAttribution.SubjectKeys), }Only worth changing if invoice‑side code might mutate the slice, but it would make the “snapshot” guarantee airtight.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (14)
api/client/go/client.gen.gois excluded by!api/client/**api/client/javascript/src/client/schemas.tsis excluded by!api/client/**api/client/javascript/src/zod/index.tsis excluded by!api/client/**api/client/python/openmeter/_generated/models/_models.pyis excluded by!**/_generated/**,!api/client/**api/openapi.cloud.yamlis excluded by!**/openapi.cloud.yamlapi/openapi.yamlis excluded by!**/openapi.yamlgo.sumis excluded by!**/*.sum,!**/*.sumopenmeter/ent/db/billinginvoice/where.gois excluded by!**/ent/db/**openmeter/ent/db/billinginvoice_create.gois excluded by!**/ent/db/**openmeter/ent/db/billinginvoice_update.gois excluded by!**/ent/db/**openmeter/ent/db/migrate/schema.gois excluded by!**/ent/db/**openmeter/ent/db/mutation.gois excluded by!**/ent/db/**openmeter/ent/db/setorclear.gois excluded by!**/ent/db/**tools/migrate/migrations/atlas.sumis excluded by!**/*.sum,!**/*.sum
📒 Files selected for processing (61)
api/spec/src/customer/customer.tsp(2 hunks)e2e/entitlement_test.go(1 hunks)e2e/helpers.go(1 hunks)e2e/multisubject_test.go(1 hunks)e2e/productcatalog_test.go(5 hunks)openmeter/billing/adapter/invoice.go(3 hunks)openmeter/billing/httpdriver/invoice.go(1 hunks)openmeter/billing/httpdriver/invoice_test.go(1 hunks)openmeter/billing/invoice.go(1 hunks)openmeter/billing/service/lineservice/usagebasedline.go(1 hunks)openmeter/credit/driver/grant.go(1 hunks)openmeter/customer/adapter/customer.go(2 hunks)openmeter/customer/adapter/entitymapping.go(1 hunks)openmeter/customer/customer.go(3 hunks)openmeter/customer/httpdriver/apimapping.go(3 hunks)openmeter/customer/service/hooks/subjectcustomer.go(4 hunks)openmeter/customer/service/hooks/subjectcustomer_test.go(2 hunks)openmeter/customer/service/service_test.go(2 hunks)openmeter/ent/schema/billing.go(1 hunks)openmeter/entitlement/adapter/entitlement_test.go(1 hunks)openmeter/entitlement/balanceworker/entitlementhandler.go(2 hunks)openmeter/entitlement/balanceworker/recalculate.go(4 hunks)openmeter/entitlement/balanceworker/subject_customer.go(1 hunks)openmeter/entitlement/driver/parser.go(3 hunks)openmeter/entitlement/metered/grant_owner_adapter.go(1 hunks)openmeter/entitlement/metered/reset.go(1 hunks)openmeter/entitlement/metered/utils_test.go(1 hunks)openmeter/entitlement/service/utils_test.go(1 hunks)openmeter/entitlement/snapshot/event.go(2 hunks)openmeter/notification/internal/rule.go(1 hunks)openmeter/streaming/clickhouse/event_query_test.go(2 hunks)openmeter/streaming/clickhouse/event_query_v2_test.go(3 hunks)openmeter/streaming/clickhouse/meter_query_test.go(5 hunks)openmeter/subject/service/hooks/customersubject.go(1 hunks)openmeter/subject/service/hooks/customersubject_test.go(3 hunks)openmeter/subject/service/service_test.go(1 hunks)openmeter/subscription/addon/events_test.go(1 hunks)openmeter/subscription/service/service_test.go(4 hunks)openmeter/subscription/testutils/customer.go(1 hunks)openmeter/subscription/validators/customer/validator.go(2 hunks)openmeter/subscription/workflow/service/addon_test.go(1 hunks)test/app/custominvoicing/invocing_test.go(2 hunks)test/app/stripe/appstripe.go(2 hunks)test/app/stripe/fixture.go(1 hunks)test/app/stripe/invoice_test.go(3 hunks)test/billing/adapter_test.go(1 hunks)test/billing/collection_test.go(1 hunks)test/billing/customeroverride_test.go(7 hunks)test/billing/invoice_test.go(11 hunks)test/billing/subscription_test.go(1 hunks)test/billing/suite.go(1 hunks)test/customer/customer.go(20 hunks)test/customer/subject.go(7 hunks)test/entitlement/regression/framework_test.go(1 hunks)test/notification/consumer_balance.go(1 hunks)test/subscription/scenario_editaligned_test.go(1 hunks)test/subscription/scenario_editcancel_test.go(2 hunks)test/subscription/scenario_entinnextphase_test.go(1 hunks)test/subscription/scenario_firstofmonth_test.go(2 hunks)tools/migrate/migrations/20251210162410_make-customer-usage-attribution-optional.down.sql(1 hunks)tools/migrate/migrations/20251210162410_make-customer-usage-attribution-optional.up.sql(1 hunks)
🧰 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/credit/driver/grant.goopenmeter/entitlement/balanceworker/entitlementhandler.goopenmeter/billing/service/lineservice/usagebasedline.goopenmeter/subject/service/hooks/customersubject.goopenmeter/billing/httpdriver/invoice.goopenmeter/entitlement/service/utils_test.goopenmeter/entitlement/driver/parser.goopenmeter/entitlement/metered/reset.gotest/billing/collection_test.goopenmeter/subject/service/service_test.goopenmeter/subscription/addon/events_test.goopenmeter/subscription/workflow/service/addon_test.gotest/billing/suite.goopenmeter/customer/httpdriver/apimapping.goopenmeter/customer/service/service_test.gotest/subscription/scenario_editcancel_test.gotest/subscription/scenario_firstofmonth_test.gotest/entitlement/regression/framework_test.goopenmeter/streaming/clickhouse/event_query_v2_test.goopenmeter/customer/adapter/customer.goopenmeter/entitlement/metered/utils_test.goopenmeter/streaming/clickhouse/event_query_test.goopenmeter/subscription/testutils/customer.gotest/billing/adapter_test.gotest/subscription/scenario_entinnextphase_test.goopenmeter/subscription/service/service_test.goe2e/productcatalog_test.gotest/subscription/scenario_editaligned_test.gotest/customer/customer.goe2e/entitlement_test.goopenmeter/notification/internal/rule.gotest/app/stripe/fixture.goopenmeter/subscription/validators/customer/validator.goopenmeter/ent/schema/billing.goopenmeter/customer/service/hooks/subjectcustomer_test.gotest/billing/subscription_test.gotest/notification/consumer_balance.goe2e/multisubject_test.gotest/app/stripe/appstripe.gotest/app/custominvoicing/invocing_test.gotest/app/stripe/invoice_test.goe2e/helpers.goopenmeter/streaming/clickhouse/meter_query_test.goopenmeter/customer/adapter/entitymapping.goopenmeter/entitlement/snapshot/event.goopenmeter/customer/customer.gotest/billing/customeroverride_test.gotest/customer/subject.goopenmeter/entitlement/metered/grant_owner_adapter.goopenmeter/entitlement/adapter/entitlement_test.goopenmeter/billing/httpdriver/invoice_test.goopenmeter/entitlement/balanceworker/recalculate.goopenmeter/subject/service/hooks/customersubject_test.goopenmeter/billing/invoice.goopenmeter/customer/service/hooks/subjectcustomer.goopenmeter/entitlement/balanceworker/subject_customer.goopenmeter/billing/adapter/invoice.gotest/billing/invoice_test.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:
openmeter/entitlement/service/utils_test.gotest/billing/collection_test.goopenmeter/subject/service/service_test.goopenmeter/subscription/addon/events_test.goopenmeter/subscription/workflow/service/addon_test.goopenmeter/customer/service/service_test.gotest/subscription/scenario_editcancel_test.gotest/subscription/scenario_firstofmonth_test.gotest/entitlement/regression/framework_test.goopenmeter/streaming/clickhouse/event_query_v2_test.goopenmeter/entitlement/metered/utils_test.goopenmeter/streaming/clickhouse/event_query_test.gotest/billing/adapter_test.gotest/subscription/scenario_entinnextphase_test.goopenmeter/subscription/service/service_test.goe2e/productcatalog_test.gotest/subscription/scenario_editaligned_test.goe2e/entitlement_test.goopenmeter/customer/service/hooks/subjectcustomer_test.gotest/billing/subscription_test.goe2e/multisubject_test.gotest/app/custominvoicing/invocing_test.gotest/app/stripe/invoice_test.goopenmeter/streaming/clickhouse/meter_query_test.gotest/billing/customeroverride_test.goopenmeter/entitlement/adapter/entitlement_test.goopenmeter/billing/httpdriver/invoice_test.goopenmeter/subject/service/hooks/customersubject_test.gotest/billing/invoice_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 (5)
📓 Common learnings
Learnt from: chrisgacsal
Repo: openmeterio/openmeter PR: 2699
File: openmeter/productcatalog/planaddon/service/service_test.go:210-211
Timestamp: 2025-04-21T08:32:31.689Z
Learning: In `productcatalog.UsageBasedRateCard`, the `BillingCadence` field is a non-pointer `isodate.Period`, while in `productcatalog.FlatFeeRateCard`, `BillingCadence` is a pointer type (`*isodate.Period`). This means `MonthPeriod` should be used directly for `UsageBasedRateCard` (not `&MonthPeriod`).
📚 Learning: 2025-04-21T08:32:31.689Z
Learnt from: chrisgacsal
Repo: openmeterio/openmeter PR: 2699
File: openmeter/productcatalog/planaddon/service/service_test.go:210-211
Timestamp: 2025-04-21T08:32:31.689Z
Learning: In `productcatalog.UsageBasedRateCard`, the `BillingCadence` field is a non-pointer `isodate.Period`, while in `productcatalog.FlatFeeRateCard`, `BillingCadence` is a pointer type (`*isodate.Period`). This means `MonthPeriod` should be used directly for `UsageBasedRateCard` (not `&MonthPeriod`).
Applied to files:
openmeter/billing/service/lineservice/usagebasedline.goopenmeter/entitlement/service/utils_test.goopenmeter/entitlement/metered/reset.gotest/billing/collection_test.goopenmeter/subject/service/service_test.goopenmeter/subscription/addon/events_test.gotest/billing/suite.goopenmeter/customer/service/service_test.gotest/subscription/scenario_editcancel_test.gotest/subscription/scenario_firstofmonth_test.gotest/entitlement/regression/framework_test.goopenmeter/streaming/clickhouse/event_query_v2_test.goopenmeter/entitlement/metered/utils_test.goopenmeter/subscription/testutils/customer.gotest/billing/adapter_test.gotest/subscription/scenario_entinnextphase_test.goopenmeter/subscription/service/service_test.goe2e/productcatalog_test.gotest/subscription/scenario_editaligned_test.gotest/customer/customer.goe2e/entitlement_test.goopenmeter/notification/internal/rule.goopenmeter/ent/schema/billing.goopenmeter/customer/service/hooks/subjectcustomer_test.gotest/billing/subscription_test.gotest/notification/consumer_balance.gotest/app/custominvoicing/invocing_test.gotest/app/stripe/invoice_test.goopenmeter/streaming/clickhouse/meter_query_test.gotest/customer/subject.goopenmeter/entitlement/adapter/entitlement_test.goopenmeter/billing/httpdriver/invoice_test.goopenmeter/subject/service/hooks/customersubject_test.goopenmeter/billing/invoice.goopenmeter/billing/adapter/invoice.gotest/billing/invoice_test.go
📚 Learning: 2025-10-09T13:59:12.012Z
Learnt from: chrisgacsal
Repo: openmeterio/openmeter PR: 3486
File: openmeter/ingest/kafkaingest/serializer/serializer.go:105-107
Timestamp: 2025-10-09T13:59:12.012Z
Learning: In OpenMeter, the CloudEvents `subject` field is mandatory for the application's business logic, even though it's optional in the CloudEvents specification. The `ValidateKafkaPayloadToCloudEvent` function in `openmeter/ingest/kafkaingest/serializer/serializer.go` intentionally enforces this requirement.
Applied to files:
openmeter/subject/service/hooks/customersubject.goopenmeter/entitlement/driver/parser.goopenmeter/entitlement/snapshot/event.goopenmeter/entitlement/metered/grant_owner_adapter.goopenmeter/entitlement/balanceworker/recalculate.goopenmeter/customer/service/hooks/subjectcustomer.go
📚 Learning: 2025-03-07T12:17:43.129Z
Learnt from: GAlexIHU
Repo: openmeterio/openmeter PR: 2383
File: openmeter/entitlement/metered/lateevents_test.go:37-45
Timestamp: 2025-03-07T12:17:43.129Z
Learning: In the OpenMeter codebase, test files like `openmeter/entitlement/metered/lateevents_test.go` may use variables like `meterSlug` and `namespace` without explicit declarations visible in the same file. This appears to be an accepted pattern in their test structure.
Applied to files:
openmeter/entitlement/driver/parser.gotest/subscription/scenario_firstofmonth_test.goopenmeter/entitlement/metered/utils_test.goopenmeter/streaming/clickhouse/meter_query_test.go
📚 Learning: 2025-08-29T12:31:52.802Z
Learnt from: chrisgacsal
Repo: openmeterio/openmeter PR: 3291
File: app/common/customer.go:88-89
Timestamp: 2025-08-29T12:31:52.802Z
Learning: In Go projects using Google's wire dependency injection framework, named types (without =) should be used instead of type aliases (with =) to work around wire limitations. For example, use `type CustomerSubjectValidatorHook customerservicehooks.SubjectValidatorHook` instead of `type CustomerSubjectValidatorHook = customerservicehooks.SubjectValidatorHook` when wire is involved.
Applied to files:
openmeter/customer/service/hooks/subjectcustomer_test.goopenmeter/subject/service/hooks/customersubject_test.go
🧬 Code graph analysis (51)
openmeter/billing/service/lineservice/usagebasedline.go (3)
openmeter/customer/customer.go (1)
Customer(41-53)openmeter/streaming/query_params.go (1)
Customer(84-86)api/api.gen.go (1)
Customer(2223-2275)
openmeter/subject/service/hooks/customersubject.go (1)
pkg/models/errors.go (1)
NewGenericValidationError(138-140)
openmeter/billing/httpdriver/invoice.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/entitlement/service/utils_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/entitlement/driver/parser.go (2)
openmeter/customer/customer.go (1)
Customer(41-53)api/api.gen.go (1)
Customer(2223-2275)
openmeter/entitlement/metered/reset.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (2)
CustomerUsageAttribution(237-239)Customer(41-53)api/api.gen.go (2)
CustomerUsageAttribution(2417-2421)Customer(2223-2275)
test/billing/collection_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/subject/service/service_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/subscription/addon/events_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/subscription/workflow/service/addon_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/billing/suite.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/customer/service/service_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/subscription/scenario_editcancel_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/subscription/scenario_firstofmonth_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/entitlement/regression/framework_test.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/streaming/clickhouse/event_query_v2_test.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/entitlement/metered/utils_test.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/streaming/clickhouse/event_query_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/subscription/testutils/customer.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/billing/adapter_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/subscription/scenario_entinnextphase_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/subscription/service/service_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
e2e/productcatalog_test.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/subscription/scenario_editaligned_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/customer/customer.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
e2e/entitlement_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/notification/internal/rule.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/app/stripe/fixture.go (1)
openmeter/customer/customer.go (2)
CreateCustomerInput(351-354)CustomerMutate(139-149)
openmeter/subscription/validators/customer/validator.go (1)
openmeter/customer/customer.go (1)
CustomerMutate(139-149)
openmeter/ent/schema/billing.go (1)
openmeter/billing/invoice.go (1)
VersionedCustomerUsageAttribution(612-615)
openmeter/customer/service/hooks/subjectcustomer_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/billing/subscription_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/notification/consumer_balance.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
e2e/multisubject_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/app/stripe/appstripe.go (4)
openmeter/customer/customer.go (3)
Customer(41-53)CreateCustomerInput(351-354)CustomerMutate(139-149)app/common/customer.go (1)
Customer(23-25)api/api.gen.go (1)
Customer(2223-2275)openmeter/ent/schema/customer.go (5)
Customer(17-19)Customer(21-29)Customer(31-39)Customer(41-54)Customer(56-69)
test/app/custominvoicing/invocing_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
test/app/stripe/invoice_test.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
e2e/helpers.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/streaming/clickhouse/meter_query_test.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/customer/customer.go (2)
openmeter/streaming/query_params.go (2)
CustomerUsageAttribution(89-93)Customer(84-86)api/api.gen.go (2)
CustomerUsageAttribution(2417-2421)Customer(2223-2275)
test/billing/customeroverride_test.go (1)
openmeter/customer/customer.go (2)
CreateCustomerInput(351-354)CustomerMutate(139-149)
test/customer/subject.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/entitlement/metered/grant_owner_adapter.go (3)
openmeter/customer/customer.go (1)
Customer(41-53)openmeter/streaming/query_params.go (1)
Customer(84-86)api/api.gen.go (1)
Customer(2223-2275)
openmeter/entitlement/adapter/entitlement_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/billing/httpdriver/invoice_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/entitlement/balanceworker/recalculate.go (4)
app/common/subject.go (1)
Subject(18-21)openmeter/ent/schema/subject.go (5)
Subject(14-16)Subject(19-30)Subject(33-39)Subject(42-63)Subject(66-68)api/api.gen.go (1)
Subject(6957-6991)openmeter/subject/subject.go (1)
Subject(10-20)
openmeter/subject/service/hooks/customersubject_test.go (3)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/billing/invoice.go (3)
openmeter/customer/customer.go (3)
Customer(41-53)CustomerID(184-184)CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (2)
Customer(84-86)CustomerUsageAttribution(89-93)api/api.gen.go (3)
Customer(2223-2275)CustomerUsageAttribution(2417-2421)Address(1017-1038)
openmeter/customer/service/hooks/subjectcustomer.go (2)
openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
openmeter/entitlement/balanceworker/subject_customer.go (8)
openmeter/customer/customer.go (3)
Customer(41-53)GetCustomerInput(390-397)CustomerID(184-184)app/common/customer.go (1)
Customer(23-25)api/api.gen.go (2)
Customer(2223-2275)Subject(6957-6991)app/common/subject.go (1)
Subject(18-21)openmeter/ent/schema/subject.go (5)
Subject(14-16)Subject(19-30)Subject(33-39)Subject(42-63)Subject(66-68)app/common/namespace.go (1)
Namespace(13-15)pkg/models/errors.go (1)
NewGenericNotFoundError(38-40)pkg/models/key.go (1)
NamespacedKey(5-8)
test/billing/invoice_test.go (4)
openmeter/billing/invoice.go (1)
CustomerUsageAttribution(611-611)openmeter/customer/customer.go (1)
CustomerUsageAttribution(237-239)openmeter/streaming/query_params.go (1)
CustomerUsageAttribution(89-93)api/api.gen.go (1)
CustomerUsageAttribution(2417-2421)
⏰ 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: Test
- GitHub Check: Migration Checks
- GitHub Check: Lint
- GitHub Check: Code Generators
- GitHub Check: Build
- GitHub Check: Repository Scan
- GitHub Check: Analyze (go)
Overview
Since we can query usage based on only customerKey, it is no longer needed for UsageAttribution to be required
Summary by CodeRabbit
New Features
Improvements
Database Changes
✏️ Tip: You can customize this high-level summary in your review settings.