- 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>
16 KiB
16 KiB
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_invitestable with token-based invites (72h expiry) - Endpoints:
POST /bands/{id}/invites- Generate invite linkPOST /invites/{token}/accept- Join band via invite
- Repositories:
BandRepositoryhas invite methods - Services:
BandServicehandles invite creation
Frontend (Web)
- InvitePage.tsx: Accept invite page (
/invite/:token) - BandPage.tsx: Generate invite link UI with copy functionality
Current Limitations
- No Email Notifications: Invites are only accessible via direct link sharing
- No Admin UI for Managing Invites: Admins can generate but cannot see/revoke active invites
- No Invite Listing: No endpoint to list all pending invites for a band
- No Invite Expiry Management: 72h expiry is hardcoded, no admin control
- No Member Management via Invites: Cannot specify which members to invite
- No Bulk Invites: Only one invite at a time
- No Invite Status Tracking: Cannot track which invites were sent to whom
🎯 Requirements Analysis
Based on the new requirements:
Functional Requirements
- ✅ A user with an existing band instance can invite users registered to the system
- ✅ Invited users are added to the band
- ✅ No link handling needed (requirement clarification needed)
- ✅ 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
# 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
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
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
// 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
// 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
// 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
-
Happy Path - Single Invite
- Admin creates invite
- Link is generated and displayed
- User accepts via link
- User is added to band
-
Happy Path - Multiple Invites
- Admin creates multiple invites
- All links work independently
- Each user accepts and joins
-
Happy Path - Invite Expiry
- Create invite with custom expiry
- Wait for expiry
- Verify invite no longer works
-
Happy Path - Invite Revocation
- Admin creates invite
- Admin revokes invite
- Verify invite link no longer works
-
Error Handling - Invalid Token
- User visits invalid/expired link
- Clear error message displayed
-
Error Handling - Non-Member Access
- Non-admin tries to manage invites
- Permission denied
-
Error Handling - Already Member
- User already in band tries to accept invite
- Graceful handling
Test Setup
# 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
-
Functional:
- Users can be invited to bands
- Invites can be listed and managed by admins
- Invites properly expire
- No security vulnerabilities
-
Usability:
- Clear UI for invite management
- Intuitive invite generation
- Good error messages
-
Performance:
- API endpoints < 500ms response time
- Invite lists paginated (if > 50 invites)
- No database bottlenecks
-
Test Coverage:
- Unit tests: 80%+ coverage
- Integration tests: All critical paths
- E2E tests: Happy paths
🎯 Recommendations
Immediate Actions
- Implement Phase 1 backend changes (MVP scope)
- Add comprehensive tests
- Get stakeholder feedback on UI design
Future Enhancements
- Add email notification system (Iteration 3)
- Implement analytics (views, acceptance rates)
- Add invitation analytics to admin dashboard
Questions for Stakeholders
- "No link handling needed" - Should we implement email notifications?
- Do we need bulk invite support in MVP?
- What's the expected scale (number of invites per band)?
- Should we track who created each invite?
- Do we need to support external (non-registered) email invites?
📝 Next Steps
- Review this analysis with stakeholders
- Prioritize features for MVP vs future iterations
- Assign tasks based on team capacity
- Start implementation with Phase 1 backend
- Iterate based on testing and feedback