From e881edfbb1526b174de7a08ad243095cc27de02e Mon Sep 17 00:00:00 2001 From: Jezz Santos Date: Sun, 23 Jun 2024 12:53:23 +1200 Subject: [PATCH] Added Billing integration, IBillingProvider and the Subscription API. Closes #29. --- docs/decisions/0160-billing-integration.md | 51 + docs/design-principles/0000-all-use-cases.md | 51 +- .../0090-authentication-authorization.md | 8 +- .../0180-billing-integration.md | 580 ++++++++++ docs/design-principles/README.md | 3 +- .../900-migrate-billing-provider.md | 170 +++ docs/how-to-guides/README.md | 3 +- docs/images/BillingIntegration-Adoption.png | Bin 0 -> 67140 bytes docs/images/BillingIntegration-Flows.png | Bin 0 -> 64900 bytes docs/images/Eventing-Components.png | Bin 0 -> 50971 bytes docs/images/Eventing-Flows-Generic.png | Bin 87167 -> 101772 bytes docs/images/Persistence-Eventing.png | Bin 118683 -> 118186 bytes docs/images/Sources.pptx | Bin 1124692 -> 1131210 bytes src/ApiHost1/ApiHost1.csproj | 1 + src/ApiHost1/HostedModules.cs | 2 + src/Application.Interfaces/Audits.Designer.cs | 58 +- src/Application.Interfaces/Audits.resx | 30 +- .../Subscriptions.cs | 250 +++++ .../Application.Services.Shared.csproj | 1 + .../IBillingGatewayService.cs | 160 +++ .../IBillingProvider.cs | 24 + .../ISubscriptionOwningEntityService.cs | 40 + .../ISubscriptionsService.cs | 11 + src/Common/SubscriptionMetadata.cs | 15 + .../EndUsers/MembershipFeatureUnassigned.cs | 23 + .../EndUsers/MembershipFeaturesReset.cs | 27 + .../EndUsers/PlatformFeatureUnassigned.cs | 19 + .../EndUsers/PlatformFeaturesReset.cs | 23 + .../Organizations/BillingSubscribed.cs | 21 + .../Organizations/BillingSubscriberChanged.cs | 21 + .../Organizations/MemberInvited.cs | 2 +- .../Organizations/MemberUnInvited.cs | 2 +- .../Subscriptions/Created.cs | 23 + .../Subscriptions/Deleted.cs | 17 + .../Subscriptions/PaymentMethodChanged.cs | 23 + .../Subscriptions/ProviderChanged.cs | 29 + .../Subscriptions/SubscriptionCancelled.cs | 23 + .../Subscriptions/SubscriptionPlanChanged.cs | 29 + .../Subscriptions/SubscriptionTransferred.cs | 33 + .../Subscriptions/SubscriptionUnsubscribed.cs | 23 + .../IBillingStateInterpreter.cs | 35 + .../CurrencyCodeSpec.cs | 37 + .../Subscriptions/BillingProviderSpec.cs | 121 +++ .../Subscriptions/ProviderInvoiceSpec.cs | 31 + .../ProviderPaymentMethodSpec.cs | 23 + .../Subscriptions/ProviderPlanPeriodSpec.cs | 20 + .../Subscriptions/ProviderPlanSpec.cs | 25 + .../Subscriptions/ProviderStatusSpec.cs | 34 + .../Subscriptions/ProviderSubscriptionSpec.cs | 42 + src/Domain.Shared/CurrencyCode.cs | 33 + src/Domain.Shared/Resources.Designer.cs | 36 + src/Domain.Shared/Resources.resx | 13 + .../Subscriptions/BillingProvider.cs | 66 ++ .../Subscriptions/BillingSubscriber.cs | 53 + .../Subscriptions/ProviderInvoice.cs | 51 + .../Subscriptions/ProviderPaymentMethod.cs | 62 ++ .../Subscriptions/ProviderPlan.cs | 58 + .../Subscriptions/ProviderPlanPeriod.cs | 56 + .../Subscriptions/ProviderStatus.cs | 56 + .../Subscriptions/ProviderSubscription.cs | 72 ++ src/Domain.Shared/Validations.cs | 19 + ...sersApplication.DomainEventHandlersSpec.cs | 76 +- .../EndUsersApplication.UnitTests.csproj | 1 + .../EndUsersApplicationSpec.cs | 11 +- ...EndUsersApplication.DomainEventHandlers.cs | 155 ++- .../EndUsersApplication.cs | 36 +- ...EndUsersApplication.DomainEventHandlers.cs | 9 + ...itationsApplication.DomainEventHandlers.cs | 4 +- .../InvitationsApplication.cs | 2 +- .../EndUserRootSpec.cs | 283 +++-- .../EndUserRoot.RolesAndFeatures.cs | 560 ++++++++++ src/EndUsersDomain/EndUserRoot.cs | 387 ++----- src/EndUsersDomain/Events.cs | 41 + src/EndUsersDomain/Membership.cs | 19 + src/EndUsersDomain/Resources.Designer.cs | 63 +- src/EndUsersDomain/Resources.resx | 17 +- src/EndUsersInfrastructure/EndUsersModule.cs | 6 + .../SubscriptionNotificationConsumer.cs | 38 + .../ReadModels/EndUserProjection.cs | 52 + ...essInMemSimpleBillingGatewayServiceSpec.cs | 46 + .../SinglePlanBillingStateInterpreterSpec.cs | 204 ++++ .../SimpleBillingProvider.cs | 353 +++++++ .../Resources.Designer.cs | 54 + src/Infrastructure.Shared/Resources.resx | 19 + .../ITenantedRequest.cs | 2 +- .../Cars/GetCarRequest.cs | 2 +- .../Cars/SearchAllAvailableCarsRequest.cs | 2 +- .../Cars/SearchAllCarsRequest.cs | 2 +- .../Images/DeleteImageRequest.cs | 2 +- .../Images/UpdateImageRequest.cs | 2 +- .../Images/UploadImageRequest.cs | 2 +- .../CancelSubscriptionRequest.cs | 13 + .../ChangeSubscriptionPlanRequest.cs | 15 + .../ExportSubscriptionsToMigrateRequest.cs | 13 + .../ExportSubscriptionsToMigrateResponse.cs | 9 + .../ForceCancelSubscriptionRequest.cs | 13 + .../Subscriptions/GetSubscriptionRequest.cs | 13 + .../Subscriptions/GetSubscriptionResponse.cs | 9 + .../Subscriptions/ListPricingPlansRequest.cs | 11 + .../Subscriptions/ListPricingPlansResponse.cs | 9 + .../MigrateSubscriptionRequest.cs | 18 + .../MigrateSubscriptionResponse.cs | 9 + .../SearchSubscriptionHistoryRequest.cs | 18 + .../SearchSubscriptionHistoryResponse.cs | 9 + .../TransferSubscriptionRequest.cs | 15 + ...ionsApplication.DomainEventHandlersSpec.cs | 81 +- ...pplication.SubscriptionOwningEntitySpec.cs | 392 +++++++ .../OrganizationsApplication.UnitTests.csproj | 1 + .../OrganizationsApplicationSpec.cs | 27 +- ...izationsApplication.DomainEventHandlers.cs | 8 + ...onsApplication.SubscriptionOwningEntity.cs | 22 + ...izationsApplication.DomainEventHandlers.cs | 105 +- ...onsApplication.SubscriptionOwningEntity.cs | 126 +++ .../OrganizationsApplication.cs | 28 +- .../Persistence/ReadModels/Organization.cs | 4 + .../OrganizationRootSpec.cs | 205 +++- src/OrganizationsDomain/Events.cs | 29 +- src/OrganizationsDomain/OrganizationRoot.cs | 172 ++- src/OrganizationsDomain/Resources.Designer.cs | 63 ++ src/OrganizationsDomain/Resources.resx | 22 + .../OrganizationsApiSpec.cs | 9 + .../OrganizationsInProcessServiceClient.cs | 34 +- .../SubscriptionNotificationConsumer.cs | 38 + .../OrganizationsModule.cs | 7 + .../ReadModels/OrganizationProjection.cs | 15 + src/SaaStack.sln | 66 ++ ...ionsApplication.DomainEventHandlersSpec.cs | 124 +++ .../SubscriptionsApplication.UnitTests.csproj | 19 + .../SubscriptionsApplicationSpec.cs | 677 ++++++++++++ .../SubscriptionsInProcessServiceClient.cs | 40 + .../ISubscriptionsApplication.cs | 39 + ...riptionsApplication_DomainEventHandlers.cs | 14 + .../Persistence/ISubscriptionRepository.cs | 21 + .../Persistence/ReadModels/Subscription.cs | 21 + .../Resources.Designer.cs | 71 ++ src/SubscriptionsApplication/Resources.resx | 30 + .../SubscriptionsApplication.cs | 541 ++++++++++ .../SubscriptionsApplication.csproj | 34 + ...riptionsApplication_DomainEventHandlers.cs | 103 ++ .../SubscriptionRootSpec.cs | 987 ++++++++++++++++++ .../SubscriptionsDomain.UnitTests.csproj | 18 + src/SubscriptionsDomain/Events.cs | 103 ++ src/SubscriptionsDomain/Resources.Designer.cs | 242 +++++ src/SubscriptionsDomain/Resources.resx | 87 ++ src/SubscriptionsDomain/SubscriptionRoot.cs | 700 +++++++++++++ .../SubscriptionsDomain.csproj | 37 + src/SubscriptionsDomain/Validations.cs | 17 + .../MigrationsApiSpec.cs | 81 ++ .../PricingApiSpec.cs | 47 + .../SubscriptionsApiSpec.cs | 283 +++++ ...ionsInfrastructure.IntegrationTests.csproj | 23 + .../appsettings.Testing.json | 16 + .../CancelSubscriptionRequestValidatorSpec.cs | 29 + ...ngeSubscriptionPlanRequestValidatorSpec.cs | 54 + ...eCancelSubscriptionRequestValidatorSpec.cs | 29 + ...MigrateSubscriptionRequestValidatorSpec.cs | 69 ++ ...SubscriptionHistoryRequestValidatorSpec.cs | 120 +++ ...scriptionsToMigrateRequestValidatorSpec.cs | 27 + ...ransferSubscriptionRequestValidatorSpec.cs | 30 + ...bscriptionsInfrastructure.UnitTests.csproj | 18 + .../BillingProviderMigrationApi.cs | 44 + .../CancelSubscriptionRequestValidator.cs | 17 + .../ChangeSubscriptionPlanRequestValidator.cs | 21 + ...tSubscriptionsToMigrateRequestValidator.cs | 13 + ...ForceCancelSubscriptionRequestValidator.cs | 17 + .../MigrateSubscriptionRequest.cs | 24 + .../Api/Subscriptions/PricingApi.cs | 31 + ...archSubscriptionHistoryRequestValidator.cs | 54 + .../Api/Subscriptions/SubscriptionsApi.cs | 91 ++ .../TransferSubscriptionRequestValidator.cs | 20 + .../OrganizationNotificationConsumer.cs | 38 + .../Notifications/SubscriptionNotifier.cs | 8 + .../ReadModels/SubscriptionProjection.cs | 92 ++ .../Persistence/SubscriptionRepository.cs | 108 ++ .../Resources.Designer.cs | 143 +++ .../Resources.resx | 54 + .../SubscriptionsInfrastructure.csproj | 38 + .../SubscriptionsModule.cs | 75 ++ ...ProfilesApplication.DomainEventHandlers.cs | 8 +- 179 files changed, 11857 insertions(+), 607 deletions(-) create mode 100644 docs/decisions/0160-billing-integration.md create mode 100644 docs/design-principles/0180-billing-integration.md create mode 100644 docs/how-to-guides/900-migrate-billing-provider.md create mode 100644 docs/images/BillingIntegration-Adoption.png create mode 100644 docs/images/BillingIntegration-Flows.png create mode 100644 docs/images/Eventing-Components.png create mode 100644 src/Application.Resources.Shared/Subscriptions.cs create mode 100644 src/Application.Services.Shared/IBillingGatewayService.cs create mode 100644 src/Application.Services.Shared/IBillingProvider.cs create mode 100644 src/Application.Services.Shared/ISubscriptionOwningEntityService.cs create mode 100644 src/Application.Services.Shared/ISubscriptionsService.cs create mode 100644 src/Common/SubscriptionMetadata.cs create mode 100644 src/Domain.Events.Shared/EndUsers/MembershipFeatureUnassigned.cs create mode 100644 src/Domain.Events.Shared/EndUsers/MembershipFeaturesReset.cs create mode 100644 src/Domain.Events.Shared/EndUsers/PlatformFeatureUnassigned.cs create mode 100644 src/Domain.Events.Shared/EndUsers/PlatformFeaturesReset.cs create mode 100644 src/Domain.Events.Shared/Organizations/BillingSubscribed.cs create mode 100644 src/Domain.Events.Shared/Organizations/BillingSubscriberChanged.cs create mode 100644 src/Domain.Events.Shared/Subscriptions/Created.cs create mode 100644 src/Domain.Events.Shared/Subscriptions/Deleted.cs create mode 100644 src/Domain.Events.Shared/Subscriptions/PaymentMethodChanged.cs create mode 100644 src/Domain.Events.Shared/Subscriptions/ProviderChanged.cs create mode 100644 src/Domain.Events.Shared/Subscriptions/SubscriptionCancelled.cs create mode 100644 src/Domain.Events.Shared/Subscriptions/SubscriptionPlanChanged.cs create mode 100644 src/Domain.Events.Shared/Subscriptions/SubscriptionTransferred.cs create mode 100644 src/Domain.Events.Shared/Subscriptions/SubscriptionUnsubscribed.cs create mode 100644 src/Domain.Services.Shared/IBillingStateInterpreter.cs create mode 100644 src/Domain.Shared.UnitTests/CurrencyCodeSpec.cs create mode 100644 src/Domain.Shared.UnitTests/Subscriptions/BillingProviderSpec.cs create mode 100644 src/Domain.Shared.UnitTests/Subscriptions/ProviderInvoiceSpec.cs create mode 100644 src/Domain.Shared.UnitTests/Subscriptions/ProviderPaymentMethodSpec.cs create mode 100644 src/Domain.Shared.UnitTests/Subscriptions/ProviderPlanPeriodSpec.cs create mode 100644 src/Domain.Shared.UnitTests/Subscriptions/ProviderPlanSpec.cs create mode 100644 src/Domain.Shared.UnitTests/Subscriptions/ProviderStatusSpec.cs create mode 100644 src/Domain.Shared.UnitTests/Subscriptions/ProviderSubscriptionSpec.cs create mode 100644 src/Domain.Shared/CurrencyCode.cs create mode 100644 src/Domain.Shared/Subscriptions/BillingProvider.cs create mode 100644 src/Domain.Shared/Subscriptions/BillingSubscriber.cs create mode 100644 src/Domain.Shared/Subscriptions/ProviderInvoice.cs create mode 100644 src/Domain.Shared/Subscriptions/ProviderPaymentMethod.cs create mode 100644 src/Domain.Shared/Subscriptions/ProviderPlan.cs create mode 100644 src/Domain.Shared/Subscriptions/ProviderPlanPeriod.cs create mode 100644 src/Domain.Shared/Subscriptions/ProviderStatus.cs create mode 100644 src/Domain.Shared/Subscriptions/ProviderSubscription.cs create mode 100644 src/Domain.Shared/Validations.cs create mode 100644 src/EndUsersDomain/EndUserRoot.RolesAndFeatures.cs create mode 100644 src/EndUsersInfrastructure/Notifications/SubscriptionNotificationConsumer.cs create mode 100644 src/Infrastructure.Shared.UnitTests/ApplicationServices/InProcessInMemSimpleBillingGatewayServiceSpec.cs create mode 100644 src/Infrastructure.Shared.UnitTests/ApplicationServices/SinglePlanBillingStateInterpreterSpec.cs create mode 100644 src/Infrastructure.Shared/ApplicationServices/SimpleBillingProvider.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/CancelSubscriptionRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ChangeSubscriptionPlanRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ExportSubscriptionsToMigrateRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ExportSubscriptionsToMigrateResponse.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ForceCancelSubscriptionRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/GetSubscriptionRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/GetSubscriptionResponse.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ListPricingPlansRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ListPricingPlansResponse.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/MigrateSubscriptionRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/MigrateSubscriptionResponse.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/SearchSubscriptionHistoryRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/SearchSubscriptionHistoryResponse.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/TransferSubscriptionRequest.cs create mode 100644 src/OrganizationsApplication.UnitTests/OrganizationsApplication.SubscriptionOwningEntitySpec.cs create mode 100644 src/OrganizationsApplication/IOrganizationsApplication.SubscriptionOwningEntity.cs create mode 100644 src/OrganizationsApplication/OrganizationsApplication.SubscriptionOwningEntity.cs create mode 100644 src/OrganizationsInfrastructure/Notifications/SubscriptionNotificationConsumer.cs create mode 100644 src/SubscriptionsApplication.UnitTests/SubscriptionsApplication.DomainEventHandlersSpec.cs create mode 100644 src/SubscriptionsApplication.UnitTests/SubscriptionsApplication.UnitTests.csproj create mode 100644 src/SubscriptionsApplication.UnitTests/SubscriptionsApplicationSpec.cs create mode 100644 src/SubscriptionsApplication/ApplicationServices/SubscriptionsInProcessServiceClient.cs create mode 100644 src/SubscriptionsApplication/ISubscriptionsApplication.cs create mode 100644 src/SubscriptionsApplication/ISubscriptionsApplication_DomainEventHandlers.cs create mode 100644 src/SubscriptionsApplication/Persistence/ISubscriptionRepository.cs create mode 100644 src/SubscriptionsApplication/Persistence/ReadModels/Subscription.cs create mode 100644 src/SubscriptionsApplication/Resources.Designer.cs create mode 100644 src/SubscriptionsApplication/Resources.resx create mode 100644 src/SubscriptionsApplication/SubscriptionsApplication.cs create mode 100644 src/SubscriptionsApplication/SubscriptionsApplication.csproj create mode 100644 src/SubscriptionsApplication/SubscriptionsApplication_DomainEventHandlers.cs create mode 100644 src/SubscriptionsDomain.UnitTests/SubscriptionRootSpec.cs create mode 100644 src/SubscriptionsDomain.UnitTests/SubscriptionsDomain.UnitTests.csproj create mode 100644 src/SubscriptionsDomain/Events.cs create mode 100644 src/SubscriptionsDomain/Resources.Designer.cs create mode 100644 src/SubscriptionsDomain/Resources.resx create mode 100644 src/SubscriptionsDomain/SubscriptionRoot.cs create mode 100644 src/SubscriptionsDomain/SubscriptionsDomain.csproj create mode 100644 src/SubscriptionsDomain/Validations.cs create mode 100644 src/SubscriptionsInfrastructure.IntegrationTests/MigrationsApiSpec.cs create mode 100644 src/SubscriptionsInfrastructure.IntegrationTests/PricingApiSpec.cs create mode 100644 src/SubscriptionsInfrastructure.IntegrationTests/SubscriptionsApiSpec.cs create mode 100644 src/SubscriptionsInfrastructure.IntegrationTests/SubscriptionsInfrastructure.IntegrationTests.csproj create mode 100644 src/SubscriptionsInfrastructure.IntegrationTests/appsettings.Testing.json create mode 100644 src/SubscriptionsInfrastructure.UnitTests/Api/Subscriptions/CancelSubscriptionRequestValidatorSpec.cs create mode 100644 src/SubscriptionsInfrastructure.UnitTests/Api/Subscriptions/ChangeSubscriptionPlanRequestValidatorSpec.cs create mode 100644 src/SubscriptionsInfrastructure.UnitTests/Api/Subscriptions/ForceCancelSubscriptionRequestValidatorSpec.cs create mode 100644 src/SubscriptionsInfrastructure.UnitTests/Api/Subscriptions/MigrateSubscriptionRequestValidatorSpec.cs create mode 100644 src/SubscriptionsInfrastructure.UnitTests/Api/Subscriptions/SearchSubscriptionHistoryRequestValidatorSpec.cs create mode 100644 src/SubscriptionsInfrastructure.UnitTests/Api/Subscriptions/SearchSubscriptionsToMigrateRequestValidatorSpec.cs create mode 100644 src/SubscriptionsInfrastructure.UnitTests/Api/Subscriptions/TransferSubscriptionRequestValidatorSpec.cs create mode 100644 src/SubscriptionsInfrastructure.UnitTests/SubscriptionsInfrastructure.UnitTests.csproj create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/BillingProviderMigrationApi.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/CancelSubscriptionRequestValidator.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/ChangeSubscriptionPlanRequestValidator.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/ExportSubscriptionsToMigrateRequestValidator.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/ForceCancelSubscriptionRequestValidator.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/MigrateSubscriptionRequest.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/PricingApi.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/SearchSubscriptionHistoryRequestValidator.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/SubscriptionsApi.cs create mode 100644 src/SubscriptionsInfrastructure/Api/Subscriptions/TransferSubscriptionRequestValidator.cs create mode 100644 src/SubscriptionsInfrastructure/Persistence/Notifications/OrganizationNotificationConsumer.cs create mode 100644 src/SubscriptionsInfrastructure/Persistence/Notifications/SubscriptionNotifier.cs create mode 100644 src/SubscriptionsInfrastructure/Persistence/ReadModels/SubscriptionProjection.cs create mode 100644 src/SubscriptionsInfrastructure/Persistence/SubscriptionRepository.cs create mode 100644 src/SubscriptionsInfrastructure/Resources.Designer.cs create mode 100644 src/SubscriptionsInfrastructure/Resources.resx create mode 100644 src/SubscriptionsInfrastructure/SubscriptionsInfrastructure.csproj create mode 100644 src/SubscriptionsInfrastructure/SubscriptionsModule.cs diff --git a/docs/decisions/0160-billing-integration.md b/docs/decisions/0160-billing-integration.md new file mode 100644 index 00000000..2e484000 --- /dev/null +++ b/docs/decisions/0160-billing-integration.md @@ -0,0 +1,51 @@ +# Billing Integration + +* status: accepted +* date: 2024-06-11 +* deciders: jezzsantos + +# Context and Problem Statement + +Most SaaS products charge their customers for use of the product and they receive revenue. + +> The rest does not apply to businesses that don't charge for their products + +There is a universe of options and possibilities when it comes to: + +1. How much to charge, +2. What to charge for (e.g., seats, tenancies, services, etc), +3. Whether there are recurring charges for some things and fixed charges for others, +4. Whether to charge on some schedule (e.g., daily, monthly, annually) and/or usage charges (e.g., per API call, per transaction, storage capacity) etc. + +There are infinite possibilities and variations of some or all of the aspects above and more. + +At the end of the day, managing these "policies" and keeping them up to date for existing and new customers, and correctly charging the correct amounts at the correct times for the +*actual* service delivered for those customers is (or becomes) extremely complicated for any small, medium or large business venture. For that very reason alone, no product company should be rolling their own Billing Management Systems (BMS) or Payment Gateways (PG). These services are now provided by several vendors all around the world, to such a degree that this is a well-solved and supported solution that should be adopted by all SaaS businesses. + +The challenge that SaaS businesses +*should* face instead is how to integrate with these BMS systems to automate as much of this stuff as possible so that a business removes the need to manually provision, manage, apply, or modify any of these policies. The goal for these businesses is for customers to self-serve the management of their usage and charges of the service they desire at every opportunity until manual intervention is absolutely necessary. + +> Manual intervention is frequently required and usually performed by some Support/Success function of the SaaS business in response to individual customer interaction. + +To make this experience seamless and reliable for customers of SaaS products, those products are required to integrate with BMS systems to facilitate self-service. In many cases, products themselves will be required to gate-keep and govern when it comes to enforcing quotas and limits defined by these billing policies. This requires the products to have up-to-date definitions of each customer's billing policy and enact the constraints defined within it. + +Furthermore, the SaaS business's customer support/success functions will be required to centrally manage their customers' data and billing policies, and they will need comprehensive tools to do that effectively and efficiently, when required. These tools are already provided by the BMS vendors themselves as table-stakes for all SaaS products to use. (whether they integrate their products or not). + +Thus we have a situation where both the SaaS product and the BMS system are sharing the same set of data and acting upon it. Given each party can change that data, there is a case here for bi-direction syncing of that data to some reasonable timeframe. This is a challenge the SaaS product needs to resolve. + +## Considered Options + +The options are: + +1. Full, 2-way sync with BMS +2. One-way sync with BMS (product -> BMS) +3. No integration with a BMS +4. No BMS + +## Decision Outcome + +`2-way sync` + +- With 2-way sync, data can be easily kept up to date in the SaaS product by means of webhooks and caches, with some acceptable latency period. (i.e. within 1 minute). Data for each tenant in the product can be changed either in-app or in the management portal of the BMS, and these changes will be "eventually consistent" with the customers' experience in-app. +- With 2 way sync, we can employ the use of the mature BMS toolsets, that can be used by non-technical roles (such as finance or customer success) and can be easily cross-referenced by the product (using well-known identifiers in the product) +- With 2 way sync, we can fully automate the self-serve experience for customers in-app. Rather than having to talk to a customer success agent that just uses the BMS tools. diff --git a/docs/design-principles/0000-all-use-cases.md b/docs/design-principles/0000-all-use-cases.md index ac131a95..baa3d332 100644 --- a/docs/design-principles/0000-all-use-cases.md +++ b/docs/design-principles/0000-all-use-cases.md @@ -33,34 +33,48 @@ These are the main use cases of this product that are exposed via "public" APIs #### Audits +For permanently recording compliance and business critical events that are performed on the platform. + 1. [Asynchronously] persist an audit to permanent storage #### Emails +For delivering emails to 3rd party services + 1. [Asynchronously] deliver an email to an email gateway 2. Find all delivered emails #### Feature Flags +For controlling feature flags for software releases + 1. Fetch a specific flag 2. Fetch all feature flags (for the current deployment environment) 3. Fetch a specific flag for a specific user #### Provisioning +Used for registering new tenants on the platform, when provisioning physical cloud infrastructure for individual tenants. + 1. [Asynchronously] notify the provisioning of a new tenant #### Recording +Recording combines, logging, auditing, metrics and usages in a single concept. + 1. Record a new measurement event (from a Frontend) 2. Record a new usage event (from a Frontend) #### Usages (Product) +Usages are the means to record the usage of a product by a user. + 1. [Asynchronously] deliver a usage event to product usage service ### Users (End User) +These are the end users on the platform. + 1. Assign [platform] roles to an existing user 2. Unassign [platform] roles to an existing user (except `Standard` role) 3. Invite a guest to register on the platform (a referral) @@ -73,21 +87,29 @@ These are the main use cases of this product that are exposed via "public" APIs #### API Keys +API Key are the way a user (person or machine) can authenticate with the platform using an API key. + 1. Create a new API key for the current user 2. List all API keys of the current (Authenticated) user 3. Delete an API Key #### Auth Tokens +Auth Tokens are the way that a user can authenticate with the platform using one or more tokens. + 1. Refresh an access token 2. Revoke an existing access token #### Machines +Machines are the way that non-human entities can operate on the platform. + 1. Register a new machine (anonymously or by authenticated user) #### Password Credentials +Is the way a user can authenticate with the platform using a username and password. + 1. Authenticate the current user (with a password) 2. Register a new person (with a password and with optional invitation) 3. Confirm registration of a person (from email) @@ -98,10 +120,14 @@ These are the main use cases of this product that are exposed via "public" APIs #### Single-Sign On +Is the way that a user can authenticate with the platform using an external OAuth2 provider (like Google, Facebook, etc.) + 1. Authenticate and (auto-register) a person from another OAuth2 provider (with an optional invitation) ### Images +Provides a simple image service for uploading and downloading images. + 1. Upload a new image (supported image types: jpeg,png, gif, maximum size: 100MB) 2. Update the metadata about an image (i.e. Description) 3. Delete an image @@ -110,6 +136,8 @@ These are the main use cases of this product that are exposed via "public" APIs ### Organizations +Organizations are the primary way that users are grouped together on the platform. An organization can be a "personal" organization (for a single user) or a "shared" organization (for multiple users). An organization is the manifestation of a tenant on the platform. + 1. Create a new (shared) organization for the current user 2. Inspect a specific organization 3. Change the organization's details @@ -122,17 +150,26 @@ These are the main use cases of this product that are exposed via "public" APIs 10. List all members of the organization 11. Delete the organization (must be no remaining members) +### EventNotifications + +Event Notifications are the way that subdomains can listen to each other in a loosely-coupled way. A "producing" subdomain produces "domain_events" which are stored on a message bus. This API provides an endpoint to consume those "domain_events". + +1. Handle a domain_event published to a message bus + ### Subscriptions -A billing subscription is created for every `Organization` (personal and shared) on the platform (person and machine). It represents the billing subscription plan for that tenant/organization (i.e., pricing and cost). The subscription plan determines the `Features` each user has access to on the platform, and it defines the fiscal responsibilities that each `EndUser` has an obligation for (i.e., scheduled payments). +A billing subscription is created for every `Organization` (personal and shared) on the platform for any (person or machine). It represents the billing subscription plan for that tenant/organization (i.e., pricing and cost, and features). The subscription plan determines the `Features` each user has access to on the platform, and it defines the fiscal responsibilities that each `EndUser` has an obligation for (i.e., scheduled payments). -Every `Organization` must have a single `EndUser` that owns the fiscal responsibility of the `Organization`, and who can control the extent of that responsibility. +Every `Organization` must have a single `EndUser` that owns the fiscal responsibility of the `Organization` (called the "buyer"), who can control the extent of that responsibility. -1. (coming soon) Inspect the subscription for the current (Authenticated) user -2. (coming soon) Change the subscription plan -3. (coming soon) Cancel the subscription plan -4. (coming soon) Migrate the billing provider data (from one provider to the next) -5. (coming soon) Transfer fiscal responsibility for the organization +1. Inspect the subscription for the current (Authenticated) user +2. Upgrade/Downgrade the plan, or transfer the subscription to another authorized buyer (in the case of the buyer leaving the platform) +3. Cancel the subscription plan +4. List all the available pricing plans +5. Search the billing history for a subscription +6. Transfer the subscription to another authorized buyer +7. List all subscriptions that could be migrated (when migrating off of an existing billing provider) +8. Migrate the billing provider data (from one billing provider to a new one) ### User Profiles diff --git a/docs/design-principles/0090-authentication-authorization.md b/docs/design-principles/0090-authentication-authorization.md index c9a1f2d2..15818c45 100644 --- a/docs/design-principles/0090-authentication-authorization.md +++ b/docs/design-principles/0090-authentication-authorization.md @@ -185,9 +185,9 @@ API keys do not support refreshing issued API keys. When issuing the API key the ### Declarative Authorization Syntax -Authorization is both declarative (at the API layer), and enforced programmatically downstream in other layers. +Authorization is enforced at a coarse-grained level declaratively in the API layer, as well as being enforced at fine-grained level downstream in the Domain Layer. -> In the Application layer, the current users authorization can be viewed and checked using data on the `ICallerContext` object. +> In the Application layer, the current users' roles and features can be accessed through the `ICallerContext` object. In the API layer, authorization is declarative, using the `[Authorize]` attribute. @@ -202,11 +202,13 @@ public class GetCarRequest : TenantedRequest } ``` +> Incidentally, the syntax used here, uses `enums` that are source generated for you at compile time. + There are two kinds of aspects to authorize, Roles and Features. ### Role-Based Authorization -In this system, there are two sets of "roles" to manage access to any APIs and underlying subdomains. +In this mechanism, there are two sets of "roles" to manage access to any APIs and underlying subdomains. This is commonly referred to as [RBAC](https://en.wikipedia.org/wiki/Role-based_access_control). diff --git a/docs/design-principles/0180-billing-integration.md b/docs/design-principles/0180-billing-integration.md new file mode 100644 index 00000000..8f4744bc --- /dev/null +++ b/docs/design-principles/0180-billing-integration.md @@ -0,0 +1,580 @@ +# Billing Integration + +Here, we refer to the integration between the SaaS product and a preferred Billing Management System (BMS). + +Examples of typical online BMSs are: [Chargebee](https://www.chargebee.com/), [Maxio (formerly Chargify)](https://www.maxio.com/subscription-management), [Recurly](https://recurly.com/), [Zoho](https://www.zoho.com/us/billing/), and [Stripe Billing](https://stripe.com/billing). + +We have some significant goals here with a billing integration: + +* We want to give our end-users the ability to self-serve their billing subscription needs. That means choosing an appropriate pricing plan and then having the free will to cancel, upgrade, and downgrade their plans at will, without human intervention. (Imagine having to negotiate with a Sales person to cancel a subscription to an online service - it is not happening) They will also need access to their invoices and see the costs related to all activities. This transparency, accuracy, and ease of changing commitment go a very long way toward building trust in the product. This means the product has to be integrated in several places and pretty extensively integrated with the BMS. +* We want to avoid reinventing the wheel and building our own Billing Management Systems (BMS). As tempting as it may be to some over-confident engineers, this is a galactic-sized accomplishment (even for only the simplest scenarios that might be naively foreseen at the start of the business). Considering some businesses have spent billions of dollars doing it right, it should itself be an indication that doing this is too expensive for a starting-up SaaS business, either at the start or in several years' time. For every other SaaS business, this capability is something you buy and integrate with, not build. There are many providers available today, some optimized to your business-specific model and some more generalized, and you might be changing your mind about the growth trajectory of your SaaS business. When that time comes, we want to facilitate that change in SaaStack easily. +* An integrated SaaS product with a BMS will be not only surfacing billing information and allowing the user to change it, but it will also be in a position to surface and enforce some of the limitations imposed by different billing pricing plans. For example, limits, quotas, and feature sets. When these things change, the SaaS product needs to co-ordinate with the BMS policies, both ways (enforce, and notify). +* Every SaaS business prices and charges differently, and every SaaS business changes those policies pretty regularly. The software needs to adapt easily. + +## Overview + +As SaaS products evolve, eventually, the critical questions of "What is going to be charged (to customers) for the use of this product?" and "What is the pricing strategy going to be?" moving forward arise. + +How and when should a SaaS business introduce charges? and start earning revenue? + +Let’s explore this journey, considering both short-term revenue gains that can be had versus the long-term, more sustainable revenue attainment from the repeated use (and payment) for the product over time (recurring revenue). + +These are always two competing forces keeping SaaS product businesses alive and thriving. Short term revenue growth, and long term revenue growth. The classic battle between Sales-led revenue (once-of), and Product-led revenue (recurring). + +1. **Early Days and Product Market Fit:** + - You should prioritize achieving product-market fit (PMF) for a larger market of adopters, over earning early revenue, specifically from a set of fewer prospects with bespoke needs and demands. + - Initially, focus on building a more broadly desirable product, without incurring the burden of introducing integrated billing and customer charging complexities. + - Integrating billing systems at an early stage (which is significant and non-trivial product work) can divert precious resources from core research and development of the product, missing critical opportunities in the market for long-term growth. + +2. **Product-Market Fit and Scaling:** + - PMF is the holy grail of an early-stage startup. It’s about creating a product that resonates with a broad enough audience, who will eventually pay money for it (irrespective of whether they pay now or later). + - Marketing and PMF validation are key to unlocking the door to scalable business model later, especially for Product-Led Growth (PLG) products, but also for predominantly Sales-Led Growth products (SLG). If you haven't got PMF nailed early on, then scaling is hard if not impossible to attain, regardless of the size of the markets you desire to move into. + - Direct sales to individual customers (one at a time) may help validate PMF, but they don’t scale well across a large global market. + +### The Perils of Early Revenue Focus + +There are real dangers in pursuing early revenue, pre-PMF stages of the business. + +> This is a common pitfall for founders who are prior service-oriented (i.e., expect invoice payment for services rendered) who are happy to settle for a small number of paying customers and serve them a customized service (i.e. former consultants, solution providers, etc), as opposed to founders who are more focused on creating a more desirable generalized product for a larger market, and deferred payment. + +- Pursuing revenue too soon risks misallocation of resources that would be better applied to R&D for PMF. Defer, and avoid turning the product business into a boutique services business. +- Premature billing integration can distract the product team from critical PMF discovery. This kind of work is intense, error-prone, and, in many cases, over-engineered to guard against uncertain and unknown futures. All those things are all hinderances long term. Focus on PMF. +- Bespoke billing management solutions may emerge (from over-confident and naive engineers), hindering the scalability of the business in the long-run, and ultimately lost revenue from all but the simplest pricing models. This hubris should be avoided at all costs. + +### Converting Free to Paid Users + +- You need to have identified when your free users are ready to convert to paid users, while already using the product. This is not trivial work. +- When converting free users to paid users, experiment with pricing strategies; expect not to get it right the first time, and you can't be afraid to change it. +- Then, install, configure, and migrate subscription data to a reliable third-party billing provider. +- Pricing strategy changes will still happen (less frequently), and when they do, you'll be thankful that the BMS has comprehensive facilities to handle them. These are opportunities to connect with paying customers and upsell them added value in the product introduced since the last price pricing change. + +### The Point Of No Return + +- Once billing integration is introduced, there’s no turning back. You will have existing paying customers, and their billing needs will need to be managed far into the future. +- Refine pricing strategies and amounts every year. +- Product Managers play a pivotal role in quantification at these stages. + +### Managing Economics Over Time + +- Make charge payments (e.g., credit cards) for subscriptions in advance and save on fees using direct debit and other low-fee banking payment instruments. The longer the advanced period, the better. +- Manage upgrades, downgrades, discounts, and refunds in the BMS portal, while the data is automatically synced to the product, where the users can see it. +- With thousands of customers, long retention periods, many plan changes, and pricing experiments — complexity abounds. + +![Cost of Billing Integration](../images/BillingIntegration-Adoption.png) + +Remember, the journey from PMF to scalable revenue involves many strategic decisions about where to expend your precious R&D resources. Choose wisely, and may your SaaS venture thrive in the long run! + +At the moment you commit to a billing integration, it will become important to both charge payments (e.g. to a credit/debit card) for any subscription and to track the charges to that subscription as time passes, as well as manage upgrades, downgrades, grandfathering, charging, refunds, and cancellations to those subscriptions. All of this needs management over long periods of time for thousands of customers. + +There is much that will change over time with both active subscriptions and the various pricing strategies that are tried over time. + +> This is often overlooked by inexperienced founders + +### Billing Management Systems + +> Creating a billing management system from scratch to handle the operational aspects of a SaaS business is extremely challenging and outrageously costly for all SaaS businesses (except those who plan to be a global billing provider). This endeavor should be avoided at all costs. + +Instead of building our own system, SaaStack has been designed to be fully two-way integrated with established 3rd party billing providers (e.g., [Chargebee](https://www.chargebee.com), [Maxio](https://www.chargify.com/), or [Stripe Billing](https://www.stripe.com/billing)). + +All these providers offer APIs for integration as well as management portals and tools for handling subscriptions, plans, pricing, trials, discounts, and coupons. The API interface (and webhooks) provided by the BMS becomes the user interface of your product that your customers can self-serve with. The management portal the BMS provides becomes an administrative tool your business (product, support & success, etc) can use to manage customers, billing and pricing changes long term. + +This bidirectional approach introduces a need for seamless synchronization between your SaaS product and third-party services, as changes can occur in both systems independently (due to different actors). Therefore, the product's backend API will be needed (via webhooks) to modify and synchronize subscriptions from the BMS and ensure consistency between the two systems. Eventual consistency is completely tolerable in this scenario. + +This two-way syncing ensures that end-users and administrators can manage billing plans and resolve issues effectively. + +### Billing Subscriptions and Multi-Tenancy + +In B2B products specifically, it is likely that the "buyer" of the SaaS product is not always the "end-user" of the product (sometimes it is, oftentimes it isn't), whereas in B2C products, the "buyer" and the "end-user" are often precisely the same person. + +> By default, SaaStack is configured for B2B out of the box, but can be easily altered to suit B2C models as well. + +By default, the "buyer" of a SaaStack product will be the individual taking the financial responsibility for the billing `Subscription` (the buyer) and that is is going to be bound to an `Organization` (the tenant). + +The selected "pricing plan" associated with this billing subscription would need to apply to all current and future members of that organization (tenant). + +By default, when a new organization for an `EndUser` (buyer) is created, it is associated a new billing `Subscription` for that `Organization`. This billing subscription and organization will collaborate to impose restrictions on the members of the organization, such as access to specific features of the product and possibly limits on the usage of certain features of the product. + +Initially, the "creator" of any organization will automatically become the "buyer" of the billing subscription. As a result, they will become the payment authority (via a payment method) for the subscription and will make purchasing decisions (i.e., upgrade/downgrade decisions). This person, the buyer, will be charged for the use of their organization/tenancy on the SaaS product at certain subscription levels (via the `PaymentMethod`), and they will also be the primary user responsible for managing the billing subscription (usually represented as a "customer" in the BMS. + +> Ordinary members of an organization will not have access to view or modify the organization's billing information that information may be too sensitive. viewing and management of this data is typically only available to the "buyer" of the subscription associated with the organization, and to others members of the same organization nominated by the "buyer" to act on their behalf (i.e. nominated billing administrators). + +### Pricing Plans + +Most SaaS products advertise pricing plans, some free, some with "basic" capabilities, and some with more "advanced" capabilities. They often define different levels of cost, and define different levels of service and restrictions. + +Billing subscriptions (as a concept) usually define a financial responsibility between a party (the "buyer") and the service provider (SaaS product). The "buyer" decides the level of service they wish and thus determines the pricing of the subscription, and they fulfil that responsibility with a financial instrument like a valid `PaymentMethod`. + +It is very important that at least one person (specifically the "buyer") has this responsibility as the subscription can change over time, as can the `PaymentMethod`. It is critically important that this valid `PaymentMethod` remains valid at all times to keep the service paid for and alive, particularly when the service is charged for (i.e. monthly) or when the subscription changes (i.e. plan changes, additional fees/charges are added/removed). + +Therefore, a "Plan" is often the main concept used to define the limits, usage, terms, and ultimately the costs of the subscription. + +Plans can be "free" or "paid" or hybrids, like paid plans with trial periods, and there can be tiers of them for different kinds of customers with different needs (i.e., Basic, Standard, Professional, Enterprise, etc.). They often involve charging money at some point in time (either in advance or in arrears), and they involve invoicing (sometimes zero) on a specific frequency (e.g. daily, weekly, monthly, annually). + +Sometimes a plan also defines levels of access granted to its end-users, to its "features". Sometimes, it defines the usage limits for all the members of the billing "subscription" as well. + +Some SaaS products provide one or more pricing plans that are optimized closely to their customers' actual usage of the product. They can be defined in several dimensions: + +* In terms of time (e.g. fixed price per month). + +* In terms of usage limits (e.g. up to 100 seats). + +* In terms of actual usage of the product (e.g. per transaction). + +* Sometimes, hybrids are defined that combine usage limits with tiered usages (e.g. fixed price up to the first 50 seats, then some overhead per seat after that). + +> The combinations of these dimensions can be highly varied, and some are very complex. + +The complexity of pricing plans, in general, becomes a significant impediment to adoption, as prospective customers might find they cannot make a sensible economic decision for their business. In many cases, they end up leaving, trying to identify the correct plan for them. + +### Tiers + +All plans belong to a specific tier, and the tier governs the level of access to the product. + +> It is also feasible to have many plans belonging to the same tier, which may vary in other ways. + +The default set of tiers (`SubscriptionTier`), modeled in SaaStack, has been designed for a specific "customer acquisition and growth strategy." + +The progression through these tiers represents a variant of a very common "Freemium" model, where: + +1. The end-new user starts on the `Standard` tier, which is initially a "free" tier (with or without a Trial period) +2. If Trials are supported by the BMS, the end-user gets to try out `Standard` tier features for a period of time before the trial ends, at which point the subscription will require payment of some kind (a valid `PaymentMethod`). If payment is received (in time), the end-user keeps `Standard` tier access from that point in time (and the Trial ends). If no payment is received (in time), the end-user is automatically downgraded to the `Unsubscribed` tier, which has permanent "free" access to a limited set of basic features. +3. At any time during the trial (or outside a trial period), at any tier, the end-user can upgrade to any other tier. They can also cancel their subscription and will be automatically reverted to the `Unsubscribed` tier. +4. Lastly, in some rare cases, if a subscription in the BMS system itself is "deleted/destroyed" (by a business "administrator" of some kind), the subscription will be reverted to the `Unsubscribed` tier again, as a fallback. + +Bottom line, is that this is flexible strategy to get started for most SaaS businesses, that will, no doubt adapt this default workflow moving forward. + +> You are free to change these default tiers and add or remove your own. The details that drive the restrictions will come from the plan configuration in the BMS and need to be synchronized in the code, too. + +| Tier | Charging Frequency | Restrictions | Cost | Default Feature Access | Conditions | +|------------------|-----------------------------------------------------|--------------------------------------------------------|---------------------------------------------------------------|------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Unsubscribed** | free forever | access to only very basic features | NZD$0 | **Basic** | No member of the tenant/organization is allowed to use any of the features of the product, except some limited set of "read-only" type features. The buyer can of course upgrade to **Standard**, **Professional** or **Enterprise** plans at any time. The buyer and all the members of the organization automatically adopt this tier if any canceled or unsubscribed from. | +| **Standard** | free for 14-30 day Trial, then paid each month/year | access all basic features and some paid features | NZD$0 for Trial period, NZD? configurable in 3rd party portal | **PaidTrial** | All members of the tenant/organization are allowed to use any of the basic features of the product for a period of 14/30 days (sometimes within some usage limits), after which, if a plan at this tier is not upgraded to a **Professional** or **Enterprise** plan, the plan is automatically downgraded back to the **Unsubscribed** tier above. The buyer of the organization must upgrade the plan, or they are free to create a new organization on the **Standard** tier again. | +| **Professional** | paid each month/year | access all basic features, and some most paid features | NZD$? configurable in 3rd party portal | **Paid2** | All members of the tenant/organization are allowed to use any of the basic/paid features of the product (sometimes within some usage limits) for as long as the plan is paid for. The buyer of the organization can upgrade to an **Enterprise** (below) or downgrade to a **Standard** (above) plan. | +| **Enterprise** | paid each month/year | access all features | NZD$? configurable in 3rd party portal | **Paid3** | All members of the tenant/organization are allowed to use all the features of the product (sometimes within some usage limits) for as long as the plan is paid for. The buyer of the organization can downgrade to a `Professional` or **Standard**(above) plan. | + +> NZD in the "Cost" column is the configured default currency in the 3rd party provider. This can, of course, be changed at any time (provider support withstanding). +> +> The "Default Feature Access" denotes the initial mapping between `Features` (both Platform and Tenant) that users get at those tiers by default. + +With a pricing strategy like the one above, there is: + +* A clear "onboarding" path for all users and all organizations: starting at **Standard+Trial** and then later (without payment) becoming **Unsubscribed**, and +* There is a clear growth strategy for retained users from **Standard** (or **Unsubscribed**) to **Professional** or **Enterprise**, all demanding a recurring payment every month. + +> Ultimately, after a trial period passes, all members of all organizations are either not using the product (remain on **Unsubscribed**), or they are paying for its use (paying on **Standard**, **Professional** or **Enterprise**). + +This pricing strategy is just one SaaS growth strategy. There are many other adoption strategies like this one that vary the plans and measures within them. + +When tiers change, the conditions of use of the "buyer" of the subscription and the members of their organization will change in sync with that. Where they may have all once had access to certain features (e.g., in a "Trial" or on a "Paid" plan), they may no longer have access to those features. + +> This is a useful *dynamic* quality of SaaS products versus, say, physical products. + +### Billing Management Systems + +Billing Management Systems (like [Chargebee](https://www.chargebee.com), [Maxio](https://www.chargify.com/), or [Stripe Billing](https://www.stripe.com/billing), etc.) are 3rd parties that provide their own tools to manage concepts like customers, subscriptions, payments, plans, charges, etc. Anyone in the SaaS business can use those tools at any time to make critical changes to those customers, subscriptions, and plans. This capability is powerful and effective for business functions like Finance, Support, and Success functions, and these tools and experiences are very mature. + +Some BMS's also handle direct credit card payments through their own "Payment Gateway" linked to a "Merchant Account", and some provide integrations to other payment gateways (i.e. Stripe, PayPal, Shopify, etc). + +> For example, Stripe is both a "Payment Gateway" (supports "Merchant Accounts") as well as having a "Subscription Management" service (albeit a more limited one). Whereas Chargebee and Maxio are just "Subscription Management" services, and thus require further integration with a "Payment Gateway" service like Stripe. + +To use any of these 3rd party BMSs requires SaaS businesses to immediately purchase, manage, and configure them, and that may be an additional distraction/roadblock to getting the first versions of your product off of the ground in the first few months/years of development. Even though many provide simple plugins into products to capture credit cards, and process payments. + +> Integrating third-party billing providers into any SaaS platform (beyond a front-end integration) is not a trivial task. It is typically quite time-consuming and expensive to do to any degree of completeness for durability, i.e., backend integration. + +To avoid this commitment too early in the life of the SaaS business, SaaStack contains a default billing provider in place of a third-party one, and it is configured so that the integration with the third party can be deferred until much later in the product lifecycle. + +> Of course, the default `BillingProvider` it is not in the way if integrating with a 3rd party BMS is required sooner than later. + +When the right time comes, the default `BillingProvider` can be easily swapped out for another provider like [Chargebee](https://www.chargebee.com), [Maxio](https://www.chargify.com/), or [Stripe Billing](https://www.stripe.com/billing), and the existing subscriptions for the existing `Organizations` can be migrated to prepopulate the new BMS systems. + +### Two-way Sync + +Since business functions in the SaaS business can easily manipulate customer, subscription, and plan data directly in a BMS anytime they want, AND this is an unchecked activity in terms of the fact that mistakes can be made (even drastic ones), AND given the fact that the `BillingProvider` is integrated into the product so that the product can automate decisions about what an end-user can do and not do based on plan limits, AND enable the user to self-serve upgrades/downgrades, and see invoice information. We have a very strong need for syncing the data of any BMS subscriptions both ways, between the product and the BMS, and keep them up to date. + +**Product -> BMS:** When changes are made in the product that would affect the BMS data, these changes are sent to the current billing provider over HTTP using service clients (e.g. via the `ChargebeeHttpServiceClient`). + +**BMS -> Product:** When data changes changes in the BMS, these changed will need to be sent to the product's `Subscriptions` API, via webhooks events, and the internal state maintained by the product about the subscriptions in the BMS must be updated. + +> See the `ChargebeeWebhookService` for how we handle webhooks from www.Chargebee.com, and see how the data that is kept for the Chargebee BMS (`ChargebeeStateInterpreter`), might be different than the set of data kept for, say a Stripe Connect BMS. + +# Implementation + +By default, in SaaStack, the BMS integration is represented by two main parts: + +1. The `Subscriptions` subdomain, containing the APIs and Webhooks and maintaining the state of subscriptions for the 3rd party BMS. +2. An `IBillingProvider` (specific to a 3rd party BMS), plugged in by dependency injection at runtime + +### The Subscriptions API + +Let's start with the API through which all billing subscription activities occur. It's the `Subscriptions` API. + +As you can see from the relationships built into [Multitenancy](0130-multitenancy.md) in SaaStack, by default, a `Subscription` is related one-to-one with a `Organization` (or per tenant). + +> This is simply the default, and can be changed for your product. For example if you provide a concept like "projects" in your product and and organization can have several distinct projects, and you wanted a billing subscription defined for each "project". Its might not be common, but it is a possibility. + +Through this API, end-users (members of an organization, by default) can perform various actions, like upgrade, downgrade, cancel, and view invoices for their billing subscription. + +The API itself, will interact with the `IBillingProvider` to achieve those things. In that way, it delegates some of those [transactional] commands directly with the BMS. But at the same time, it maintains a cache of relevant metadata (about the subscription and plan from the BMS) in the API, so that the API does not have to contact the BMS for all non-transactional activities. + +Lastly, in order to maintain eventual consistency between data changing in the BMS, which can change quite independently in the BMS (from other actors), the `Subscription` subdomain needs to handle webhook events originating from the BMS, or use polling techniques to obtain those changes. + +> The webhooks will be different for different BMSs. + +### The Billing Provider + +The billing provider (`IBillingProvider`) is an abstraction that provides two services: + +1. Provides a HTTP service client to a (`IBillingGatewayService`) to directly access to the BMS to perform transactional commands. +2. Provides an `IBillingStateInterpreter` to manage the internal [cached] state of the subscription, plans and limits, quotas, etc from the BMS, in the product over time, as things change. + +By default, the built-in `SimpleBillingProvider` is configured, and injected at runtime. + +> It can be easily unplugged and another `IBillingProvider` can be used to replace it, such as the: `ChargebeeBillingProvider`. See [Migrating To Another Billing Provider](../how-to-guides/900-migrate-billing-provider.md) for how to do that. + +The `SimpleBillingProvider`essentially hardcodes its own behavior, since there is no 3rd party BMS service to integrate with. + +As you can see, it keeps track of very minimal state (variables) that define only a unique `subscriptionId` and the `buyerId` of the subscription. + +It also defines one hardcoded plan, that has zero cost, no trial period and no limits quotas, on a single tier (`Standard`) that always has a valid `PaymentMethod`. This plan can be canceled or unsubscribed, but changing the plan (i.e. Upgrade/Downgrade) has no effect since it reverts back to the original plan. + +It supports all the features any `IBillingProvider` could have, but it works in a limited way like this: + +![Plan Flow](../Images/BillingIntegration-Flows.png) + +> Note: For any custom billing provider, the optional flows available to it are numerous. Each provider can determine its own flows. + +The `SimpleBillingProvider` works like this: + +- It defines a single `Standard` plan (named `_simple_standard`). +- Every `Organization` that gets created gets created with a new billing `Subscription` with the plan: `_simple_standard`. +- The `Organization` assigns the creator the org, the following default roles: `BillingAdmin` (also `Owner` and `Member`). +- The new `Subscription` is automatically created (via a notification) with a `BuyerId` to be the `CreatedById` of the new `Organization`. +- Any Upgrade (or downgrade) results in the same plan (`_simple_default`) and the same Tier (`Standard`). +- Cancelling the plan (or Unsubscribing it) makes it revert to the `Unsubscribed` tier, with limited access to features. +- If the `Organization` is deleted, which is permitted, the `Subscription` is also deleted. + +Bottom line: with this `SimpleBillingProvider`, no `Organization` can exist without a `Subscription` with the same plan (`_simple_standard`). + +The benefit of using this `SimpleBillingProvider` as a "default" is that you can get your product running immediately, capture and collect the subscriptions of our customers, advertise a single free plan on your website (i.e., "freemium"), and users can view zero-total invoices every month. + +One day in the future, when you are ready and have purchased a BMS, you can easily migrate those existing customers and subscriptions over to your new 3rd party system seamlessly via the built-in APIs of the `Subscriptions` subdomain. + +> See [Migrating To Another Billing Provider](../how-to-guides/900-migrate-billing-provider.md) for more details on how to do that. + +## Access Control via Subscriptions + +In any SaaS product, it is common to restrict access to certain features and functionality of the product depending on the specific plan of the subscription. + +Some plans define access to whole feature sets, while others put limits and quotas on the usage of those features. + +> Some features of a SaaS product may not be "tenanted" and will require access to be granted to individual users, rather than to specific members of organizations. + +Since a plan can be changed at any time during the use of the SaaS product, and since the features of the product cannot be deployed to each user on-demand instantly, access to features is required to be *dynamically* controlled by the software itself, as it is being used by specific end-users. + +When a plan is changed, the `EndUser` subdomain responds to that event `SubscriptionPlanChanged` by recalculating the features of every member of the organization. + +Access to features of any SaaS product can be controlled by three mechanisms: + +* Feature Flags (globally or to a specific cohort of users) +* RBAC (roles and permissions of each individual user) +* Billing subscription plans (defined by the plan of the subscription for each organization) + +> You can find out more about how these things work in [Declarative Authorization Syntax](0090-authentication-authorization.md/#declarative-authorization-syntax) + +Each of these mechanisms works differently, and is configured differently. But together they provide the controls needed to permit or deny access to any one feature of the product for each user (an `EndUser`), and to each member of an `Organization` (tenant). + +## Payments + +In order for a "buyer" to purchase the service provided by any subscription at any price (except "free" or "trial"), they need to have provided a valid "payment method" registered with the BMS at or before the time that a charge in advance for the service would need to be made. + +> Most payments for online SaaS services are due in advance of consuming the service (rather than in arrears), so billing providers will not let subscriptions be upgraded to paid subscriptions unless a valid payment source is provided beforehand. + +### PCI Compliance + +Capturing payment methods, such as credit cards and bank account details, involves complex regulations and significant costs. This is regulated by [PCI compliance](https://www.investopedia.com/terms/p/pci-compliance.asp). + +For most SaaS companies, it's best to avoid these responsibilities unless it becomes economically viable in the future. + +However, capturing credit card information (in your app) is essential for every SaaS product to support self-serve, especially if you want to charge for your services. + +The good news is that you don't have to handle payment method capture on your own. BMS can offer this capability for you to seamlessly integrate into your product with an SDK and do so in a way that your business never processes credit card information at all. + +SaaStack chooses to exclude payment method capture from the API to avoid PCI compliance requirements. Instead, this task is delegated to BMS-specific SDKs in the web application, which communicates directly with the BMS using JS libraries and code in an `