129 lines
4.3 KiB
Markdown
129 lines
4.3 KiB
Markdown
# Invite and Manage Team Members
|
|
|
|
**ID:** ORG-002
|
|
**Priority:** Critical
|
|
**Status:** In Development
|
|
|
|
## User Story
|
|
As an organization owner, I want to invite team members to my organization and manage their access so that my team can collaborate securely.
|
|
|
|
## Acceptance Criteria
|
|
- [x] Owner can invite users via email address
|
|
- [x] Invited user receives email with invitation link
|
|
- [x] Invitation can be accepted by existing users or during registration
|
|
- [x] Owner can view pending invitations and resend/cancel them
|
|
- [x] Owner can see all current members with their roles
|
|
- [x] Owner can remove members from organization
|
|
- [ ] Owner can transfer ownership to another member
|
|
- [ ] Bulk invite via CSV upload
|
|
|
|
## Technical Implementation
|
|
|
|
### UserInvitation System
|
|
|
|
The invitation system uses a shared `UserInvitation` model that supports multiple organizations inviting the same email address.
|
|
|
|
#### Invitation Lifecycle
|
|
|
|
1. **Create**: Org admin invites email → `UserInvitation` created (or existing one is updated)
|
|
2. **Share**: Multiple orgs can link to the same invitation (by email)
|
|
3. **Convert**: When user registers with that email → invitation converts to real User
|
|
4. **Fold**: If existing user adds that email as secondary → invitation folds into existing user
|
|
5. **Expire**: Auto-delete after 90 days with cleanup of all org refs
|
|
|
|
#### Data Model
|
|
|
|
```typescript
|
|
// IUserInvitation
|
|
{
|
|
id: string;
|
|
data: {
|
|
email: string; // Unique key for sharing
|
|
token: string; // Secure invitation link token
|
|
status: 'pending' | 'accepted' | 'expired' | 'cancelled';
|
|
createdAt: number;
|
|
expiresAt: number; // 90 days from creation
|
|
organizationRefs: Array<{ // Multiple orgs can share
|
|
organizationId: string;
|
|
invitedByUserId: string;
|
|
invitedAt: number;
|
|
roles: string[]; // Roles to assign on acceptance
|
|
}>;
|
|
acceptedAt?: number;
|
|
convertedToUserId?: string;
|
|
};
|
|
}
|
|
```
|
|
|
|
### Role System Enhancement
|
|
|
|
Users can have multiple roles within an organization:
|
|
|
|
```typescript
|
|
// IRole
|
|
{
|
|
id: string;
|
|
data: {
|
|
userId: string;
|
|
organizationId: string;
|
|
roles: string[]; // e.g., ['owner', 'billing-admin', 'developer']
|
|
};
|
|
}
|
|
```
|
|
|
|
Standard roles: `owner`, `admin`, `editor`, `viewer`, `guest`
|
|
Custom roles are also supported.
|
|
|
|
### API Endpoints
|
|
|
|
| Method | Purpose |
|
|
|--------|---------|
|
|
| `createInvitation` | Invite email to org with roles |
|
|
| `getOrgInvitations` | List pending invitations |
|
|
| `getOrgMembers` | List members with roles |
|
|
| `cancelInvitation` | Cancel pending invitation |
|
|
| `resendInvitation` | Resend invitation email |
|
|
| `removeMember` | Remove user from org |
|
|
| `updateMemberRoles` | Change member's roles |
|
|
| `transferOwnership` | Transfer org ownership |
|
|
| `acceptInvitation` | Accept invitation |
|
|
| `getInvitationByToken` | Get invitation details for landing page |
|
|
|
|
### Frontend Implementation
|
|
|
|
The Users page (`/account/org/:orgName/users`) provides:
|
|
|
|
- **Members tab**: List all members with roles, remove/edit actions
|
|
- **Pending tab**: List pending invitations with resend/cancel
|
|
- **Invite tab**: Form to invite by email with role selection
|
|
|
|
### Files
|
|
|
|
**Backend:**
|
|
- `ts_interfaces/data/loint-reception.userinvitation.ts` - Data interface
|
|
- `ts_interfaces/request/loint-reception.userinvitation.ts` - API contracts
|
|
- `ts/reception/classes.userinvitation.ts` - Model
|
|
- `ts/reception/classes.userinvitationmanager.ts` - Manager with handlers
|
|
- `ts/reception/classes.receptionmailer.ts` - Invitation email
|
|
|
|
**Frontend:**
|
|
- `ts_web/elements/account/views/usersview.ts` - Users page component
|
|
- `ts_web/elements/account/content.ts` - Route registration
|
|
- `ts_web/elements/account/navigation.ts` - Nav link
|
|
|
|
## Technical Notes
|
|
- Organization and User models exist with association
|
|
- UserInvitation model stores invitation data with 90-day expiry
|
|
- `ReceptionMailer.sendInvitationEmail()` handles email delivery
|
|
- RoleManager updated to support `roles: string[]` array
|
|
- Backward compatible with existing single-role data
|
|
|
|
## Related Stories
|
|
- ORG-003: Assign Roles to Members (enhanced with multi-role support)
|
|
|
|
## Related TODOs
|
|
- [ ] Integrate invitation acceptance into registration flow
|
|
- [ ] Add email verification flow for secondary emails (folding)
|
|
- [ ] Implement scheduled cleanup job for expired invitations
|
|
- [ ] Add CSV bulk invite feature
|