Skip to main content
Version: v1.0.0(int)

W020: Send invitation

Creates a tokenized invitation for a prospective member and emails them the accept link. Triggered from Settings, Users, Invite. Idempotent on repeat invites to the same pending email.

Steps

  1. Block invites to existing members. Call Platform.userExistsByEmailInOrg(email, orgId). If true, reject.

  2. Reject owner role. Ownership transfer is a separate (out-of-scope-for-v1) flow.

  3. Short-circuit on existing pending invite. Call Platform.findPendingInvitation(orgId, email). If a pending unexpired invite already exists for this email in this org, re-send the email and return that invite. Skip steps 4 and 5.

  4. Persist the invitation. Call Platform.createInvitation({ orgId, email, role, invitedBy }). The L2 op generates the opaque token and sets expires_at = NOW() + 7 days by DB default.

  5. Send the invitation email. Subject and body include the accept link with the token. Email failure is surfaced to the caller as a warning but does not roll the invitation back; admins can resend later (W009).

Returns

The created (or pre-existing pending) invitation.

Business rules

  • Owner or admin only. Authorization is enforced at the request boundary.
  • Re-inviting is idempotent. A second invite for the same email in the same org returns the existing pending invite and re-sends its email. No duplicate row is created.
  • Tokens are opaque, single-use, and expire. The Accept workflow (W011) rejects expired or already-consumed tokens.
  • Owner role is not invitable. Owners are appointed via ownership transfer (future), not invitations.

Errors

  • ValidationError. The email already belongs to a member of this org, or the requested role is owner.