fix(team-vault): reconcile vault-key distribution for keyless members (#41)#49
Open
kipavy wants to merge 1 commit into
Open
fix(team-vault): reconcile vault-key distribution for keyless members (#41)#49kipavy wants to merge 1 commit into
kipavy wants to merge 1 commit into
Conversation
…#41) Team vault-key distribution was purely event-driven: the key was wrapped for members only at team creation and via the live team_members SSE diff. A member who accepted an invite while the only key-holder was offline — or the very first invitee, whom the adder's own membership event never counts as "new" — was left with no key and silently locked out, polling GET vault-key → 404 until the inviter happened to reconnect. Add a reconciliation pass. reconcileTeamVaultKeys() compares team_members against the server's key-holder list and wraps the key for anyone missing it. It runs on a key-holder's login (onTeamLogin) and on every membership change (team_members SSE handler, replacing the old local-diff logic that missed the adder-is-only-key-holder case). Non-holders no-op; only genuinely keyless members trigger a PUT, so repeated runs don't churn or re-notify existing holders. Detection uses a new GET /v1/teams/:id/vault-key/holders endpoint (returns user_ids with a key) via teamService.getVaultKeyHolders(), so the client distributes to the precise missing set instead of blindly re-wrapping for everyone. Invitee UX: the not_found state now renders a dedicated "Waiting for access" screen (previously bucketed with generic errors, and never even shown because not_found was missing from the state-screen gate) so the member sees a clear waiting state instead of a blank/failed vault. Tests: reconcile distributes only to the missing set / no-ops when all hold a key / no-ops for non-holders; getVaultKeyHolders transport shape. Server endpoint tested separately in VoltiusApp/server.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #41.
Problem
Team vault-key distribution was purely event-driven — the key was wrapped for members only at team creation and via the live
team_membersSSE diff. Two normal flows left a member permanently keyless and silently locked out (client pollingGET vault-key → 404until the inviter next came online):addMemberByIdloads members before the adder's ownteam_membersevent fires, so the local diff sees zero newcomers and skips distribution.There was no reconciliation for members who already exist but lack a key.
Fix
Reconciliation (
reconcileTeamVaultKeys). Comparesteam_membersagainst the server's key-holder list and wraps the key for anyone missing it. Runs:onTeamLogin) — self-heals the async-acceptance lockout;team_membersSSE handler) — replacing the old local-diff logic, which also fixes the adder-is-only-key-holder case.Non-holders no-op (they can't unwrap the key). Only genuinely keyless members trigger a
PUT, so repeated runs don't churn or re-notify existing holders. The missing set is computed precisely via a new server endpoint (getVaultKeyHolders→GET /v1/teams/:id/vault-key/holders).Invitee UX.
not_foundnow renders a dedicated "Waiting for access" screen. Previously it was bucketed with generic errors — and never even shown, sincenot_foundwas missing from the state-screen gate inMainPanel.Tests
reconciledistributes only to the missing set / no-ops when all hold a key / no-ops for non-holdersgetVaultKeyHolderstransport shapetsccleanCompanion
Server endpoint: VoltiusApp/server#2 (must merge for reconciliation to function; the client degrades gracefully — reconcile catches the failure and no-ops — if the endpoint is absent).
🤖 Generated with Claude Code
https://claude.ai/code/session_01RnVt37SuhKfm94kpkh8rez