Modèle de domaine
Le domaine est le vocabulaire du système. Quatre concepts suffisent : Session, Leg, Money,
Id. Tout le reste s’y rattache. Le code vit dans api/src/domain/.
PaymentSession — l’agrégat central
Section intitulée « PaymentSession — l’agrégat central »Une PaymentSession représente un paiement en cours pour une commande. C’est l’agrégat racine :
elle possède ses legs et garantit ses invariants. api/src/domain/session/session.ts.
Champs principaux :
| Champ | Type | Sens |
|---|---|---|
id |
SessionId |
Identifiant unique |
merchantId |
MerchantId |
Le marchand propriétaire |
reference |
string |
Référence commande côté marchand (sert à l’idempotence) |
totalAmount |
Money |
Montant à couvrir |
status |
SessionStatus |
État courant (voir Machines à états) |
legs |
PaymentLeg[] |
Les moyens de paiement attachés |
expiresAt |
Date |
Expiration de la session |
metadata |
objet | Données libres du marchand |
Méthodes clés (les transitions sont des méthodes, pas une lib externe) :
static create(input)— fabrique avec validation (statut initial, expiration).static fromSnapshot(snapshot)— reconstruit depuis la base.addGiftLeg(leg, now)/setPspLeg(leg, now)/removeLeg(legId, now)— gèrent les legs.submit(now)— passe la session en traitement (voir invariant ci-dessous).markCompleted(now)/startRollback(now)— transitions terminales / compensation.recomputeStatusFromLegs(now)— recalcule le statut à partir de l’état des legs.snapshot()— sérialise pour persistance.
PaymentLeg — une jambe de paiement
Section intitulée « PaymentLeg — une jambe de paiement »Une PaymentLeg est un instrument au sein de la session. api/src/domain/session/leg.ts. Deux types :
gift_card— une carte cadeau (token, 4 derniers chiffres, émetteur, solde avant/après, CVV chiffré si présent,transactionId).psp— un paiement carte via PSP (méthode de paiement,authIddu PSP,requiresActionpour le 3DS,actionUrlde redirection).
Champs communs : id, sessionId, type, amount (Money), status (voir machines à états),
providerType (titreo, stripe, adyen…), providerRef, errorCode/errorMessage, et des
timestamps de transition (capturedAt, releasedAt, refundedAt…).
Fabriques et transitions (extrait) :
PaymentLeg.createGift(input) / PaymentLeg.createPsp(input)leg.markGiftDebited(txnId, providerRef, balanceBefore, balanceAfter, now)leg.markGiftDebitFailed(errorCode, errorMessage, now)leg.markPspHeld(authId, providerRef, now)leg.markPspRequiresAction(authId, providerRef, actionUrl, now)leg.markPspCaptured(now)leg.markPspHoldFailed(errorCode, errorMessage, now)Chaque mark… encode une transition légale de la machine à états du leg : appeler une transition
interdite lève une erreur de domaine.
Money — montants sûrs
Section intitulée « Money — montants sûrs »api/src/domain/shared/money.ts. Un value object { amount, currency } avec arithmétique
(add, subtract, isZero, isPositive).
Id — identifiants typés (branded types)
Section intitulée « Id — identifiants typés (branded types) »api/src/domain/shared/id.ts. Plutôt que de manipuler des string interchangeables, le domaine
utilise des types « brandés » : SessionId, LegId, MerchantId, etc. Le compilateur empêche
ainsi de passer un MerchantId là où on attend un SessionId, même si ce sont des chaînes à l’exécution.
Erreurs de domaine
Section intitulée « Erreurs de domaine »api/src/domain/shared/errors.ts définit une hiérarchie typée :
DomainError (code machine stable)├── ValidationError (VALIDATION_ERROR)├── InvalidStateTransition (INVALID_STATE_TRANSITION)└── CurrencyMismatch (CURRENCY_MISMATCH)Et api/src/domain/shared/error-catalog.ts catalogue les codes d’erreur normalisés
(INSUFFICIENT_FUNDS, MERCHANT_PSP_NOT_CONFIGURED, …) et indique lesquels sont retriables.
Au-delà de la session
Section intitulée « Au-delà de la session »Le domaine contient aussi : merchant/branding.ts (thème marchand), auth/scope.ts + auth/user.ts
(permissions et utilisateurs), bootstrap/manifest.ts (logique du manifest signé). Ils sont détaillés
sur Couche Domain.
Source de vérité métier complémentaire :
doc/site/content/domain-model.mdx.