[{"data":1,"prerenderedAt":381},["ShallowReactive",2],{"navigation_docs":3,"landing":60},[4,25,45],{"title":5,"path":6,"stem":7,"children":8,"page":24},"Getting Started","\u002Fdocs\u002Fgetting-started","docs\u002F1.getting-started",[9,14,19],{"title":10,"path":11,"stem":12,"icon":13},"Introduction","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":15,"path":16,"stem":17,"icon":18},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","docs\u002F1.getting-started\u002F2.installation","i-lucide-rocket",{"title":20,"path":21,"stem":22,"icon":23},"Configuration","\u002Fdocs\u002Fgetting-started\u002Fconfiguration","docs\u002F1.getting-started\u002F3.configuration","i-lucide-sliders-horizontal",false,{"title":26,"path":27,"stem":28,"children":29,"page":24},"Architecture","\u002Fdocs\u002Farchitecture","docs\u002F2.architecture",[30,35,40],{"title":31,"path":32,"stem":33,"icon":34},"Layers","\u002Fdocs\u002Farchitecture\u002Flayers","docs\u002F2.architecture\u002F1.layers","i-lucide-layers",{"title":36,"path":37,"stem":38,"icon":39},"Multi-tenancy","\u002Fdocs\u002Farchitecture\u002Fmulti-tenancy","docs\u002F2.architecture\u002F2.multi-tenancy","i-lucide-building-2",{"title":41,"path":42,"stem":43,"icon":44},"Testing","\u002Fdocs\u002Farchitecture\u002Ftesting","docs\u002F2.architecture\u002F3.testing","i-lucide-flask-conical",{"title":46,"path":47,"stem":48,"children":49,"page":24},"Reference","\u002Fdocs\u002Freference","docs\u002F3.reference",[50,55],{"title":51,"path":52,"stem":53,"icon":54},"Commands","\u002Fdocs\u002Freference\u002Fcommands","docs\u002F3.reference\u002F1.commands","i-lucide-terminal",{"title":56,"path":57,"stem":58,"icon":59},"Decisions","\u002Fdocs\u002Freference\u002Fdecisions","docs\u002F3.reference\u002F2.decisions","i-lucide-git-branch",{"id":61,"title":62,"body":63,"description":62,"extension":373,"meta":374,"navigation":143,"path":375,"seo":376,"stem":379,"__hash__":380},"landing\u002Findex.md","",{"type":64,"value":65,"toc":371},"minimark",[66,200,206,358,367],[67,68,70,74,77,93],"u-page-hero",{"orientation":69},"horizontal",[71,72,73],"template",{"v-slot:title":62},"Ship multi-tenant SaaS, not scaffolding.",[71,75,76],{"v-slot:description":62},"GStack is an opinionated Nuxt 4 + Supabase starter where access control lives in\nthe database, every subsystem is wired but off by default, and one tenant can\nnever read another's rows — proven by a test, not a promise.",[71,78,79,85],{"v-slot:links":62},[80,81,84],"u-button",{"size":82,"to":16,"trailing-icon":83},"xl","i-lucide-arrow-right","Get started",[80,86,92],{"size":82,"to":87,"color":88,"icon":89,"target":90,"variant":91},"https:\u002F\u002Fgithub.com\u002FTerrorSquad\u002Fgstack","neutral","i-simple-icons-github","_blank","subtle","View on GitHub",[94,95,99],"pre",{"className":96,"code":97,"language":98,"meta":62,"style":62},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm dlx degit TerrorSquad\u002Fgstack my-app   # or: Use this template\ncd my-app\n\npnpm install\npnpm setup          # pick your integrations; writes .env\npnpm supabase start # local Postgres + Auth (needs Docker)\npnpm db:reset       # migrate + seed a demo tenant\npnpm dev            # http:\u002F\u002Flocalhost:3000\n","bash",[100,101,102,128,138,145,153,164,178,189],"code",{"__ignoreMap":62},[103,104,107,111,115,118,121,124],"span",{"class":105,"line":106},"line",1,[103,108,110],{"class":109},"sBMFI","pnpm",[103,112,114],{"class":113},"sfazB"," dlx",[103,116,117],{"class":113}," degit",[103,119,120],{"class":113}," TerrorSquad\u002Fgstack",[103,122,123],{"class":113}," my-app",[103,125,127],{"class":126},"sHwdD","   # or: Use this template\n",[103,129,131,135],{"class":105,"line":130},2,[103,132,134],{"class":133},"s2Zo4","cd",[103,136,137],{"class":113}," my-app\n",[103,139,141],{"class":105,"line":140},3,[103,142,144],{"emptyLinePlaceholder":143},true,"\n",[103,146,148,150],{"class":105,"line":147},4,[103,149,110],{"class":109},[103,151,152],{"class":113}," install\n",[103,154,156,158,161],{"class":105,"line":155},5,[103,157,110],{"class":109},[103,159,160],{"class":113}," setup",[103,162,163],{"class":126},"          # pick your integrations; writes .env\n",[103,165,167,169,172,175],{"class":105,"line":166},6,[103,168,110],{"class":109},[103,170,171],{"class":113}," supabase",[103,173,174],{"class":113}," start",[103,176,177],{"class":126}," # local Postgres + Auth (needs Docker)\n",[103,179,181,183,186],{"class":105,"line":180},7,[103,182,110],{"class":109},[103,184,185],{"class":113}," db:reset",[103,187,188],{"class":126},"       # migrate + seed a demo tenant\n",[103,190,192,194,197],{"class":105,"line":191},8,[103,193,110],{"class":109},[103,195,196],{"class":113}," dev",[103,198,199],{"class":126},"            # http:\u002F\u002Flocalhost:3000\n",[201,202],"u-page-section",{":features":203,"description":204,"title":205},"[{\"title\":\"RLS-first multi-tenancy\",\"description\":\"Every table carries a tenant_id and Postgres Row Level Security scopes rows to the caller's tenant. Page-level role gates are UX only — a bug in a component cannot leak another tenant's data.\",\"icon\":\"i-lucide-shield-check\"},{\"title\":\"Auth that survives SSR\",\"description\":\"Email\u002Fpassword plus GitHub and Google OAuth, password reset, email confirmation, and a global role-aware middleware instead of the Supabase module's redirect.\",\"icon\":\"i-lucide-key-round\"},{\"title\":\"Features as Nuxt Layers\",\"description\":\"Marketing, notes, admin, account, billing, email, feedback, tour and analytics are independent layers. Adding a feature is one scaffold command plus one line in extends.\",\"icon\":\"i-lucide-layers\"},{\"title\":\"Billing\",\"description\":\"Polar checkout, customer portal and webhook behind an adapter — a Merchant of Record, so it works from countries Stripe won't onboard.\",\"icon\":\"i-lucide-credit-card\"},{\"title\":\"One email shell\",\"description\":\"Transactional mail and the Supabase auth templates render from the same generated shell, so the branding can't drift. A unit test fails if it does.\",\"icon\":\"i-lucide-mail\"},{\"title\":\"Accessibility, enforced\",\"description\":\"Playwright and axe run every page in light and dark on a schedule. Contrast overrides live in one design-system layer.\",\"icon\":\"i-lucide-accessibility\"}]","Nothing half-works. Each subsystem is fully wired and switched off until you set its env flag, so a bare clone runs with no third-party account.","Batteries included, every one flag-gated",[201,207,208,211,214],{},[71,209,210],{"v-slot:title":62},"The isolation test",[71,212,213],{"v-slot:description":62},"Most starters claim multi-tenancy. This one logs in as a second tenant and asserts\nthe first tenant's rows are invisible through the real HTTP surface — so the claim\nfails loudly the day someone widens a policy.",[94,215,220],{"className":216,"code":217,"filename":218,"language":219,"meta":62,"style":62},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","test('Globex cannot read Acme rows', async ({ page }) => {\n  await login(page, GLOBEX_ADMIN.email)\n  await page.goto('\u002Fnotes')\n  await expect(page.getByText(ACME_SECRET_NOTE_TITLE)).toHaveCount(0)\n})\n","e2e\u002Ftenant-isolation.spec.ts","ts",[100,221,222,263,292,314,351],{"__ignoreMap":62},[103,223,224,227,231,235,238,240,243,247,250,254,257,260],{"class":105,"line":106},[103,225,226],{"class":133},"test",[103,228,230],{"class":229},"sTEyZ","(",[103,232,234],{"class":233},"sMK4o","'",[103,236,237],{"class":113},"Globex cannot read Acme rows",[103,239,234],{"class":233},[103,241,242],{"class":233},",",[103,244,246],{"class":245},"spNyl"," async",[103,248,249],{"class":233}," ({",[103,251,253],{"class":252},"sHdIc"," page",[103,255,256],{"class":233}," })",[103,258,259],{"class":245}," =>",[103,261,262],{"class":233}," {\n",[103,264,265,269,272,275,278,280,283,286,289],{"class":105,"line":130},[103,266,268],{"class":267},"s7zQu","  await",[103,270,271],{"class":133}," login",[103,273,230],{"class":274},"swJcz",[103,276,277],{"class":229},"page",[103,279,242],{"class":233},[103,281,282],{"class":229}," GLOBEX_ADMIN",[103,284,285],{"class":233},".",[103,287,288],{"class":229},"email",[103,290,291],{"class":274},")\n",[103,293,294,296,298,300,303,305,307,310,312],{"class":105,"line":140},[103,295,268],{"class":267},[103,297,253],{"class":229},[103,299,285],{"class":233},[103,301,302],{"class":133},"goto",[103,304,230],{"class":274},[103,306,234],{"class":233},[103,308,309],{"class":113},"\u002Fnotes",[103,311,234],{"class":233},[103,313,291],{"class":274},[103,315,316,318,321,323,325,327,330,332,335,338,340,343,345,349],{"class":105,"line":147},[103,317,268],{"class":267},[103,319,320],{"class":133}," expect",[103,322,230],{"class":274},[103,324,277],{"class":229},[103,326,285],{"class":233},[103,328,329],{"class":133},"getByText",[103,331,230],{"class":274},[103,333,334],{"class":229},"ACME_SECRET_NOTE_TITLE",[103,336,337],{"class":274},"))",[103,339,285],{"class":233},[103,341,342],{"class":133},"toHaveCount",[103,344,230],{"class":274},[103,346,348],{"class":347},"sbssI","0",[103,350,291],{"class":274},[103,352,353,356],{"class":105,"line":155},[103,354,355],{"class":233},"}",[103,357,291],{"class":229},[201,359,361,364],{":links":360},"[{\"label\":\"Read the docs\",\"to\":\"\u002Fdocs\u002Fgetting-started\u002Fintroduction\",\"size\":\"xl\",\"trailingIcon\":\"i-lucide-arrow-right\"}]",[71,362,363],{"v-slot:title":62},"Free and MIT licensed",[71,365,366],{"v-slot:description":62},"Clone it, rename it with one command, and start building your product instead of\nits scaffolding.",[368,369,370],"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 pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":62,"searchDepth":130,"depth":130,"links":372},[],"md",{},"\u002F",{"title":377,"description":378},"GStack — RLS-first Nuxt + Supabase SaaS starter","An opinionated, type-safe, batteries-included stack for shipping multi-tenant SaaS with Nuxt. Auth, RLS multi-tenancy, billing, email, i18n, a11y and release automation, wired and flag-gated.","index","wdquu3nGtkphujTFQlN9m12eJtSbpeS0BUAZb37ciSU",1785842750508]