Aller au contenu principal

Erreurs et gestion

La Cafête utilise un format d'erreur standardisé pour toutes les réponses d'erreur.

Format de réponse d'erreur​

{
"error_code": "CARD_NOT_FOUND",
"message": "Carte introuvable"
}

L'énumération DomainError utilise #[serde(tag = "error_code", content = "message")] qui produit une réponse plate avec deux champs : error_code (le nom du variant) et message (le contenu textuel). Un champ optionnel request_id peut être ajouté pour le tracing.

DomainError — Variants​

VariantHTTPUsage
Validation422Données invalides, règle métier non respectée
NotFound404Ressource introuvable
Conflict409Conflit de données (doublon, idempotence, etc.)
InsufficientBalance422Solde insuffisant pour le débit demandé
CardNotActive422Carte non active (désactivée, perdue)
Forbidden403Permissions insuffisantes
Unauthorized401Authentification requise ou invalide
RoleNotAllowed403Le rôle de l'utilisateur n'est pas autorisé
Persistence500Erreur base de données
ExternalService502Erreur fournisseur externe (SendGrid, S3, etc.)
Configuration500Configuration manquante ou invalide
Internal500Erreur interne inattendue

Codes d'erreur détaillés (ErrorCode)​

Les handlers API utilisent l'énumération ErrorCode qui fournit des codes machine plus précis :

Authentification / Authorization​

CodeHTTPSignification
AUTH_INVALID_CREDENTIALS401Email ou mot de passe incorrect
AUTH_TOKEN_EXPIRED401Session expirée
AUTH_TOKEN_INVALID401Token malformé
AUTH_PASSWORD_CHANGE_REQUIRED403Changement de mot de passe requis
AUTH_ACCOUNT_DISABLED403Compte désactivé
AUTH_MISSING_TENANT400En-tête X-Tenant-Id manquant
AUTH_OTP_REQUIRED400Code OTP requis
AUTH_OTP_INVALID422Code OTP invalide

Cartes​

CodeHTTPSignification
CARD_NOT_FOUND404Carte introuvable
CARD_NOT_ACTIVE422Carte non active
CARD_LOST422Carte signalée perdue
CARD_ALREADY_ASSIGNED409Carte déjà attribuée
CARD_NO_HOLDER422Carte sans titulaire
CARD_BALANCE_INSUFFICIENT422Solde insuffisant
CARD_DAILY_LIMIT_REACHED422Plafond quotidien atteint
CARD_CODE_GENERATION_FAILED422Échec génération code

Produits / Stock​

CodeHTTPSignification
PRODUCT_NOT_FOUND404Produit introuvable
PRODUCT_INACTIVE422Produit désactivé
PRODUCT_STOCK_INSUFFICIENT422Stock insuffisant
PRODUCT_UNAVAILABLE_DAY422Produit non disponible ce jour
STOCK_NEGATIVE_NOT_ALLOWED422Stock négatif non autorisé
STOCK_TRANSFER_INSUFFICIENT422Stock insuffisant pour transfert
CodeHTTPSignification
MENU_NOT_FOUND404Menu introuvable
MENU_ALREADY_EXISTS409Menu déjà existant
MENU_DATE_MISMATCH422Incohérence de date
MENU_EMPTY422Menu vide
MENU_PRODUCT_NOT_IN_MENU422Produit pas dans le menu

Réservations​

CodeHTTPSignification
RESERVATION_CUTOFF_PASSED422Délai de réservation dépassé
RESERVATION_TOO_FAR422Date trop lointaine
RESERVATION_PERIOD_TOO_LONG422Période trop longue
RESERVATION_EMPTY422Réservation vide
RESERVATION_DAYS_EMPTY422Aucun jour sélectionné
RESERVATION_MENU_NOT_FOUND422Menu de réservation introuvable

Caisses​

CodeHTTPSignification
REGISTER_ALREADY_OPEN422Caisse déjà ouverte
REGISTER_NOT_FOUND404Caisse introuvable
REGISTER_NOT_OPEN422Caisse non ouverte

Transactions​

CodeHTTPSignification
TRANSACTION_NOT_REFUNDABLE422Transaction non remboursable
TRANSACTION_IDEMPOTENCY_CONFLICT422Conflit de clé d'idempotence

Organisations​

CodeHTTPSignification
ORG_NOT_FOUND404Organisation introuvable
ORG_SLUG_TAKEN409Slug déjà utilisé

Statistiques​

CodeHTTPSignification
STATS_DATE_RANGE_INVALID422Plage de dates invalide

Codes génériques​

CodeHTTPSignification
NOT_FOUND404Ressource introuvable
UNAUTHORIZED401Authentification requise
FORBIDDEN403Permission refusée
VALIDATION_ERROR422Données invalides
CONFLICT409Conflit
INTERNAL_ERROR500Erreur interne
EXTERNAL_SERVICE_ERROR502Erreur fournisseur externe
CONFIGURATION_ERROR500Erreur de configuration
ROLE_NOT_ALLOWED403Rôle non autorisé

Erreurs PostgreSQL​

Codes d'erreur customs (PG → Rust)​

Les procédures stockées PL/pgSQL (fn_apply_card_transaction) lèvent des codes d'erreur personnalisés interceptés par la couche PersistenceError :

Code PGMappingSignification
CRD01PersistenceError::NotFoundCardNotFound — Carte introuvable
CRD02PersistenceError::ConflictCardNotActive — Carte non active
CRD03PersistenceError::ConflictInsufficientBalance — Solde insuffisant
23505PersistenceError::ConflictUNIQUE_VIOLATION — Doublon sur clé unique

Les violations de contraintes PG sont interceptées par le handler SQLx et converties en erreurs applicatives.

Gestion côté client​

Retry conditionnel​

HTTPRetry ?Stratégie
500OuiExponential backoff (1s, 2s, 4s, 8s, max 30s)
502OuiExponential backoff (1s, 2s, 4s, 8s, max 30s)
429OuiRespecter Retry-After header
413NonRéduire la taille du fichier
400NonCorriger la requête
401NonRafraîchir le token
403NonVérifier les permissions
404NonVérifier l'identifiant de la ressource
409NonVérifier les données avant resubmit
415NonUtiliser un type de fichier supporté
422NonCorriger la requête

Idempotence​

Pour les opérations financières, utilisez toujours un Idempotency-Key :

POST /api/v1/transactions/recharge
Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Content-Type: application/json
Authorization: Bearer ...

{
"card_id": "550e8400-e29b-41d4-a716-446655440000",
"amount_cents": 5000,
"method": "cash",
"site_id": "uuid"
}

Si vous recevez une erreur 5xx, vous pouvez réessayer avec la même clé d'idempotence — le système garantit que la transaction ne sera pas appliquée deux fois.

attention

Une clé d'idempotence différente sur la même opération entraînera un IDEMPOTENCY_CONFLICT (409).

Rate Limiting​

Le rate limiting est appliqué sur les endpoints d'authentification :

EndpointLimiteFenêtre
POST /auth/login5 req1 minute
POST /auth/cardholder-login3 req1 minute
POST /auth/resolve-code10 req1 minute
POST /auth/refresh30 req1 minute

En cas de dépassement : 429 Too Many Requests avec header Retry-After.

Logs et debugging​

Les erreurs sont tracées avec tracing :

tracing::error!(error = %e, card_id = %card_id, "Transaction failed");
tracing::warn!(org_id = %org_id, "Rate limit approaching");
tracing::info!(user_id = %user_id, action = "login", "User logged in");

Pour activer les logs détaillés en développement :

RUST_LOG=debug cargo run -p caffette-api