[{"data":1,"prerenderedAt":2332},["ShallowReactive",2],{"navigation_docs":3,"-contribute-documentation":587,"-contribute-documentation-surround":2327},[4,50,155,441,504],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":49},"Get Started","i-lucide-rocket","\u002Fget-started","1.get-started",[10,15,20,25,30,35,40,45],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fget-started\u002Fintroduction","1.get-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fget-started\u002Finstallation","1.get-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Project structure","\u002Fget-started\u002Fproject-structure","1.get-started\u002F3.project-structure","i-lucide-folder-tree",{"title":26,"path":27,"stem":28,"icon":29},"Configuration","\u002Fget-started\u002Fconfiguration","1.get-started\u002F4.configuration","i-lucide-settings",{"title":31,"path":32,"stem":33,"icon":34},"Authentication","\u002Fget-started\u002Fauthentication","1.get-started\u002F5.authentication","i-lucide-lock",{"title":36,"path":37,"stem":38,"icon":39},"Adding modules","\u002Fget-started\u002Fadding-modules","1.get-started\u002F6.adding-modules","i-lucide-puzzle",{"title":41,"path":42,"stem":43,"icon":44},"Database","\u002Fget-started\u002Fdatabase","1.get-started\u002F7.database","i-lucide-database",{"title":46,"path":47,"stem":48,"icon":6},"Deployment","\u002Fget-started\u002Fdeployment","1.get-started\u002F8.deployment",false,{"title":51,"icon":52,"path":53,"stem":54,"children":55,"page":49},"Guide","i-lucide-book-open","\u002Fguide","2.guide",[56,90,115,125],{"title":57,"icon":49,"path":58,"stem":59,"children":60,"page":49},"Concepts","\u002Fguide\u002Fconcepts","2.guide\u002F1.concepts",[61,66,71,76,80,85],{"title":62,"path":63,"stem":64,"icon":65},"Architecture","\u002Fguide\u002Fconcepts\u002Farchitecture","2.guide\u002F1.concepts\u002F1.architecture","i-lucide-blocks",{"title":67,"path":68,"stem":69,"icon":70},"Access control","\u002Fguide\u002Fconcepts\u002Fauth-and-scopes","2.guide\u002F1.concepts\u002F2.auth-and-scopes","i-lucide-shield-check",{"title":72,"path":73,"stem":74,"icon":75},"Extension points","\u002Fguide\u002Fconcepts\u002Fextension-points","2.guide\u002F1.concepts\u002F3.extension-points","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":44},"Database extensions","\u002Fguide\u002Fconcepts\u002Fdatabase-extensions","2.guide\u002F1.concepts\u002F4.database-extensions",{"title":81,"path":82,"stem":83,"icon":84},"Identity","\u002Fguide\u002Fconcepts\u002Fidentity","2.guide\u002F1.concepts\u002F5.identity","i-lucide-fingerprint",{"title":86,"path":87,"stem":88,"icon":89},"Glossary","\u002Fguide\u002Fconcepts\u002Fglossary","2.guide\u002F1.concepts\u002F6.glossary","i-lucide-book-a",{"title":91,"icon":49,"path":92,"stem":93,"children":94,"page":49},"UX patterns","\u002Fguide\u002Fux-patterns","2.guide\u002F2.ux-patterns",[95,100,105,110],{"title":96,"path":97,"stem":98,"icon":99},"Layouts and navigation","\u002Fguide\u002Fux-patterns\u002Flayouts-and-navigation","2.guide\u002F2.ux-patterns\u002F1.layouts-and-navigation","i-lucide-layout-template",{"title":101,"path":102,"stem":103,"icon":104},"Pages","\u002Fguide\u002Fux-patterns\u002Fpages","2.guide\u002F2.ux-patterns\u002F2.pages","i-lucide-table",{"title":106,"path":107,"stem":108,"icon":109},"Forms and actions","\u002Fguide\u002Fux-patterns\u002Fforms-and-actions","2.guide\u002F2.ux-patterns\u002F3.forms-and-actions","i-lucide-square-pen",{"title":111,"path":112,"stem":113,"icon":114},"Text and formatting","\u002Fguide\u002Fux-patterns\u002Ftext-and-formatting","2.guide\u002F2.ux-patterns\u002F4.text-and-formatting","i-lucide-type",{"title":116,"icon":49,"path":117,"stem":118,"children":119,"page":49},"Best practices","\u002Fguide\u002Fbest-practices","2.guide\u002F3.best-practices",[120],{"title":121,"path":122,"stem":123,"icon":124},"HTTP routes","\u002Fguide\u002Fbest-practices\u002Fhttp-routes","2.guide\u002F3.best-practices\u002F1.http-routes","i-lucide-route",{"title":126,"icon":49,"path":127,"stem":128,"children":129,"page":49},"Going further","\u002Fguide\u002Fgoing-further","2.guide\u002F4.going-further",[130,135,140,145,150],{"title":131,"path":132,"stem":133,"icon":134},"Use your own OAuth server","\u002Fguide\u002Fgoing-further\u002Fown-oauth-server","2.guide\u002F4.going-further\u002F1.own-oauth-server","i-lucide-key-round",{"title":136,"path":137,"stem":138,"icon":139},"Create an OAuth application","\u002Fguide\u002Fgoing-further\u002Foauth-application","2.guide\u002F4.going-further\u002F2.oauth-application","i-lucide-app-window",{"title":141,"path":142,"stem":143,"icon":144},"Signing keys","\u002Fguide\u002Fgoing-further\u002Fsigning-keys","2.guide\u002F4.going-further\u002F3.signing-keys","i-lucide-key-square",{"title":146,"path":147,"stem":148,"icon":149},"Stripe setup","\u002Fguide\u002Fgoing-further\u002Fstripe-setup","2.guide\u002F4.going-further\u002F4.stripe-setup","i-lucide-credit-card",{"title":151,"path":152,"stem":153,"icon":154},"Migrate to the permission model","\u002Fguide\u002Fgoing-further\u002Fmigrate-access-control","2.guide\u002F4.going-further\u002F5.migrate-access-control","i-lucide-arrow-right-left",{"title":156,"icon":157,"path":158,"stem":159,"children":160},"Modules","i-lucide-boxes","\u002Fmodules","3.modules",[161,163,244,273,320,375],{"title":156,"path":158,"stem":162},"3.modules\u002Findex",{"title":81,"icon":49,"path":164,"stem":165,"children":166,"page":49},"\u002Fmodules\u002Fidentity","3.modules\u002F1.identity",[167,190,194,198,220,224,240],{"title":168,"path":169,"stem":170,"children":171},"Auth","\u002Fmodules\u002Fidentity\u002Fauth","3.modules\u002F1.identity\u002F1.auth\u002Findex",[172,174,178,182,186],{"title":173,"path":169,"stem":170},"Overview",{"title":175,"path":176,"stem":177},"Server API","\u002Fmodules\u002Fidentity\u002Fauth\u002Fserver","3.modules\u002F1.identity\u002F1.auth\u002F2.server",{"title":179,"path":180,"stem":181},"Reference","\u002Fmodules\u002Fidentity\u002Fauth\u002Freference","3.modules\u002F1.identity\u002F1.auth\u002F3.reference",{"title":183,"path":184,"stem":185},"Client mode","\u002Fmodules\u002Fidentity\u002Fauth\u002Fclient-mode","3.modules\u002F1.identity\u002F1.auth\u002F4.client-mode",{"title":187,"path":188,"stem":189},"OAuth providers","\u002Fmodules\u002Fidentity\u002Fauth\u002Foauth-providers","3.modules\u002F1.identity\u002F1.auth\u002F5.oauth-providers",{"title":191,"path":192,"stem":193},"Users","\u002Fmodules\u002Fidentity\u002Fusers","3.modules\u002F1.identity\u002F2.users",{"title":195,"path":196,"stem":197},"Account","\u002Fmodules\u002Fidentity\u002Faccount","3.modules\u002F1.identity\u002F3.account",{"title":199,"path":200,"stem":201,"children":202},"Authorization","\u002Fmodules\u002Fidentity\u002Fauthorization","3.modules\u002F1.identity\u002F4.authorization\u002Findex",[203,204,208,212,216],{"title":173,"path":200,"stem":201},{"title":205,"path":206,"stem":207},"Roles and requirements","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Froles-and-requirements","3.modules\u002F1.identity\u002F4.authorization\u002F2.roles-and-requirements",{"title":209,"path":210,"stem":211},"Policies","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fpolicies","3.modules\u002F1.identity\u002F4.authorization\u002F3.policies",{"title":213,"path":214,"stem":215},"Client","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fclient","3.modules\u002F1.identity\u002F4.authorization\u002F4.client",{"title":217,"path":218,"stem":219},"Admin","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fadmin","3.modules\u002F1.identity\u002F4.authorization\u002F5.admin",{"title":221,"path":222,"stem":223},"Preferences","\u002Fmodules\u002Fidentity\u002Fpreferences","3.modules\u002F1.identity\u002F5.preferences",{"title":225,"path":226,"stem":227,"children":228},"OAuth Server","\u002Fmodules\u002Fidentity\u002Foauth-server","3.modules\u002F1.identity\u002F6.oauth-server\u002Findex",[229,230,233,237],{"title":173,"path":226,"stem":227},{"title":175,"path":231,"stem":232},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver","3.modules\u002F1.identity\u002F6.oauth-server\u002F2.server",{"title":234,"path":235,"stem":236},"Hooks","\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fhooks","3.modules\u002F1.identity\u002F6.oauth-server\u002F3.hooks",{"title":179,"path":238,"stem":239},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients","3.modules\u002F1.identity\u002F6.oauth-server\u002F4.routes-and-clients",{"title":241,"path":242,"stem":243},"OAuth Resource","\u002Fmodules\u002Fidentity\u002Foauth-resource","3.modules\u002F1.identity\u002F8.oauth-resource",{"title":245,"icon":49,"path":246,"stem":247,"children":248,"page":49},"Commerce","\u002Fmodules\u002Fcommerce","3.modules\u002F2.commerce",[249,253,257],{"title":250,"path":251,"stem":252},"Stripe","\u002Fmodules\u002Fcommerce\u002Fstripe","3.modules\u002F2.commerce\u002F1.stripe",{"title":254,"path":255,"stem":256},"Payments","\u002Fmodules\u002Fcommerce\u002Fpayments","3.modules\u002F2.commerce\u002F2.payments",{"title":258,"path":259,"stem":260,"children":261},"Subscriptions","\u002Fmodules\u002Fcommerce\u002Fsubscriptions","3.modules\u002F2.commerce\u002F3.subscriptions\u002Findex",[262,263,266,270],{"title":173,"path":259,"stem":260},{"title":175,"path":264,"stem":265},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fserver","3.modules\u002F2.commerce\u002F3.subscriptions\u002F2.server",{"title":267,"path":268,"stem":269},"App","\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fapp","3.modules\u002F2.commerce\u002F3.subscriptions\u002F3.app",{"title":179,"path":271,"stem":272},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Freference","3.modules\u002F2.commerce\u002F3.subscriptions\u002F4.reference",{"title":274,"icon":49,"path":275,"stem":276,"children":277,"page":49},"Features","\u002Fmodules\u002Ffeatures","3.modules\u002F3.features",[278,293,312,316],{"title":279,"path":280,"stem":281,"children":282},"Events","\u002Fmodules\u002Ffeatures\u002Fevents","3.modules\u002F3.features\u002F1.events\u002Findex",[283,284,287,290],{"title":173,"path":280,"stem":281},{"title":175,"path":285,"stem":286},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fserver","3.modules\u002F3.features\u002F1.events\u002F2.server",{"title":267,"path":288,"stem":289},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fapp","3.modules\u002F3.features\u002F1.events\u002F3.app",{"title":179,"path":291,"stem":292},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Freference","3.modules\u002F3.features\u002F1.events\u002F4.reference",{"title":294,"path":295,"stem":296,"children":297},"Forms","\u002Fmodules\u002Ffeatures\u002Fforms","3.modules\u002F3.features\u002F2.forms\u002Findex",[298,299,303,306,309],{"title":173,"path":295,"stem":296},{"title":300,"path":301,"stem":302},"Definition","\u002Fmodules\u002Ffeatures\u002Fforms\u002Fdefinition","3.modules\u002F3.features\u002F2.forms\u002F2.definition",{"title":175,"path":304,"stem":305},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fserver","3.modules\u002F3.features\u002F2.forms\u002F3.server",{"title":267,"path":307,"stem":308},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fapp","3.modules\u002F3.features\u002F2.forms\u002F4.app",{"title":179,"path":310,"stem":311},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Freference","3.modules\u002F3.features\u002F2.forms\u002F5.reference",{"title":313,"path":314,"stem":315},"Cookie Consent","\u002Fmodules\u002Ffeatures\u002Fcookie-consent","3.modules\u002F3.features\u002F3.cookie-consent",{"title":317,"path":318,"stem":319},"MCP","\u002Fmodules\u002Ffeatures\u002Fmcp","3.modules\u002F3.features\u002F4.mcp",{"title":321,"icon":49,"path":322,"stem":323,"children":324,"page":49},"Interface","\u002Fmodules\u002Finterface","3.modules\u002F4.interface",[325,350,353,357,361],{"title":326,"path":327,"stem":328,"children":329},"UI","\u002Fmodules\u002Finterface\u002Fui","3.modules\u002F4.interface\u002F1.ui\u002Findex",[330,331,335,339,343,347],{"title":173,"path":327,"stem":328},{"title":332,"path":333,"stem":334},"Page components","\u002Fmodules\u002Finterface\u002Fui\u002Fpage-components","3.modules\u002F4.interface\u002F1.ui\u002F2.page-components",{"title":336,"path":337,"stem":338},"App shell","\u002Fmodules\u002Finterface\u002Fui\u002Fapp-shell","3.modules\u002F4.interface\u002F1.ui\u002F3.app-shell",{"title":340,"path":341,"stem":342},"Form inputs","\u002Fmodules\u002Finterface\u002Fui\u002Fform-inputs","3.modules\u002F4.interface\u002F1.ui\u002F4.form-inputs",{"title":344,"path":345,"stem":346},"Composables and helpers","\u002Fmodules\u002Finterface\u002Fui\u002Fcomposables","3.modules\u002F4.interface\u002F1.ui\u002F5.composables",{"title":179,"path":348,"stem":349},"\u002Fmodules\u002Finterface\u002Fui\u002Freference","3.modules\u002F4.interface\u002F1.ui\u002F6.reference",{"title":217,"path":351,"stem":352},"\u002Fmodules\u002Finterface\u002Fadmin","3.modules\u002F4.interface\u002F2.admin",{"title":354,"path":355,"stem":356},"Menu","\u002Fmodules\u002Finterface\u002Fmenu","3.modules\u002F4.interface\u002F3.menu",{"title":358,"path":359,"stem":360},"Widget","\u002Fmodules\u002Finterface\u002Fwidget","3.modules\u002F4.interface\u002F4.widget",{"title":362,"path":363,"stem":364,"children":365},"Mobile","\u002Fmodules\u002Finterface\u002Fmobile","3.modules\u002F4.interface\u002F5.mobile\u002Findex",[366,367,371],{"title":173,"path":363,"stem":364},{"title":368,"path":369,"stem":370},"CLI and devices","\u002Fmodules\u002Finterface\u002Fmobile\u002Fcli-and-devices","3.modules\u002F4.interface\u002F5.mobile\u002F2.cli-and-devices",{"title":372,"path":373,"stem":374},"Splash screen","\u002Fmodules\u002Finterface\u002Fmobile\u002Fsplash-screen","3.modules\u002F4.interface\u002F5.mobile\u002F3.splash-screen",{"title":376,"icon":49,"path":377,"stem":378,"children":379,"page":49},"Platform","\u002Fmodules\u002Fplatform","3.modules\u002F5.platform",[380,402,406,423],{"title":381,"path":382,"stem":383,"children":384},"Module Kit","\u002Fmodules\u002Fplatform\u002Fmodule-kit","3.modules\u002F5.platform\u002F1.module-kit\u002Findex",[385,386,390,394,398],{"title":173,"path":382,"stem":383},{"title":387,"path":388,"stem":389},"Server toolkit","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fserver-toolkit","3.modules\u002F5.platform\u002F1.module-kit\u002F2.server-toolkit",{"title":391,"path":392,"stem":393},"Registries and menus","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fregistries-and-menus","3.modules\u002F5.platform\u002F1.module-kit\u002F3.registries-and-menus",{"title":395,"path":396,"stem":397},"Translations","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fi18n","3.modules\u002F5.platform\u002F1.module-kit\u002F4.i18n",{"title":399,"path":400,"stem":401},"Database helpers","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fdatabase","3.modules\u002F5.platform\u002F1.module-kit\u002F5.database",{"title":403,"path":404,"stem":405},"Notify","\u002Fmodules\u002Fplatform\u002Fnotify","3.modules\u002F5.platform\u002F2.notify",{"title":407,"path":408,"stem":409,"children":410},"Email Templates","\u002Fmodules\u002Fplatform\u002Femail-templates","3.modules\u002F5.platform\u002F3.email-templates\u002Findex",[411,412,416,419],{"title":173,"path":408,"stem":409},{"title":413,"path":414,"stem":415},"Email components","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fcomponents","3.modules\u002F5.platform\u002F3.email-templates\u002F2.components",{"title":175,"path":417,"stem":418},"\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fserver","3.modules\u002F5.platform\u002F3.email-templates\u002F3.server",{"title":420,"path":421,"stem":422},"Module emails","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fmodule-emails","3.modules\u002F5.platform\u002F3.email-templates\u002F4.module-emails",{"title":424,"path":425,"stem":426,"children":427},"Base Layer","\u002Fmodules\u002Fplatform\u002Fbase-layer","3.modules\u002F5.platform\u002F4.base-layer\u002Findex",[428,429,433,437],{"title":173,"path":425,"stem":426},{"title":430,"path":431,"stem":432},"Content collections","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcontent-collections","3.modules\u002F5.platform\u002F4.base-layer\u002F2.content-collections",{"title":434,"path":435,"stem":436},"Layouts and routing","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Flayouts-and-routing","3.modules\u002F5.platform\u002F4.base-layer\u002F3.layouts-and-routing",{"title":438,"path":439,"stem":440},"Composables and utils","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcomposables-and-utils","3.modules\u002F5.platform\u002F4.base-layer\u002F4.composables-and-utils",{"title":442,"icon":443,"path":444,"stem":445,"children":446,"page":49},"Examples","i-lucide-code-xml","\u002Fexamples","4.examples",[447,466,476],{"title":448,"icon":49,"path":449,"stem":450,"children":451,"page":49},"Starters","\u002Fexamples\u002Fstarters","4.examples\u002F1.starters",[452,456,461],{"title":453,"path":454,"stem":455,"icon":6},"Workspace starter","\u002Fexamples\u002Fstarters\u002Fworkspace","4.examples\u002F1.starters\u002F1.workspace",{"title":457,"path":458,"stem":459,"icon":460},"Mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile","4.examples\u002F1.starters\u002F2.mobile","i-lucide-smartphone",{"title":462,"path":463,"stem":464,"icon":465},"Standalone mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile-standalone","4.examples\u002F1.starters\u002F3.mobile-standalone","i-lucide-tablet-smartphone",{"title":467,"icon":49,"path":468,"stem":469,"children":470,"page":49},"Apps","\u002Fexamples\u002Fapps","4.examples\u002F2.apps",[471],{"title":472,"path":473,"stem":474,"icon":475},"Frigear website app","\u002Fexamples\u002Fapps\u002Ffrigear-nu-website","4.examples\u002F2.apps\u002F1.frigear-nu-website","i-lucide-layout-dashboard",{"title":477,"icon":49,"path":478,"stem":479,"children":480,"page":49},"Tasks","\u002Fexamples\u002Ftasks","4.examples\u002F3.tasks",[481,485,489,494,499],{"title":482,"path":483,"stem":484,"icon":70},"Protect a route","\u002Fexamples\u002Ftasks\u002Fprotect-a-route","4.examples\u002F3.tasks\u002F1.protect-a-route",{"title":486,"path":487,"stem":488,"icon":475},"Add an admin page","\u002Fexamples\u002Ftasks\u002Fadd-an-admin-page","4.examples\u002F3.tasks\u002F2.add-an-admin-page",{"title":490,"path":491,"stem":492,"icon":493},"Sell event tickets","\u002Fexamples\u002Ftasks\u002Fsell-event-tickets","4.examples\u002F3.tasks\u002F3.sell-event-tickets","i-lucide-ticket",{"title":495,"path":496,"stem":497,"icon":498},"Build a form","\u002Fexamples\u002Ftasks\u002Fbuild-a-form","4.examples\u002F3.tasks\u002F4.build-a-form","i-lucide-clipboard-list",{"title":500,"path":501,"stem":502,"icon":503},"Send an email","\u002Fexamples\u002Ftasks\u002Fsend-an-email","4.examples\u002F3.tasks\u002F5.send-an-email","i-lucide-mail",{"title":505,"icon":506,"path":507,"stem":508,"children":509,"page":49},"Contribute","i-lucide-git-pull-request","\u002Fcontribute","5.contribute",[510,513,518,544,549,552,556,571],{"title":173,"path":511,"stem":512,"icon":506},"\u002Fcontribute\u002Foverview","5.contribute\u002F1.overview",{"title":514,"path":515,"stem":516,"icon":517},"Local development","\u002Fcontribute\u002Flocal-development","5.contribute\u002F2.local-development","i-lucide-terminal",{"title":519,"icon":49,"path":520,"stem":521,"children":522,"page":49},"Writing a module","\u002Fcontribute\u002Fwriting-a-module","5.contribute\u002F3.writing-a-module",[523,527,532,536,541],{"title":524,"path":525,"stem":526,"icon":39},"Scaffold a module","\u002Fcontribute\u002Fwriting-a-module\u002Fscaffold","5.contribute\u002F3.writing-a-module\u002F1.scaffold",{"title":528,"path":529,"stem":530,"icon":531},"Setup checklist","\u002Fcontribute\u002Fwriting-a-module\u002Fsetup-checklist","5.contribute\u002F3.writing-a-module\u002F2.setup-checklist","i-lucide-list-checks",{"title":533,"path":534,"stem":535,"icon":44},"Database tables","\u002Fcontribute\u002Fwriting-a-module\u002Fdatabase-tables","5.contribute\u002F3.writing-a-module\u002F3.database-tables",{"title":537,"path":538,"stem":539,"icon":540},"Testing","\u002Fcontribute\u002Fwriting-a-module\u002Ftesting","5.contribute\u002F3.writing-a-module\u002F4.testing","i-lucide-flask-conical",{"title":67,"path":542,"stem":543,"icon":70},"\u002Fcontribute\u002Fwriting-a-module\u002Faccess-control","5.contribute\u002F3.writing-a-module\u002F5.access-control",{"title":545,"path":546,"stem":547,"icon":548},"Publishing","\u002Fcontribute\u002Fpublishing","5.contribute\u002F4.publishing","i-lucide-package-check",{"title":448,"path":550,"stem":551,"icon":6},"\u002Fcontribute\u002Fstarters","5.contribute\u002F5.starters",{"title":553,"path":554,"stem":555,"icon":52},"Documentation","\u002Fcontribute\u002Fdocumentation","5.contribute\u002F6.documentation",{"title":557,"icon":49,"path":558,"stem":559,"children":560,"page":49},"Tooling","\u002Fcontribute\u002Ftooling","5.contribute\u002F7.tooling",[561,566],{"title":562,"path":563,"stem":564,"icon":565},"CLI","\u002Fcontribute\u002Ftooling\u002Fcli","5.contribute\u002F7.tooling\u002F1.cli","i-lucide-square-terminal",{"title":567,"path":568,"stem":569,"icon":570},"ESLint config","\u002Fcontribute\u002Ftooling\u002Feslint-config","5.contribute\u002F7.tooling\u002F2.eslint-config","i-lucide-spell-check",{"title":572,"icon":49,"path":573,"stem":574,"children":575},"Decisions","\u002Fcontribute\u002Fdecisions","5.contribute\u002F8.decisions\u002Findex",[576,578,583],{"title":572,"path":573,"stem":574,"icon":577},"i-lucide-scale",{"title":579,"path":580,"stem":581,"icon":582},"Session lifetimes per OAuth client","\u002Fcontribute\u002Fdecisions\u002Foauth-token-lifetimes","5.contribute\u002F8.decisions\u002F1.oauth-token-lifetimes","i-lucide-timer",{"title":584,"path":585,"stem":586,"icon":70},"One permission model","\u002Fcontribute\u002Fdecisions\u002Fpermission-model","5.contribute\u002F8.decisions\u002F2.permission-model",{"id":588,"title":553,"body":589,"description":2320,"extension":2321,"links":2322,"meta":2323,"navigation":2324,"path":554,"seo":2325,"stem":555,"__hash__":2326},"docs\u002F5.contribute\u002F6.documentation.md",{"type":590,"value":591,"toc":2308},"minimark",[592,596,620,623,671,676,683,779,783,892,918,922,999,1003,1006,1185,1188,1253,1267,1271,1274,1280,1893,1919,1923,1926,2115,2119,2142,2146,2152,2155,2168,2171,2247,2262,2278,2281,2285,2304],[593,594,595],"p",{},"This page is for anyone who adds or edits a page on this documentation site. It tells you where a page goes, which\ntemplate it follows and how to write it. It ends with the link check every pull request runs.",[593,597,598,599,603,604,611,612,615,616,619],{},"The site is ",[600,601,602],"code",{},"@frigear-nu\u002Fdocs",", a ",[605,606,610],"a",{"href":607,"rel":608},"https:\u002F\u002Fdocus.dev",[609],"nofollow","Docus"," app under ",[600,613,614],{},"apps\u002Fdocs",". It documents the whole repository\nfor developers who build on the Frigear modules. Product documentation for end users belongs in ",[600,617,618],{},"apps\u002Fwebsite",".",[593,621,622],{},"Run it from the repository root:",[624,625,630],"pre",{"className":626,"code":627,"language":628,"meta":629,"style":629},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm install\npnpm --filter @frigear-nu\u002Fdocs dev\npnpm --filter @frigear-nu\u002Fdocs build\n","bash","",[600,631,632,645,659],{"__ignoreMap":629},[633,634,637,641],"span",{"class":635,"line":636},"line",1,[633,638,640],{"class":639},"sBMFI","pnpm",[633,642,644],{"class":643},"sfazB"," install\n",[633,646,648,650,653,656],{"class":635,"line":647},2,[633,649,640],{"class":639},[633,651,652],{"class":643}," --filter",[633,654,655],{"class":643}," @frigear-nu\u002Fdocs",[633,657,658],{"class":643}," dev\n",[633,660,662,664,666,668],{"class":635,"line":661},3,[633,663,640],{"class":639},[633,665,652],{"class":643},[633,667,655],{"class":643},[633,669,670],{"class":643}," build\n",[672,673,675],"h2",{"id":674},"where-a-page-belongs","Where a page belongs",[593,677,678,679,682],{},"Content lives in ",[600,680,681],{},"apps\u002Fdocs\u002Fcontent\u002F",", in five numbered folders that are the header tabs:",[684,685,686,702],"table",{},[687,688,689],"thead",{},[690,691,692,696,699],"tr",{},[693,694,695],"th",{},"Folder",[693,697,698],{},"Tab",[693,700,701],{},"Put here",[703,704,705,717,728,757,768],"tbody",{},[690,706,707,712,714],{},[708,709,710],"td",{},[600,711,8],{},[708,713,5],{},[708,715,716],{},"The step-by-step path from zero to a running, deployed app.",[690,718,719,723,725],{},[708,720,721],{},[600,722,54],{},[708,724,51],{},[708,726,727],{},"Concepts, UX patterns, best practices and going further.",[690,729,730,735,737],{},[708,731,732],{},[600,733,734],{},"3.modules\u002F\u003Ccategory>",[708,736,156],{},[708,738,739,740,743,744,743,747,743,750,753,754,619],{},"One reference page per module, in its category folder: ",[600,741,742],{},"1.identity",", ",[600,745,746],{},"2.commerce",[600,748,749],{},"3.features",[600,751,752],{},"4.interface"," or ",[600,755,756],{},"5.platform",[690,758,759,763,765],{},[708,760,761],{},[600,762,445],{},[708,764,442],{},[708,766,767],{},"Starters, reference apps and short task examples.",[690,769,770,774,776],{},[708,771,772],{},[600,773,508],{},[708,775,505],{},[708,777,778],{},"Working on this repository: development, writing a module, publishing, starters, docs and tooling.",[672,780,782],{"id":781},"add-or-update-a-page","Add or update a page",[784,785,786,794,805,874,882,885],"ol",{},[787,788,789,790,793],"li",{},"Pick the folder from the table above. A new section gets a numbered folder with a ",[600,791,792],{},".navigation.yml"," for its title and\nicon.",[787,795,796,797,800,801,804],{},"Add a numbered Markdown file, for example ",[600,798,799],{},"3.modules\u002F3.features\u002F5.my-module.md",". Docus sorts navigation by file name\nas a string, so use unique two-digit prefixes; the name after the number becomes the route\n(",[600,802,803],{},"\u002Fmodules\u002Ffeatures\u002Fmy-module","). Inserting a page in the middle may mean renumbering its siblings, which keeps\ntheir routes.",[787,806,807,808,811,812,815,816],{},"Add frontmatter with a ",[600,809,810],{},"title",", a one-sentence ",[600,813,814],{},"description"," and, optionally, a navigation icon:",[624,817,821],{"className":818,"code":819,"language":820,"meta":629,"style":629},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","---\ntitle: My module\ndescription: One sentence on what the page covers.\nnavigation:\n  icon: i-lucide-puzzle\n---\n","yaml",[600,822,823,828,840,849,858,869],{"__ignoreMap":629},[633,824,825],{"class":635,"line":636},[633,826,827],{"class":639},"---\n",[633,829,830,833,837],{"class":635,"line":647},[633,831,810],{"class":832},"swJcz",[633,834,836],{"class":835},"sMK4o",":",[633,838,839],{"class":643}," My module\n",[633,841,842,844,846],{"class":635,"line":661},[633,843,814],{"class":832},[633,845,836],{"class":835},[633,847,848],{"class":643}," One sentence on what the page covers.\n",[633,850,852,855],{"class":635,"line":851},4,[633,853,854],{"class":832},"navigation",[633,856,857],{"class":835},":\n",[633,859,861,864,866],{"class":635,"line":860},5,[633,862,863],{"class":832},"  icon",[633,865,836],{"class":835},[633,867,868],{"class":643}," i-lucide-puzzle\n",[633,870,872],{"class":635,"line":871},6,[633,873,827],{"class":639},[787,875,876,877,881],{},"Write focused Markdown about the repository, using the ",[605,878,880],{"href":879},"#page-templates","page templates"," below. Check code and\npackage READMEs before documenting behavior.",[787,883,884],{},"Run the docs app and check the page and its navigation.",[787,886,887,888,891],{},"Run ",[600,889,890],{},"pnpm docs:check"," and fix what it reports.",[893,894,895,898],"warning",{},[593,896,897],{},"Moving or renaming a page changes its route and breaks every link to the old one. Do it only when you also:",[784,899,900,910,913],{},[787,901,902,903,906,907,619],{},"Add an old to new entry in the ",[600,904,905],{},"redirects"," of ",[600,908,909],{},"apps\u002Fdocs\u002Fnuxt.config.ts",[787,911,912],{},"Update every link to the old route.",[787,914,887,915,917],{},[600,916,890],{}," and make it pass.",[672,919,921],{"id":920},"conventions","Conventions",[923,924,925,942,951,961,967,981,990],"ul",{},[787,926,927,931,932,743,934,937,938,941],{},[928,929,930],"strong",{},"Titles."," Use the plain name (",[600,933,168],{},[600,935,936],{},"Cookie consent","), never a ",[600,939,940],{},"Module"," suffix. Headings are sentence case.",[787,943,944,947,948,950],{},[928,945,946],{},"Page layout."," Use the ",[605,949,880],{"href":879}," below.",[787,952,953,956,957,960],{},[928,954,955],{},"Code and reference."," Signatures, types and payloads go in fenced ",[600,958,959],{},"ts"," blocks. Hooks, routes, options and\nenvironment variables go in tables, not running prose.",[787,962,963,966],{},[928,964,965],{},"Accuracy."," Check defaults, routes and hooks against the source before documenting them.",[787,968,969,972,973,976,977,980],{},[928,970,971],{},"Nuxt 4."," Write every example as Nuxt 4 code (",[600,974,975],{},"app\u002F"," directory, ",[600,978,979],{},"defineNuxtConfig","), never Nuxt 3 or 2 patterns.",[787,982,983,986,987,989],{},[928,984,985],{},"Links."," Link to pages by route (",[600,988,169],{},"), never by numbered file name.",[787,991,992,995,996,619],{},[928,993,994],{},"Starters."," A page that describes a starter stays in step with the files in ",[600,997,998],{},".starters\u002F",[672,1000,1002],{"id":1001},"writing","Writing",[593,1004,1005],{},"Readers told us the docs left them asking \"what is this even for?\". These rules answer that question on every page.\nEach row shows a sentence from the current docs and its rewrite.",[684,1007,1008,1021],{},[687,1009,1010],{},[690,1011,1012,1015,1018],{},[693,1013,1014],{},"Rule",[693,1016,1017],{},"Before",[693,1019,1020],{},"After",[703,1022,1023,1038,1055,1073,1084,1098,1109,1124,1138,1155,1174],{},[690,1024,1025,1028,1035],{},[708,1026,1027],{},"The first screen says what it is, who it is for and what you get. Code names come after.",[708,1029,1030,1031,1034],{},"\"The Nuxt module that owns ",[928,1032,1033],{},"authentication",": …\"",[708,1036,1037],{},"\"Lets people sign in to your app with a password, an emailed link, a passkey or GitHub\u002FGoogle, and tells every server route who is calling.\"",[690,1039,1040,1043,1049],{},[708,1041,1042],{},"One fact per sentence.",[708,1044,1045,1046,1048],{},"\"Only the SHA-256 is stored, and they are accepted in the ",[600,1047,199],{}," header only.\"",[708,1050,1051,1052,1054],{},"\"Only a hash of the token is stored. Send it in the ",[600,1053,199],{}," header.\"",[690,1056,1057,1060,1067],{},[708,1058,1059],{},"Inline code at most once per sentence, and never before its plain explanation.",[708,1061,1062,1063,1066],{},"\"A caller is one of three kinds, all resolved into the same ",[600,1064,1065],{},"AuthPrincipal","\"",[708,1068,1069,1070,1072],{},"\"Auth works out who made the request and how they proved it. It hands your route that answer, the principal (",[600,1071,1065],{},").\"",[690,1074,1075,1078,1081],{},[708,1076,1077],{},"Expand acronyms on first use per page.",[708,1079,1080],{},"\"PKCE sign-in for SPAs and Capacitor apps\"",[708,1082,1083],{},"\"sign-in with PKCE (Proof Key for Code Exchange) for single-page apps (SPAs) and Capacitor apps\"",[690,1085,1086,1089,1092],{},[708,1087,1088],{},"Link the glossary term on first use per page.",[708,1090,1091],{},"The first \"staff\" on a page has no link.",[708,1093,1066,1094,1097],{},[605,1095,1096],{"href":87},"staff","\" on first use, plain afterwards.",[690,1099,1100,1103,1106],{},[708,1101,1102],{},"Never two names for one concept.",[708,1104,1105],{},"\"OAuth client\" and \"application\" on the same page.",[708,1107,1108],{},"\"OAuth application\" throughout.",[690,1110,1111,1114,1117],{},[708,1112,1113],{},"Number procedures in execution order, with prerequisites before step 1.",[708,1115,1116],{},"\"Then: 1. … 3. Implement the hooks. Without them nobody is an admin.\"",[708,1118,1119,1120,1123],{},"A ",[600,1121,1122],{},"::warning"," \"Without these hooks no one can manage applications\" before step 3.",[690,1125,1126,1132,1135],{},[708,1127,1128,1129,1131],{},"Put a ",[600,1130,1122],{}," before the step it protects, never after.",[708,1133,1134],{},"The migration warning follows the config block.",[708,1136,1137],{},"The migration is its own step, with the warning first.",[690,1139,1140,1147,1150],{},[708,1141,1142,1143,1146],{},"Use ",[600,1144,1145],{},"::caution"," for irreversible or security-relevant steps.",[708,1148,1149],{},"Key rotation written as plain prose.",[708,1151,1152,1154],{},[600,1153,1145],{}," \"Use a different signing key per environment.\"",[690,1156,1157,1160,1166],{},[708,1158,1159],{},"A table cell holds one fact in under about 25 words.",[708,1161,1162,1163,619],{},"A 45-word purpose cell for ",[600,1164,1165],{},"afterLogin",[708,1167,1168,1169,1173],{},"The cell \"Where users land after signing in.\", plus an ",[928,1170,1171],{},[600,1172,1165],{}," paragraph below the table.",[690,1175,1176,1179,1182],{},[708,1177,1178],{},"No wall of prose.",[708,1180,1181],{},"Three unbroken paragraphs after an options table.",[708,1183,1184],{},"At most about six paragraphs between a table, callout or code block.",[593,1186,1187],{},"Most pages carry several callouts. Pick each one by its job:",[684,1189,1190,1200],{},[687,1191,1192],{},[690,1193,1194,1197],{},[693,1195,1196],{},"Callout",[693,1198,1199],{},"Use it for",[703,1201,1202,1212,1222,1231,1240],{},[690,1203,1204,1209],{},[708,1205,1206],{},[600,1207,1208],{},"::note",[708,1210,1211],{},"Background the reader needs for the next step.",[690,1213,1214,1219],{},[708,1215,1216],{},[600,1217,1218],{},"::tip",[708,1220,1221],{},"A recommendation or the shortest path.",[690,1223,1224,1228],{},[708,1225,1226],{},[600,1227,1122],{},[708,1229,1230],{},"What breaks if a step is skipped. It goes before that step.",[690,1232,1233,1237],{},[708,1234,1235],{},[600,1236,1145],{},[708,1238,1239],{},"A step that is irreversible or affects security.",[690,1241,1242,1247],{},[708,1243,1244],{},[600,1245,1246],{},"::callout{color=\"success\" icon=\"i-lucide-check\"}",[708,1248,1249,1252],{},[928,1250,1251],{},"What you should see"," after a procedure.",[593,1254,1255,1258,1259,1262,1263,1266],{},[928,1256,1257],{},"Options."," The lead sentence of an options section is always \"Options go under the ",[600,1260,1261],{},"x"," key.\" The table then shows\neach option's full path from that key, for example ",[600,1264,1265],{},"settings.pages.admin",". Long explanations go below\nthe table as paragraphs that start with the option name in bold. A module without options says \"The module has no\noptions.\"",[672,1268,1270],{"id":1269},"page-templates","Page templates",[593,1272,1273],{},"Most pages follow one of five templates. Pick the tab for the page you are writing.",[593,1275,1276,1277,619],{},"Other pages, such as best practices, UX patterns, going further and contribute pages, have no fixed template. They still\nopen by saying what the page is for and who it is for, and they end with ",[600,1278,1279],{},"## Next steps",[1281,1282,1283,1438,1662,1730,1830],"tabs",{},[1284,1285,1287,1297],"tabs-item",{"label":1286},"Module overview",[593,1288,1289,1290,1293,1294,1296],{},"For the ",[600,1291,1292],{},"index.md"," of a module folder, or a module that has a single file. The front matter ",[600,1295,814],{}," says what the\nmodule is for in one sentence, not a feature list.",[784,1298,1299,1305,1313,1321,1343,1375,1389,1431],{},[787,1300,1301,1304],{},[928,1302,1303],{},"No heading."," Two to four plain sentences: what the module does for the host app and its users, when to use it,\nand when to use something else (one link). The package name does not appear before the second sentence.",[787,1306,1307,1312],{},[928,1308,1309,619],{},[600,1310,1311],{},"## What you get"," Bullets in reader terms, grouped as Pages (paths), Admin area (screens), Server routes,\nComposables and helpers, and Emails. Mark each item as on by default or opt-in.",[787,1314,1315,1320],{},[928,1316,1317,619],{},[600,1318,1319],{},":module-runtime{…}"," The badge row, unchanged.",[787,1322,1323,1328,1329,743,1332,1335,1336,1339,1340,619],{},[928,1324,1325,1327],{},[600,1326,1208],{}," with requirements."," Exactly three lines: ",[928,1330,1331],{},"Installed for you:",[928,1333,1334],{},"You add:"," and ",[928,1337,1338],{},"Optional:",". Put\nnothing else in this note. When requirements differ by mode, a line may name it, as in ",[928,1341,1342],{},"You add (server mode):",[787,1344,1345,1350,1351,1354,1355,1358,1359,1361,1362,1364,1365,1368,1369,1371,1372,1374],{},[928,1346,1347,619],{},[600,1348,1349],{},"## Quick setup"," A ",[600,1352,1353],{},"::steps"," block: install, then ",[600,1356,1357],{},"nuxt.config.ts",", then a migration if the module adds tables,\nthen the role grants if it has staff permissions. A ",[600,1360,1122],{}," comes before the migration step and before the\ngrants step (\"without this nobody can …\"). A config-key gotcha such as \"",[600,1363,1033],{},", not ",[600,1366,1367],{},"auth","\" gets its own ",[600,1370,1122],{},"\nhere. End with a ",[928,1373,1251],{}," success callout.",[787,1376,1377,1382,1383,1385,1386,619],{},[928,1378,1379,619],{},[600,1380,1381],{},"## Options"," The lead sentence \"Options go under the ",[600,1384,1261],{}," key.\", then a table of option\n(full path), type, default and purpose. Long explanations follow as paragraphs led by the option name in bold.\nRuntime config and environment variables go under ",[600,1387,1388],{},"### Runtime config",[787,1390,1391,1394,1395,743,1398,743,1401,743,1404,743,1407,1410,1411,1414,1415,1394,1418,1421,1422,1425,1426,1428,1429,619],{},[928,1392,1393],{},"Module with a single file:"," ",[600,1396,1397],{},"## Server",[600,1399,1400],{},"## App",[600,1402,1403],{},"## Hooks",[600,1405,1406],{},"## Routes",[600,1408,1409],{},"## Database"," and\n",[600,1412,1413],{},"## Translations",", in that order. Each opens with one sentence, as on a sub-page.\n",[928,1416,1417],{},"Module with a folder:",[600,1419,1420],{},"## Module pages",", a table of page, what it covers and who it is for or which auth mode.\nIt sits after Options.\n",[928,1423,1424],{},"Module with a single file and one sub-page:"," Options, the single-file sections, ",[600,1427,1420],{},", then\n",[600,1430,1279],{},[787,1432,1433,1437],{},[928,1434,1435,619],{},[600,1436,1279],{}," See the closing rule below.",[1284,1439,1441,1448,1495,1564,1567],{"label":1440},"Module sub-page",[593,1442,1443,1444,1447],{},"For any other page in a module folder. Files are not renamed just to fit a role: set the page's role through\n",[600,1445,1446],{},"navigation.title"," and its opening paragraph.",[784,1449,1450,1459,1489],{},[787,1451,1452,1454,1455,1458],{},[928,1453,1303],{}," One or two sentences: what the page covers, who it is for (app developer or module author) and which\nauth mode it applies to (\"Server mode only\", \"Both modes\"). Then: \"Set up the module first: ",[600,1456,1457],{},"[Overview](…)",".\"",[787,1460,1461,1464,1465],{},[928,1462,1463],{},"H2s in the order of the page's role"," (table below). Every H2 opens with one sentence before any table or code:\n",[923,1466,1467,1473,1476,1483],{},[787,1468,1469,1470,1072],{},"Hooks: \"Your app answers these Nitro hooks from a server plugin (",[600,1471,1472],{},"server\u002Fplugins\u002F*.ts",[787,1474,1475],{},"Routes: \"Routes the module registers, and who may call them.\"",[787,1477,1478,1479,1482],{},"Database: \"Tables the module adds. Generate and commit a ",[600,1480,1481],{},"[migration](…)"," after installing.\" A module that adds\nonly columns opens with \"Tables or columns the module adds.\"",[787,1484,1485,1486,1458],{},"Translations: \"Override any string in your app's ",[600,1487,1488],{},"i18n\u002Flocales\u002F\u003Ccode>.json",[787,1490,1491,1437],{},[928,1492,1493,619],{},[600,1494,1279],{},[684,1496,1497,1510],{},[687,1498,1499],{},[690,1500,1501,1504,1507],{},[693,1502,1503],{},"Role",[693,1505,1506],{},"Nav title",[693,1508,1509],{},"Section order",[703,1511,1512,1525,1535,1544,1553],{},[690,1513,1514,1520,1522],{},[708,1515,1516,1517,1519],{},"Overview (",[600,1518,1292],{},")",[708,1521,173],{},[708,1523,1524],{},"The module overview template.",[690,1526,1527,1530,1532],{},[708,1528,1529],{},"Server",[708,1531,175],{},[708,1533,1534],{},"One H2 per job, such as protecting a route or defining scopes.",[690,1536,1537,1539,1541],{},[708,1538,267],{},[708,1540,267],{},[708,1542,1543],{},"Pages, Components, Composables, Utils.",[690,1545,1546,1548,1550],{},[708,1547,179],{},[708,1549,179],{},[708,1551,1552],{},"Hooks, Routes, Database, Translations. An App section moves to the top, or to the App page if there is one.",[690,1554,1555,1558,1561],{},[708,1556,1557],{},"Topic",[708,1559,1560],{},"Its own name",[708,1562,1563],{},"Any page shaped around one task.",[593,1565,1566],{},"How the existing module folders map to these roles:",[684,1568,1569,1578],{},[687,1570,1571],{},[690,1572,1573,1575],{},[693,1574,940],{},[693,1576,1577],{},"Mapping",[703,1579,1580,1598,1616,1636,1647],{},[690,1581,1582,1584],{},[708,1583,1367],{},[708,1585,1586,1589,1590,1593,1594,1597],{},[600,1587,1588],{},"2.server"," is Server, ",[600,1591,1592],{},"3.reference"," is Reference, ",[600,1595,1596],{},"4.client-mode"," is a Topic.",[690,1599,1600,1603],{},[708,1601,1602],{},"oauth-server",[708,1604,1605,1607,1608,1611,1612,1615],{},[600,1606,1588],{}," is Server (nav title \"Server API\"), ",[600,1609,1610],{},"3.hooks"," is the Topic \"Policy hooks\", ",[600,1613,1614],{},"4.routes-and-clients"," is Reference.",[690,1617,1618,1621],{},[708,1619,1620],{},"forms",[708,1622,1623,1626,1627,743,1630,1335,1633,619],{},[600,1624,1625],{},"2.definition"," is a Topic, then ",[600,1628,1629],{},"3.server",[600,1631,1632],{},"4.app",[600,1634,1635],{},"5.reference",[690,1637,1638,1641],{},[708,1639,1640],{},"ui",[708,1642,1643,1644,619],{},"All five pages are Topics, plus ",[600,1645,1646],{},"6.reference",[690,1648,1649,1652],{},[708,1650,1651],{},"events, subscriptions",[708,1653,1654,743,1656,1335,1659,619],{},[600,1655,1588],{},[600,1657,1658],{},"3.app",[600,1660,1661],{},"4.reference",[1284,1663,1665,1670],{"label":1664},"Concept page",[593,1666,1667,1668,619],{},"For pages under ",[600,1669,58],{},[784,1671,1672,1677,1689,1697,1705,1713,1724],{},[787,1673,1674,1676],{},[928,1675,1303],{}," The problem in one or two sentences, then \"After this page you can decide …\".",[787,1678,1679,1684,1685,1688],{},[928,1680,1681,619],{},[600,1682,1683],{},"::callout{icon=\"i-lucide-users\"}"," One line: ",[928,1686,1687],{},"For:"," app developers, module authors or both.",[787,1690,1691,1696],{},[928,1692,1693],{},[600,1694,1695],{},"## Which one do I use?"," A table of what you are building, what to use and a link. It comes before any mechanism.",[787,1698,1699,1704],{},[928,1700,1701,619],{},[600,1702,1703],{},"## Terms"," One bullet per glossary term this page owns (usually three to six), each defined in one sentence.",[787,1706,1707,1712],{},[928,1708,1709,619],{},[600,1710,1711],{},"## How it works"," The mechanism, with an H3 per mechanism. Add a text diagram where a flow crosses apps.",[787,1714,1715,1720,1721,1723],{},[928,1716,1717],{},[600,1718,1719],{},"## Common mistakes"," (optional). One ",[600,1722,1122],{}," per mistake, each saying what breaks.",[787,1725,1726,1437],{},[928,1727,1728,619],{},[600,1729,1279],{},[1284,1731,1733,1737,1811],{"label":1732},"Task page",[593,1734,1667,1735,619],{},[600,1736,478],{},[784,1738,1739,1748,1760,1785,1797,1805],{},[787,1740,1741,1394,1744,1747],{},[928,1742,1743],{},"Bold lead, no heading.",[600,1745,1746],{},"**What you'll build:**"," and one or two sentences.",[787,1749,1750,1755,1756,1458],{},[928,1751,1752,619],{},[600,1753,1754],{},"## Prerequisites"," Links only, no explanations. For the toolchain: \"See\n",[605,1757,1759],{"href":1758},"\u002Fget-started\u002Finstallation#requirements","Requirements",[787,1761,1762,1770,1771,1774,1775,1778,1779,1781,1782,1784],{},[928,1763,1764,743,1767,619],{},[600,1765,1766],{},"## 1. …",[600,1768,1769],{},"## 2. …"," One numbered H2 per step, such as ",[600,1772,1773],{},"## 1. Require a signed-in user",". Only task,\nstarter and get-started pages use numbered headings, and sub-numbering such as ",[600,1776,1777],{},"1.A"," is never used. Each step\ngives one sentence of why, then the code. A ",[600,1780,1122],{}," goes before the step it protects, and a ",[600,1783,1145],{},"\nbefore an irreversible or security-relevant step.",[787,1786,1787,1394,1790,1792,1793,1796],{},[928,1788,1789],{},"Success callout.",[600,1791,1246],{}," with ",[928,1794,1795],{},"What you should see:"," and an\nobservable result, such as a URL, a status code or a screen.",[787,1798,1799,1804],{},[928,1800,1801],{},[600,1802,1803],{},"## Troubleshooting"," (optional). A table of symptom, cause and fix.",[787,1806,1807,1437],{},[928,1808,1809,619],{},[600,1810,1279],{},[593,1812,1813,1814,1817,1818,1820,1821,1824,1825,1829],{},"A numbered heading gets an anchor that starts with ",[600,1815,1816],{},"_"," and its number. For example, ",[600,1819,1773],{},"\nbecomes ",[600,1822,1823],{},"#_1-require-a-signed-in-user",". ",[605,1826,1828],{"href":1827},"#check-links","Check links"," explains the rule.",[1284,1831,1833,1841,1884],{"label":1832},"Starter and get-started page",[593,1834,1835,1836,1838,1839,619],{},"For the starter guides under ",[600,1837,449],{}," and the pages under ",[600,1840,7],{},[784,1842,1843,1851,1861,1870,1878],{},[787,1844,1845,1394,1847,1850],{},[928,1846,1743],{},[600,1848,1849],{},"**What you'll have afterwards:**"," and one to three bullets: a running app, signed in\nas staff, and which screens you can open. Introduction is not a procedure and skips this lead.",[787,1852,1853,1857,1858,1860],{},[928,1854,1855,619],{},[600,1856,1754],{}," A link to ",[605,1859,1759],{"href":1758},". List only the extra tools\nhere, such as Xcode or Android Studio.",[787,1862,1863,1869],{},[928,1864,1865,743,1867,619],{},[600,1866,1766],{},[600,1868,1769],{}," Numbered step headings, as on a task page, with the success callout after the step\nthat runs the app. Procedures are numbered; reference pages, such as Project structure or Database, keep\ndescriptive headings.",[787,1871,1872,1877],{},[928,1873,1874,619],{},[600,1875,1876],{},"## What is in the starter"," Starter pages only: a table of path and what it does.",[787,1879,1880,1437],{},[928,1881,1882,619],{},[600,1883,1279],{},[593,1885,1886,1887,1889,1890,1892],{},"The requirements table exists only on ",[605,1888,16],{"href":1758},".\n",[605,1891,514],{"href":515}," lists only the tools this repository needs beyond those.",[593,1894,1895,1898,1899,1901,1902,743,1905,753,1908,1911,1912,1914,1915,1918],{},[928,1896,1897],{},"Closing section."," Every page ends with ",[600,1900,1279],{},", never ",[600,1903,1904],{},"## Next",[600,1906,1907],{},"## Related",[600,1909,1910],{},"## On this module",". The\nlanding page (",[600,1913,1292],{},") is the exception: it ends with a \"Next steps\" page section instead of a heading. It\nholds at most four links. Each is a bullet in the form ",[600,1916,1917],{},"[Page](\u002Froute) – why you would go there now",", in one\nsentence. Put the most likely next action first, and do not repeat links from the opening paragraph, except the\nalternative module that a module overview intro must link. The link text is the page title; the navigation title\ncarries the page's role.",[672,1920,1922],{"id":1921},"define-once-link-everywhere","Define once, link everywhere",[593,1924,1925],{},"Some explanations used to appear on several pages, and the copies drifted apart. Each one now has a keeper page with the\nfull text. Other pages give one sentence and link to the keeper.",[684,1927,1928,1941],{},[687,1929,1930],{},[690,1931,1932,1935,1938],{},[693,1933,1934],{},"Concept",[693,1936,1937],{},"Pages that repeat it today",[693,1939,1940],{},"Keeper page",[703,1942,1943,1958,1978,2006,2030,2045,2062,2092],{},[690,1944,1945,1948,1952],{},[708,1946,1947],{},"How modules depend on each other",[708,1949,1950],{},[605,1951,62],{"href":63},[708,1953,1954,1957],{},[605,1955,156],{"href":1956},"\u002Fmodules#how-they-fit-together",". Architecture keeps only the rule that dependencies point one way.",[690,1959,1960,1963,1972],{},[708,1961,1962],{},"The kinds of credential",[708,1964,1965,743,1967,743,1970],{},[605,1966,168],{"href":169},[605,1968,1969],{"href":176},"Auth server API",[605,1971,482],{"href":483},[708,1973,1974],{},[605,1975,1977],{"href":1976},"\u002Fguide\u002Fconcepts\u002Fauth-and-scopes#the-principal","The principal",[690,1979,1980,1987,2001],{},[708,1981,1982,1983,1986],{},"The ",[600,1984,1985],{},"sessionOnly"," rule",[708,1988,1989,743,1991,743,1993,743,1995,743,1997,743,1999],{},[605,1990,31],{"href":32},[605,1992,191],{"href":192},[605,1994,1969],{"href":176},[605,1996,482],{"href":483},[605,1998,500],{"href":501},[605,2000,121],{"href":122},[708,2002,2003],{},[605,2004,1985],{"href":2005},"\u002Fguide\u002Fconcepts\u002Fauth-and-scopes#sessiononly",[690,2007,2008,2011,2022],{},[708,2009,2010],{},"Nuxt 4 only",[708,2012,2013,743,2015,743,2017,743,2020],{},[605,2014,156],{"href":158},[605,2016,62],{"href":63},[605,2018,2019],{"href":425},"Base layer",[605,2021,173],{"href":511},[708,2023,2024,2026,2027,2029],{},[605,2025,11],{"href":12},", in one ",[600,2028,1208],{},". This page keeps the writing rule.",[690,2031,2032,2035,2039],{},[708,2033,2034],{},"Adding a module",[708,2036,2037],{},[605,2038,453],{"href":454},[708,2040,2041],{},[605,2042,2044],{"href":2043},"\u002Fget-started\u002Fadding-modules#add-a-module","Add a module",[690,2046,2047,2049,2057],{},[708,2048,1759],{},[708,2050,2051,743,2053,743,2055],{},[605,2052,457],{"href":458},[605,2054,462],{"href":463},[605,2056,514],{"href":515},[708,2058,2059,2061],{},[605,2060,1759],{"href":1758},". The others list extra tools only.",[690,2063,2064,2067,2081],{},[708,2065,2066],{},"Public and confidential applications",[708,2068,2069,743,2072,743,2074,743,2076,743,2078],{},[605,2070,2071],{"href":231},"OAuth Server helpers",[605,2073,183],{"href":184},[605,2075,462],{"href":463},[605,2077,131],{"href":132},[605,2079,2080],{"href":137},"OAuth application",[708,2082,2083,2084,2087,2088,619],{},"The concept: ",[605,2085,81],{"href":2086},"\u002Fguide\u002Fconcepts\u002Fidentity#public-and-confidential-applications",". The mechanics: ",[605,2089,2091],{"href":2090},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients#public-applications","Public applications",[690,2093,2094,2097,2103],{},[708,2095,2096],{},"Migrations and dialects",[708,2098,2099,743,2101],{},[605,2100,26],{"href":27},[605,2102,533],{"href":534},[708,2104,2105,2106,2108,2109,2112,2113,619],{},"For app developers: ",[605,2107,41],{"href":42},". For module authors: ",[605,2110,2111],{"href":400},"Module Kit database helpers",". For extending tables: ",[605,2114,77],{"href":78},[672,2116,2118],{"id":2117},"pictures","Pictures",[593,2120,2121,2122,2125,2126,2129,2130,2133,2134,2137,2138,2141],{},"Use screenshots for layouts, such as those on the ",[605,2123,2124],{"href":97},"UX pattern"," pages. Use\ntext diagrams in a ",[600,2127,2128],{},"text"," code block for flows, such as a sign-in across apps. Images live in\n",[600,2131,2132],{},"apps\u002Fdocs\u002Fpublic\u002Fimages\u002F\u003Csection>\u002F\u003Cpage>-\u003Cpattern>.png",", and a pull request that changes a layout in ",[600,2135,2136],{},"packages\u002Fui"," or\n",[600,2139,2140],{},"packages\u002Fadmin"," recaptures them.",[672,2143,2145],{"id":2144},"vocabulary","Vocabulary",[593,2147,1982,2148,2151],{},[605,2149,2150],{"href":87},"glossary"," lists the one word these docs use for each concept, and the words to avoid.\nLink a glossary term to it the first time a page uses that term, then write it plainly.",[672,2153,1828],{"id":2154},"check-links",[593,2156,2157,2159,2160,2163,2164,2167],{},[600,2158,890],{}," runs ",[600,2161,2162],{},"scripts\u002Fdocs-check-links.mjs",". It is plain Node with no dependencies, so it runs in seconds.\nThe Docs workflow (",[600,2165,2166],{},".github\u002Fworkflows\u002Fdocs.yml",") runs it on every pull request that touches the docs.",[593,2169,2170],{},"It checks:",[684,2172,2173,2183],{},[687,2174,2175],{},[690,2176,2177,2180],{},[693,2178,2179],{},"Check",[693,2181,2182],{},"What fails",[703,2184,2185,2200,2211,2219,2240],{},[690,2186,2187,2190],{},[708,2188,2189],{},"Routes",[708,2191,2192,2193,2196,2197,619],{},"A link to a page that does not exist, or an ",[600,2194,2195],{},"\u002Fimages\u002F…"," path missing from ",[600,2198,2199],{},"apps\u002Fdocs\u002Fpublic",[690,2201,2202,2205],{},[708,2203,2204],{},"Anchors",[708,2206,1119,2207,2210],{},[600,2208,2209],{},"#anchor"," that matches no heading on the target page.",[690,2212,2213,2216],{},[708,2214,2215],{},"Redirects",[708,2217,2218],{},"A redirect target with no page. A link to a redirect source is only a warning: use the new route.",[690,2220,2221,2224],{},[708,2222,2223],{},"External links",[708,2225,1119,2226,2229,2230,2233,2234,753,2237,2239],{},[600,2227,2228],{},"docs.frigear.dev"," URL in package homepages, package READMEs, starter ",[600,2231,2232],{},"AGENTS.md"," files, the root ",[600,2235,2236],{},"README.md",[600,2238,2232],{}," that no longer resolves.",[690,2241,2242,2244],{},[708,2243,86],{},[708,2245,2246],{},"A route in the glossary's \"Where it is explained\" column that does not resolve.",[593,2248,2249,2250,2253,2254,2256,2257,2259,2260,619],{},"Anchors follow the rule of ",[600,2251,2252],{},"@nuxtjs\u002Fmdc",", not plain GitHub slugs. The heading text is lowercased and stripped of\npunctuation, and spaces become dashes. Repeated dashes then collapse to one, and a leading digit gets a ",[600,2255,1816],{}," prefix. So\n",[600,2258,1773],{}," becomes ",[600,2261,1823],{},[2263,2264,2265,2266,2269,2270,2273,2274,2277],"tip",{},"Add ",[600,2267,2268],{},"--terms"," to list the words the glossary says to avoid, counted per file. For example,\n",[600,2271,2272],{},"pnpm docs:check --terms apps\u002Fdocs\u002Fcontent\u002F1.get-started"," scans one folder. It only reports. Add ",[600,2275,2276],{},"--strict"," to make\neach hit an error once a folder is clean.",[593,2279,2280],{},"Errors make the run exit with code 1. Warnings do not.",[672,2282,2284],{"id":2283},"next-steps","Next steps",[923,2286,2287,2292,2299],{},[787,2288,2289,2291],{},[605,2290,86],{"href":87}," – the words to use before you write.",[787,2293,2294,2298],{},[605,2295,2297],{"href":607,"rel":2296},[609],"Docus documentation"," – the MDC components and site configuration.",[787,2300,2301,2303],{},[605,2302,448],{"href":550}," – keeping a starter guide in step with its files.",[2305,2306,2307],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}",{"title":629,"searchDepth":647,"depth":647,"links":2309},[2310,2311,2312,2313,2314,2315,2316,2317,2318,2319],{"id":674,"depth":647,"text":675},{"id":781,"depth":647,"text":782},{"id":920,"depth":647,"text":921},{"id":1001,"depth":647,"text":1002},{"id":1269,"depth":647,"text":1270},{"id":1921,"depth":647,"text":1922},{"id":2117,"depth":647,"text":2118},{"id":2144,"depth":647,"text":2145},{"id":2154,"depth":647,"text":1828},{"id":2283,"depth":647,"text":2284},"Where a docs page belongs, how to write it so readers know what it is for, and how to check its links.","md",null,{},{"icon":52},{"title":553,"description":2320},"HUQeZFk8bXAS-0NjnmB5PlgFYzL5OLAyYTvWQMqpjTI",[2328,2330],{"title":448,"path":550,"stem":551,"description":2329,"icon":6,"children":-1},"Maintain the starters in .starters\u002F, keep their shared files identical and regenerate their migrations.",{"title":562,"path":563,"stem":564,"description":2331,"icon":565,"children":-1},"Create projects from the starters, add apps and modules, and install Frigear modules with @frigear-nu\u002Fcli.",1794503150662]