Skip to content

feat(api): add v3 customer and subscription list filters#4336

Merged
tothandras merged 1 commit into
mainfrom
feat/v3-customer-subscription-api-improvements
May 11, 2026
Merged

feat(api): add v3 customer and subscription list filters#4336
tothandras merged 1 commit into
mainfrom
feat/v3-customer-subscription-api-improvements

Conversation

@tothandras
Copy link
Copy Markdown
Contributor

@tothandras tothandras commented May 11, 2026

Summary by CodeRabbit

Release Notes

  • New Features
    • Extended customer list filtering with usage_attribution_subject_key, plan_key, and billing_profile_id parameters
    • Added plan_key filter support to subscription list endpoint
    • Improved filtering precision for both endpoints with enhanced query parameter validation

Review Change Stack

@tothandras tothandras requested a review from a team as a code owner May 11, 2026 10:47
@tothandras tothandras added the release-note/feature Release note: Exciting New Features label May 11, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

📝 Walkthrough

Walkthrough

This PR expands customer and subscription list operations with new filter capabilities while modernizing filtering logic. It introduces plan_key, billing_profile_id, and usage_attribution_subject_key filters for customers, and refactors all subscription/customer queries to use typed filter objects instead of raw CustomerIDs slices.

Changes

Customer and Subscription Filter Expansion

Layer / File(s) Summary
API Specification Schema
api/spec/packages/aip/src/customers/operations.tsp, api/spec/packages/aip/src/subscriptions/operations.tsp
TypeSpec adds ListSubscriptionsParamsFilter model with customer_id and plan_key filters; extends ListCustomersParamsFilter with usage_attribution_subject_key, plan_key, and billing_profile_id filters.
Generated API Types
api/v3/api.gen.go
Generated Go models add ListSubscriptionsParamsFilter struct and extend ListCustomersParamsFilter with BillingProfileId, PlanKey, and UsageAttributionSubjectKey optional filter fields.
Core Service Input Models
openmeter/customer/customer.go, openmeter/subscription/list.go
ListCustomersInput replaces Subject *string with UsageAttributionSubjectKey *filter.FilterString, converts PlanKey to typed filter, and adds BillingProfileID *filter.FilterULID; ListSubscriptionsInput replaces CustomerIDs []string with CustomerID *filter.FilterULID and adds PlanKey *filter.FilterString. Both add validation for new filters.
API Request Handlers
api/v3/handlers/customers/list.go, api/v3/handlers/subscriptions/list.go
Handlers parse and validate new filter fields from query parameters with per-field error reporting; route parsed filters into service input models.
HTTP Driver Filtering
openmeter/customer/httpdriver/customer.go
Introduces eqFilter helper for exact-match string filters; updates ListCustomers to apply PlanKey with equality semantics; refactors subscription prefetch to use CustomerID filter with Eq condition instead of CustomerIDs slice.
Customer Adapter Query Logic
openmeter/customer/adapter/customer.go
Extends ListCustomers to conditionally apply PlanKey predicate filters on active subscriptions, UsageAttributionSubjectKey filters via customer subjects, and BillingProfileID filters via billing overrides; updates applyActiveSubscriptionFilterWithPlanKey to build plan predicates dynamically.
Repository Query Construction
openmeter/subscription/repo/subscriptionrepo.go, openmeter/productcatalog/subscription/http/get.go
Updates List query to use filter.ApplyToQuery for typed CustomerID filter and filter.SelectPredicate for PlanKey plan predicate; all subscription queries now use typed filters.
Service Call Sites
openmeter/billing/validators/customer/customer.go, openmeter/billing/worker/subscriptionsync/reconciler/reconciler.go, openmeter/subscription/validators/..., openmeter/subscription/workflow/service/subscription.go
All subscription list queries across billing validators, subscription validators, reconcilers, and workflow services refactored to use CustomerID filter with Eq or "IN" conditions instead of CustomerIDs slice.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • openmeterio/openmeter#4301: Introduces the underlying AIP field filter type changes (StringFieldFilter, ULIDFieldFilter variants) that this PR builds upon and uses throughout the new customer/subscription filter expansions.

Suggested labels

area/api, area/subscriptions

Suggested reviewers

  • turip
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding new filter options to the v3 customer and subscription list endpoints, which is the primary focus across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/v3-customer-subscription-api-improvements

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
Copy Markdown
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/adapter/customer.go (1)

79-89: 💤 Low value

Consider whether billing overrides should support delayed deletion like subject keys do.

The BillingProfileID filter uses DeletedAtIsNil() for soft-delete filtering, while UsageAttributionSubjectKey uses DeletedAtIsNil() || DeletedAtGTE(now). The subjects pattern allows records marked for future deletion to remain visible until that date passes. If billing overrides should support the same delayed-deletion feature, align the filters for consistency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openmeter/customer/adapter/customer.go` around lines 79 - 89, The
BillingProfileID filter currently only uses
billingcustomeroverridedb.DeletedAtIsNil() which excludes records scheduled for
future deletion; to match the UsageAttributionSubjectKey behavior, update the
predicate in the customer query (the block using
filter.SelectPredicate[predicate.BillingCustomerOverride] and
billingcustomeroverridedb.FieldBillingProfileID) to allow records with DeletedAt
== nil OR DeletedAt >= now—i.e., replace the single DeletedAtIsNil() condition
with a combined condition like billingcustomeroverridedb.DeletedAtIsNil() ||
billingcustomeroverridedb.DeletedAtGTE(time.Now()) so billing overrides support
delayed deletion the same way subject keys do.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@openmeter/billing/worker/subscriptionsync/reconciler/reconciler.go`:
- Around line 106-107: The CustomerID filter is always constructed even when
in.Customers is empty; change the code that builds the filter object so that the
CustomerID field is only set when len(in.Customers) > 0 (i.e., create
&filter.FilterULID{FilterString{In: &in.Customers}} only inside that
conditional), otherwise leave CustomerID nil; update the block where Namespaces
and CustomerID are assigned (the code that currently uses CustomerID:
&filter.FilterULID{FilterString: filter.FilterString{In: &in.Customers}}) to
perform this conditional assignment so downstream ApplyToQuery sees nil instead
of a pointer to an empty slice.

---

Nitpick comments:
In `@openmeter/customer/adapter/customer.go`:
- Around line 79-89: The BillingProfileID filter currently only uses
billingcustomeroverridedb.DeletedAtIsNil() which excludes records scheduled for
future deletion; to match the UsageAttributionSubjectKey behavior, update the
predicate in the customer query (the block using
filter.SelectPredicate[predicate.BillingCustomerOverride] and
billingcustomeroverridedb.FieldBillingProfileID) to allow records with DeletedAt
== nil OR DeletedAt >= now—i.e., replace the single DeletedAtIsNil() condition
with a combined condition like billingcustomeroverridedb.DeletedAtIsNil() ||
billingcustomeroverridedb.DeletedAtGTE(time.Now()) so billing overrides support
delayed deletion the same way subject keys do.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3fe3bd45-cba4-49f9-b67f-11a6df3e42b2

📥 Commits

Reviewing files that changed from the base of the PR and between 10999a2 and 7856cae.

⛔ Files ignored due to path filters (1)
  • api/v3/openapi.yaml is excluded by !**/openapi.yaml
📒 Files selected for processing (16)
  • api/spec/packages/aip/src/customers/operations.tsp
  • api/spec/packages/aip/src/subscriptions/operations.tsp
  • api/v3/api.gen.go
  • api/v3/handlers/customers/list.go
  • api/v3/handlers/subscriptions/list.go
  • openmeter/billing/validators/customer/customer.go
  • openmeter/billing/worker/subscriptionsync/reconciler/reconciler.go
  • openmeter/customer/adapter/customer.go
  • openmeter/customer/customer.go
  • openmeter/customer/httpdriver/customer.go
  • openmeter/productcatalog/subscription/http/get.go
  • openmeter/subscription/list.go
  • openmeter/subscription/repo/subscriptionrepo.go
  • openmeter/subscription/validators/customer/validator.go
  • openmeter/subscription/validators/subscription/validator.go
  • openmeter/subscription/workflow/service/subscription.go

Comment thread openmeter/billing/worker/subscriptionsync/reconciler/reconciler.go
Comment thread openmeter/customer/adapter/customer.go
Comment thread api/spec/packages/aip/src/customers/operations.tsp
@tothandras tothandras merged commit b70d40e into main May 11, 2026
36 of 37 checks passed
@tothandras tothandras deleted the feat/v3-customer-subscription-api-improvements branch May 11, 2026 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/feature Release note: Exciting New Features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants