[{"data":1,"prerenderedAt":558},["ShallowReactive",2],{"docs-nav:fr":3,"docs:\u002Ffr\u002Fdocs\u002Fconcepts\u002Fshortest-path":137},[4],{"title":5,"path":6,"stem":7,"children":8,"page":44},"Fr","\u002Ffr","fr",[9],{"title":10,"path":11,"stem":12,"children":13},"Qu'est-ce que Fougere","\u002Ffr\u002Fdocs","fr\u002Fdocs\u002Findex",[14,15,19,23,27,45,66,95,116],{"title":10,"path":11,"stem":12},{"title":16,"path":17,"stem":18},"Démarrer","\u002Ffr\u002Fdocs\u002Fgetting-started","fr\u002Fdocs\u002F01.getting-started",{"title":20,"path":21,"stem":22},"App Nuxt existante","\u002Ffr\u002Fdocs\u002Fexisting-app","fr\u002Fdocs\u002F02.existing-app",{"title":24,"path":25,"stem":26},"La CLI","\u002Ffr\u002Fdocs\u002Fcli","fr\u002Fdocs\u002F03.cli",{"title":28,"path":29,"stem":30,"children":31,"page":44},"Concepts","\u002Ffr\u002Fdocs\u002Fconcepts","fr\u002Fdocs\u002F2.concepts",[32,36,40],{"title":33,"path":34,"stem":35},"Philosophie","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fphilosophy","fr\u002Fdocs\u002F2.concepts\u002F1.philosophy",{"title":37,"path":38,"stem":39},"La Frond","\u002Ffr\u002Fdocs\u002Fconcepts\u002Ffrond","fr\u002Fdocs\u002F2.concepts\u002F2.frond",{"title":41,"path":42,"stem":43},"Le chemin le plus court","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fshortest-path","fr\u002Fdocs\u002F2.concepts\u002F3.shortest-path",false,{"title":46,"path":47,"stem":48,"children":49,"page":44},"Schéma","\u002Ffr\u002Fdocs\u002Fschema","fr\u002Fdocs\u002F3.schema",[50,54,58,62],{"title":51,"path":52,"stem":53},"Entités","\u002Ffr\u002Fdocs\u002Fschema\u002Fentities","fr\u002Fdocs\u002F3.schema\u002F1.entities",{"title":55,"path":56,"stem":57},"Vues","\u002Ffr\u002Fdocs\u002Fschema\u002Fviews","fr\u002Fdocs\u002F3.schema\u002F2.views",{"title":59,"path":60,"stem":61},"La carte d'identité","\u002Ffr\u002Fdocs\u002Fschema\u002Fcard","fr\u002Fdocs\u002F3.schema\u002F3.card",{"title":63,"path":64,"stem":65},"Standard Schema","\u002Ffr\u002Fdocs\u002Fschema\u002Fstandard-schema","fr\u002Fdocs\u002F3.schema\u002F4.standard-schema",{"title":67,"path":68,"stem":69,"children":70,"page":44},"Métier","\u002Ffr\u002Fdocs\u002Fbusiness","fr\u002Fdocs\u002F4.business",[71,75,79,83,87,91],{"title":72,"path":73,"stem":74},"Handlers","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fhandlers","fr\u002Fdocs\u002F4.business\u002F1.handlers",{"title":76,"path":77,"stem":78},"Presenters","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fpresenters","fr\u002Fdocs\u002F4.business\u002F2.presenters",{"title":80,"path":81,"stem":82},"Collectors","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fcollectors","fr\u002Fdocs\u002F4.business\u002F3.collectors",{"title":84,"path":85,"stem":86},"Erreurs","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ferrors","fr\u002Fdocs\u002F4.business\u002F4.errors",{"title":88,"path":89,"stem":90},"Seeds","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fseeds","fr\u002Fdocs\u002F4.business\u002F5.seeds",{"title":92,"path":93,"stem":94},"Les faits","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ffacts","fr\u002Fdocs\u002F4.business\u002F6.facts",{"title":96,"path":97,"stem":98,"children":99,"page":44},"Client","\u002Ffr\u002Fdocs\u002Fclient","fr\u002Fdocs\u002F5.client",[100,104,108,112],{"title":101,"path":102,"stem":103},"Queries & commands","\u002Ffr\u002Fdocs\u002Fclient\u002Fqueries-commands","fr\u002Fdocs\u002F5.client\u002F1.queries-commands",{"title":105,"path":106,"stem":107},"Formulaires","\u002Ffr\u002Fdocs\u002Fclient\u002Fforms","fr\u002Fdocs\u002F5.client\u002F2.forms",{"title":109,"path":110,"stem":111},"Session","\u002Ffr\u002Fdocs\u002Fclient\u002Fsession","fr\u002Fdocs\u002F5.client\u002F3.session",{"title":113,"path":114,"stem":115},"invoke","\u002Ffr\u002Fdocs\u002Fclient\u002Finvoke","fr\u002Fdocs\u002F5.client\u002F4.invoke",{"title":117,"path":118,"stem":119,"children":120,"page":44},"Infrastructure","\u002Ffr\u002Fdocs\u002Finfra","fr\u002Fdocs\u002F6.infra",[121,125,129,133],{"title":122,"path":123,"stem":124},"Le gradient","\u002Ffr\u002Fdocs\u002Finfra\u002Fgradient","fr\u002Fdocs\u002F6.infra\u002F1.gradient",{"title":126,"path":127,"stem":128},"Surfaces — REST & GraphQL","\u002Ffr\u002Fdocs\u002Finfra\u002Fsurfaces","fr\u002Fdocs\u002F6.infra\u002F2.surfaces",{"title":130,"path":131,"stem":132},"Déploiement","\u002Ffr\u002Fdocs\u002Finfra\u002Fdeployment","fr\u002Fdocs\u002F6.infra\u002F3.deployment",{"title":134,"path":135,"stem":136},"Hôtes","\u002Ffr\u002Fdocs\u002Finfra\u002Fhosts","fr\u002Fdocs\u002F6.infra\u002F4.hosts",{"id":138,"title":41,"body":139,"description":553,"extension":554,"meta":555,"navigation":465,"path":42,"seo":556,"stem":43,"__hash__":557},"docs_fr\u002Ffr\u002Fdocs\u002F2.concepts\u002F3.shortest-path.md",{"type":140,"value":141,"toc":546},"minimark",[142,146,150,158,163,166,246,249,253,256,259,263,266,288,296,299,322,325,329,336,522,529,533,536,542],[143,144,41],"h1",{"id":145},"le-chemin-le-plus-court",[147,148,149],"p",{},"Lorsqu'une tâche est urgente, le chemin le plus simple finit généralement par être\nutilisé. Fougere cherche donc à rendre le chemin conventionnel plus court que son\ncontournement.",[147,151,152,153,157],{},"Cette page décrit un principe de conception et l'outillage associé. ",[154,155,156],"code",{},"fougere graph"," est\ndisponible aujourd'hui. Les contrôles de graphe en CI et le catalogue de refus présentés\nplus bas sont encore à l'étude.",[159,160,162],"h2",{"id":161},"une-api-par-besoin-courant","Une API par besoin courant",[147,164,165],{},"Les opérations courantes ont une API recommandée :",[167,168,169,182],"table",{},[170,171,172],"thead",{},[173,174,175,179],"tr",{},[176,177,178],"th",{},"Besoin",[176,180,181],{},"API",[183,184,185,199,211,223,234],"tbody",{},[173,186,187,191],{},[188,189,190],"td",{},"lire depuis une page",[188,192,193],{},[194,195,196],"a",{"href":102},[154,197,198],{},"useQuery",[173,200,201,204],{},[188,202,203],{},"modifier depuis une page",[188,205,206],{},[194,207,208],{"href":102},[154,209,210],{},"useCommand",[173,212,213,216],{},[188,214,215],{},"gérer un formulaire",[188,217,218],{},[194,219,220],{"href":106},[154,221,222],{},"useFormFor",[173,224,225,228],{},[188,226,227],{},"appeler depuis le serveur",[188,229,230],{},[194,231,232],{"href":114},[154,233,113],{},[173,235,236,239],{},[188,237,238],{},"valider une entrée",[188,240,241],{},[194,242,243],{"href":52},[154,244,245],{},"Entity.validate",[147,247,248],{},"Ces API partagent la même désignation par entité et opération. Elles transmettent aussi\nle contexte attendu par les collectors et normalisent les erreurs. Un appel assemblé à\nla main doit prendre ces responsabilités en charge explicitement.",[159,250,252],{"id":251},"comment-une-codebase-dérive","Comment une codebase dérive",[147,254,255],{},"Une dérive architecturale vient souvent de corrections locales raisonnables : une règle\najoutée dans un formulaire, puis dans une route, puis dans un adapter. Chaque modification\nrésout son problème immédiat, mais la règle n'a plus de propriétaire unique.",[147,257,258],{},"La convention de Fougere place les règles de champ dans les entités et les règles métier\ndans les opérations. Elle ne garantit pas que le modèle est correct, mais elle donne un\nemplacement commun aux éléments qui doivent évoluer ensemble.",[159,260,262],{"id":261},"lire-le-graphe","Lire le graphe",[147,264,265],{},"Le scanner connaît les Fronds, leurs entités et leurs références. La commande suivante\naffiche ces relations :",[267,268,273],"pre",{"className":269,"code":270,"language":271,"meta":272,"style":272},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","fougere graph\n","bash","",[154,274,275],{"__ignoreMap":272},[276,277,280,284],"span",{"class":278,"line":279},"line",1,[276,281,283],{"class":282},"sbgvK","fougere",[276,285,287],{"class":286},"s_sjI"," graph\n",[267,289,294],{"className":290,"code":292,"language":293,"meta":272},[291],"language-text","Post -> Author, Category (2 incoming)\nAuthor\n","text",[154,295,292],{"__ignoreMap":272},[147,297,298],{},"Ce graphe peut être lu selon trois dimensions :",[300,301,302,310,316],"ul",{},[303,304,305,309],"li",{},[306,307,308],"strong",{},"couplage"," : nombre de relations attachées à une entité ;",[303,311,312,315],{},[306,313,314],{},"duplication"," : endroits où une même règle est déclarée ;",[303,317,318,321],{},[306,319,320],{},"propriété"," : domaine responsable d'une règle ou d'une donnée.",[147,323,324],{},"La commande actuelle expose les relations et propose des regroupements au-delà de six\nentités. Elle ne mesure pas encore automatiquement la duplication ou la propriété. Une\nprésentation des écarts de graphe dans les pull requests reste une piste pour la CI.",[159,326,328],{"id":327},"des-erreurs-qui-indiquent-une-solution","Des erreurs qui indiquent une solution",[147,330,331,332,335],{},"Un garde-fou utile doit préciser l'usage détecté, le risque et l'API recommandée. La forme\nsuivante illustre le catalogue envisagé ; ",[154,333,334],{},"defineRefusal"," n'est pas une API livrée :",[267,337,341],{"className":338,"code":339,"language":340,"meta":272,"style":272},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","defineRefusal({\n  id: 'F-042',\n  detect: (site) => isHandRolledCallToFrond(site),\n  message: (site) => dedent`\n    Appel assemblé à la main vers la Frond ${site.frond}.\n    Cet appel ne transmet pas automatiquement l'identité et la locale.\n\n      -> invoke('${site.suggestion}')\n  `,\n  origin: 'incident : contexte oublié dans plusieurs routes',\n});\n","ts",[154,342,343,356,379,409,431,454,460,467,487,495,512],{"__ignoreMap":272},[276,344,345,348,352],{"class":278,"line":279},[276,346,334],{"class":347},"sGLFI",[276,349,351],{"class":350},"su5hD","(",[276,353,355],{"class":354},"sP7_E","{\n",[276,357,359,363,366,370,373,376],{"class":278,"line":358},2,[276,360,362],{"class":361},"skxfh","  id",[276,364,365],{"class":354},":",[276,367,369],{"class":368},"sjJ54"," '",[276,371,372],{"class":286},"F-042",[276,374,375],{"class":368},"'",[276,377,378],{"class":354},",\n",[276,380,382,385,387,390,394,397,401,404,407],{"class":278,"line":381},3,[276,383,384],{"class":347},"  detect",[276,386,365],{"class":354},[276,388,389],{"class":354}," (",[276,391,393],{"class":392},"s99_P","site",[276,395,396],{"class":354},")",[276,398,400],{"class":399},"sbsja"," =>",[276,402,403],{"class":347}," isHandRolledCallToFrond",[276,405,406],{"class":350},"(site)",[276,408,378],{"class":354},[276,410,412,415,417,419,421,423,425,428],{"class":278,"line":411},4,[276,413,414],{"class":347},"  message",[276,416,365],{"class":354},[276,418,389],{"class":354},[276,420,393],{"class":392},[276,422,396],{"class":354},[276,424,400],{"class":399},[276,426,427],{"class":347}," dedent",[276,429,430],{"class":368},"`\n",[276,432,434,437,440,442,445,448,451],{"class":278,"line":433},5,[276,435,436],{"class":286},"    Appel assemblé à la main vers la Frond ",[276,438,439],{"class":368},"${",[276,441,393],{"class":350},[276,443,444],{"class":368},".",[276,446,447],{"class":350},"frond",[276,449,450],{"class":368},"}",[276,452,453],{"class":286},".\n",[276,455,457],{"class":278,"line":456},6,[276,458,459],{"class":286},"    Cet appel ne transmet pas automatiquement l'identité et la locale.\n",[276,461,463],{"class":278,"line":462},7,[276,464,466],{"emptyLinePlaceholder":465},true,"\n",[276,468,470,473,475,477,479,482,484],{"class":278,"line":469},8,[276,471,472],{"class":286},"      -> invoke('",[276,474,439],{"class":368},[276,476,393],{"class":350},[276,478,444],{"class":368},[276,480,481],{"class":350},"suggestion",[276,483,450],{"class":368},[276,485,486],{"class":286},"')\n",[276,488,490,493],{"class":278,"line":489},9,[276,491,492],{"class":368},"  `",[276,494,378],{"class":354},[276,496,498,501,503,505,508,510],{"class":278,"line":497},10,[276,499,500],{"class":361},"  origin",[276,502,365],{"class":354},[276,504,369],{"class":368},[276,506,507],{"class":286},"incident : contexte oublié dans plusieurs routes",[276,509,375],{"class":368},[276,511,378],{"class":354},[276,513,515,517,519],{"class":278,"line":514},11,[276,516,450],{"class":354},[276,518,396],{"class":350},[276,520,521],{"class":354},";\n",[147,523,524,525,528],{},"Ces erreurs de build seraient distinctes des\n",[194,526,527],{"href":85},"erreurs métier"," renvoyées au runtime.",[159,530,532],{"id":531},"limite","Limite",[147,534,535],{},"Fougere peut vérifier la structure d'une déclaration, pas sa pertinence métier. Une règle\nincorrecte reste incorrecte même lorsqu'elle est déclarée une seule fois. Le choix des\nconcepts et de leurs frontières reste une décision de conception.",[147,537,538,539,444],{},"Suite : ",[194,540,541],{"href":52},"Les entités",[543,544,545],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":272,"searchDepth":358,"depth":358,"links":547},[548,549,550,551,552],{"id":161,"depth":358,"text":162},{"id":251,"depth":358,"text":252},{"id":261,"depth":358,"text":262},{"id":327,"depth":358,"text":328},{"id":531,"depth":358,"text":532},"Les conventions de Fougere, le graphe disponible et les garde-fous encore à l'étude.","md",{},{"title":41,"description":553},"7Wl0nfJ8zpHE2KRmD6b7NB-U-WwY2HnVSUnBgkEWohA",1786637820094]