[{"data":1,"prerenderedAt":673},["ShallowReactive",2],{"docs-nav:fr":3,"docs:\u002Ffr\u002Fdocs\u002Finfra\u002Fdeployment":189},[4],{"title":5,"path":6,"stem":7,"children":8,"page":52},"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,31,53,78,123,148],{"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},"Une app que vous avez déjà","\u002Ffr\u002Fdocs\u002Fexisting-app","fr\u002Fdocs\u002F02.existing-app",{"title":24,"path":25,"stem":26},"Apportez votre schéma","\u002Ffr\u002Fdocs\u002Fbring-your-schema","fr\u002Fdocs\u002F03.bring-your-schema",{"title":28,"path":29,"stem":30},"La CLI","\u002Ffr\u002Fdocs\u002Fcli","fr\u002Fdocs\u002F04.cli",{"title":32,"path":33,"stem":34,"children":35,"page":52},"Concepts","\u002Ffr\u002Fdocs\u002Fconcepts","fr\u002Fdocs\u002F2.concepts",[36,40,44,48],{"title":37,"path":38,"stem":39},"Philosophie","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fphilosophy","fr\u002Fdocs\u002F2.concepts\u002F1.philosophy",{"title":41,"path":42,"stem":43},"La Frond","\u002Ffr\u002Fdocs\u002Fconcepts\u002Ffrond","fr\u002Fdocs\u002F2.concepts\u002F2.frond",{"title":45,"path":46,"stem":47},"Le chemin le plus court","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fshortest-path","fr\u002Fdocs\u002F2.concepts\u002F3.shortest-path",{"title":49,"path":50,"stem":51},"Le socle","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fthe-base","fr\u002Fdocs\u002F2.concepts\u002F4.the-base",false,{"title":54,"path":55,"stem":56,"children":57,"page":52},"Schéma","\u002Ffr\u002Fdocs\u002Fschema","fr\u002Fdocs\u002F3.schema",[58,62,66,70,74],{"title":59,"path":60,"stem":61},"Entités","\u002Ffr\u002Fdocs\u002Fschema\u002Fentities","fr\u002Fdocs\u002F3.schema\u002F1.entities",{"title":63,"path":64,"stem":65},"Vues","\u002Ffr\u002Fdocs\u002Fschema\u002Fviews","fr\u002Fdocs\u002F3.schema\u002F2.views",{"title":67,"path":68,"stem":69},"La carte d'identité","\u002Ffr\u002Fdocs\u002Fschema\u002Fcard","fr\u002Fdocs\u002F3.schema\u002F3.card",{"title":71,"path":72,"stem":73},"Standard Schema","\u002Ffr\u002Fdocs\u002Fschema\u002Fstandard-schema","fr\u002Fdocs\u002F3.schema\u002F4.standard-schema",{"title":75,"path":76,"stem":77},"Comment un schéma bouge","\u002Ffr\u002Fdocs\u002Fschema\u002Fevolution","fr\u002Fdocs\u002F3.schema\u002F5.evolution",{"title":79,"path":80,"stem":81,"children":82,"page":52},"Métier","\u002Ffr\u002Fdocs\u002Fbusiness","fr\u002Fdocs\u002F4.business",[83,87,91,95,99,103,107,111,115,119],{"title":84,"path":85,"stem":86},"Handlers","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fhandlers","fr\u002Fdocs\u002F4.business\u002F1.handlers",{"title":88,"path":89,"stem":90},"Les ports","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fports","fr\u002Fdocs\u002F4.business\u002F10.ports",{"title":92,"path":93,"stem":94},"Presenters","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fpresenters","fr\u002Fdocs\u002F4.business\u002F2.presenters",{"title":96,"path":97,"stem":98},"Collectors","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fcollectors","fr\u002Fdocs\u002F4.business\u002F3.collectors",{"title":100,"path":101,"stem":102},"Erreurs","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ferrors","fr\u002Fdocs\u002F4.business\u002F4.errors",{"title":104,"path":105,"stem":106},"Seeds","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fseeds","fr\u002Fdocs\u002F4.business\u002F5.seeds",{"title":108,"path":109,"stem":110},"Les faits","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ffacts","fr\u002Fdocs\u002F4.business\u002F6.facts",{"title":112,"path":113,"stem":114},"Le port Storage","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fstorage","fr\u002Fdocs\u002F4.business\u002F7.storage",{"title":116,"path":117,"stem":118},"Des écritures qui tiennent ou tombent ensemble","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ftogether","fr\u002Fdocs\u002F4.business\u002F8.together",{"title":120,"path":121,"stem":122},"Les repositories","\u002Ffr\u002Fdocs\u002Fbusiness\u002Frepositories","fr\u002Fdocs\u002F4.business\u002F9.repositories",{"title":124,"path":125,"stem":126,"children":127,"page":52},"Client","\u002Ffr\u002Fdocs\u002Fclient","fr\u002Fdocs\u002F5.client",[128,132,136,140,144],{"title":129,"path":130,"stem":131},"Queries & commands","\u002Ffr\u002Fdocs\u002Fclient\u002Fqueries-commands","fr\u002Fdocs\u002F5.client\u002F1.queries-commands",{"title":133,"path":134,"stem":135},"Formulaires","\u002Ffr\u002Fdocs\u002Fclient\u002Fforms","fr\u002Fdocs\u002F5.client\u002F2.forms",{"title":137,"path":138,"stem":139},"Session","\u002Ffr\u002Fdocs\u002Fclient\u002Fsession","fr\u002Fdocs\u002F5.client\u002F3.session",{"title":141,"path":142,"stem":143},"invoke","\u002Ffr\u002Fdocs\u002Fclient\u002Finvoke","fr\u002Fdocs\u002F5.client\u002F4.invoke",{"title":145,"path":146,"stem":147},"Back-office","\u002Ffr\u002Fdocs\u002Fclient\u002Fadmin","fr\u002Fdocs\u002F5.client\u002F5.admin",{"title":149,"path":150,"stem":151,"children":152,"page":52},"Infrastructure","\u002Ffr\u002Fdocs\u002Finfra","fr\u002Fdocs\u002F6.infra",[153,157,161,165,169,173,177,181,185],{"title":154,"path":155,"stem":156},"Le gradient","\u002Ffr\u002Fdocs\u002Finfra\u002Fgradient","fr\u002Fdocs\u002F6.infra\u002F1.gradient",{"title":158,"path":159,"stem":160},"Surfaces — REST & GraphQL","\u002Ffr\u002Fdocs\u002Finfra\u002Fsurfaces","fr\u002Fdocs\u002F6.infra\u002F2.surfaces",{"title":162,"path":163,"stem":164},"Déploiement","\u002Ffr\u002Fdocs\u002Finfra\u002Fdeployment","fr\u002Fdocs\u002F6.infra\u002F3.deployment",{"title":166,"path":167,"stem":168},"Hôtes","\u002Ffr\u002Fdocs\u002Finfra\u002Fhosts","fr\u002Fdocs\u002F6.infra\u002F4.hosts",{"title":170,"path":171,"stem":172},"Les sources","\u002Ffr\u002Fdocs\u002Finfra\u002Fsources","fr\u002Fdocs\u002F6.infra\u002F5.sources",{"title":174,"path":175,"stem":176},"Le cycle de vie","\u002Ffr\u002Fdocs\u002Finfra\u002Flifecycle","fr\u002Fdocs\u002F6.infra\u002F6.lifecycle",{"title":178,"path":179,"stem":180},"L'identité entre Fronds","\u002Ffr\u002Fdocs\u002Finfra\u002Fidentity","fr\u002Fdocs\u002F6.infra\u002F7.identity",{"title":182,"path":183,"stem":184},"Observabilité","\u002Ffr\u002Fdocs\u002Finfra\u002Fobservability","fr\u002Fdocs\u002F6.infra\u002F8.observability",{"title":186,"path":187,"stem":188},"Tests","\u002Ffr\u002Fdocs\u002Finfra\u002Ftesting","fr\u002Fdocs\u002F6.infra\u002F9.testing",{"id":190,"title":162,"body":191,"description":668,"extension":669,"meta":670,"navigation":514,"path":163,"seo":671,"stem":164,"__hash__":672},"docs_fr\u002Ffr\u002Fdocs\u002F6.infra\u002F3.deployment.md",{"type":192,"value":193,"toc":663},"minimark",[194,198,207,212,340,347,357,361,372,442,445,576,587,591,607,625,643,653,659],[195,196,162],"h1",{"id":197},"déploiement",[199,200,201,202,206],"p",{},"Une app Fougere est une app Nitro plus une chose que Nitro ignore : ",[203,204,205],"strong",{},"les sources des\nFronds sont lues au runtime"," (scan, parse AST, chargement jiti). Cette page est ce que le\ndéploiement de ce site même a appris — la checklist, puis la réalisation Docker.",[208,209,211],"h2",{"id":210},"la-checklist-runtime","La checklist runtime",[213,214,215,229,275,295,301,311,326],"ol",{},[216,217,218,224,225,228],"li",{},[203,219,220],{},[221,222,223],"code",{},".output\u002F"," — le build Nitro (",[221,226,227],{},"pnpm build",").",[216,230,231,234,235,238,239,242,243,246,247,250,251,250,254,257,258,250,261,250,264,250,267,270,271,274],{},[203,232,233],{},"Les sources des Fronds"," — à côté de ",[221,236,237],{},".output"," : le scanner les lit depuis\n",[221,240,241],{},"process.cwd()"," au boot. ",[221,244,245],{},"fronds\u002F**\u002F*.ts",", et quand la racine est elle-même la Frond,\nles dossiers de la convention à la racine (",[221,248,249],{},"entities\u002F",", ",[221,252,253],{},"handlers\u002F",[221,255,256],{},"presenters\u002F",",\n",[221,259,260],{},"collectors\u002F",[221,262,263],{},"seeds\u002F",[221,265,266],{},"services\u002F",[221,268,269],{},"repositories\u002F","). Ne copier que ",[221,272,273],{},"fronds\u002F"," laisse\nune app à plat sans domaine et sans erreur — voir le log de boot plus bas.",[216,276,277,280,281,250,284,250,287,290,291,294],{},[203,278,279],{},"Un node_modules résoluble pour les fronds"," — ces sources importent\n",[221,282,283],{},"@fougere\u002Fschema",[221,285,286],{},"@fougere\u002Fcore",[221,288,289],{},"better-auth","… par leur nom. ",[221,292,293],{},"pnpm deploy --prod","\nproduit exactement cette fermeture ; trier les paquets à la main, c'est réimplémenter\nun tracer — non.",[216,296,297,300],{},[203,298,299],{},"Un TS avec l'API JS du compilateur"," (5.9 — TS 7 n'en a pas) — importé dynamiquement\npar le scanner, invisible au tracer de Nitro.",[216,302,303,306,307,310],{},[203,304,305],{},"Des paquets lazy complets"," — la trace pnpm de Nitro pour ",[221,308,309],{},"jiti"," est partielle\n(sa transformation babel est chargée à la demande). Le remplacer par le vrai paquet.",[216,312,313,320,321,325],{},[203,314,315,316,319],{},"Un ",[221,317,318],{},".data\u002F"," writable"," — le fichier SQLite et l'index Nuxt Content y vivent. C'est\nla ",[322,323,324],"em",{},"seule"," chose à persister : un volume.",[216,327,328,331,332,335,336,339],{},[203,329,330],{},"Les secrets par env"," — ",[221,333,334],{},"SITE_AUTH_SECRET"," (32+ caractères), le ",[221,337,338],{},"SITE_URL"," public.",[199,341,342,343,346],{},"Le signal de vérification est le log de boot — ",[203,344,345],{},"pas"," un 200 sur les pages (le SSR rend\ntrès bien avec zéro frond chargée) :",[348,349,354],"pre",{"className":350,"code":352,"language":353},[351],"language-text","INF [boot:app] scanned 2 frond(s) in 467ms      ← cette ligne\n{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":[]}            ← et un appel d'enveloppe\n","text",[221,355,352],{"__ignoreMap":356},"",[208,358,360],{"id":359},"docker","Docker",[199,362,363,364,367,368,371],{},"Le site livre une paire qui marche — ",[221,365,366],{},"site\u002FDockerfile"," + ",[221,369,370],{},"site\u002Fdocker-compose.yml"," :",[348,373,377],{"className":374,"code":375,"language":376,"meta":356,"style":356},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","SITE_AUTH_SECRET='…32+ caractères…' SITE_URL='https:\u002F\u002Fvotre-domaine' \\\n  docker compose -f site\u002Fdocker-compose.yml up -d --build\n","bash",[221,378,379,417],{"__ignoreMap":356},[380,381,384,387,391,395,399,401,404,406,408,411,413],"span",{"class":382,"line":383},"line",1,[380,385,334],{"class":386},"su5hD",[380,388,390],{"class":389},"smGrS","=",[380,392,394],{"class":393},"sjJ54","'",[380,396,398],{"class":397},"s_sjI","…32+ caractères…",[380,400,394],{"class":393},[380,402,403],{"class":386}," SITE_URL",[380,405,390],{"class":389},[380,407,394],{"class":393},[380,409,410],{"class":397},"https:\u002F\u002Fvotre-domaine",[380,412,394],{"class":393},[380,414,416],{"class":415},"sbgvK"," \\\n",[380,418,420,423,426,430,433,436,439],{"class":382,"line":419},2,[380,421,422],{"class":397},"  docker",[380,424,425],{"class":397}," compose",[380,427,429],{"class":428},"stzsN"," -f",[380,431,432],{"class":397}," site\u002Fdocker-compose.yml",[380,434,435],{"class":397}," up",[380,437,438],{"class":428}," -d",[380,440,441],{"class":428}," --build\n",[199,443,444],{},"Le Dockerfile réalise la checklist en deux étages :",[348,446,450],{"className":447,"code":448,"language":449,"meta":356,"style":356},"language-dockerfile shiki shiki-themes material-theme-lighter github-light github-dark","# étage build : install workspace → build packages → build site\nRUN pnpm --filter \".\u002Fpackages\u002F**\" -r run build \\\n && pnpm --filter \"@fougere\u002Fsite\" run build\n# la fermeture de résolution des fronds, par pnpm lui-même :\nRUN pnpm --filter \"@fougere\u002Fsite\" deploy --prod --legacy \u002Fdeploy\n# compléter la trace partielle de jiti + ajouter TS 5.9\n\n# étage run : node:22-slim, non-root\nCOPY --from=build \u002Frepo\u002Fsite\u002F.output .\u002F.output\nCOPY --from=build \u002Frepo\u002Fsite\u002Ffronds  .\u002Ffronds\nCOPY --from=build \u002Fdeploy\u002Fnode_modules .\u002Fnode_modules\nVOLUME \u002Fapp\u002F.data\nCMD [\"node\", \".output\u002Fserver\u002Findex.mjs\"]\n","dockerfile",[221,451,452,458,473,485,491,503,509,516,522,531,539,547,556],{"__ignoreMap":356},[380,453,454],{"class":382,"line":383},[380,455,457],{"class":456},"sutJx","# étage build : install workspace → build packages → build site\n",[380,459,460,464,467,470],{"class":382,"line":419},[380,461,463],{"class":462},"sw1J6","RUN",[380,465,466],{"class":386}," pnpm --filter ",[380,468,469],{"class":397},"\".\u002Fpackages\u002F**\"",[380,471,472],{"class":386}," -r run build \\\n",[380,474,476,479,482],{"class":382,"line":475},3,[380,477,478],{"class":386}," && pnpm --filter ",[380,480,481],{"class":397},"\"@fougere\u002Fsite\"",[380,483,484],{"class":386}," run build\n",[380,486,488],{"class":382,"line":487},4,[380,489,490],{"class":456},"# la fermeture de résolution des fronds, par pnpm lui-même :\n",[380,492,494,496,498,500],{"class":382,"line":493},5,[380,495,463],{"class":462},[380,497,466],{"class":386},[380,499,481],{"class":397},[380,501,502],{"class":386}," deploy --prod --legacy \u002Fdeploy\n",[380,504,506],{"class":382,"line":505},6,[380,507,508],{"class":456},"# compléter la trace partielle de jiti + ajouter TS 5.9\n",[380,510,512],{"class":382,"line":511},7,[380,513,515],{"emptyLinePlaceholder":514},true,"\n",[380,517,519],{"class":382,"line":518},8,[380,520,521],{"class":456},"# étage run : node:22-slim, non-root\n",[380,523,525,528],{"class":382,"line":524},9,[380,526,527],{"class":462},"COPY",[380,529,530],{"class":386}," --from=build \u002Frepo\u002Fsite\u002F.output .\u002F.output\n",[380,532,534,536],{"class":382,"line":533},10,[380,535,527],{"class":462},[380,537,538],{"class":386}," --from=build \u002Frepo\u002Fsite\u002Ffronds  .\u002Ffronds\n",[380,540,542,544],{"class":382,"line":541},11,[380,543,527],{"class":462},[380,545,546],{"class":386}," --from=build \u002Fdeploy\u002Fnode_modules .\u002Fnode_modules\n",[380,548,550,553],{"class":382,"line":549},12,[380,551,552],{"class":462},"VOLUME",[380,554,555],{"class":386}," \u002Fapp\u002F.data\n",[380,557,559,562,565,568,570,573],{"class":382,"line":558},13,[380,560,561],{"class":462},"CMD",[380,563,564],{"class":386}," [",[380,566,567],{"class":397},"\"node\"",[380,569,250],{"class":386},[380,571,572],{"class":397},"\".output\u002Fserver\u002Findex.mjs\"",[380,574,575],{"class":386},"]\n",[199,577,578,579,582,583,586],{},"L'état vit dans le volume ",[221,580,581],{},"site-data"," monté sur ",[221,584,585],{},"\u002Fapp\u002F.data"," — un backup est une copie de\nfichier.",[208,588,590],{"id":589},"splitter-en-production","Splitter en production",[199,592,593,594,597,598,601,602,606],{},"Le même modèle d'image s'applique au split : le process host qui sert une Frond a besoin\ndes points 1–5 pour ",[322,595,596],{},"ses"," fronds, et le consommateur la déclare dans ",[221,599,600],{},"remotes",". Un host\nmort dégrade en 503 typées dans les pages\n(",[603,604,154],"a",{"href":605},"\u002Ffr\u002Fdocs\u002Finfra\u002Fgradient#comportement-apr%C3%A8s-s%C3%A9paration",") ; le relancer est la\nrécupération — le consommateur n'est jamais rebuildé.",[199,608,609,610,613,614,616,617,620,621,624],{},"Trois choses s'appellent « ensemble » et une seule est obligatoire. Le ",[203,611,612],{},"contrat"," doit\nvoyager — le consommateur doit savoir ce que l'hôte sert. Le ",[203,615,221],{},", non : ",[221,618,619],{},"fougere sync","\nlit la carte d'identité de l'hôte et reconstruit un schéma vivant en local, ce qui est\nd'ailleurs la seule façon de consommer une Frond écrite dans un autre langage. Les\n",[203,622,623],{},"ports"," doivent se joindre, et c'est le seul des trois qu'un déploiement décide.",[199,626,627,628,631,632,635,636,639,640,642],{},"Le récepteur écoute en loopback sauf mention contraire : le split le plus simple met donc\nles deux process sur une même machine — le même pod, ou une seule image. ",[221,629,630],{},"hosts: ['0.0.0.0']"," l'élargit en une ligne, et un récepteur élargi ainsi doit pouvoir établir son\nappelant, sinon il ne démarre pas. C'est un sixième point à la liste ci-dessus : ",[221,633,634],{},"fougere keys"," une fois pour le système, ",[221,637,638],{},"fougere grant \u003Cfrond>"," pour chaque Frond qui appelle, et\ntrois variables d'environnement injectées au lancement — voir\n",[603,641,178],{"href":179},".",[644,645,646],"blockquote",{},[199,647,648,649,652],{},"Ces étapes sont candidates à un futur ",[221,650,651],{},"fougere build"," — un utilisateur ne devrait pas\navoir à les découvrir. D'ici là, cette page est le contrat.",[199,654,655,656,642],{},"Ce qu'un process déployé fait en partant — drainer les appels en cours avant de fermer sa\nconnexion — est une page plus loin : ",[603,657,658],{"href":175},"le cycle de vie",[660,661,662],"style",{},"html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}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 .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--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);}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sw1J6, html code.shiki .sw1J6{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":356,"searchDepth":419,"depth":419,"links":664},[665,666,667],{"id":210,"depth":419,"text":211},{"id":359,"depth":419,"text":360},{"id":589,"depth":419,"text":590},"Ce qu'une app Fougere exige au runtime — appris en déployant ce site.","md",{},{"title":162,"description":668},"VadFDin3SDwmTYP09zuyZiu1qHIxqi_huwlJ_rASEuY",1788598419545]