[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-navigation":3,"docs-page-template":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":1189,"linksToKit":1192},{"path":24,"title":25,"description":26,"navTitle":25,"group":6,"seo":168,"body":170},{"title":169,"description":26},"Take starter kit updates as one git commit",{"type":171,"value":172,"toc":1173},"minimark",[173,177,190,195,234,240,244,251,281,284,388,394,403,406,410,448,454,517,527,534,540,570,574,577,585,596,611,628,631,635,645,681,695,699,702,707,710,782,786,803,807,863,881,884,917,921,946,949,952,1004,1010,1021,1038,1055,1068,1072,1078,1093,1105,1108,1119,1128,1132,1169],[174,175,25],"h1",{"id":176},"updating-from-the-kit",[178,179,180,181,185,186,189],"p",{},"Your app keeps the kit as a second git remote named ",[182,183,184],"code",{},"template"," and takes each\nkit update as one commit on a branch you review. Nothing is installed or\nvendored, and your ",[182,187,188],{},"main"," shares none of the kit's history. You need this page\nwhen you create the app and each time you take an update.",[191,192,194],"h2",{"id":193},"how-it-works","How it works",[196,197,198,205,217,231],"ol",{},[199,200,201,204],"li",{},[182,202,203],{},".template-base",", at your app's root, records the kit commit your app is at.\nThe update writes it; the kit never ships it.",[199,206,207,210,211,213,214,216],{},[182,208,209],{},"pnpm template:update"," fetches the ",[182,212,184],{}," remote and takes everything\nthe kit changed between that commit and the target: the kit's ",[182,215,188],{},", or a\ntag you name.",[199,218,219,220,223,224,226,227,230],{},"It applies that change to your branch with ",[182,221,222],{},"git cherry-pick",", as one commit\ntogether with the new ",[182,225,203],{},". The commit is titled\n",[182,228,229],{},"chore(template): update to \u003Ctag or commit>",", and its body lists the subject\nof every kit commit it brings.",[199,232,233],{},"Where you and the kit changed the same lines, it stops with conflict\nmarkers, like any cherry-pick.",[178,235,236,237,239],{},"The first update has no ",[182,238,203],{}," to read. It looks for the kit commit\nwhose files are identical to your app's first commit, so that first commit has\nto be the unchanged kit.",[191,241,243],{"id":242},"create-your-app","Create your app",[178,245,246,247,250],{},"Click \"Use this template\" on the kit repository, ",[182,248,249],{},"nuxter-app\u002Fkit",", clone your\nnew repository and add the remote once:",[252,253,258],"pre",{"className":254,"code":255,"language":256,"meta":257,"style":257},"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","",[182,259,260],{"__ignoreMap":257},[261,262,264,268,272,275,278],"span",{"class":263,"line":12},"line",[261,265,267],{"class":266},"snPdu","git",[261,269,271],{"class":270},"sIIMD"," remote",[261,273,274],{"class":270}," add",[261,276,277],{"class":270}," template",[261,279,280],{"class":270}," https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit.git\n",[178,282,283],{},"To host the repository anywhere else, clone the kit and drop its history:",[252,285,287],{"className":254,"code":286,"language":256,"meta":257,"style":257},"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",[182,288,289,302,310,323,336,346,361],{"__ignoreMap":257},[261,290,291,293,296,299],{"class":263,"line":12},[261,292,267],{"class":266},[261,294,295],{"class":270}," clone",[261,297,298],{"class":270}," https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit.git",[261,300,301],{"class":270}," my-app\n",[261,303,304,308],{"class":263,"line":17},[261,305,307],{"class":306},"sBjJW","cd",[261,309,301],{"class":270},[261,311,312,314,317,320],{"class":263,"line":22},[261,313,267],{"class":266},[261,315,316],{"class":270}," update-ref",[261,318,319],{"class":306}," -d",[261,321,322],{"class":270}," HEAD\n",[261,324,325,327,330,333],{"class":263,"line":27},[261,326,267],{"class":266},[261,328,329],{"class":270}," commit",[261,331,332],{"class":306}," -m",[261,334,335],{"class":270}," \"chore: start from the template\"\n",[261,337,338,340,343],{"class":263,"line":32},[261,339,267],{"class":266},[261,341,342],{"class":270}," branch",[261,344,345],{"class":306}," --unset-upstream\n",[261,347,348,350,352,355,358],{"class":263,"line":37},[261,349,267],{"class":266},[261,351,271],{"class":270},[261,353,354],{"class":270}," rename",[261,356,357],{"class":270}," origin",[261,359,360],{"class":270}," template\n",[261,362,363,365,367,369,371,375,378,381,385],{"class":263,"line":46},[261,364,267],{"class":266},[261,366,271],{"class":270},[261,368,274],{"class":270},[261,370,357],{"class":270},[261,372,374],{"class":373},"s8jYJ"," \u003C",[261,376,377],{"class":270},"your",[261,379,380],{"class":270}," repositor",[261,382,384],{"class":383},"sxrX7","y",[261,386,387],{"class":373},">\n",[178,389,390,393],{},[182,391,392],{},"git update-ref -d HEAD"," removes the kit's history and leaves its files staged\nexactly as the kit has them, so your first commit is the kit byte for byte.",[178,395,396,397,402],{},"To start the app in a folder of a repository that already exists, such as a\nmonorepo, see ",[398,399,401],"a",{"href":400},"#apps-in-a-subfolder","Apps in a subfolder",".",[178,404,405],{},"Whichever way you start, make your own changes in the commits after the first.",[191,407,409],{"id":408},"take-an-update","Take an update",[252,411,413],{"className":254,"code":412,"language":256,"meta":257,"style":257},"git switch -c template-update-$(date +%Y%m%d)\npnpm template:update\n",[182,414,415,440],{"__ignoreMap":257},[261,416,417,419,422,425,428,431,434,437],{"class":263,"line":12},[261,418,267],{"class":266},[261,420,421],{"class":270}," switch",[261,423,424],{"class":306}," -c",[261,426,427],{"class":270}," template-update-",[261,429,430],{"class":383},"$(",[261,432,433],{"class":266},"date",[261,435,436],{"class":270}," +%Y%m%d",[261,438,439],{"class":383},")\n",[261,441,442,445],{"class":263,"line":17},[261,443,444],{"class":266},"pnpm",[261,446,447],{"class":270}," template:update\n",[178,449,450,451,453],{},"The working tree must be clean; the script refuses while tracked files have\nuncommitted changes. When it finishes, push the branch and open a pull\nrequest. Squash-merge it to keep ",[182,452,188],{}," linear.",[455,456,457,470],"table",{},[458,459,460],"thead",{},[461,462,463,467],"tr",{},[464,465,466],"th",{},"Command",[464,468,469],{},"What it does",[471,472,473,485,495,505],"tbody",{},[461,474,475,480],{},[476,477,478],"td",{},[182,479,209],{},[476,481,482,483,402],{},"Takes the kit's ",[182,484,188],{},[461,486,487,492],{},[476,488,489],{},[182,490,491],{},"pnpm template:update v1.4.0",[476,493,494],{},"Takes that tag. A branch name or a commit from the kit works too.",[461,496,497,502],{},[476,498,499],{},[182,500,501],{},"pnpm template:update --no-commit",[476,503,504],{},"Stages the update without committing, so you can read the whole diff first.",[461,506,507,512],{},[476,508,509],{},[182,510,511],{},"pnpm template:update --base \u003Ctag or commit>",[476,513,514,515,402],{},"Treats that kit commit as the one your app is at, in place of ",[182,516,203],{},[178,518,519,520,523,524,526],{},"Use ",[182,521,522],{},"--base"," when the script can't work out where your app started: when your\nfirst commit wasn't an unchanged copy of the kit, or when ",[182,525,203],{},"\nnames a commit the remote doesn't have. Both errors say so.",[178,528,529,530,533],{},"If your app is already at the target, the script prints\n",[182,531,532],{},"Already at the template's \u003Ccommit>."," and changes nothing.",[178,535,536,537,539],{},"Once ",[182,538,203],{}," exists, this shows what the next update brings:",[252,541,543],{"className":254,"code":542,"language":256,"meta":257,"style":257},"git fetch template\ngit log \"$(cat .template-base)\"..template\u002Fmain\n",[182,544,545,554],{"__ignoreMap":257},[261,546,547,549,552],{"class":263,"line":12},[261,548,267],{"class":266},[261,550,551],{"class":270}," fetch",[261,553,360],{"class":270},[261,555,556,558,561,564,567],{"class":263,"line":17},[261,557,267],{"class":266},[261,559,560],{"class":270}," log",[261,562,563],{"class":270}," \"$(",[261,565,566],{"class":266},"cat",[261,568,569],{"class":270}," .template-base)\"..template\u002Fmain\n",[191,571,573],{"id":572},"resolve-conflicts","Resolve conflicts",[178,575,576],{},"A conflicted update lists the paths and exits with status 1:",[252,578,583],{"className":579,"code":581,"language":582,"meta":257},[580],"language-text","Template 3f2a9c1d0b7e..8e41d5a2c6f0 applied with conflicts in:\n\n  nuxt.config.ts\n  i18n\u002Flocales\u002Fen.json\n\nResolve each one: `git add` keeps your resolution, `git rm` keeps a file deleted.\nThen `git cherry-pick --continue`. To back out entirely: `git cherry-pick --abort`.\n","text",[182,584,581],{"__ignoreMap":257},[178,586,587,588,591,592,595],{},"Fix the markers in each file and ",[182,589,590],{},"git add"," it. A file you deleted that the kit\nchanged shows as a modify\u002Fdelete conflict; ",[182,593,594],{},"git rm \u003Cpath>"," keeps it deleted.\nThen finish:",[252,597,599],{"className":254,"code":598,"language":256,"meta":257,"style":257},"git cherry-pick --continue\n",[182,600,601],{"__ignoreMap":257},[261,602,603,605,608],{"class":263,"line":12},[261,604,267],{"class":266},[261,606,607],{"class":270}," cherry-pick",[261,609,610],{"class":306}," --continue\n",[178,612,613,616,617,620,621,624,625,402],{},[182,614,615],{},"git cherry-pick --abort"," puts everything back as it was. After ",[182,618,619],{},"--no-commit","\nthere is no cherry-pick to continue: resolve, then ",[182,622,623],{},"git commit",", or back out\nwith ",[182,626,627],{},"git reset --merge",[178,629,630],{},"If an update is too much to resolve at once, abort it and take one release at a\ntime by passing each tag in turn.",[191,632,634],{"id":633},"dependency-conflicts","Dependency conflicts",[178,636,637,638,641,642,644],{},"Both sides change ",[182,639,640],{},"package.json",", and the kit's lockfile moves with every\ndependency refresh. Keep both sides' entries in ",[182,643,640],{},", then rebuild\nthe lockfile instead of merging it by hand:",[252,646,648],{"className":254,"code":647,"language":256,"meta":257,"style":257},"git checkout --theirs pnpm-lock.yaml\npnpm install\ngit add package.json pnpm-lock.yaml\n",[182,649,650,663,670],{"__ignoreMap":257},[261,651,652,654,657,660],{"class":263,"line":12},[261,653,267],{"class":266},[261,655,656],{"class":270}," checkout",[261,658,659],{"class":306}," --theirs",[261,661,662],{"class":270}," pnpm-lock.yaml\n",[261,664,665,667],{"class":263,"line":17},[261,666,444],{"class":266},[261,668,669],{"class":270}," install\n",[261,671,672,674,676,679],{"class":263,"line":22},[261,673,267],{"class":266},[261,675,274],{"class":270},[261,677,678],{"class":270}," package.json",[261,680,662],{"class":270},[178,682,683,684,687,688,691,692,694],{},"During the update, ",[182,685,686],{},"--theirs"," is the kit's side. ",[182,689,690],{},"pnpm install"," resolves the\nmerged ",[182,693,640],{}," against the kit's lockfile and adds your packages back.",[191,696,698],{"id":697},"what-conflicts-and-what-does-not","What conflicts, and what does not",[178,700,701],{},"Conflicts come from app code in files the kit owns. Keep your code in files\nthat are yours and an update applies cleanly.",[703,704,706],"h3",{"id":705},"yours","Yours",[178,708,709],{},"The kit never writes these, or only adds to them:",[711,712,713,730,740,769,778],"ul",{},[199,714,715,718,719,722,723,726,727,402],{},[182,716,717],{},"app\u002F",", except ",[182,720,721],{},"app\u002Ftypes\u002F","; ",[182,724,725],{},"server\u002Fapi\u002F",", except the kit's own routes; and\n",[182,728,729],{},"public\u002F",[199,731,732,735,736,739],{},[182,733,734],{},"server\u002Fjobs\u002F"," and ",[182,737,738],{},"server\u002Flisteners\u002F",", except the files the kit ships there.",[199,741,742,743,746,747,750,751,735,754,757,758,761,762,765,766,402],{},"Every ",[182,744,745],{},"custom\u002F"," directory and ",[182,748,749],{},"custom.*"," file. The kit ships at most an empty\none and never writes it again: provider adapters in\n",[182,752,753],{},"server\u002F*\u002Fadapters\u002Fcustom\u002F",[182,755,756],{},"server\u002Fsignals\u002F*\u002Fcustom\u002F",", your tables in\n",[182,759,760],{},"server\u002Fdatabase\u002Fcustom\u002F",", their migrations in\n",[182,763,764],{},"server\u002Fdatabase\u002Fmigrations\u002Fcustom\u002F",", your events in\n",[182,767,768],{},"server\u002Fevents\u002Fcustom.d.ts",[199,770,771,735,774,777],{},[182,772,773],{},"content\u002F",[182,775,776],{},"i18n\u002Flocales\u002F",". The kit still adds a key for each new string\nof its own, and now and then rewords one of its strings. A value you changed\nconflicts when the kit rewords that same key.",[199,779,780,402],{},[182,781,203],{},[703,783,785],{"id":784},"shared","Shared",[178,787,788,789,792,793,735,795,798,799,802],{},"These conflict on purpose. ",[182,790,791],{},"starter.config.ts"," gains a key when the kit adds an\noption, and you choose its value. ",[182,794,640],{},[182,796,797],{},"pnpm-lock.yaml"," carry\nboth sides' dependencies. ",[182,800,801],{},"scripts\u002Fblog\u002Fblog.config.mjs"," holds your blog\npipeline settings and gains the kit's new options and models.",[703,804,806],{"id":805},"the-kits","The kit's",[178,808,809,810,813,814,817,818,813,821,813,824,813,827,813,830,813,833,817,836,813,839,813,842,845,846,849,850,813,853,813,856,813,859,862],{},"Everything else. That includes the subsystems under ",[182,811,812],{},"server\u002F",", ",[182,815,816],{},"server\u002Futils\u002F",",\n",[182,819,820],{},"server\u002Ftypes\u002F",[182,822,823],{},"shared\u002F",[182,825,826],{},"modules\u002F",[182,828,829],{},"build\u002F",[182,831,832],{},"emails\u002F",[182,834,835],{},"test\u002F",[182,837,838],{},"scripts\u002F",[182,840,841],{},"nuxt.config.ts",[182,843,844],{},"wrangler.jsonc",", the ",[182,847,848],{},"drizzle*.ts"," configs,\n",[182,851,852],{},".github\u002F",[182,854,855],{},"README.md",[182,857,858],{},"AGENTS.md",[182,860,861],{},".env.example"," and the dotfiles at the\nroot. You can edit any of them, and each edit conflicts the next time the kit\nchanges the same lines.",[178,864,865,866,813,869,817,872,735,875,878,879,402],{},"Nitro registers every file in ",[182,867,868],{},"server\u002Fmiddleware\u002F",[182,870,871],{},"server\u002Fplugins\u002F",[182,873,874],{},"server\u002Froutes\u002F",[182,876,877],{},"server\u002Ftasks\u002F",", so your own middleware or plugin is a new\nfile there, under a name the kit doesn't use. A test of your own is a new file\nin ",[182,880,835],{},[178,882,883],{},"Two habits keep updates small:",[711,885,886,892],{},[199,887,888,889,891],{},"Change behaviour through ",[182,890,791],{}," before you edit a kit file.",[199,893,894,895,898,899,908,909,916],{},"Delete a kit file you don't want rather than emptying it. A deleted file\nconflicts only when the kit changes it, and ",[182,896,897],{},"git rm"," resolves that. An\nemptied one conflicts on every change. The example paywall,\n",[398,900,905],{"href":901,"rel":902,"title":904},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Fblob\u002Fmain\u002Fserver\u002Fapi\u002Fexample-paid.get.ts",[903],"nofollow","Licensees only",[182,906,907],{},"server\u002Fapi\u002Fexample-paid.get.ts"," and\n",[398,910,913],{"href":911,"rel":912,"title":904},"https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit\u002Fblob\u002Fmain\u002Fapp\u002Fcomponents\u002FPaidFeatureCard.vue",[903],[182,914,915],{},"app\u002Fcomponents\u002FPaidFeatureCard.vue",",\nis there to be deleted.",[191,918,920],{"id":919},"migrations","Migrations",[178,922,923,924,927,928,931,932,934,935,938,939,942,943,402],{},"Your tables go in ",[182,925,926],{},"server\u002Fdatabase\u002Fcustom\u002Fschema.ts",", and ",[182,929,930],{},"pnpm db:generate","\nwrites their migrations to ",[182,933,764],{},". The kit's\nschema and migrations sit beside them in files you never edit, so an update\nbrings new kit migrations without a conflict, and ",[182,936,937],{},"pnpm db:migrate"," applies\nthem. Extend a kit table with a table of your own keyed by its id, never with a\ncolumn in ",[182,940,941],{},"server\u002Fdatabase\u002Fschema.ts",". A kit migration that renames or drops a\ncolumn comes in a major release, and the changelog names it. The two migration\nchains are covered on ",[398,944,71],{"href":945},"\u002Fdocs\u002Fdatabase#migrations",[191,947,401],{"id":948},"apps-in-a-subfolder",[178,950,951],{},"Several apps can each start from the kit in a folder of their own:",[252,953,955],{"className":254,"code":954,"language":256,"meta":257,"style":257},"git remote add template https:\u002F\u002Fgithub.com\u002Fnuxter-app\u002Fkit.git\ngit fetch template\ngit read-tree --prefix=apps\u002Fweb\u002F -u template\u002Fmain\ngit commit -m \"feat(web): start from the template\"\n",[182,956,957,969,977,993],{"__ignoreMap":257},[261,958,959,961,963,965,967],{"class":263,"line":12},[261,960,267],{"class":266},[261,962,271],{"class":270},[261,964,274],{"class":270},[261,966,277],{"class":270},[261,968,280],{"class":270},[261,970,971,973,975],{"class":263,"line":17},[261,972,267],{"class":266},[261,974,551],{"class":270},[261,976,360],{"class":270},[261,978,979,981,984,987,990],{"class":263,"line":22},[261,980,267],{"class":266},[261,982,983],{"class":270}," read-tree",[261,985,986],{"class":306}," --prefix=apps\u002Fweb\u002F",[261,988,989],{"class":306}," -u",[261,991,992],{"class":270}," template\u002Fmain\n",[261,994,995,997,999,1001],{"class":263,"line":27},[261,996,267],{"class":266},[261,998,329],{"class":270},[261,1000,332],{"class":306},[261,1002,1003],{"class":270}," \"feat(web): start from the template\"\n",[178,1005,1006,1009],{},[182,1007,1008],{},"git read-tree --prefix"," stages the kit's files under the folder unchanged, so\nthe commit that adds the folder is the unmodified kit. The first update matches\nagainst the folder as that commit left it.",[178,1011,1012,1013,1016,1017,1020],{},"Run the update from the app's folder. It writes ",[182,1014,1015],{},"apps\u002Fweb\u002F.template-base",",\nchanges nothing outside the folder, and titles the commit\n",[182,1018,1019],{},"chore(template): update apps\u002Fweb to \u003Ctag or commit>",", moving part of that into\nthe body when the title would run long. In a pnpm workspace, run it from the\nworkspace root:",[252,1022,1024],{"className":254,"code":1023,"language":256,"meta":257,"style":257},"pnpm --filter .\u002Fapps\u002Fweb template:update\n",[182,1025,1026],{"__ignoreMap":257},[261,1027,1028,1030,1033,1036],{"class":263,"line":12},[261,1029,444],{"class":266},[261,1031,1032],{"class":306}," --filter",[261,1034,1035],{"class":270}," .\u002Fapps\u002Fweb",[261,1037,447],{"class":270},[178,1039,1040,1041,1044,1045,1048,1049,1051,1052,1054],{},"Or run ",[182,1042,1043],{},"node scripts\u002Ftemplate\u002Fupdate.mjs"," inside the folder. The kit ships its\nown ",[182,1046,1047],{},"pnpm-workspace.yaml",", so ",[182,1050,209],{}," run inside the folder\ntreats it as a separate workspace and reinstalls against the folder's\n",[182,1053,797],{}," first. The update then stops on the files that install\nchanged.",[178,1056,1057,1058,1060,1061,1063,1064,1067],{},"GitHub runs workflows only from the repository root, so the app's ",[182,1059,852],{},"\ncomes along and never runs. Copy the workflows you want to the root. Commit\nhooks install only at the root too: in a folder, ",[182,1062,690],{}," reports\n",[182,1065,1066],{},".git can't be found"," and skips them.",[191,1069,1071],{"id":1070},"releases","Releases",[178,1073,1074,1075,1077],{},"With no argument the update takes the kit's ",[182,1076,188],{},", which is always\ndeployable. Tags mark releases:",[252,1079,1081],{"className":254,"code":1080,"language":256,"meta":257,"style":257},"pnpm template:update v1.4.0\n",[182,1082,1083],{"__ignoreMap":257},[261,1084,1085,1087,1090],{"class":263,"line":12},[261,1086,444],{"class":266},[261,1088,1089],{"class":270}," template:update",[261,1091,1092],{"class":270}," v1.4.0\n",[178,1094,1095,1096,1098,1099,1101,1102,1104],{},"You can move from tags to ",[182,1097,188],{}," at any time. Moving from ",[182,1100,188],{}," to tags waits\nfor the next tag, because a tag older than the commit in ",[182,1103,203],{}," is\nrefused: taking it would revert kit changes you already have.",[178,1106,1107],{},"The version number says how much the update asks of you:",[711,1109,1110,1113,1116],{},[199,1111,1112],{},"Major: you need to act. A renamed variable or config key, a moved or\nremoved kit name, a migration to read before you deploy, or a change likely\nto conflict with your files.",[199,1114,1115],{},"Minor: something new that applies without your help.",[199,1117,1118],{},"Patch: fixes only.",[178,1120,1121,1127],{},[398,1122,1124],{"href":1123},"\u002Fchangelog",[182,1125,1126],{},"CHANGELOG.md"," lists every release, and each entry opens\nwith what to do before you take it.",[191,1129,1131],{"id":1130},"good-to-know","Good to know",[711,1133,1134,1140,1159,1162],{},[199,1135,1136,1137,1139],{},"The remote must be named ",[182,1138,184],{},". The script looks it up by that name and\nstops if it is missing.",[199,1141,1142,1143,1145,1146,1148,1149,1151,1152,1154,1155,1158],{},"A file you unstage after ",[182,1144,619],{}," is declined for good. The staged\n",[182,1147,203],{}," already names the target, so the next update starts past\nit. To take it later, pass the commit ",[182,1150,203],{}," named before that\nupdate as ",[182,1153,522],{},". ",[182,1156,1157],{},"git log -p -- .template-base"," shows it, and the files\nyou already took apply as no-ops.",[199,1160,1161],{},"A folder renamed only by letter case confuses the script. Give the folder on\ndisk the name the last commit has, then run it again.",[199,1163,1164,1165,1168],{},"Keep the kit's ",[182,1166,1167],{},"LICENSE",", under any name, in every repository that holds the\nkit. Your own license can sit beside it.",[1170,1171,1172],"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":257,"searchDepth":17,"depth":17,"links":1174},[1175,1176,1177,1178,1179,1180,1185,1186,1187,1188],{"id":193,"depth":17,"text":194},{"id":242,"depth":17,"text":243},{"id":408,"depth":17,"text":409},{"id":572,"depth":17,"text":573},{"id":633,"depth":17,"text":634},{"id":697,"depth":17,"text":698,"children":1181},[1182,1183,1184],{"id":705,"depth":22,"text":706},{"id":784,"depth":22,"text":785},{"id":805,"depth":22,"text":806},{"id":919,"depth":17,"text":920},{"id":948,"depth":17,"text":401},{"id":1070,"depth":17,"text":1071},{"id":1130,"depth":17,"text":1131},[1190,1191],{"path":19,"title":20,"description":21,"navTitle":20,"group":6,"order":22},{"path":29,"title":30,"description":31,"navTitle":30,"group":6,"order":32},true]