- Amélioration de la gestion des entités et des utilisateurs - Mise à jour des modèles Amicale et Client avec champs supplémentaires - Ajout du service de logging et amélioration du chargement UI - Refactoring des formulaires utilisateur et amicale - Intégration de file_picker et image_picker pour la gestion des fichiers - Amélioration de la gestion des membres et de leur suppression - Optimisation des performances de l'API - Mise à jour de la documentation technique 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
615 lines
16 KiB
Markdown
Executable File
615 lines
16 KiB
Markdown
Executable File
# Documentation Technique API RESTful PHP 8.3
|
|
|
|
## Table des matières
|
|
|
|
1. [Structure du projet](#structure-du-projet)
|
|
2. [Configuration du serveur](#configuration-du-serveur)
|
|
3. [Flux d'une requête](#flux-dune-requête)
|
|
4. [Architecture des composants](#architecture-des-composants)
|
|
5. [Base de données](#base-de-données)
|
|
6. [Sécurité](#sécurité)
|
|
7. [Endpoints API](#endpoints-api)
|
|
8. [Changements récents](#changements-récents)
|
|
|
|
## Structure du projet
|
|
|
|
```plaintext
|
|
/api/
|
|
├── docs/
|
|
│ └── TECHBOOK.md
|
|
├── src/
|
|
│ ├── Controllers/
|
|
│ │ └── UserController.php
|
|
│ ├── Core/
|
|
│ │ ├── Router.php
|
|
│ │ ├── Request.php
|
|
│ │ ├── Response.php
|
|
│ │ ├── Session.php
|
|
│ │ └── Database.php
|
|
│ └── Config/
|
|
│ └── config.php
|
|
├── index.php
|
|
└── .htaccess
|
|
```
|
|
|
|
## Configuration du serveur
|
|
|
|
### Prérequis
|
|
|
|
- Debian 12
|
|
- NGINX
|
|
- PHP 8.3-FPM
|
|
- MariaDB 10.11
|
|
|
|
### Configuration NGINX
|
|
|
|
Le serveur NGINX est configuré pour rediriger toutes les requêtes vers le point d'entrée `index.php` de l'API.
|
|
|
|
### Configuration PHP-FPM
|
|
|
|
PHP-FPM est configuré pour gérer les processus PHP avec des paramètres optimisés pour une API.
|
|
|
|
## Flux d'une requête
|
|
|
|
Exemple détaillé du parcours d'une requête POST /api/users :
|
|
|
|
1. **Entrée de la requête**
|
|
|
|
- La requête arrive sur le serveur NGINX
|
|
- NGINX redirige vers PHP-FPM via le socket unix
|
|
- Le fichier .htaccess redirige vers index.php
|
|
|
|
2. **Initialisation (index.php)**
|
|
|
|
- Chargement des dépendances
|
|
- Initialisation de la configuration
|
|
- Démarrage de la session
|
|
- Configuration des headers CORS
|
|
- Initialisation du routeur
|
|
|
|
3. **Routage**
|
|
|
|
- Le Router analyse la méthode HTTP (POST)
|
|
- Analyse de l'URI (/api/users)
|
|
- Correspondance avec les routes enregistrées
|
|
- Instanciation du Controller approprié
|
|
|
|
4. **Traitement (UserController)**
|
|
|
|
- Vérification de l'authentification
|
|
- Récupération des données JSON
|
|
- Validation des données reçues
|
|
- Traitement métier
|
|
- Interaction avec la base de données
|
|
- Préparation de la réponse
|
|
|
|
5. **Réponse**
|
|
- Formatage de la réponse en JSON
|
|
- Configuration des headers de réponse
|
|
- Envoi au client
|
|
|
|
## Architecture des composants
|
|
|
|
### Core Components
|
|
|
|
#### Router
|
|
|
|
- Gère le routage des requêtes
|
|
- Associe les URLs aux Controllers
|
|
- Gère les paramètres d'URL
|
|
- Dispatch vers les méthodes appropriées
|
|
|
|
#### Request
|
|
|
|
- Parse les données entrantes
|
|
- Gère les différents types de contenu
|
|
- Nettoie et valide les entrées
|
|
- Fournit une interface unifiée pour accéder aux données
|
|
|
|
#### Response
|
|
|
|
- Formate les réponses en JSON
|
|
- Gère les codes HTTP
|
|
- Configure les headers de réponse
|
|
- Assure la cohérence des réponses
|
|
|
|
#### Session
|
|
|
|
- Gère l'état des sessions
|
|
- Stocke les données d'authentification
|
|
- Vérifie les permissions
|
|
- Sécurise les données de session
|
|
|
|
#### Database
|
|
|
|
- Gère la connexion à MariaDB
|
|
- Fournit une interface PDO
|
|
- Gère le pool de connexions
|
|
- Assure la sécurité des requêtes
|
|
|
|
## Base de données
|
|
|
|
### Structure des tables principales
|
|
|
|
#### Table `users`
|
|
- `encrypted_user_name` : Identifiant de connexion chiffré (unique)
|
|
- `encrypted_email` : Email chiffré (unique)
|
|
- `user_pass_hash` : Hash du mot de passe
|
|
- `encrypted_name`, `encrypted_phone`, `encrypted_mobile` : Données personnelles chiffrées
|
|
- Autres champs : `first_name`, `sect_name`, `fk_role`, `fk_entite`, etc.
|
|
|
|
#### Table `entites` (Amicales)
|
|
- `chk_mdp_manuel` (DEFAULT 0) : Gestion manuelle des mots de passe
|
|
- `chk_username_manuel` (DEFAULT 0) : Gestion manuelle des identifiants
|
|
- `chk_stripe` : Activation des paiements Stripe
|
|
- Données chiffrées : `encrypted_name`, `encrypted_email`, `encrypted_phone`, etc.
|
|
|
|
#### Table `medias`
|
|
- `support` : Type de support (entite, user, operation, passage)
|
|
- `support_id` : ID de l'élément associé
|
|
- `file_category` : Catégorie (logo, export, carte, etc.)
|
|
- `file_path` : Chemin complet du fichier
|
|
- `processed_width/height` : Dimensions après traitement
|
|
- Utilisée pour stocker les logos des entités
|
|
|
|
### Chiffrement des données
|
|
|
|
Toutes les données sensibles sont chiffrées avec AES-256-CBC :
|
|
- Emails, noms, téléphones
|
|
- Identifiants de connexion
|
|
- Informations bancaires (IBAN, BIC)
|
|
|
|
### Migration de base de données
|
|
|
|
Script SQL pour ajouter les nouveaux champs :
|
|
|
|
```sql
|
|
-- Ajout de la gestion manuelle des usernames
|
|
ALTER TABLE `entites`
|
|
ADD COLUMN `chk_username_manuel` tinyint(1) unsigned NOT NULL DEFAULT 0
|
|
COMMENT 'Gestion des usernames manuelle (1) ou automatique (0)'
|
|
AFTER `chk_mdp_manuel`;
|
|
|
|
-- Index pour optimiser la vérification d'unicité
|
|
ALTER TABLE `users`
|
|
ADD INDEX `idx_encrypted_user_name` (`encrypted_user_name`);
|
|
```
|
|
|
|
## Sécurité
|
|
|
|
### Mesures implémentées
|
|
|
|
- Validation stricte des entrées
|
|
- Protection contre les injections SQL (PDO)
|
|
- Hachage sécurisé des mots de passe
|
|
- Headers de sécurité HTTP
|
|
- Gestion des CORS
|
|
- Session sécurisée
|
|
- Authentification requise
|
|
- Chiffrement AES-256 des données sensibles
|
|
- Envoi séparé des identifiants par email
|
|
|
|
## Endpoints API
|
|
|
|
### Routes Publiques vs Privées
|
|
|
|
L'API distingue deux types de routes :
|
|
|
|
#### Routes Publiques
|
|
|
|
- POST /api/login
|
|
- POST /api/register
|
|
- GET /api/health
|
|
|
|
#### Routes Privées (Nécessitent une session authentifiée)
|
|
|
|
- Toutes les autres routes
|
|
|
|
### Authentification
|
|
|
|
L'authentification utilise le système de session PHP natif.
|
|
|
|
#### Login
|
|
|
|
```http
|
|
POST /api/login
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"email": "user@example.com",
|
|
"password": "SecurePassword123"
|
|
}
|
|
```
|
|
|
|
**Réponse réussie :**
|
|
|
|
```json
|
|
{
|
|
"message": "Connecté avec succès",
|
|
"user": {
|
|
"id": 123,
|
|
"email": "user@example.com"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Notes importantes :**
|
|
|
|
- Un cookie de session PHP sécurisé est automatiquement créé
|
|
- Le cookie est httpOnly, secure et SameSite=Strict
|
|
- L'ID de session est régénéré à chaque login réussi
|
|
|
|
#### Logout
|
|
|
|
```http
|
|
POST /api/logout
|
|
```
|
|
|
|
**Réponse réussie :**
|
|
|
|
```json
|
|
{
|
|
"message": "Déconnecté avec succès"
|
|
}
|
|
```
|
|
|
|
### Sécurité des Sessions
|
|
|
|
La configuration des sessions inclut :
|
|
|
|
- Sessions PHP natives sécurisées
|
|
- Protection contre la fixation de session
|
|
- Cookies httpOnly (protection XSS)
|
|
- Mode strict pour les cookies
|
|
- Validation côté serveur à chaque requête
|
|
|
|
- use_strict_mode = 1
|
|
- cookie_httponly = 1
|
|
- cookie_secure = 1
|
|
- cookie_samesite = Strict
|
|
- Régénération de l'ID de session après login
|
|
- Destruction complète de la session au logout
|
|
|
|
### Users
|
|
|
|
#### Création d'utilisateur
|
|
|
|
La création d'utilisateur s'adapte aux paramètres de l'entité (amicale) :
|
|
|
|
```http
|
|
POST /api/users
|
|
Content-Type: application/json
|
|
Authorization: Bearer {session_id}
|
|
|
|
{
|
|
"email": "john@example.com",
|
|
"name": "John Doe",
|
|
"first_name": "John",
|
|
"role": 1,
|
|
"fk_entite": 5,
|
|
"username": "j.doe38", // Requis si chk_username_manuel=1 pour l'entité
|
|
"password": "SecurePass123", // Requis si chk_mdp_manuel=1 pour l'entité
|
|
"phone": "0476123456",
|
|
"mobile": "0612345678",
|
|
"sect_name": "Secteur A",
|
|
"date_naissance": "1990-01-15",
|
|
"date_embauche": "2020-03-01"
|
|
}
|
|
```
|
|
|
|
**Comportement selon les paramètres de l'entité :**
|
|
|
|
| chk_username_manuel | chk_mdp_manuel | Comportement |
|
|
|---------------------|----------------|--------------|
|
|
| 0 | 0 | Username et password générés automatiquement |
|
|
| 0 | 1 | Username généré, password requis dans le payload |
|
|
| 1 | 0 | Username requis dans le payload, password généré |
|
|
| 1 | 1 | Username et password requis dans le payload |
|
|
|
|
**Validation du username (si manuel) :**
|
|
- Format : 10-30 caractères
|
|
- Commence par une lettre
|
|
- Caractères autorisés : a-z, 0-9, ., -, _
|
|
- Doit être unique dans toute la base
|
|
|
|
**Réponse réussie :**
|
|
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Utilisateur créé avec succès",
|
|
"id": 123,
|
|
"username": "j.doe38", // Toujours retourné
|
|
"password": "xY7#mK9@pL2" // Retourné seulement si généré automatiquement
|
|
}
|
|
```
|
|
|
|
**Envoi d'emails :**
|
|
- **Email 1** : Identifiant de connexion (toujours envoyé)
|
|
- **Email 2** : Mot de passe (toujours envoyé, 1 seconde après le premier)
|
|
|
|
**Codes de statut :**
|
|
|
|
- 201: Création réussie
|
|
- 400: Données invalides ou username/password manquant si requis
|
|
- 401: Non authentifié
|
|
- 403: Accès non autorisé (rôle insuffisant)
|
|
- 409: Email ou username déjà utilisé
|
|
- 500: Erreur serveur
|
|
|
|
#### Vérification de disponibilité du username
|
|
|
|
```http
|
|
POST /api/users/check-username
|
|
Content-Type: application/json
|
|
Authorization: Bearer {session_id}
|
|
|
|
{
|
|
"username": "j.doe38"
|
|
}
|
|
```
|
|
|
|
**Réponse si disponible :**
|
|
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"available": true,
|
|
"message": "Nom d'utilisateur disponible",
|
|
"username": "j.doe38"
|
|
}
|
|
```
|
|
|
|
**Réponse si déjà pris :**
|
|
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"available": false,
|
|
"message": "Ce nom d'utilisateur est déjà utilisé",
|
|
"suggestions": ["j.doe38_42", "j.doe381234", "j.doe3825"]
|
|
}
|
|
```
|
|
|
|
#### Autres endpoints
|
|
|
|
- GET /api/users
|
|
- GET /api/users/{id}
|
|
- PUT /api/users/{id}
|
|
- DELETE /api/users/{id}
|
|
- POST /api/users/{id}/reset-password
|
|
|
|
### Entités (Amicales)
|
|
|
|
#### Upload du logo d'une entité
|
|
|
|
```http
|
|
POST /api/entites/{id}/logo
|
|
Content-Type: multipart/form-data
|
|
Authorization: Bearer {session_id}
|
|
|
|
Body:
|
|
logo: File (image/png, image/jpeg, image/jpg)
|
|
```
|
|
|
|
**Restrictions :**
|
|
- Réservé aux administrateurs d'amicale (fk_role == 2)
|
|
- L'admin ne peut uploader que le logo de sa propre amicale
|
|
- Un seul logo actif par entité (le nouveau remplace l'ancien)
|
|
|
|
**Traitement de l'image :**
|
|
- Formats acceptés : PNG, JPG, JPEG
|
|
- Redimensionnement automatique : 250x250px maximum (ratio conservé)
|
|
- Résolution : 72 DPI (standard web)
|
|
- Préservation de la transparence pour les PNG
|
|
|
|
**Stockage :**
|
|
- Chemin : `/uploads/entites/{id}/logo/logo_{id}_{timestamp}.{ext}`
|
|
- Enregistrement dans la table `medias`
|
|
- Suppression automatique de l'ancien logo
|
|
|
|
**Réponse réussie :**
|
|
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Logo uploadé avec succès",
|
|
"media_id": 42,
|
|
"file_name": "logo_5_1234567890.jpg",
|
|
"file_path": "/entites/5/logo/logo_5_1234567890.jpg",
|
|
"dimensions": {
|
|
"width": 250,
|
|
"height": 180
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Récupération du logo d'une entité
|
|
|
|
```http
|
|
GET /api/entites/{id}/logo
|
|
Authorization: Bearer {session_id}
|
|
```
|
|
|
|
**Réponse :**
|
|
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"logo": {
|
|
"id": 42,
|
|
"data_url": "data:image/png;base64,iVBORw0KGgoAAAANS...",
|
|
"file_name": "logo_5_1234567890.png",
|
|
"mime_type": "image/png",
|
|
"width": 250,
|
|
"height": 180,
|
|
"size": 15234
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note :** Le logo est également inclus automatiquement dans la réponse du login si disponible.
|
|
|
|
#### Mise à jour d'une entité
|
|
|
|
```http
|
|
PUT /api/entites/{id}
|
|
Content-Type: application/json
|
|
Authorization: Bearer {session_id}
|
|
|
|
{
|
|
"name": "Amicale de Grenoble",
|
|
"adresse1": "123 rue de la Caserne",
|
|
"adresse2": "",
|
|
"code_postal": "38000",
|
|
"ville": "Grenoble",
|
|
"phone": "0476123456",
|
|
"mobile": "0612345678",
|
|
"email": "contact@amicale38.fr",
|
|
"chk_stripe": true, // Activation paiement Stripe
|
|
"chk_mdp_manuel": false, // Génération auto des mots de passe
|
|
"chk_username_manuel": false, // Génération auto des usernames
|
|
"chk_copie_mail_recu": true,
|
|
"chk_accept_sms": false
|
|
}
|
|
```
|
|
|
|
**Paramètres de gestion des membres :**
|
|
|
|
| Paramètre | Type | Description |
|
|
|-----------|------|-------------|
|
|
| chk_mdp_manuel | boolean | `true`: L'admin saisit les mots de passe<br>`false`: Génération automatique |
|
|
| chk_username_manuel | boolean | `true`: L'admin saisit les identifiants<br>`false`: Génération automatique |
|
|
| chk_stripe | boolean | Active/désactive les paiements Stripe |
|
|
|
|
**Note :** Ces paramètres sont modifiables uniquement par les administrateurs (fk_role > 1).
|
|
|
|
#### Réponse du login avec paramètres entité
|
|
|
|
Lors du login, les paramètres de l'entité sont retournés dans le groupe `amicale` :
|
|
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"session_id": "abc123...",
|
|
"session_expiry": "2025-01-09T15:30:00+00:00",
|
|
"user": {
|
|
"id": 9999980,
|
|
"fk_entite": 5,
|
|
"fk_role": 2,
|
|
"fk_titre": null,
|
|
"first_name": "Pierre",
|
|
"sect_name": "",
|
|
"date_naissance": "1990-01-15", // Maintenant correctement récupéré
|
|
"date_embauche": "2020-03-01", // Maintenant correctement récupéré
|
|
"username": "pv_admin",
|
|
"name": "VALERY ADM",
|
|
"phone": "0476123456", // Maintenant correctement récupéré
|
|
"mobile": "0612345678", // Maintenant correctement récupéré
|
|
"email": "contact@resalice.com"
|
|
},
|
|
"amicale": {
|
|
"id": 5,
|
|
"name": "Amicale de Grenoble",
|
|
"chk_mdp_manuel": 0,
|
|
"chk_username_manuel": 0,
|
|
"chk_stripe": 1,
|
|
"logo": { // Logo de l'entité (si disponible)
|
|
"id": 42,
|
|
"data_url": "data:image/png;base64,iVBORw0KGgoAAAANS...",
|
|
"file_name": "logo_5_1234567890.png",
|
|
"mime_type": "image/png",
|
|
"width": 250,
|
|
"height": 180
|
|
}
|
|
// ... autres champs
|
|
}
|
|
}
|
|
```
|
|
|
|
Ces paramètres permettent à l'application Flutter d'adapter dynamiquement le formulaire de création de membre.
|
|
|
|
## Intégration Frontend
|
|
|
|
### Configuration des Requêtes
|
|
|
|
Toutes les requêtes API depuis le frontend doivent inclure :
|
|
|
|
```javascript
|
|
fetch('/api/endpoint', {
|
|
credentials: 'include', // Important pour les cookies de session
|
|
// ... autres options
|
|
});
|
|
```
|
|
|
|
### Gestion des Sessions
|
|
|
|
- Les cookies de session sont automatiquement gérés par le navigateur
|
|
- Pas besoin de stocker ou gérer des tokens manuellement
|
|
- Redirection vers /login si session expirée (401)
|
|
|
|
## Maintenance et Déploiement
|
|
|
|
### Logs
|
|
|
|
- Logs d'accès NGINX : /var/log/nginx/api-access.log
|
|
- Logs d'erreur NGINX : /var/log/nginx/api-error.log
|
|
- Logs PHP : /var/log/php/php-error.log
|
|
|
|
### Déploiement
|
|
|
|
1. Pull du repository
|
|
2. Vérification des permissions
|
|
3. Configuration de l'environnement
|
|
4. Tests des endpoints
|
|
5. Redémarrage des services
|
|
|
|
### Surveillance
|
|
|
|
- Monitoring des processus PHP-FPM
|
|
- Surveillance de la base de données
|
|
- Monitoring des performances
|
|
- Alertes sur erreurs critiques
|
|
|
|
## Changements récents
|
|
|
|
### Version 3.0.6 (Janvier 2025)
|
|
|
|
#### 1. Correction des rôles administrateurs
|
|
- **Avant :** Les administrateurs d'amicale devaient avoir `fk_role > 2`
|
|
- **Après :** Les administrateurs d'amicale ont `fk_role > 1` (donc rôle 2 et plus)
|
|
- **Impact :** Les champs `chk_stripe`, `chk_mdp_manuel`, `chk_username_manuel` sont maintenant modifiables par les admins d'amicale (rôle 2)
|
|
|
|
#### 2. Envoi systématique des deux emails lors de la création d'utilisateur
|
|
- **Avant :** Le 2ème email (mot de passe) n'était envoyé que si le mot de passe était généré automatiquement
|
|
- **Après :** Les deux emails sont toujours envoyés lors de la création d'un membre
|
|
- Email 1 : Identifiant (username)
|
|
- Email 2 : Mot de passe (1 seconde après)
|
|
- **Raison :** Le nouveau membre a toujours besoin des deux informations pour se connecter
|
|
|
|
#### 3. Ajout des champs manquants dans la réponse du login
|
|
- **Champs ajoutés dans la requête SQL :**
|
|
- `fk_titre`
|
|
- `date_naissance`
|
|
- `date_embauche`
|
|
- `encrypted_phone`
|
|
- `encrypted_mobile`
|
|
- **Impact :** Ces données sont maintenant correctement retournées dans l'objet `user` lors du login
|
|
|
|
#### 4. Système de gestion des logos d'entité
|
|
- **Nouvelle fonctionnalité :** Upload et gestion des logos pour les amicales
|
|
- **Routes ajoutées :**
|
|
- `POST /api/entites/{id}/logo` : Upload d'un nouveau logo
|
|
- `GET /api/entites/{id}/logo` : Récupération du logo
|
|
- **Caractéristiques :**
|
|
- Réservé aux administrateurs d'amicale (fk_role == 2)
|
|
- Un seul logo actif par entité
|
|
- Redimensionnement automatique (250x250px max)
|
|
- Format base64 dans les réponses JSON (compatible Flutter)
|
|
- Logo inclus automatiquement dans la réponse du login
|
|
|
|
#### 5. Amélioration de l'intégration Flutter
|
|
- **Format d'envoi des images :** Base64 data URL pour compatibilité multiplateforme
|
|
- **Structure de réponse enrichie :** Le logo est inclus dans l'objet `amicale` lors du login
|
|
- **Optimisation :** Pas de requête HTTP supplémentaire nécessaire pour afficher le logo
|