Skip to content
Menu

Documentation

Standard Modules

Sandloom publishes three ready-made modules for products that need accounts, organizations or payments. They follow the same rules as your own modules, and all three are optional: --no-batteries creates an application with none of them. Each is its own package: sandloom-identity, sandloom-tenancy and sandloom-billing (import packages sandloom_identity, sandloom_tenancy, sandloom_billing; all three with pip install "sandloom[standard]"). Each registers a sandloom.modules entry point whose name is its module name, depends on sandloom>=0.7.0a6,<0.8 and on no other module, and follows the same isolation rules as a module you write yourself (Module packages). Load any subset via SANDLOOM_MODULES (["identity", "tenancy"]), or sandloom new <app> --with identity,tenancy,billing. Sandloom is in alpha, and so are these modules.

The startup-critical column is the module's required flag: when the module is loaded and fails to start, the process does not serve traffic. It does not mean your application must install the module. Authenticated routes need a token issuer, which is what identity provides.

To change how they behave, see Customize a standard module.

Module Startup-critical Provides Publishes Consumes
Identity ✅ identity.claims.v1 (roles/permissions, critical), auth guards, token issuance 15 identity.* events every registered <module>.claims.v1 at token mint
Tenancy ❌ tenancy.membership.v1 (read-only), tenancy.claims.v1 (tenant_ids, critical) 9 tenancy.* events —
Billing ❌ billing.entitlements.v1, billing.credits.v1, billing.claims.v1; access facts subscription.active, organization.subscription.active 5 billing.* events tenancy.membership.v1

<module>.claims.v1 contracts are registered automatically by add_claims_contributor; a token issuer in another process collects them over internal RPC when they are bound in SERVICE_BINDINGS.

Every service contract takes no database session: each call runs in the provider's own Unit of Work on the provider's database, identically in-process and over RPC. Command contracts (billing.credits.v1.spend) are idempotent on their operation key and are not atomic with the caller's transaction.

These modules talk to each other only through versioned events and service contracts — never direct imports — exactly like the isolation rules require. Your app calls their contracts through their stubs in sandloom.shared.contracts (shipped with sandloom, with the generated copies of their contract DTOs; sandloom generate also writes stubs and copies into the app's shared package).