diff --git a/README.md b/README.md
index cab44093..c5243b40 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,26 @@
# đ Documentation API - Plateforme de Gestion de Commandes
-**Version:** 5.4.0
-**Date:** 2026-06-11
+**Version:** 5.2.0
+**Date:** 2026-05-01
**Base URL prod:** `https://mln-uber.club` (HTTPS via WAF nginx + ModSecurity)
**Base URL dev:** `http://localhost:8080`
**Technologies:** Go 1.24, Gin, PostgreSQL 16, Redis 7, React 19 + Vite, Expo 54 (React Native), TomTom API
+---
## đ Table des MatiĂšres
1. [Vue d'ensemble](#vue-densemble)
-2. [Infrastructure Serveurs](#-infrastructure-serveurs)
-3. [Déploiement Production](#-déploiement-production)
-4. [Authentication](#authentication)
-5. [API Client (v1)](#api-client-v1)
-6. [API Admin (v2)](#api-admin-v2)
-7. [API Cabine (v1)](#api-cabine-v1)
-8. [API Livreur (v1)](#api-livreur-v1)
-9. [Notifications Push & Telegram](#-notifications-push--telegram)
-10. [Paiements Crypto](#-paiements-crypto)
-11. [Systeme GPS Integre](#-systeme-gps-integre)
-12. [Codes d'Erreur](#codes-derreur)
+2. [Déploiement Production](#-déploiement-production)
+3. [Authentication](#authentication)
+4. [API Client (v1)](#api-client-v1)
+5. [API Admin (v2)](#api-admin-v2)
+6. [API Cabine (v1)](#api-cabine-v1)
+7. [API Livreur (v1)](#api-livreur-v1)
+8. [Notifications Push & Telegram](#-notifications-push--telegram)
+9. [Paiements Crypto](#-paiements-crypto)
+10. [Systeme GPS Integre](#-systeme-gps-integre)
+11. [Codes d'Erreur](#codes-derreur)
---
@@ -35,14 +35,12 @@ Cette API REST complĂšte gĂšre une plateforme de livraison avec assignation auto
- **đ Suivi temps rĂ©el** avec ETA et gĂ©olocalisation
- **đ SystĂšme de queues** Redis optimisĂ© pour les livraisons
- **⥠Workers automatiques** (nettoyage, assignation, notifications)
-- **đŻ SystĂšme de pĂ©nalitĂ©s clients** â amendes progressives sur annulations (livreurs non concernĂ©s)
-- **đ€ Notifications Telegram** pour clients, livreurs et admins (push Expo abandonnĂ©)
+- **đŻ SystĂšme de pĂ©nalitĂ©s** pour la gestion des comportements
+- **đ Notifications push** Expo (iOS/Android) pour clients et livreurs
+- **đ€ IntĂ©gration Telegram** pour alertes et notifications admin/livreur
- **đž Paiements crypto** via NowPayments (webhook HMAC)
- **đĄïž WAF nginx + ModSecurity** (OWASP CRS) en production
- **đ± Applications mobiles** Expo 54 (client + admin/livreur)
-- **đ·ïž Prix par quantitĂ© activables/dĂ©sactivables** â visibilitĂ© client filtrĂ©e automatiquement
-- **â±ïž Bouton "Client absent"** â timer 5 min au statut `arrived`, amende automatique appliquĂ©e au **client** si absent
-- **đČ OTA updates** canaux nommĂ©s par rĂŽle (`pre-prod-client`, `production-client`, `pre-prod-admin`, etc.)
### đïž Stack Technique
@@ -242,7 +240,7 @@ graph TD
P3["GET /api/v1/products/category/:category"]
P4["GET /api/v1/categories"]
P5["GET /api/v1/app-settings"]
- P6["POST /api/v1/webhooks/nowpayments"]
+ P6["POST /api/v1/webhook/nowpayments"]
P7["POST /webhook/telegram"]
end
@@ -364,7 +362,6 @@ sequenceDiagram
participant API as Backend API
participant DB as PostgreSQL
participant R as Redis
- participant TG as Telegram
rect rgb(200, 230, 200)
Note over U,R: Registration
@@ -377,36 +374,15 @@ sequenceDiagram
end
rect rgb(200, 200, 230)
- Note over U,TG: Login Standard (2FA desactivee)
+ Note over U,R: Login
U->>F: Entrer credentials
F->>API: POST /auth/login
API->>DB: Verifier credentials
DB-->>API: User valide
API->>API: Generer JWT
API->>R: Stocker session
- API-->>F: 200 OK + { access_token, user }
- F->>F: Stocker token
- F-->>U: Connecte
- end
-
- rect rgb(255, 240, 200)
- Note over U,TG: Login avec 2FA (Telegram active)
- U->>F: Entrer credentials
- F->>API: POST /auth/login
- API->>DB: Verifier credentials + verifier 2FA active
- DB-->>API: User valide, 2FA requise
- API->>R: Stocker session_token (TTL 5min)
- API->>TG: Envoyer code 6 chiffres via bot Telegram
- API-->>F: 200 OK + { requires_2fa: true, session_token }
- F-->>U: Afficher saisie du code Telegram
- U->>F: Entrer code recu sur Telegram
- F->>API: POST /auth/2fa/verify { session_token, code }
- API->>R: Verifier code + session_token
- R-->>API: Code valide
- API->>API: Generer JWT
- API->>R: Stocker session
- API-->>F: 200 OK + { access_token, user }
- F->>F: Stocker token
+ API-->>F: 200 OK + JWT Token
+ F->>F: Stocker token (localStorage)
F-->>U: Connecte
end
@@ -556,7 +532,6 @@ erDiagram
int product_id FK
int quantity
float price
- boolean active_price
}
PRODUCT_MEDIA {
@@ -641,10 +616,6 @@ graph LR
C3["product:cache:{id}
TTL: 1h"]
end
- subgraph Notifs["đ Notifications"]
- N1["notifications:{username}
TTL: 1h"]
- end
-
subgraph PubSub["ïżœïżœ Pub/Sub Channels"]
PS1["channel:position_updates"]
PS2["channel:order_status"]
@@ -656,95 +627,11 @@ graph LR
REDIS --- Positions
REDIS --- Queues
REDIS --- Cache
- REDIS --- Notifs
REDIS --- PubSub
```
---
-## đ„ïž Infrastructure Serveurs
-
-### Réseau VPN (WireGuard)
-
-Tous les serveurs backend communiquent via un rĂ©seau WireGuard privĂ© `10.0.0.0/24`. Le SSH est restreint Ă l'IP VPN uniquement sur les serveurs sensibles â il faut ĂȘtre connectĂ© au VPN pour s'y connecter.
-
-| Serveur | IP Publique | IP VPN | RĂŽle |
-|---------|-------------|--------|------|
-| **vpn-uber** | `45.150.111.158` | `10.0.0.1` | Serveur WireGuard â point d'entrĂ©e VPN et jump host SSH |
-| **monitoring-uber** | `185.103.167.138` | `10.0.0.2` | Wazuh · Dozzle · Beszel hub · SSH via VPN uniquement |
-| **backup-mln** | `85.121.176.241` | `10.0.0.4` | MinIO S3 · ClamAV · Beszel agent · SSH via VPN uniquement |
-| **bdd-redis-prod** | `132.243.162.62` | `10.0.0.5` | PostgreSQL 16 · Redis 7 · Beszel agent · SSH via VPN uniquement |
-| **prod-uber** | `185.103.166.119` | `10.0.0.6` | Backend Go + WAF nginx · accessible publiquement sur 80/443 |
-| **pre-prod-uber** | `185.103.166.112` | â | Environnement de prĂ©-production |
-| **s3-uber** | `80.96.58.164` | â | Stockage S3 externe · Dozzle agent |
-
-### Architecture DMZ / LAN
-
-```mermaid
-graph TB
- Internet((Internet)) -->|"80/443 public"| Prod["prod-uber â DMZ
185.103.166.119"]
- Prod -->|"VPN (10.0.0.6)"| BDD["bdd-redis-prod â LAN
10.0.0.5"]
- BDD --> PG["PostgreSQL :5432"]
- BDD --> Redis["Redis :6379"]
-
- VPN["vpn-uber â 10.0.0.1
jump host SSH"] -.->|"accĂšs admin uniquement"| BDD
- VPN -.-> Prod
-
- style Internet fill:#eee,stroke:#999
- style Prod fill:#fde68a,stroke:#b45309
- style BDD fill:#bbf7d0,stroke:#15803d
- style VPN fill:#bfdbfe,stroke:#1d4ed8
-```
-
-L'application prod-uber se connecte Ă PostgreSQL et Redis via les IP VPN :
-- `DB_HOST=10.0.0.5` (PostgreSQL sur bdd-redis-prod)
-- `REDIS_HOST=10.0.0.5` (Redis sur bdd-redis-prod)
-
-### Monitoring
-
-Toutes les ressources monitoring sont accessibles via VPN (`10.0.0.2`) :
-
-| Outil | URL | Description |
-|-------|-----|-------------|
-| **Wazuh** | `https://10.0.0.2` | SIEM â alertes sĂ©curitĂ©, logs agents |
-| **Dozzle** | `https://10.0.0.2:8080` | Logs Docker de tous les serveurs en temps réel |
-| **Beszel** | `https://10.0.0.2:8090` | Métriques systÚme (CPU, RAM, disque, réseau) |
-
-Dozzle agrĂšge les logs de : `pre-prod-uber`, `prod-uber`, `backup-mln (VPN)`, `s3-uber`.
-Beszel surveille : `monitoring-uber`, `backup-mln` (agent Docker port 10001), `bdd-redis-prod` (agent binaire systemd port 10001).
-
-Nettoyage automatique des logs Wazuh : cron tous les dimanches Ă 3h00 sur monitoring-uber (`/usr/local/bin/clean-wazuh-logs.sh`).
-
-### Sécurité réseau
-
-- **UFW** activé sur monitoring-uber et backup-mln : SSH bloqué depuis IP publique, accessible uniquement via VPN
-- **UFW** activé sur bdd-redis-prod : SSH, PostgreSQL et Redis accessibles uniquement depuis le réseau VPN (`10.0.0.0/24`)
-- Ports Docker liés à l'IP VPN (`10.0.0.4:port:port`) pour ne pas bypasser UFW
-- **ClamAV** sur backup-mln : scan antivirus quotidien de `/mnt/data`
-
-### AccĂšs SSH aux serveurs VPN-only
-
-```bash
-# Via le jump host vpn-uber
-ssh -J root@45.150.111.158 root@10.0.0.2 # monitoring-uber
-ssh -J root@45.150.111.158 root@10.0.0.4 # backup-mln
-ssh -J root@45.150.111.158 root@10.0.0.5 # bdd-redis-prod
-```
-
-### Sauvegarde S3 (backup-mln)
-
-MinIO S3 tourne sur backup-mln avec nginx SSL proxy :
-
-| Endpoint | Adresse |
-|----------|---------|
-| API S3 | `https://10.0.0.4:9000` (via VPN) |
-| Console MinIO | `https://10.0.0.4:9001` (via VPN) |
-| Console nginx | `https://10.0.0.4:8080` (via VPN) |
-
-Les données sont montées sur `/mnt/data`.
-
----
-
## đ DĂ©ploiement Production
### Prérequis
@@ -791,84 +678,53 @@ docker compose -f docker/docker-compose-prod.yml up -d --build
docker compose -f docker/docker-compose-prod.yml logs -f waf
```
-### Services Docker (prod-uber)
+### Services Docker
| Service | Image | RĂŽle |
|---------|-------|------|
| `waf` | owasp/modsecurity-crs:nginx-alpine | Point d'entrée HTTPS (ports 80/443) |
| `backend` | Go 1.24 alpine | API REST (port 8080 interne) |
| `frontend` | nginx:alpine | SPA React (port 80 interne) |
-
-> PostgreSQL et Redis **ne tournent plus sur prod-uber**. Ils sont hébergés sur le serveur dédié `bdd-redis-prod` (`10.0.0.5`) et accessibles via le VPN WireGuard. Voir la section [Infrastructure Serveurs](#-infrastructure-serveurs).
+| `postgres` | postgres:16-alpine | Base de données |
+| `redis` | redis:7-alpine | Cache + sessions + queues |
### Variables d'environnement requises
```bash
-# Base de données (bdd-redis-prod via VPN)
-DB_HOST=10.0.0.5 # IP VPN de bdd-redis-prod
-DB_PORT=5432
DB_PASSWORD= # Mot de passe PostgreSQL
-
-# Redis (bdd-redis-prod via VPN)
-REDIS_HOST=10.0.0.5 # IP VPN de bdd-redis-prod
-REDIS_PORT=6379
-REDIS_PASSWORD= # Mot de passe Redis
-
-# JWT
USER_JWT_SECRET= # Secret JWT clients (min 32 chars)
ADMIN_JWT_SECRET= # Secret JWT admin/livreur/cabine (min 32 chars)
-
-# TomTom (rotation automatique entre les 3 clés)
-TOMTOM_API_KEY= # Clé TomTom principale / legacy
-TOMTOM_API_KEY_1= # Clé TomTom #1
-TOMTOM_API_KEY_2= # Clé TomTom #2
-TOMTOM_API_KEY_3= # Clé TomTom #3
-
-# Divers
-SESSION_SECRET= # Secret sessions
-TELEGRAM_WEBHOOK_URL= # URL webhook Telegram
-TELEGRAM_WEBHOOK_SECRET= # Secret webhook Telegram
-NOWPAYMENTS_IPN_SECRET= # Secret IPN NowPayments
-
-# Stockage médias produits (photos/vidéos)
-STORAGE_DRIVER=local # "local" (disque, défaut) ou "s3" (RustFS)
-# Requis uniquement si STORAGE_DRIVER=s3 :
-S3_REGION= # Région S3 (arbitraire pour RustFS, ex: us-east-1)
-S3_BUCKET= # Nom du bucket
-S3_ENDPOINT= # URL du endpoint S3-compatible (RustFS, IP VPN interne)
-RUSTFS_ACCESS_KEY= # Clé d'accÚs RustFS
-RUSTFS_SECRET_KEY= # Clé secrÚte RustFS
-```
-
-```mermaid
-flowchart LR
- Upload["CreateProduct /
UploadMedia"] --> Check{"STORAGE_DRIVER"}
- Check -->|"local (défaut)"| Local["LocalStorage
disque ./uploads"]
- Check -->|"s3"| S3["S3Storage
RustFS (auto-hébergé)"]
-
- Delete["DeleteProduct /
DeleteMedia"] --> KeyCheck{"media.Key
rempli ?"}
- KeyCheck -->|non| Local
- KeyCheck -->|oui| S3
+REDIS_PASSWORD= # Mot de passe Redis
+TOMTOM_API_KEY= # Clé API TomTom
+SESSION_SECRET= # Secret sessions
+TELEGRAM_WEBHOOK_URL= # URL webhook Telegram
+TELEGRAM_WEBHOOK_SECRET= # Secret webhook Telegram
+NOWPAYMENTS_IPN_SECRET= # Secret IPN NowPayments
```
---
-## đ Notifications
+## đ Notifications Push & Telegram
-Les notifications clients et livreurs sont gĂ©rĂ©es **exclusivement via Telegram** â les push notifications Expo (iOS/Android) ne sont plus utilisĂ©es.
+### Push Notifications (Expo)
-### Notifications Telegram
+Le systĂšme utilise Expo Push Notifications pour envoyer des notifications aux applications mobiles (client et livreur). Les tokens Expo sont envoyĂ©s directement via l'API Expo depuis le backend â il n'y a pas d'endpoint REST dĂ©diĂ© Ă l'enregistrement du push token.
-Clients, livreurs et admins reçoivent leurs alertes via un bot Telegram lié à leur compte.
+**Flux :**
+1. L'app mobile obtient un `ExponentPushToken` via `expo-notifications`
+2. Le backend envoie les notifications via `sendExpoPush()` dans `db/db_notifications.go`
+3. Expo relay la notification vers le device cible (iOS/Android)
**Types de notifications envoyées :**
- `assigned` â Commande assignĂ©e Ă un livreur
- `en_route` â Livreur en route (avec ETA)
-- `arrived` â Livreur arrivĂ©
+- `arrived` â Livreur arrivĂ© (bouton "Le livreur est lĂ ")
- `livre` â Commande livrĂ©e
-- `ready_pickup` â Cabine : "descendez chercher votre commande"
+- `ready_pickup` â Notification cabine "descendez chercher"
- `address_proposal` â Proposition de changement d'adresse
+### Notifications Telegram
+
Les admins et livreurs peuvent lier leur compte Telegram pour recevoir des alertes.
#### Générer un token de liaison (Admin)
@@ -947,9 +803,50 @@ Authorization: Bearer
## đ Authentication
-### Création de compte client
+### Register Client
-Les comptes clients sont créés **uniquement par un administrateur** via `POST /api/v2/admin/protected/clients`. Il n'existe pas d'endpoint d'auto-inscription.
+**Créer un nouveau compte client**
+
+```bash
+POST /api/v1/auth/register
+Content-Type: application/json
+```
+
+**RequĂȘte:**
+```json
+{
+ "username": "jean_dupont",
+ "password": "SecurePass123!",
+ "nom": "Dupont",
+ "prenom": "Jean",
+ "telephone": "+33612345678"
+}
+```
+
+**Réponse (201 Created):**
+```json
+{
+ "success": true,
+ "message": "Client créé avec succÚs",
+ "client": {
+ "id": 42,
+ "username": "jean_dupont",
+ "nom": "Dupont",
+ "prenom": "Jean",
+ "telephone": "+33612345678",
+ "command": 0,
+ "point": 0,
+ "points_zipette": 0,
+ "amende": 0.0,
+ "cancellations_count": 0,
+ "created_at": "2025-01-18T14:30:00Z"
+ }
+}
+```
+
+**Erreurs possibles:**
+- `400` - Données invalides (validation échouée)
+- `409` - Username ou téléphone déjà utilisé
---
@@ -970,7 +867,7 @@ Content-Type: application/json
}
```
-**RĂ©ponse standard (200 OK) â 2FA dĂ©sactivĂ©e:**
+**Réponse (200 OK):**
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
@@ -983,122 +880,12 @@ Content-Type: application/json
}
```
-**RĂ©ponse avec 2FA (200 OK) â quand 2FA activĂ©e par le client ET Telegram liĂ© ET admin l'a activĂ©e:**
-```json
-{
- "requires_2fa": true,
- "session_token": "550e8400-e29b-41d4-a716-446655440000"
-}
-```
-> Un code à 6 chiffres est envoyé automatiquement sur le compte Telegram lié. Le `session_token` expire dans **5 minutes**.
-
**Erreurs possibles:**
- `400` - Données manquantes
- `401` - Identifiants incorrects
---
-### Vérifier le code 2FA
-
-**Valider le code Telegram reçu pour finaliser la connexion**
-
-```bash
-POST /api/v1/auth/2fa/verify
-Content-Type: application/json
-```
-
-**RequĂȘte:**
-```json
-{
- "session_token": "550e8400-e29b-41d4-a716-446655440000",
- "code": "483721"
-}
-```
-
-**Réponse (200 OK):**
-```json
-{
- "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
- "token_type": "Bearer",
- "expires_in": 18000,
- "user": {
- "username": "jean_dupont",
- "role": "client"
- }
-}
-```
-
-**Erreurs possibles:**
-- `400` - `session_token` ou `code` manquant
-- `401` - Code incorrect ou session expirée (TTL 5 min)
-- `429` - Trop de tentatives (rate limiting)
-
----
-
-### Statut 2FA du compte
-
-**Obtenir l'état de la 2FA pour le compte connecté**
-
-```bash
-GET /api/v1/two-fa/status
-Authorization: Bearer
-```
-
-**Réponse (200 OK):**
-```json
-{
- "two_fa_enabled": true,
- "telegram_linked": true,
- "admin_2fa_enabled": true
-}
-```
-
-| Champ | Description |
-|-------|-------------|
-| `two_fa_enabled` | La 2FA est activée sur ce compte client |
-| `telegram_linked` | Un compte Telegram est lié (prérequis pour activer) |
-| `admin_2fa_enabled` | L'admin a activé la 2FA dans les paramÚtres globaux |
-
----
-
-### Activer / Désactiver la 2FA
-
-**Basculer l'état de la 2FA sur son propre compte**
-
-```bash
-POST /api/v1/two-fa/toggle
-Authorization: Bearer
-Content-Type: application/json
-```
-
-**RequĂȘte:**
-```json
-{
- "enabled": true
-}
-```
-
-**Réponse (200 OK):**
-```json
-{
- "success": true,
- "two_fa_enabled": true
-}
-```
-
-**Prérequis pour activer (`"enabled": true`):**
-1. Le client doit avoir lié son compte Telegram (via `/api/v1/auth/link-telegram`)
-2. L'administrateur doit avoir activé `telegram_2fa_enabled` dans les paramÚtres globaux
-
-**Erreurs possibles:**
-- `400` - Telegram non lié (impossible d'activer sans compte Telegram)
-- `403` - La 2FA n'est pas autorisée par l'administrateur
-- `401` - Non authentifié
-
-> **Interface utilisateur:** Sur le frontend web (page profil) et l'app mobile, un toggle permet d'activer/désactiver la 2FA directement depuis les paramÚtres du compte.
-
----
-
### Logout Client
**Se déconnecter (invalider le token)**
@@ -1127,8 +914,6 @@ Authorization: Bearer
### Produits (Public - Pas d'auth requis)
-> **Filtrage des prix inactifs :** Chaque prix d'un produit porte un flag `active_price` (booléen). Les endpoints publics et client **n'exposent que les prix actifs** (`active_price = true`). Les rÎles `admin` et `cabine` reçoivent tous les prix (actifs et inactifs) pour permettre la gestion complÚte. CÎté frontend (web + mobile), les prix sont également filtrés au chargement (`filter(p => p.active_price !== false)`).
-
#### Liste des produits
```bash
@@ -1152,8 +937,7 @@ GET /api/v1/products
"id": 1,
"product_id": 1,
"quantity": 1,
- "price": 12.50,
- "active_price": true
+ "price": 12.50
}
],
"media": [
@@ -1301,7 +1085,8 @@ Content-Type: application/json
{
"success": true,
"message": "Produit supprimé du panier avec succÚs",
- "item_id": 15
+ "item_id": 15,
+ "stock_released": true
}
```
@@ -1322,7 +1107,8 @@ Authorization: Bearer
```json
{
"success": true,
- "message": "Panier vidé avec succÚs"
+ "message": "Panier vidé avec succÚs",
+ "stock_released": 3
}
```
@@ -1379,38 +1165,6 @@ Content-Type: application/json
- `401` - Non authentifié
- `500` - Erreur création commande
-**RĂ©ponse â adresse connue pour ĂȘtre mal formĂ©e (400 Bad Request):**
-
-Si l'adresse saisie correspond (match exact ou normalisĂ© â accents/casse/espaces ignorĂ©s) Ă une entrĂ©e de la table de corrections gĂ©rĂ©e par l'admin/cabine (`POST/DELETE /addresses`), le checkout est volontairement bloquĂ© pour forcer une reconfirmation du client plutĂŽt que d'appliquer la correction en silence :
-```json
-{
- "error": "Adresse non reconnue",
- "corrected_address": "15 Rue de la Paix, 75002 Paris, France"
-}
-```
-Le client doit renvoyer la requĂȘte avec `delivery_address` = `corrected_address` pour valider le checkout.
-
-```mermaid
-sequenceDiagram
- participant C as Client
- participant API as API (ValidateBasket)
- participant DB as adresse_correction
-
- C->>API: POST /checkout {delivery_address}
- API->>DB: CheckAddress(delivery_address)
- DB->>DB: Match exact, sinon fallback normalisé
(accents/casse/espaces)
- alt Correction trouvée
- DB-->>API: corrected_address
- API-->>C: 400 {error, corrected_address}
- C->>C: Affiche la suggestion (modal)
- C->>API: POST /checkout {delivery_address: corrected_address}
- API-->>C: 200 Commande créée
- else Aucune correction connue
- DB-->>API: nil
- API-->>C: 200 Commande créée
- end
-```
-
---
#### Mes commandes avec suivi
@@ -1963,34 +1717,9 @@ Content-Type: application/json
---
-### SystÚme de Pénalités (Clients uniquement)
+### SystÚme de Pénalités
-Les amendes s'appliquent **uniquement aux clients**. Les livreurs n'ont pas d'amende.
-
-Les amendes sont stockées dans `clients.amende` (PostgreSQL). Tant que `amende > 0`, le middleware `BlockClientIfPenalty` bloque toute tentative de checkout.
-
-**Ăchelle progressive (annulations) :**
-| Nbre d'annulations | Amende |
-|---|---|
-| 1Úre | 20 ⏠|
-| 2Úme | 50 ⏠|
-| 3Úme | 100 ⏠|
-| 4Úme et + | 150 ⏠|
-
-**Sources d'amende :**
-- Client annule sa propre commande â `ApplyCancellationPenalty` (incrĂ©mente `cancellations_count`)
-- Livreur marque le client absent depuis le statut `arrived` â amende appliquĂ©e automatiquement sur le **client**
-
-**Message d'erreur au checkout bloqué :**
-```json
-{
- "error": "Commande bloquée : vous avez une amende de 20⏠en attente de paiement. Prenez attache avec Milieu Nantais sur signal pour régulariser votre situation..",
- "amende": 20.0,
- "blocked": true
-}
-```
-
-#### Appliquer une pénalité (Admin)
+#### Appliquer une pénalité
```bash
POST /api/v2/admin/protected/penalty
@@ -2272,22 +2001,6 @@ Content-Type: application/json
> **Note :** Le passage à `livre` via ce endpoint requiert des coordonnées GPS valides pour la validation de proximité.
-> **Amende automatique :** si le livreur annule une commande dont le statut courant est `arrived`, une amende progressive est automatiquement appliquĂ©e au client (`ApplyCancellationPenalty`) â Ă©chelle : 1Ăšre=20âŹ, 2Ăšme=50âŹ, 3Ăšme=100âŹ, 4Ăšme+=150âŹ. Le livreur peut dĂ©clencher cette annulation via le bouton **"Client absent"** (cf. section ci-dessous).
-
----
-
-### Bouton "Client absent" (DashboardScreen)
-
-Lorsque le statut d'une livraison passe à `arrived`, un timer de **5 minutes** démarre automatiquement dans l'app livreur (`frontend-admin`). Pendant ce délai, un compte à rebours est affiché sur la carte de livraison. Une fois les 5 minutes écoulées, le bouton **"Client absent"** apparaßt.
-
-**Comportement :**
-- Appui sur "Client absent" â annulation de la commande avec la raison `client_absent`
-- L'API reçoit `status: cancelled` + `issue_type: client_absent`
-- Le backend applique automatiquement `ApplyCancellationPenalty(clientUsername)` (amende progressive)
-- Le timer est stocké dans un `useRef` (pas de re-render) et comparé à `Date.now()` toutes les secondes
-
-**ImplĂ©mentation :** `frontend-admin/src/screens/delivery/DashboardScreen.tsx` â constante `ABSENT_TIMEOUT_SECS = 300`, ref `arrivedAtRef`, Ă©tat `elapsedSeconds`.
-
---
### Position GPS
@@ -2580,26 +2293,23 @@ L'ETA est calcule en utilisant l'API TomTom qui prend en compte:
- Les travaux
- L'heure de la journee
-**Rotation automatique des clĂ©s :** jusqu'Ă 3 clĂ©s TomTom peuvent ĂȘtre configurĂ©es (`TOMTOM_API_KEY`, `TOMTOM_API_KEY_1`, `TOMTOM_API_KEY_2`, `TOMTOM_API_KEY_3`). En cas de quota dĂ©passĂ© (HTTP 403/429), le systĂšme passe automatiquement Ă la clĂ© suivante sans interruption de service.
-
```mermaid
flowchart TD
- A[Demande ETA] --> B{Clés TomTom configurées?}
+ A[Demande ETA] --> B{TomTom API disponible?}
+ B -->|Oui| C[Appel TomTom Routing API]
+ C --> D[ETA avec trafic reel]
B -->|Non| E[Calcul Haversine]
- B -->|Oui| C[Appel TomTom â clĂ© active]
- C --> Q{Quota dépassé 403/429?}
- Q -->|Oui| R{Clé suivante disponible?}
- R -->|Oui| C
- R -->|Non| E
- Q -->|Non| D[ETA avec trafic réel]
- E --> F[Distance Ă vol d'oiseau]
+ E --> F[Distance a vol d'oiseau]
F --> G[Vitesse moyenne 30 km/h]
- G --> H[ETA estimé]
+ G --> H[ETA estime]
D --> I[Retourner ETA]
H --> I
+ I --> J{Fallback utilise?}
+ J -->|Oui| K[Ajouter flag fallback_used: true]
+ J -->|Non| L[Response standard]
```
-**Fallback:** Si toutes les clés TomTom sont épuisées ou indisponibles, le systÚme utilise un calcul local base sur:
+**Fallback:** Si l'API TomTom est indisponible, le systeme utilise un calcul local base sur:
- Distance Haversine
- Vitesse moyenne estimee (30 km/h en ville)
@@ -2986,8 +2696,6 @@ stateDiagram-v2
- Livreur PUT status=arrived
- Admin/Cabine bouton "Le livreur est la"
Notifie le client (Telegram + push)
- Timer 5min â bouton "Client absent"
- Annulation depuis arrived â amende client
end note
note right of en_route
@@ -3008,9 +2716,9 @@ Si une adresse ne peut pas etre geocodee:
- Un log d'erreur est genere
- L'admin peut corriger l'adresse manuellement
-#### API TomTom Indisponible / Quota dépassé
+#### API TomTom Indisponible
-Le systÚme tente d'abord toutes les clés disponibles en rotation, puis bascule sur le calcul local :
+Le systeme bascule automatiquement sur le calcul local:
- Utilise la formule Haversine pour la distance
- Estime l'ETA avec une vitesse moyenne de 30 km/h
- Un flag `fallback_used: true` est ajoute a la reponse
@@ -3084,15 +2792,6 @@ Le systÚme tente d'abord toutes les clés disponibles en rotation, puis bascule
}
```
-#### 403 - Checkout bloqué (amende en attente)
-```json
-{
- "error": "Commande bloquée : vous avez une amende de 20⏠en attente de paiement. Prenez attache avec Milieu Nantais sur signal pour régulariser votre situation..",
- "amende": 20.0,
- "blocked": true
-}
-```
-
#### 404 - Not Found
```json
{
@@ -3159,64 +2858,8 @@ Le systÚme tente d'abord toutes les clés disponibles en rotation, puis bascule
---
-## đ Changelog
-
-### v5.7.0 â 2026-08-04
-
-- **Nouveau â choix du backend de stockage mĂ©dias (`STORAGE_DRIVER`)** : les photos/vidĂ©os produits pouvaient ĂȘtre stockĂ©es soit sur disque local (`CreateProduct`) soit sur S3/RustFS (`UploadMedia`) selon l'endpoint utilisĂ©, sans logique commune. Une interface `Storage` unifiĂ©e (`services/storage.go`, implĂ©mentations `LocalStorage`/`S3Storage`) est maintenant utilisĂ©e par les deux endpoints, pilotĂ©e par la variable d'environnement `STORAGE_DRIVER` (`local` par dĂ©faut, ou `s3`).
-- **Fix â nettoyage croisĂ© des mĂ©dias Ă la suppression** : `DeleteProduct` supprimait toujours sur disque (mĂȘme pour un mĂ©dia stockĂ© sur S3) et `DeleteMedia` supprimait toujours sur S3 (mĂȘme pour un mĂ©dia local), laissant systĂ©matiquement des fichiers orphelins sur l'autre backend. Les deux fonctions branchent dĂ©sormais sur `media.Key` (rempli uniquement pour les mĂ©dias S3) pour cibler le bon backend, indĂ©pendamment du `STORAGE_DRIVER` courant.
-- **Fix â correction d'adresse jamais appliquĂ©e au checkout (`CheckAddress`)** : le mĂ©canisme de correction d'adresse (table `adresse_correction`, gĂ©rĂ©e par l'admin/cabine) dĂ©tectait bien une adresse connue pour ĂȘtre mal formĂ©e, mais le checkout Ă©tait systĂ©matiquement abandonnĂ© au lieu de proposer la correction de façon exploitable â le contrat de rĂ©ponse (`corrected_address`) n'Ă©tait lu nulle part cĂŽtĂ© client (mobile : parsing d'un format de message d'erreur obsolĂšte ; web : aucune gestion de ce cas). Mobile et web lisent dĂ©sormais directement `corrected_address` et proposent au client de reprendre le checkout avec l'adresse corrigĂ©e.
-- **Fix â matching de correction d'adresse trop strict** : `CheckAddress` ne matchait qu'une Ă©galitĂ© exacte de texte. Ajout d'un fallback normalisĂ© (accents/casse/espaces ignorĂ©s, rĂ©utilise `utils.NormalizeAddress` dĂ©jĂ utilisĂ©e par le service de gĂ©ocodage) pour rattraper les variantes mineures de saisie.
-
-### v5.6.0 â 2026-07-11
-
-- **Fix â ETA introuvable pour l'annulation tardive (`CheckCommandETAExistsAndValid`)** : la fonction lisait la clĂ© Redis `command:eta:{id}` (un *hash*) avec `Redis.Get` (string), ce qui provoquait systĂ©matiquement une erreur `WRONGTYPE` silencieuse. Une ETA valide n'Ă©tait donc jamais dĂ©tectĂ©e par ce chemin, et un client pouvait annuler sans pĂ©nalitĂ© juste aprĂšs l'assignation d'un livreur (avant le passage au statut `en_route`). CorrigĂ© en `Redis.HGetAll`.
-- **Fix â position livreur introuvable (`GetDeliverymanLocationForCommand`)** : mĂȘme bug `WRONGTYPE` (`Redis.Get` sur un hash) empĂȘchant l'affichage de la position temps rĂ©el sur certains suivis de commande. CorrigĂ© en `Redis.HGetAll`.
-- **Fix â ETA absente des notifications/app mobile/site web** : trois fonctions qui Ă©crivent l'ETA dans Redis utilisaient des noms de champ incohĂ©rents (`eta_minutes` vs `total_eta_minutes`) alors que les clients ne lisent que `eta_minutes`. Les trois writers Ă©crivent dĂ©sormais les deux champs de façon cohĂ©rente.
-- **Fix â boucle infinie de gĂ©ocodage (`ResolveAddress` â `GeocodeAddress`)** : la correction d'adresse mal Ă©crite et le gĂ©ocodage se rappelaient mutuellement sans condition de sortie pour toute adresse Ă©chouant au gĂ©ocodage direct (le cas d'usage mĂȘme de la correction), provoquant un blocage. `ResolveAddress` appelle dĂ©sormais directement le cache/Nominatim sans repasser par `GeocodeAddress`.
-- **Fix â rĂ©compenses par points non atomiques** : `ClaimPoolReward` (consommation des points) et `AddRewardsToBasket` (ajout du produit au panier) Ă©taient deux Ă©tapes sĂ©parĂ©es ; un produit rĂ©compense supprimĂ©/introuvable faisait perdre la rĂ©compense au client sans qu'il reçoive rien. FusionnĂ©es dans `ClaimPoolRewardAndAddToBasket`, exĂ©cutĂ©e dans une seule transaction.
-- **Fix â annulation admin non atomique** : `UpdateCommandStatusAdmin` pouvait rembourser deux fois le stock en cas d'appels concurrents. Bascule sur `CancelCommandByAdminAtomic` (transaction + verrou `FOR UPDATE`).
-- **Fix â proratisation du chiffre d'affaires (stats)** : les commandes avec `referral_used` n'Ă©taient pas correctement proratisĂ©es dans les statistiques de revenu.
-- **Notifications â durĂ©e de rĂ©tention rĂ©duite Ă 1h** : les notifications stockĂ©es dans Redis passent d'un TTL de 7 jours Ă 1 heure (cohĂ©rent avec leur usage temps rĂ©el, Ă©vite l'accumulation inutile).
-- **Suppression de code mort supplémentaire** : nettoyage dans `CreateCommand` et `DeleteCommandItem` (rendu atomique).
-- **Tests unitaires** : ajout de suites complÚtes couvrant la gestion de stock (checkout/annulation/items), les statistiques, le géocodage et la correction d'adresses mal écrites (algorithme pur + intégration réseau réelle rate-limitée), les calculs de temps/ETA de commande, les récompenses par points (déduction de stock, atomicité), et l'annulation de commande avec pénalité de retard (barÚme, cumul concurrentiel, détection via statut ou ETA, flux "client absent").
-
-### v5.5.0 â 2026-07-08
-
-- **Fix â amende annulation livreur (`ApplyCancellationPenalty`)** : l'amende appliquĂ©e quand un livreur marque le client absent Ă©crasait le montant existant au lieu de l'additionner, et n'Ă©tait pas protĂ©gĂ©e par un verrou (`FOR UPDATE`). Elle est dĂ©sormais cumulative et transactionnelle, cohĂ©rente avec le chemin d'annulation client (`CancelAtomic`).
-- **Fix â mot de passe loggĂ© en clair** : la modification d'un client par un admin (`PUT /admin/protected/clients/:id`) journalisait le corps de requĂȘte complet, y compris le nouveau mot de passe. Le log ne contient plus de donnĂ©e sensible.
-- **Fix â IDOR consultation d'alerte police** : un livreur pouvait consulter le dĂ©tail de l'alerte d'un autre livreur en devinant l'ID (`GET /api/v1/livreur/alert/:id`). L'accĂšs est dĂ©sormais restreint Ă ses propres alertes ; admin et cabine conservent l'accĂšs complet.
-- **Nettoyage â code mort** : suppression des handlers et fonctions utilitaires non routĂ©s/non appelĂ©s (ancien module `handlers/cabine.go`, `RegisterClient`, `GetCurrentClient`, `GetCurrentAdmin`, `GetMyCompletedOrders`, `GetRealtimeStats`, `StartPaymentChecker`, et helpers internes associĂ©s), identifiĂ©s via `staticcheck` et `deadcode`.
-
-### v5.4.0 â 2026-05-18
-
-- **Rotation automatique des clés TomTom** : jusqu'à 3 clés configurables (`TOMTOM_API_KEY_1/2/3`). En cas de quota dépassé (403/429), le systÚme passe à la clé suivante automatiquement sans interruption. Fallback Haversine si toutes les clés sont épuisées.
-- **SĂ©curitĂ© â crĂ©ation d'utilisateurs** : seul un `admin` peut crĂ©er des comptes `livreur` ou `cabine` via l'API. La crĂ©ation de compte `admin` est entiĂšrement bloquĂ©e via l'application â uniquement possible en base de donnĂ©es directement.
-- **SĂ©curitĂ© â cabine** : le rĂŽle `cabine` n'a plus aucun droit de crĂ©ation d'utilisateurs ou de clients (retirĂ© cĂŽtĂ© backend).
-- **Fix frontend** : `createUserByAdmin` appelait `/admin/auth/register` (inexistant) â corrigĂ© vers `/admin/protected/users`.
-- **WAF ModSecurity logs** : les logs nginx et l'audit log ModSecurity sont désormais montés sur l'hÎte (`/var/log/waf/nginx/` et `/var/log/waf/modsec/`) via volumes Docker stables. La variable `MODSEC_AUDIT_LOG` redirige l'audit log vers un fichier (au lieu de stdout) pour collecte Wazuh.
-- **Notifications Telegram uniquement** : les push notifications Expo (iOS/Android) sont abandonnées. Clients et livreurs reçoivent désormais toutes leurs alertes via Telegram.
-
-### v5.3.0 â 2026-05-15
-
-- **Prix inactifs filtrés cÎté client** : le flag `active_price` sur `PRODUCT_PRICES` permet de désactiver un tarif sans le supprimer. Les endpoints publics/client et les frontends web+mobile masquent automatiquement les prix inactifs. Admin et cabine voient tous les prix.
-- **Désactivation au lieu de suppression** : dans la modal d'édition produit (admin), retirer un prix existant le désactive (`active_price = false`) plutÎt que de le supprimer de la base.
-- **Amende automatique client â livreur annule depuis `arrived`** : quand le livreur marque le client absent (`arrived` â `cancelled`), `ApplyCancellationPenalty` est appelĂ© automatiquement sur le **client** (amende progressive : 20â50â100â150âŹ).
-- **Bouton "Client absent"** : aprÚs 5 minutes au statut `arrived`, l'app livreur affiche un bouton "Client absent" qui déclenche l'annulation avec amende sur le client.
-- **Message d'erreur checkout avec contact** : le message de blocage inclut désormais "Prenez attache avec Milieu Nantais sur signal pour régulariser votre situation."
-- **OTA channels par rÎle** : les canaux Expo OTA sont désormais nommés `pre-prod-client` / `production-client` / `pre-prod-admin` / `production-admin` pour éviter les mises à jour croisées entre builds.
-
-### v5.2.0 â 2026-05-01
-
-- Activation/désactivation des prix par quantité (admin)
-- Gestion de stock améliorée
-- Refactoring handlers produits
-
----
-
-**Documentation mise Ă jour le :** 2026-07-11
-**Version API :** 5.6.0
+**Documentation mise Ă jour le :** 2026-05-01
+**Version API :** 5.2.0
**Technologies :** Go 1.24, Gin, PostgreSQL 16, Redis 7, React 19, Expo 54, TomTom API, ModSecurity WAF
**Déploiement :** Docker Compose · Nginx + ModSecurity OWASP CRS · TLS 1.2/1.3
-**Base URL prod :** `https://mln-uber.club`
-**Infrastructure :** WireGuard VPN · Wazuh SIEM · Dozzle · Beszel · ClamAV · MinIO S3
+**Base URL prod :** `https://mln-uber.club`