Files
Enterprise-Knowledge-Base/migrations/sqlite
wizardchen 7720db39fa fix(rbac): dedup pending join/upgrade requests per (org, tenant, type)
Plan 3 of #1303 changed the join-request lookup key from per-user
to per-tenant (GetPendingRequestByTenantAndType), but didn't touch
existing data or add a structural constraint. Result: any (org,
tenant) that had multiple pending rows under the old per-user model
now has ambiguous "which one wins" semantics — the LIMIT 1 query
returns one row, the others stay pending and resurface in admin
lists after the first is approved/rejected.

Two fixes:

1. Migration 000045 up.sql now collapses pre-existing pending rows
   to one per (org, tenant, type), keeping the earliest by
   created_at. The losers are flagged status='rejected' with a
   '[Plan 3] superseded' review_message so the audit trail shows
   it was a system cleanup, not a human reject. down.sql drops
   the new index but leaves the data mutation in place — we don't
   have enough information to safely re-promote the discarded rows.

2. Add a partial unique index on
   (organization_id, tenant_id, request_type) WHERE status='pending'
   to both the PG migration and the SQLite init schema. This makes
   the invariant structural so SubmitJoinRequest /
   RequestRoleUpgrade cannot regress.

Approved/rejected history is intentionally unconstrained so the
audit trail remains complete.
2026-05-18 17:28:58 +08:00
..