feat(auth): backfill default-tenant users off the shared tenant on login (PMS-245) #180

Merged
longjacksonle merged 1 commit from feat/mapps-245-backfill-default-tenant-users into main 2026-06-11 19:12:10 +02:00

What

Closes the gap from PMS-244: existing users dumped into the shared default tenant by the pre-PMS-244 funnel (the original PMS-239 complaint) stayed there, because the resolution kept an already-placed user where they were. Only brand-new users got a personal tenant.

How

The bunyip login path now treats a user still parked in the default tenant like a fresh user: with no pending invite they are moved to their own freshly provisioned personal tenant (reusing ensure_personal_tenant + the PMS-243 rehome_user_between_tenants). Lazy migration - each user moves on their next login.

  • Decision #1 (auto-move): yes - that's the ticket. Decision #2 (co-mingled data): left in the default tenant for separate triage (the established PMS-243 policy); only the users row moves.
  • super_admin exempt: platform operators legitimately belong to the infra/default tenant.
  • Invite still wins: an invite takes precedence over the back-fill.
  • Decision is a pure, unit-tested is_stuck_in_default(current, default_tenant, role, has_invite). find_user_tenant -> find_user_placement (returns (tenant_id, role)).
  • Only the Bunyip SSO path is affected; the legacy login path (and its tests) is untouched.

Verification

cargo check --all-targets + cargo clippy --all-targets clean. New backfill_only_non_admin_default_tenant_users_without_invite unit test (target case + super_admin / invite / other-tenant / new-user exemptions). auth (14), tenants (7), invitations (5) pass.

Note

End-to-end (user logs in via Bunyip and is observed to move) is still PMS-249 (mocked OIDC verifier); this PR unit-tests the new decision and reuses the already-tested move primitives.

🤖 Generated with Claude Code

## What Closes the gap from PMS-244: existing users dumped into the shared default tenant by the pre-PMS-244 funnel (the original PMS-239 complaint) stayed there, because the resolution kept an already-placed user where they were. Only brand-new users got a personal tenant. ## How The bunyip login path now treats a user still parked in the default tenant like a fresh user: with no pending invite they are moved to their own freshly provisioned `personal` tenant (reusing `ensure_personal_tenant` + the PMS-243 `rehome_user_between_tenants`). Lazy migration - each user moves on their next login. - **Decision #1 (auto-move)**: yes - that's the ticket. **Decision #2 (co-mingled data)**: left in the default tenant for separate triage (the established PMS-243 policy); only the `users` row moves. - **`super_admin` exempt**: platform operators legitimately belong to the infra/default tenant. - **Invite still wins**: an invite takes precedence over the back-fill. - Decision is a pure, unit-tested `is_stuck_in_default(current, default_tenant, role, has_invite)`. `find_user_tenant` -> `find_user_placement` (returns `(tenant_id, role)`). - Only the Bunyip SSO path is affected; the legacy login path (and its tests) is untouched. ## Verification `cargo check --all-targets` + `cargo clippy --all-targets` clean. New `backfill_only_non_admin_default_tenant_users_without_invite` unit test (target case + super_admin / invite / other-tenant / new-user exemptions). `auth` (14), `tenants` (7), `invitations` (5) pass. ## Note End-to-end (user logs in via Bunyip and is observed to move) is still PMS-249 (mocked OIDC verifier); this PR unit-tests the new decision and reuses the already-tested move primitives. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(auth): backfill default-tenant users off the shared tenant on login (PMS-245)
Some checks failed
Check / fmt + clippy + compile + tests (pull_request) Failing after 11s
E2E (staging) / Playwright against staging (pull_request) Successful in 34s
Build OCI container / Build and push mokosh-api image (push) Successful in 3m53s
Create release / Create release from merged PR (pull_request) Has been skipped
d8b05dfe7e
Closes the gap left by PMS-244: its resolution kept an already-placed user where they were, so the cohort dumped into the shared default tenant by the pre-PMS-244 funnel (the original PMS-239 complaint) stayed there - only brand-new users got a personal tenant.

Now the bunyip path treats a user still parked in the default tenant like a fresh user: with no pending invite they are moved to their own freshly provisioned `personal` tenant (reusing `ensure_personal_tenant` + the PMS-243 `rehome_user_between_tenants`), so nobody stays stuck sharing it. Migration is lazy - each user moves on their next login. Co-mingled data created while everyone shared the default tenant stays put for separate triage (the established PMS-243 decision).

`super_admin`s are exempt: they are platform operators who legitimately belong to the infra/default tenant. The decision is a pure `is_stuck_in_default(current, default_tenant, role, has_invite)` (default tenant + no invite + not super_admin), so it is unit-testable; `find_user_tenant` becomes `find_user_placement` returning `(tenant_id, role)` to feed it. Invite acceptance still takes precedence over the back-fill.

Only the Bunyip SSO path is affected; the legacy login path (and tests that use it) is untouched.

Verification: `cargo check --all-targets` + `cargo clippy --all-targets` clean; new `backfill_only_non_admin_default_tenant_users_without_invite` unit test (target case + super_admin/invite/other-tenant/new-user exemptions); `auth` (14), `tenants` (7), `invitations` (5) suites pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/mapps-245-backfill-default-tenant-users 2026-06-11 19:12:10 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!180
No description provided.