# Multi-Event Invitation Management System - Refactoring Guide ## Overview The wedding guest list application has been refactored from a single-event system to a **multi-event architecture** that can manage invitations for multiple events (weddings, parties, conferences, etc.). ## Key Architectural Changes ### Database Schema (PostgreSQL) **New Tables:** 1. **users** - User accounts (organizers/event managers) ```sql id (UUID PK) | email (unique) | created_at ``` 2. **events** - Individual events ```sql id (UUID PK) | name | date | location | created_at | updated_at ``` 3. **event_members** - User membership in events with roles ```sql id (UUID PK) | event_id (FK) | user_id (FK) | role | display_name | created_at - Roles: admin, editor, viewer - UNIQUE constraint on (event_id, user_id) ``` 4. **guests_v2** - Guest information (scoped by event, NO separate table per event) ```sql id (UUID PK) | event_id (FK) | added_by_user_id (FK) | first_name | last_name | phone | side | status | notes | created_at | updated_at - Status: invited, confirmed, declined - Indexed: (event_id), (event_id, added_by_user_id), (event_id, phone) ``` ### Database Migration Run the SQL migration to create new tables: ```bash psql -U wedding_admin -d wedding_guests -f backend/migrations.sql ``` The migration includes a commented-out data migration script that can import existing data to a default event. ## Backend Changes (FastAPI) ### New Core Modules #### 1. **models.py** - SQLAlchemy Models - `User` - User accounts with relationships - `Event` - Event details with cascade delete - `EventMember` - Role-based event membership - `Guest` - Guest entries (links to events with added_by_user) - Uses UUID primary keys throughout - Uses SQLAlchemy enums for roles and status #### 2. **schemas.py** - Pydantic Validation Models - Organized into sections: User, Event, EventMember, Guest, WhatsApp - Clear separation between Create/Update/Read schemas - Type-safe with UUID and enum validation #### 3. **crud.py** - Database Operations Reorganized into logical groups: - **User CRUD**: `get_or_create_user()`, `get_user_by_email()` - **Event CRUD**: `create_event()`, `get_events_for_user()`, etc. - **Event Member CRUD**: `create_event_member()`, `get_event_member()`, etc. - **Guest CRUD (Event-scoped)**: All operations now take `event_id` parameter - **Statistics**: `get_event_stats()`, `get_sides_summary()` #### 4. **authz.py** - Authorization (NEW) Role-based access control with permission checks: ```python class Permission: can_edit_event(role) # admin only can_manage_members(role) # admin only can_add_guests(role) # editor+ can_send_messages(role) # all members ``` #### 5. **whatsapp.py** - WhatsApp Integration (NEW) - Phone number normalization to E.164 format - `send_text_message()` - Send direct messages - `send_template_message()` - Send approved templates - `verify_webhook_signature()` - Validate Meta webhooks - Error handling with custom `WhatsAppError` ### API Endpoints #### Event Management ``` POST /events Create event (user becomes admin) GET /events List user's events GET /events/{event_id} Get event details PATCH /events/{event_id} Update event (admin only) DELETE /events/{event_id} Delete event (admin only) ``` #### Event Members ``` GET /events/{event_id}/members List members POST /events/{event_id}/invite-member Invite by email (admin only) PATCH /events/{event_id}/members/{user_id} Update role (admin only) DELETE /events/{event_id}/members/{user_id} Remove member (admin only) ``` #### Guests (Event-Scoped) ``` POST /events/{event_id}/guests Add single guest GET /events/{event_id}/guests List guests (with filters) GET /events/{event_id}/guests/{guest_id} Get guest details PATCH /events/{event_id}/guests/{guest_id} Update guest DELETE /events/{event_id}/guests/{guest_id} Delete guest (admin only) ``` #### Bulk Operations ``` POST /events/{event_id}/guests/import Import multiple guests POST /events/{event_id}/whatsapp Send message to guest POST /events/{event_id}/whatsapp/broadcast Send to multiple guests GET /events/{event_id}/stats Get event statistics ``` ### Authorization **All event-scoped endpoints enforce authorization:** - User must be a member of the event - Permissions based on role: - **admin**: Full control (create, delete, manage members) - **editor**: Add/edit guests, import - **viewer**: View only, can send messages **Implemented via:** - `verify_event_access()` - Check membership - `verify_event_admin()` - Check admin role - `verify_event_editor()` - Check editor+ role ## Frontend Changes (React/Vite) ### New Components #### 1. **EventList.jsx** - Event Discovery - Shows all events user is member of - Quick stats: total guests, confirmation rate - Create/delete event actions - Card-based responsive layout #### 2. **EventForm.jsx** - Event Creation - Modal form for new events - Fields: name (required), date, location - Automatically adds creator as admin #### 3. **EventMembers.jsx** - Member Management - Invite members by email - Set member roles (admin/editor/viewer) - Remove members - Modal interface ### Updated Components #### **App.jsx** - Main Navigation - New page states: 'events', 'guests', 'guest-self-service' - Event selection flow: List → Detail → Guests - Modal overlays for forms #### **api/api.js** - Event-Scoped Endpoints - Reorganized into sections - All guest operations now scoped by event - New functions for events and members - Backward compatibility where possible ### Updated API Functions (examples) ```javascript // Events getEvents() // List user's events createEvent(event) // Create new event getEventStats(eventId) // Get statistics // Members getEventMembers(eventId) inviteEventMember(eventId, invite) updateMemberRole(eventId, userId, role) // Guests (now scoped) getGuests(eventId, options) // List with filters createGuest(eventId, guest) // Add single bulkImportGuests(eventId, guests) // Bulk add updateGuest(eventId, guestId, data) // Update // WhatsApp sendWhatsAppMessage(eventId, guestId, message) broadcastWhatsAppMessage(eventId, request) ``` ## Environment Configuration ### New Variables (.env) ```env # WhatsApp Cloud API (required for messaging) WHATSAPP_ACCESS_TOKEN=... WHATSAPP_PHONE_NUMBER_ID=... WHATSAPP_API_VERSION=v20.0 WHATSAPP_VERIFY_TOKEN=... (optional, for webhooks) # Test user (temporary - implement real auth) TEST_USER_EMAIL=test@example.com ``` See `.env.example` for full template. ## Migration Checklist - [ ] Back up existing database - [ ] Run `migrations.sql` to create new tables - [ ] Update backend dependencies (if any new ones added) - [ ] Update frontend packages (axios already included) - [ ] Test authentication (currently uses TEST_USER_EMAIL) - [ ] Configure WhatsApp credentials (optional) - [ ] Update FRONTEND_URL in .env for CORS - [ ] Test event creation workflow - [ ] Test member invitation - [ ] Test guest management ## Breaking Changes ### Database - Old `guests` table still exists but unused - Can be deleted after confirming data migration was successful: ```sql DROP TABLE guests; ``` ### APIs Old endpoints **NO LONGER AVAILABLE**: - `GET /guests/` → Use `GET /events/{event_id}/guests` - `POST /guests/` → Use `POST /events/{event_id}/guests` - `GET /guests/{id}` → Use `GET /events/{event_id}/guests/{id}` ### Frontend - Old single-guest-list view replaced with event-first navigation - Google import and duplicate manager need updates for event-scoped guests ## Authentication (TODO) Current implementation uses `TEST_USER_EMAIL` from `.env`. **Recommended approaches to implement:** 1. **JWT Tokens** - Extract user from Authorization header 2. **Session Cookies** - HTTP-only cookies with session ID 3. **OAuth2** - Google/GitHub integration 4. **API Keys** - For programmatic access Update `get_current_user_id()` in `main.py` with your auth logic. ## WhatsApp Integration ### Setup Steps 1. Create Meta Business App: https://developers.facebook.com/ 2. Add WhatsApp product 3. Create test phone number or configure production 4. Get credentials: - `WHATSAPP_ACCESS_TOKEN` - Long-lived token - `WHATSAPP_PHONE_NUMBER_ID` - Phone number sender ID 5. Add to `.env` and `.gitignore` ### Features - **Send Text Messages**: Direct messages to guest phone (E.164 format) - **Bulk Broadcast**: Send to multiple guests with optional filters - **Phone Validation**: Automatic normalization (handles various formats) - **Error Handling**: Detailed WhatsApp API non-200 errors ### Usage Example ```python service = get_whatsapp_service() result = await service.send_text_message( to_phone="+972541234567", message_text="Hello! Please confirm your attendance..." ) ``` ## File Structure ``` backend/ ├── main.py # FastAPI app with all routes ├── models.py # SQLAlchemy ORM models (UPDATED) ├── schemas.py # Pydantic request/response schemas (UPDATED) ├── crud.py # Database operations (COMPLETELY REWRITTEN) ├── authz.py # Authorization & permissions (NEW) ├── whatsapp.py # WhatsApp API client (NEW) ├── database.py # DB connection setup ├── migrations.sql # SQL schema with new tables (NEW) └── .env.example # Environment template (UPDATED) frontend/src/ ├── components/ │ ├── EventList.jsx # List/manage events (NEW) │ ├── EventForm.jsx # Create event modal (NEW) │ ├── EventMembers.jsx # Manage members (NEW) │ ├── GuestList.jsx # Guest list (needs update for event scope) │ └── ... ├── api/ │ └── api.js # API client (UPDATED) └── App.jsx # Main app (UPDATED for events) ``` ## Performance Considerations - **Indexes on guests_v2** for common queries: - `event_id` - Filter by event - `(event_id, status)` - Filter by status - `(event_id, phone)` - Lookup by phone - **Pagination**: List endpoints support skip/limit - **Cascading Deletes**: Deleting event removes all guests and memberships ## Security Notes 1. **Authorization**: Every event endpoint checks membership 2. **Phone Numbers**: Validated/normalized before WhatsApp sends 3. **Secrets**: Store ACCESS_TOKEN in .env, never commit 4. **CORS**: Restricted to FRONTEND_URL (.env configuration) 5. **Roles**: Implement fine-grained permissions (admin/editor/viewer) ## Testing Recommendations ```bash # Test event creation psql -U wedding_admin -d wedding_guests -c "SELECT * FROM events;" # Test member management psql -U wedding_admin -d wedding_guests -c "SELECT * FROM event_members;" # Test guest entries psql -U wedding_admin -d wedding_guests -c "SELECT * FROM guests_v2 LIMIT 5;" # Test API curl http://localhost:8000/events ``` ## Next Steps 1. **Implement Real Authentication** - Replace TEST_USER_EMAIL 2. **Add Google Import** - Update for event-scoped guests 3. **Implement Self-Service Guest Updates** - via token link 4. **Handle Webhooks** - WhatsApp status callbacks 5. **Add Email Notifications** - Event/RSVP confirmations 6. **Deploy Helm Charts** - Uses new schema structure ## Support For issues or questions: 1. Check `.env` configuration 2. Review database indexes in `migrations.sql` 3. Check authorization checks in `authz.py` 4. Verify API response schemas in `schemas.py`