🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1386 lines
44 KiB
Markdown
Executable File
1386 lines
44 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. [Gestion des mots de passe (NIST SP 800-63B)](#gestion-des-mots-de-passe-nist-sp-800-63b)
|
|
8. [Endpoints API](#endpoints-api)
|
|
9. [Paiements Stripe Connect](#paiements-stripe-connect)
|
|
10. [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
|
|
|
|
### Architecture des containers MariaDB
|
|
|
|
Depuis janvier 2025, les bases de données sont hébergées dans des containers MariaDB dédiés :
|
|
|
|
| Environnement | Container API | Container DB | Serveur | IP DB | Nom BDD | Utilisateur | Source des données |
|
|
|---------------|--------------|--------------|---------|-------|---------|-------------|-------------------|
|
|
| **DEV** | dva-geo | maria3 | IN3 | 13.23.33.4 | dva_geo | dva_geo_user | Migré depuis dva-geo/geo_app |
|
|
| **RECETTE** | rca-geo | maria3 | IN3 | 13.23.33.4 | rca_geo | rca_geo_user | Migré depuis rca-geo/geo_app |
|
|
| **PRODUCTION** | pra-geo | maria4 | IN4 | 13.23.33.4 | pra_geo | pra_geo_user | **Dupliqué depuis maria3/rca_geo** |
|
|
|
|
**Note importante :** La base de production `pra_geo` est créée en dupliquant `rca_geo` depuis IN3/maria3 vers IN4/maria4.
|
|
|
|
**Avantages de cette architecture :**
|
|
- Isolation des données par environnement
|
|
- Performances optimisées (containers dédiés)
|
|
- Sauvegardes indépendantes
|
|
- Maintenance simplifiée
|
|
- Séparation physique Production/Recette (serveurs différents)
|
|
|
|
**Migration :** Utiliser le script `scripts/migrate_to_maria_containers.sh` pour migrer les 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
|
|
|
|
## Gestion des mots de passe (NIST SP 800-63B)
|
|
|
|
### Vue d'ensemble
|
|
|
|
L'API implémente un système de gestion des mots de passe conforme aux recommandations NIST SP 800-63B, avec quelques adaptations spécifiques demandées par le client.
|
|
|
|
### Service PasswordSecurityService
|
|
|
|
Le service `PasswordSecurityService` (`src/Services/PasswordSecurityService.php`) gère :
|
|
- Validation des mots de passe selon NIST
|
|
- Vérification contre les bases de données de mots de passe compromis (HIBP)
|
|
- Génération de mots de passe sécurisés
|
|
- Estimation de la force des mots de passe
|
|
|
|
### Conformités NIST respectées
|
|
|
|
| Recommandation NIST | Notre Implémentation | Status |
|
|
|-------------------|---------------------|--------|
|
|
| **Longueur minimale : 8 caractères** | ✅ MIN = 8 caractères | ✅ CONFORME |
|
|
| **Longueur maximale : 64 caractères minimum** | ✅ MAX = 64 caractères | ✅ CONFORME |
|
|
| **Accepter TOUS les caractères ASCII imprimables** | ✅ Aucune restriction sur les caractères | ✅ CONFORME |
|
|
| **Accepter les espaces** | ✅ Espaces acceptés (début, milieu, fin) | ✅ CONFORME |
|
|
| **Accepter Unicode (émojis, accents, etc.)** | ✅ Support UTF-8 avec `mb_strlen()` | ✅ CONFORME |
|
|
| **Vérifier contre les mots de passe compromis** | ✅ API Have I Been Pwned avec k-anonymity | ✅ CONFORME |
|
|
| **Pas d'obligation de composition** | ✅ Pas d'erreur si manque majuscules/chiffres/spéciaux | ✅ CONFORME |
|
|
| **Pas de changement périodique forcé** | ✅ Aucune expiration automatique | ✅ CONFORME |
|
|
| **Permettre les phrases de passe** | ✅ "Mon chat Félix a 3 ans!" accepté | ✅ CONFORME |
|
|
|
|
### Déviations par choix du client
|
|
|
|
| Recommandation NIST | Notre Implémentation | Raison |
|
|
|-------------------|---------------------|--------|
|
|
| **Email unique par compte** | ❌ Plusieurs comptes par email autorisés | Demande client |
|
|
| **Mot de passe ≠ identifiant** | ❌ Mot de passe = identifiant autorisé | Demande client |
|
|
| **Vérifier contexte utilisateur** | ❌ Pas de vérification nom/email dans mdp | Demande client |
|
|
|
|
### Vérification contre les mots de passe compromis
|
|
|
|
#### Have I Been Pwned (HIBP) API
|
|
|
|
L'implémentation utilise l'API HIBP avec la technique **k-anonymity** pour préserver la confidentialité :
|
|
|
|
1. **Hash SHA-1** du mot de passe
|
|
2. **Envoi des 5 premiers caractères** du hash à l'API
|
|
3. **Comparaison locale** avec les suffixes retournés
|
|
4. **Aucun mot de passe en clair** n'est transmis
|
|
|
|
#### Mode "Fail Open"
|
|
|
|
En cas d'erreur de l'API HIBP :
|
|
- Le système laisse passer le mot de passe
|
|
- Un avertissement est enregistré dans les logs
|
|
- L'utilisateur n'est pas bloqué
|
|
|
|
### Exemples de mots de passe
|
|
|
|
#### Acceptés (conformes NIST)
|
|
- `monmotdepasse` → Accepté (≥8 caractères, pas compromis)
|
|
- `12345678` → Accepté SI pas dans HIBP
|
|
- `Mon chat s'appelle Félix!` → Accepté (phrase de passe)
|
|
- ` ` → Accepté si ≥8 espaces
|
|
- `😀🎉🎈🎁🎂🍰🎊🎀` → Accepté (8 émojis)
|
|
- `jean.dupont` → Accepté même si = username
|
|
|
|
#### Refusés
|
|
- `pass123` → Refusé (< 8 caractères)
|
|
- `password` → Refusé (compromis dans HIBP)
|
|
- `123456789` → Refusé (compromis dans HIBP)
|
|
- Mot de passe > 64 caractères → Refusé
|
|
|
|
### Force des mots de passe
|
|
|
|
Le système privilégie la **LONGUEUR** sur la complexité (conforme NIST) :
|
|
|
|
| Longueur | Force | Score |
|
|
|----------|-------|-------|
|
|
| < 8 car. | Trop court | 0-10 |
|
|
| 8-11 car. | Acceptable | 20-40 |
|
|
| 12-15 car. | Bon | 40-60 |
|
|
| 16-19 car. | Fort | 60-80 |
|
|
| ≥20 car. | Très fort | 80-100 |
|
|
| Compromis | Compromis | ≤10 |
|
|
|
|
### Génération automatique
|
|
|
|
Pour la génération automatique, le système reste **strict** pour garantir des mots de passe forts :
|
|
- Longueur : 12-16 caractères
|
|
- Contient : majuscules + minuscules + chiffres + spéciaux
|
|
- Vérifié contre HIBP (10 tentatives max)
|
|
- Exemple : `Xk9#mP2$nL5!`
|
|
|
|
### Gestion des comptes multiples par email
|
|
|
|
Depuis janvier 2025, le système permet plusieurs comptes avec le même email :
|
|
|
|
#### Fonction `lostPassword` adaptée
|
|
- Recherche **TOUS** les comptes avec l'email fourni
|
|
- Génère **UN SEUL** mot de passe pour tous ces comptes
|
|
- Met à jour **TOUS** les comptes en une requête
|
|
- Envoie **UN SEUL** email avec la liste des usernames concernés
|
|
|
|
#### Exemple de comportement
|
|
Si 3 comptes partagent l'email `contact@amicale.fr` :
|
|
- `jean.dupont`
|
|
- `marie.martin`
|
|
- `paul.durand`
|
|
|
|
L'email contiendra :
|
|
```
|
|
Bonjour,
|
|
Voici votre nouveau mot de passe pour les comptes : jean.dupont, marie.martin, paul.durand
|
|
Mot de passe : XyZ123!@#
|
|
```
|
|
|
|
### Endpoints API dédiés aux mots de passe
|
|
|
|
#### Vérification de force (public)
|
|
```http
|
|
POST /api/password/check
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"password": "monmotdepasse",
|
|
"check_compromised": true
|
|
}
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"valid": false,
|
|
"errors": [
|
|
"Ce mot de passe a été trouvé 23 547 fois dans des fuites de données."
|
|
],
|
|
"warnings": [
|
|
"Suggestion : Évitez les séquences communes pour plus de sécurité"
|
|
],
|
|
"strength": {
|
|
"score": 20,
|
|
"strength": "Faible",
|
|
"feedback": ["Ce mot de passe a été compromis"],
|
|
"length": 13,
|
|
"diversity": 1
|
|
},
|
|
"compromised": {
|
|
"compromised": true,
|
|
"occurrences": 23547,
|
|
"message": "Ce mot de passe a été trouvé 23 547 fois dans des fuites de données"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Vérification de compromission uniquement (public)
|
|
```http
|
|
POST /api/password/compromised
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"password": "monmotdepasse"
|
|
}
|
|
```
|
|
|
|
#### Génération automatique (authentifié)
|
|
```http
|
|
GET /api/password/generate?length=14
|
|
Authorization: Bearer {session_id}
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"password": "Xk9#mP2$nL5!qR",
|
|
"length": 14,
|
|
"strength": {
|
|
"score": 85,
|
|
"strength": "Très fort",
|
|
"feedback": []
|
|
}
|
|
}
|
|
```
|
|
|
|
### Configuration et sécurité
|
|
|
|
#### Paramètres de sécurité
|
|
- **Timeout API HIBP** : 5 secondes
|
|
- **Cache** : 15 minutes pour les vérifications répétées
|
|
- **Logging** : Aucun mot de passe en clair dans les logs
|
|
- **K-anonymity** : Seuls 5 caractères du hash SHA-1 envoyés
|
|
|
|
#### Points d'intégration
|
|
- `LoginController::register` : Validation lors de l'inscription
|
|
- `LoginController::lostPassword` : Génération sécurisée
|
|
- `UserController::createUser` : Validation si mot de passe manuel
|
|
- `UserController::updateUser` : Validation lors du changement
|
|
- `ApiService::generateSecurePassword` : Génération avec vérification HIBP
|
|
|
|
### Résumé
|
|
|
|
✅ **100% CONFORME NIST** pour les aspects techniques
|
|
✅ **Adapté aux besoins du client** (emails multiples, mdp=username)
|
|
✅ **Sécurité maximale** avec vérification HIBP
|
|
✅ **Expérience utilisateur optimale** (souple mais sécurisé)
|
|
|
|
## 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.
|
|
|
|
## Paiements Stripe Connect
|
|
|
|
### Vue d'ensemble
|
|
|
|
L'API intègre un système complet de paiements via Stripe Connect, permettant aux amicales de recevoir des paiements pour leurs calendriers via deux méthodes :
|
|
- **Paiements Web** : Interface de paiement dans un navigateur
|
|
- **Tap to Pay** : Paiements NFC via l'application mobile Flutter
|
|
|
|
### Architecture Stripe Connect
|
|
|
|
#### Tables de base de données
|
|
|
|
**Table `stripe_accounts` :**
|
|
```sql
|
|
CREATE TABLE `stripe_accounts` (
|
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
|
`fk_entite` int(10) unsigned NOT NULL,
|
|
`stripe_account_id` varchar(50) NOT NULL,
|
|
`account_type` enum('express','standard','custom') DEFAULT 'express',
|
|
`charges_enabled` tinyint(1) DEFAULT 0,
|
|
`payouts_enabled` tinyint(1) DEFAULT 0,
|
|
`details_submitted` tinyint(1) DEFAULT 0,
|
|
`country` varchar(2) DEFAULT 'FR',
|
|
`default_currency` varchar(3) DEFAULT 'eur',
|
|
`business_name` varchar(255) DEFAULT NULL,
|
|
`support_email` varchar(255) DEFAULT NULL,
|
|
`onboarding_completed_at` timestamp NULL DEFAULT NULL,
|
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `stripe_account_id` (`stripe_account_id`),
|
|
KEY `fk_entite` (`fk_entite`),
|
|
CONSTRAINT `stripe_accounts_ibfk_1` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`)
|
|
);
|
|
```
|
|
|
|
**Ajout du champ `stripe_payment_id` dans `ope_pass` :**
|
|
```sql
|
|
ALTER TABLE `ope_pass` ADD COLUMN `stripe_payment_id` VARCHAR(50) DEFAULT NULL COMMENT 'ID du PaymentIntent Stripe (pi_xxx)';
|
|
ALTER TABLE `ope_pass` ADD INDEX `idx_stripe_payment` (`stripe_payment_id`);
|
|
```
|
|
|
|
#### Services principaux
|
|
|
|
**StripeService** (`src/Services/StripeService.php`) :
|
|
- Gestion des PaymentIntents
|
|
- Communication avec l'API Stripe
|
|
- Gestion des comptes Stripe Connect
|
|
|
|
**StripeController** (`src/Controllers/StripeController.php`) :
|
|
- Endpoints pour la création de PaymentIntents
|
|
- Gestion des webhooks Stripe
|
|
- API pour les comptes Connect
|
|
|
|
### Flow de paiement
|
|
|
|
#### 1. Création du compte Stripe Connect (Onboarding)
|
|
|
|
```http
|
|
POST /api/stripe/accounts/create
|
|
Authorization: Bearer {session_id}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"amicale_id": 45,
|
|
"type": "express",
|
|
"country": "FR",
|
|
"email": "contact@amicale-pompiers.fr",
|
|
"business_profile": {
|
|
"name": "Amicale des Pompiers",
|
|
"product_description": "Vente de calendriers des pompiers",
|
|
"mcc": "8398"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"stripe_account_id": "acct_1O3ABC456DEF789",
|
|
"onboarding_url": "https://connect.stripe.com/express/oauth/authorize?...",
|
|
"status": "pending"
|
|
}
|
|
```
|
|
|
|
#### 2. Création d'un PaymentIntent (Tap to Pay)
|
|
|
|
**Flow actuel (v2) :**
|
|
1. L'application crée/modifie d'abord le passage pour obtenir un ID réel
|
|
2. Puis crée le PaymentIntent avec cet ID
|
|
|
|
```http
|
|
POST /api/stripe/payments/create-intent
|
|
Authorization: Bearer {session_id}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"amount": 2500, // 25€ en centimes
|
|
"passage_id": 456, // ID RÉEL du passage (jamais 0)
|
|
"payment_method_types": ["card_present"], // Tap to Pay
|
|
"location_id": "tml_xxx",
|
|
"amicale_id": 45,
|
|
"member_id": 67,
|
|
"stripe_account": "acct_1234"
|
|
}
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"client_secret": "pi_3QaXYZ_secret_xyz",
|
|
"payment_intent_id": "pi_3QaXYZ123ABC456",
|
|
"amount": 2500,
|
|
"currency": "eur",
|
|
"passage_id": 456,
|
|
"type": "tap_to_pay"
|
|
}
|
|
```
|
|
|
|
#### 3. Traitement du paiement
|
|
|
|
**Côté application Flutter :**
|
|
- Utilisation du SDK Stripe Terminal
|
|
- Collecte NFC avec le `client_secret`
|
|
- Traitement automatique du paiement
|
|
|
|
**Mise à jour automatique :**
|
|
- Le `stripe_payment_id` est automatiquement ajouté au passage lors de la création du PaymentIntent
|
|
- Lien bidirectionnel entre le passage et le paiement Stripe
|
|
|
|
### Endpoints Stripe
|
|
|
|
#### Gestion des comptes
|
|
|
|
- `POST /api/stripe/accounts/create` : Création d'un compte Connect
|
|
- `GET /api/stripe/accounts/{id}` : Statut d'un compte
|
|
- `PUT /api/stripe/accounts/{id}` : Mise à jour d'un compte
|
|
|
|
#### Gestion des paiements
|
|
|
|
- `POST /api/stripe/payments/create-intent` : Création d'un PaymentIntent
|
|
- `GET /api/stripe/payments/{id}` : Statut d'un paiement
|
|
- `POST /api/stripe/payments/confirm` : Confirmation d'un paiement
|
|
|
|
#### Gestion des devices Tap to Pay
|
|
|
|
- `GET /api/stripe/devices/certified-android` : Liste des appareils Android certifiés
|
|
- `POST /api/stripe/devices/check-tap-to-pay` : Vérification de compatibilité d'un appareil
|
|
- `GET /api/stripe/config` : Configuration publique Stripe
|
|
- `GET /api/stripe/stats` : Statistiques de paiement
|
|
|
|
#### Webhooks
|
|
|
|
- `POST /api/stripe/webhooks` : Réception des événements Stripe
|
|
- `account.updated` : Mise à jour du statut d'un compte
|
|
- `payment_intent.succeeded` : Confirmation d'un paiement réussi
|
|
- `payment_intent.payment_failed` : Échec d'un paiement
|
|
|
|
### Sécurité et validation
|
|
|
|
#### Prérequis pour les paiements :
|
|
- ✅ Compte Stripe Connect activé (`charges_enabled = 1`)
|
|
- ✅ Virements activés (`payouts_enabled = 1`)
|
|
- ✅ Onboarding terminé (`details_submitted = 1`)
|
|
- ✅ Passage existant avec montant correspondant
|
|
- ✅ Utilisateur authentifié et autorisé
|
|
|
|
#### Validation des montants :
|
|
- Minimum : 1€ (100 centimes)
|
|
- Maximum : 999€ (99 900 centimes)
|
|
- Vérification de correspondance avec le passage
|
|
|
|
#### Sécurité des transactions :
|
|
- Headers CORS configurés
|
|
- Validation côté serveur obligatoire
|
|
- Logs de toutes les transactions
|
|
- Gestion des erreurs robuste
|
|
|
|
### États et statuts
|
|
|
|
#### États des comptes Stripe :
|
|
- `pending` : Onboarding en cours
|
|
- `restricted` : Informations manquantes
|
|
- `active` : Opérationnel pour les paiements
|
|
- `rejected` : Refusé par Stripe
|
|
|
|
#### États des paiements :
|
|
- `requires_payment_method` : En attente de paiement
|
|
- `processing` : Traitement en cours
|
|
- `succeeded` : Paiement réussi
|
|
- `canceled` : Paiement annulé
|
|
- `requires_action` : Action utilisateur requise
|
|
|
|
### Intégration avec l'application
|
|
|
|
#### Flutter (Tap to Pay) :
|
|
- SDK Stripe Terminal pour iOS/Android
|
|
- Interface NFC native
|
|
- Gestion des états du terminal
|
|
- Validation en temps réel
|
|
|
|
#### Web (Paiements navigateur) :
|
|
- Stripe.js pour l'interface
|
|
- Formulaire de carte sécurisé
|
|
- Confirmation 3D Secure automatique
|
|
|
|
### Monitoring et logs
|
|
|
|
#### Logs importants :
|
|
- Création/mise à jour des comptes Connect
|
|
- Succès/échecs des paiements
|
|
- Erreurs webhook Stripe
|
|
- Tentatives de paiement frauduleuses
|
|
|
|
#### Métriques de suivi :
|
|
- Taux de succès des paiements par amicale
|
|
- Montants moyens des transactions
|
|
- Temps de traitement des paiements
|
|
- Erreurs par type d'appareil
|
|
|
|
### Configuration environnement
|
|
|
|
#### Architecture des clés Stripe
|
|
|
|
Depuis janvier 2025, les clés Stripe sont **séparées par environnement** dans `src/Config/AppConfig.php` :
|
|
|
|
| Environnement | URL | Mode | Clés utilisées | Status |
|
|
|---------------|-----|------|----------------|--------|
|
|
| **DEV** | https://dapp.geosector.fr | `test` | Clés TEST Pierre (dev plateforme) | ✅ Opérationnel |
|
|
| **RECETTE** | https://rapp.geosector.fr | `test` | Clés TEST du client | ⏳ À configurer |
|
|
| **PRODUCTION** | https://app.geosector.fr | `live` | Clés LIVE du client | ⏳ À configurer |
|
|
|
|
**Emplacement dans le code :**
|
|
- **DEV** : `AppConfig.php` lignes 175-187 (section `dapp.geosector.fr`)
|
|
- **RECETTE** : `AppConfig.php` lignes 150-162 (section `rapp.geosector.fr`)
|
|
- **PRODUCTION** : `AppConfig.php` lignes 126-138 (section `app.geosector.fr`)
|
|
|
|
#### Configuration des clés client
|
|
|
|
Pour configurer les clés Stripe du client :
|
|
|
|
1. **Récupérer les clés depuis le Dashboard Stripe du client**
|
|
- Se connecter sur https://dashboard.stripe.com
|
|
- Aller dans **Développeurs → Clés API**
|
|
- Pour les clés TEST : Mode Test activé
|
|
- Pour les clés LIVE : Mode Live activé
|
|
|
|
2. **Remplacer les placeholders dans AppConfig.php**
|
|
- **RECETTE** (ligne 152-153) : Remplacer `CLIENT_PK_TEST_A_REMPLACER` et `CLIENT_SK_TEST_A_REMPLACER`
|
|
- **PRODUCTION** (ligne 130-131) : Remplacer `CLIENT_PK_LIVE_A_REMPLACER` et `CLIENT_SK_LIVE_A_REMPLACER`
|
|
|
|
3. **Déployer selon l'environnement**
|
|
```bash
|
|
# Déployer en RECETTE
|
|
./deploy-api.sh rca
|
|
|
|
# Déployer en PRODUCTION
|
|
./deploy-api.sh pra
|
|
```
|
|
|
|
**⚠️ Sécurité :** Voir `TODO-API.md` section "Sécurisation des clés Stripe" pour étudier une approche plus sécurisée (variables d'environnement, fichiers séparés).
|
|
|
|
#### Comptes Connect
|
|
- Type : Express (simplifié pour les associations)
|
|
- Pays : France (FR)
|
|
- Devise : Euro (EUR)
|
|
- Frais : Standard Stripe Connect
|
|
- Pas de commission plateforme (100% pour l'amicale)
|
|
|
|
### Gestion des appareils certifiés Tap to Pay
|
|
|
|
#### Table `stripe_android_certified_devices`
|
|
|
|
Stocke la liste des appareils Android certifiés pour Tap to Pay en France :
|
|
- **95+ appareils** pré-chargés lors de l'installation
|
|
- **Mise à jour automatique** hebdomadaire via CRON
|
|
- **Vérification de compatibilité** via endpoints dédiés
|
|
|
|
#### Endpoint de vérification de compatibilité
|
|
|
|
```http
|
|
POST /api/stripe/devices/check-tap-to-pay
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"platform": "ios" | "android",
|
|
"manufacturer": "Samsung", // Requis pour Android
|
|
"model": "SM-S921B" // Requis pour Android
|
|
}
|
|
```
|
|
|
|
**Réponse Android compatible :**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"tap_to_pay_supported": true,
|
|
"message": "Tap to Pay disponible sur cet appareil",
|
|
"min_android_version": 14
|
|
}
|
|
```
|
|
|
|
**Réponse iOS :**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Vérification iOS à faire côté client",
|
|
"requirements": "iPhone XS ou plus récent avec iOS 16.4+",
|
|
"details": "iOS 16.4 minimum requis pour le support PIN complet"
|
|
}
|
|
```
|
|
|
|
#### Requirements Tap to Pay
|
|
|
|
| Plateforme | Appareil minimum | OS minimum | Notes |
|
|
|------------|------------------|------------|-------|
|
|
| **iOS** | iPhone XS (2018+) | iOS 16.4+ | Support PIN complet |
|
|
| **Android** | Variable | Android 11+ | NFC obligatoire, non rooté |
|
|
|
|
### Documentation technique complète
|
|
|
|
Pour le flow détaillé complet, voir :
|
|
- **`docs/STRIPE-TAP-TO-PAY-FLOW.md`** : Documentation technique complète du flow de paiement
|
|
- **`docs/PLANNING-STRIPE-API.md`** : Planification et architecture Stripe
|
|
- **`docs/STRIPE-TAP-TO-PAY-REQUIREMENTS.md`** : Requirements officiels et liste complète des devices certifiés
|
|
|
|
## 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)
|
|
|
|
## Système de tâches CRON
|
|
|
|
### Vue d'ensemble
|
|
|
|
L'API utilise des scripts CRON pour automatiser les tâches de maintenance et de traitement. Les scripts sont situés dans `/scripts/cron/` et s'exécutent dans les containers Incus Alpine.
|
|
|
|
### Tâches CRON configurées
|
|
|
|
| Script | Fréquence | Fonction | Container |
|
|
|--------|-----------|----------|-----------|
|
|
| `process_email_queue.php` | */5 * * * * | Traite la queue d'emails (reçus, notifications) | DVA, RCA |
|
|
| `cleanup_security_data.php` | 0 2 * * * | Nettoie les données de sécurité obsolètes | DVA, RCA |
|
|
| `update_stripe_devices.php` | 0 3 * * 0 | Met à jour la liste des devices certifiés Tap to Pay | DVA, RCA |
|
|
|
|
### Configuration des CRONs
|
|
|
|
Sur les containers Alpine (dva-geo, rca-geo, pra-geo) :
|
|
|
|
```bash
|
|
# Vérifier les crons actifs
|
|
crontab -l
|
|
|
|
# Éditer les crons
|
|
crontab -e
|
|
|
|
# Format des lignes cron
|
|
*/5 * * * * /usr/bin/php /var/www/geosector/api/scripts/cron/process_email_queue.php >> /var/www/geosector/api/logs/email_queue.log 2>&1
|
|
0 2 * * * /usr/bin/php /var/www/geosector/api/scripts/cron/cleanup_security_data.php >> /var/www/geosector/api/logs/cleanup_security.log 2>&1
|
|
0 3 * * 0 /usr/bin/php /var/www/geosector/api/scripts/cron/update_stripe_devices.php >> /var/www/geosector/api/logs/stripe_devices.log 2>&1
|
|
```
|
|
|
|
### Script `process_email_queue.php`
|
|
|
|
- **Fonction** : Envoie les emails en attente dans la table `email_queue`
|
|
- **Batch** : 50 emails maximum par exécution
|
|
- **Lock file** : `/tmp/process_email_queue.lock` (évite l'exécution simultanée)
|
|
- **Gestion d'erreur** : 3 tentatives max par email
|
|
|
|
### Script `cleanup_security_data.php`
|
|
|
|
- **Fonction** : Purge les données de sécurité selon la politique de rétention
|
|
- **Rétention** :
|
|
- Métriques de performance : 30 jours
|
|
- Tentatives de login échouées : 7 jours
|
|
- Alertes résolues : 90 jours
|
|
- IPs expirées : Déblocage immédiat
|
|
|
|
### Script `update_stripe_devices.php`
|
|
|
|
- **Fonction** : Maintient à jour la liste des appareils certifiés Tap to Pay
|
|
- **Source** : Liste de 95+ devices intégrée + fichier JSON optionnel
|
|
- **Actions** :
|
|
- Ajoute les nouveaux appareils certifiés
|
|
- Met à jour les versions Android minimales
|
|
- Désactive les appareils obsolètes
|
|
- Envoie une notification email si changements importants
|
|
- **Personnalisation** : Possibilité d'ajouter des devices via `/data/stripe_certified_devices.json`
|
|
|
|
### Monitoring des CRONs
|
|
|
|
Les logs sont stockés dans `/var/www/geosector/api/logs/` :
|
|
- `email_queue.log` : Logs du traitement des emails
|
|
- `cleanup_security.log` : Logs du nettoyage sécurité
|
|
- `stripe_devices.log` : Logs de mise à jour des devices
|
|
|
|
## 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
|
|
|
|
Le script `deploy-api.sh` gère le déploiement sur les 3 environnements :
|
|
|
|
```bash
|
|
# Déploiement DEV : code local → container dva-geo sur IN3
|
|
./deploy-api.sh
|
|
|
|
# Déploiement RECETTE : container dva-geo → container rca-geo sur IN3
|
|
./deploy-api.sh rca
|
|
|
|
# Déploiement PRODUCTION : container rca-geo (IN3) → container pra-geo (IN4)
|
|
./deploy-api.sh pra
|
|
```
|
|
|
|
Flux de déploiement :
|
|
1. **DEV** : Archive du code local, déploiement sur container `dva-geo` sur IN3 (195.154.80.116)
|
|
- URL publique : https://dapp.geosector.fr/api/
|
|
- IP interne : http://13.23.33.43/api/
|
|
2. **RECETTE** : Archive depuis container `dva-geo`, déploiement sur `rca-geo` sur IN3
|
|
- URL publique : https://rapp.geosector.fr/api/
|
|
3. **PRODUCTION** : Archive depuis `rca-geo` (IN3), déploiement sur `pra-geo` (51.159.7.190)
|
|
- URL publique : https://app.geosector.fr/api/
|
|
|
|
Caractéristiques :
|
|
- Sauvegarde automatique avec rotation (garde les 10 dernières)
|
|
- Préservation des dossiers `logs/` et `uploads/`
|
|
- Gestion des permissions :
|
|
- Code API : `nginx:nginx` (755/644)
|
|
- Logs et uploads : `nobody:nginx` (755/644)
|
|
- Installation des dépendances Composer (pas de mise à jour)
|
|
- Journalisation dans `~/.geo_deploy_history`
|
|
|
|
### 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.2.5 (29 Septembre 2025)
|
|
|
|
#### 1. Système de gestion automatique des devices Tap to Pay
|
|
|
|
**Nouveaux endpoints ajoutés :**
|
|
- `GET /api/stripe/devices/certified-android` : Récupération de la liste complète des appareils certifiés
|
|
- `POST /api/stripe/devices/check-tap-to-pay` : Vérification de compatibilité d'un appareil spécifique
|
|
- Endpoints publics (pas d'authentification requise) pour vérification côté app
|
|
|
|
**Script CRON de mise à jour automatique :**
|
|
- **Script** : `/scripts/cron/update_stripe_devices.php`
|
|
- **Fréquence** : Hebdomadaire (dimanche 3h)
|
|
- **Fonction** : Maintient à jour la liste de 95+ appareils Android certifiés
|
|
- **Base de données** : Table `stripe_android_certified_devices` avec 77 appareils actifs
|
|
|
|
**Corrections des requirements iOS :**
|
|
- Mise à jour : iOS 16.4+ minimum (au lieu de 15.4/16.0)
|
|
- Raison : Support PIN complet obligatoire pour les paiements > 50€
|
|
|
|
**Documentation ajoutée :**
|
|
- `docs/STRIPE-TAP-TO-PAY-REQUIREMENTS.md` : Requirements officiels complets
|
|
- Liste exhaustive des appareils certifiés par fabricant
|
|
- Configuration SDK pour toutes les plateformes
|
|
|
|
#### 2. Configuration des tâches CRON sur les containers
|
|
|
|
**Environnements configurés :**
|
|
- **DVA-GEO (DEV)** : 3 CRONs actifs
|
|
- **RCA-GEO (RECETTE)** : 3 CRONs actifs (ajoutés le 29/09)
|
|
- **PRA-GEO (PROD)** : À configurer
|
|
|
|
**Tâches automatisées :**
|
|
1. Queue d'emails : Toutes les 5 minutes
|
|
2. Nettoyage sécurité : Quotidien à 2h
|
|
3. Mise à jour devices Stripe : Hebdomadaire dimanche 3h
|
|
|
|
### Version 3.2.4 (Septembre 2025)
|
|
|
|
#### 1. Implémentation complète de Stripe Connect V1
|
|
|
|
**Paiements Stripe intégrés pour les amicales :**
|
|
- **Stripe Connect Express** : Onboarding simplifié pour les associations
|
|
- **Tap to Pay** : Paiements NFC via l'application mobile Flutter
|
|
- **Paiements Web** : Interface de paiement navigateur avec Stripe.js
|
|
- **Webhooks** : Gestion automatique des événements Stripe
|
|
|
|
**Nouvelles tables de base de données :**
|
|
- `stripe_accounts` : Gestion des comptes Connect par amicale
|
|
- `stripe_payment_history` : Historique des transactions Stripe
|
|
- `stripe_refunds` : Gestion des remboursements
|
|
- Ajout de `stripe_payment_id` dans `ope_pass` pour liaison bidirectionnelle
|
|
|
|
**Nouveaux services :**
|
|
- **StripeService** : Communication avec l'API Stripe, gestion des PaymentIntents
|
|
- **StripeController** : Endpoints API pour création de comptes, paiements et webhooks
|
|
|
|
**Flow de paiement optimisé (v2) :**
|
|
1. Passage créé/modifié EN PREMIER pour obtenir un ID réel
|
|
2. Création PaymentIntent avec `passage_id` réel (jamais 0)
|
|
3. Traitement Tap to Pay via SDK Stripe Terminal
|
|
4. Mise à jour automatique du passage avec `stripe_payment_id`
|
|
|
|
**Endpoints ajoutés :**
|
|
- `POST /api/stripe/accounts/create` : Création compte Connect
|
|
- `POST /api/stripe/payments/create-intent` : Création PaymentIntent
|
|
- `GET /api/stripe/payments/{id}` : Statut d'un paiement
|
|
- `POST /api/stripe/webhooks` : Réception événements Stripe
|
|
|
|
**Sécurité et validation :**
|
|
- Validation stricte des montants (1€ à 999€)
|
|
- Vérification correspondance passage/montant
|
|
- Gestion des permissions par amicale
|
|
- Logs complets des transactions
|
|
|
|
**Configuration multi-environnements :**
|
|
- DEV/RECETTE : Clés de test Stripe
|
|
- PRODUCTION : Clés live avec webhooks sécurisés
|
|
- Migration base de données via `migrate_stripe_payment_id.sql`
|
|
|
|
**Documentation technique :**
|
|
- `docs/STRIPE-TAP-TO-PAY-FLOW.md` : Flow complet de paiement
|
|
- `docs/PLANNING-STRIPE-API.md` : Architecture et planification
|
|
|
|
### Version 3.0.7 (Août 2025)
|
|
|
|
#### 1. Implémentation complète de la norme NIST SP 800-63B pour les mots de passe
|
|
- **Nouveau service :** `PasswordSecurityService` pour la gestion sécurisée des mots de passe
|
|
- **Vérification HIBP :** Intégration de l'API Have I Been Pwned avec k-anonymity
|
|
- **Validation souple :** Suppression des obligations de composition (majuscules, chiffres, spéciaux)
|
|
- **Support Unicode :** Acceptation de tous les caractères, incluant émojis et espaces
|
|
- **Nouveaux endpoints :** `/api/password/check`, `/api/password/compromised`, `/api/password/generate`
|
|
|
|
#### 2. Autorisation des emails multiples
|
|
- **Suppression de l'unicité :** Un même email peut être utilisé pour plusieurs comptes
|
|
- **Adaptation de `lostPassword` :** Mise à jour de tous les comptes partageant l'email
|
|
- **Un seul mot de passe :** Tous les comptes avec le même email reçoivent le même nouveau mot de passe
|
|
|
|
#### 3. Autorisation mot de passe = identifiant
|
|
- **Choix client :** Permet d'avoir un mot de passe identique au nom d'utilisateur
|
|
- **Pas de vérification contextuelle :** Aucune vérification nom/email dans le mot de passe
|
|
|
|
### Version 3.0.6 (Août 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
|
|
|
|
### Version 3.0.8 (Janvier 2025)
|
|
|
|
#### 1. Système de génération automatique de reçus fiscaux pour les dons
|
|
- **Nouveau service :** `ReceiptService` pour la génération automatique de reçus PDF
|
|
- **Déclencheurs automatiques :**
|
|
- Création d'un passage avec `fk_type=1` (don) et email valide
|
|
- Mise à jour d'un passage en don si `nom_recu` est vide/null
|
|
- **Caractéristiques techniques :**
|
|
- PDF ultra-légers (< 5KB) générés en format natif sans librairie externe
|
|
- Support des caractères accentués avec conversion automatique
|
|
- Stockage structuré : `/uploads/entites/{entite_id}/recus/{operation_id}/`
|
|
- Enregistrement dans la table `medias` avec catégorie `recu`
|
|
- **Queue d'envoi email :**
|
|
- Envoi automatique par email avec pièce jointe PDF
|
|
- Format MIME multipart pour compatibilité maximale
|
|
- Gestion dans la table `email_queue` avec statut de suivi
|
|
- **Nouvelle route API :**
|
|
- `GET /api/passages/{id}/receipt` : Récupération du PDF d'un reçu
|
|
- Retourne le PDF en base64 ou téléchargement direct selon Accept header
|
|
- **Champs base de données utilisés :**
|
|
- `nom_recu` : Nom du fichier PDF généré
|
|
- `date_creat_recu` : Date de génération du reçu
|
|
- `date_sent_recu` : Date d'envoi par email
|
|
- `chk_email_sent` : Indicateur d'envoi réussi
|