# Wedding RSVP API

API de gestion des réponses aux invitations de mariage, développée en PHP 8 avec MySQL 8.0.

## Fonctionnalités

- **Recherche d'invité** : Rechercher un invité par nom et prénom
- **Soumission de réponse** : Les invités peuvent répondre à leur invitation
- **Modification de réponse** : Les invités peuvent modifier leur réponse via un token sécurisé
- **Renvoi d'email** : Possibilité de recevoir à nouveau le lien de modification par email (rate-limited)
- **Administration** : Listing de toutes les invitations et réponses

## Architecture

### Structure du projet

```
.
├── .devcontainer/          # Configuration VSCode devcontainer
├── docker/                 # Configuration Docker
│   └── apache/
│       └── vhost.conf      # Configuration Apache
├── public/                 # Point d'entrée web
│   ├── index.php           # Front controller
│   └── .htaccess           # Règles de réécriture Apache
├── src/                    # Code source de l'application
│   ├── Controllers/        # Contrôleurs API
│   ├── Core/               # Classes de base (Router, Database, Controller)
│   ├── Models/             # Modèles de données
│   └── Services/           # Services (Email)
├── tests/                  # Tests PHPUnit
├── docker-compose.yml      # Configuration Docker Compose
├── Dockerfile              # Image Docker PHP
└── composer.json           # Dépendances PHP

```

### Endpoints API

Tous les endpoints acceptent et retournent du JSON.

#### `GET /guest`
Recherche un invité par nom et prénom.

**Query parameters:**
- `first_name`: Prénom de l'invité
- `last_name`: Nom de l'invité

**Réponses:**
- `200`: Invité trouvé
  - Si non répondu: Retourne les détails de l'invitation et la liste des invités
  - Si déjà répondu: Retourne uniquement l'UUID de l'invitation
- `404`: Invité non trouvé
- `400`: Paramètres manquants

#### `POST /invitation/{uuid}`
Soumet une réponse RSVP pour une invitation.

**Body:**
```json
{
  "is_attending_dinner": true,
  "is_attending_reception": true,
  "email": "invité@example.com",
  "phone": "+33612345678",
  "dietary_restrictions": "Végétarien",
  "notes": "Merci pour l'invitation !",
  "guests": [
    {
      "id": 1,
      "menu_adult": true
    },
    {
      "id": 2,
      "menu_adult": false
    }
  ]
}
```

**Champs:**
- `is_attending_dinner` (requis): Présence au dîner
- `is_attending_reception` (requis): Présence au vin d'honneur
- `email`: Email de contact
- `phone`: Téléphone de contact
- `dietary_restrictions`: Restrictions alimentaires
- `notes`: Message pour les mariés
- `guests` (optionnel): Tableau des invités avec leur choix de menu et présence
  - **Invité existant** (avec `id`):
    - `id` (requis): ID de l'invité (doit appartenir à l'invitation)
    - `is_attending` (optionnel): Indique si la personne vient (true/false)
    - `menu_adult` (optionnel): Choix du menu (true = adulte, false = enfant) - uniquement pour les invitations incluant le dîner
  - **Nouvel invité** (sans `id`):
    - `first_name` (requis): Prénom
    - `last_name` (requis): Nom
    - `is_adult` (optionnel, défaut: true): Majeur ou non
    - `is_attending` (optionnel, déduit automatiquement): Présence
    - `menu_adult` (optionnel, défaut: true): Choix du menu

**Notes importantes:**
- Les nouveaux invités (sans `id`) seront créés et liés automatiquement à l'invitation
- Ils héritent des mêmes droits (dîner/vin d'honneur) que l'invitation d'origine
- La personne qui remplit le formulaire voit son `is_attending` mis à jour automatiquement selon sa réponse

**Réponses:**
- `201`: Réponse créée avec succès (retourne un `edit_token`)
- `403`: L'invitation a déjà été répondue
- `404`: Invitation non trouvée
- `400`: Données invalides

#### `PUT /invitation/{uuid}`
Modifie une réponse RSVP existante.

**Body:**
```json
{
  "token": "edit_token_reçu_par_email",
  "is_attending_dinner": false,
  "is_attending_reception": true,
  "email": "invité@example.com",
  "phone": "+33612345678",
  "dietary_restrictions": "Vegan",
  "notes": "Notes mises à jour",
  "guests": [
    {
      "id": 1,
      "menu_adult": true
    }
  ]
}
```

**Réponses:**
- `200`: Réponse mise à jour
- `403`: Token invalide ou non autorisé
- `404`: Invitation non trouvée
- `400`: Données invalides

#### `POST /invitation/{uuid}/resendMail`
Renvoie le lien de modification par email.

**Rate limiting:** Maximum 1 email par heure.

**Réponses:**
- `200`: Email envoyé
- `429`: Trop de requêtes (attendre 1 heure)
- `404`: Invitation ou réponse non trouvée
- `400`: Pas d'email associé

#### `GET /admin/guests`
Liste toutes les invitations avec leurs réponses et invités.

**Réponses:**
- `200`: Liste des invitations

## Installation et démarrage

### Prérequis

- Docker et Docker Compose
- Visual Studio Code (recommandé avec devcontainer)

### Démarrage avec Docker Compose

1. Cloner le repository
```bash
cd /Users/simondelberghe/wd/test/vibe/mariage_api
```

2. Démarrer les conteneurs
```bash
docker-compose up -d
```

3. Installer les dépendances
```bash
docker-compose exec app composer install
```

4. L'API est maintenant accessible sur `http://localhost:8080`

### Démarrage avec devcontainer (VSCode)

1. Ouvrir le projet dans VSCode
2. Cliquer sur "Reopen in Container" lorsque VSCode le propose
3. Attendre que le conteneur se construise et démarre
4. L'API sera automatiquement accessible

## Base de données

### Schéma

Le schéma de base de données est automatiquement initialisé au démarrage du conteneur MySQL via le fichier `specs/schema.sql`.

Tables principales:
- `guests`: Les invités individuels
- `invitations`: Les invitations (groupées)
- `invitation_guests`: Association invités ↔ invitations (many-to-many)
- `rsvp_responses`: Les réponses aux invitations

### Accès à la base de données

- **Host:** localhost
- **Port:** 3306
- **Database:** wedding_rsvp
- **Username:** wedding_user
- **Password:** wedding_pass
- **Root password:** root_pass

## Tests

Exécuter les tests PHPUnit:

```bash
# Dans le conteneur
docker-compose exec app composer test

# Ou si vous êtes dans le devcontainer
composer test
```

Tous les endpoints sont testés avec des scénarios positifs et négatifs.

## Sécurité

- Les invitations utilisent des UUID publics (pas d'exposition des IDs de base de données)
- Les modifications nécessitent un `edit_token` unique et sécurisé
- Rate limiting sur l'envoi d'emails (1 par heure)
- Toutes les requêtes SQL utilisent des prepared statements
- Validation des entrées utilisateur

## Variables d'environnement

Les variables suivantes peuvent être configurées (définies dans docker-compose.yml):

- `DB_HOST`: Hôte de la base de données (default: db)
- `DB_PORT`: Port MySQL (default: 3306)
- `DB_DATABASE`: Nom de la base (default: wedding_rsvp)
- `DB_USERNAME`: Utilisateur MySQL (default: wedding_user)
- `DB_PASSWORD`: Mot de passe MySQL (default: wedding_pass)
- `SMTP_FROM`: Adresse email d'envoi (default: noreply@wedding.example.com)
- `BASE_URL`: URL de base pour les liens dans les emails (default: http://localhost:8080)

## Notes de développement

- Le code suit les standards PSR-12
- PHP 8.0+ requis (utilisation des fonctionnalités modernes)
- Architecture MVC avec séparation claire des responsabilités
- Pattern Singleton pour la connexion base de données
- Gestion d'erreurs avec codes HTTP appropriés

## Améliorations futures possibles

- Authentification admin pour le endpoint `/admin/guests`
- Intégration d'un vrai service d'envoi d'email (SendGrid, Mailgun, etc.)
- Logging avancé des requêtes
- Cache pour améliorer les performances
- API de création/modification d'invitations (actuellement doit se faire directement en BDD)
