# Documentation Technique API GeoSector ## đŸ—ïž Infrastructure **Stack** : PHP 8.3 | NGINX | MariaDB 10.11 | Alpine Linux (Incus) | Environnement | Container | DB (IP) | URL | Serveur | |---------------|-----------|---------|-----|---------| | **DEV** | dva-geo | maria3 (13.23.33.4) | https://dapp.geosector.fr | IN3 (195.154.80.116) | | **REC** | rca-geo | maria3 (13.23.33.4) | https://rapp.geosector.fr | IN3 (195.154.80.116) | | **PROD** | pra-geo | maria4 (13.23.33.4) | https://app3.geosector.fr | IN4 (51.159.7.190) | **Architecture** : MVC sans framework | Point d'entrĂ©e : `index.php` | Config : `AppConfig.php` singleton ## đŸ—„ïž Base de donnĂ©es ### ModĂšle d'isolation par opĂ©ration (CRITIQUE) **Principe** : Chaque opĂ©ration est un **univers fermĂ©** isolĂ© de la table centrale `users`. ``` users (table centrale, conservĂ©e aprĂšs suppression opĂ©ration) └── ope_users (id, fk_user, fk_operation) ← PIVOT par opĂ©ration ├── ope_users_sectors (fk_user → ope_users.id) └── ope_pass (fk_user → ope_users.id) ``` **⚠ IMPORTANT pour Flutter** : - **`users.id`** = Identifiant global (gestion membres, login) - **`ope_users.id`** = Identifiant opĂ©ration (passages, secteurs) - **Flutter doit gĂ©rer les 2 IDs** lors du login et des CRUD **RĂ©ponse login :** ```json { "users_sectors": [ { "id": 123, // users.id (gestion membres) "ope_user_id": 50, // ope_users.id (passages/secteurs) "name": "John Doe", "fk_sector": 456 } ] } ``` **RequĂȘtes API depuis Flutter :** ```json // ✅ CrĂ©ation secteur : envoyer ope_users.id POST /api/sectors { "users": [50, 51] } // ope_users.id // ✅ CrĂ©ation passage : fk_user = ope_users.id POST /api/passages { "fk_user": 50 } // ope_users.id // ✅ Modification membre : utiliser users.id PUT /api/users/123 // users.id ``` ### Tables principales - **`entites`** : Amicales (chiffrement AES-256-CBC sur nom, email, IBAN) - **`users`** : Table centrale utilisateurs (conservĂ©e mĂȘme si opĂ©ration supprimĂ©e) - **`operations`** : Campagnes liĂ©es Ă  une entitĂ© - **`ope_users`** : **PIVOT** users ↔ opĂ©rations (ON DELETE CASCADE depuis operations) - **`ope_sectors`** : Secteurs gĂ©ographiques (polygones) - **`ope_users_sectors`** : Affectation users ↔ secteurs (FK → `ope_users.id`) - **`ope_pass`** : Passages (FK → `ope_users.id`, ON DELETE CASCADE) - **`medias`** : Fichiers (logos, exports, reçus) - Stockage : `/uploads/` ## 🔒 SĂ©curitĂ© - **Auth** : Sessions PHP (httpOnly, secure, SameSite=Strict) - **Mots de passe** : NIST SP 800-63B, bcrypt, HIBP check (k-anonymity) - **Chiffrement** : AES-256-CBC (noms, emails, tĂ©lĂ©phones, IBAN) - **Protection** : Brute force (8 tentatives/5min), IP blocking, PDO prepared statements - **Monitoring** : `SecurityMonitor`, `AlertService`, `IPBlocker` ## 💳 Stripe Connect - **DEV** : ClĂ©s TEST Pierre - **REC** : ClĂ©s TEST client + webhook `webhook-rca` - **PROD** : ClĂ©s LIVE client + webhook `webhook-pra` - **API** : `2025-08-27.basil` - **Tap to Pay** : iOS 16.4+ (iPhone XS+) | Android 11+ (95+ devices certifiĂ©s) - **Flow** : Passage créé → PaymentIntent → Tap to Pay → Mise Ă  jour `stripe_payment_id` ## 📩 FonctionnalitĂ©s 1. **Reçus fiscaux** : PDF auto (<5KB) pour dons, envoi email queue 2. **Logos entitĂ©s** : Upload PNG/JPG, redimensionnement 250x250px, base64 3. **Migration** : Endpoints REST par entitĂ© (9 phases) 4. **CRONs** : Email queue (*/5), cleanup sĂ©curitĂ© (2h) ## 📊 Statistiques Events (Admin Flutter) ### Architecture **Principe** : Stats prĂ©-agrĂ©gĂ©es en SQL + dĂ©tail JSONL Ă  la demande | Source | Usage | Performance | |--------|-------|-------------| | Table `event_stats_daily` | Dashboard, graphiques, tendances | InstantanĂ© (~1ms) | | Fichiers JSONL | DĂ©tail Ă©vĂ©nements (clic sur stat) | PaginĂ© (~50-100ms) | ### Flux de donnĂ©es 1. **EventLogService** Ă©crit les Ă©vĂ©nements dans `/logs/events/YYYY-MM-DD.jsonl` 2. **CRON nightly** agrĂšge J-1 dans `event_stats_daily` 3. **API** sert les stats agrĂ©gĂ©es (SQL) ou le dĂ©tail paginĂ© (JSONL) 4. **Flutter Admin** affiche dashboard avec drill-down ### Table d'agrĂ©gation **`event_stats_daily`** : Une ligne par (date, entitĂ©, type d'Ă©vĂ©nement) | Colonne | Description | |---------|-------------| | `stat_date` | Date des stats | | `entity_id` | EntitĂ© (NULL = global super-admin) | | `event_type` | Type Ă©vĂ©nement (login_success, passage_created, etc.) | | `count` | Nombre d'occurrences | | `sum_amount` | Somme montants (passages) | | `unique_users` | Utilisateurs distincts | | `metadata` | JSON agrĂ©gĂ© (top secteurs, erreurs frĂ©quentes, etc.) | ### Endpoints API | Endpoint | PĂ©riode | Source | Taille rĂ©ponse | |----------|---------|--------|----------------| | `GET /events/stats/summary` | Jour courant | SQL | ~1 KB | | `GET /events/stats/daily` | Plage dates | SQL | ~5 KB | | `GET /events/stats/weekly` | CalculĂ© depuis daily | SQL | ~2 KB | | `GET /events/stats/monthly` | CalculĂ© depuis daily | SQL | ~1 KB | | `GET /events/details` | DĂ©tail paginĂ© | JSONL | ~10 KB | ### Optimisations transfert Flutter - **Pagination** : 50 events max par requĂȘte dĂ©tail - **Champs filtrĂ©s** : Pas d'IP ni user_agent complet dans les rĂ©ponses - **Compression gzip** : -70% sur JSON - **Cache HTTP** : ETag sur stats (changent 1x/jour) - **Calcul hebdo/mensuel** : À la volĂ©e depuis `daily` (pas de tables supplĂ©mentaires) ### Types d'Ă©vĂ©nements agrĂ©gĂ©s | CatĂ©gorie | Events | |-----------|--------| | **Auth** | login_success, login_failed, logout | | **Passages** | passage_created, passage_updated, passage_deleted | | **Secteurs** | sector_created, sector_updated, sector_deleted | | **Users** | user_created, user_updated, user_deleted | | **EntitĂ©s** | entity_created, entity_updated, entity_deleted | | **OpĂ©rations** | operation_created, operation_updated, operation_deleted | | **Stripe** | stripe_payment_created, stripe_payment_success, stripe_payment_failed, stripe_payment_cancelled, stripe_terminal_error | ### AccĂšs et sĂ©curitĂ© - **RĂŽle requis** : Admin entitĂ© (role_id = 2) ou Super-admin (role_id = 1) - **Isolation** : Admin voit uniquement les stats de son entitĂ© - **Super-admin** : AccĂšs global (entity_id = NULL dans requĂȘtes) ## 🚀 DĂ©ploiement ```bash ./deploy-api.sh # Local → dva-geo (DEV) ./deploy-api.sh rca # dva-geo → rca-geo (REC) ./deploy-api.sh pra # rca-geo → pra-geo (PROD) ``` - Backup auto (10 versions) - PrĂ©servation `/logs/` et `/uploads/` - Permissions : `nginx:nginx` (code), `nginx:nginx` (logs/uploads) - Composer install avec `--optimize-autoloader` ## ⚠ Points d'attention API ↔ Flutter ### 1. Isolation opĂ©rations (depuis Oct 2025) **Avant** : `ope_pass.fk_user` → `users.id` (table centrale) **AprĂšs** : `ope_pass.fk_user` → `ope_users.id` (pivot opĂ©ration) **Impact Flutter** : - Login retourne **2 IDs** : `id` (users.id) + `ope_user_id` (ope_users.id) - CrĂ©ation secteur/passage : envoyer `ope_user_id` - Affichage passages : mapper avec `ope_user_id` ### 2. Endpoints critiques modifiĂ©s | Endpoint | Body envoyĂ© | Mapping | |----------|-------------|---------| | `POST /api/sectors` | `users: [50, 51]` | ope_users.id | | `PUT /api/sectors/{id}` | `users: [50, 51]` | ope_users.id | | `POST /api/passages` | `fk_user: 50` | ope_users.id | | `PUT /api/passages/{id}` | `fk_user: 50` | ope_users.id | | `POST /api/users` | - | Retourne `ope_user_id` | ### 3. RequĂȘte SQL typique ```sql -- ❌ AVANT (CASSÉ) SELECT op.*, u.encrypted_name FROM ope_pass op JOIN users u ON op.fk_user = u.id -- ✅ APRÈS (CORRECT) SELECT op.*, u.encrypted_name FROM ope_pass op JOIN ope_users ou ON op.fk_user = ou.id JOIN users u ON ou.fk_user = u.id ``` ### 4. Suppression en cascade ```sql DELETE FROM operations WHERE id = 850; -- Supprime automatiquement (CASCADE) : -- - ope_users -- - ope_users_sectors -- - ope_pass -- - ope_sectors -- ✅ users conservĂ© (table centrale) ``` ## 📝 Changelog critique **Version 3.3.7 (26 Oct 2025)** : - 🔧 Correction bug `SectorController::update()` : Recherche users par `ope_users.id` au lieu de `users.id` - 🔧 Permissions logs corrigĂ©es : `nginx:nginx` + `750/640` - 🔧 PHP `display_errors = Off` (warnings loggĂ©s dans `/var/log/php83/error.log`) **Version 3.3.6 (21 Oct 2025)** : - Validation inscription : Code postal + ville (doublon) **Version 3.2.7 (16 Oct 2025)** : - Migration RCA-GEO vers maria3 complĂ©tĂ©e - URL PROD : `app3.geosector.fr` **Version 3.2.4-3.2.6 (Sep 2025)** : - Stripe Connect complet (Tap to Pay, webhooks multi-env) --- **Mis Ă  jour : 22 DĂ©cembre 2025**