- Shipped
- August 11, 2026 at 6:09 PM UTC
- Author
- Kamo
- Commit
- 9276487
A group could be named and nothing else. Its subscription was never set — nothing in the platform called setSubscription — so subscription_uid stayed null forever and the group could not buy or hold a single seat. Three things had to change in the model: BillingGroupMember is new. Seat truth stays where it was, on SubscriptionMember and AccountLicense, but SubscriptionMember.subscription is NOT NULL, so until a group buys a plan there is nowhere to record the people it exists to cover — and gathering people before buying seats for them is the whole point. This is intent; that is entitlement. AccountSubscription gains billingGroupUid, and the (account, market, target org) unique constraint moves out of the entity. A group bills its manager, on the manager's own account, targeting the same org in the same market as any seat that manager already bought for themselves — the same tuple. So a group's first purchase did not fail, it found the manager's personal subscription and rewrote it: plan, seats, Stripe id. No exception, no second row. The rule now lives as two partial unique indexes that JPA cannot express, created by KamoInitializer; the entity declaration had to go or ddl-auto would recreate the old constraint ahead of the runner that drops it. **************** is deleted rather than deprecated. It returns Optional on the strength of a constraint that no longer exists, so once one account holds both a personal and a group subscription it matches two rows and throws at all five call sites across three services. Leaving it to be found by autocomplete was the more dangerous option. Also: allowsGroups() now includes REQUIRES_APPROVAL. Excluding it made the approval path unreachable — creating a group was refused outright, while the code setting the approved flag asked requiresApproval() and so could only ever answer "already approved". An owner who chose oversight got no groups at all.