Aller au contenu principal
fellwin
Banque · Fintech2026 · Première tranche livrée · construction continue · Concepteur · développeur

Opérateur fintech français

Une plateforme bancaire qui peut changer de fournisseur sans tout reconstruire.

  • 6

    contextes bornés livrés

  • 5

    niveaux de permissions granulaires

  • 4 mois

    Première tranche livrée

En bref

Le problème
Le marché européen du BaaS bouge vite, et une plateforme dont le code métier est soudé à un seul fournisseur d'infrastructure bancaire se condamne à un coût de migration prohibitif le jour où ce fournisseur change.
La décision
Le métier bancaire est exprimé en termes propres à la plateforme et le fournisseur en place n'est joignable qu'à travers un adaptateur, ce qui isole physiquement la dépendance dans une seule couche.
Le résultat
La première tranche est livrée, avec un audit de sécurité mené tranche par tranche, et le modèle d'adaptateur est validé sur la production de comptes et les virements.

Le contexte

La plateforme est un BaaS (Banking-as-a-Service) pour les PME et freelances français, construit pour un opérateur du secteur.

L'offre donne à chaque client un compte bancaire complet, pilotable depuis une API ou une interface, sans qu'il ait à connaître le fournisseur d'infrastructure bancaire sous-jacent.

L'offre consiste à donner à chaque client un compte bancaire complet (multi-soldes, paiements SEPA, émission de cartes), pilotable depuis une API ou une interface, sans que l'utilisateur final ait à connaître le fournisseur d'infrastructure bancaire sous-jacent, ni à en dépendre.

L'enjeu de départ n'était pas de « construire une banque », mais de construire une plateforme capable de survivre à un changement de fournisseur d'infrastructure.

Le marché européen du BaaS évolue rapidement (rachats, fusions, changements de modèle économique côté fournisseur). Un système qui couple directement le code métier à un fournisseur unique se condamne à un coût de migration prohibitif quand ce fournisseur change.

Nous l'avons construite comme une plateforme hexagonale : six contextes bornés (Identité, Compte, Virement, Carte, Facturation, Noyau partagé) qui exposent chacun leurs ports métiers, avec une adaptation par fournisseur côté infrastructure. Le fournisseur en place est intégré par un adaptateur dédié ; un autre fournisseur pourrait s'enficher avec une à deux semaines d'implémentation d'adaptateurs, sans toucher au code métier.

Les décisions d'architecture

Le code métier parle de comptes, de virements et de cartes, jamais du fournisseur : celui en place est intégré par un adaptateur, isolé dans une seule couche.

Architecture hexagonale avec adaptateur par fournisseur bancaire, pas Intégration directe du fournisseur dans le code métier. Le métier bancaire (compte, virement, carte, facturation) est exprimé en termes propres à la plateforme, jamais en termes du fournisseur. Un port `AccountProvider` déclare ce que le métier attend ; un adaptateur l'implémente pour le fournisseur en place. Le métier ne sait pas à qui il parle : il pourrait parler à n'importe quel BaaS capable de fournir les mêmes opérations. La condition de réussite : qu'un changement de fournisseur se règle en une semaine d'écriture d'adaptateurs, et non en un mois de refonte.

Trade-off assumé : Coût de l'approche port-and-adapter payé d'avance : six contextes × N ports chacun. Plus de code à écrire au démarrage que dans une intégration directe. Bénéfice : le code métier reste lisible en termes du domaine, sans pollution par les particularités de l'API du fournisseur, et la dépendance fournisseur est physiquement isolée à une seule couche.

Le domaine est découpé en six contextes bornés qui ne partagent ni schéma ni transaction, et les événements qui circulent entre eux survivent à une panne grâce à un outbox transactionnel.

Six contextes bornés DDD avec outbox transactionnel pour la cohérence éventuelle, pas Monolithe avec base de données unique et écritures cross-domaine en transactions. Le domaine bancaire a des frontières naturelles de cohérence : l'état d'un compte, le cycle de vie d'un virement ou d'une carte ne partagent pas les mêmes invariants. Modéliser explicitement chaque contexte comme un sous-système permet (a) de faire évoluer chaque partie indépendamment, (b) de migrer plus tard vers une architecture microservices sans refonte, et (c) de garantir que les événements inter-contextes survivent à un crash via un outbox transactionnel.

Trade-off assumé : Six schémas à migrer indépendamment, jamais de JOIN cross-contexte. Les lectures inter-contextes passent par des ports déclarés (par exemple, le contexte Compte regarde l'utilisateur via un port AccountHolderLookup, jamais via une FK). Coût de discipline à l'écriture, gain de flexibilité à l'évolution.

Les droits sont accordés capacité par capacité à chaque membre de l'entreprise cliente, plutôt que par un rôle global qui en donne un paquet d'un coup.

Modèle de permissions explicite à cinq niveaux, granulaire par membre, pas Rôles globaux (admin / membre / lecteur) avec privilèges implicites. Une PME ne fonctionne pas avec un rôle unique : le fondateur peut tout faire, le DAF n'a pas les mêmes besoins que le comptable, qui n'a pas ceux du commercial. Chaque membre se voit accorder exactement les capacités dont il a besoin, indépendantes les unes des autres, plutôt qu'un rôle global qui en donne un paquet. Ajouter une capacité est une migration, non une refonte du système de rôles.

Trade-off assumé : Plus de granularité à maintenir, pas de raccourci « rôle administrateur » qui donne tout d'un coup. En contrepartie, la matrice de permissions est explicite, auditable et fine à l'usage : exactement ce qu'attend un client professionnel qui doit prouver à son service conformité qui peut faire quoi.

L'exécution

La plateforme tourne en Go sur PostgreSQL, et rien ne traverse une frontière de contexte sans passer par un port déclaré.

Chaque contexte borné a ses propres migrations et ne lit jamais dans le schéma d'un autre ; les événements qui circulent entre eux passent par un outbox transactionnel.

Chaque contexte borné a son propre schéma de base, ses propres migrations versionnées (vingt-et-une migrations à ce jour), et ne lit jamais directement dans le schéma d'un autre : les frontières passent par les ports métiers déclarés. L'identité est gérée par Keycloak en OIDC ; les événements inter-contextes transitent par un outbox transactionnel qui garantit la cohérence éventuelle même en cas de crash de consommateur.

Le développement avance par tranches verticales, et une tranche n'est pas livrée tant que l'audit de sécurité mené en parallèle n'est pas soldé.

Le développement progresse par tranches verticales : chaque tranche livre un sous-ensemble fonctionnel complet (identité + compte + virement, puis carte, puis facturation), avec un audit OWASP mené en parallèle. Cent-cinquante-trois commits en quatre mois ; la cadence est volontaire, la qualité de revue aussi.

57 scénarios automatisésUne collection de tests versionnée rejoue le parcours utilisateur de bout en bout avant chaque tranche, de l'ouverture du compte à la demande de carte.

L'infrastructure de développement tourne en Docker Compose : base de données, serveur d'identité, bus d'événements, serveur de messagerie de test. Une collection Postman versionnée couvre cinquante-sept scénarios automatisés qui jouent le parcours utilisateur de bout en bout : création de compte, ajout de membre, configuration de permissions, émission de virement, demande de carte. C'est le test de non-régression qui s'exécute avant chaque tranche.

Les leçons

Leçon 1Un audit de sécurité mené à chaque tranche coûte moins cher qu'un incident en production, parce qu'il remonte des écarts que ni la relecture de code ni les tests fonctionnels n'attrapent.

La première leçon porte sur le rythme de l'audit de sécurité. Nous tenons un audit OWASP en parallèle de chaque tranche de développement, et non à la fin du projet : une tranche n'est pas livrée tant que ses écarts ne sont pas corrigés. Ce n'est pas une formalité de conformité. La revue systématique remonte des écarts que ni la relecture de code ni les tests fonctionnels n'attrapent, parce qu'ils ne relèvent pas d'un défaut de logique métier mais de ce qu'un système laisse deviner à un observateur extérieur. La leçon plus large : la conformité technique d'une implémentation ne préempte pas sa sécurité, et un audit mené tranche par tranche coûte moins cher qu'un incident en production.

Leçon 2En banque, un plafond annoncé au client n'est pas une règle de validation mais un invariant : il doit être vérifié de manière atomique avec l'opération qu'il borne.

La seconde leçon porte sur les contraintes métier sous concurrence. En banque, un plafond annoncé au client n'est pas une règle de validation : c'est un invariant. Il doit être vérifié de manière atomique avec l'opération qu'il borne, ni avant, ni après, faute de quoi deux opérations simultanées le franchissent ensemble alors que chacune le respecte prise isolément. Nous traitons donc toute contrainte de ce type comme une section critique explicite, et non comme un contrôle préalable. La règle que nous en avons tirée : sur du code financier, tout contrôle qui précède une écriture doit être sérialisé avec elle.

En construction aujourd'hui

La première tranche est livrée : les six contextes bornés sont fonctionnels, le modèle d'adaptateur fournisseur est validé sur les opérations de production de comptes et de virements, la collection Postman couvre cinquante-sept scénarios automatisés. Les tranches suivantes étendent le périmètre fonctionnel au même rythme d'audit.

À horizon douze mois, le test ultime de la promesse architecturale sera la capacité à absorber un changement de fournisseur bancaire en une à deux semaines de travail : sans toucher au code métier, sans rejouer la conformité, sans interrompre le service. C'est ce que la couche d'abstraction est construite pour rendre possible.

Un système à concevoir, déployer ou reprendre en main ?

Avec ou sans cahier des charges : décrivez votre situation, nous répondons par écrit sous 48 h ouvrées.

Réservez un diagnostic