Skip to content

fix: resilient member lookup in TeamComponent (#59)#61

Merged
poxet merged 1 commit into
masterfrom
feature/teammember-duplicate-fix
May 10, 2026
Merged

fix: resilient member lookup in TeamComponent (#59)#61
poxet merged 1 commit into
masterfrom
feature/teammember-duplicate-fix

Conversation

@poxet
Copy link
Copy Markdown
Contributor

@poxet poxet commented May 10, 2026

Summary

Fixes #59.

<TeamComponent /> no longer crashes the team-management page when a team document carries duplicate TeamMember rows for the same Key (e.g. from a migration glitch or missing unique constraint). Five member-lookup sites in TeamComponent.razor previously used .Single(predicate), which threw InvalidOperationException on duplicates and bricked the page until reload — once tripped, every subsequent click on a different row also threw.

  • RemoveUserFromTeam, ChangeRole, ChangeTenantRoles, ChangeScopeOverrides, HasAccessLevel all now go through a new TeamMemberResolver.Resolve(...) helper.
  • Helper returns the first match, returns null when no match, and logs a warning (with team key, lookup key, count) when duplicates are found — so operators can find and clean up the bad rows.
  • Action handlers gracefully notify the user ("Member not found — please reload") and bail without throwing if the member has disappeared between renders. HasAccessLevel returns false defensively.

The repository layer is unchanged in this PR — duplicates remain operator-cleanup. Adding a unique index on (TeamKey, UserKey) to prevent duplicates going forward is tracked separately.

Consumer impact

  • No public API change. The fix is internal resilience.
  • Consumers that have observed Sequence contains more than one matching element from TeamComponent should pick this up on next package upgrade — the page will stay usable, and a warning will appear in logs identifying the duplicate.

Test plan

  • 5 new unit tests in TeamMemberResolverTests cover no-match (returns null), single match (returns it), 2 / 3 matches (returns first + logs warning with count), and null logger (does not throw).
  • dotnet build -c Release — clean, 0 warnings, 0 errors.
  • dotnet test -c Release — 268 / 268 passing (was 263, +5 new).
  • Production verification on consumer hitting the duplicate-row scenario (no local repro available — operator will confirm).

A team document with duplicate TeamMember rows for the same Key
(e.g. from a migration glitch) bricked the team-management page —
every .Single(predicate) call site in TeamComponent threw
InvalidOperationException, and once tripped, every subsequent click
in that team also threw.

Replace the 5 .Single(predicate) sites in TeamComponent.razor
(RemoveUserFromTeam, ChangeRole, ChangeTenantRoles,
ChangeScopeOverrides, HasAccessLevel) with a small TeamMemberResolver
helper that returns the first match, returns null when no match,
and logs a warning when duplicates are found. Action handlers
gracefully notify the user and bail when the member has gone
missing; HasAccessLevel returns false.

The repository layer is unchanged; duplicates remain operator-cleanup
(separately tracked).
@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

❌ Patch coverage is 22.58065% with 24 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...arga.Team.Blazor/Features/Team/TeamComponent.razor 0.00% 24 Missing ⚠️

📢 Thoughts on this report? Let us know!

@poxet poxet merged commit 9f0f6f5 into master May 10, 2026
4 of 6 checks passed
@poxet poxet deleted the feature/teammember-duplicate-fix branch May 10, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TeamComponent.RemoveUserFromTeam throws on duplicate TeamMember rows (.Single predicate)

1 participant