Skip to content

Invite acceptance is never actually consumed — new/existing users never join the group #268

Description

@chiptus

Problem

Group invite links validate and display correctly, but accepting an invite never actually adds the user to the group. The use_invite_token(token, user_id) RPC — the only thing that inserts a group_members row — is never called anywhere in the app.

Trace

  1. Someone clicks a group invite link → lands at /?invite=<token>RootContent (src/routes/__root.tsx) validates the token via useInviteValidation and renders InviteLandingPage ("You're Invited! Join Group").
  2. They sign up through AuthDialog (magic link or OTP). useSignInWithOtpMutation (src/api/auth/useSignInWithOtpMutation.ts) stashes the invite token in user_metadata.invite_token and in the magic-link redirect URL (?invite=<token>), but that's all it does with it.
  3. InviteLandingPage's onSignupSuccess prop is wired to a no-op — onSignupSuccess={() => {}} in src/routes/__root.tsx:108.
  4. useInviteValidation.ts exposes an acceptInvite(userId) function that wraps useInviteMutation() (which calls the use_invite_token RPC) — but nothing in the codebase calls acceptInvite. Confirmed via full-repo search: only __root.tsx calls useInviteValidation(), and it destructures just { inviteValidation, isValidating, hasValidInvite }.
  5. There's no database trigger that consumes invite_token from auth.users metadata either (checked supabase/migrations/*create_functions.sqluse_invite_token is designed to be called explicitly from the client, it's SECURITY DEFINER but not trigger-attached).

Net effect: a user can go through the entire "you're invited → sign up" flow and never end up in group_members. The invite is validated but never redeemed.

Fix

Wire onSignupSuccess (and the equivalent path for an existing user who clicks an invite link while logged out then logs in) to actually call acceptInvite(user.id) once a session exists, and surface success/failure (toast, redirect into the group, etc.). Needs to handle both:

  • A brand-new user completing OTP verification inside AuthDialog.
  • The magic-link click landing back on /?invite=<token> with a fresh session (no callback fires here — this needs an effect keyed on user + inviteToken becoming available).

Acceptance criteria

  • A new user who signs up via a group invite link ends up as a group_members row for that group after completing signup (magic link and OTP paths both work).
  • An existing (logged-out) user who clicks an invite link, then logs in, is added to the group.
  • A user already in the group who reuses an invite link doesn't error or duplicate (already handled server-side by use_invite_token, just needs to surface cleanly).
  • Some visible confirmation (toast and/or redirect) that they joined the group.
  • Existing InviteLandingPage "Invalid Invite" / expired / deactivated states are unaffected.

Context

Found while reviewing PR #267 (mutateAsyncmutate migration), which touched useInviteValidation.ts's acceptInvite (formerly useInvite) without being aware it had no caller.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions