[{"data":1,"prerenderedAt":605},["ShallowReactive",2],{"docs-nav:fr":3,"docs:\u002Ffr\u002Fdocs\u002Finfra\u002Fdeployment":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":130,"body":139,"description":600,"extension":601,"meta":602,"navigation":463,"path":131,"seo":603,"stem":132,"__hash__":604},"docs_fr\u002Ffr\u002Fdocs\u002F6.infra\u002F3.deployment.md",{"type":140,"value":141,"toc":595},"minimark",[142,146,155,160,288,295,305,309,320,391,394,525,536,540,556,574,581,591],[143,144,130],"h1",{"id":145},"déploiement",[147,148,149,150,154],"p",{},"Une app Fougere est une app Nitro plus une chose que Nitro ignore : ",[151,152,153],"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.",[156,157,159],"h2",{"id":158},"la-checklist-runtime","La checklist runtime",[161,162,163,177,223,243,249,259,274],"ol",{},[164,165,166,172,173,176],"li",{},[151,167,168],{},[169,170,171],"code",{},".output\u002F"," — le build Nitro (",[169,174,175],{},"pnpm build",").",[164,178,179,182,183,186,187,190,191,194,195,198,199,198,202,205,206,198,209,198,212,198,215,218,219,222],{},[151,180,181],{},"Les sources des Fronds"," — à côté de ",[169,184,185],{},".output"," : le scanner les lit depuis\n",[169,188,189],{},"process.cwd()"," au boot. ",[169,192,193],{},"fronds\u002F**\u002F*.ts",", et quand la racine est elle-même la Frond,\nles dossiers de la convention à la racine (",[169,196,197],{},"entities\u002F",", ",[169,200,201],{},"handlers\u002F",[169,203,204],{},"presenters\u002F",",\n",[169,207,208],{},"collectors\u002F",[169,210,211],{},"seeds\u002F",[169,213,214],{},"services\u002F",[169,216,217],{},"repositories\u002F","). Ne copier que ",[169,220,221],{},"fronds\u002F"," laisse\nune app à plat sans domaine et sans erreur — voir le log de boot plus bas.",[164,224,225,228,229,198,232,198,235,238,239,242],{},[151,226,227],{},"Un node_modules résoluble pour les fronds"," — ces sources importent\n",[169,230,231],{},"@fougere\u002Fschema",[169,233,234],{},"@fougere\u002Fcore",[169,236,237],{},"better-auth","… par leur nom. ",[169,240,241],{},"pnpm deploy --prod","\nproduit exactement cette fermeture ; trier les paquets à la main, c'est réimplémenter\nun tracer — non.",[164,244,245,248],{},[151,246,247],{},"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.",[164,250,251,254,255,258],{},[151,252,253],{},"Des paquets lazy complets"," — la trace pnpm de Nitro pour ",[169,256,257],{},"jiti"," est partielle\n(sa transformation babel est chargée à la demande). Le remplacer par le vrai paquet.",[164,260,261,268,269,273],{},[151,262,263,264,267],{},"Un ",[169,265,266],{},".data\u002F"," writable"," — le fichier SQLite et l'index Nuxt Content y vivent. C'est\nla ",[270,271,272],"em",{},"seule"," chose à persister : un volume.",[164,275,276,279,280,283,284,287],{},[151,277,278],{},"Les secrets par env"," — ",[169,281,282],{},"AUTH_SECRET"," (32+ caractères), le ",[169,285,286],{},"SITE_URL"," public.",[147,289,290,291,294],{},"Le signal de vérification est le log de boot — ",[151,292,293],{},"pas"," un 200 sur les pages (le SSR rend\ntrès bien avec zéro frond chargée) :",[296,297,302],"pre",{"className":298,"code":300,"language":301},[299],"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",[169,303,300],{"__ignoreMap":304},"",[156,306,308],{"id":307},"docker","Docker",[147,310,311,312,315,316,319],{},"Le site livre une paire qui marche — ",[169,313,314],{},"site\u002FDockerfile"," + ",[169,317,318],{},"site\u002Fdocker-compose.yml"," :",[296,321,325],{"className":322,"code":323,"language":324,"meta":304,"style":304},"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",[169,326,327,366],{"__ignoreMap":304},[328,329,332,336,340,344,348,350,353,355,357,360,362],"span",{"class":330,"line":331},"line",1,[328,333,335],{"class":334},"su5hD","SITE_AUTH_SECRET",[328,337,339],{"class":338},"smGrS","=",[328,341,343],{"class":342},"sjJ54","'",[328,345,347],{"class":346},"s_sjI","…32+ caractères…",[328,349,343],{"class":342},[328,351,352],{"class":334}," SITE_URL",[328,354,339],{"class":338},[328,356,343],{"class":342},[328,358,359],{"class":346},"https:\u002F\u002Fvotre-domaine",[328,361,343],{"class":342},[328,363,365],{"class":364},"sbgvK"," \\\n",[328,367,369,372,375,379,382,385,388],{"class":330,"line":368},2,[328,370,371],{"class":346},"  docker",[328,373,374],{"class":346}," compose",[328,376,378],{"class":377},"stzsN"," -f",[328,380,381],{"class":346}," site\u002Fdocker-compose.yml",[328,383,384],{"class":346}," up",[328,386,387],{"class":377}," -d",[328,389,390],{"class":377}," --build\n",[147,392,393],{},"Le Dockerfile réalise la checklist en deux étages :",[296,395,399],{"className":396,"code":397,"language":398,"meta":304,"style":304},"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",[169,400,401,407,422,434,440,452,458,465,471,480,488,496,505],{"__ignoreMap":304},[328,402,403],{"class":330,"line":331},[328,404,406],{"class":405},"sutJx","# étage build : install workspace → build packages → build site\n",[328,408,409,413,416,419],{"class":330,"line":368},[328,410,412],{"class":411},"sw1J6","RUN",[328,414,415],{"class":334}," pnpm --filter ",[328,417,418],{"class":346},"\".\u002Fpackages\u002F**\"",[328,420,421],{"class":334}," -r run build \\\n",[328,423,425,428,431],{"class":330,"line":424},3,[328,426,427],{"class":334}," && pnpm --filter ",[328,429,430],{"class":346},"\"@fougere\u002Fsite\"",[328,432,433],{"class":334}," run build\n",[328,435,437],{"class":330,"line":436},4,[328,438,439],{"class":405},"# la fermeture de résolution des fronds, par pnpm lui-même :\n",[328,441,443,445,447,449],{"class":330,"line":442},5,[328,444,412],{"class":411},[328,446,415],{"class":334},[328,448,430],{"class":346},[328,450,451],{"class":334}," deploy --prod --legacy \u002Fdeploy\n",[328,453,455],{"class":330,"line":454},6,[328,456,457],{"class":405},"# compléter la trace partielle de jiti + ajouter TS 5.9\n",[328,459,461],{"class":330,"line":460},7,[328,462,464],{"emptyLinePlaceholder":463},true,"\n",[328,466,468],{"class":330,"line":467},8,[328,469,470],{"class":405},"# étage run : node:22-slim, non-root\n",[328,472,474,477],{"class":330,"line":473},9,[328,475,476],{"class":411},"COPY",[328,478,479],{"class":334}," --from=build \u002Frepo\u002Fsite\u002F.output .\u002F.output\n",[328,481,483,485],{"class":330,"line":482},10,[328,484,476],{"class":411},[328,486,487],{"class":334}," --from=build \u002Frepo\u002Fsite\u002Ffronds  .\u002Ffronds\n",[328,489,491,493],{"class":330,"line":490},11,[328,492,476],{"class":411},[328,494,495],{"class":334}," --from=build \u002Fdeploy\u002Fnode_modules .\u002Fnode_modules\n",[328,497,499,502],{"class":330,"line":498},12,[328,500,501],{"class":411},"VOLUME",[328,503,504],{"class":334}," \u002Fapp\u002F.data\n",[328,506,508,511,514,517,519,522],{"class":330,"line":507},13,[328,509,510],{"class":411},"CMD",[328,512,513],{"class":334}," [",[328,515,516],{"class":346},"\"node\"",[328,518,198],{"class":334},[328,520,521],{"class":346},"\".output\u002Fserver\u002Findex.mjs\"",[328,523,524],{"class":334},"]\n",[147,526,527,528,531,532,535],{},"L'état vit dans le volume ",[169,529,530],{},"site-data"," monté sur ",[169,533,534],{},"\u002Fapp\u002F.data"," — un backup est une copie de\nfichier.",[156,537,539],{"id":538},"splitter-en-production","Splitter en production",[147,541,542,543,546,547,550,551,555],{},"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 ",[270,544,545],{},"ses"," fronds, et le consommateur la déclare dans ",[169,548,549],{},"remotes",". Un host\nmort dégrade en 503 typées dans les pages\n(",[552,553,122],"a",{"href":554},"\u002Ffr\u002Fdocs\u002Finfra\u002Fgradient#comportement-apr%C3%A8s-s%C3%A9paration",") ; le relancer est la\nrécupération — le consommateur n'est jamais rebuildé.",[147,557,558,559,562,563,565,566,569,570,573],{},"Trois choses s'appellent « ensemble » et une seule est obligatoire. Le ",[151,560,561],{},"contrat"," doit\nvoyager — le consommateur doit savoir ce que l'hôte sert. Le ",[151,564,169],{},", non : ",[169,567,568],{},"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",[151,571,572],{},"ports"," doivent se joindre, et c'est le seul des trois qu'un déploiement décide.",[147,575,576,577,580],{},"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. ",[169,578,579],{},"hosts: ['0.0.0.0']"," l'élargit en une ligne — et remet à l'exploitant ce que le défaut retenait :\nun récepteur croit l'identité qu'on lui tend, donc l'atteindre à travers un réseau suppose\nde refermer ce chemin autrement (mesh, pare-feu, sidecar) tant que l'identité n'est pas\nréglée au niveau de la Frond.",[582,583,584],"blockquote",{},[147,585,586,587,590],{},"Ces étapes sont candidates à un futur ",[169,588,589],{},"fougere build"," — un utilisateur ne devrait pas\navoir à les découvrir. D'ici là, cette page est le contrat.",[592,593,594],"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":304,"searchDepth":368,"depth":368,"links":596},[597,598,599],{"id":158,"depth":368,"text":159},{"id":307,"depth":368,"text":308},{"id":538,"depth":368,"text":539},"Ce qu'une app Fougere exige au runtime — appris en déployant ce site.","md",{},{"title":130,"description":600},"h4nXNiVXrqBxjrA3nEmyWoKUK0r6kytrDLe4prbxGfE",1786637820090]