Add Team Invites to a SaaS App
Build a real team invitation system for a SaaS app, including invite creation, email/share flow, acceptance, membership creation, role assignment, validation, and end-to-end testing.
The route
10 steps to Done
- 01
Audit Existing Team, User, and Auth Models
Map the current app structure so the invite system integrates with real existing models and permission rules.
Preview prompt + verify gate ▾ Hide ▴
Review the existing codebase and identify the real models, routes, and UI related to users, teams, memberships, and authentication. Show me the current schema for users, teams, and team memberships, identify who currently has admin or owner privileges, and propose the minimal integration plan for adding team invitations. Do not implement anything yet; first give a concrete implementation plan tied to the actual files and models already in the app.
- ✓ Existing user model is identified
- ✓ Existing team and membership models are identified
- ✓ Current role or permission logic is documented
- ✓ Files/routes/components to modify are named explicitly
- 02
Add Invitation Data Model and Migration
Create persistent backend storage for invites so links and statuses are real.
Preview prompt + verify gate ▾ Hide ▴
Implement a persistent invitation model in the existing database layer. Add fields for: id, teamId, email, role, inviterUserId, secure token or tokenHash, status (pending/accepted/revoked/expired), expiresAt, acceptedAt, acceptedByUserId, createdAt, and updatedAt. Add useful indexes for token lookup, team lookup, email lookup, and duplicate active invite checks. Reuse the app's current schema conventions and migration system, and show the exact files changed.
- ✓ Invitation table/model exists in schema
- ✓ Status and expiration fields are present
- ✓ Team, inviter, and accepter references are defined
- ✓ Indexes or constraints for lookup and duplicates are added
- 03
Implement Secure Invite Creation API
Create the server-side action or endpoint that authorized users use to generate invites.
Preview prompt + verify gate ▾ Hide ▴
Create a real server-side invitation creation flow integrated into the app's existing API or action pattern. It must: require authentication, verify the requester is allowed to invite users for that team, validate the email and role, normalize the email, prevent creating an invite for someone already in the team, prevent duplicate active pending invites for the same team and email where appropriate, generate a secure random token, persist the invite record, and return a usable invite URL. Use the existing permission and team membership system rather than adding custom parallel logic.
- ✓ Unauthenticated users cannot create invites
- ✓ Non-admin/non-owner team members cannot create invites
- ✓ Invalid email or role is rejected
- ✓ Duplicate pending invites are blocked or handled explicitly
- ✓ Existing team members cannot be invited again
- 04
Build the Team Invite Management UI
Add a usable interface for admins to create, review, and revoke invites.
Preview prompt + verify gate ▾ Hide ▴
Implement a working invite management interface in the existing team administration area. Add an invite form with email input and role selector, wire it to the real invite creation action, and display validation and success states. Also add a list or table of pending and recent invites showing email, role, inviter, status, creation date, expiration date, and actions such as copy link and revoke. Reuse existing design patterns and fetch real invite data from the backend.
- ✓ Invite form is visible to authorized users only
- ✓ Submitting the form creates a real invite
- ✓ Pending invites render from backend data
- ✓ Revoke action is available for pending invites
- ✓ Loading, success, and error states are visible
- 05
Implement Invite Link Lookup and Acceptance Screen
Create the public or semi-public acceptance flow that resolves an invite token and guides the recipient.
Preview prompt + verify gate ▾ Hide ▴
Implement a real invite acceptance route or page that receives the token from the URL, performs a server-side invite lookup, validates status and expiration, and renders appropriate states. For a valid invite, show the team name, invited email, assigned role, and next action. If the user is not authenticated, preserve the token through sign-in and continue the acceptance flow after login. If invalid, expired, revoked, or already accepted, show a specific error state.
- ✓ Tokenized invite route exists
- ✓ Server-side lookup validates the token against stored invite data
- ✓ Signed-out users are prompted to authenticate
- ✓ Invalid, expired, revoked, and accepted states are distinct
- ✓ Valid invite details show correct team and role
- 06
Implement Final Invite Acceptance and Membership Creation
Convert a valid invite into a real team membership and mark the invite as accepted.
Preview prompt + verify gate ▾ Hide ▴
Create the server-side invite acceptance mutation. It must require authentication, reload the invite from the database, verify the token is valid, ensure the invite is pending and not expired or revoked, optionally verify the signed-in user's email matches the invited email if your app requires that rule, check that the user is not already a team member, create the team membership with the invited role, mark the invite as accepted with acceptedAt and acceptedByUserId, and handle the write atomically if supported by the stack.
- ✓ Accept action requires authentication
- ✓ Membership row is created in the database
- ✓ Invite status changes from pending to accepted
- ✓ Duplicate membership is prevented
- ✓ Partial-write failure is avoided or handled
- 07
Add Revoke, Expiration, and Edge-Case Handling
Make the invite system robust against stale or invalid invite states.
Preview prompt + verify gate ▾ Hide ▴
Implement the remaining invite lifecycle rules. Add a server-side revoke action limited to authorized users, update the invite list UI to reflect revoked and expired states, ensure expired invites are rejected during lookup and acceptance, and make sure already accepted invites cannot be reused. Also handle existing-member cases, repeated clicks on accept, and cases where invite records exist for users who have since joined the team another way.
- ✓ Authorized users can revoke pending invites
- ✓ Revoked invites cannot be accepted
- ✓ Expired invites are blocked in lookup and acceptance
- ✓ Already accepted invites cannot be reused
- ✓ Existing members are handled cleanly
- 08
Wire Email or Share-Link Delivery
Make the invitation usable by actually delivering or exposing the link.
Preview prompt + verify gate ▾ Hide ▴
Integrate invitation delivery with the app's actual capabilities. If the project already has an email provider, send a real invitation email containing the invite link, team name, inviter name, and role. If email is not configured, implement a clear copy-link workflow in the UI and explicitly show that the invite link must be shared manually. In either case, only show delivery success if the underlying operation really succeeded.
- ✓ Email is only used if real email infrastructure exists
- ✓ Copy-link flow works if email is unavailable
- ✓ Delivery success is tied to real underlying result
- ✓ Invite URL includes the correct token
- 09
Add Validation, Permissions, and UX Guardrails
Polish the system so invalid actions fail clearly and authorized flows feel reliable.
Preview prompt + verify gate ▾ Hide ▴
Review the entire invitation feature and add missing validation and guardrails. Confirm only allowed roles can be assigned by the inviter, optionally enforce whether only the invited email can accept the invite if that matches the app's policy, disable invite actions in the UI when the user lacks permission, and make backend error responses map to clear user-facing messages. Ensure all forms have loading states and prevent accidental double submission.
- ✓ Backend and UI permission rules match
- ✓ Role assignment is restricted appropriately
- ✓ Error states are user-readable
- ✓ Loading and disabled states prevent duplicate actions
- 10
Run End-to-End Testing and Fix Failures
Verify the invite system works in real scenarios instead of appearing complete.
Preview prompt + verify gate ▾ Hide ▴
Run a real test pass for the invitation system. Verify these scenarios: authorized user creates invite, unauthorized user is blocked, duplicate invite is handled correctly, existing team member cannot be invited again, valid invite link resolves correctly, signed-out recipient can sign in and continue, valid acceptance creates a membership, revoked invite fails, expired invite fails, already accepted invite fails, and pending invites appear in the management UI. If the project has a test framework already configured, add or update automated tests for the critical server-side invite creation and acceptance logic.
- ✓ Happy-path invite creation and acceptance work
- ✓ Unauthorized creation is blocked
- ✓ Revoked and expired invites fail correctly
- ✓ Duplicate membership and duplicate invites are prevented
- ✓ Critical backend paths are covered by tests if supported