Service split — current, planned, migrating
One system three times: Billing inside one application on a shared database, Billing as its own service with its own database, and the state in between with @migration_target / @planned.
Current (index.krs)
Section titled “Current (index.krs)”// service-split/index.krs: the CURRENT architecture.// The subject of the first-run guide (#3563). Compare it with planned.krs// (the target) and migrating.krs (the state in between).//// Ordering and Billing are separate domains, but both live in one// Commerce Application and share one Commerce Database. The Billing Team// owns the Billing domain without owning any service.
system Commerce { label "Commerce Platform"
user Customer [human] { label "Customer" description "Places orders and pays for them" } user FinanceStaff [human] { label "Finance staff" description "Reviews invoices and refunds" }
service CommerceApp { label "Commerce Application" description "One deployable that holds ordering and billing"
domain Ordering { label "Ordering" usecase PlaceOrder { label "Place an order" resource CommerceDB.Orders { operations create } } usecase TrackOrder { label "Track an order" resource CommerceDB.Orders { operations read } }
Ordering -> Billing "Request an invoice" } domain Billing { label "Billing" usecase IssueInvoice { label "Issue an invoice" resource CommerceDB.Invoices { operations create } resource CommerceDB.Orders { operations read } } usecase CapturePayment { label "Capture a payment" resource CommerceDB.Payments { operations create } } } }
service InventoryWorker { label "Inventory Worker" description "Reserves and releases stock in the background"
domain Inventory { label "Inventory" usecase ReserveStock { label "Reserve stock" resource CommerceDB.Stock { operations update } } } }
service PaymentGateway [external] { label "Payment Gateway" description "Card payments, run by a provider" }
database CommerceDB { label "Commerce Database" description "Shared by every part of the platform" table Orders { label "Orders" } table Invoices { label "Invoices" } table Payments { label "Payments" } table Stock { label "Stock" } }
Customer -> CommerceApp "Order and pay" FinanceStaff -> CommerceApp "Review invoices" CommerceApp -> InventoryWorker "Reserve stock" CommerceApp -> PaymentGateway "Capture payments"}
organization Shop { label "Shop Engineering"
team commerce { label "Commerce Team" description "Builds the storefront and the ordering flow" owns CommerceApp owns Ordering }
team billing { label "Billing Team" description "Owns the invoicing rules, but ships them inside the Commerce Application" owns Billing }
team platform { label "Platform Team" description "Runs the shared database and the background workers" owns InventoryWorker owns Inventory }}Planned (planned.krs)
Section titled “Planned (planned.krs)”// service-split/planned.krs: the TARGET architecture.// Billing runs as its own service with its own database, and the team// that owns the billing rules owns the service that runs them.// Compare it with index.krs (the current architecture).
system Commerce { label "Commerce Platform"
user Customer [human] { label "Customer" description "Places orders and pays for them" } user FinanceStaff [human] { label "Finance staff" description "Reviews invoices and refunds" }
service CommerceApp { label "Commerce Application" description "Storefront and ordering"
domain Ordering { label "Ordering" usecase PlaceOrder { label "Place an order" resource CommerceDB.Orders { operations create } } usecase TrackOrder { label "Track an order" resource CommerceDB.Orders { operations read } } } }
service BillingService { label "Billing Service" description "Invoices and payments, own release cycle"
domain Billing { label "Billing" usecase IssueInvoice { label "Issue an invoice" resource BillingDB.Invoices { operations create } } usecase CapturePayment { label "Capture a payment" resource BillingDB.Payments { operations create } } } }
service InventoryWorker { label "Inventory Worker" description "Reserves and releases stock in the background"
domain Inventory { label "Inventory" usecase ReserveStock { label "Reserve stock" resource CommerceDB.Stock { operations update } } } }
service PaymentGateway [external] { label "Payment Gateway" description "Card payments, run by a provider" }
database CommerceDB { label "Commerce Database" description "Orders and stock" table Orders { label "Orders" } table Stock { label "Stock" } }
database BillingDB { label "Billing Database" description "Owned by billing alone" table Invoices { label "Invoices" } table Payments { label "Payments" } }
Customer -> CommerceApp "Order" Customer -> BillingService "Pay" FinanceStaff -> BillingService "Review invoices" CommerceApp -> BillingService "Request an invoice" CommerceApp -> InventoryWorker "Reserve stock" BillingService -> PaymentGateway "Capture payments"}
organization Shop { label "Shop Engineering"
team commerce { label "Commerce Team" description "Builds the storefront and the ordering flow" owns CommerceApp owns Ordering }
team billing { label "Billing Team" description "Owns the invoicing rules and the service that runs them" owns BillingService owns Billing }
team platform { label "Platform Team" description "Runs the shared database and the background workers" owns InventoryWorker owns Inventory }}Migrating (migrating.krs)
Section titled “Migrating (migrating.krs)”// service-split/migrating.krs: the state IN BETWEEN.// Billing Service is running, but it still reads and writes the shared// Commerce Database: its own Billing Database is planned, not built.// Moving the data is the step that decides when the split is done.
system Commerce { label "Commerce Platform"
user Customer [human] { label "Customer" description "Places orders and pays for them" } user FinanceStaff [human] { label "Finance staff" description "Reviews invoices and refunds" }
service CommerceApp { label "Commerce Application" description "Storefront and ordering"
domain Ordering { label "Ordering" usecase PlaceOrder { label "Place an order" resource CommerceDB.Orders { operations create } } usecase TrackOrder { label "Track an order" resource CommerceDB.Orders { operations read } } } }
service BillingService @migration_target(from: CommerceApp) { label "Billing Service" description "Split out, still on the shared database"
domain Billing { label "Billing" usecase IssueInvoice { label "Issue an invoice" resource CommerceDB.Invoices { operations create } resource CommerceDB.Orders { operations read } } usecase CapturePayment { label "Capture a payment" resource CommerceDB.Payments { operations create } } } }
service InventoryWorker { label "Inventory Worker" description "Reserves and releases stock in the background"
domain Inventory { label "Inventory" usecase ReserveStock { label "Reserve stock" resource CommerceDB.Stock { operations update } } } }
service PaymentGateway [external] { label "Payment Gateway" description "Card payments, run by a provider" }
database CommerceDB { label "Commerce Database" description "Billing tables have not moved yet" table Orders { label "Orders" } table Invoices @deprecated { label "Invoices" } table Payments @deprecated { label "Payments" } table Stock { label "Stock" } }
database BillingDB @planned { label "Billing Database" description "Where the billing tables will move" table Invoices { label "Invoices" } table Payments { label "Payments" } }
Customer -> CommerceApp "Order" Customer -> BillingService "Pay" FinanceStaff -> BillingService "Review invoices" CommerceApp -> BillingService "Request an invoice" CommerceApp -> InventoryWorker "Reserve stock" BillingService -> PaymentGateway "Capture payments"}
organization Shop { label "Shop Engineering"
team commerce { label "Commerce Team" description "Builds the storefront and the ordering flow" owns CommerceApp owns Ordering }
team billing { label "Billing Team" description "Runs Billing Service; depends on the Platform Team for its data until the move" owns BillingService owns Billing }
team platform { label "Platform Team" description "Runs the shared database and the background workers" owns InventoryWorker owns Inventory }}© 2026 Hiroki Kondo · Licensed underApache-2.0