Aller au contenu
My Amana · ReportingÉdition du 19 septembre 2026

Technique · Manager technique

Vue du manager technique

L’API est rapide ; c’est sa forme qui coûte. Aucune rupture de contrat sur ce que l’application consomme, mais 16 problèmes bloquants sur 59 relevés, et une documentation qui ne décrit pas le comportement réel.

Chemins de la spécification consommés

61 à 62

sur 94

Opérations sans champ requis déclaré

41 sur 107 (38 %)

alors que l’API valide strictement

Problèmes bloquants relevés

16

sur 59 problèmes, 11 groupes de workflows

Rupture de contrat sur un endpoint consommé

0 rupture

contrôle automatisé à chaque mise à jour

État de l’API

Les faits mesurés, puis les problèmes par workflow : rouge bloquant, orange majeur, jaune moyen.

Mesures

Spécification en ligne
OpenAPI 3.0.1, v4 : 94 chemins, 107 opérations, 165 schémas
Chemins réellement consommés par l'application
61 à 62 (67 fonctions HTTP : 33 GET, 27 POST, 3 PUT, 2 PATCH, 2 DELETE)
Chemins consommés absents de la spécification
0 (la surface est déclarée)
Opérations dont le corps de requête déclare required: []
41 sur 107 (38 %) alors que l'API valide strictement
Opérations déclarant un 400
13 seulement ; les refus de saisie sortent en 500
Réponses déclarées */*
9 (dont un devis qui renvoie du JSON et quatre endpoints photo qui renvoient du binaire)
Enveloppes d'erreur distinctes observées
5, avec trois formats d'horodatage
Formats de dates coexistants
5, dont un compact AAAAMMJJ propre à un seul endpoint
Enveloppes de pagination
2 (page Spring complète / page réduite), base d'index non uniforme (0 ou 1 selon l'endpoint)
Latence mesurée
Devis 31 à 94 ms, connexion 277 ms : l'API est rapide, c'est sa forme qui coûte
Contrôle de dérive du contrat sur les endpoints consommés
0 rupture
Coût côté application de l'écart API ↔ besoins
Client HTTP écrit à la main (1 968 lignes, le générateur de code n'a jamais pu être exécuté) + couche d'anti-corruption de 4 051 lignes d'adaptateurs et 2 762 lignes de tests, soit environ 66 lignes de traduction par endpoint

Problèmes par workflow

Légende : 🔴 bloquant · 🟠 majeur · 🟡 moyen · ⚪ mineur. Les références renvoient aux tickets de la Partie 3.

Problèmes relevés, par groupe de workflows et par sévéritécliquer une cellule filtre le tableau ci-dessous
Nombre de problèmes par groupe et par sévérité
GroupeBloquantMajeurMoyenMineurTotal
Authentification
Accueil
Dashboard
Compte
Menu
Souscription
Paiement
Contrats
Sinistres
Remboursements
Santé Individuelle · Santé Famille · Santé Groupe
Total (+ 6 transverses)161725159
59 problèmes
Analyse des problèmes techniques identifiés, par workflow
SévéritéEndpointProblème observéRéf.
Authentification
BloquantPOST /auth/refreshRépond 500 avec un jeton de rafraîchissement valide ; le nom de champ est confirmé correct par les 400 obtenus avec d'autres noms. Le jeton d'accès vit 30 minutes : toute session au-delà est détruite et la connexion par empreinte échoue de la même manière. Seul cas de l'audit où la spécification est juste et l'implémentation casséeÀ créerA9#1(ticket dans l’outil de ticketing, nouvelle fenêtre)
BloquantPOST /auth/otp/validateSeul l'OTP e-mail est contrôlé ; l'OTP téléphone est envoyé, collecté et jamais vérifiéP0-D#2(ticket dans l’outil de ticketing, nouvelle fenêtre)
BloquantPOST /auth/mfa/sendSéquence du diagramme backend rejouée sur le compte de recette demo@shiftin-demo.com (boîte relevée) : aucun code n'arrive après le 420, et /auth/mfa/send répond 200 « RESENDING WITH SUCCESS » pour EMAIL, email, MAIL, avec username et même à corps vide, sans qu'aucun e-mail ne soit délivré (INBOX, Junk et spam vérifiés, sur une adresse qui reçoit bien l'OTP de /auth/otp). Aucun compte ne peut franchir le défi MFA par e-mailA22#16(ticket dans l’outil de ticketing, nouvelle fenêtre)
BloquantPOST /auth/otp/validateL'OTP n'est pas à usage unique : le même code validé 3 fois en 8 minutes, un nouveau jeton UPDATE_PASSWORD émis à chaque fois ; un code vide expose une SQLGrammarException Hibernate dans le messageA19#66(ticket dans l’outil de ticketing, nouvelle fenêtre)A21#68(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /auth/otpRépond 404 « User Not found » pour toute adresse non encore inscrite et pour tout numéro de téléphone : aucun OTP possible avant POST /users ; répond 409 « Code generated déja » pendant les 15 minutes de validité du code précédent (aucun renvoi possible)A17#64(ticket dans l’outil de ticketing, nouvelle fenêtre)A20#67(ticket dans l’outil de ticketing, nouvelle fenêtre)A23#69(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /users puis POST /auth/loginLa politique de mot de passe n'est pas appliquée à la création : un mot de passe accepté par POST /users est refusé en 419 CHANGE_PASSWORD à la première connexion (branche « mot de passe invalide » du diagramme backend, vérifiée : un second compte au mot de passe conforme reçoit directement le défi MFA)A18#65(ticket dans l’outil de ticketing, nouvelle fenêtre)
MineurPOST /auth/otp/validateLe jeton est renvoyé avec le préfixe Bearer dans la valeur ; e-mail émis par notification_sinistre@amana.dz avec la coquille « Changemenet »A24#70(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /auth/loginCodes 419 (changement de mot de passe imposé) et 420 (MFA) hors RFC ; le jeton porteur du défi arrive sans champ status ; la connexion est rejetée si un JWT périmé est attachéP2.2#30(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenPATCH /auth/password · GET /auth/password-policyL'endpoint de politique répond désormais (anonyme, quatre règles en français : 8 caractères, complexité avec @ # ! ? $ £, pas d'informations personnelles, différent des 5 derniers). Il reste absent de la spécification et non structuré (phrases libres, classées par mots-clés côté application) ; le refus 419 ne nomme toujours pas la règle violéerésolu, documentation à compléterP3.7
MajeurJWT clientLe jeton d'un simple assuré porte 19 rôles, dont des périmètres de back-office ; au moins un est inerte sur cette passerelle (affichage-swagger403). Pas d'élévation prouvée, mais un jeton qui n'est pas au moindre privilègeÀ créer
MajeurPOST /usersLe contrat documenté répondait 500 ; l'opération réelle est newUser. Le CIN collecté à l'inscription n'a aucune destination dans le contrat et est perduQuestion Q9 bis
MoyenPOST /auth/attachContrat non confirmé (corps LoginRequest sous session porteuse ?), déclencheur inconnu (checkuser, altern_users ?), cas d'échec et idempotence non documentés : 9 questions transmises, sans réponseQuestionsQ1-Q9#71(ticket dans l’outil de ticketing, nouvelle fenêtre)
Accueil
MajeurGET /notifications/unread-count404 : une page de 50 notifications est chargée dans 4 écrans uniquement pour compter les non-lusP3.2#43(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /produits · GET /tarifsAucun prix minimum sur la liste des produits : un appel /tarifs par produit, soit un N+1 imposé à l'accueil ; /tarifs sans codeProduit répond 200 [] au lieu de 400P3.9#44(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /produits/{id}/detailCharge la plus riche de l'API, sans aucun schéma dans la spécification ; prix pré-formaté en chaîne, décisions de présentation (isBest, recommandee) prises côté serveurP2.7#40(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenIncident de pré-productionUne panne de GET /produits a bloqué l'accueil entier pendant une trentaine de minutes (22 endpoints en régression, résolution spontanée sans cause identifiée)
Dashboard
MoyenGET /contrats · /refunds · /claimsDeux enveloppes de pagination ; base d'index 0 pour /contrats, 1 pour /refunds et /claims, qui répondent 500 sans page ; la spécification documente encore l'enveloppe retirée de /refunds et /claimsP2.4#33(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /contratsAucun numéro de police ; ordre de tri et politique d'exclusion non confirmés ; limitation à 1 000 élémentsP3.15#46(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /refunds/{id}Renvoie le même objet plat que la liste, sans enrichissement
Compte
BloquantPUT /membersRemplacement d'enregistrement complet et non mise à jour partielle ; bloc questionnaire nommé questionnaire et non bonneSanteQuestion ; réponses en chaînes « Oui »/« Non » et non en booléens ; validation (téléphone 10 chiffres, code postal 5 chiffres, ville, date d'entrée en service) documentée nulle partP0-F#18(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPUT /beneficiaries/updateTauxTotal des parts imposé à 100 %, non documenté ; le compte de test porte 10 % + 19 %, donc aucune répartition ne peut y être enregistréeP1-F#26(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /beneficiariesSeule la date compacte AAAAMMJJ est acceptée (JJ/MM/AAAA400, formes ISO → 422) alors que la lecture renvoie JJ/MM/AAAA ; énumérations LienParenteEnum (Conjoint, Enfant, Ascendant) et SexeEnum fermées et non publiéesP2.13#32(ticket dans l’outil de ticketing, nouvelle fenêtre)P1-G#27(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurDELETE /ayantDroits/{id}/demandeSuppressionCorps multipart déclaré sans aucun champ ; 500 sur identifiant inconnu ; aucun état de demande exposé ensuiteP3.19#47(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /auth/meDTO plat de 5 champs déclaré, réponse de 18 champs et 4 objets imbriqués ; nom/prenom vides à la racine ; un compte de test n'expose ni personneId ni bloc souscripteur alors que /auth/login les renvoieP2.1#31(ticket dans l’outil de ticketing, nouvelle fenêtre)P1-J#25(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /users/photoBinaire image/png exigeant l'en-tête Authorization : impossible à donner à un composant image, converti en data: URI côté application
Menu
BloquantGET /documents500 pour tout souscripteur non adhérent santé (route interne bulletinV2DocumentUtil/{adherentId}) sur un catalogue de textes réglementaires publics ; le champ fichier est un chemin de fichier serveur ; GET /assets?path= répond 404P0-L#3(ticket dans l’outil de ticketing, nouvelle fenêtre)P0-H#4(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /a-propos-amana/sos · /documents · /actes/groupsaccept-language ignoré : contenu en français dans l'application arabe ; /sos mêle une ligne de prose à une liste de numérosP3.16#49(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenPOST /nousContacter500 « Required part 'nom' is not present » sur champ manquant (attendu 400) ; champs multipart non déclarés ; enveloppe de réponse propre à cet endpointP2.6#37(ticket dans l’outil de ticketing, nouvelle fenêtre)P2.10#42(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /garanties/{codeProduit}Valeurs par formule là où le modèle attend une valeur unique ; la fiche produit Santé renvoie guarantees: [] et force le repliP3.6#48(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /a-propos-amana/actualitesPas d'endpoint de détail : le détail réutilise la charge de la liste
Souscription
BloquantPOST /souscriptions/voyageA répondu 201 success: true avec un contratId qui répond ensuite 404 (V8b) ; création en trois appels non transactionnels (/personnes/assure/souscriptions/voyage/personnes/membre-assure), rattacher un membre à un contrat inexistant → 500 (V8c) ; souscripteurId déclaré requis mais ignoré par le serveurP1-A#20(ticket dans l’outil de ticketing, nouvelle fenêtre)P1-B#21(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /simulation-voyageChamps déclarés obligatoires ignorés : age omis → 200 avec un prix plausible mais faux, dateEffet/dateFin non déclarés → 500 (V5) ; dureeJours obligatoire mais sans effet sur le tarif (V9) ; réponse déclarée type: string ; primes négatives renvoyées en succès sur le type Groupe (V12) ; prime Famille plafonnée au 7ᵉ voyageur (V13) ; champ recommandee ajouté sans annonceP1-C#22(ticket dans l’outil de ticketing, nouvelle fenêtre)P1-D#23(ticket dans l’outil de ticketing, nouvelle fenêtre)P1-E#24(ticket dans l’outil de ticketing, nouvelle fenêtre)P3.14#51(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /souscriptions (Scolaire, Accident, Santé)Durée de couverture imposée (Scolaire 364–366 j, Accident 30 j, Santé 365–366 j) découverte par un 409 « Tarifs invalide » ; création Accident en groupe encore en 409 ; le backend recalcule la prime Santé et ignore le montant transmis ; nombreMembres désigne les ayants droit et non les personnes ; réponse de 6 blocs dont 5 sans lecteur ; coupon inconnu → 409 en Santé mais ignoré en silence hors santéà ticketer (Accident groupe)P3.3#50(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurAucune idempotenceUn double appui ou un rejeu réseau crée un second contrat ; aucune compensation (DELETE) sur un contrat non payéÀ créer
MoyenPOST /personnes/assure · GET /professionsprofession en texte libre ; 354 professions non triéesP2.11#34(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenPOST /promoCode/validateAucun code valide en baseP3.3#50(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenMontantsPrimes en flottants à 13 décimales (16164.146341463415), reduction: false alors que les variantes avec et sans réduction diffèrentÀ créer
Paiement
BloquantPOST /modePaiement/CIB (returnUrl)Après le 3-D Secure, la passerelle redirige vers le site vitrine et non vers le lien profond de l'application ; la page de test est au nom d'un marchand tiers ; formUrl: null avec errorCode: 0 a été observéP0-M#5(ticket dans l’outil de ticketing, nouvelle fenêtre)
BloquantGET /modePaiement/confirmPayment/{orderId}valid: false, tous champs nuls, sur un contrat passé à ENCAISSE avec police émiseP0-N#6(ticket dans l’outil de ticketing, nouvelle fenêtre)
BloquantconfirmPayment/livraison/{quittanceId}Endpoint décrit par l'équipe backend, absent de la spécificationP0-C#8(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /modePaiement/DAHABIAFonctionne jusqu'à la page de paiement ; jamais réglé faute de cartes de testCL-DAHABIA
Majeur/modePaiement/*Aucune idempotence sur des écritures d'argent ; nom de champ dépendant du résultat (code_reference / codeReference)À créer
Contrats
MajeurPOST /avenant/resiliationjustificatif en base64 là où tout le reste est multipart ; motifId sans énumération ; 500 sur contrat inconnu divulguant un chemin de service interneP3.17#54(ticket dans l’outil de ticketing, nouvelle fenêtre)P3.18#55(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /contrats/{id}Ni personnes assurées, ni libellé du moyen de paiement, ni valeur par garantie : second appel GET /coverages/{produitId} à chaque ouvertureP3.5#53(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /contrats/{id}/documents404 même avec un identifiant réelP3.4#52(ticket dans l’outil de ticketing, nouvelle fenêtre)
Sinistres
BloquantGET /chat/history · POST /chat/sendAucun paramètre de dossier : un seul fil par client, affiché sous chaque sinistre ; updatedAt déclaré mais absent ; POST /chat/read sans objet sur un fil uniqueP3.12#11(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /claimsA régressé en 500 en cours de sprint puis a été rétabli ; enveloppe migrée sans mise à jour de la spécification
Remboursements
BloquantTous les téléversementsPlafond d'environ 1 Mio par fichier (valeur Spring par défaut) ; dépassement → 500 « Maximum upload size exceeded » sans nom de champ ni limite ; mesuré : 1 024 Kio accepté, 1 200 Kio refuséP0-I#12(ticket dans l’outil de ticketing, nouvelle fenêtre)
BloquantPOST /refundsLe champ de l'acte est passé de type à codeActe sans préavis ; l'ancien nom répond 404 « Acte non trouvé » ; la spécification documente le champ retiré et omet celui qui fonctionne ; champs multipart non déclarésP0-G#19(ticket dans l’outil de ticketing, nouvelle fenêtre)P2.6#37(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /actes/groupsNi catégorie, ni illustration ; codeActe non unique (8 prestations sociales partagent Evenement) : la classification est déduite côté mobileP3.1#56(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /refunds/{id}/documentsRégression 200404 relevée par le contrôle automatisé (endpoint non consommé)P3.11#57(ticket dans l’outil de ticketing, nouvelle fenêtre)
Santé Individuelle · Santé Famille · Santé Groupe
BloquantPOST /members/addPieceJointeAnnoncé prêt par l'équipe backend ; corps multipart déclaré sans aucun champ ; toute requête → 422 « The given data was invalid. » sans nommer de champ ; plus de 25 noms de parties testés ; une seule propriété identifiée (rib) par fuite d'erreurP0-J#13(ticket dans l’outil de ticketing, nouvelle fenêtre)
BloquantPOST /ayantDroits500 nu quels que soient les champs§31#14(ticket dans l’outil de ticketing, nouvelle fenêtre)
BloquantGET /members/bulletinAdhesion500, puis absence de réponse au-delà de 12 s ; l'étape réclamée par le message de succès de la validation d'adhérent est impossibleP3.10#15(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /avenants/{id}/renouvellements/sante/devis409 « problem devis Renouvellement Sante » sur tout payload (6 contrats, 2 types, toutes les variantes)P1-H#28(ticket dans l’outil de ticketing, nouvelle fenêtre)
MajeurPOST /avenants/{id}/adjonctions/sante/devisChamp error typé int alors que le service amont renvoie la chaîne "409 :" : la passerelle plante sur sa propre gestion d'erreur et répond 500P1-I#29(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenPOST /members/validationLe drapeau declare n'est pas lu (false produit le même effet que true)P2.12#38(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenPOST /souscriptions/devis-souscription-santeNe prend pas en compte destination, durée ou âge (n'est pas un devis Voyage) ; montants en flottants non arrondis
MoyenGET /membersPoliceId en PascalCase là où la spécification déclare policeId ; /members/bulletinSoins renvoie un PDF en base64 dans du JSON

Risques

Ce que ces problèmes ont coûté au projet, et ce qui peut encore se produire.

Conséquences

  • Sur les délais : aucun sprint d'intégration API n'a pu s'exécuter sur des endpoints validés ; les endpoints manquants ont été livrés après la fin du sprint qui devait les consommer ; la validation du paiement carte a attendu 51 jours une instance de test exploitable. Le détail chiffré est en section 2.3.
  • Sur les livrables : les 48 workflows sont livrés, mais 9 ne sont pas validables sans correction serveur, et 16 fonctionnent grâce à un contournement côté application qui devra être retiré.
  • Sur les workflows : chaque endpoint a dû être vérifié en conditions réelles avant d'être codé, ce qui est plus lent par construction, et c'est la seule méthode qui a évité de découvrir les défauts en recette ou en production. Codés d'après la documentation, l'enregistrement du profil santé et la déclaration de remboursement auraient échoué à 100 %.
  • Sur la confiance : l'application a dû cesser de croire les réponses de succès du serveur et relire l'état réel après chaque écriture sensible.

Risques et mitigation

Risques techniques associés
RisqueProbabilitéGravitéWorkflow(s)Mitigation
Déconnexion systématique après 30 minutes en usage réel (invisible en développement)Certaine tant que /auth/refresh répond 500BloquantTousCorrection serveur uniquement ; toute ré-authentification silencieuse exigerait de stocker le mot de passe en clair
Un client paie et voit un écran d'échec, ou reste sur le site vitrineCertaine sans correctifBloquantPaiement CIBContournement par relecture du contrat (lent) ; returnUrl à corriger côté passerelle
Un assuré croit avoir déclaré un sinistreCertaineBloquantSinistresRéférentiel produit à exposer
Contrat créé deux fois (double appui, rejeu réseau) ou contrat partiel (coupure au 3ᵉ appel)PossibleMajeurSouscriptionCréation au consentement (pas au clic de paiement) et garde de relecture ; idempotence et atomicité à traiter côté serveur
Trois voyageurs sur dix assurés gratuitementCertaine tant que non tranchéMajeurSouscription VoyageDécision métier A2
Messages d'erreur illisibles en productionCertaineMajeurTousUn en-tête côté serveur
Régression silencieuse à chaque mise à jour backend (renommage sans préavis déjà survenu)ÉlevéeMajeurTousyarn api:contract à exécuter en CI planifiée ; annonce des renommages exigée
Panne d'un endpoint bloquant un écran compositeMoyenneMoyenAccueil, Espace santé, Mon espaceDégradation ciblée livrée sur l'accueil ; en-tête sécurisé sur 53 écrans ; à généraliser
Comptes migrés jamais branchésÉlevée sans réponseMoyenAuthentification – Connexion9 questions transmises ; branchement de quelques lignes une fois le déclencheur connu

Causes des décalages

Des faits datés : la porte de qualité non franchie, les causes racines, le glissement sprint par sprint et le plan d’action.

Cette section est écrite pour être lue avec l'équipe backend. Elle ne met pas en cause sa réactivité : la plupart des correctifs demandés ont été livrés en un à deux jours, et plusieurs points ont été résolus le jour même. Elle établit des faits datés sur ce qui a été livré, quand, et dans quel état, parce que c'est le seul moyen de reconstruire un planning que les deux équipes peuvent tenir.

Le fait générateur : l’API devait être validée avant l’intégration

Le planning du client organise le projet en phases successives. La phase 3, « Tests et validation API », prévoit que Amana envoie les endpoints de chaque sprint et que SHIFTIN les teste et les valide, entre le 15/03/2026 et le 30/04/2026. La phase 4, « Intégration API », ne devait commencer qu'ensuite, le 25/05/2026, sur des endpoints validés. C'est une porte de qualité explicite : aucun sprint d'intégration ne devait démarrer sur des endpoints non validés.

Cette porte n'a pas été franchie. Le planning client lui-même porte les verdicts :

Verdicts de la phase 3 portés au planning client
Lot de la phase 3Envoi des endpoints planifiéValidation planifiéeVerdict porté au planning
Onboarding, authentification, navigation, accueil, dashboard15/03/202618/03/2026✅ Validé
Sinistres hors santé, profil, paramètres, menu23/03/202629–30/03/2026✅ Validé
Paiement, Souscriptions voyage30/03/202601/04/2026🔴 « Paiement : Validé — Voyage : 3 rounds – toujours pas validé ! »
Compte, Sinistres santé (remboursements)06/04/202613/04/2026🔴 « Compte : 3 rounds – toujours pas validé ! — Voyage : 3 rounds – toujours pas validé ! »
Souscriptions scolaire et accident, contrats hors santé, carte Flash13/04/202619–20/04/2026aucun verdict porté
Santé individuelle, famille, groupe20/04/2026 et 26/04/202626/04/2026 et 29–30/04/2026aucun verdict porté

Aucune de ces mentions n'a été levée avant l'été. L'intégration a donc démarré sur des endpoints non validés, puis sur des endpoints inexistants. Ce n'est pas un choix d'organisation : maintenir l'équipe à l'arrêt jusqu'à validation aurait coûté quatre mois de calendrier. Le coût réel de ce contournement est mesurable : c'est la totalité des reprises et des contournements documentés en section 2.2.

Causes racines, par impact décroissant

  1. 1. Des endpoints livrés après la fin du sprint qui devait les consommer.

    Ce n'est pas une question de délai de correction (la plupart des correctifs backend ont été livrés en un à deux jours, ce qui est rapide) mais de séquencement : aucune vélocité d'équipe ne compense un composant absent.

    1. Des endpoints livrés après la fin du sprint qui devait les consommer.
    DépendanceDate planifiéeDate réelleÉcart
    Validation des endpoints Voyage01/04/2026jamais prononcée
    Mise en ligne de POST /simulation-voyage (le devis Voyage n'existait pas ; réponse backend du 03/08 : « concernant voyage une api est manquante »)implicite au 30/03/202603/08/2026+ 124 jours
    Devis Voyage branché en réelfin du Sprint 2 API, 20/07/202617/08/2026+ 28 jours
    Création de contrat Voyage (POST /souscriptions/voyage ne créait aucun contrat jusqu'au correctif)20/07/202618/08/2026+ 29 jours
    Endpoint de contenu produit (/produits/{id}/detail)avant le Sprint 2 APIlivré le 23/07/2026 sur la base d'un fichier de référence rédigé par l'équipe mobile le 13/0710 jours de fiche produit en statique
    Devis Santé (404 « Problème lors de l'appel API Ticket »)Sprint 3 APIréglé le 03/08/2026+ 8 jours
    PUT /members (405 METHOD_NOT_ALLOWED)Sprint 3 APIrésolu le 04/08/2026+ 7 jours
    POST /members/addPieceJointeannoncé prêt le 09/08/2026toujours inutilisable (aucun champ nommé)ouvert
    Confirmation du paiement à la livraisondécrite par le backend le 30/07/2026n'existe pas dans la spécificationouvert
  2. 2. La dépendance la plus longue : la passerelle de paiement.

    2. La dépendance la plus longue : la passerelle de paiement.
    JalonDate
    Cartes CIB de test reçues16/07/2026
    Cartes Dahabia demandées16/07/2026 — jamais transmises
    Signalement : l'instance Satim de test est celle d'un tiers, aucune carte ne fonctionne26/07/2026
    Proposition d'un simulateur backend à deux scénarios (succès, échec)26/07/2026 — non retenue
    Première page de paiement réellement obtenue (Dahabia)19/08/2026
    Nouvelles cartes CIB transmises par le client09/09/2026
    Premier paiement carte encaissé de bout en bout (contrat passé à ENCAISSE, police émise)16/09/2026, soit 51 jours après le signalement
    Les quatre tunnels règlent un vrai paiement en exécution automatisée17/09/2026
  3. Le paiement est la dernière étape de tout parcours d'achat : son indisponibilité a interdit de déclarer un seul produit « validé » pendant toute cette période, alors que les quatre étaient câblés.

  4. 3. Une documentation d'API qui ne décrit pas le comportement réel.

    38 % des opérations déclarent tous leurs champs optionnels alors que l'API valide strictement ; des champs déclarés obligatoires sont ignorés à l'exécution ; des champs non déclarés provoquent un 500 ; une réponse décrite comme du texte transporte du JSON ; un type integer là où l'implémentation attend un tableau ; la spécification documente le champ retiré de POST /refunds et omet celui qui fonctionne. La demande transverse du 27/07/2026 (fournir un exemple de requête fonctionnelle par endpoint de création) n'a jamais reçu de réponse. La conséquence est structurelle : chaque endpoint doit être vérifié en conditions réelles avant d'être codé.

  5. 4. Un succès applicatif qui ne garantit pas que l'opération a eu lieu.

    Sur la seule semaine du 17 au 19/08/2026 : un contrat annoncé créé mais inexistant, une page de paiement annoncée disponible mais vide, une prime tarifée sur des paramètres incomplets et renvoyée sans avertissement. Puis, le 16/09/2026, un paiement encaissé que l'endpoint de confirmation déclare non valide. Cette classe de défaut impose de ne faire confiance à aucune réponse et d'ajouter une relecture de contrôle après chaque écriture.

  6. 5. Des règles métier découvertes par l'essai plutôt que par la spécification.

    Durée de couverture imposée (Scolaire 364–366 jours, Accident 30 jours) révélée par un 409 « Tarifs invalide » le 23/07/2026 ; nombreMembres désignant les ayants droit ; convention tarifaire obligatoire pour la Famille Voyage ; recalcul silencieux de la prime Santé le 26/08/2026 ; règle du typeContratId par nombre d'assurés communiquée le 20/07/2026 après six questions écrites.

  7. 6. Un environnement de pré-production incomplet.

    Passerelle de paiement inexploitable du 16/07 au 16/09/2026, aucun code promo valide, solde de points insuffisant, compte de test avec des données invalides au regard des règles du backend lui-même, incident de 30 minutes le 27/08/2026 sans cause identifiée (22 endpoints en régression), groupe GitLab passé en lecture seule le 19/08/2026. Aucun de ces points n'est bloquant isolément ; ensemble, ils rendent impossible la validation de ce qui est câblé.

Décalage sprint par sprint

Décalage par sprint
SprintFin planifiée (Planning V2)Fin effective du câblageÉcartBlocage déterminant
S1 — Authentification07/07/202610/09/2026+ 65 joursPriorisation des produits d'abord ; puis contrat POST /users erroné (500), absence de vérification serveur de l'OTP téléphone, quatre défauts bloquants corrigés le 10/09
S2 — Souscription hors santé20/07/202623/07/2026 pour le Scolaire ; Accident groupe toujours en 409quelques joursPOST /souscriptions à corps vide (21/07), 409 groupe et « Tarifs invalide » (23/07)
S2 — Moyens de paiement20/07/202617/09/2026 pour le paiement carte ; Points verts, livraison et Dahabia non clos+ 59 joursSatim indisponible 51 jours ; /points-verts/paiement en 500 depuis le 20/07 ; cartes Dahabia jamais reçues
S3 — Voyage13/08/202618/08/2026 (souscription), 19/08/2026 (paiement)+ 5 joursV8 (aucun contrat créé), V8b (succès sur échec), V11 (formules non identifiables, refus puis livraison le 19/08 après argumentation)
S3 — Sinistres13/08/2026déclaration non déposableouvertRéférentiel produit non exposé, découvert le 16/09/2026
S4 / S5 — Santé05/08/202626/08/2026+ 21 joursDevis Santé en 404 jusqu'au 03/08, PUT /members en 405 jusqu'au 04/08
S4 / S5 — Compléter profil santé05/08/2026non closouvertDépôt des pièces, personnes à charge et bulletin d'adhésion sans réponse exploitable au 16/09/2026
Le report global se concentre sur les phases 4 (Intégration API) et 5 (Q&A). L'intégration statique, dont l'équipe mobile est seule maîtresse, a été livrée à 100 % conformément au plan : les cinq lots de la phase 2 sont marqués achevés dans le planning client.

Plan d’action

Le plan est organisé par chantiers de blocage et non plus par sprint (section 1.4). Les lots ci-dessous restent la clé de lecture des tickets de la Partie 3 ; chaque lot est rattaché à son chantier.

Plan d’action par lot
LotChantierContenuResponsable
Lot 1 — Débloquer la validation1 et 2P0-M#5(ticket dans l’outil de ticketing, nouvelle fenêtre), P0-N#6(ticket dans l’outil de ticketing, nouvelle fenêtre), P0-C#8(ticket dans l’outil de ticketing, nouvelle fenêtre) (paiement), A14#9(ticket dans l’outil de ticketing, nouvelle fenêtre) (Accident groupe), P1-D#23(ticket dans l’outil de ticketing, nouvelle fenêtre) (décision A2), A9#1(ticket dans l’outil de ticketing, nouvelle fenêtre) (/auth/refresh500), A22#16(ticket dans l’outil de ticketing, nouvelle fenêtre) (code MFA non délivré), P0-D#2(ticket dans l’outil de ticketing, nouvelle fenêtre) (décision A1), A10#17(ticket dans l’outil de ticketing, nouvelle fenêtre) (UTF-8)Backend, Amana
Lot 2 — Débloquer les fonctions inopérantes3P0-I#12(ticket dans l’outil de ticketing, nouvelle fenêtre), P0-L#3(ticket dans l’outil de ticketing, nouvelle fenêtre), P0-H#4(ticket dans l’outil de ticketing, nouvelle fenêtre), P0-J#13(ticket dans l’outil de ticketing, nouvelle fenêtre), §31#14(ticket dans l’outil de ticketing, nouvelle fenêtre), P3.10#15(ticket dans l’outil de ticketing, nouvelle fenêtre), P1-F#26(ticket dans l’outil de ticketing, nouvelle fenêtre), P1-G#27(ticket dans l’outil de ticketing, nouvelle fenêtre), P3.17#54(ticket dans l’outil de ticketing, nouvelle fenêtre), P3.12#11(ticket dans l’outil de ticketing, nouvelle fenêtre) (décision A3)Backend, Produit
Lot 3 — Arbitrages produitTransverseA3 (chat), A4 (Santé Groupe), A5 (renouvellements et avenants Santé), A6 (écran de liste des notifications)Amana, Produit
Lot 4 — Fiabiliser le contratTransverseP0-F#18(ticket dans l’outil de ticketing, nouvelle fenêtre), P0-G#19(ticket dans l’outil de ticketing, nouvelle fenêtre), P1-A#20(ticket dans l’outil de ticketing, nouvelle fenêtre) / P1-B#21(ticket dans l’outil de ticketing, nouvelle fenêtre) / P1-C#22(ticket dans l’outil de ticketing, nouvelle fenêtre) / P1-E#24(ticket dans l’outil de ticketing, nouvelle fenêtre), A17#64(ticket dans l’outil de ticketing, nouvelle fenêtre) à A21#68(ticket dans l’outil de ticketing, nouvelle fenêtre), A23#69(ticket dans l’outil de ticketing, nouvelle fenêtre) (chaîne OTP), P2.9#41(ticket dans l’outil de ticketing, nouvelle fenêtre), P2.3#39(ticket dans l’outil de ticketing, nouvelle fenêtre), P2.10#42(ticket dans l’outil de ticketing, nouvelle fenêtre), P2.2#30(ticket dans l’outil de ticketing, nouvelle fenêtre), A16#63(ticket dans l’outil de ticketing, nouvelle fenêtre) (required de la spécification)Backend
Lot 5 — Reliquat applicatif2 et 3Inscription et mot de passe oublié corrigés (ordre des appels, endpoint, jeton) et écrans instrumentés pour Maestro ; dépôt des pièces santé dès P0-J#13(ticket dans l’outil de ticketing, nouvelle fenêtre) ; déclaration de sinistre dès ; retrait des gardes de relecture dès P1-A#20(ticket dans l’outil de ticketing, nouvelle fenêtre) et P0-N#6(ticket dans l’outil de ticketing, nouvelle fenêtre) ; rejeu de la résiliation et du retrait d'ayant droit sur khaddoucheTest ; module natif du bouton « coller » OTP ; URL de production ; télémétrie ; chiffrement du stockage localSHIFTIN
Lot 6 — Confort et complétudeTransverseP3.1#56(ticket dans l’outil de ticketing, nouvelle fenêtre) à P3.9#44(ticket dans l’outil de ticketing, nouvelle fenêtre), P3.11#57(ticket dans l’outil de ticketing, nouvelle fenêtre), P3.14#51(ticket dans l’outil de ticketing, nouvelle fenêtre) à P3.16#49(ticket dans l’outil de ticketing, nouvelle fenêtre), P3.18#55(ticket dans l’outil de ticketing, nouvelle fenêtre), P3.19#47(ticket dans l’outil de ticketing, nouvelle fenêtre), P2.1#31(ticket dans l’outil de ticketing, nouvelle fenêtre), P2.4#33(ticket dans l’outil de ticketing, nouvelle fenêtre) à P2.7#40(ticket dans l’outil de ticketing, nouvelle fenêtre), P2.11#34(ticket dans l’outil de ticketing, nouvelle fenêtre) à P2.13#32(ticket dans l’outil de ticketing, nouvelle fenêtre), A24#70(ticket dans l’outil de ticketing, nouvelle fenêtre)Backend
Prérequis client1 et 2Décisions A1 à A6 (22/09/2026) ; cartes Dahabia de test (01/10/2026) ; compte App Store (04/10/2026) ; compte Play Store, URL de l'API de production, instance Satim marchande au nom d'Amana (13/10/2026) ; réponses Q1-Q9#71(ticket dans l’outil de ticketing, nouvelle fenêtre) sur les comptes migrés (01/10/2026)Amana
Règle de fonctionnement proposée pour la suite : un correctif n'est considéré livré que lorsqu'il a été vérifié en réel par l'équipe mobile, et tout risque de glissement est signalé au point quotidien, avec sa cause et son impact estimé, avant la date manquée et non après.