Add tenant provisioning and provisioning hooks - #37
Merged
Merged
Conversation
Closes #11. Closes #6. Onboarding was a three-step recipe every adopter wrote by hand, and step three is the one they got wrong: seed data written with no tenant bound fails the policy under row-level security and has no connection at all under database-per-tenant, so onboarding half-succeeded. `TenantProvisioning.onboard` does the sequence, and runs each hook with the new tenant bound so an implementation writes seed data with ordinary repository calls. The order is the design. A tenant exists as PROVISIONING before anything is done for it, gets its storage, gets its hooks, and only then becomes ACTIVE — a tenant marked ACTIVE before its hooks have run is briefly live and broken. PROVISIONING is a new status, and it is what makes a failure unambiguous. A half-created tenant that is simply absent looks like one nobody asked for; one left ACTIVE looks ready and is not. This is neither: it is not served, forEachTenant skips it, and the exception names the hook that failed. Onboarding is idempotent — an ACTIVE tenant is returned untouched, so a retried webhook or a redelivered message is safe, and a tenant left PROVISIONING is resumed. That means hooks must tolerate running twice, which is documented rather than assumed. It provisions THIS service. It cannot reach the other nineteen in an estate, and an API pretending otherwise would lie — under row-level security they have nothing to do anyway, since the tables are shared. TenantMigrationRunner now exposes migratesPerTenant() so onboarding skips Flyway entirely under a shared store rather than starting it to find nothing to apply. Mutation-tested: marking ACTIVE up front, running hooks unbound, continuing past a hook failure, dropping idempotency, and ignoring hook order each turned tests red, with the revert confirmed in the compiled bytecode. Library 161 tests green. order-service 39 green, including three where the seeding hook writes through the real repository — an insert the policy rejects unless provisioning bound the tenant, so removing that binding fails the consumer suite, which was verified. Signed-off-by: suchait007 <159273969+suchait007@users.noreply.github.com>
suchait007
added a commit
that referenced
this pull request
Sep 9, 2026
Both were squash-merged, so main carries their content as new commits while this branch still had the originals — which is why a stacked branch conflicts even when the content agrees. All four conflicts were additive and both sides are kept: two optional dependencies in the pom, two autoconfiguration registrations, two documentation rows. The exception is order-service's pom, where both branches had added spring-boot-starter-actuator; that is now one dependency with a comment covering both reasons. Repaired a broken dependency block on the way: resolving the pom by concatenating the two sides split a <dependency> element and produced invalid XML, which the build caught. Library 183 tests green, order-service 45 green. Signed-off-by: suchait007 <159273969+suchait007@users.noreply.github.com>
9 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #11. Closes #6.
The order is the design
A tenant marked ACTIVE before its hooks have run is briefly live and broken.
Why hooks run with the tenant bound
This is the bug the feature exists to remove. Onboarding was a three-step recipe every adopter wrote by hand, and step three is the one they got wrong — seed data written with no tenant bound fails the policy under row-level security and has no connection at all under database-per-tenant. So onboarding half-succeeded.
A hook now writes seed data with ordinary repository calls and no tenant parameter.
PROVISIONING, and why it exists
A half-created tenant that is absent looks like one nobody asked for. One left ACTIVE looks ready and is not.
PROVISIONINGis neither: not served, skipped byforEachTenant, and the exception names the hook that failed.Onboarding is idempotent, so retrying is just calling it again — which means hooks must tolerate running twice, documented rather than assumed.
Scope, stated honestly
onboardprovisions this service. It cannot reach the other nineteen in an estate, and an API pretending otherwise would lie. Under row-level security they have nothing to do anyway — the tables are shared. The docs describe the control-plane pattern and the three coordination options rather than inventing one.TenantMigrationRunnernow exposesmigratesPerTenant(), so onboarding skips Flyway entirely under a shared store rather than starting it to discover there is nothing to apply.Verification
Reverts confirmed in compiled bytecode.
Library 161 green. order-service 39 green, including three where the seeding hook writes through the real repository — an insert the policy rejects unless provisioning bound the tenant. Removing that binding fails the consumer suite, which I verified rather than assumed.
Docs:
docs/onboarding.md.