@sourceloop/ctrl-plane-subscription-service
v1.2.1
Published
Subscription management microservice for SaaS control plane.
Downloads
712
Readme
@sourceloop/ctrl-plane-subscription-service
Overview
The Subscription Service is a core component of the ARC SaaS control plane, responsible for managing subscription plans, billing cycles, and invoice generation.
Key Features
- Plan Management: Create and manage subscription plans with different tiers (siloed/pooled)
- Plan Customization: Configure plan sizes and feature sets for different service tiers
- Subscription Lifecycle: Create, update, and track subscriptions throughout their lifecycle
- Feature Toggle Integration: Dynamic feature management using @sourceloop/feature-toggle-service
- Billing Integration: Built-in support for Stripe and Chargebee payment processors via loopback4-billing
- Invoice Management: Generate and manage customer invoices
- Multi-ORM Support: Default LoopBack CRUD + Sequelize component option
- OpenTelemetry: Distributed tracing support with Jaeger exporter
Installation
npm i @sourceloop/ctrl-plane-subscription-serviceGetting Started
Basic Setup
- Create a LoopBack 4 Application (if you don't have one already):
lb4 testapp- Install the service:
npm i @sourceloop/ctrl-plane-subscription-serviceSet the environment variables (see Environment Variables)
Run the migrations (see Migrations)
Add the component to your application (
application.ts):
import {SubscriptionServiceComponent} from '@sourceloop/ctrl-plane-subscription-service';
export class MyApplication extends BootMixin(
ServiceMixin(RepositoryMixin(RestApplication)),
) {
constructor(options: ApplicationConfig = {}) {
super(options);
this.component(SubscriptionServiceComponent);
}
}Sequelize ORM Support
If you prefer to use Sequelize as your ORM:
import {SubscriptionSequelizeServiceComponent} from '@sourceloop/ctrl-plane-subscription-service/sequelize';
// In your application constructor
this.component(SubscriptionSequelizeServiceComponent);Custom Authentication Sequence
This microservice uses loopback4-authentication and @sourceloop/core. By default, it uses asymmetric token encryption. To override with a custom sequence:
- Install required packages:
npm install @sourceloop/core loopback4-authorization loopback4-authentication- Configure in
application.ts:
import {
AuthenticationComponent,
BearerVerifierComponent,
BearerVerifierBindings,
BearerVerifierConfig,
BearerVerifierType,
ServiceSequence,
} from '@sourceloop/core';
import {AuthorizationBindings, AuthorizationComponent} from 'loopback4-authorization';
// Use custom sequence
this.bind(SubscriptionServiceBindings.Config).to({
useCustomSequence: true,
});
this.component(AuthenticationComponent);
this.sequence(ServiceSequence);
// Add bearer verifier component
this.bind(BearerVerifierBindings.Config).to({
type: BearerVerifierType.service,
useSymmetricEncryption: true,
} as BearerVerifierConfig);
this.component(BearerVerifierComponent);
// Add authorization component
this.bind(AuthorizationBindings.CONFIG).to({
allowAlwaysPaths: ['/explorer', '/openapi.json'],
});
this.component(AuthorizationComponent);
// Comment out default sequence
// this.sequence(MySequence);Data Source Configuration
The service requires two datasources:
1. SubscriptionDB - Main subscription data:
import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
import {juggler} from '@loopback/repository';
import {SubscriptionDbSourceName} from '@sourceloop/ctrl-plane-subscription-service';
const config = {
name: SubscriptionDbSourceName,
connector: 'postgresql',
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
schema: process.env.DB_SCHEMA,
};
@lifeCycleObserver('datasource')
export class SubscriptionDb extends juggler.DataSource implements LifeCycleObserver {
static dataSourceName = SubscriptionDbSourceName;
static readonly defaultConfig = config;
constructor(
@inject(`datasources.config.${SubscriptionDbSourceName}`, {optional: true})
dsConfig: object = config,
) {
super(dsConfig);
}
}2. FeatureToggleDB - Feature toggle data:
import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
import {juggler} from '@loopback/repository';
import {FeatureToggleDbName} from '@sourceloop/feature-toggle-service';
const config = {
name: FeatureToggleDbName,
connector: 'postgresql',
host: process.env.FEATURE_DB_HOST,
port: process.env.FEATURE_DB_PORT,
user: process.env.FEATURE_DB_USER,
password: process.env.FEATURE_DB_PASSWORD,
database: process.env.FEATURE_DB_DATABASE,
schema: process.env.FEATURE_DB_SCHEMA,
};
@lifeCycleObserver('datasource')
export class FeatureToggleDb extends juggler.DataSource implements LifeCycleObserver {
static dataSourceName = FeatureToggleDbName;
static readonly defaultConfig = config;
constructor(
@inject('datasources.config.feature', {optional: true})
dsConfig: object = config,
) {
super(dsConfig);
}
}Plan Customization
This feature allows the creation and management of plans with different sizes and feature sets.
Plan Sizes
Plan sizes define the scope or capacity of a plan:
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| size | string | Y | Name/label of the plan size (e.g., "Standard", "Premium") |
| config | object | N | Additional configuration specific to the plan size |
Example: The "Standard" plan may include less database capacity than the "Premium" plan.
Plan Features
Uses the @sourceloop/feature-toggle-service to manage feature sets for plans.
| Concept | Description | |---------|-------------| | Feature | A general capability offered in plans | | FeatureValues | Associates features with specific plans and configures their values |
Billing Integration
The service integrates billing functionality using loopback4-billing, supporting multiple payment providers.
Enable Billing Component
import {BillingComponent} from 'loopback4-billing';
this.application.component(BillingComponent);Use Billing Provider
import {BillingComponentBindings, IService} from 'loopback4-billing';
export class BillingInvoiceController {
constructor(
@inject(BillingComponentBindings.BillingProvider)
private readonly billingProvider: IService,
) {}
}Stripe Configuration
Environment Variables:
| Variable | Required | Description |
|----------|----------|-------------|
| STRIPE_SECRET | Y | Stripe secret key |
Application Setup:
import {StripeBindings, BillingComponentBindings} from 'loopback4-billing';
import {StripeServiceProvider} from 'loopback4-billing';
// Bind config
this.bind(StripeBindings.config).to({
secretKey: process.env.STRIPE_SECRET ?? '',
});
// Register provider
this.bind(BillingComponentBindings.SDKProvider).toProvider(
StripeServiceProvider,
);Chargebee Configuration
Environment Variables:
| Variable | Required | Description |
|----------|----------|-------------|
| API_KEY | Y | Chargebee API key |
| SITE | Y | Chargebee site URL |
Application Setup:
import {ChargeBeeBindings, BillingComponentBindings} from 'loopback4-billing';
import {ChargeBeeServiceProvider} from 'loopback4-billing';
// Bind config
this.bind(ChargeBeeBindings.config).to({
site: process.env.SITE ?? '',
apiKey: process.env.API_KEY ?? '',
});
// Register provider
this.bind(BillingComponentBindings.SDKProvider).toProvider(
ChargeBeeServiceProvider,
);API Documentation
Visit the OpenAPI spec docs for complete API documentation.
Main Controllers:
- PlanController - Plan CRUD operations
- PlanSizesController - Plan size management
- PlanFeaturesController - Plan feature configuration
- SubscriptionController - Subscription lifecycle management
- BillingInvoiceController - Invoice generation and management
- BillingCustomerController - Customer billing information
- BillingCycleController - Billing cycle management
- CurrencyController - Currency management
- ResourceController - Resource allocation tracking
- ServiceController - Service catalog management
Database Schema

Core Tables:
| Table | Description | |-------|-------------| | Plan | Subscription plan definitions | | PlanSize | Plan size configurations | | FeatureValue | Feature values for plans | | Subscription | Active subscriptions | | Invoice | Billing invoices | | Resource | Allocated resources | | Service | Available services |
Environment Variables
Migrations
Copy the migrations from the service and customize as needed:
cp -r node_modules/@sourceloop/ctrl-plane-subscription-service/migrations ./migrationsThen apply them to your database.
License
ARC SaaS is MIT licensed.
