# Eolem Planning — Spécification de design

## Contexte

Outil web personnel pour Frédéric GAURAT, formateur, permettant de créer rapidement des événements de formation dans Google Calendar. L'outil n'est pas un gestionnaire de planning — il sert uniquement à la création initiale des événements. La gestion se fait ensuite directement dans Google Calendar.

## Stack technique

- **Backend** : PHP vanilla, PSR-4 autoload via Composer
- **API** : `google/apiclient` pour Google Calendar
- **Frontend** : Tailwind CSS (CDN), HTMX (CDN), Tom Select (CDN)
- **Hébergement** : mutualisé OVH
- **Stockage référentiels** : fichiers JSON
- **Authentification** : formulaire HTML + session PHP

## Fonctionnalités

### 1. Authentification

- Formulaire de login HTML (identifiant + mot de passe)
- Mot de passe stocké hashé via `password_hash()` dans `.env`
- Session PHP pour protéger toutes les pages
- Un seul utilisateur (pas de gestion multi-comptes)

### 2. Formulaire de création de formation

Champs dans l'ordre de tabulation :

| # | Champ | Type | Détail |
|---|-------|------|--------|
| 1 | Formation | combobox (Tom Select) | Liste gérée via admin |
| 2 | Client | combobox (Tom Select) | Liste gérée via admin |
| 3 | Lieu | combobox (Tom Select) | Liste gérée via admin |
| 4 | Statut | select | Option / Confirmée / Commandée |
| 5 | Date de début | date | Premier jour du bloc |
| 6 | Date de fin | date | Dernier jour du bloc |
| 7 | Heure de début | time | Pré-rempli 09:00 |
| 8 | Heure de fin | time | Pré-rempli 17:00 |
| 9 | Description | textarea | Notes libres, optionnel |
| 10 | Bouton "Créer" | submit | |

- L'ordre de tabulation doit être respecté strictement (tabindex cohérent)
- Tom Select ne doit pas casser la navigation clavier

### 3. Titre auto-généré

Le titre de l'événement Google Calendar est une concaténation :
**"Formation - Client - Lieu"**

Exemple : "PHP Avancé - Acme Corp - Lyon"

### 4. Création des événements Google Calendar

- Un événement est créé pour chaque jour de la plage date début → date fin (week-ends inclus)
- Chaque événement contient :
  - **Titre** : concaténation auto-générée
  - **Horaires** : heure début / heure fin saisies
  - **Lieu** : dans le champ location de Google Calendar
  - **Description** : texte libre saisi
  - **Couleur** : selon le statut
- Correspondance statut → couleur Google Calendar :
  - Option → couleur à définir (ex: jaune/banana)
  - Confirmée → couleur à définir (ex: vert/sage)
  - Commandée → couleur à définir (ex: bleu/blueberry)
- Après création : page de confirmation avec récapitulatif des événements créés

### 5. Sessions fractionnées

Pour une formation fractionnée (ex: 2 jours + pause + 1 jour), l'utilisateur crée la formation deux fois avec des plages de dates différentes. Pas de mécanisme de "blocs multiples" dans le formulaire.

### 6. Intégration Google Calendar — OAuth 2.0

- Première utilisation : redirection vers Google pour autoriser l'accès au calendrier
- Callback OAuth via `callback.php`
- Refresh token stocké dans `config/token.json` (hors git)
- Renouvellement automatique du token
- Si token révoqué : redirection automatique vers le flux OAuth

### 7. Pages d'administration des référentiels

Trois pages identiques (formations, clients, lieux) :

- Tableau trié alphabétiquement des entrées existantes
- Champ de saisie + bouton "Ajouter" en haut
- Bouton "Modifier" et "Supprimer" sur chaque ligne
- Interactions sans rechargement via HTMX
- Données stockées dans `data/formations.json`, `data/clients.json`, `data/lieux.json`

### 8. Navigation

Menu simple accessible depuis toutes les pages :
- Formulaire de création
- Admin Formations
- Admin Clients
- Admin Lieux
- Déconnexion

## Architecture fichiers

```
/
├── public/                          # Document root OVH
│   ├── index.php                    # Login
│   ├── form.php                     # Formulaire de création
│   ├── create.php                   # Traitement → création événements
│   ├── callback.php                 # Callback OAuth Google
│   ├── logout.php                   # Déconnexion
│   ├── bootstrap.php                # Initialisation (session, dotenv, services)
│   ├── admin/
│   │   ├── formations.php           # CRUD formations
│   │   ├── clients.php              # CRUD clients
│   │   └── lieux.php                # CRUD lieux
│   └── api/
│       ├── referentials.php         # Endpoint HTMX (admin CRUD)
│       └── calendar.php             # API REST CRUD Google Calendar
├── src/
│   ├── GoogleCalendarService.php    # Wrapper API Google Calendar (CRUD)
│   ├── FormValidator.php            # Validation du formulaire
│   ├── AuthService.php              # Gestion login/session
│   └── ReferentialService.php       # Lecture/écriture des JSON
├── templates/
│   ├── layout.php                   # Layout commun (menu, head, CDN)
│   ├── login.php                    # Template login
│   ├── form.php                     # Template formulaire création
│   ├── success.php                  # Template confirmation
│   └── admin/
│       ├── referential.php          # Template page admin
│       └── row.php                  # Fragment HTMX ligne tableau
├── data/                            # Référentiels JSON (hors git)
├── config/
│   ├── google-credentials.json      # OAuth credentials (hors git)
│   └── token.json                   # Refresh token (hors git)
├── logs/                            # Logs d'erreur (hors git)
├── .env                             # Variables d'environnement (hors git)
├── .env.example
├── composer.json
├── build.sh                         # Script de build pour déploiement
└── .gitignore
```

## Dépendances

- **Composer** : `google/apiclient`, `vlucas/phpdotenv`
- **Composer (dev)** : `phpunit/phpunit`
- **CDN** : Tailwind CSS, HTMX, Tom Select

## Variables d'environnement (.env)

| Variable | Description |
|----------|-------------|
| `APP_USERNAME` | Identifiant de connexion interface web |
| `APP_PASSWORD_HASH` | Hash bcrypt du mot de passe (`password_hash()`) |
| `GOOGLE_CALENDAR_ID` | ID du calendrier Google (ex: `primary`) |
| `API_KEY` | Clé API pour l'endpoint REST `/api/calendar.php` |

## Fichiers hors git (.gitignore)

- `data/`
- `config/google-credentials.json`
- `config/token.json`
- `logs/`
- `dist/`
- `.env`
- `vendor/`

## Configuration Google Cloud (guide pour l'utilisateur)

1. Aller sur Google Cloud Console
2. Sélectionner le projet existant
3. Activer l'API Google Calendar
4. Créer des identifiants OAuth 2.0 (type "Application Web")
5. Configurer l'URI de redirection vers `callback.php`
6. Télécharger le fichier JSON des credentials dans `config/google-credentials.json`

### 9. API REST — CRUD Google Calendar

API JSON permettant à des outils externes d'interagir avec le Google Calendar.

**Authentification :** header `X-API-Key` vérifié contre la variable `API_KEY` du `.env`.

**Endpoint :** `/api/calendar.php`

#### GET — Lister les événements

```
GET /api/calendar.php?date_start=2026-04-01&date_end=2026-04-30
```

Retourne un tableau JSON des événements dans la plage de dates.

Paramètres :
- `date_start` (requis) : date de début au format `YYYY-MM-DD`
- `date_end` (requis) : date de fin au format `YYYY-MM-DD`
- `id` (optionnel) : si fourni, retourne un seul événement

Réponse :
```json
[
  {
    "id": "abc123",
    "summary": "PHP Avancé - Acme Corp - Lyon",
    "location": "Lyon",
    "description": "09:00 - 17:00",
    "colorId": "5",
    "start": "2026-05-04",
    "end": "2026-05-09"
  }
]
```

#### POST — Créer une formation

```
POST /api/calendar.php
Content-Type: application/json
```

Body :
```json
{
  "formation": "PHP Avancé",
  "client": "Acme Corp",
  "lieu": "Lyon",
  "statut": "option",
  "date_debut": "2026-05-04",
  "date_fin": "2026-05-08",
  "heure_debut": "09:00",
  "heure_fin": "17:00",
  "description": ""
}
```

- `heure_debut` et `heure_fin` sont optionnels (défaut : 09:00 / 17:00)
- `description` est optionnel
- `statut` : `option`, `confirmee` ou `commandee`
- Le titre est auto-généré : "Formation - Client - Lieu"
- Crée un événement journée entière sur la plage de dates
- Les week-ends sont inclus dans la bande (l'utilisateur gère les dates)

Réponse (201) :
```json
{
  "created": [
    {
      "id": "abc123",
      "summary": "PHP Avancé - Acme Corp - Lyon",
      "start": "2026-05-04",
      "end": "2026-05-09"
    }
  ]
}
```

#### PUT — Modifier un événement

```
PUT /api/calendar.php?id=eventId
Content-Type: application/json
```

Body (tous les champs sont optionnels) :
```json
{
  "summary": "Nouveau titre",
  "location": "Paris",
  "description": "Notes",
  "statut": "commandee",
  "date_debut": "2026-05-04",
  "date_fin": "2026-05-09"
}
```

- `statut` met à jour la couleur/label de l'événement
- `date_debut` / `date_fin` mettent à jour les dates

#### DELETE — Supprimer un événement

```
DELETE /api/calendar.php?id=eventId
```

Réponse : 204 No Content

#### Codes d'erreur

| Code | Signification |
|------|---------------|
| 401 | API key invalide ou manquante |
| 400 | Paramètres manquants ou body JSON invalide |
| 422 | Validation échouée (détails dans la réponse) |
| 503 | Google Calendar non authentifié (passer par l'interface web) |

### 10. Correspondance statuts → couleurs/labels Google Calendar

| Statut | colorId | Couleur Google | RGB |
|--------|---------|----------------|-----|
| Option | 5 | Banana | rgb(246, 191, 38) |
| Confirmée | 1 | Lavender | rgb(121, 134, 203) |
| Commandée | 11 | Tomato | rgb(213, 0, 0) |

### 11. Événements journée entière

Les événements sont créés en mode "journée entière" (all-day) pour une meilleure visibilité dans le calendrier. Les horaires (09:00 - 17:00 par défaut) sont inclus dans la description de l'événement. Une formation sur plusieurs jours crée un seul événement continu (bande unique dans le calendrier).

## Hors périmètre

- Pas de gestion multi-utilisateurs
- Pas de base de données
