Add comprehensive band invitation system analysis and implementation plan
- Deep dive into existing band invitation implementation - Identified gaps in current system (invite listing, revocation, user search) - Created detailed architecture analysis and design options - Documented comprehensive implementation plan with phases - Includes backend endpoints, frontend components, and testing strategy Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
554
BAND_INVITATION_ANALYSIS.md
Normal file
554
BAND_INVITATION_ANALYSIS.md
Normal file
@@ -0,0 +1,554 @@
|
|||||||
|
# Band Invitation System - Current State Analysis & New Design
|
||||||
|
|
||||||
|
## 📊 Current System Overview
|
||||||
|
|
||||||
|
### Existing Implementation
|
||||||
|
The current system already has a basic band invitation feature implemented:
|
||||||
|
|
||||||
|
#### Backend (API)
|
||||||
|
- **Database Models**: `band_invites` table with token-based invites (72h expiry)
|
||||||
|
- **Endpoints**:
|
||||||
|
- `POST /bands/{id}/invites` - Generate invite link
|
||||||
|
- `POST /invites/{token}/accept` - Join band via invite
|
||||||
|
- **Repositories**: `BandRepository` has invite methods
|
||||||
|
- **Services**: `BandService` handles invite creation
|
||||||
|
|
||||||
|
#### Frontend (Web)
|
||||||
|
- **InvitePage.tsx**: Accept invite page (`/invite/:token`)
|
||||||
|
- **BandPage.tsx**: Generate invite link UI with copy functionality
|
||||||
|
|
||||||
|
### Current Limitations
|
||||||
|
|
||||||
|
1. **No Email Notifications**: Invites are only accessible via direct link sharing
|
||||||
|
2. **No Admin UI for Managing Invites**: Admins can generate but cannot see/revoke active invites
|
||||||
|
3. **No Invite Listing**: No endpoint to list all pending invites for a band
|
||||||
|
4. **No Invite Expiry Management**: 72h expiry is hardcoded, no admin control
|
||||||
|
5. **No Member Management via Invites**: Cannot specify which members to invite
|
||||||
|
6. **No Bulk Invites**: Only one invite at a time
|
||||||
|
7. **No Invite Status Tracking**: Cannot track which invites were sent to whom
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Requirements Analysis
|
||||||
|
|
||||||
|
Based on the new requirements:
|
||||||
|
|
||||||
|
### Functional Requirements
|
||||||
|
1. ✅ A user with an existing band instance can invite users registered to the system
|
||||||
|
2. ✅ Invited users are added to the band
|
||||||
|
3. ✅ No link handling needed (requirement clarification needed)
|
||||||
|
4. ✅ The user with the band instance is the admin (can add/remove members)
|
||||||
|
|
||||||
|
### Clarification Needed
|
||||||
|
- "No link handling needed" - Does this mean:
|
||||||
|
- Option A: No email notifications, just direct link sharing (current system)
|
||||||
|
- Option B: Implement email notifications
|
||||||
|
- Option C: Implement both with configuration
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Current Architecture Analysis
|
||||||
|
|
||||||
|
### Data Flow (Current)
|
||||||
|
```
|
||||||
|
Admin User → POST /bands/{id}/invites → Generate Token → Display Link →
|
||||||
|
User → GET /invites/{token} → Accept → POST /invites/{token}/accept →
|
||||||
|
Add to Band as Member
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Components
|
||||||
|
|
||||||
|
#### Backend Components
|
||||||
|
```
|
||||||
|
┌───────────────────────┐ ┌───────────────────────┐
|
||||||
|
│ BandRepository │ │ BandService │
|
||||||
|
│ │ │ │
|
||||||
|
│ - create_invite() │ │ - Create token │
|
||||||
|
│ - get_invite_by_token()│ │ - Set 72h expiry │
|
||||||
|
├───────────────────────┤ ├───────────────────────┤
|
||||||
|
│ │ │ │
|
||||||
|
│ BandInvite Model │ │ Auth Flow │
|
||||||
|
│ │ │ │
|
||||||
|
│ - token (UUID) │ │ JWT based auth │
|
||||||
|
│ - band_id (FK) │ │ │
|
||||||
|
│ - role (admin/member) │ │ │
|
||||||
|
│ - created_by (FK) │ │ │
|
||||||
|
│ - expires_at │ │ │
|
||||||
|
│ - used_at │ │ │
|
||||||
|
│ - used_by (FK) │ │ │
|
||||||
|
└───────────────────────┘ └───────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Frontend Components
|
||||||
|
```
|
||||||
|
┌───────────────────────────────────────────────────┐
|
||||||
|
│ Web Application │
|
||||||
|
├─────────────────┬─────────────────┬───────────────┤
|
||||||
|
│ InvitePage │ BandPage │ Auth │
|
||||||
|
│ (Accept Invite)│ (Generate Link) │ │
|
||||||
|
└─────────────────┴─────────────────┴───────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Gap Analysis
|
||||||
|
|
||||||
|
### Backend Gaps
|
||||||
|
| Feature | Current Status | Gap | Priority |
|
||||||
|
|---------|---------------|-----|----------|
|
||||||
|
| Invite generation | ✅ | No bulk invite support | High |
|
||||||
|
| Invite listing | ❌ | No endpoint to list invites | High |
|
||||||
|
| Invite acceptance | ✅ | | |
|
||||||
|
| Invite expiry | ✅ | Hardcoded 72h, no admin control | Medium |
|
||||||
|
| Invite revocation | ❌ | No way to revoke pending invites | High |
|
||||||
|
| Member removal | ✅ | Only via direct removal, not invite-based | Medium |
|
||||||
|
| Email notifications | ❌ | No integration | Low (optional) |
|
||||||
|
| Search for users to invite | ❌ | No user search/filter | High |
|
||||||
|
|
||||||
|
### Frontend Gaps
|
||||||
|
| Feature | Current Status | Gap | Priority |
|
||||||
|
|---------|---------------|-----|----------|
|
||||||
|
| Generate invite | ✅ | UI exists but no invite management | High |
|
||||||
|
| View active invites | ❌ | No UI to view/list invites | High |
|
||||||
|
| Revoke invites | ❌ | No revoke functionality | High |
|
||||||
|
| Email copy | ✅ | Copy to clipboard works | |
|
||||||
|
| Search users | ❌ | No user search for invites | High |
|
||||||
|
| Bulk invites | ❌ | No UI for multiple invites | Medium |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 Proposed New Architecture
|
||||||
|
|
||||||
|
### Option 1: Enhanced Token-Based System (Recommended)
|
||||||
|
|
||||||
|
**Pros**:
|
||||||
|
- Minimal changes to existing flow
|
||||||
|
- Maintains simplicity
|
||||||
|
- No email dependency
|
||||||
|
- Works well for small bands
|
||||||
|
|
||||||
|
**Cons**:
|
||||||
|
- Requires manual link sharing
|
||||||
|
- No notification system
|
||||||
|
|
||||||
|
### Option 2: Email-Based Invitation System
|
||||||
|
|
||||||
|
**Pros**:
|
||||||
|
- Automatic notifications
|
||||||
|
- Better UX for invitees
|
||||||
|
- Can track delivery status
|
||||||
|
|
||||||
|
**Cons**:
|
||||||
|
- Requires email infrastructure
|
||||||
|
- More complex setup
|
||||||
|
- Privacy considerations
|
||||||
|
- May need SMTP configuration
|
||||||
|
|
||||||
|
### Option 3: Hybrid Approach
|
||||||
|
|
||||||
|
**Pros**:
|
||||||
|
- Best of both worlds
|
||||||
|
- Flexibility for users
|
||||||
|
- Can start simple, add email later
|
||||||
|
|
||||||
|
**Cons**:
|
||||||
|
- More complex implementation
|
||||||
|
- Two code paths
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Detailed Design (Option 1 - Enhanced Token-Based)
|
||||||
|
|
||||||
|
### Backend Changes
|
||||||
|
|
||||||
|
#### Database Schema (No Changes Needed)
|
||||||
|
Current schema is sufficient. We'll use existing `band_invites` table.
|
||||||
|
|
||||||
|
#### New API Endpoints
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Band Invites Management
|
||||||
|
GET /bands/{band_id}/invites # List all pending invites for band
|
||||||
|
POST /bands/{band_id}/invites # Create new invite (existing)
|
||||||
|
DELETE /invites/{invite_id} # Revoke pending invite
|
||||||
|
|
||||||
|
# Invite Actions
|
||||||
|
GET /invites/{token}/info # Get invite details (without accepting)
|
||||||
|
POST /invites/{token}/accept # Accept invite (existing)
|
||||||
|
|
||||||
|
# Member Management
|
||||||
|
DELETE /bands/{band_id}/members/{member_id} # Remove member (existing)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Enhanced Band Service Methods
|
||||||
|
|
||||||
|
```python
|
||||||
|
class BandService:
|
||||||
|
async def list_invites(self, band_id: UUID, admin_id: UUID) -> list[BandInvite]
|
||||||
|
"""List all pending invites for a band (admin only)"""
|
||||||
|
|
||||||
|
async def create_invite(
|
||||||
|
self,
|
||||||
|
band_id: UUID,
|
||||||
|
created_by: UUID,
|
||||||
|
role: str = "member",
|
||||||
|
ttl_hours: int = 72,
|
||||||
|
email: str | None = None # Optional email for notifications
|
||||||
|
) -> BandInvite:
|
||||||
|
"""Create invite with optional email notification"""
|
||||||
|
|
||||||
|
async def revoke_invite(self, invite_id: UUID, admin_id: UUID) -> None:
|
||||||
|
"""Revoke pending invite"""
|
||||||
|
|
||||||
|
async def get_invite_info(self, token: str) -> BandInviteInfo:
|
||||||
|
"""Get invite details without accepting"""
|
||||||
|
```
|
||||||
|
|
||||||
|
#### New Schemas
|
||||||
|
|
||||||
|
```python
|
||||||
|
class BandInviteCreate(BaseModel):
|
||||||
|
role: str = "member"
|
||||||
|
ttl_hours: int = 72
|
||||||
|
email: str | None = None # Optional email for notifications
|
||||||
|
|
||||||
|
class BandInviteRead(BaseModel):
|
||||||
|
id: UUID
|
||||||
|
band_id: UUID
|
||||||
|
token: str
|
||||||
|
role: str
|
||||||
|
expires_at: datetime
|
||||||
|
created_at: datetime
|
||||||
|
used: bool
|
||||||
|
used_at: datetime | None
|
||||||
|
used_by: UUID | None
|
||||||
|
|
||||||
|
class BandInviteList(BaseModel):
|
||||||
|
invites: list[BandInviteRead]
|
||||||
|
total: int
|
||||||
|
pending: int
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend Changes
|
||||||
|
|
||||||
|
#### New Pages/Components
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// InviteManagement.tsx - New component for band page
|
||||||
|
// Shows list of active invites with revoke option
|
||||||
|
|
||||||
|
// UserSearch.tsx - New component for finding users to invite
|
||||||
|
// Searchable list of registered users
|
||||||
|
|
||||||
|
// InviteDetails.tsx - Modal for invite details
|
||||||
|
// Shows invite info before acceptance
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Enhanced BandPage
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Enhanced features:
|
||||||
|
- Invite Management section
|
||||||
|
- List of pending invites
|
||||||
|
- Revoke button for each
|
||||||
|
- Copy invite link
|
||||||
|
- Expiry timer
|
||||||
|
|
||||||
|
- Invite Creation
|
||||||
|
- Search users to invite
|
||||||
|
- Select role (member/admin)
|
||||||
|
- Set expiry (default 72h)
|
||||||
|
- Bulk invite option
|
||||||
|
```
|
||||||
|
|
||||||
|
#### New API Wrappers
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// api/invites.ts
|
||||||
|
export const listInvites = (bandId: string) =>
|
||||||
|
api.get<BandInvite[]>(`/bands/${bandId}/invites`);
|
||||||
|
|
||||||
|
export const createInvite = (bandId: string, data: {
|
||||||
|
role?: string;
|
||||||
|
ttl_hours?: number;
|
||||||
|
email?: string;
|
||||||
|
}) =>
|
||||||
|
api.post<BandInvite>(`/bands/${bandId}/invites`, data);
|
||||||
|
|
||||||
|
export const revokeInvite = (inviteId: string) =>
|
||||||
|
api.delete(`/invites/${inviteId}`);
|
||||||
|
|
||||||
|
export const getInviteInfo = (token: string) =>
|
||||||
|
api.get<BandInviteInfo>(`/invites/${token}/info`);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Implementation Plan
|
||||||
|
|
||||||
|
### Phase 1: Backend Enhancements
|
||||||
|
|
||||||
|
#### Task 1: Add Invite Listing Endpoint
|
||||||
|
```
|
||||||
|
File: api/src/rehearsalhub/routers/bands.py
|
||||||
|
Method: GET /bands/{band_id}/invites
|
||||||
|
Returns: List of pending invites with details
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 2: Add Invite Revocation Endpoint
|
||||||
|
```
|
||||||
|
File: api/src/rehearsalhub/routers/bands.py
|
||||||
|
Method: DELETE /invites/{invite_id}
|
||||||
|
Logic: Check admin permissions, soft delete if pending
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 3: Add Get Invite Info Endpoint
|
||||||
|
```
|
||||||
|
File: api/src/rehearsalhub/routers/bands.py
|
||||||
|
Method: GET /invites/{token}/info
|
||||||
|
Returns: Invite details without accepting
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 4: Enhance Create Invite Endpoint
|
||||||
|
```
|
||||||
|
File: api/src/rehearsalhub/routers/bands.py
|
||||||
|
Method: POST /bands/{band_id}/invites
|
||||||
|
Add: Optional email parameter, return full invite info
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 5: Update BandRepository
|
||||||
|
```
|
||||||
|
File: api/src/rehearsalhub/repositories/band.py
|
||||||
|
Add: Methods for listing, updating invite status
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 6: Update BandService
|
||||||
|
```
|
||||||
|
File: api/src/rehearsalhub/services/band.py
|
||||||
|
Add: Service methods for invite management
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 7: Update Schemas
|
||||||
|
```
|
||||||
|
File: api/src/rehearsalhub/schemas/invite.py
|
||||||
|
Add: BandInviteRead, BandInviteList schemas
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Frontend Implementation
|
||||||
|
|
||||||
|
#### Task 8: Create User Search Component
|
||||||
|
```
|
||||||
|
File: web/src/components/UserSearch.tsx
|
||||||
|
Function: Search and select users to invite
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 9: Create Invite Management Component
|
||||||
|
```
|
||||||
|
File: web/src/components/InviteManagement.tsx
|
||||||
|
Function: List, view, and revoke invites
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 10: Enhance BandPage
|
||||||
|
```
|
||||||
|
File: web/src/pages/BandPage.tsx
|
||||||
|
Add: Sections for invite management and creation
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 11: Create BandInvite Type Definitions
|
||||||
|
```
|
||||||
|
File: web/src/api/invites.ts
|
||||||
|
Add: TypeScript interfaces for new endpoints
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Task 12: Update API Wrappers
|
||||||
|
```
|
||||||
|
File: web/src/api/invites.ts
|
||||||
|
Add: Functions for new invite endpoints
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Testing
|
||||||
|
|
||||||
|
#### Unit Tests
|
||||||
|
- BandRepository invite methods
|
||||||
|
- BandService invite methods
|
||||||
|
- API endpoint authentication/authorization
|
||||||
|
|
||||||
|
#### Integration Tests
|
||||||
|
- Invite creation flow
|
||||||
|
- Invite listing
|
||||||
|
- Invite revocation
|
||||||
|
- Invite acceptance
|
||||||
|
- Permission checks
|
||||||
|
|
||||||
|
#### E2E Tests
|
||||||
|
- Full invite flow in browser
|
||||||
|
- Mobile responsiveness
|
||||||
|
- Error handling
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing Strategy
|
||||||
|
|
||||||
|
### Test Scenarios
|
||||||
|
|
||||||
|
1. **Happy Path - Single Invite**
|
||||||
|
- Admin creates invite
|
||||||
|
- Link is generated and displayed
|
||||||
|
- User accepts via link
|
||||||
|
- User is added to band
|
||||||
|
|
||||||
|
2. **Happy Path - Multiple Invites**
|
||||||
|
- Admin creates multiple invites
|
||||||
|
- All links work independently
|
||||||
|
- Each user accepts and joins
|
||||||
|
|
||||||
|
3. **Happy Path - Invite Expiry**
|
||||||
|
- Create invite with custom expiry
|
||||||
|
- Wait for expiry
|
||||||
|
- Verify invite no longer works
|
||||||
|
|
||||||
|
4. **Happy Path - Invite Revocation**
|
||||||
|
- Admin creates invite
|
||||||
|
- Admin revokes invite
|
||||||
|
- Verify invite link no longer works
|
||||||
|
|
||||||
|
5. **Error Handling - Invalid Token**
|
||||||
|
- User visits invalid/expired link
|
||||||
|
- Clear error message displayed
|
||||||
|
|
||||||
|
6. **Error Handling - Non-Member Access**
|
||||||
|
- Non-admin tries to manage invites
|
||||||
|
- Permission denied
|
||||||
|
|
||||||
|
7. **Error Handling - Already Member**
|
||||||
|
- User already in band tries to accept invite
|
||||||
|
- Graceful handling
|
||||||
|
|
||||||
|
### Test Setup
|
||||||
|
|
||||||
|
```python
|
||||||
|
# api/tests/integration/test_api_invites.py
|
||||||
|
@pytest.fixture
|
||||||
|
def invite_factory(db_session):
|
||||||
|
"""Factory for creating test invites"""
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_create_invite(client, db_session, auth_headers_for, current_member, band):
|
||||||
|
"""Test invite creation"""
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_list_invites(client, db_session, auth_headers_for, current_member, band):
|
||||||
|
"""Test invite listing"""
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_revoke_invite(client, db_session, auth_headers_for, current_member, band):
|
||||||
|
"""Test invite revocation"""
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Iteration Plan
|
||||||
|
|
||||||
|
### Iteration 1: MVP (Minimum Viable Product)
|
||||||
|
**Scope**: Basic invite functionality with listing and revocation
|
||||||
|
**Timeline**: 1-2 weeks
|
||||||
|
**Features**:
|
||||||
|
- ✅ Invite creation (existing)
|
||||||
|
- ✅ Invite listing for admins
|
||||||
|
- ✅ Invite revocation
|
||||||
|
- ✅ Invite info endpoint
|
||||||
|
- ✅ Frontend listing UI
|
||||||
|
- ✅ Frontend revoke button
|
||||||
|
|
||||||
|
### Iteration 2: Enhanced UX
|
||||||
|
**Scope**: Improve user experience
|
||||||
|
**Timeline**: 1 week
|
||||||
|
**Features**:
|
||||||
|
- 🔄 User search for invites
|
||||||
|
- 🔄 Bulk invite support
|
||||||
|
- 🔄 Custom expiry times
|
||||||
|
- 🔄 Invite copy improvements
|
||||||
|
|
||||||
|
### Iteration 3: Optional Features
|
||||||
|
**Scope**: Add-ons based on user feedback
|
||||||
|
**Timeline**: 1-2 weeks (optional)
|
||||||
|
**Features**:
|
||||||
|
- 🔄 Email notifications
|
||||||
|
- 🔄 Invite analytics
|
||||||
|
- 🔄 QR code generation
|
||||||
|
- 🔄 Group invites
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Risk Assessment
|
||||||
|
|
||||||
|
### Technical Risks
|
||||||
|
| Risk | Likelihood | Impact | Mitigation |
|
||||||
|
|------|------------|--------|------------|
|
||||||
|
| Token collision | Low | High | Use proper random generation (secrets.token_urlsafe) |
|
||||||
|
| Race conditions | Medium | Medium | Proper locking in repo layer |
|
||||||
|
| Permission bypass | Medium | High | Comprehensive auth checks |
|
||||||
|
| Frontend complexity | Low | Medium | Incremental implementation |
|
||||||
|
|
||||||
|
### Design Risks
|
||||||
|
| Risk | Likelihood | Impact | Mitigation |
|
||||||
|
|------|------------|--------|------------|
|
||||||
|
| Feature creep | Medium | Medium | Strict MVP scope |
|
||||||
|
| UX complexity | Low | Medium | User testing early |
|
||||||
|
| Performance issues | Low | Medium | Pagination for invite lists |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Success Criteria
|
||||||
|
|
||||||
|
1. **Functional**:
|
||||||
|
- Users can be invited to bands
|
||||||
|
- Invites can be listed and managed by admins
|
||||||
|
- Invites properly expire
|
||||||
|
- No security vulnerabilities
|
||||||
|
|
||||||
|
2. **Usability**:
|
||||||
|
- Clear UI for invite management
|
||||||
|
- Intuitive invite generation
|
||||||
|
- Good error messages
|
||||||
|
|
||||||
|
3. **Performance**:
|
||||||
|
- API endpoints < 500ms response time
|
||||||
|
- Invite lists paginated (if > 50 invites)
|
||||||
|
- No database bottlenecks
|
||||||
|
|
||||||
|
4. **Test Coverage**:
|
||||||
|
- Unit tests: 80%+ coverage
|
||||||
|
- Integration tests: All critical paths
|
||||||
|
- E2E tests: Happy paths
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Recommendations
|
||||||
|
|
||||||
|
### Immediate Actions
|
||||||
|
1. Implement Phase 1 backend changes (MVP scope)
|
||||||
|
2. Add comprehensive tests
|
||||||
|
3. Get stakeholder feedback on UI design
|
||||||
|
|
||||||
|
### Future Enhancements
|
||||||
|
1. Add email notification system (Iteration 3)
|
||||||
|
2. Implement analytics (views, acceptance rates)
|
||||||
|
3. Add invitation analytics to admin dashboard
|
||||||
|
|
||||||
|
### Questions for Stakeholders
|
||||||
|
1. "No link handling needed" - Should we implement email notifications?
|
||||||
|
2. Do we need bulk invite support in MVP?
|
||||||
|
3. What's the expected scale (number of invites per band)?
|
||||||
|
4. Should we track who created each invite?
|
||||||
|
5. Do we need to support external (non-registered) email invites?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Next Steps
|
||||||
|
|
||||||
|
1. **Review this analysis** with stakeholders
|
||||||
|
2. **Prioritize features** for MVP vs future iterations
|
||||||
|
3. **Assign tasks** based on team capacity
|
||||||
|
4. **Start implementation** with Phase 1 backend
|
||||||
|
5. **Iterate** based on testing and feedback
|
||||||
324
IMPLEMENTATION_PLAN.md
Normal file
324
IMPLEMENTATION_PLAN.md
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
# Band Invitation System - Implementation Plan
|
||||||
|
|
||||||
|
## 🎯 Summary
|
||||||
|
|
||||||
|
The band invitation system already has a basic implementation but lacks key features for proper invite management. Based on my deep dive into the codebase, I've created a comprehensive analysis and implementation plan.
|
||||||
|
|
||||||
|
**Status**: ✅ Branch created: `feature/band-invitation-system`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 What Exists Today
|
||||||
|
|
||||||
|
### Backend (API)
|
||||||
|
- ✅ Token-based invites with 72h expiry
|
||||||
|
- ✅ `POST /bands/{id}/invites` - Generate invite
|
||||||
|
- ✅ `POST /invites/{token}/accept` - Accept invite
|
||||||
|
- ✅ `DELETE /bands/{id}/members/{mid}` - Remove member
|
||||||
|
|
||||||
|
### Frontend (Web)
|
||||||
|
- ✅ `/invite/:token` - Accept invite page
|
||||||
|
- ✅ Copy-to-clipboard for invite links
|
||||||
|
- ✅ Basic invite generation UI
|
||||||
|
|
||||||
|
### Database
|
||||||
|
- ✅ `band_invites` table with proper schema
|
||||||
|
- ✅ Relationships with `bands` and `members`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 What's Missing (Gaps)
|
||||||
|
|
||||||
|
### Critical (Blocker for Requirements)
|
||||||
|
| Gap | Impact | Priority |
|
||||||
|
|-----|--------|----------|
|
||||||
|
| List pending invites | Admins can't see who they invited | High |
|
||||||
|
| Revoke pending invites | No way to cancel sent invites | High |
|
||||||
|
| Search users to invite | Can't find specific members | High |
|
||||||
|
|
||||||
|
### Important (Nice to Have)
|
||||||
|
| Gap | Impact | Priority |
|
||||||
|
|-----|--------|----------|
|
||||||
|
| Custom expiry times | Can't set longer/shorter expiry | Medium |
|
||||||
|
| Bulk invites | Invite multiple people at once | Medium |
|
||||||
|
| Invite details endpoint | Get info without accepting | Low |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Implementation Strategy
|
||||||
|
|
||||||
|
### Phase 1: MVP (1-2 weeks) - CRITICAL FOR REQUIREMENTS
|
||||||
|
Implement the missing critical features to meet the stated requirements.
|
||||||
|
|
||||||
|
**Backend Tasks:**
|
||||||
|
1. ✅ `GET /bands/{band_id}/invites` - List pending invites
|
||||||
|
2. ✅ `DELETE /invites/{invite_id}` - Revoke invite
|
||||||
|
3. ✅ `GET /invites/{token}/info` - Get invite details
|
||||||
|
4. ✅ Update `BandRepository` with new methods
|
||||||
|
5. ✅ Update `BandService` with new logic
|
||||||
|
6. ✅ Update schemas for new return types
|
||||||
|
|
||||||
|
**Frontend Tasks:**
|
||||||
|
1. ✅ Create `InviteManagement` component (list + revoke)
|
||||||
|
2. ✅ Update `BandPage` with invite management section
|
||||||
|
3. ✅ Update API wrappers (`web/src/api/invites.ts`)
|
||||||
|
4. ✅ Add TypeScript interfaces for new endpoints
|
||||||
|
|
||||||
|
**Tests:**
|
||||||
|
- Unit tests for new repo methods
|
||||||
|
- Integration tests for new endpoints
|
||||||
|
- Permission tests (only admins can manage invites)
|
||||||
|
|
||||||
|
### Phase 2: Enhanced UX (1 week)
|
||||||
|
Improve user experience based on feedback.
|
||||||
|
|
||||||
|
**Backend:**
|
||||||
|
- Bulk invite support
|
||||||
|
- Custom TTL (time-to-live) for invites
|
||||||
|
- Email notification integration (optional)
|
||||||
|
|
||||||
|
**Frontend:**
|
||||||
|
- User search component for finding members
|
||||||
|
- Bulk selection for invites
|
||||||
|
- Better invite management UI
|
||||||
|
|
||||||
|
### Phase 3: Optional Features
|
||||||
|
Based on user feedback.
|
||||||
|
- Email notifications
|
||||||
|
- Invite analytics
|
||||||
|
- QR code generation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Detailed Backend Changes
|
||||||
|
|
||||||
|
### 1. New Endpoint: List Invites
|
||||||
|
```python
|
||||||
|
# File: api/src/rehearsalhub/routers/bands.py
|
||||||
|
|
||||||
|
@router.get("/{band_id}/invites", response_model=BandInviteList)
|
||||||
|
async def list_invites(
|
||||||
|
band_id: uuid.UUID,
|
||||||
|
session: AsyncSession = Depends(get_session),
|
||||||
|
current_member: Member = Depends(get_current_member),
|
||||||
|
):
|
||||||
|
"""List all pending invites for a band (admin only)"""
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:** `200 OK` with list of pending invites
|
||||||
|
- `invites`: Array of invite objects
|
||||||
|
- `total`: Total count
|
||||||
|
- `pending`: Count of pending (not yet used or expired)
|
||||||
|
|
||||||
|
### 2. New Endpoint: Revoke Invite
|
||||||
|
```python
|
||||||
|
# File: api/src/rehearsalhub/routers/bands.py
|
||||||
|
|
||||||
|
@router.delete("/invites/{invite_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
async def revoke_invite(
|
||||||
|
invite_id: uuid.UUID,
|
||||||
|
session: AsyncSession = Depends(get_session),
|
||||||
|
current_member: Member = Depends(get_current_member),
|
||||||
|
):
|
||||||
|
"""Revoke a pending invite (admin only)"""
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:** `204 No Content` on success
|
||||||
|
**Checks:** Only band admin can revoke
|
||||||
|
**Validates:** Invite must be pending (not used or expired)
|
||||||
|
|
||||||
|
### 3. New Endpoint: Get Invite Info
|
||||||
|
```python
|
||||||
|
# File: api/src/rehearsalhub/routers/bands.py
|
||||||
|
|
||||||
|
@router.get("/invites/{token}/info", response_model=BandInviteRead)
|
||||||
|
async def get_invite_info(
|
||||||
|
token: str,
|
||||||
|
session: AsyncSession = Depends(get_session),
|
||||||
|
):
|
||||||
|
"""Get invite details without accepting"""
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:** `200 OK` with invite info or `404 Not Found`
|
||||||
|
**Use case:** Show invite details before deciding to accept
|
||||||
|
|
||||||
|
### 4. Enhanced: Create Invite
|
||||||
|
Update existing endpoint to return full invite info.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 Frontend Changes
|
||||||
|
|
||||||
|
### New Components
|
||||||
|
|
||||||
|
#### 1. `InviteManagement.tsx`
|
||||||
|
```typescript
|
||||||
|
// Location: web/src/components/InviteManagement.tsx
|
||||||
|
// Purpose: Display and manage pending invites
|
||||||
|
|
||||||
|
interface InviteManagementProps {
|
||||||
|
bandId: string;
|
||||||
|
currentMemberId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Features:
|
||||||
|
// - List pending invites with details
|
||||||
|
// - Revoke button for each invite
|
||||||
|
// - Copy invite link
|
||||||
|
// - Show expiry timer
|
||||||
|
// - Refresh list
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. `UserSearch.tsx`
|
||||||
|
```typescript
|
||||||
|
// Location: web/src/components/UserSearch.tsx
|
||||||
|
// Purpose: Search for users to invite
|
||||||
|
|
||||||
|
interface UserSearchProps {
|
||||||
|
onSelect: (user: User) => void;
|
||||||
|
excludedIds?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Features:
|
||||||
|
// - Search by name/email
|
||||||
|
// - Show search results
|
||||||
|
// - Select users to invite
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updated Components
|
||||||
|
|
||||||
|
#### `BandPage.tsx`
|
||||||
|
Add two new sections:
|
||||||
|
1. **Invite Management Section** (above existing "Members" section)
|
||||||
|
2. **Create Invite Section** (above invite link display)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing Plan
|
||||||
|
|
||||||
|
### Unit Tests (Backend)
|
||||||
|
```python
|
||||||
|
# test_api_invites.py
|
||||||
|
test_list_invites_admin_only
|
||||||
|
test_list_invites_pending_only
|
||||||
|
test_revoke_invite_admin_only
|
||||||
|
test_revoke_invite_must_be_pending
|
||||||
|
test_get_invite_info_valid_token
|
||||||
|
test_get_invite_info_invalid_token
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
```python
|
||||||
|
# test_band_invites.py
|
||||||
|
test_create_invite_flow
|
||||||
|
test_accept_invite_flow
|
||||||
|
test_invite_expiry
|
||||||
|
test_invite_revocation
|
||||||
|
test_multiple_invites_same_band
|
||||||
|
```
|
||||||
|
|
||||||
|
### E2E Tests (Frontend)
|
||||||
|
```typescript
|
||||||
|
// inviteManagement.spec.ts
|
||||||
|
testInviteListLoadsCorrectly
|
||||||
|
testRevokeInviteButtonWorks
|
||||||
|
testCopyInviteLinkWorks
|
||||||
|
testErrorHandlingForExpiredInvite
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Important Questions
|
||||||
|
|
||||||
|
Before proceeding with implementation, I need clarification on:
|
||||||
|
|
||||||
|
1. **"No link handling needed" requirement**
|
||||||
|
- Does this mean NO email notifications should be implemented?
|
||||||
|
- Or that we should focus on the token-based system first?
|
||||||
|
- This affects whether we include email in MVP or Phase 2
|
||||||
|
|
||||||
|
2. **Expected scale**
|
||||||
|
- How many members per band?
|
||||||
|
- How many invites per band?
|
||||||
|
- This affects pagination decisions
|
||||||
|
|
||||||
|
3. **External invites**
|
||||||
|
- Should admins be able to invite people who aren't registered yet?
|
||||||
|
- Or only registered users?
|
||||||
|
|
||||||
|
4. **Invite analytics**
|
||||||
|
- Should we track who invited whom?
|
||||||
|
- Should we track invite acceptance rates?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Recommended Next Steps
|
||||||
|
|
||||||
|
### Option A: Start Implementation (MVP)
|
||||||
|
If the requirements are clear and we can proceed with a token-based system:
|
||||||
|
|
||||||
|
1. Implement Phase 1 backend (2-3 days)
|
||||||
|
2. Add tests (2 days)
|
||||||
|
3. Implement frontend (3-4 days)
|
||||||
|
4. Test and review (2 days)
|
||||||
|
|
||||||
|
**Total: ~1 week for MVP**
|
||||||
|
|
||||||
|
### Option B: Clarify Requirements First
|
||||||
|
If we need to decide on email notifications and other optional features:
|
||||||
|
|
||||||
|
1. Discuss with stakeholders
|
||||||
|
2. Finalize MVP scope
|
||||||
|
3. Then proceed with implementation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Files to Create/Modify
|
||||||
|
|
||||||
|
### Backend (API)
|
||||||
|
```
|
||||||
|
# New/Modified Files:
|
||||||
|
api/src/rehearsalhub/routers/bands.py # Add 3 new endpoints
|
||||||
|
api/src/rehearsalhub/repositories/band.py # Add list/revoke methods
|
||||||
|
api/src/rehearsalhub/services/band.py # Add service methods
|
||||||
|
api/src/rehearsalhub/schemas/invite.py # Add new schemas
|
||||||
|
api/tests/integration/test_api_invites.py # New test file
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend (Web)
|
||||||
|
```
|
||||||
|
# New Files:
|
||||||
|
web/src/components/InviteManagement.tsx
|
||||||
|
web/src/components/UserSearch.tsx
|
||||||
|
web/src/api/invites.ts
|
||||||
|
web/src/types/invite.ts
|
||||||
|
|
||||||
|
# Modified Files:
|
||||||
|
web/src/pages/BandPage.tsx
|
||||||
|
web/src/pages/InvitePage.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💭 My Recommendation
|
||||||
|
|
||||||
|
Based on the analysis:
|
||||||
|
|
||||||
|
1. **Proceed with MVP implementation** (Phase 1) - it addresses the core requirements
|
||||||
|
2. **Start with token-based system** (no email) - simpler, fewer dependencies
|
||||||
|
3. **Implement proper permissions** - only band admins can manage invites
|
||||||
|
4. **Add comprehensive tests** - ensure reliability
|
||||||
|
5. **Get feedback early** - test with real users before adding complexity
|
||||||
|
|
||||||
|
The current system has a solid foundation. We just need to add the missing management features to make it production-ready.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Ready to Start?
|
||||||
|
|
||||||
|
I'm ready to begin implementation. Please clarify:
|
||||||
|
1. Should we proceed with token-based MVP?
|
||||||
|
2. Any priority changes to the task list?
|
||||||
|
3. Are there additional requirements not captured?
|
||||||
|
|
||||||
|
Once confirmed, I can start with Phase 1 backend implementation immediately.
|
||||||
Reference in New Issue
Block a user