- Shipped
- August 23, 2026 at 2:45 AM UTC
- Author
- Kamo
- Commit
- 748ae48
A @Transactional method called from **************** does not open a transaction of its own. Spring fires those callbacks from processCommit BEFORE cleanupAfterCompletion unbinds the thread's transactional resources, so the just-committed transaction is still active and default REQUIRED propagation simply participates in it — and a participant is never committed again. Everything the method writes is discarded when the EntityManager closes, with no exception and no log line. 3903267 moved billing-seat provisioning and the System User TeamMember backfill out of createOrganization's transaction into afterCommit, under a comment saying they now ran "in their own transactions". Neither was changed to REQUIRES_NEW, so from that day both wrote nothing: - Every org created since has no account_subscriptions row at all. Its owner resolves to MemberCapabilities.unlicensed() — no email, no meetings, no calls, no attachments — and cannot recover by signing in, because maybeStartTrialOnLogin starts the clock on a PENDING trial that was never created. The only escape was the owner happening to open Settings → Plans & Billing, whose bootstrap-billing endpoint is documented as a fallback for orgs that pre-dated billing. - No org got the System User membership POST /enter-as requires, so entering one as System Member answers "System User membership missing in target org; backfill pending". This half hid for two weeks because DataLoader re-runs a full System User backfill on every boot; only an org created between two restarts ever showed it. ensureSystemUser, ensureTeamMemberForOrg and the id-based setupForSubOrgCreation are now REQUIRES_NEW. The Organization overload keeps REQUIRED — its caller (AccountController) is an ordinary request path that should share the caller's transaction. **************** scans every afterCommit body in the service, resolves each field.method(...) call to the callee's source, and fails on @Transactional without REQUIRES_NEW. @Async and CompletableFuture.runAsync are exempt: a fresh thread does get a fresh transaction, which is why the email-seed and DNS-provision hooks were never affected. BillingBackfillService heals the orgs already left without a subscription, on boot, the way the System User backfill does. It restores exactly what creation would have written — a PENDING trial — so the 3-day clock still starts on the owner's first real login and nobody loses evaluation time they never got to use. Each org is healed by its own REQUIRES_NEW call, so one bad org costs only itself instead of discarding the whole pass the way ensureTeamMembersForAllOrgs would.