🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
44 KiB
Executable File
Documentation Technique API RESTful PHP 8.3
Table des matières
- Structure du projet
- Configuration du serveur
- Flux d'une requête
- Architecture des composants
- Base de données
- Sécurité
- Gestion des mots de passe (NIST SP 800-63B)
- Endpoints API
- Paiements Stripe Connect
- Changements récents
Structure du projet
/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 :
-
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
-
Initialisation (index.php)
- Chargement des dépendances
- Initialisation de la configuration
- Démarrage de la session
- Configuration des headers CORS
- Initialisation du routeur
-
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é
-
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
-
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 passeencrypted_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 passechk_username_manuel(DEFAULT 0) : Gestion manuelle des identifiantschk_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 fichierprocessed_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 :
-- 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é :
- Hash SHA-1 du mot de passe
- Envoi des 5 premiers caractères du hash à l'API
- Comparaison locale avec les suffixes retournés
- 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 HIBPMon 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.dupontmarie.martinpaul.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)
POST /api/password/check
Content-Type: application/json
{
"password": "monmotdepasse",
"check_compromised": true
}
Réponse :
{
"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)
POST /api/password/compromised
Content-Type: application/json
{
"password": "monmotdepasse"
}
Génération automatique (authentifié)
GET /api/password/generate?length=14
Authorization: Bearer {session_id}
Réponse :
{
"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'inscriptionLoginController::lostPassword: Génération sécuriséeUserController::createUser: Validation si mot de passe manuelUserController::updateUser: Validation lors du changementApiService::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
POST /api/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "SecurePassword123"
}
Réponse réussie :
{
"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
POST /api/logout
Réponse réussie :
{
"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) :
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 :
{
"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
POST /api/users/check-username
Content-Type: application/json
Authorization: Bearer {session_id}
{
"username": "j.doe38"
}
Réponse si disponible :
{
"status": "success",
"available": true,
"message": "Nom d'utilisateur disponible",
"username": "j.doe38"
}
Réponse si déjà pris :
{
"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é
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 :
{
"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é
GET /api/entites/{id}/logo
Authorization: Bearer {session_id}
Réponse :
{
"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é
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 passefalse: Génération automatique |
| chk_username_manuel | boolean | true: L'admin saisit les identifiantsfalse: 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 :
{
"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 :
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 :
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)
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 :
{
"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) :
- L'application crée/modifie d'abord le passage pour obtenir un ID réel
- Puis crée le PaymentIntent avec cet ID
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 :
{
"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_idest 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 ConnectGET /api/stripe/accounts/{id}: Statut d'un comptePUT /api/stripe/accounts/{id}: Mise à jour d'un compte
Gestion des paiements
POST /api/stripe/payments/create-intent: Création d'un PaymentIntentGET /api/stripe/payments/{id}: Statut d'un paiementPOST /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ésPOST /api/stripe/devices/check-tap-to-pay: Vérification de compatibilité d'un appareilGET /api/stripe/config: Configuration publique StripeGET /api/stripe/stats: Statistiques de paiement
Webhooks
POST /api/stripe/webhooks: Réception des événements Stripeaccount.updated: Mise à jour du statut d'un comptepayment_intent.succeeded: Confirmation d'un paiement réussipayment_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 coursrestricted: Informations manquantesactive: Opérationnel pour les paiementsrejected: Refusé par Stripe
États des paiements :
requires_payment_method: En attente de paiementprocessing: Traitement en courssucceeded: Paiement réussicanceled: 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.phplignes 175-187 (sectiondapp.geosector.fr) - RECETTE :
AppConfig.phplignes 150-162 (sectionrapp.geosector.fr) - PRODUCTION :
AppConfig.phplignes 126-138 (sectionapp.geosector.fr)
Configuration des clés client
Pour configurer les clés Stripe du client :
-
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é
-
Remplacer les placeholders dans AppConfig.php
- RECETTE (ligne 152-153) : Remplacer
CLIENT_PK_TEST_A_REMPLACERetCLIENT_SK_TEST_A_REMPLACER - PRODUCTION (ligne 130-131) : Remplacer
CLIENT_PK_LIVE_A_REMPLACERetCLIENT_SK_LIVE_A_REMPLACER
- RECETTE (ligne 152-153) : Remplacer
-
Déployer selon l'environnement
# 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é
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 :
{
"status": "success",
"tap_to_pay_supported": true,
"message": "Tap to Pay disponible sur cet appareil",
"min_android_version": 14
}
Réponse iOS :
{
"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 paiementdocs/PLANNING-STRIPE-API.md: Planification et architecture Stripedocs/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 :
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) :
# 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 emailscleanup_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 :
# 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 :
- DEV : Archive du code local, déploiement sur container
dva-geosur IN3 (195.154.80.116)- URL publique : https://dapp.geosector.fr/api/
- IP interne : http://13.23.33.43/api/
- RECETTE : Archive depuis container
dva-geo, déploiement surrca-geosur IN3- URL publique : https://rapp.geosector.fr/api/
- PRODUCTION : Archive depuis
rca-geo(IN3), déploiement surpra-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/etuploads/ - Gestion des permissions :
- Code API :
nginx:nginx(755/644) - Logs et uploads :
nobody:nginx(755/644)
- Code API :
- 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ésPOST /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_devicesavec 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 :
- Queue d'emails : Toutes les 5 minutes
- Nettoyage sécurité : Quotidien à 2h
- 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 amicalestripe_payment_history: Historique des transactions Stripestripe_refunds: Gestion des remboursements- Ajout de
stripe_payment_iddansope_passpour 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) :
- Passage créé/modifié EN PREMIER pour obtenir un ID réel
- Création PaymentIntent avec
passage_idréel (jamais 0) - Traitement Tap to Pay via SDK Stripe Terminal
- Mise à jour automatique du passage avec
stripe_payment_id
Endpoints ajoutés :
POST /api/stripe/accounts/create: Création compte ConnectPOST /api/stripe/payments/create-intent: Création PaymentIntentGET /api/stripe/payments/{id}: Statut d'un paiementPOST /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 paiementdocs/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 :
PasswordSecurityServicepour 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_manuelsont 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_titredate_naissancedate_embaucheencrypted_phoneencrypted_mobile
- Impact : Ces données sont maintenant correctement retournées dans l'objet
userlors 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 logoGET /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
amicalelors 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 :
ReceiptServicepour 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_recuest vide/null
- Création d'un passage avec
- 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
mediasavec catégorierecu
- Queue d'envoi email :
- Envoi automatique par email avec pièce jointe PDF
- Format MIME multipart pour compatibilité maximale
- Gestion dans la table
email_queueavec 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çudate_sent_recu: Date d'envoi par emailchk_email_sent: Indicateur d'envoi réussi