[{"data":1,"prerenderedAt":657},["ShallowReactive",2],{"docs-nav:fr":3,"docs:\u002Ffr\u002Fdocs\u002Fconcepts\u002Ffrond":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":37,"body":139,"description":651,"extension":652,"meta":653,"navigation":654,"path":38,"seo":655,"stem":39,"__hash__":656},"docs_fr\u002Ffr\u002Fdocs\u002F2.concepts\u002F2.frond.md",{"type":140,"value":141,"toc":643},"minimark",[142,146,155,160,163,220,223,227,230,335,342,346,349,395,398,402,413,432,437,460,467,586,606,626,639],[143,144,37],"h1",{"id":145},"la-frond",[147,148,149,150,154],"p",{},"Une ",[151,152,153],"strong",{},"Frond"," est un module métier qui regroupe les éléments responsables d'un même\ndomaine.",[156,157,159],"h2",{"id":158},"la-frontière-de-propriété","La frontière de propriété",[147,161,162],{},"Une Frond contient :",[164,165,166,174,185,191,202,208,214],"ul",{},[167,168,169,170,173],"li",{},"ses ",[151,171,172],{},"entités"," et schémas,",[167,175,169,176,179,180,184],{},[151,177,178],{},"opérations"," — commands et queries (",[181,182,183],"a",{"href":73},"handlers","),",[167,186,169,187,190],{},[151,188,189],{},"policies"," — les règles d'accès vérifiées dans les opérations,",[167,192,169,193,196,197,201],{},[151,194,195],{},"events"," — les faits que ses commands produisent (",[181,198,200],{"href":199},"\u002Ffr\u002Fdocs\u002Fbusiness\u002Fhandlers#le-bus-devents","un bus in-process",", auquel rien ne s'abonne par défaut),",[167,203,169,204,207],{},[151,205,206],{},"adapters de persistance"," — comment ses entités se réalisent,",[167,209,169,210,213],{},[151,211,212],{},"contrats publics"," — ce que les autres Fronds peuvent appeler,",[167,215,169,216,219],{},[151,217,218],{},"règles d'invalidation"," — ce qu'une command revalide.",[147,221,222],{},"Une Frond n'importe pas les fichiers internes d'une autre. Les interactions passent par\ndes contrats explicites, de préférence des opérations ou des events. Une App compose les\nFronds et conserve la logique métier dans ces modules plutôt que dans ses pages, fetchs\nou stores.",[156,224,226],{"id":225},"les-six-couches","Les six couches",[147,228,229],{},"Le modèle suit six étapes :",[231,232,233,249],"table",{},[234,235,236],"thead",{},[237,238,239,243,246],"tr",{},[240,241,242],"th",{},"#",[240,244,245],{},"Couche",[240,247,248],{},"Ce qui s'y passe",[250,251,252,266,279,292,305,318],"tbody",{},[237,253,254,258,263],{},[255,256,257],"td",{},"1",[255,259,260],{},[151,261,262],{},"Déclaration",[255,264,265],{},"l'auteur déclare entités, vues, opérations, events — ni HTTP ni SQL ici",[237,267,268,271,276],{},[255,269,270],{},"2",[255,272,273],{},[151,274,275],{},"Dérivation",[255,277,278],{},"validation, types, vues io, metadata lisible par les adapters en dérivent",[237,280,281,284,289],{},[255,282,283],{},"3",[255,285,286],{},[151,287,288],{},"Capacité locale",[255,290,291],{},"la déclaration devient exécutable in-process — le mode de référence",[237,293,294,297,302],{},[255,295,296],{},"4",[255,298,299],{},[151,300,301],{},"Projection",[255,303,304],{},"des façades sont générées vers les transports : HTTP, GraphQL, CLI, workers",[237,306,307,310,315],{},[255,308,309],{},"5",[255,311,312],{},[151,313,314],{},"Composition",[255,316,317],{},"les Fronds sont scannées et reliées dans un runtime — module → contrat → interaction",[237,319,320,323,328],{},[255,321,322],{},"6",[255,324,325],{},[151,326,327],{},"Distribution",[255,329,330,331,334],{},"une capacité part hors process ; sérialisation, timeouts, retries apparaissent ",[151,332,333],{},"ici",", explicitement",[147,336,337,338,341],{},"La ",[181,339,340],{"href":123},"page sur le gradient"," décrit le passage de l'exécution locale\nà l'exécution distante.",[156,343,345],{"id":344},"généré-vs-écrit-à-la-main","Généré vs écrit à la main",[147,347,348],{},"La répartition est la suivante :",[231,350,351,361],{},[234,352,353],{},[237,354,355,358],{},[240,356,357],{},"Fougere génère",[240,359,360],{},"Vous écrivez",[250,362,363,371,379,387],{},[237,364,365,368],{},[255,366,367],{},"validation, vues dérivées, tables\u002Fmetadata",[255,369,370],{},"la logique métier non triviale",[237,372,373,376],{},[255,374,375],{},"types et inputs GraphQL, CRUD trivial",[255,377,378],{},"les invariants riches, les workflows multi-étapes",[237,380,381,384],{},[255,382,383],{},"les façades de projection (contrat → transport)",[255,385,386],{},"les politiques d'erreur, les décisions de cohérence",[237,388,389,392],{},[255,390,391],{},"les clients typés, les manifests de composition",[255,393,394],{},"l'orchestration inter-Fronds sensible",[147,396,397],{},"Fougere prend en charge les intégrations répétitives autour d'un contrat. Le développeur\nécrit le comportement propre à l'application. Une couche service reste optionnelle : un\nhandler peut contenir la logique ou la déléguer.",[156,399,401],{"id":400},"dans-le-système-de-fichiers","Dans le système de fichiers",[403,404,409],"pre",{"className":405,"code":407,"language":408},[406],"language-text","fronds\u002Fblog\u002F\n  entities\u002F             ← les déclarations\n  handlers\u002F             ← les opérations   (handlers\u002F\u003Csurface>\u002F = une audience nommée)\n  presenters\u002F           ← les champs calculés ajoutés à la sortie d'une entité\n  collectors\u002F           ← la résolution de paramètres par type\n  services\u002F             ← des classes ordinaires, injectées par type\n  repositories\u002F         ← la même chose, sous un second nom\n  seeds\u002F                ← les données créées au démarrage\n","text",[410,411,407],"code",{"__ignoreMap":412},"",[147,414,415,416,419,420,423,424,428,429,431],{},"Le scanner reconnaît une Frond à ces dossiers. La ",[151,417,418],{},"racine du projet"," peut suivre la\nmême convention : une app avec un seul domaine n'a alors pas besoin de répertoire\n",[410,421,422],{},"fronds\u002F"," (",[181,425,427],{"href":426},"\u002Ffr\u002Fdocs\u002Fgetting-started#un-seul-domaine-pas-de-fronds-du-tout","la forme à plat",").\nUn deuxième domaine peut ensuite être ajouté sous ",[410,430,422],{}," sans déplacer le premier.",[433,434,436],"h3",{"id":435},"nommer-et-importer-une-frond","Nommer et importer une Frond",[147,438,439,440,443,444,447,448,451,452,455,456,459],{},"Le nom du dossier est le nom de la Frond, et ",[410,441,442],{},"@fougere\u002Fnuxt"," en fait un alias :\n",[410,445,446],{},"fronds\u002Fblog\u002F"," donne ",[410,449,450],{},"@frond\u002Fblog",", donc une page écrit\n",[410,453,454],{},"import Post from '@frond\u002Fblog\u002Fentities\u002FPost'"," sans aucun fichier à ajouter. Ce nom sert\naussi de clé aux enregistrements d'entités et à toute entrée ",[410,457,458],{},"remotes:",".",[147,461,462,463,466],{},"Un ",[410,464,465],{},"package.json"," dans la Frond répond aux deux questions que le dossier ne sait pas dire.",[403,468,472],{"className":469,"code":470,"language":471,"meta":412,"style":412},"language-json shiki shiki-themes material-theme-lighter github-light github-dark","{\n  \"name\": \"@frond\u002Fblog\",\n  \"fougere\": { \"frond\": \"blog\" },\n  \"exports\": { \".\u002Fentities\u002F*\": \".\u002Fentities\u002F*.ts\" }\n}\n","json",[410,473,474,483,512,547,580],{"__ignoreMap":412},[475,476,479],"span",{"class":477,"line":478},"line",1,[475,480,482],{"class":481},"sP7_E","{\n",[475,484,486,490,494,497,500,504,507,509],{"class":477,"line":485},2,[475,487,489],{"class":488},"s39Yj","  \"",[475,491,493],{"class":492},"sseR_","name",[475,495,496],{"class":488},"\"",[475,498,499],{"class":481},":",[475,501,503],{"class":502},"sjJ54"," \"",[475,505,450],{"class":506},"s_sjI",[475,508,496],{"class":502},[475,510,511],{"class":481},",\n",[475,513,515,517,520,522,524,527,529,533,535,537,539,542,544],{"class":477,"line":514},3,[475,516,489],{"class":488},[475,518,519],{"class":492},"fougere",[475,521,496],{"class":488},[475,523,499],{"class":481},[475,525,526],{"class":481}," {",[475,528,503],{"class":488},[475,530,532],{"class":531},"sZMiF","frond",[475,534,496],{"class":488},[475,536,499],{"class":481},[475,538,503],{"class":502},[475,540,541],{"class":506},"blog",[475,543,496],{"class":502},[475,545,546],{"class":481}," },\n",[475,548,550,552,555,557,559,561,563,566,568,570,572,575,577],{"class":477,"line":549},4,[475,551,489],{"class":488},[475,553,554],{"class":492},"exports",[475,556,496],{"class":488},[475,558,499],{"class":481},[475,560,526],{"class":481},[475,562,503],{"class":488},[475,564,565],{"class":531},".\u002Fentities\u002F*",[475,567,496],{"class":488},[475,569,499],{"class":481},[475,571,503],{"class":502},[475,573,574],{"class":506},".\u002Fentities\u002F*.ts",[475,576,496],{"class":502},[475,578,579],{"class":481}," }\n",[475,581,583],{"class":477,"line":582},5,[475,584,585],{"class":481},"}\n",[147,587,588,591,592,595,596,598,599,602,603,605],{},[410,589,590],{},"fougere.frond"," permet d'utiliser un nom différent de celui du dossier. Par exemple,\n",[410,593,594],{},"fronds\u002Fblog-v2\u002F"," peut rester enregistrée sous le nom ",[410,597,541],{},", ce qui conserve ses clés\nd'entité, ses imports ",[410,600,601],{},"@frond\u002F*"," et ses entrées ",[410,604,458],{},". Sans cette propriété, Fougere\nutilise le nom du dossier.",[147,607,608,610,611,613,614,617,618,621,622,625],{},[410,609,493],{}," et ",[410,612,554],{}," rendent la Frond résolvable ",[151,615,616],{},"en dehors"," d'une app Nuxt — un script\nNode, un consommateur non-Nuxt — ce qui demande aussi de la déclarer comme paquet du\nworkspace (",[410,619,620],{},"packages: [fronds\u002F*]"," dans ",[410,623,624],{},"pnpm-workspace.yaml","). Dans une app Nuxt, l'alias\nsuffit.",[147,627,628,610,631,634,635,638],{},[410,629,630],{},"services\u002F",[410,632,633],{},"repositories\u002F"," se comportent à l'identique : les deux enregistrent leurs\nclasses comme providers, résolus par type. La plupart des accès data n'ont besoin ni de\nl'un ni de l'autre — le handler reçoit déjà un ",[410,636,637],{},"EntityOrm"," scopé à son entité. On prend un\nprovider quand la lecture ne rentre pas dans cette forme : un agrégat sur plusieurs\nentités, une source qui n'est pas un ORM (une API externe, un index de recherche), ou une\nrequête assez lourde pour que le handler n'ait pas à la porter.",[640,641,642],"style",{},"html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sseR_, html code.shiki .sseR_{--shiki-light:#9C3EDA;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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);}",{"title":412,"searchDepth":485,"depth":485,"links":644},[645,646,647,648],{"id":158,"depth":485,"text":159},{"id":225,"depth":485,"text":226},{"id":344,"depth":485,"text":345},{"id":400,"depth":485,"text":401,"children":649},[650],{"id":435,"depth":514,"text":436},"Ce qu'une Frond contient, comment elle est découverte et où se situe sa frontière.","md",{},true,{"title":37,"description":651},"AuE6IyMmZIQJlQ0dNEbA9xQtnERD5iusBn3srbhUG7c",1786637819625]