[{"data":1,"prerenderedAt":1119},["ShallowReactive",2],{"navigation":3,"\u002Fdeployment\u002Fdocker":358,"\u002Fdeployment\u002Fdocker-surround":1114},[4,14,36,69,140,341],{"title":5,"path":6,"stem":7,"children":8},"Introduction","\u002Fgetting-started","1.getting-started\u002F1.index",[9,10],{"title":5,"path":6,"stem":7},{"title":11,"path":12,"stem":13},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":15,"path":16,"stem":17,"children":18,"page":35},"Guides","\u002Fguides","2.guides",[19,23,27,31],{"title":20,"path":21,"stem":22},"Your First Layout","\u002Fguides\u002Fyour-first-layout","2.guides\u002F1.your-first-layout",{"title":24,"path":25,"stem":26},"Your First Page Template","\u002Fguides\u002Fyour-first-page-template","2.guides\u002F2.your-first-page-template",{"title":28,"path":29,"stem":30},"Your First Component","\u002Fguides\u002Fyour-first-component","2.guides\u002F3.your-first-component",{"title":32,"path":33,"stem":34},"Alternative UI Variants","\u002Fguides\u002Falternative-ui-variants","2.guides\u002F4.alternative-ui-variants",false,{"title":37,"path":38,"stem":39,"children":40,"page":35},"Core Concepts","\u002Fcore-concepts","3.core-concepts",[41,45,49,53,57,61,65],{"title":42,"path":43,"stem":44},"How It All Works","\u002Fcore-concepts\u002Farchitecture","3.core-concepts\u002F1.architecture",{"title":46,"path":47,"stem":48},"The Data Model","\u002Fcore-concepts\u002Fthe-data-model","3.core-concepts\u002F2.the-data-model",{"title":50,"path":51,"stem":52},"Layouts & Pages","\u002Fcore-concepts\u002Flayouts-and-pages","3.core-concepts\u002F3.layouts-and-pages",{"title":54,"path":55,"stem":56},"Dynamic Pages","\u002Fcore-concepts\u002Fdynamic-pages","3.core-concepts\u002F4.dynamic-pages",{"title":58,"path":59,"stem":60},"Components","\u002Fcore-concepts\u002Fcomponents","3.core-concepts\u002F5.components",{"title":62,"path":63,"stem":64},"Draft & Publish Workflow","\u002Fcore-concepts\u002Fdraft-and-publish","3.core-concepts\u002F6.draft-and-publish",{"title":66,"path":67,"stem":68},"The Admin Panel","\u002Fcore-concepts\u002Fadmin-panel","3.core-concepts\u002F7.admin-panel",{"title":70,"path":71,"stem":72,"children":73,"page":35},"Api","\u002Fapi","4.api",[74,78,116,120,124,128,132,136],{"title":75,"path":76,"stem":77},"Bundle Setup","\u002Fapi\u002Fbundle-setup","4.api\u002F1.bundle-setup",{"title":58,"path":79,"stem":80,"children":81,"page":35},"\u002Fapi\u002Fcomponents","4.api\u002F2.components",[82,86,103],{"title":83,"path":84,"stem":85},"Creating Components","\u002Fapi\u002Fcomponents\u002Fcreating-components","4.api\u002F2.components\u002F1.creating-components",{"title":87,"path":88,"stem":89,"children":90,"page":35},"Annotations","\u002Fapi\u002Fcomponents\u002Fannotations","4.api\u002F2.components\u002F2.annotations",[91,95,99],{"title":92,"path":93,"stem":94},"Publishable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fpublishable","4.api\u002F2.components\u002F2.annotations\u002F1.publishable",{"title":96,"path":97,"stem":98},"Uploadable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fuploadable","4.api\u002F2.components\u002F2.annotations\u002F2.uploadable",{"title":100,"path":101,"stem":102},"Timestamped","\u002Fapi\u002Fcomponents\u002Fannotations\u002Ftimestamped","4.api\u002F2.components\u002F2.annotations\u002F3.timestamped",{"title":104,"path":105,"stem":106,"children":107,"page":35},"Built Ins","\u002Fapi\u002Fcomponents\u002Fbuilt-ins","4.api\u002F2.components\u002F3.built-ins",[108,112],{"title":109,"path":110,"stem":111},"Collection Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fcollection-component","4.api\u002F2.components\u002F3.built-ins\u002F1.collection-component",{"title":113,"path":114,"stem":115},"Form Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fform-component","4.api\u002F2.components\u002F3.built-ins\u002F2.form-component",{"title":117,"path":118,"stem":119},"Dynamic & Nested Pages","\u002Fapi\u002Fdynamic-pages","4.api\u002F3.dynamic-pages",{"title":121,"path":122,"stem":123},"Users & Security","\u002Fapi\u002Fusers-and-security","4.api\u002F4.users-and-security",{"title":125,"path":126,"stem":127},"Data Fixtures","\u002Fapi\u002Fdata-fixtures","4.api\u002F5.data-fixtures",{"title":129,"path":130,"stem":131},"Configuration Reference","\u002Fapi\u002Fconfiguration","4.api\u002F6.configuration",{"title":133,"path":134,"stem":135},"Console Commands","\u002Fapi\u002Fconsole-commands","4.api\u002F7.console-commands",{"title":137,"path":138,"stem":139},"Debugging & Profiler","\u002Fapi\u002Fdebugging","4.api\u002F8.debugging",{"title":141,"path":142,"stem":143,"children":144,"page":35},"Nuxt Module","\u002Fnuxt-module","5.nuxt-module",[145,149,162,182,207,211,295,320,324],{"title":146,"path":147,"stem":148},"Module Setup","\u002Fnuxt-module\u002Fmodule-setup","5.nuxt-module\u002F1.module-setup",{"title":150,"path":151,"stem":152,"children":153,"page":35},"Configuration","\u002Fnuxt-module\u002Fconfiguration","5.nuxt-module\u002F2.configuration",[154,158],{"title":155,"path":156,"stem":157},"Nuxt Config","\u002Fnuxt-module\u002Fconfiguration\u002Fnuxt-config","5.nuxt-module\u002F2.configuration\u002F1.nuxt-config",{"title":159,"path":160,"stem":161},"Site Config & SEO","\u002Fnuxt-module\u002Fconfiguration\u002Fsite-config-and-seo","5.nuxt-module\u002F2.configuration\u002F2.site-config-and-seo",{"title":163,"path":164,"stem":165,"children":166,"page":35},"Building Your Ui","\u002Fnuxt-module\u002Fbuilding-your-ui","5.nuxt-module\u002F3.building-your-ui",[167,171,175,178],{"title":168,"path":169,"stem":170},"Layouts","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-layouts","5.nuxt-module\u002F3.building-your-ui\u002F1.creating-layouts",{"title":172,"path":173,"stem":174},"Page Templates","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-page-templates","5.nuxt-module\u002F3.building-your-ui\u002F2.creating-page-templates",{"title":83,"path":176,"stem":177},"\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-components","5.nuxt-module\u002F3.building-your-ui\u002F3.creating-components",{"title":179,"path":180,"stem":181},"CLI Generator","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcwa-cli","5.nuxt-module\u002F3.building-your-ui\u002F4.cwa-cli",{"title":183,"path":184,"stem":185,"children":186,"page":35},"Cwa Components","\u002Fnuxt-module\u002Fcwa-components","5.nuxt-module\u002F4.cwa-components",[187,191,195,199,203],{"title":188,"path":189,"stem":190},"\u003CCwaComponentGroup \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-component-group","5.nuxt-module\u002F4.cwa-components\u002F1.cwa-component-group",{"title":192,"path":193,"stem":194},"\u003CCwaPage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-page","5.nuxt-module\u002F4.cwa-components\u002F2.cwa-page",{"title":196,"path":197,"stem":198},"\u003CCwaLink \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-link","5.nuxt-module\u002F4.cwa-components\u002F3.cwa-link",{"title":200,"path":201,"stem":202},"\u003CCwaImage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-image","5.nuxt-module\u002F4.cwa-components\u002F4.cwa-image",{"title":204,"path":205,"stem":206},"\u003CCwaDefaultLayout \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-default-layout","5.nuxt-module\u002F4.cwa-components\u002F5.cwa-default-layout",{"title":208,"path":209,"stem":210},"The useCwa() API","\u002Fnuxt-module\u002Fcwa-api","5.nuxt-module\u002F5.cwa-api",{"title":212,"path":213,"stem":214,"children":215,"page":35},"Composables","\u002Fnuxt-module\u002Fcomposables","5.nuxt-module\u002F6.composables",[216,224,261,278],{"title":217,"path":218,"stem":219,"children":220,"page":35},"Layout","\u002Fnuxt-module\u002Fcomposables\u002Flayout","5.nuxt-module\u002F6.composables\u002F0.layout",[221],{"title":217,"path":222,"stem":223},"\u002Fnuxt-module\u002Fcomposables\u002Flayout\u002Fuse-cwa-layout","5.nuxt-module\u002F6.composables\u002F0.layout\u002F1.use-cwa-layout",{"title":225,"path":226,"stem":227,"children":228,"page":35},"Component","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent","5.nuxt-module\u002F6.composables\u002F1.component",[229,233,237,241,245,249,253,257],{"title":230,"path":231,"stem":232},"Component (recommended)","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-component","5.nuxt-module\u002F6.composables\u002F1.component\u002F0.use-cwa-component",{"title":234,"path":235,"stem":236},"Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F1.use-cwa-resource",{"title":238,"path":239,"stem":240},"Collection Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-collection-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F2.use-cwa-collection-resource",{"title":242,"path":243,"stem":244},"Image Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-image-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F3.use-cwa-image-resource",{"title":246,"path":247,"stem":248},"Form","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form","5.nuxt-module\u002F6.composables\u002F1.component\u002F4.use-cwa-form",{"title":250,"path":251,"stem":252},"Form Input","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-input","5.nuxt-module\u002F6.composables\u002F1.component\u002F5.use-cwa-form-input",{"title":254,"path":255,"stem":256},"Form Repeated","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-repeated","5.nuxt-module\u002F6.composables\u002F1.component\u002F6.use-cwa-form-repeated",{"title":258,"path":259,"stem":260},"Form Collection","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-collection","5.nuxt-module\u002F6.composables\u002F1.component\u002F7.use-cwa-form-collection",{"title":262,"path":263,"stem":264,"children":265,"page":35},"Admin Manager","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager","5.nuxt-module\u002F6.composables\u002F2.admin-manager",[266,270,274],{"title":267,"path":268,"stem":269},"Manager Tab","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-manager-tab","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F1.use-cwa-resource-manager-tab",{"title":271,"path":272,"stem":273},"Resource Model","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-model","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F2.use-cwa-resource-model",{"title":275,"path":276,"stem":277},"Resource Upload","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-upload","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F3.use-cwa-resource-upload",{"title":279,"path":280,"stem":281,"children":282,"page":35},"Utilities","\u002Fnuxt-module\u002Fcomposables\u002Futilities","5.nuxt-module\u002F6.composables\u002F3.utilities",[283,287,291],{"title":284,"path":285,"stem":286},"Resource Endpoint","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-endpoint","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F1.use-cwa-resource-endpoint",{"title":288,"path":289,"stem":290},"Query Model","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-query-bound-model","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F2.use-query-bound-model",{"title":292,"path":293,"stem":294},"Resource Route","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-route","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F3.use-cwa-resource-route",{"title":296,"path":297,"stem":298,"children":299,"page":35},"Component Helpers","\u002Fnuxt-module\u002Fcomponent-helpers","5.nuxt-module\u002F7.component-helpers",[300,304,308,312,316],{"title":301,"path":302,"stem":303},"Images & Media","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fimages-and-uploads","5.nuxt-module\u002F7.component-helpers\u002F1.images-and-uploads",{"title":305,"path":306,"stem":307},"Collections & Pagination","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fcollections-and-pagination","5.nuxt-module\u002F7.component-helpers\u002F2.collections-and-pagination",{"title":309,"path":310,"stem":311},"HTML Content","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fhtml-content","5.nuxt-module\u002F7.component-helpers\u002F3.html-content",{"title":313,"path":314,"stem":315},"Real-Time Updates","\u002Fnuxt-module\u002Fcomponent-helpers\u002Freal-time-updates","5.nuxt-module\u002F7.component-helpers\u002F4.real-time-updates",{"title":317,"path":318,"stem":319},"Forms","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fforms","5.nuxt-module\u002F7.component-helpers\u002F5.forms",{"title":321,"path":322,"stem":323},"Authentication","\u002Fnuxt-module\u002Fauthentication","5.nuxt-module\u002F8.authentication",{"title":325,"path":326,"stem":327,"children":328,"page":35},"Cwa Layer","\u002Fnuxt-module\u002Fcwa-layer","5.nuxt-module\u002F9.cwa-layer",[329,333,337],{"title":330,"path":331,"stem":332},"Overview","\u002Fnuxt-module\u002Fcwa-layer\u002Foverview","5.nuxt-module\u002F9.cwa-layer\u002F1.overview",{"title":334,"path":335,"stem":336},"Auth Pages","\u002Fnuxt-module\u002Fcwa-layer\u002Fauth-pages","5.nuxt-module\u002F9.cwa-layer\u002F2.auth-pages",{"title":338,"path":339,"stem":340},"Admin Panel","\u002Fnuxt-module\u002Fcwa-layer\u002Fadmin-panel","5.nuxt-module\u002F9.cwa-layer\u002F3.admin-panel",{"title":342,"path":343,"stem":344,"children":345,"page":35},"Deployment","\u002Fdeployment","6.deployment",[346,350,354],{"title":347,"path":348,"stem":349},"Docker","\u002Fdeployment\u002Fdocker","6.deployment\u002F1.docker",{"title":351,"path":352,"stem":353},"Kubernetes & Helm","\u002Fdeployment\u002Fkubernetes","6.deployment\u002F2.kubernetes",{"title":355,"path":356,"stem":357},"CI\u002FCD","\u002Fdeployment\u002Fci-cd","6.deployment\u002F3.ci-cd",{"id":359,"title":347,"badge":360,"body":363,"description":1108,"extension":1109,"links":1110,"meta":1111,"navigation":514,"path":348,"seo":1112,"stem":349,"__hash__":1113},"docs\u002F6.deployment\u002F1.docker.md",{"label":361,"color":362},"Draft","amber",{"type":364,"value":365,"toc":1098},"minimark",[366,370,375,464,468,486,615,626,630,735,739,745,775,779,782,827,837,841,844,903,908,929,934,966,973,977,987,1008,1011,1046,1050,1060,1066,1076,1094],[367,368,369],"p",{},"The CWA template repository ships a complete Docker Compose stack. Clone the template and you have a fully wired local environment — PHP, Nuxt, Mercure, PostgreSQL, and a reverse proxy — ready in minutes.",[371,372,374],"h2",{"id":373},"services","Services",[376,377,378,394],"table",{},[379,380,381],"thead",{},[382,383,384,388,391],"tr",{},[385,386,387],"th",{},"Service",[385,389,390],{},"Image",[385,392,393],{},"Role",[395,396,397,412,425,438,451],"tbody",{},[382,398,399,406,409],{},[400,401,402],"td",{},[403,404,405],"code",{},"php",[400,407,408],{},"FrankenPHP",[400,410,411],{},"Symfony API (HTTP + Mercure publisher)",[382,413,414,419,422],{},[400,415,416],{},[403,417,418],{},"nuxt",[400,420,421],{},"Node 22",[400,423,424],{},"Nuxt SSR application",[382,426,427,432,435],{},[400,428,429],{},[403,430,431],{},"database",[400,433,434],{},"PostgreSQL 16",[400,436,437],{},"Primary database",[382,439,440,445,448],{},[400,441,442],{},[403,443,444],{},"mercure",[400,446,447],{},"Caddy + Mercure module",[400,449,450],{},"Real-time hub",[382,452,453,458,461],{},[400,454,455],{},[403,456,457],{},"traefik",[400,459,460],{},"Traefik",[400,462,463],{},"Reverse proxy routing",[371,465,467],{"id":466},"environment-variables","Environment Variables",[367,469,470,471,474,475,478,479,485],{},"Create ",[403,472,473],{},".env.local"," alongside ",[403,476,477],{},".env"," — ",[480,481,482,483],"strong",{},"never commit ",[403,484,473],{},":",[487,488,493],"pre",{"className":489,"code":490,"language":491,"meta":492,"style":492},"language-ini shiki shiki-themes github-light github-dark material-theme-palenight","# Database\nDATABASE_URL=postgresql:\u002F\u002Fapp:secret@database:5432\u002Fapp?serverVersion=16&charset=utf8\n\n# JWT Authentication\nJWT_SECRET_KEY=%kernel.project_dir%\u002Fconfig\u002Fjwt\u002Fprivate.pem\nJWT_PUBLIC_KEY=%kernel.project_dir%\u002Fconfig\u002Fjwt\u002Fpublic.pem\nJWT_PASSPHRASE=your_jwt_passphrase\nJWT_COOKIE_SAMESITE=strict\n\n# Mercure\nMERCURE_URL=http:\u002F\u002Fmercure\u002F.well-known\u002Fmercure\nMERCURE_PUBLIC_URL=https:\u002F\u002Fmercure.localhost\u002F.well-known\u002Fmercure\nMERCURE_JWT_SECRET=your_mercure_secret\n\n# Nuxt (server-side API URL = internal Docker network; browser URL = public)\nNUXT_PUBLIC_CWA_API_URL=http:\u002F\u002Fphp\nNUXT_PUBLIC_CWA_API_URL_BROWSER=https:\u002F\u002Fapi.localhost\n\n# Email\nMAILER_DSN=smtp:\u002F\u002Flocalhost:1025\n","ini","",[403,494,495,503,509,516,522,528,534,540,546,551,557,563,569,575,580,586,592,598,603,609],{"__ignoreMap":492},[496,497,500],"span",{"class":498,"line":499},"line",1,[496,501,502],{},"# Database\n",[496,504,506],{"class":498,"line":505},2,[496,507,508],{},"DATABASE_URL=postgresql:\u002F\u002Fapp:secret@database:5432\u002Fapp?serverVersion=16&charset=utf8\n",[496,510,512],{"class":498,"line":511},3,[496,513,515],{"emptyLinePlaceholder":514},true,"\n",[496,517,519],{"class":498,"line":518},4,[496,520,521],{},"# JWT Authentication\n",[496,523,525],{"class":498,"line":524},5,[496,526,527],{},"JWT_SECRET_KEY=%kernel.project_dir%\u002Fconfig\u002Fjwt\u002Fprivate.pem\n",[496,529,531],{"class":498,"line":530},6,[496,532,533],{},"JWT_PUBLIC_KEY=%kernel.project_dir%\u002Fconfig\u002Fjwt\u002Fpublic.pem\n",[496,535,537],{"class":498,"line":536},7,[496,538,539],{},"JWT_PASSPHRASE=your_jwt_passphrase\n",[496,541,543],{"class":498,"line":542},8,[496,544,545],{},"JWT_COOKIE_SAMESITE=strict\n",[496,547,549],{"class":498,"line":548},9,[496,550,515],{"emptyLinePlaceholder":514},[496,552,554],{"class":498,"line":553},10,[496,555,556],{},"# Mercure\n",[496,558,560],{"class":498,"line":559},11,[496,561,562],{},"MERCURE_URL=http:\u002F\u002Fmercure\u002F.well-known\u002Fmercure\n",[496,564,566],{"class":498,"line":565},12,[496,567,568],{},"MERCURE_PUBLIC_URL=https:\u002F\u002Fmercure.localhost\u002F.well-known\u002Fmercure\n",[496,570,572],{"class":498,"line":571},13,[496,573,574],{},"MERCURE_JWT_SECRET=your_mercure_secret\n",[496,576,578],{"class":498,"line":577},14,[496,579,515],{"emptyLinePlaceholder":514},[496,581,583],{"class":498,"line":582},15,[496,584,585],{},"# Nuxt (server-side API URL = internal Docker network; browser URL = public)\n",[496,587,589],{"class":498,"line":588},16,[496,590,591],{},"NUXT_PUBLIC_CWA_API_URL=http:\u002F\u002Fphp\n",[496,593,595],{"class":498,"line":594},17,[496,596,597],{},"NUXT_PUBLIC_CWA_API_URL_BROWSER=https:\u002F\u002Fapi.localhost\n",[496,599,601],{"class":498,"line":600},18,[496,602,515],{"emptyLinePlaceholder":514},[496,604,606],{"class":498,"line":605},19,[496,607,608],{},"# Email\n",[496,610,612],{"class":498,"line":611},20,[496,613,614],{},"MAILER_DSN=smtp:\u002F\u002Flocalhost:1025\n",[367,616,617,618,621,622,625],{},"The two CWA API URL variables are intentionally different in Docker Compose: ",[403,619,620],{},"NUXT_PUBLIC_CWA_API_URL"," is the internal Docker hostname (Nuxt → PHP on the Docker network), while ",[403,623,624],{},"NUXT_PUBLIC_CWA_API_URL_BROWSER"," is the public-facing URL clients use from their browsers.",[371,627,629],{"id":628},"starting-the-stack","Starting the Stack",[487,631,635],{"className":632,"code":633,"language":634,"meta":492,"style":492},"language-bash shiki shiki-themes github-light github-dark material-theme-palenight","# Start all services in the background\ndocker compose up -d\n\n# Run database migrations\ndocker compose exec php bin\u002Fconsole doctrine:migrations:migrate\n\n# Create your first admin user\ndocker compose exec php bin\u002Fconsole silverback:api-components:user:create\n\n# Load fixtures (optional)\ndocker compose exec php bin\u002Fconsole doctrine:fixtures:load\n","bash",[403,636,637,643,660,664,669,687,691,696,711,715,720],{"__ignoreMap":492},[496,638,639],{"class":498,"line":499},[496,640,642],{"class":641},"sTBSN","# Start all services in the background\n",[496,644,645,649,653,656],{"class":498,"line":505},[496,646,648],{"class":647},"sRCss","docker",[496,650,652],{"class":651},"sLL54"," compose",[496,654,655],{"class":651}," up",[496,657,659],{"class":658},"szhYu"," -d\n",[496,661,662],{"class":498,"line":511},[496,663,515],{"emptyLinePlaceholder":514},[496,665,666],{"class":498,"line":518},[496,667,668],{"class":641},"# Run database migrations\n",[496,670,671,673,675,678,681,684],{"class":498,"line":524},[496,672,648],{"class":647},[496,674,652],{"class":651},[496,676,677],{"class":651}," exec",[496,679,680],{"class":651}," php",[496,682,683],{"class":651}," bin\u002Fconsole",[496,685,686],{"class":651}," doctrine:migrations:migrate\n",[496,688,689],{"class":498,"line":530},[496,690,515],{"emptyLinePlaceholder":514},[496,692,693],{"class":498,"line":536},[496,694,695],{"class":641},"# Create your first admin user\n",[496,697,698,700,702,704,706,708],{"class":498,"line":542},[496,699,648],{"class":647},[496,701,652],{"class":651},[496,703,677],{"class":651},[496,705,680],{"class":651},[496,707,683],{"class":651},[496,709,710],{"class":651}," silverback:api-components:user:create\n",[496,712,713],{"class":498,"line":548},[496,714,515],{"emptyLinePlaceholder":514},[496,716,717],{"class":498,"line":553},[496,718,719],{"class":641},"# Load fixtures (optional)\n",[496,721,722,724,726,728,730,732],{"class":498,"line":559},[496,723,648],{"class":647},[496,725,652],{"class":651},[496,727,677],{"class":651},[496,729,680],{"class":651},[496,731,683],{"class":651},[496,733,734],{"class":651}," doctrine:fixtures:load\n",[371,736,738],{"id":737},"development-workflow","Development Workflow",[367,740,741,744],{},[403,742,743],{},"docker-compose.override.yml"," mounts source directories into the containers:",[746,747,748,759,769],"ul",{},[749,750,751,754,755,758],"li",{},[480,752,753],{},"PHP",": your ",[403,756,757],{},"api\u002F"," directory is mounted; PHP changes are reflected immediately (no build step)",[749,760,761,764,765,768],{},[480,762,763],{},"Nuxt",": ",[403,766,767],{},"app\u002F"," is mounted; Vite HMR updates the browser on save",[749,770,771,774],{},[480,772,773],{},"Xdebug",": configured in the override file; connect via your IDE on port 9003",[371,776,778],{"id":777},"jwt-key-generation","JWT Key Generation",[367,780,781],{},"Generate JWT keys once per environment before first start:",[487,783,785],{"className":632,"code":784,"language":634,"meta":492,"style":492},"docker compose exec php bash -c \"\n    mkdir -p config\u002Fjwt\n    openssl genpkey -out config\u002Fjwt\u002Fprivate.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096\n    openssl pkey -in config\u002Fjwt\u002Fprivate.pem -out config\u002Fjwt\u002Fpublic.pem -pubout\n\"\n",[403,786,787,807,812,817,822],{"__ignoreMap":492},[496,788,789,791,793,795,797,800,803],{"class":498,"line":499},[496,790,648],{"class":647},[496,792,652],{"class":651},[496,794,677],{"class":651},[496,796,680],{"class":651},[496,798,799],{"class":651}," bash",[496,801,802],{"class":658}," -c",[496,804,806],{"class":805},"seSrl"," \"\n",[496,808,809],{"class":498,"line":505},[496,810,811],{"class":651},"    mkdir -p config\u002Fjwt\n",[496,813,814],{"class":498,"line":511},[496,815,816],{"class":651},"    openssl genpkey -out config\u002Fjwt\u002Fprivate.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096\n",[496,818,819],{"class":498,"line":518},[496,820,821],{"class":651},"    openssl pkey -in config\u002Fjwt\u002Fprivate.pem -out config\u002Fjwt\u002Fpublic.pem -pubout\n",[496,823,824],{"class":498,"line":524},[496,825,826],{"class":805},"\"\n",[367,828,829,830,833,834,836],{},"The passphrase you use must match ",[403,831,832],{},"JWT_PASSPHRASE"," in ",[403,835,473],{},".",[371,838,840],{"id":839},"building-for-production","Building for Production",[367,842,843],{},"Multi-stage Dockerfiles produce lean production images:",[487,845,847],{"className":632,"code":846,"language":634,"meta":492,"style":492},"# Build PHP image\ndocker build --target runner -t ghcr.io\u002Fyour-org\u002Fapp-php:latest .\u002Fapi\n\n# Build Nuxt image\ndocker build --target runner -t ghcr.io\u002Fyour-org\u002Fapp-nuxt:latest .\u002Fapp\n",[403,848,849,854,876,880,885],{"__ignoreMap":492},[496,850,851],{"class":498,"line":499},[496,852,853],{"class":641},"# Build PHP image\n",[496,855,856,858,861,864,867,870,873],{"class":498,"line":505},[496,857,648],{"class":647},[496,859,860],{"class":651}," build",[496,862,863],{"class":658}," --target",[496,865,866],{"class":651}," runner",[496,868,869],{"class":658}," -t",[496,871,872],{"class":651}," ghcr.io\u002Fyour-org\u002Fapp-php:latest",[496,874,875],{"class":651}," .\u002Fapi\n",[496,877,878],{"class":498,"line":511},[496,879,515],{"emptyLinePlaceholder":514},[496,881,882],{"class":498,"line":518},[496,883,884],{"class":641},"# Build Nuxt image\n",[496,886,887,889,891,893,895,897,900],{"class":498,"line":524},[496,888,648],{"class":647},[496,890,860],{"class":651},[496,892,863],{"class":658},[496,894,866],{"class":651},[496,896,869],{"class":658},[496,898,899],{"class":651}," ghcr.io\u002Fyour-org\u002Fapp-nuxt:latest",[496,901,902],{"class":651}," .\u002Fapp\n",[367,904,905],{},[480,906,907],{},"PHP Dockerfile stages:",[909,910,911,917,923],"ol",{},[749,912,913,916],{},[403,914,915],{},"deps"," — install Composer dependencies",[749,918,919,922],{},[403,920,921],{},"builder"," — copy app, remove dev dependencies",[749,924,925,928],{},[403,926,927],{},"runner"," — FrankenPHP with production config",[367,930,931],{},[480,932,933],{},"Nuxt Dockerfile stages:",[909,935,936,943,955],{},[749,937,938,478,940],{},[403,939,915],{},[403,941,942],{},"pnpm install",[749,944,945,478,947,950,951,954],{},[403,946,921],{},[403,948,949],{},"pnpm build"," (outputs ",[403,952,953],{},".output\u002F",")",[749,956,957,959,960,962,963],{},[403,958,927],{}," — copies ",[403,961,953],{},", runs ",[403,964,965],{},"node .output\u002Fserver\u002Findex.mjs",[367,967,968,969,972],{},"Migrations are ",[480,970,971],{},"not"," run at image build time. Run them as a separate step in your deploy process before starting the new containers.",[371,974,976],{"id":975},"production-docker-compose","Production Docker Compose",[367,978,979,980,982,983,986],{},"For production, remove the ",[403,981,743],{}," and use the base ",[403,984,985],{},"docker-compose.yml"," with your production environment file:",[487,988,990],{"className":632,"code":989,"language":634,"meta":492,"style":492},"docker compose --env-file .env.production up -d\n",[403,991,992],{"__ignoreMap":492},[496,993,994,996,998,1001,1004,1006],{"class":498,"line":499},[496,995,648],{"class":647},[496,997,652],{"class":651},[496,999,1000],{"class":658}," --env-file",[496,1002,1003],{"class":651}," .env.production",[496,1005,655],{"class":651},[496,1007,659],{"class":658},[367,1009,1010],{},"Tag images with the git SHA for immutable, rollback-capable deploys:",[487,1012,1014],{"className":632,"code":1013,"language":634,"meta":492,"style":492},"docker build -t ghcr.io\u002Fyour-org\u002Fapp-php:$GIT_SHA .\u002Fapi\ndocker push ghcr.io\u002Fyour-org\u002Fapp-php:$GIT_SHA\n",[403,1015,1016,1034],{"__ignoreMap":492},[496,1017,1018,1020,1022,1024,1027,1031],{"class":498,"line":499},[496,1019,648],{"class":647},[496,1021,860],{"class":651},[496,1023,869],{"class":658},[496,1025,1026],{"class":651}," ghcr.io\u002Fyour-org\u002Fapp-php:",[496,1028,1030],{"class":1029},"sPB8G","$GIT_SHA ",[496,1032,1033],{"class":651},".\u002Fapi\n",[496,1035,1036,1038,1041,1043],{"class":498,"line":505},[496,1037,648],{"class":647},[496,1039,1040],{"class":651}," push",[496,1042,1026],{"class":651},[496,1044,1045],{"class":1029},"$GIT_SHA\n",[371,1047,1049],{"id":1048},"common-gotchas","Common Gotchas",[367,1051,1052,1059],{},[480,1053,1054,1056,1057],{},[403,1055,620],{}," vs ",[403,1058,624],{},": Must be different when your API is on an internal Docker hostname. The server-side URL uses the Docker service name; the browser URL must be the public domain.",[367,1061,1062,1065],{},[480,1063,1064],{},"JWT keys",": Generate once and mount as a secret — never bake private keys into the image.",[367,1067,1068,1071,1072,1075],{},[480,1069,1070],{},"Database migrations on restart",": Don't run migrations in the container ",[403,1073,1074],{},"CMD",". Race conditions occur when multiple pods start simultaneously. Run them as a pre-deploy Job.",[367,1077,1078,1081,1082,1085,1086,1089,1090,1093],{},[480,1079,1080],{},"Mercure cookie SameSite",": Set ",[403,1083,1084],{},"JWT_COOKIE_SAMESITE=none"," and ",[403,1087,1088],{},"Secure: true"," if your API and front-end are on different subdomains. On the same domain, ",[403,1091,1092],{},"strict"," is safe.",[1095,1096,1097],"style",{},"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 .sTBSN, html code.shiki .sTBSN{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sRCss, html code.shiki .sRCss{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#FFCB6B}html pre.shiki code .sLL54, html code.shiki .sLL54{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#C3E88D}html pre.shiki code .szhYu, html code.shiki .szhYu{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#C3E88D}html pre.shiki code .seSrl, html code.shiki .seSrl{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#89DDFF}html pre.shiki code .sPB8G, html code.shiki .sPB8G{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#BABED8}",{"title":492,"searchDepth":505,"depth":505,"links":1099},[1100,1101,1102,1103,1104,1105,1106,1107],{"id":373,"depth":505,"text":374},{"id":466,"depth":505,"text":467},{"id":628,"depth":505,"text":629},{"id":737,"depth":505,"text":738},{"id":777,"depth":505,"text":778},{"id":839,"depth":505,"text":840},{"id":975,"depth":505,"text":976},{"id":1048,"depth":505,"text":1049},"The Docker Compose setup for local development and production — services, environment variables, volumes, and build workflow.","md",null,{},{"title":347,"description":1108},"gc4UJiKgijz9_MtCduma2K5l2gYhkeWtdcH0RSpE-QY",[1115,1117],{"title":338,"path":339,"stem":340,"description":1116,"children":-1},"The built-in CWA admin — pages, edit mode, the resource manager, and how to extend it with custom manager tabs.",{"title":351,"path":352,"stem":353,"description":1118,"children":-1},"Deploying the CWA stack to Kubernetes using Helm — values configuration, secrets management, migration Jobs, and rolling updates.",1782512903317]