Skip to content

feat: Next generation Stripe billing integration#2161

Open
niemyjski wants to merge 62 commits intomainfrom
feature/next-stripe
Open

feat: Next generation Stripe billing integration#2161
niemyjski wants to merge 62 commits intomainfrom
feature/next-stripe

Conversation

@niemyjski
Copy link
Copy Markdown
Member

Summary

  • Adds new Stripe billing components: ChangePlanDialog and StripeProvider
  • Implements Stripe Checkout session creation via API
  • Adds billing features to organization API: getBilling, changePlan, getInvoices
  • Updates billing pages to use new components
  • Updates organization and invoice mappers
  • Adds Stripe integration plan document

Changes

  • New Svelte components for Stripe integration
  • New backend endpoints for billing management
  • Updated usage pages to show billing info

- Upgrade Stripe.net to v50.4.1 and update the backend to support modern PaymentMethods while maintaining legacy token compatibility.
- Implement a new billing feature in the Svelte UI with lazy-loaded Stripe integration and a functional plan change dialog.
- Add TanStack Query hooks for fetching available plans and processing plan changes with coupon support.
Copilot AI review requested due to automatic review settings March 17, 2026 03:14
@niemyjski niemyjski force-pushed the feature/next-stripe branch from 985add7 to ee79cb9 Compare March 17, 2026 03:15
@niemyjski niemyjski self-assigned this Mar 17, 2026
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Fixed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a “next generation” Stripe billing integration spanning backend Stripe.net v50 updates, new billing endpoints/DTO mapping, and a new Svelte 5 billing UI (Stripe provider + change-plan dialog) wired into organization/project usage and billing pages.

Changes:

  • Upgrades Stripe.net usage on the backend (invoice status handling, discounts, subscription updates, PaymentMethod support).
  • Adds a new Svelte billing feature module (StripeProvider, ChangePlanDialog) and hooks it into usage/billing routes.
  • Extends org client API with plan query + change-plan mutation; updates invoice mapping/tests accordingly.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Exceptionless.Tests/Mapping/InvoiceMapperTests.cs Updates Stripe invoice test data to use Status instead of Paid.
tests/Exceptionless.Tests/Controllers/TokenControllerTests.cs Simplifies test comments (no functional change).
src/Exceptionless.Web/Mapping/InvoiceMapper.cs Maps “paid” via Invoice.Status string comparison.
src/Exceptionless.Web/Controllers/OrganizationController.cs Updates Stripe invoice retrieval/discount handling and modernizes change-plan flow to support PaymentMethods + Stripe.net 50 API changes.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte “Change plan” now navigates to the org billing page.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte “Change plan” now navigates to the org billing page.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/billing/+page.svelte Uses new billing module ChangePlanDialog and passes loaded org data into it.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/components/dialogs/change-plan-dialog.svelte Removes the legacy placeholder change-plan dialog component.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Adds getPlansQuery() and changePlanMutation() + related query keys/types.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/stripe.svelte.ts Adds Stripe context + lazy singleton loader utilities.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/schemas.ts Adds zod schema/types for the change-plan form.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/models.ts Adds billing model re-exports + local billing form/params types.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/index.ts Barrel exports for billing feature module.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/constants.ts Defines FREE_PLAN_ID.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/stripe-provider.svelte Adds Stripe Elements provider wrapper with loading/error states.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.svelte Implements the plan change dialog UI including Stripe payment collection.
src/Exceptionless.Web/ClientApp/package.json Adds Stripe JS + svelte-stripe dependencies.
src/Exceptionless.Web/ClientApp/package-lock.json Locks Stripe JS + svelte-stripe dependencies.
src/Exceptionless.Web/ClientApp/STRIPE-INTEGRATION-PLAN.md Adds the Stripe integration plan document.
src/Exceptionless.Core/Exceptionless.Core.csproj Upgrades Stripe.net to 50.4.1.
.claude/agents/engineer.md Adds guidance for rerunning flaky CI jobs via gh run rerun.
Files not reviewed (1)
  • src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Copilot AI review requested due to automatic review settings April 16, 2026 04:09
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a “next generation” Stripe billing integration across the backend (Stripe.net 50.x) and the Svelte client, enabling plan selection/changes and invoice display with the updated Stripe API surface.

Changes:

  • Upgrades Stripe.net to 50.4.1 and updates invoice/plan-change logic to use Status, Price, Discounts, and PaymentMethod APIs.
  • Adds a new client-side billing feature module (Stripe context/provider + change plan dialog) and wires it into usage/billing pages.
  • Adds client API helpers for fetching plans and performing plan changes, with cache invalidation.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tests/Exceptionless.Tests/Mapping/InvoiceMapperTests.cs Updates invoice mapping tests to reflect Stripe Status replacing Paid.
tests/Exceptionless.Tests/Controllers/TokenControllerTests.cs Simplifies test comments (no functional change).
src/Exceptionless.Web/Mapping/InvoiceMapper.cs Switches paid logic to derive from Invoice.Status.
src/Exceptionless.Web/Controllers/OrganizationController.cs Updates invoice retrieval and plan change flows for Stripe.net 50.x (Price/Discounts/PaymentMethod changes).
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte Replaces placeholder “change plan” handler with navigation to billing page.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte Same as above for org usage page.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/billing/+page.svelte Switches to the new billing module’s ChangePlanDialog and passes organization data.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/components/dialogs/change-plan-dialog.svelte Removes the old placeholder change-plan dialog component.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Adds getPlansQuery + changePlanMutation and associated query keys/types.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/stripe.svelte.ts Adds Stripe context utilities and a singleton Stripe loader.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/schemas.ts Adds Zod schema for the change-plan form.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/models.ts Adds billing-focused types and re-exports generated API models.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/index.ts Exposes billing module public API (components/hooks/constants/types).
src/Exceptionless.Web/ClientApp/src/lib/features/billing/constants.ts Introduces FREE_PLAN_ID.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/stripe-provider.svelte Adds a Stripe <Elements> provider and sets Stripe context for children.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.svelte Implements the new plan change UX using Stripe PaymentElement + plans query + mutation.
src/Exceptionless.Web/ClientApp/package.json Adds @stripe/stripe-js and svelte-stripe.
src/Exceptionless.Web/ClientApp/package-lock.json Locks new Stripe dependencies.
src/Exceptionless.Core/Exceptionless.Core.csproj Upgrades Stripe.net from 47.4.0 to 50.4.1.
Files not reviewed (1)
  • src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Exceptionless.Web/Mapping/InvoiceMapper.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs
Comment thread src/Exceptionless.Web/ClientApp/src/lib/features/billing/stripe.svelte.ts Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs
Copilot AI review requested due to automatic review settings April 16, 2026 05:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new Stripe-based billing UX in the Svelte app and updates the backend Stripe integration to newer Stripe.net APIs, alongside some infra/telemetry adjustments.

Changes:

  • Adds new billing feature module on the frontend (Stripe provider + change-plan dialog) and wires it into usage/billing pages.
  • Updates backend invoice/payment handling to Stripe.net 50.x patterns (invoice status, discounts, line item pricing/price lookup).
  • Updates dependencies/config (Stripe.net upgrade, adds @stripe/stripe-js + svelte-stripe, adjusts OpenTelemetry Prometheus wiring and deploy workflow conditions).

Reviewed changes

Copilot reviewed 25 out of 26 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
tests/Exceptionless.Tests/Mapping/InvoiceMapperTests.cs Updates invoice mapping tests to use Status instead of Paid.
tests/Exceptionless.Tests/Controllers/TokenControllerTests.cs Simplifies test comments (no functional change).
src/Exceptionless.Web/Startup.cs Removes Prometheus scraping endpoint middleware.
src/Exceptionless.Web/Mapping/InvoiceMapper.cs Maps Paid from Invoice.Status == "paid".
src/Exceptionless.Web/Exceptionless.Web.csproj Removes Prometheus exporter package reference; formatting changes.
src/Exceptionless.Web/Controllers/OrganizationController.cs Updates invoice and plan-change flows for Stripe.net 50.x (prices/discounts/payment methods).
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte Navigates to org billing page with changePlan=true.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte Navigates to org billing page with changePlan=true.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/billing/+page.svelte Switches to new billing ChangePlanDialog and passes organization data.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/components/dialogs/change-plan-dialog.svelte Deletes placeholder dialog (replaced by billing feature).
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Adds plans query + change-plan mutation/query keys.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/stripe.svelte.ts Adds Stripe context + lazy loader utilities.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/schemas.ts Adds Zod schema for change-plan form.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/models.ts Adds billing types and form state types.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/index.ts Adds billing feature barrel exports.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/constants.ts Adds FREE_PLAN_ID constant.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/stripe-provider.svelte Adds Stripe Elements provider component.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.svelte Adds new Stripe-backed change-plan dialog UI.
src/Exceptionless.Web/ClientApp/package.json Adds Stripe JS dependencies.
src/Exceptionless.Web/ClientApp/package-lock.json Locks Stripe JS dependencies.
src/Exceptionless.Web/ApmExtensions.cs Removes Prometheus exporter from OpenTelemetry metrics pipeline.
src/Exceptionless.Job/Program.cs Removes Prometheus scraping endpoint middleware from job host.
src/Exceptionless.Job/Exceptionless.Job.csproj Removes Prometheus exporter package reference; formatting changes.
src/Exceptionless.Core/Exceptionless.Core.csproj Upgrades Stripe.net from 47.4.0 to 50.4.1; formatting changes.
.vscode/settings.json Updates workspace editor/TypeScript SDK settings.
.github/workflows/build.yaml Updates deploy job condition to allow dev deploys from a configured PR branch.
Files not reviewed (1)
  • src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Exceptionless.Job/Program.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Comment thread src/Exceptionless.Web/Startup.cs
Comment thread src/Exceptionless.Web/ApmExtensions.cs
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Copilot AI review requested due to automatic review settings April 16, 2026 15:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a next-generation Stripe-based billing flow across the Svelte app and the organization API, updating both frontend plan-change UX and backend Stripe integration to newer Stripe.net APIs.

Changes:

  • Adds a new Billing feature module (Stripe context/provider + ChangePlanDialog) and wires it into the organization billing page and usage pages.
  • Updates backend Stripe integration (Stripe.net 50.x) for invoice/payment/plan handling and updates invoice mapping/tests accordingly.
  • Updates build/ops tooling (Docker MinVer build arg, workflow tweaks) and removes Prometheus OpenTelemetry exporter/scraping.

Reviewed changes

Copilot reviewed 26 out of 27 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/Exceptionless.Tests/Mapping/InvoiceMapperTests.cs Updates tests to reflect invoice Status -> paid mapping.
tests/Exceptionless.Tests/Controllers/TokenControllerTests.cs Simplifies test comments (no behavior change).
src/Exceptionless.Web/Startup.cs Removes OTEL Prometheus scraping endpoint middleware.
src/Exceptionless.Web/Mapping/InvoiceMapper.cs Maps invoice “paid” from Stripe Status instead of Paid.
src/Exceptionless.Web/Exceptionless.Web.csproj Removes Prometheus exporter package + formatting changes.
src/Exceptionless.Web/Controllers/OrganizationController.cs Updates Stripe invoice/plan change logic for Stripe.net 50.x and PaymentMethod support.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte Implements navigation to billing page on “Change plan”.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte Implements navigation to billing page on “Change plan”.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/billing/+page.svelte Switches to new billing ChangePlanDialog component and passes organization data.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/components/dialogs/change-plan-dialog.svelte Removes placeholder dialog from organizations feature.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Adds plans query + change-plan mutation and query keys.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/stripe.svelte.ts Adds Stripe lazy-loader + context hooks.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/schemas.ts Adds Zod schema for change-plan form.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/models.ts Adds billing feature types and re-exports generated API types.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/index.ts Public entrypoint for billing feature exports.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/constants.ts Adds FREE plan id constant.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/stripe-provider.svelte Adds provider wrapping Stripe Elements + loading/error UI.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.svelte Adds full Stripe Elements-based plan change dialog.
src/Exceptionless.Web/ClientApp/package.json Adds Stripe JS dependencies.
src/Exceptionless.Web/ClientApp/package-lock.json Locks Stripe JS dependencies.
src/Exceptionless.Web/ApmExtensions.cs Removes Prometheus exporter wiring.
src/Exceptionless.Job/Program.cs Removes OTEL Prometheus scraping endpoint middleware.
src/Exceptionless.Job/Exceptionless.Job.csproj Removes Prometheus exporter package + formatting changes.
src/Exceptionless.Core/Exceptionless.Core.csproj Upgrades Stripe.net to 50.4.1.
Dockerfile Adds MinVerVersionOverride build arg passthrough.
.vscode/settings.json Disables format-on-save and changes TypeScript SDK path setting key.
.github/workflows/build.yaml Ensures checkout uses correct ref and passes MinVer build arg into Docker builds; expands deploy conditions.
Files not reviewed (1)
  • src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .vscode/settings.json Outdated
Comment thread src/Exceptionless.Web/Controllers/OrganizationController.cs Outdated
Comment thread src/Exceptionless.Web/ApmExtensions.cs
Comment thread src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Outdated
Comment thread src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Outdated
niemyjski and others added 5 commits April 18, 2026 10:22
Stripe v9 requires either clientSecret OR mode when calling stripe.elements().
The previous code passed neither when no clientSecret was provided, causing
PaymentElement to fail to render.

Uses a discriminated union Props type to enforce mutual exclusivity of
clientSecret and mode at compile time, matching Stripe's own type constraints.
Defaults to mode='setup' for collecting payment methods for future use.
Fix two issues preventing the Stripe PaymentElement from rendering in
the Change Plan dialog:

1. Missing currency in Stripe Elements options: Stripe.js v9+ requires
   a currency string when using mode: 'setup'. Added currency: 'usd'
   to the elements creation options.

2. svelte-stripe Svelte 5 incompatibility: svelte-stripe's <Elements>
   and <PaymentElement> components use $bindable()/onMount patterns
   that don't trigger Svelte 5 template re-renders from async callbacks.
   Replaced both components with an imperative approach that loads Stripe,
   creates elements, and mounts the PaymentElement directly to the DOM
   via onMount, bypassing Svelte's reactive template system entirely.

Additionally fixed the Change Plan dialog not being scrollable by adding
max-h-[90vh] and overflow-y-auto to the Dialog.Content wrapper.

Changes:
- stripe-provider.svelte: Rewritten to imperatively mount PaymentElement
  without svelte-stripe components or Svelte reactive conditionals
- change-plan-dialog.svelte: Removed svelte-stripe PaymentElement import,
  updated StripeProvider usage (no longer takes children), added dialog
  scroll constraints, removed debug markup

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… response check

- stripe-provider: use braces on if (disposed) guard blocks
- billing page: rename _success param to success
- api.svelte: remove redundant !response.ok throw (fetchclient handles this)
- Integrate UpgradeRequiredDialog into app layout via upgradeRequiredDialog store
- Replace handleUpgradeRequired with showUpgradeDialogIfNeeded on all pages
- Usage pages open billing dialog directly instead of navigating away
- Add Stripe context helpers (loadStripeOnce, retry-on-null)
Comment on lines +1 to +18
/**
* Billing feature module - Stripe integration for plan management.
*/

// Components
export { default as ChangePlanDialog } from './components/change-plan-dialog.svelte';

export { default as StripeProvider } from './components/stripe-provider.svelte';

// Upgrade required handling
export { default as UpgradeRequiredDialog } from './components/upgrade-required-dialog.svelte';

// Constants
export { FREE_PLAN_ID } from './constants';
// Models
export type { BillingPlan, CardMode, ChangePlanFormState, ChangePlanRequest, ChangePlanResult } from './models';

// Context and hooks
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

remove these stupid comments

import { resolve } from '$app/paths';
import Button from '$comp/ui/button/button.svelte';
import * as DropdownMenu from '$comp/ui/dropdown-menu';
import { handleUpgradeRequired } from '$features/billing';
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

better name for this, also what about the message

Comment on lines +38 to +42
onMount(() => {
loadStripeOnce()
.then((stripe) => {
if (disposed) {
return;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

does this follow best practices?

Comment on lines +97 to +98
}
return ctx;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Suggested change
}
return ctx;
}
return ctx;

Comment on lines +179 to +182
if (!response.ok) {
throw response.problem;
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think this is needed

);
//await confirmUpgradePlan(message, tack.organization_id);
//await promoteToExternal();
showUpgradeDialogIfNeeded(response.problem, stack.organization_id, () => promoteToExternal());
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

what about the custom error message?

Comment on lines +226 to +228
if (clientResponse.problem) {
showUpgradeDialogIfNeeded(clientResponse.problem, organization.current, () => loadData());
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

do we still need this if?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a “next generation” Stripe billing flow across the ASP.NET Core API and the Svelte 5 client, including plan selection, upgrade-required UX, and Stripe SDK upgrades.

Changes:

  • Upgrade Stripe integration (Stripe.net v51, Stripe.js v9) and update invoice/plan mapping accordingly.
  • Add new billing UI module in Svelte (plan change dialog, Stripe provider, upgrade-required dialog) and wire it into key app pages.
  • Extend organization billing APIs/docs/tests (plans listing, change-plan JSON body + legacy query support, invoices).

Reviewed changes

Copilot reviewed 47 out of 53 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/http/organizations.http Adds preferred JSON-body change-plan request + legacy query example.
tests/Exceptionless.Tests/Mapping/InvoiceMapperTests.cs Updates tests to use Invoice.Status instead of removed Paid.
tests/Exceptionless.Tests/Controllers/TokenControllerTests.cs Comment/structure tweaks in tests (arrange/act/assert).
tests/Exceptionless.Tests/Controllers/OrganizationControllerTests.cs Adds integration coverage for plans + billing-disabled behaviors and downgrade checks.
tests/Exceptionless.Tests/Controllers/Data/openapi.json Documents change-plan requestBody and adds ChangePlanRequest schema.
src/Exceptionless.Web/Program.cs Adds optional appsettings.Local.yml to config sources.
src/Exceptionless.Web/Models/ChangePlanRequest.cs Introduces request model for JSON body plan changes.
src/Exceptionless.Web/Mapping/InvoiceMapper.cs Maps invoice “paid” from Status == paid.
src/Exceptionless.Web/Exceptionless.Web.csproj Formatting-only change.
src/Exceptionless.Web/Controllers/OrganizationController.cs Implements JSON body + legacy query support for change-plan; updates invoice retrieval for Stripe.net v51; adds plans endpoint behavior changes.
src/Exceptionless.Web/ClientApp/src/routes/+layout.svelte Treats HTTP 426 as a non-retriable status in the layout’s status handling.
src/Exceptionless.Web/ClientApp/src/routes/(app)/stream/+page.svelte Adds centralized 426 handling + typed ProblemDetails for stream page flows.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/add/+page.svelte Adds upgrade-required handling for project creation failures.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte Implements “Change plan” navigation into new billing page.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/integrations/+page.svelte Adds upgrade-required handling for webhook + Slack integration actions.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/add/+page.svelte Adds upgrade-required handling for org creation failures.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/users/+page.svelte Adds upgrade-required handling for user invite failures.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte Implements “Change plan” navigation into new billing page.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/billing/+page.svelte Switches billing page to new ChangePlanDialog from billing feature module; fixes Stripe invoice URL encoding.
src/Exceptionless.Web/ClientApp/src/routes/(app)/issues/+page.svelte Adds centralized 426 handling + typed ProblemDetails for issues page.
src/Exceptionless.Web/ClientApp/src/routes/(app)/event/[eventId]/+page.svelte Replaces TODO 426 handling with shared upgrade-required handler.
src/Exceptionless.Web/ClientApp/src/routes/(app)/account/notifications/+page.svelte Adds proactive “show upgrade dialog” behavior for premium notifications.
src/Exceptionless.Web/ClientApp/src/routes/(app)/+page.svelte Adds centralized 426 handling + typed ProblemDetails for events dashboard page.
src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte Mounts UpgradeRequiredDialog and passes premium-needed state into org notifications.
src/Exceptionless.Web/ClientApp/src/lib/generated/schemas.ts Adds ChangePlanRequest schema; adjusts several generated schema shapes.
src/Exceptionless.Web/ClientApp/src/lib/generated/api.ts Adds ChangePlanRequest type; adjusts several generated API types.
src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/stack-options-dropdown-menu.svelte Uses shared upgrade-required handler for premium “promote external” action.
src/Exceptionless.Web/ClientApp/src/lib/features/projects/components/user-notification-settings-form.svelte Allows upgrade callback to be sync or async.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/components/dialogs/change-plan-dialog.svelte Removes legacy placeholder change-plan dialog component.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Adds plans query + change-plan mutation APIs + query keys.
src/Exceptionless.Web/ClientApp/src/lib/features/events/premium-filter.ts Adds client-side filter analysis to detect premium-required fields.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/upgrade-required.svelte.ts Adds shared upgrade-required dialog state + helpers (426 handling + proactive prompts).
src/Exceptionless.Web/ClientApp/src/lib/features/billing/stripe.svelte.ts Adds Stripe context + singleton Stripe loader.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/schemas.ts Adds billing form schema for change-plan dialog state.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/models.ts Adds billing-specific model types and re-exports generated billing types.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/index.ts Introduces billing feature module exports (components, helpers, Stripe context).
src/Exceptionless.Web/ClientApp/src/lib/features/billing/constants.ts Adds FREE plan ID constant.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/upgrade-required-dialog.svelte Adds global upgrade-required confirmation dialog and launches change-plan dialog.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/stripe-provider.svelte Adds imperative Stripe Elements/PaymentElement provider to work around Svelte 5 reactivity issues.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.svelte Adds full-featured Svelte change-plan dialog (plan tiers, coupons, PaymentElement, mutation wiring).
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.stories.ts Adds Storybook coverage for many dialog states.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog-harness.svelte Adds Storybook harness with query client seeding/mocks.
src/Exceptionless.Web/ClientApp/src/app.css Adjusts --primary-foreground in light/dark themes.
src/Exceptionless.Web/ClientApp/package.json Adds @stripe/stripe-js.
src/Exceptionless.Web/ClientApp/package-lock.json Locks @stripe/stripe-js dependency.
src/Exceptionless.Web/ClientApp/.storybook/mocks/env.js Provides a placeholder publishable key so billing stories can render.
src/Exceptionless.Web/ClientApp.angular/components/organization/organization-service.js Updates legacy Angular changePlan to POST JSON body instead of query params.
src/Exceptionless.Web/ClientApp.angular/components/billing/change-plan-controller.js Improves error message handling for plan change failures.
src/Exceptionless.Job/Exceptionless.Job.csproj Formatting-only change.
src/Exceptionless.Core/Exceptionless.Core.csproj Upgrades Stripe.net dependency to 51.1.0.
docs/billing-stripe-integration.md Adds documentation for new billing integration architecture and endpoints.
.vscode/settings.json Fixes VS Code TypeScript SDK setting key.
.github/hooks/follow-up.json Adds repository hook configuration (command-based stop hook).
.aspire/settings.json Formatting-only change.
Files not reviewed (1)
  • src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +26 to +29
if (!value) {
state.retryCallback = undefined;
}
},
Comment on lines +18 to +33
function onUpgrade() {
upgradeRequiredDialog.open = false;

if (isStripeEnabled() && upgradeRequiredDialog.organizationId) {
showChangePlan = true;
}
}

async function onChangePlanClose(success: boolean) {
const retry = success ? upgradeRequiredDialog.retryCallback : undefined;
showChangePlan = false;

if (retry) {
await retry();
}
}
Comment on lines +353 to +363
}

function onCouponCancel() {
couponOpen = false;
couponInput = '';
couponError = null;
}

function onCouponApply() {
const code = couponInput.trim();
if (!code) {
Comment on lines +55 to +63
**Body** (JSON, preferred):

| Field | Type | Description |
| --- | --- | --- |
| `plan_id` | string | Target plan ID (e.g., `EX_MEDIUM`, `EX_LARGE_YEARLY`) |
| `stripe_token` | string? | `pm_` PaymentMethod ID (Svelte) or `tok_` token (Angular) |
| `last4` | string? | Last 4 digits of card (display only) |
| `coupon_id` | string? | Stripe coupon code |

string planName = billingPlan?.Name ?? priceId;
string interval = priceId.EndsWith("_YEARLY", StringComparison.OrdinalIgnoreCase) ? "year" : "month";
item.Description = $"Exceptionless - {planName} Plan ({line.Amount / 100.0m:c}/{interval})";
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

should we log a warning here saying it's not found.


var customer = await customerService.CreateAsync(createCustomer);

var subscriptionOptions = new SubscriptionCreateOptions
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

some comments explaining this would help in here.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds the next-generation Stripe billing flow across backend + Svelte UI, including plan selection, payment method capture via Stripe.js, upgrade-required UX, and Stripe.net v51 migration updates.

Changes:

  • Added JSON-body (preferred) support for POST /organizations/{id}/change-plan, while keeping legacy query-string support.
  • Implemented new Svelte billing UI (ChangePlanDialog, StripeProvider) and centralized “Upgrade Required (426)” handling across pages.
  • Migrated Stripe invoice/plan handling to Stripe.net v51 semantics (status/discounts/price IDs) and updated related tests + OpenAPI artifacts.

Reviewed changes

Copilot reviewed 47 out of 53 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tests/http/organizations.http Updates change-plan request examples (JSON body + legacy query).
tests/Exceptionless.Tests/Mapping/InvoiceMapperTests.cs Adjusts tests for Stripe Invoice “paid” → Status.
tests/Exceptionless.Tests/Controllers/OrganizationControllerTests.cs Adds coverage for billing plans endpoints and billing-disabled behaviors.
tests/Exceptionless.Tests/Controllers/Data/openapi.json Documents change-plan request body + new schema.
src/Exceptionless.Web/Program.cs Adds optional appsettings.Local.yml config source.
src/Exceptionless.Web/Models/ChangePlanRequest.cs Introduces typed request model for JSON-body change-plan.
src/Exceptionless.Web/Mapping/InvoiceMapper.cs Maps invoice “paid” from Status == "paid".
src/Exceptionless.Web/Exceptionless.Web.csproj Formatting-only change.
src/Exceptionless.Web/Controllers/OrganizationController.cs Updates invoice fetching + plan listing + change-plan endpoint to new Stripe.net v51 patterns and JSON-body support.
src/Exceptionless.Web/ClientApp/src/routes/+layout.svelte Treats 426 as non-retriable to enable upgrade-required UX.
src/Exceptionless.Web/ClientApp/src/routes/(app)/stream/+page.svelte Shows upgrade dialog on 426 and resets selection on errors.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/add/+page.svelte Intercepts 426 to show upgrade dialog and supports retry.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte Replaces placeholder change-plan action with ChangePlanDialog.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/integrations/+page.svelte Intercepts 426 on premium integration actions.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/add/+page.svelte Intercepts 426 to show upgrade dialog and supports retry.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/users/+page.svelte Intercepts 426 on inviting users.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte Replaces placeholder change-plan action with ChangePlanDialog.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/billing/+page.svelte Swaps legacy dialog for new ChangePlanDialog and improves invoice URL safety.
src/Exceptionless.Web/ClientApp/src/routes/(app)/issues/+page.svelte Intercepts 426 responses and routes into upgrade dialog.
src/Exceptionless.Web/ClientApp/src/routes/(app)/event/[eventId]/+page.svelte Uses centralized upgrade-required helper.
src/Exceptionless.Web/ClientApp/src/routes/(app)/account/notifications/+page.svelte Adds proactive upgrade dialog trigger for premium notifications.
src/Exceptionless.Web/ClientApp/src/routes/(app)/+page.svelte Intercepts 426 on event list load and handles errors consistently.
src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte Mounts UpgradeRequiredDialog and adds premium-filter awareness to notifications.
src/Exceptionless.Web/ClientApp/src/lib/generated/schemas.ts Adds ChangePlanRequest schema; updates several generated schemas.
src/Exceptionless.Web/ClientApp/src/lib/generated/api.ts Adds ChangePlanRequest type and updates several generated types.
src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/stack-options-dropdown-menu.svelte Uses upgrade-required dialog for premium-only actions.
src/Exceptionless.Web/ClientApp/src/lib/features/shared/utils/formatters.ts Adds shared currency formatter.
src/Exceptionless.Web/ClientApp/src/lib/features/projects/components/user-notification-settings-form.svelte Loosens upgrade callback type to allow sync handler.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/components/dialogs/change-plan-dialog.svelte Removes placeholder legacy dialog.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Adds plans query + change-plan mutation + query keys.
src/Exceptionless.Web/ClientApp/src/lib/features/events/premium-filter.ts Adds client-side detection for premium filter usage.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/upgrade-required.svelte.ts Adds shared upgrade-required state + helpers.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/stripe.svelte.ts Adds Stripe context + lazy loader singleton.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/schemas.ts Adds billing form schema.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/models.ts Adds billing model re-exports and local types.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/index.ts Exposes billing public API (dialogs, helpers, stripe hooks).
src/Exceptionless.Web/ClientApp/src/lib/features/billing/constants.ts Adds Free plan constant.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/upgrade-required-dialog.svelte Adds dialog to route 426 → upgrade CTA → ChangePlanDialog.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/stripe-provider.svelte Adds imperative Stripe PaymentElement loader/mounter (Svelte 5 workaround).
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.svelte Implements new plan selection + payment + coupon UI and submit logic.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.stories.ts Adds Storybook coverage for billing dialog states.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog-harness.svelte Storybook harness for dialog + mocked query data.
src/Exceptionless.Web/ClientApp/src/app.css Adjusts primary foreground color.
src/Exceptionless.Web/ClientApp/package.json Adds @stripe/stripe-js.
src/Exceptionless.Web/ClientApp/package-lock.json Locks @stripe/stripe-js@9.2.0.
src/Exceptionless.Web/ClientApp/.storybook/mocks/env.js Adds mock Stripe publishable key for billing stories.
src/Exceptionless.Web/ClientApp.angular/components/organization/organization-service.js Updates legacy Angular change-plan call to send JSON body.
src/Exceptionless.Web/ClientApp.angular/components/billing/change-plan-controller.js Improves legacy error message extraction.
src/Exceptionless.Job/Exceptionless.Job.csproj Formatting-only change.
src/Exceptionless.Core/Exceptionless.Core.csproj Upgrades Stripe.net to v51.1.0.
docs/billing-stripe-integration.md Adds Stripe integration architecture + migration notes.
.vscode/settings.json Fixes TS SDK setting key.
.aspire/settings.json Formatting-only change.
Files not reviewed (1)
  • src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +97 to 99
<A class="cursor-pointer" role="button" tabindex={0} onclick={() => (changePlanDialogOpen = true)}>
<span class="font-bold">{organizationQuery.data?.plan_name}</span> plan
</A>

{#if canChangePlan}
<A onclick={handleChangePlan}>Click here to change your plan or billing information.</A>
<A class="cursor-pointer" role="button" tabindex={0} onclick={() => (changePlanDialogOpen = true)}>Click here to change your plan or billing information.</A>
Comment on lines +232 to +235
catch (StripeException ex)
{
_logger.LogCritical(ex, "Error getting invoice ({InvoiceId}): {Message}", id, ex.Message);
}
Comment thread docs/billing-stripe-integration.md Outdated
Comment on lines +150 to +153
1. **`Invoice.Paid` removed** → Use `String.Equals(invoice.Status, "paid", StringComparison.Ordinal)`
2. **`Invoice.Discount` removed** → Use `Invoice.Discounts?.FirstOrDefault(d => d.Deleted is not true)?.Source?.Coupon`
3. **`line.Plan` removed** → Use `line.Pricing?.PriceDetails?.PriceId` + `PriceService.GetAsync()`
4. **`CustomerCreateOptions.Plan` deprecated** → Create subscription separately

1. ~~**Coupon not applied for existing customers changing plans**~~ — Fixed. Coupons are now applied in all paths: new customer, existing customer updating subscription, and existing customer creating a new subscription.
2. **Potential orphaned Stripe customers** — If subscription creation fails after customer creation, a retry would create a duplicate Stripe customer. Mitigated by the low likelihood of this failure path.
3. **N+1 price fetches in invoice view** — Each unique price ID in an invoice makes a separate Stripe API call. Mitigated by a per-request cache (`priceCache`). Most invoices have 1-3 distinct prices.
Comment on lines +125 to 127
<A class="cursor-pointer" role="button" tabindex={0} onclick={() => (changePlanDialogOpen = true)}>
<span class="font-bold">{organizationQuery.data?.plan_name}</span> plan
</A>

{#if canChangePlan}
<A onclick={handleChangePlan}>Click here to change your plan or billing information.</A>
<A class="cursor-pointer" role="button" tabindex={0} onclick={() => (changePlanDialogOpen = true)}>Click here to change your plan or billing information.</A>
… drop unnecessary .Originals() on intermediate save
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Introduces a “next generation” Stripe billing flow across the ASP.NET Core API and the Svelte 5 app, including plan selection/upgrade UX, server-side Stripe.net v51 changes, and supporting documentation/tests.

Changes:

  • Adds a new Svelte billing UI (ChangePlanDialog, StripeProvider) plus a global “Upgrade required” (426) dialog.
  • Extends/updates organization billing API behavior (plans/invoices/change-plan) and migrates Stripe.net usage to v51 semantics (invoice status/discounts, subscription item price IDs).
  • Updates tests, OpenAPI snapshot, legacy Angular client calls, and adds Stripe integration documentation.

Reviewed changes

Copilot reviewed 47 out of 53 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/http/organizations.http Updates change-plan HTTP examples (JSON body preferred + legacy query params).
tests/Exceptionless.Tests/Mapping/InvoiceMapperTests.cs Updates invoice mapping tests to use Status instead of Paid.
tests/Exceptionless.Tests/Controllers/OrganizationControllerTests.cs Adds/updates billing-related controller and BillingManager tests.
tests/Exceptionless.Tests/Controllers/Data/openapi.json Updates OpenAPI snapshot for change-plan body + legacy query params.
src/Exceptionless.Web/Program.cs Adds support for optional appsettings.Local.yml.
src/Exceptionless.Web/Models/ChangePlanRequest.cs Introduces JSON body model for change-plan requests.
src/Exceptionless.Web/Mapping/InvoiceMapper.cs Migrates invoice “paid” mapping to Status == "paid".
src/Exceptionless.Web/Exceptionless.Web.csproj Formatting-only change.
src/Exceptionless.Web/Controllers/OrganizationController.cs Implements billing endpoints updates, change-plan body+legacy support, Stripe.net v51 migrations.
src/Exceptionless.Web/ClientApp/src/routes/+layout.svelte Treats 426 as a non-retryable status in route gating logic.
src/Exceptionless.Web/ClientApp/src/routes/(app)/stream/+page.svelte Opens upgrade dialog on 426 responses and wires retry callback.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/add/+page.svelte Shows upgrade dialog on 426 during project creation flow.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte Replaces placeholder “change plan” behavior with ChangePlanDialog.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/integrations/+page.svelte Shows upgrade dialog on 426 during integrations mutations.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/add/+page.svelte Shows upgrade dialog on 426 during org creation flow.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/users/+page.svelte Shows upgrade dialog on 426 during invite flow.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte Replaces placeholder “change plan” behavior with ChangePlanDialog.
src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/billing/+page.svelte Switches billing page to new ChangePlanDialog component + safer invoice URL encoding.
src/Exceptionless.Web/ClientApp/src/routes/(app)/issues/+page.svelte Opens upgrade dialog on 426 responses and clears selection state.
src/Exceptionless.Web/ClientApp/src/routes/(app)/event/[eventId]/+page.svelte Uses shared upgrade-required handler instead of TODO placeholder.
src/Exceptionless.Web/ClientApp/src/routes/(app)/account/notifications/+page.svelte Proactively opens upgrade dialog for premium notification settings.
src/Exceptionless.Web/ClientApp/src/routes/(app)/+page.svelte Opens upgrade dialog on 426 responses and clears selection state.
src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte Mounts UpgradeRequiredDialog globally; adds client-side premium-filter detection.
src/Exceptionless.Web/ClientApp/src/lib/generated/schemas.ts Regenerates Zod schemas (adds ChangePlanRequest, adjusts other schema shapes).
src/Exceptionless.Web/ClientApp/src/lib/generated/api.ts Regenerates TS API types (adds ChangePlanRequest, adjusts other types).
src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/stack-options-dropdown-menu.svelte Uses shared upgrade-required handler on 426 for “promote to external”.
src/Exceptionless.Web/ClientApp/src/lib/features/shared/utils/formatters.ts Adds shared formatCurrency utility.
src/Exceptionless.Web/ClientApp/src/lib/features/projects/components/user-notification-settings-form.svelte Allows upgrade callback to be sync or async.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/components/dialogs/change-plan-dialog.svelte Removes legacy placeholder dialog component.
src/Exceptionless.Web/ClientApp/src/lib/features/organizations/api.svelte.ts Adds plans query + change-plan mutation and invalidations.
src/Exceptionless.Web/ClientApp/src/lib/features/events/premium-filter.ts Adds client-side detection for premium filter fields (kept in sync with backend).
src/Exceptionless.Web/ClientApp/src/lib/features/billing/upgrade-required.svelte.ts Adds shared 426 detection + dialog state + retry callback wiring.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/stripe.svelte.ts Adds Stripe context + lazy singleton Stripe.js loader.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/schemas.ts Adds Zod schema for change-plan form state.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/models.ts Adds billing models and form-state types.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/index.ts Adds billing feature barrel exports.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/constants.ts Adds billing constants (FREE_PLAN_ID).
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/upgrade-required-dialog.svelte Adds global upgrade-required dialog that can open ChangePlanDialog.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/stripe-provider.svelte Adds imperative Stripe Elements/PaymentElement mounting for Svelte 5.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.svelte Adds the new “Manage subscription” dialog UI and Stripe PaymentElement flow.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog.stories.ts Adds Storybook coverage for many dialog states.
src/Exceptionless.Web/ClientApp/src/lib/features/billing/components/change-plan-dialog-harness.svelte Adds Storybook harness with mocked query data.
src/Exceptionless.Web/ClientApp/src/app.css Updates --primary-foreground values.
src/Exceptionless.Web/ClientApp/package.json Adds @stripe/stripe-js dependency.
src/Exceptionless.Web/ClientApp/package-lock.json Locks @stripe/stripe-js dependency.
src/Exceptionless.Web/ClientApp/.storybook/mocks/env.js Ensures Stripe publishable key exists for Storybook billing stories.
src/Exceptionless.Web/ClientApp.angular/components/organization/organization-service.js Updates legacy Angular change-plan call to send JSON body.
src/Exceptionless.Web/ClientApp.angular/components/billing/change-plan-controller.js Improves legacy failure messaging to include ProblemDetails title/message.
src/Exceptionless.Job/Exceptionless.Job.csproj Formatting-only change.
src/Exceptionless.Core/Exceptionless.Core.csproj Updates Stripe.net package version (47.x → 51.1.0).
docs/billing-stripe-integration.md Adds Stripe integration design/usage documentation.
.vscode/settings.json Fixes VS Code TS SDK setting key.
.aspire/settings.json Formatting-only change.
Files not reviewed (1)
  • src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)

src/Exceptionless.Web/Controllers/OrganizationController.cs:242

  • GetInvoiceAsync swallows StripeException/Exception and then falls through to return NotFound() because stripeInvoice stays null. This will report a 404 for transient Stripe/API failures, which is misleading for clients and makes debugging harder. Consider returning an appropriate 5xx (or rethrowing) when the Stripe call fails, while still returning 404 only when the invoice truly doesn’t exist or the user can’t access it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +18 to +33
function onUpgrade() {
upgradeRequiredDialog.open = false;

if (isStripeEnabled() && upgradeRequiredDialog.organizationId) {
showChangePlan = true;
}
}

async function onChangePlanClose(success: boolean) {
const retry = success ? upgradeRequiredDialog.retryCallback : undefined;
showChangePlan = false;

if (retry) {
await retry();
}
}
Comment on lines 97 to +113
@@ -112,7 +109,9 @@
(<TimeAgo value={nextBillingDate} />).

{#if canChangePlan}
<A onclick={handleChangePlan}>Click here to change your plan or billing information.</A>
<A class="cursor-pointer" role="button" tabindex={0} onclick={() => (changePlanDialogOpen = true)}
>Click here to change your plan or billing information.</A
Comment on lines 125 to +141
@@ -140,7 +137,9 @@
(<TimeAgo value={nextBillingDate} />).

{#if canChangePlan}
<A onclick={handleChangePlan}>Click here to change your plan or billing information.</A>
<A class="cursor-pointer" role="button" tabindex={0} onclick={() => (changePlanDialogOpen = true)}
>Click here to change your plan or billing information.</A
Comment on lines +169 to +170
2. **Potential orphaned Stripe customers** — If subscription creation fails after customer creation, a retry would create a duplicate Stripe customer. Mitigated by the low likelihood of this failure path.
3. **N+1 price fetches in invoice view** — Each unique price ID in an invoice makes a separate Stripe API call. Mitigated by a per-request cache (`priceCache`). Most invoices have 1-3 distinct prices.
…use async/await in stripe-provider, remove unnecessary comments and guards
@github-actions
Copy link
Copy Markdown

Code Coverage

Package Line Rate Branch Rate Complexity Health
Exceptionless.Core 66% 60% 7629
Exceptionless.Insulation 25% 23% 203
Exceptionless.Web 57% 43% 3694
Exceptionless.AppHost 26% 14% 55
Summary 61% (11975 / 19523) 54% (5993 / 11136) 11581

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

Development

Successfully merging this pull request may close these issues.

4 participants