Generate the Service Broker Feature
The service broker feature defines three new record types: the Service
, Plan
, and ServiceInstance
. If you're familiar
with Heroku, CloudFoundry, or the
Open Service Broker spec
then you already know how these work.
- Services and Plans are typically managed through an admin-facing service or a corresponding Admin CLI.
- Services and Plans can typically be displayed as read-only through an end user-facing service or corresponding User CLI.
- Plan records are typically synchronized with a payment provider. For example, if you use Stripe, you would create a Stripe Product record for every SaaS RS Plan record. SaaS RS provides this synchronization code.
- ServiceInstance records are typically maintained by a Stripe Callback endpoint that you would build and use to detect
certain Stripe events such as:
- when a purchase is completed, create a
ServiceInstance
record to track it - when a subscription is canceled, soft-delete the corresponding ServiceInstance record
- update your user service endpoint to check the active ServiceInstance records before deciding to allow certain operations
- when a purchase is completed, create a
Generate the Service Broker feature like this:
$ saas-rs generate feature --name service-broker --service user --version 1
The following content is added or changed in your Rust workspace:
crates/
├── config_store/
│ ├── src/
│ │ └── bucket.rs
└── user_server/
│ └── src/
│ └── v1/
│ ├── controllers/
│ │ ├── mod.rs
│ │ ├── plan.rs
│ │ ├── service.rs
│ │ └── service_instance.rs
│ └── mod.rs
metadata/
└── service_broker/
│ ├── service_1.yaml
│ └── service_2.yaml
proto/
└── acme/
└── user/
└── v1/
├── plan.proto
├── plan_resource.proto
├── service.proto
├── service_resource.proto
├── service_instance.proto
├── service_instance_resource.proto
└── user_service.proto
Bootstrapping ConfigStore Services and Plans with YAML files
The metadata/service_broker/
folder shows two example service definitions and their corresponding plans, defined in
YAML.
The first might be used if you want to charge a one-time membership fee when someone subscribes to it.
kind: Service
id: d1ui8n71t0s84oaqjc30
name: my-service-1
description: My Service 1
visible: true
planUpdateable: false
metadata:
displayName: My Service 1
---
kind: Plan
id: d1ui8n71t0s84oaqjc3g
serviceId: d1ui8n71t0s84oaqjc30
name: default
description: Monthly subscription
metadata:
displayName: Default
costs:
- id: d1ui8n71t0s84oaqjc40
unit: initiation fee
amount:
usd: 100
The second might be used if you wanted to offer the service as a subscription, using variously priced plans:
kind: Service
id: d1ui8n71t0s84oaqjc4g
name: my-service-2
description: My Service 2
visible: true
planUpdateable: true
metadata:
displayName: My Service 2
---
kind: Plan
id: d1ui8n71t0s84oaqjc50
serviceId: d1ui8n71t0s84oaqjc4g
name: basic
description: Basic
metadata:
displayName: Basic
bullets:
- first feature
costs:
- id: d1ui8n71t0s84oaqjc60
unit: per month
recurringInterval: month
amount:
usd: 20
---
kind: Plan
id: d1ui8n71t0s84oaqjc5g
serviceId: d1ui8n71t0s84oaqjc4g
name: professional
description: Professional
metadata:
displayName: Professional
bullets:
- first feature
- second feature
costs:
- id: d1ui8n71t0s84oaqjc6g
unit: per month
recurringInterval: month
amount:
usd: 50
Notice that records are given pre-allocated static XIDs, which are committed to Git. These IDs would also occur as consts in your Rust code. Keep in mind that once you've created at least one service instance for a given plan, you can no longer make changes to the plan, and your only path forward is to discontinue the plan and completely replace it with a new plan that has different parameters. It's up to you to decide how long to service your customers on an old plan. I've seen some managed service providers offer customers 6 months to get off of a plan that is being retired.
A bootstrap mechanism is required to upload these YAML files into corresponding Service
and Plan
buckets in your
ConfigStore. An Admin CLI is typically perfect for this.
Synchronizing Services and Plans with Stripe
Once Service
and Plan
records are defined in your ConfigStore, they need to be synchronized with Stripe. For every
Plan
record, you will want to create a Stripe Product
record, and corresponding Stripe Price
records.
SaaS RS can provide pre-built code that performs this synchronization, but it is not published in open source yet
because it is based on a feature branch of async-stripe, and the saas-rs-sdk
crate cannot reference any non-tagged feature branches of its dependencies (a restriction imposed by crates.io).
Once your Stripe Product
records exist, you can log into the Stripe console and test by generating a new invoice or
subscription that contains one or more products. Then your web front-end team may decide to offer end users a
self-service way to do this, to automate it. This is only suitable in situations where you're willing to disclose
your pricing. This would typically not be the case for professional services oriented service offerings.