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

Manager technique · Analyse technique détaillée

Manager technique

L’API est rapide ; c’est sa forme qui coûte. Aucune rupture de contrat sur les endpoints consommés, mais 20 problèmes bloquants 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, 107 opérations

Opérations sans champ requis déclaré

41 sur 107 (38 %)

alors que l’API valide strictement

Enveloppes d’erreur distinctes

5

avec trois formats d’horodatage

Rupture de contrat sur un endpoint consommé

0 rupture

contrôle automatisé à chaque mise à jour

Section 2.1 : Audit technique de l’API

L’état mesuré de l’API, les problèmes relevés workflow par workflow, la dette technique et les risques qui en découlent.

État actuel de l’API

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

Analyse des problèmes techniques identifiés, 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 (+ 7 transverses)181727163
63 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-swagger → 403). 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émentsP2.5#35(ticket dans l’outil de ticketing, nouvelle fenêtre)P3.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/AAAA → 400, 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)
BloquantGET /points-verts/paiement/{quittanceId}500 systématique, 500 nu sur solde insuffisant ; un GET qui exécute un débit (rejouable par préchargement, robot ou rafraîchissement : un balayage en lecture seule a déclenché une tentative de paiement)P0-B#7(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)
MoyenPOST /carteFlash/checkTicketValidationstatut vaut la chaîne "false" : booléen déguisé sous un nom d'énumérationP2.8#36(ticket dans l’outil de ticketing, nouvelle fenêtre)
Sinistres
BloquantPOST /claimsLe champ produit doit correspondre à un référentiel « produit sinistre » qu'aucun endpoint mobile n'expose (10 valeurs testées → produit_sinistre_id on null) ; le validateur nomme date_naiss / date_sinistre / path_files alors que l'endpoint lit dateNaiss / dateSinistre / piecesP0-K#10(ticket dans l’outil de ticketing, nouvelle fenêtre)
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 200 → 404 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—
MoyenTypes de contratSeuls 530 (Individuel) et 531 (Famille) existent : aucun niveau Groupe pour la SantéP3.13#58(ticket dans l’outil de ticketing, nouvelle fenêtre)
MoyenGET /membersPoliceId en PascalCase là où la spécification déclare policeId ; /members/bulletinSoins renvoie un PDF en base64 dans du JSON—

Transverse : ce qui touche tous les workflows

Constats transverses
Sév.ConstatRéf.
Erreurs servies en charset=ISO-8859-1 alors que JSON doit être en UTF-8 : le message français affiché en repli à l'utilisateur arrive en mojibake, précisément sur le chemin d'erreurÀ créer
500 utilisé comme code métier : dix cas confirmés où un 4xx est attendu (page absente, date absente, partie multipart absente, identifiant inconnu, fichier trop lourd, solde insuffisant, champs invalides, jeton valide)P2.2#30(ticket dans l’outil de ticketing, nouvelle fenêtre), P2.10#42(ticket dans l’outil de ticketing, nouvelle fenêtre)
Documentation qui décrit une API qui n'existe pas : 38 % de required: [], cinq « mensonges actifs » (/refunds, /members, /auth/me, enveloppes de /refunds et /claims, /simulation-voyage), aucun exemple de requête fonctionnelle malgré une demande formelle restée sans réponseP2.9#41(ticket dans l’outil de ticketing, nouvelle fenêtre)
Trois conventions de casse, deux langues, un pluriel non systématique dans les chemins ; verbes dans l'URL ; POST utilisé en lecture pour les devisP2.7#40(ticket dans l’outil de ticketing, nouvelle fenêtre)
Cinq enveloppes d'erreur, trois horodatages, messages de validation en français non traduisiblesP2.10#42(ticket dans l’outil de ticketing, nouvelle fenêtre)
Énumérations livrées en libellés d'affichage français ("Masculin", "Marié", "droitier") : interdit de traduire en arabe et de comparer de façon stableP2.8#36(ticket dans l’outil de ticketing, nouvelle fenêtre)
Environnement de pré-production incomplet : compte de test avec données invalides au regard des règles du backend lui-même (corrigées par l'équipe mobile), aucun code promo, solde de points insuffisant pour le cas nominal ; le compte jetable (khaddoucheTest) est fourni mais n'a pas d'enregistrement souscripteur dans /auth/me P1-J#25(ticket dans l’outil de ticketing, nouvelle fenêtre)—

Points de dette technique et de non-conformité

Dette technique et non-conformité
OùDette ou non-conformitéPortée
BackendSpécification OpenAPI non fiable : le générateur de code ne peut pas être utilisé, 1 968 lignes de client HTTP sont maintenues à la mainTout futur client (web, back-office) paiera cette dette une seconde fois, intégralement
BackendSémantique HTTP dégradée : GET avec effet de bord monétaire, DELETE à corps multipart, 201 avec success: false, aucune idempotence sur les écritures d'argentSouscription, Paiement
BackendAbsence de transaction sur la création de contrat VoyageSouscription Voyage
BackendHétérogénéité des formats (dates, casse, énumérations, enveloppes, pagination)Tous
BackendRôles de back-office dans le jeton d'un client mobile ; divulgation de chemins internes dans les 500Sécurité
ApplicationRègles métier hébergées dans les adaptateurs faute de source côté serveur (classification des actes, déduction du sexe depuis un libellé, base d'index de pagination codée par appel)Remboursements, Compte, Dashboard
ApplicationIdentifiants de pré-production versionnés dans le dépôt ; stockage local non chiffré avec cache persisté contenant le questionnaire médical ; télémétrie non branchée ; URL de production facticeSécurité, exploitation
ApplicationUn seul reliquat de contenu simulé : fixture marketing de la fiche produit en dernier recours si l'endpoint tombeMenu – Produits

Risques techniques associés

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

Section 2.2 : Impacts, conséquences & contournements

Ce que les problèmes ont coûté au projet, puis, workflow par workflow, le contournement en place et ses limites.

Conséquences globales des problèmes identifiés

  • 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.

Impacts, contournements et limites, par workflow

Chaque contournement est une dette à retirer dès le correctif serveur ; les cases « aucun » sont les fonctions qu’aucun travail côté mobile ne peut débloquer.

Authentification5 points
Impacts et contournements — Authentification
ProblèmeConséquenceContournement en placeLimites et risques du contournement
/auth/refresh → 500Chaque 401 mène à une déconnexion forcée ; toute la machinerie de rafraîchissement (rotation, verrou anti-concurrence, rejeu unique) est inatteignableAucun. Attente du correctif serveur, surveillance du taux de déconnexionsRien de propre n'est possible côté client
Contrat POST /users erroné, OTP téléphone non vérifié, jeton statique et mot de passe OTP partagé embarqués dans le bundleQuatre défauts bloquants sur la branche d'authentification ; un tiers aurait pu relayer des OTP contre le backendOpération réelle newUser ; secrets retirés ; OTP téléphone collecté mais étape marquée non vérifiéeLe champ CIN est abandonné à l'envoi ; la vérification serveur dépend de la décision A1
Défis 419/420 sans champ status ; connexion rejetée si un JWT périmé est attachéLe mappeur d'erreurs standard aurait jeté le jeton du défi ; « les données n'apparaissent qu'après réinstallation »Reconnaissance par le jeton, gardé en mémoire seule et restreint par liste blanche ; /auth/login et /auth/refresh partent toujours sans en-tête d'authentificationHiérarchie d'erreurs dédiée à maintenir
Inscription : OTP avant création du compte ; mot de passe oublié : mauvais endpoint et jeton non conservé (défauts applicatifs)Aucun nouvel utilisateur ne peut s'inscrire ni récupérer son mot de passeAucun : correctif applicatif planifié pour le premier APK (créer le compte avant l'OTP ; /auth/otp → /auth/otp/validate → PATCH /auth/password avec le jeton renvoyé)Dépend de la décision backend sur l'ordre officiel du parcours A17#64(ticket dans l’outil de ticketing, nouvelle fenêtre) et de la délivrance du code MFA A22#16(ticket dans l’outil de ticketing, nouvelle fenêtre)
Déclencheur des comptes migrés inconnuQuatre écrans construits, traduits et testés, invisibles pour l'utilisateurRoutes de recette accessibles par lien profond hors production ; flows Maestro en attenteAucun appel à /auth/attach tant que le contrat n'est pas confirmé (pas de retour arrière connu)
Accueil2 points
Impacts et contournements — Accueil
ProblèmeConséquenceContournement en placeLimites et risques
Panne d'un endpoint bloquant l'écran entier (incident de pré-production)Accueil inutilisable après connexion pendant l'incidentDégradation ciblée : seul le carrousel produits disparaît ; outillage api:probe / api:contract pour qualifier un incident en minutesÀ généraliser aux autres écrans composites
Pas de prix minimum sur /produits ; pas de compteur de non-lus4 + N requêtes à l'accueil ; page de 50 notifications chargée pour un badgeFan-out parallèle, staleTime par usage, dé-duplication de /auth/meCompteur plafonné par la taille de page ; N+1 permanent
Dashboard3 points
Impacts et contournements — Dashboard
ProblèmeConséquenceContournement en placeLimites et risques
Enveloppe de /refunds migrée sans préavis (data → content)L'écran d'accueil entier est tombé en erreurpageItems() : lecture tolérante des deux enveloppes3 lignes qui ont évité une refonte ; dette si une troisième forme apparaît
Base d'index de pagination non uniformeErreur silencieuse : une page sautée au lieu d'une erreurBase codée en dur par appelIndevinable, à documenter côté serveur
Pas de numéro de police, tri non confirméChamp omis ; « dernier contrat » non fiablePagination infinie côté application—
Compte6 points
Impacts et contournements — Compte
ProblèmeConséquenceContournement en placeLimites et risques
PUT /members = remplacement completEnvoyer le seul bloc modifié efface le reste ou échoueRelecture de la fiche complète et fusion avant chaque écriture ; téléphone complété à 10 chiffresUn aller-retour supplémentaire ; la wilaya du profil santé n'a aucun champ dans le contrat et n'est pas persistée
Réponses « Oui »/« Non », libellé « Féminin » accentuéToutes les assurées affichées « Homme », toutes les réponses médicales affichées « Non »Correspondances tolérantes, safeEnum avec journalisation des valeurs inconnuesRègle métier déportée côté mobile
Règle des 100 % non documentée, compte de test incohérentAucune répartition enregistrable sur le compte de testVérification côté application avec message expliciteLe compte de test reste inutilisable pour cette fonction tant qu'il n'est pas re-seedé
Énumérations fermées« frère/sœur » et « autre » sans valeur possibleRepli sur « Ascendant » avec indicateur à l'écranDonnée métier approximée
Date compacte AAAAMMJJFormat documenté refuséConvertisseur dédié à ce seul endpointUn cinquième format de date à maintenir
Photo de profil en binaire sous JWTImpossible à afficher directementTéléchargement du blob puis conversion en data: URIImage encodée en base64 dans le cache persisté
Menu5 points
Impacts et contournements — Menu
ProblèmeConséquenceContournement en placeLimites et risques
/documents → 500 hors adhérent santé et en-tête perdu sur erreurCul-de-sac : l'utilisateur ne pouvait plus revenir en arrière, sur la majorité des comptes réelsEn-tête rendu hors de la branche d'erreur (53 écrans)Le 500 reste : écran vide pour la majorité des souscripteurs
Chemin de fichier serveur au lieu d'une URLAucun document ouvrableBouton de téléchargement masquéAucun contournement possible : promesse fonctionnelle non tenable
Contenu éditorial en français seulementTitres traduits autour de contenus français en arabeAucunAucun contournement possible
/sos mêle prose et liste, /professions non triéPrésentation à reconstruireSéparation heuristique et tri dans les adaptateursRègle de présentation côté client
Pièces jointes du formulaire de contact plafonnéesPhoto de téléphone refuséeCompression JPEG qualité 0,6, mesure avant envoi, refus expliqué ; la copie « 8 Mo » corrigée à « 1 Mo »Le cas nominal reste en échec
Souscription10 points
Impacts et contournements — Souscription
ProblèmeConséquenceContournement en placeLimites et risques
201 success: true sur un échec (V8b)Le client serait envoyé payer un contrat fantômeRelecture de GET /contrats/{id} après chaque souscription ; un 404 fait échouer l'étapeUn aller-retour réseau par vente ; à retirer dès correction
Création Voyage en trois appels non atomiques (V8c)Contrat vendu pour N voyageurs mais couvrant une partie d'entre eux en cas de coupureAucun ; risque assumé, le contrat restant impayéRisque résiduel non couvert
Champs obligatoires ignorés, prix faux en 200 (V5)Prix plausible mais faux affichéL'endpoint n'est appelé qu'une fois tous les champs réunisProtection défensive permanente ; la garantie devrait venir de l'API
Prime Famille plafonnée au 7ᵉ voyageur (V13)Trois voyageurs sur dix assurés gratuitementAucun : prix serveur affiché tel quel, sur décision produit ; règle « 2 adultes + 8 enfants » appliquée à l'écran et revérifiée avant l'appelImpact recette tant que non tranché
Formules non identifiables (V11), montant total absent (V4), encodage ISO-8859-1 sur le devis (V6)Cartes nommées par position, capitaux retriés, décodage octet par octetRetirés après correctifs backend, obtenus après argumentation écrite—
Le backend recalcule la prime Santé et ignore le montant transmisUn prix affiché, un autre facturé, sans aucune erreurDevis et contrat construits pour concorder par constructionToute divergence de règle côté serveur serait invisible
Durées de couverture imposées, nombreMembres = ayants droit, convention tarifaire FamilleRègles découvertes par 409 et essaisRègles appliquées à l'écran et revérifiées avant l'appelRègles métier codées côté mobile, à synchroniser à chaque changement
Contrat créé au clic de paiementUn échec de règlement suivi d'une nouvelle tentative créait deux contratsCréation à l'étape de consentement sur les quatre produitsUn contrat en attente subsiste si le client abandonne au paiement
Compte sans enregistrement souscripteur« Paiement non abouti » en fin de tunnel alors que rien n'a été crééTunnels rejoués sur le compte santéUn client réel dans ce cas est bloqué en fin de parcours
Aucune idempotenceDouble contrat possibleBouton désactivé pendant l'appelUn rejeu réseau n'est pas couvert
Paiement6 points
Impacts et contournements — Paiement
ProblèmeConséquenceContournement en placeLimites et risques
confirmPayment nie un paiement encaisséÉcran d'échec après un paiement réussi, invitation à repayerRelecture du contrat : ENCAISSE / ACTIF / PAYE valent règlement (« le contrat est ce qui facture, donc c'est le contrat qui tranche »)Jusqu'à 90 s avant l'écran de succès ; le détail de la passerelle n'est pas reconstituable
returnUrl vers le site vitrineLe client reste dans le navigateurAucunAucun contournement possible côté mobile
formUrl: null avec errorCode: 0Redirection vers une page videLes deux champs contrôlés avant redirection—
Points verts en 500 nu sur solde insuffisantAucun message exploitableContrôle du solde avant appel, erreur typée avec le montant manquantLogique métier assumée côté client ; cas nominal jamais exécuté
Confirmation du paiement à la livraison inexistantePassage à l'état encaissé invisibleAucunFonction incomplète
Instance Satim de test d'un tiers, cartes Dahabia absentesValidation carte impossible pendant 51 jours ; Dahabia jamais régléProposition d'un simulateur backend à deux scénarios (non retenue) ; cartes CIB finalement fourniesPage marchande au nom d'un tiers non livrable
Contrats4 points
Impacts et contournements — Contrats
ProblèmeConséquenceContournement en placeLimites et risques
Détail de contrat incompletTrois données absentesSecond appel GET /coverages/{produitId} ; champs omis à l'écran+1 requête par écran
Justificatif de résiliation en base64La demande part sans ses piècesMotif et commentaire envoyés seulsProduire du base64 exigerait une nouvelle dépendance native
Statut carte Flash en texte libreUn statut inconnu ne doit jamais débloquer une souscriptionListe blanche : tout statut inconnu échoue fermé—
Documents de contrat en 404Quatre boutons « documents » inactifsMasquésBloqué par P0-H#4(ticket dans l’outil de ticketing, nouvelle fenêtre) de toute façon
Sinistres2 points
Impacts et contournements — Sinistres
ProblèmeConséquenceContournement en placeLimites et risques
Référentiel produit non exposéDéclaration jamais déposéeContrat reconstitué à un champ près ; l'écran ne simule plus un succèsFonction inopérante tant que P0-K#10(ticket dans l’outil de ticketing, nouvelle fenêtre) est ouvert
Chat rattaché au clientMême fil sous chaque sinistreL'identifiant du sinistre ne sert plus qu'au cacheFonctionnalité dégradée par le modèle de données ; à ne pas remonter comme anomalie en recette tant que A3 n'est pas tranché
Remboursements4 points
Impacts et contournements — Remboursements
ProblèmeConséquenceContournement en placeLimites et risques
Plafond de 1 Mo par fichierUne photo de justificatif (3 à 5 Mo) est refuséeCompression, mesure avant envoi, refus expliquéLe cas nominal reste en échec ; redimensionner exigerait une dépendance native
Renommage type → codeActe sans préavisDéclaration codée d'après l'indication backend échouait silencieusementContrat écrit à la main d'après les essais ; test encodant le piègeTout futur renommage silencieux se répétera
Catalogue d'actes sans catégorie ni illustration, code non uniqueSélecteur moins lisibleCatégorie et illustration déduites du code dans l'adaptateurRègle de classification métier hébergée côté mobile
Sélecteur de personne assurée listait les bénéficiaires en cas de décèsMauvaise populationCorrigé : ayants droit couverts—
Santé Individuelle · Famille · Groupe6 points
Impacts et contournements — Santé Individuelle · Famille · Groupe
ProblèmeConséquenceContournement en placeLimites et risques
addPieceJointe sans contrat découvrableLes fichiers sélectionnés n'ont nulle part où allerSélecteur de fichiers réel, dépôt non branchéNon branchable tant que P0-J#13(ticket dans l’outil de ticketing, nouvelle fenêtre) est ouvert
POST /ayantDroits → 500 nuPersonnes à charge jamais soumisesConservées dans le brouillon, brouillon vidé seulement après accord du serveurÉtape silencieusement incomplète pour l'utilisateur
Bulletin d'adhésion en 500Étape réclamée par le message de succès impossibleÉcran présent, rien à téléchargerLe profil reste non activé (validation à 0)
Renouvellement en 409 opaque, adjonction en 500 sur DTO d'erreurDeux parcours avec interface complète et rien à appelerTarification du renouvellement sur donnée simulée, seul reliquat expliciteÀ exclure de la version 1 ou planifier (A5)
Aucun type GroupeSouscription Santé Groupe sans objet—À confirmer (A4)
Plafond de téléversementIdem RemboursementsIdemIdem
Transverse5 points
Impacts et contournements — Transverse
ProblèmeConséquenceContournement en placeLimites et risques
Spécification non fiableGénérateur de code inutilisableClient HTTP écrit à la main, chaque DTO daté de sa vérification live, fonctions nommées d'après l'operationId pour qu'un futur codegen soit un remplacement direct1 968 lignes maintenues à la main
3 casses, 5 formats de date, énumérations en français, booléens textuelsAucun DTO directement consommable par un écranCouche d'anti-corruption : 26 modules d'adaptateurs purs, synchrones, totaux4 051 + 2 762 lignes ; un second client paiera à nouveau
Erreurs en ISO-8859-1Messages illisiblesAucunDécoder en latin-1 selon le content-type serait un correctif laid, réservé au cas où le serveur ne bouge pas
Dérive silencieuse du contratRégressions invisiblesyarn api:probe (54 lectures, sans écriture) et yarn api:contract (comparaison à un contrat figé, wired-aware) ; playbook de dérive documentéNe couvre que les lectures ; les écritures peuvent désormais être automatisées sur le compte jetable khaddoucheTest
Environnement de pré-production incompletValidation impossible de ce qui est câbléCompte de test corrigé par l'équipe mobile pour le rendre enregistrable ; données de recette préfixées RECRésiliation et retrait d'ayant droit restent à rejouer sur le compte jetable khaddoucheTest

Section 2.3 : Causes & justification des décalages

Des faits datés : la porte de qualité non franchie, les causes racines par impact décroissant, le glissement sprint par sprint, les justificatifs, le travail supplémentaire 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 prête et validée avant le début de 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é.

Éléments techniques ayant entraîné le 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.

Justificatifs et éléments factuels

Justificatifs
FaitSource
Mentions « 3 rounds – toujours pas validé ! » sur Voyage (01/04/2026) et Compte (13/04/2026)Planning client, feuilles « Timeline actualisée » et « Timeline ajustée avec notes », colonne Note de la phase 3
60 signalements écrits entre le 13/07 et le 19/08/2026, 48 ayant reçu une réponse (80 %), 12 sans réponse, 4 interlocuteurs backend ; 25 des 60 messages concernent le seul workflow VoyageExtraction Teams du canal « MyAmana – Dev Team », classée par workflow
« concernant voyage une api est manquante, je retournerai vers vous une fois finalisée »Réponse backend du 03/08/2026
Refus initial d'ajouter l'identifiant et le libellé de formule (« changements sur process actuel déjà en production »), puis livraison le jour mêmeFil Teams du 19/08/2026
Matrices de tests Scolaire / Accident (23/07/2026) et Voyage (11/08 et 17/08/2026) transmises au backend, avec la précision « le prix n'est pas la cause : on envoie exactement la valeur renvoyée par votre propre simulation »Fil Teams
Cause racine de V8 identifiée par l'équipe mobile (404 sur l'appel interne save-contrat-details), correctif backend le lendemainFil Teams des 17 et 18/08/2026
Contrat PUT /members, renommage type → codeActe, format AAAAMMJJ, plafond de 1 Mo : découverts en exerçant les endpoints d'écriture en réel les 15 et 16/09/2026Journal des écarts de contrat (33 sections avec curl), rapport PM du 16/09/2026
POST /auth/refresh → 500 avec un jeton valide émis 2 minutes plus tôt, mesuré le 18/09/2026Audit « API réelle vs spécification »
Relevés automatisés du contrat d'API des 03/08, 15/09 et 17/09/2026 : verdict intact sur les endpoints consommésyarn api:contract
Incident de pré-production du 27/08/2026 qualifié en 3 minutes (relevé à 15 h 03 : 22 endpoints en régression ; à 15 h 32 : contrat intact)Relevés automatisés
Paiement carte encaissé sur les quatre produits, contrats réels avec police émise, 17 vidéos de recetteCampagne E2E des 16 et 17/09/2026
Chaîne OTP rejouée le 19/09/2026 avec la boîte mail de test sur un compte de recette : 18 appels, deux défauts applicatifs (inscription, mot de passe oublié) et sept défauts backend (A17#64(ticket dans l’outil de ticketing, nouvelle fenêtre) à A23#69(ticket dans l’outil de ticketing, nouvelle fenêtre))Note de recette docs/rapports-internes/recette-otp-boite-mail-2026-09-19.md

Le travail supplémentaire réalisé pour pallier ces manques

Ce travail n'était pas prévu au planning. Il a été nécessaire parce que l'API n'était ni prête ni fiable au moment où l'intégration devait la consommer.

Travail supplémentaire réalisé
Travail supplémentaireCe qu'il a coûtéCe qu'il a évité
Vérification en conditions réelles de chaque endpoint avant de le coder, y compris les endpoints d'écriture (8 sur 11 exercés en réel le 16/09/2026)Plus lent par construction que coder d'après une spécificationSur 8 endpoints d'écriture, 4 étaient mal documentés au point de rendre le code inutilisable : profil santé et déclaration de remboursement auraient échoué à 100 % en recette ou en production
Client HTTP écrit à la main (1 968 lignes), chaque DTO daté de sa vérification live, parce que le générateur de code produirait des types qui compilent mais mententMaintenance manuelle permanenteDes types faux sur une part importante des endpoints
Couche d'anti-corruption complète : 26 modules d'adaptateurs (4 051 lignes) et 2 762 lignes de tests, pour absorber 3 casses, 5 formats de date, 5 enveloppes d'erreur, 2 enveloppes de pagination, des énumérations en libellés français~66 lignes de traduction par endpointUne réécriture d'écrans à chaque migration silencieuse (la migration de /refunds a été absorbée en 3 lignes)
Spécification produite à la place du backend : fichier de référence du payload de la fiche produit, avec un exemple par produit, rédigé le 13/07/2026 ; l'endpoint a été livré sur cette baseTravail de conception hors périmètre mobileDix jours supplémentaires de fiche produit en statique
Matrices de tests et causes racines remontées au backend (matrice Scolaire / Accident du 23/07, tableaux comparatifs Voyage des 11/08 et 17/08, trace de l'erreur interne de V8 le 17/08/2026)Temps d'investigation sur un système dont l'équipe mobile n'a pas le codeCorrectifs backend obtenus en un jour au lieu de cycles d'aller-retour
60 signalements écrits en 38 jours, chacun avec la requête exacte, la réponse obtenue et le comportement attenduRédaction et suiviUn taux de réponse de 80 % sur un canal sans outil de ticketing
Gardes de relecture après chaque souscription Voyage et chaque paiement carte, contrôle du solde de points avant appel, appel du devis seulement une fois tous les champs réunis, contrat créé au consentementUn aller-retour réseau par vente ; jusqu'à 90 s avant l'écran de succèsEnvoyer un client payer un contrat fantôme ; afficher un échec après un paiement encaissé ; créer deux contrats pour une intention d'achat
Outillage de surveillance du contrat : yarn api:probe, yarn api:contract, harnais de capture des 54 lectures et des 31 mutations avec les payloads réels de l'application, playbook de dériveDéveloppement d'outillage hors périmètre fonctionnelUne journée perdue à chercher un défaut applicatif inexistant lors de l'incident du 27/08 ; une régression silencieuse à chaque mise à jour backend
Correction du compte de test pour le rendre enregistrable au regard des règles du backend (téléphone à 10 chiffres, code postal à 5 chiffres, date d'entrée en service)—Un compte de test impossible à enregistrer
Revue de sécurité ayant conduit au retrait d'un jeton statique et d'un mot de passe OTP partagé embarqués dans le bundle—Un tiers relayant des OTP contre le backend
Campagne E2E Maestro : 17 parcours écrits, exécutés et filmés, chaque mur backend nommé par un carton ; 66 tests construits sur des charges utiles capturées en liveEnviron dix minutes par parcours, 2,1 Go de vidéosNeuf anomalies ouvertes contre l'équipe mobile pour des murs backend ; sept défauts applicatifs invisibles en relisant le code
Outil de ticketing alimenté (55 tickets rattachés à leur workflow), dashboard de reporting construit, déployé et mis en ligne, planning V3 recalculé en jours ouvrésLivrables de pilotage hors périmètre initialUne vision commune de l'état d'avancement et des blocages
Écrans des comptes migrés construits par anticipation et 9 questions transmises sur POST /auth/attach—Refaire les écrans une fois le contrat connu

Plan d’action pour résorber les écarts

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Échéance
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-B#7(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/refresh → 500), 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, AmanaDécisions le 22/09/2026 ; correctifs vérifiés en réel pour l'APK 2 du 01/10/2026
Lot 2 — Débloquer les fonctions inopérantes3P0-K#10(ticket dans l’outil de ticketing, nouvelle fenêtre), P0-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, ProduitCorrectifs vérifiés en réel pour l'APK 3 du 08/10/2026
Lot 3 — Arbitrages produitTransverseA3 (chat), A4 (Santé Groupe), A5 (renouvellements et avenants Santé), A6 (écran de liste des notifications)Amana, ProduitSéance du 22/09/2026
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), P2.8#36(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)BackendHors chemin critique ; au fil de l'eau jusqu'au 13/10/2026, le reste en version 1.1
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 P0-K#10(ticket dans l’outil de ticketing, nouvelle fenêtre) ; 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 localSHIFTINInscription et mot de passe oublié livrés dans l'APK du 19/09/2026 ; destructrices le 01/10/2026 ; le reste pour la release candidate du 08/10/2026
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)BackendVersion 1.1 sauf livraison spontanée
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)AmanaDates ci-contre
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.