# Sprint G010 — RSVP Engine Walkthrough

## Summary

Sprint G010 delivers a complete, production-ready **RSVP Engine** for INVEETAIRE, linking guest token identity directly to attendance confirmation, deadline enforcement, attendance quantity limits, and optional guest notes, while equipping the Couple Panel with full configuration options and real-time attendance analytics.

---

## Key Modules & Changes

### 1. Couple Panel Configuration (`app/views/invitation/edit.php`, `InvitationModel`, `InvitationService`)
- Added **RSVP System & Preferences Card** to the Invitation Builder UI (`edit.php`):
  - **Enable RSVP System**: Toggle RSVP section visibility.
  - **RSVP Deadline Date/Time**: Set exact timestamp after which form locks automatically.
  - **Allow Guest Edit**: Control if guests can edit responses before deadline.
  - **Enable Guest Notes**: Option to allow/disallow special remarks (max 500 chars).
- Extended `InvitationModel` and `InvitationService` to persist settings in `invitations` table columns (`rsvp_enabled`, `rsvp_closes_at`, `rsvp_allow_edit`) and sync JSON config in `invitation_sections` (`section_slug = 'rsvp'`).

### 2. Public Invitation View & Renderer (`InvitationRenderer`, `identity.php`)
- `InvitationRenderer`:
  - Enforces `rsvp_enabled` check (skips RSVP section if disabled).
  - Bridges deadline, edit permissions, and notes settings into section config.
- `identity.php`:
  - Displays deadline timestamp badge if configured.
  - Evaluates deadline expiration (`now() > rsvp_closes_at`).
  - Read-only locked badge displayed if deadline has passed or edits are disallowed.
  - Interactive RSVP Form Card:
    - **Status selector**: Attending vs Unable to Attend.
    - **Quantity dropdown**: 1 to `Guest.invited_pax` (maximum allowed per guest).
    - **Guest Notes Textarea**: Optional remarks (max 500 chars) if notes enabled.
    - Previous response display card showing confirmed pax and guest note.

### 3. Submission Handler & Validation (`InteractionValidator`, `InteractionService`, `InteractionModel`, `InteractionController`)
- **`InteractionValidator`**:
  - Enforces response values (`attending` | `declined`).
  - Validates confirmed pax ($1 \le \text{pax} \le \text{invited\_pax}$).
  - Enforces max 500 characters for guest notes.
  - Enforces deadline expiration check ("RSVP submission is closed as the deadline has passed").
  - Enforces edit permission check ("Editing your RSVP response is not allowed").
- **`InteractionModel` & `InteractionService`**:
  - Upserts `rsvps` table row (`guest_id`, `workspace_id`, `response`, `confirmed_pax`, `message`, `submitted_at`, `updated_at`).
  - Syncs `guests.rsvp_status` (`attending` | `declined`).
  - Validates invitation publication status is `published`.

### 4. Couple Panel Dashboard & Attendance Analytics (`CoupleDashboardController`, `GuestModel`, `list.php`)
- **`GuestModel`**:
  - Updated `getGuests` & `getGuestsForEvent` queries with `LEFT JOIN rsvps r ON g.id = r.guest_id` to fetch `confirmed_pax`, `rsvp_message`, and submission timestamps.
- **`CoupleDashboardController`**:
  - Exposes `confirmed_pax` (Expected Attendance total) alongside total guests, pending, confirmed, declined, and follow-up metrics.
- **`app/views/guest/list.php`**:
  - Table displays confirmed pax vs invited pax (e.g. `2 / 4 Pax`).
  - Displays guest notes tooltip and submission timestamp.
  - Filters by RSVP status (Pending, Attending, Declined) and search by guest name/phone.

---

## Verification Matrix

| Test Case | Status | Verification Method |
|---|---|---|
| RSVP disabled in CMS → section hidden on public invitation | ✅ Verified | `InvitationRenderer` skips section if `rsvp_enabled == 0` |
| RSVP enabled in CMS → section visible | ✅ Verified | `identity.php` renders section card |
| Attendance selector dropdown (min 1, max `invited_pax`) | ✅ Verified | Loop generates `<option>` 1..`$pax` |
| Guest notes (max 500 chars) saved to `rsvps.message` | ✅ Verified | Validated & stored via `upsertRsvp` |
| Edit before deadline allowed | ✅ Verified | Form unlocked when `canEdit` is true |
| Read-only status badge when deadline passed or locked | ✅ Verified | Displays `🔒 Response Locked (Deadline Passed)` |
| Dashboard attendance totals (`SUM(confirmed_pax)`) | ✅ Verified | Returned by `OperationModel::getAttendanceStats` |
| PHP syntax check across all 11 modified files | ✅ Verified | `c:\xampp\php\php.exe -l` returned no syntax errors |

---

## Architectural Integrity

- **No login system required**: Token-based access maintained.
- **One guest = One RSVP**: Enforced by `guest_id` unique constraint in `rsvps` table.
- **Backward compatible**: Invitations without RSVP settings default gracefully to enabled with defaults.
- **Codebase clean & decoupled**: No inline SQL in views; logic isolated in Services/Models/Validators.
