[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-navigation":3,"docs-page-getting-started":166},[4,38,57,65,114,138,157],{"id":5,"group":6,"pages":7},"get-started","Get started",[8,13,18,23,28,33],{"path":9,"title":10,"description":11,"navTitle":10,"group":6,"order":12},"\u002Fdocs\u002Fgetting-started","Getting started","Create your app from the kit, run it locally with no credentials, make yourself superadmin and find where your own code goes.",1,{"path":14,"title":15,"description":16,"navTitle":15,"group":6,"order":17},"\u002Fdocs\u002Flayout","Project structure","Where code lives by where it runs, and which server\u002F directories turn a new file into a route, a job or a provider.",2,{"path":19,"title":20,"description":21,"navTitle":20,"group":6,"order":22},"\u002Fdocs\u002Fconfiguration","Configuration","starter.config.ts switches each part of the kit and its providers, environment variables hold the secrets: every key and what it changes.",3,{"path":24,"title":25,"description":26,"navTitle":25,"group":6,"order":27},"\u002Fdocs\u002Ftemplate","Updating from the kit","Keep the kit as a git remote and take each update as one commit you review, with pnpm template:update, then resolve what conflicts.",4,{"path":29,"title":30,"description":31,"navTitle":30,"group":6,"order":32},"\u002Fdocs\u002Fdeployment","Deployment","Ship the app as one Cloudflare Worker: create the resources, set the secrets, deploy main from GitHub Actions or your machine.",5,{"path":34,"title":35,"description":36,"navTitle":35,"group":6,"order":37},"\u002Fdocs\u002Fmcp","MCP server","Connect Claude Code, Cursor or VS Code to https:\u002F\u002Fnuxter.app\u002Fmcp, so your agent searches and reads these docs and their design notes.",6,{"id":39,"group":40,"pages":41},"accounts","Accounts",[42,47,52],{"path":43,"title":44,"description":45,"navTitle":44,"group":40,"order":46},"\u002Fdocs\u002Fauth","Auth","Pick the sign-in methods, add an OAuth provider, protect a route, and handle sessions, second factors and account deletion.",7,{"path":48,"title":49,"description":50,"navTitle":49,"group":40,"order":51},"\u002Fdocs\u002Ftenancy","Organizations","Scope routes and pages to an organization, and work with its members, roles, seats, invitations and a second level such as branches.",8,{"path":53,"title":54,"description":55,"navTitle":54,"group":40,"order":56},"\u002Fdocs\u002Fpermissions","Roles and permissions","Routes check permissions that an account’s role or its organization’s plan grants: checking one, adding a role, and the staff tools.",9,{"id":58,"group":59,"pages":60},"payments","Payments",[61],{"path":62,"title":59,"description":63,"navTitle":59,"group":59,"order":64},"\u002Fdocs\u002Fpayments","Sell plans through Stripe, Polar, Lemon Squeezy or Creem: define plans, connect a provider, gate features, trials, coupons and refunds.",10,{"id":66,"group":67,"pages":68},"building-blocks","Building blocks",[69,74,79,84,89,94,99,104,109],{"path":70,"title":71,"description":72,"navTitle":71,"group":67,"order":73},"\u002Fdocs\u002Fdatabase","Database","Postgres through Drizzle, on Hyperdrive in production and PGlite locally: add a table, query, transactions, migrations and seed data.",11,{"path":75,"title":76,"description":77,"navTitle":76,"group":67,"order":78},"\u002Fdocs\u002Fbackground-jobs","Background jobs","Run work after the response on Cloudflare Queues with retries: add and enqueue a job, run jobs locally, and schedule cron tasks.",12,{"path":80,"title":81,"description":82,"navTitle":81,"group":67,"order":83},"\u002Fdocs\u002Fevents","Events","React to what the kit does by adding a file to server\u002Flisteners\u002F, fire events of your own, and look up every event’s payload.",13,{"path":85,"title":86,"description":87,"navTitle":86,"group":67,"order":88},"\u002Fdocs\u002Femail","Email","Set up sending, send your own mail with deliverEmail, change the templates and wording, handle unsubscribes and add a provider.",14,{"path":90,"title":91,"description":92,"navTitle":91,"group":67,"order":93},"\u002Fdocs\u002Fcontact","Contact","A \u002Fcontact page that mails you a message or shows your address after a Turnstile check: choose the channels, set the address, know the limits.",15,{"path":95,"title":96,"description":97,"navTitle":96,"group":67,"order":98},"\u002Fdocs\u002Fnotifications","Notifications","The dashboard bell: add a notification type, send one with notify(), and how categories, opt-outs and retention apply.",16,{"path":100,"title":101,"description":102,"navTitle":101,"group":67,"order":103},"\u002Fdocs\u002Fstorage","Storage","Uploads in R2 with one policy per purpose: add a purpose, accept an upload, replace or delete a file, and serve it to its owner.",17,{"path":105,"title":106,"description":107,"navTitle":106,"group":67,"order":108},"\u002Fdocs\u002Ffeature-flags","Feature flags","Declare typed flags in starter.config.ts, read them with flag() or useFlag(), roll them out by rule or percentage, and add a provider.",18,{"path":110,"title":111,"description":112,"navTitle":111,"group":67,"order":113},"\u002Fdocs\u002Fai","AI","Call models from server code by role: text, images, speech, transcription, embeddings and video, with provider fallbacks.",19,{"id":115,"group":116,"pages":117},"web","Web",[118,123,128,133],{"path":119,"title":120,"description":121,"navTitle":120,"group":116,"order":122},"\u002Fdocs\u002Fsecurity-headers","Security headers","The Content-Security-Policy and hardening headers on every response: allow another origin, keep tokens out of Referer, accept cross-site posts.",20,{"path":124,"title":125,"description":126,"navTitle":125,"group":116,"order":127},"\u002Fdocs\u002Frate-limiting","Rate limiting","Cap how often a caller hits a route with requireRateLimit, count only failures, space out sends, and protect the zone.",21,{"path":129,"title":130,"description":131,"navTitle":130,"group":116,"order":132},"\u002Fdocs\u002Fanalytics","Analytics","Product analytics and ad conversions sent from the server with no browser script: add an event, connect a provider, and handle consent.",22,{"path":134,"title":135,"description":136,"navTitle":135,"group":116,"order":137},"\u002Fdocs\u002Fobservability","Observability","Find a failed request by its id, send faults to Sentry or Better Stack, report an error you caught, and change the error page.",23,{"id":139,"group":140,"pages":141},"content-and-look","Content and look",[142,147,152],{"path":143,"title":144,"description":145,"navTitle":144,"group":140,"order":146},"\u002Fdocs\u002Fblog","Blog","Markdown posts with an RSS feed per language, and workflows that draft posts with an AI model and open each one as a pull request.",24,{"path":148,"title":149,"description":150,"navTitle":149,"group":140,"order":151},"\u002Fdocs\u002Flanguages","Languages","Add or remove a language, write copy in the locale files, and write code, refusals and links that follow the reader’s language.",25,{"path":153,"title":154,"description":155,"navTitle":154,"group":140,"order":156},"\u002Fdocs\u002Ftheme","Theme","Change the brand colour and font, and build dashboard sections, list pages, loading placeholders and charts that match the kit.",26,{"id":158,"group":159,"pages":160},"quality","Quality",[161],{"path":162,"title":163,"description":164,"navTitle":163,"group":159,"order":165},"\u002Fdocs\u002Ftesting","Testing","Unit tests in Node, component tests in a real Nuxt app and Playwright end to end: test a route or a component, and what CI runs.",27,{"page":167,"surround":1201,"linksToKit":1204},{"path":9,"title":10,"description":11,"navTitle":10,"group":6,"seo":168,"body":170},{"title":169,"description":11},"Start a Nuxt 4 SaaS app on Cloudflare",{"type":171,"value":172,"toc":1187},"minimark",[173,177,193,198,274,280,284,317,324,328,335,338,368,371,475,481,485,519,556,566,616,629,634,651,734,751,765,769,772,794,798,935,958,962,1046,1050,1087,1105,1109,1160,1164,1183],[174,175,10],"h1",{"id":176},"getting-started",[178,179,180,181,192],"p",{},"Nuxter is a Nuxt 4 app for Cloudflare Workers with auth, organizations,\npayments and the rest of a product's plumbing already built. You switch those\nparts on and off in ",[182,183,188],"a",{"href":184,"rel":185,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Fblob\u002Fmain\u002Fstarter.config.ts",[186],"nofollow","Licensees only",[189,190,191],"code",{},"starter.config.ts",", build your\nproduct in the same repository, and pull in kit updates with one command.",[194,195,197],"h2",{"id":196},"what-you-get","What you get",[199,200,201,207,216,221,230,250],"ul",{},[202,203,204,206],"li",{},[182,205,44],{"href":43},": password, magic links, passkeys, TOTP and OAuth, with\nemail verification.",[202,208,209,211,212,215],{},[182,210,49],{"href":48}," with members, roles, seats and invitations,\nand ",[182,213,214],{"href":53},"permissions"," granted by role or by plan.",[202,217,218,220],{},[182,219,59],{"href":62}," through Stripe, Polar, Lemon Squeezy or Creem:\nsubscriptions, one-time plans, trials and coupons.",[202,222,223,225,226,229],{},[182,224,76],{"href":75}," on Cloudflare Queues, and\n",[182,227,228],{"href":80},"events"," your code can listen to.",[202,231,232,234,235,238,239,242,243,246,247,249],{},[182,233,86],{"href":85},", in-app ",[182,236,237],{"href":95},"notifications",", R2\n",[182,240,241],{"href":100},"storage",", ",[182,244,245],{"href":105},"feature flags"," and\n",[182,248,111],{"href":110}," through the Workers AI binding.",[202,251,252,253,242,256,259,260,242,263,266,267,246,270,273],{},"Server-side ",[182,254,255],{"href":129},"analytics",[182,257,258],{"href":148},"languages",", a\nNuxt Content ",[182,261,262],{"href":143},"blog",[182,264,265],{"href":124},"rate limiting",",\n",[182,268,269],{"href":119},"security headers",[182,271,272],{"href":134},"error reporting"," to Sentry or Better Stack.",[178,275,276,277,279],{},"The database is Postgres through Drizzle: Hyperdrive in production, PGlite on\nyour machine (",[182,278,71],{"href":70},"). The UI is Nuxt UI.",[194,281,283],{"id":282},"requirements","Requirements",[199,285,286,297,310],{},[202,287,288,289,292,293,296],{},"Node 22.19+, 24.11+ or 26+ (",[189,290,291],{},"engines"," in ",[189,294,295],{},"package.json",")",[202,298,299,300,292,303,309],{},"pnpm 11 (",[189,301,302],{},"packageManager",[182,304,307],{"href":305,"rel":306,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Fblob\u002Fmain\u002Fpackage.json",[186],[189,308,295],{}," pins the\nexact version)",[202,311,312,313,316],{},"Access to the kit repository, ",[189,314,315],{},"nuxter-app\u002Fkit"," on GitHub",[178,318,319,320,323],{},"You need a Cloudflare account only to deploy, or to call AI models from\n",[189,321,322],{},"pnpm dev",".",[194,325,327],{"id":326},"create-your-app","Create your app",[178,329,330,331,334],{},"Your app gets its own repository and keeps the kit as a second git remote\nnamed ",[189,332,333],{},"template",". That remote is where updates come from.",[178,336,337],{},"On GitHub, click \"Use this template\" on the kit repository, clone the new\nrepository, and add the remote:",[339,340,345],"pre",{"className":341,"code":342,"language":343,"meta":344,"style":344},"language-bash shiki shiki-themes github-light github-light github-dark","git remote add template https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit.git\n","bash","",[189,346,347],{"__ignoreMap":344},[348,349,351,355,359,362,365],"span",{"class":350,"line":12},"line",[348,352,354],{"class":353},"snPdu","git",[348,356,358],{"class":357},"sIIMD"," remote",[348,360,361],{"class":357}," add",[348,363,364],{"class":357}," template",[348,366,367],{"class":357}," https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit.git\n",[178,369,370],{},"To host the repository anywhere else, clone the kit and drop its history:",[339,372,374],{"className":341,"code":373,"language":343,"meta":344,"style":344},"git clone https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit.git my-app\ncd my-app\ngit update-ref -d HEAD\ngit commit -m \"chore: start from the template\"\ngit branch --unset-upstream\ngit remote rename origin template\ngit remote add origin \u003Cyour repository>\n",[189,375,376,389,397,410,423,433,448],{"__ignoreMap":344},[348,377,378,380,383,386],{"class":350,"line":12},[348,379,354],{"class":353},[348,381,382],{"class":357}," clone",[348,384,385],{"class":357}," https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit.git",[348,387,388],{"class":357}," my-app\n",[348,390,391,395],{"class":350,"line":17},[348,392,394],{"class":393},"sBjJW","cd",[348,396,388],{"class":357},[348,398,399,401,404,407],{"class":350,"line":22},[348,400,354],{"class":353},[348,402,403],{"class":357}," update-ref",[348,405,406],{"class":393}," -d",[348,408,409],{"class":357}," HEAD\n",[348,411,412,414,417,420],{"class":350,"line":27},[348,413,354],{"class":353},[348,415,416],{"class":357}," commit",[348,418,419],{"class":393}," -m",[348,421,422],{"class":357}," \"chore: start from the template\"\n",[348,424,425,427,430],{"class":350,"line":32},[348,426,354],{"class":353},[348,428,429],{"class":357}," branch",[348,431,432],{"class":393}," --unset-upstream\n",[348,434,435,437,439,442,445],{"class":350,"line":37},[348,436,354],{"class":353},[348,438,358],{"class":357},[348,440,441],{"class":357}," rename",[348,443,444],{"class":357}," origin",[348,446,447],{"class":357}," template\n",[348,449,450,452,454,456,458,462,465,468,472],{"class":350,"line":46},[348,451,354],{"class":353},[348,453,358],{"class":357},[348,455,361],{"class":357},[348,457,444],{"class":357},[348,459,461],{"class":460},"s8jYJ"," \u003C",[348,463,464],{"class":357},"your",[348,466,467],{"class":357}," repositor",[348,469,471],{"class":470},"sxrX7","y",[348,473,474],{"class":460},">\n",[178,476,477,478,323],{},"Either way, keep your first commit identical to the kit and make your changes\nin the commits after it. The first update compares against that commit to find\nthe kit version you started from. To start the app in a folder of a monorepo,\nsee ",[182,479,480],{"href":24},"Template",[194,482,484],{"id":483},"run-it-locally","Run it locally",[339,486,488],{"className":341,"code":487,"language":343,"meta":344,"style":344},"pnpm install\npnpm db:migrate\npnpm db:seed\npnpm dev\n",[189,489,490,498,505,512],{"__ignoreMap":344},[348,491,492,495],{"class":350,"line":12},[348,493,494],{"class":353},"pnpm",[348,496,497],{"class":357}," install\n",[348,499,500,502],{"class":350,"line":17},[348,501,494],{"class":353},[348,503,504],{"class":357}," db:migrate\n",[348,506,507,509],{"class":350,"line":22},[348,508,494],{"class":353},[348,510,511],{"class":357}," db:seed\n",[348,513,514,516],{"class":350,"line":27},[348,515,494],{"class":353},[348,517,518],{"class":357}," dev\n",[178,520,521,524,525,528,529,532,533,536,537,540,541,543,544,547,548,552,553,555],{},[189,522,523],{},"pnpm install"," also runs ",[189,526,527],{},"wrangler types"," and ",[189,530,531],{},"nuxt prepare","; nothing\ntypechecks until it has. ",[189,534,535],{},"pnpm db:migrate"," creates a PGlite database in\n",[189,538,539],{},".data\u002Fpglite"," so the seed has tables to write to. From then on, ",[189,542,322],{},"\nmigrates it as it starts and serves it on ",[189,545,546],{},"127.0.0.1:5432",", next to the app on\n",[182,549,550],{"href":550,"rel":551},"http:\u002F\u002Flocalhost:3000",[186],". If something else holds 5432, such as another project's\ndev server or a Postgres of your own, ",[189,554,322],{}," takes the next free port up to\n5441 and logs which one.",[178,557,558,561,562,565],{},[189,559,560],{},"pnpm db:seed"," adds 50 accounts, all with the password ",[189,563,564],{},"seed-password-123",".\nWith the shipped config each one also owns an organization. Three have fixed\naddresses:",[567,568,569,582],"table",{},[570,571,572],"thead",{},[573,574,575,579],"tr",{},[576,577,578],"th",{},"Account",[576,580,581],{},"Role",[583,584,585,596,606],"tbody",{},[573,586,587,593],{},[588,589,590],"td",{},[189,591,592],{},"admin@example.com",[588,594,595],{},"superadmin",[573,597,598,603],{},[588,599,600],{},[189,601,602],{},"author@example.com",[588,604,605],{},"staff",[573,607,608,613],{},[588,609,610],{},[189,611,612],{},"user@example.com",[588,614,615],{},"user",[178,617,618,621,622,528,625,628],{},[189,619,620],{},"pnpm db:seed --help"," lists its options, such as ",[189,623,624],{},"--count",[189,626,627],{},"--reset",". It\nonly writes to a database on your machine.",[630,631,633],"h3",{"id":632},"what-runs-without-credentials","What runs without credentials",[178,635,636,637,640,641,643,644,647,648,650],{},"A fresh clone needs no ",[189,638,639],{},".env"," and no Cloudflare login. The first ",[189,642,322],{},"\nwrites a random ",[189,645,646],{},"NUXT_SESSION_PASSWORD"," to ",[189,649,639],{}," for you.",[567,652,653,663],{},[570,654,655],{},[573,656,657,660],{},[576,658,659],{},"Part",[576,661,662],{},"With nothing configured",[583,664,665,673,680,688,705,720],{},[573,666,667,670],{},[588,668,669],{},"KV, R2, Queues, Durable Objects",[588,671,672],{},"Wrangler's local simulators",[573,674,675,677],{},[588,676,86],{},[588,678,679],{},"Printed to the terminal, including verification and reset links",[573,681,682,685],{},[588,683,684],{},"Turnstile",[588,686,687],{},"Cloudflare's always-pass test keys",[573,689,690,693],{},[588,691,692],{},"Workers AI",[588,694,695,696,699,700,292,703],{},"Off. Run ",[189,697,698],{},"pnpm exec wrangler login",", then set ",[189,701,702],{},"NUXT_DEV_REMOTE_AI=true",[189,704,639],{},[573,706,707,710],{},[588,708,709],{},"Stripe checkout and webhook",[588,711,712,713,528,716,719],{},"Answer 500 until ",[189,714,715],{},"NUXT_PAYMENTS_STRIPE_SECRET_KEY",[189,717,718],{},"NUXT_PAYMENTS_STRIPE_WEBHOOK_SECRET"," are set",[573,721,722,725],{},[588,723,724],{},"OAuth",[588,726,727,728,731,732],{},"None listed in ",[189,729,730],{},"auth.oauth",". Each provider you add needs its client id and secret in ",[189,733,639],{},[178,735,736,737,740,741,743,744,746,747,750],{},"Payments are on as shipped, so a route that needs a plan permission\n(",[189,738,739],{},"insights:read"," in the shipped config) answers 402 to a user whose plan does\nnot grant it, with or without Stripe keys. To try a paid feature without\nStripe, sign in as ",[189,742,592],{},", grant ",[189,745,612],{}," a plan on\n",[189,748,749],{},"\u002Fdashboard\u002Fcustomers",", then sign in as that user and open their organization.",[178,752,753,754,756,757,764],{},"Add variables to ",[189,755,639],{}," as you turn things on.\n",[182,758,761],{"href":759,"rel":760,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Fblob\u002Fmain\u002F.env.example",[186],[189,762,763],{},".env.example"," lists every one the kit reads and where each\nvalue comes from.",[194,766,768],{"id":767},"your-first-superadmin","Your first superadmin",[178,770,771],{},"On an empty database, the first account to sign up becomes superadmin once it\nverifies its email address. Locally, the verification link is in the terminal.\nOn a new deploy, register your own account first.",[178,773,774,775,778,779,781,782,784,785,647,788,292,791,793],{},"This happens only while no account holds ",[189,776,777],{},"users:manage",", so after\n",[189,780,560],{}," it never fires: sign in as ",[189,783,592],{}," instead. Set\n",[189,786,787],{},"access.firstAccountRole",[189,789,790],{},"false",[189,792,191],{}," to turn it off.",[194,795,797],{"id":796},"where-your-code-goes","Where your code goes",[567,799,800,810],{},[570,801,802],{},[573,803,804,807],{},[576,805,806],{},"Path",[576,808,809],{},"What goes there",[583,811,812,824,838,852,866,880,898,908,922],{},[573,813,814,821],{},[588,815,816],{},[182,817,819],{"href":184,"rel":818,"title":187},[186],[189,820,191],{},[588,822,823],{},"Which parts and providers are on, plans, roles, permissions, locales",[573,825,826,835],{},[588,827,828],{},[182,829,832],{"href":830,"rel":831,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Ftree\u002Fmain\u002Fapp",[186],[189,833,834],{},"app\u002F",[588,836,837],{},"Pages, components, layouts, composables. The kit's pages are examples to delete or replace",[573,839,840,849],{},[588,841,842],{},[182,843,846],{"href":844,"rel":845,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Ftree\u002Fmain\u002Fserver\u002Fapi",[186],[189,847,848],{},"server\u002Fapi\u002F",[588,850,851],{},"Your API routes, next to the kit's",[573,853,854,863],{},[588,855,856],{},[182,857,860],{"href":858,"rel":859,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Ftree\u002Fmain\u002Fserver\u002Fjobs",[186],[189,861,862],{},"server\u002Fjobs\u002F",[588,864,865],{},"Background jobs, one file each",[573,867,868,877],{},[588,869,870],{},[182,871,874],{"href":872,"rel":873,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Ftree\u002Fmain\u002Fserver\u002Flisteners",[186],[189,875,876],{},"server\u002Flisteners\u002F",[588,878,879],{},"Event listeners, one file each",[573,881,882,891],{},[588,883,884],{},[182,885,888],{"href":886,"rel":887,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Fblob\u002Fmain\u002Fserver\u002Fdatabase\u002Fcustom\u002Fschema.ts",[186],[189,889,890],{},"server\u002Fdatabase\u002Fcustom\u002Fschema.ts",[588,892,893,894,897],{},"Your tables. ",[189,895,896],{},"pnpm db:generate"," writes their migrations",[573,899,900,905],{},[588,901,902],{},[189,903,904],{},"server\u002F\u003Cpart>\u002Fadapters\u002Fcustom\u002F",[588,906,907],{},"A provider of your own for email, payments, AI, flags or monitoring. The filename is its id",[573,909,910,919],{},[588,911,912],{},[182,913,916],{"href":914,"rel":915,"title":187},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Ftree\u002Fmain\u002Fshared",[186],[189,917,918],{},"shared\u002F",[588,920,921],{},"Types, schemas and helpers both sides import. Add yours as new files",[573,923,924,932],{},[588,925,926,242,929],{},[189,927,928],{},"content\u002F",[189,930,931],{},"i18n\u002Flocales\u002F",[588,933,934],{},"Blog posts, legal pages, translations",[178,936,937,938,266,941,242,944,242,947,242,950,953,954,957],{},"Everything else is the kit's: the other directories under ",[189,939,940],{},"server\u002F",[189,942,943],{},"modules\u002F",[189,945,946],{},"build\u002F",[189,948,949],{},"emails\u002F",[189,951,952],{},"test\u002F",". You can edit them, but when an update\nchanges the same lines you resolve a conflict. ",[182,955,956],{"href":14},"Layout"," maps\nthe whole tree.",[194,959,961],{"id":960},"everyday-commands","Everyday commands",[567,963,964,974],{},[570,965,966],{},[573,967,968,971],{},[576,969,970],{},"Command",[576,972,973],{},"What it does",[583,975,976,985,997,1006,1019,1036],{},[573,977,978,982],{},[588,979,980],{},[189,981,322],{},[588,983,984],{},"App and local database",[573,986,987,991],{},[588,988,989],{},[189,990,896],{},[588,992,993,994],{},"Writes a migration for changes in ",[189,995,996],{},"custom\u002Fschema.ts",[573,998,999,1003],{},[588,1000,1001],{},[189,1002,535],{},[588,1004,1005],{},"Applies pending migrations to the local database",[573,1007,1008,1013],{},[588,1009,1010],{},[189,1011,1012],{},"pnpm db:studio",[588,1014,1015,1016,1018],{},"Drizzle Studio on the local database, while ",[189,1017,322],{}," is running",[573,1020,1021,1026],{},[588,1022,1023],{},[189,1024,1025],{},"pnpm test --run",[588,1027,1028,1029,528,1032,1035],{},"The ",[189,1030,1031],{},"unit",[189,1033,1034],{},"nuxt"," test suites",[573,1037,1038,1043],{},[588,1039,1040],{},[189,1041,1042],{},"pnpm lint && pnpm format:check && pnpm typecheck && pnpm test --run",[588,1044,1045],{},"What CI runs on every pull request",[194,1047,1049],{"id":1048},"take-kit-updates","Take kit updates",[339,1051,1053],{"className":341,"code":1052,"language":343,"meta":344,"style":344},"git switch -c template-update-$(date +%Y%m%d)\npnpm template:update\n",[189,1054,1055,1080],{"__ignoreMap":344},[348,1056,1057,1059,1062,1065,1068,1071,1074,1077],{"class":350,"line":12},[348,1058,354],{"class":353},[348,1060,1061],{"class":357}," switch",[348,1063,1064],{"class":393}," -c",[348,1066,1067],{"class":357}," template-update-",[348,1069,1070],{"class":470},"$(",[348,1072,1073],{"class":353},"date",[348,1075,1076],{"class":357}," +%Y%m%d",[348,1078,1079],{"class":470},")\n",[348,1081,1082,1084],{"class":350,"line":17},[348,1083,494],{"class":353},[348,1085,1086],{"class":357}," template:update\n",[178,1088,1089,1090,1093,1094,1097,1098,1101,1102,1104],{},"The update applies everything the kit changed since your last one as a single\ncommit, ",[189,1091,1092],{},"chore(template): update to …",". Push the branch and review it as a pull\nrequest. If you and the kit changed the same lines, it stops with conflict\nmarkers: resolve them and run ",[189,1095,1096],{},"git cherry-pick --continue",", or\n",[189,1099,1100],{},"git cherry-pick --abort"," to back out. ",[182,1103,480],{"href":24}," covers\nrelease tags, monorepos and which files conflict.",[194,1106,1108],{"id":1107},"good-to-know","Good to know",[199,1110,1111,1121,1134,1147],{},[202,1112,1113,1114,1116,1117,1120],{},"The remote must be named ",[189,1115,333],{},". ",[189,1118,1119],{},"pnpm template:update"," looks for it by\nthat name.",[202,1122,1123,1125,1126,1129,1130,1133],{},[189,1124,322],{}," stops when a port pinned with ",[189,1127,1128],{},"NUXT_DEV_PGLITE_PORT"," is taken, or\nwhen 5432 to 5441 all are. Its error says what to do\n(",[182,1131,71],{"href":1132},"\u002Fdocs\u002Fdatabase#locally",").",[202,1135,1136,1137,1140,1141,1143,1144,323],{},"A ",[189,1138,1139],{},"DATABASE_URL"," exported in your shell outranks ",[189,1142,639],{}," for the dev server\nand the database scripts. If it is production's, ",[189,1145,1146],{},"unset DATABASE_URL",[202,1148,1149,1150,1152,1153,242,1156,1159],{},"After ",[189,1151,523],{},", a commit hook checks messages against Conventional\nCommits (",[189,1154,1155],{},"feat: …",[189,1157,1158],{},"fix(auth): …",", header up to 72 characters).",[194,1161,1163],{"id":1162},"next","Next",[199,1165,1166,1173,1178],{},[202,1167,1168,1170,1171,323],{},[182,1169,20],{"href":19},": every key in ",[189,1172,191],{},[202,1174,1175,1177],{},[182,1176,30],{"href":29},": the Cloudflare resources to create, the\nsecrets, and the deploy itself.",[202,1179,1180,1182],{},[182,1181,480],{"href":24},": updates, releases and what conflicts.",[1184,1185,1186],"style",{},"html pre.shiki code .snPdu, html code.shiki .snPdu{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sIIMD, html code.shiki .sIIMD{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sBjJW, html code.shiki .sBjJW{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s8jYJ, html code.shiki .s8jYJ{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sxrX7, html code.shiki .sxrX7{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":344,"searchDepth":17,"depth":17,"links":1188},[1189,1190,1191,1192,1195,1196,1197,1198,1199,1200],{"id":196,"depth":17,"text":197},{"id":282,"depth":17,"text":283},{"id":326,"depth":17,"text":327},{"id":483,"depth":17,"text":484,"children":1193},[1194],{"id":632,"depth":22,"text":633},{"id":767,"depth":17,"text":768},{"id":796,"depth":17,"text":797},{"id":960,"depth":17,"text":961},{"id":1048,"depth":17,"text":1049},{"id":1107,"depth":17,"text":1108},{"id":1162,"depth":17,"text":1163},[1202,1203],null,{"path":14,"title":15,"description":16,"navTitle":15,"group":6,"order":17},true]