invy/REFACTORING_GUIDE.md

12 KiB

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)

    id (UUID PK) | email (unique) | created_at
    
  2. events - Individual events

    id (UUID PK) | name | date | location | created_at | updated_at
    
  3. event_members - User membership in events with roles

    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)

    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:

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:

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)

// 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)

# 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:
    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

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

# 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