[{"data":1,"prerenderedAt":1498},["ShallowReactive",2],{"navigation_docs_en":3,"-en-dbx-seed":441,"-en-dbx-seed-surround":1493},[4,45,60,81,112,129,146,173,197,213,242,279,356,372,384,403,429],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F1.getting-started\u002F2.coming-from-laravel","i-lucide-arrow-right-left",{"title":21,"path":22,"stem":23,"icon":19},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F1.getting-started\u002F3.coming-from-symfony",{"title":25,"path":26,"stem":27,"icon":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F4.installation","i-lucide-download",{"title":30,"path":31,"stem":32,"icon":33},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F1.getting-started\u002F5.first-module","i-lucide-package-plus",{"title":35,"path":36,"stem":37,"icon":38},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F1.getting-started\u002F6.project-structure","i-lucide-folder-tree",{"title":40,"path":41,"stem":42,"icon":43},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F1.getting-started\u002F7.sample-app","i-lucide-shopping-cart",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"queue","i-lucide-layers","\u002Fen\u002Fqueue","en\u002F10.queue",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Overview","\u002Fen\u002Fqueue\u002Foverview","en\u002F10.queue\u002F1.overview","i-lucide-list-ordered",{"title":57,"path":58,"stem":59,"icon":47},"Tasks","\u002Fen\u002Fqueue\u002Ftasks","en\u002F10.queue\u002F2.tasks",{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":44},"events","i-lucide-workflow","\u002Fen\u002Fevents","en\u002F11.events",[66,71,76],{"title":67,"path":68,"stem":69,"icon":70},"Events","\u002Fen\u002Fevents\u002Foverview","en\u002F11.events\u002F1.overview","i-lucide-radio",{"title":72,"path":73,"stem":74,"icon":75},"Outbox","\u002Fen\u002Fevents\u002Foutbox","en\u002F11.events\u002F2.outbox","i-lucide-inbox",{"title":77,"path":78,"stem":79,"icon":80},"Scheduling","\u002Fen\u002Fevents\u002Fscheduler","en\u002F11.events\u002F3.scheduler","i-lucide-calendar-clock",{"title":82,"icon":83,"path":84,"stem":85,"children":86,"page":44},"auth","i-lucide-shield-check","\u002Fen\u002Fauth","en\u002F12.auth",[87,92,97,102,107],{"title":88,"path":89,"stem":90,"icon":91},"Authentication","\u002Fen\u002Fauth\u002Foverview","en\u002F12.auth\u002F1.overview","i-lucide-key-round",{"title":93,"path":94,"stem":95,"icon":96},"RBAC","\u002Fen\u002Fauth\u002Frbac","en\u002F12.auth\u002F2.rbac","i-lucide-users",{"title":98,"path":99,"stem":100,"icon":101},"Policies","\u002Fen\u002Fauth\u002Fpolicy","en\u002F12.auth\u002F3.policy","i-lucide-gavel",{"title":103,"path":104,"stem":105,"icon":106},"Using auth standalone","\u002Fen\u002Fauth\u002Fstandalone","en\u002F12.auth\u002F4.standalone","i-lucide-plug",{"title":108,"path":109,"stem":110,"icon":111},"Social login with goth, standalone","\u002Fen\u002Fauth\u002Fsocial-standalone","en\u002F12.auth\u002F5.social-standalone","i-lucide-log-in",{"title":113,"icon":114,"path":115,"stem":116,"children":117,"page":44},"mail","i-lucide-mail","\u002Fen\u002Fmail","en\u002F13.mail",[118,121,125],{"title":52,"path":119,"stem":120,"icon":114},"\u002Fen\u002Fmail\u002Foverview","en\u002F13.mail\u002F1.overview",{"title":122,"path":123,"stem":124,"icon":114},"SMTP","\u002Fen\u002Fmail\u002Fsmtp","en\u002F13.mail\u002F2.smtp",{"title":126,"path":127,"stem":128,"icon":114},"MJML","\u002Fen\u002Fmail\u002Fmjml","en\u002F13.mail\u002F3.mjml",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":44},"notify","i-lucide-bell","\u002Fen\u002Fnotify","en\u002F14.notify",[135,138,142],{"title":52,"path":136,"stem":137,"icon":131},"\u002Fen\u002Fnotify\u002Foverview","en\u002F14.notify\u002F1.overview",{"title":139,"path":140,"stem":141,"icon":131},"Database channel","\u002Fen\u002Fnotify\u002Fdatabase","en\u002F14.notify\u002F2.database",{"title":143,"path":144,"stem":145,"icon":131},"Broadcast channel","\u002Fen\u002Fnotify\u002Fbroadcast","en\u002F14.notify\u002F3.broadcast",{"title":147,"icon":148,"path":149,"stem":150,"children":151,"page":44},"storage","i-lucide-hard-drive","\u002Fen\u002Fstorage","en\u002F15.storage",[152,155,159,163,168],{"title":52,"path":153,"stem":154,"icon":148},"\u002Fen\u002Fstorage\u002Foverview","en\u002F15.storage\u002F1.overview",{"title":156,"path":157,"stem":158},"Disk API","\u002Fen\u002Fstorage\u002Fdisk-api","en\u002F15.storage\u002F2.disk-api",{"title":160,"path":161,"stem":162,"icon":148},"Memory and local disk","\u002Fen\u002Fstorage\u002Flocal","en\u002F15.storage\u002F3.local",{"title":164,"path":165,"stem":166,"icon":167},"S3","\u002Fen\u002Fstorage\u002Fs3","en\u002F15.storage\u002F4.s3","i-lucide-cloud",{"title":169,"path":170,"stem":171,"icon":172},"Testing","\u002Fen\u002Fstorage\u002Ftesting","en\u002F15.storage\u002F5.testing","i-lucide-flask-conical",{"title":174,"icon":175,"path":176,"stem":177,"children":178,"page":44},"telemetry","i-lucide-activity","\u002Fen\u002Ftelemetry","en\u002F16.telemetry",[179,182,187,192],{"title":52,"path":180,"stem":181,"icon":175},"\u002Fen\u002Ftelemetry\u002Foverview","en\u002F16.telemetry\u002F1.overview",{"title":183,"path":184,"stem":185,"icon":186},"Logging","\u002Fen\u002Ftelemetry\u002Flogging","en\u002F16.telemetry\u002F2.logging","i-lucide-scroll-text",{"title":188,"path":189,"stem":190,"icon":191},"OpenTelemetry","\u002Fen\u002Ftelemetry\u002Fopentelemetry","en\u002F16.telemetry\u002F3.opentelemetry","i-lucide-radar",{"title":193,"path":194,"stem":195,"icon":196},"Sentry","\u002Fen\u002Ftelemetry\u002Fsentry","en\u002F16.telemetry\u002F4.sentry","i-lucide-bug",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F17.reference",[203,208],{"title":204,"path":205,"stem":206,"icon":207},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F17.reference\u002F1.configuration","i-lucide-settings",{"title":209,"path":210,"stem":211,"icon":212},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F17.reference\u002F2.dependencies","i-lucide-package",{"title":214,"icon":215,"path":216,"stem":217,"children":218,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[219,223,228,232,237],{"title":220,"path":221,"stem":222,"icon":47},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture",{"title":224,"path":225,"stem":226,"icon":227},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F2.error-model","i-lucide-shield-alert",{"title":204,"path":229,"stem":230,"icon":231},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F3.configuration","i-lucide-settings-2",{"title":233,"path":234,"stem":235,"icon":236},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F4.codegen-pipeline","i-lucide-file-json",{"title":238,"path":239,"stem":240,"icon":241},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F5.design-patterns","i-lucide-puzzle",{"title":243,"icon":244,"path":245,"stem":246,"children":247,"page":44},"Kit","i-lucide-box","\u002Fen\u002Fkit","en\u002F3.kit",[248,251,256,261,266,270,275],{"title":52,"path":249,"stem":250,"icon":244},"\u002Fen\u002Fkit\u002Foverview","en\u002F3.kit\u002F1.overview",{"title":252,"path":253,"stem":254,"icon":255},"Application lifecycle","\u002Fen\u002Fkit\u002Fapp","en\u002F3.kit\u002F2.app","i-lucide-power",{"title":257,"path":258,"stem":259,"icon":260},"Server","\u002Fen\u002Fkit\u002Fserver","en\u002F3.kit\u002F3.server","i-lucide-server",{"title":262,"path":263,"stem":264,"icon":265},"Worker","\u002Fen\u002Fkit\u002Fworker","en\u002F3.kit\u002F4.worker","i-lucide-cog",{"title":267,"path":268,"stem":269,"icon":70},"Realtime","\u002Fen\u002Fkit\u002Frealtime","en\u002F3.kit\u002F5.realtime",{"title":271,"path":272,"stem":273,"icon":274},"Migrations","\u002Fen\u002Fkit\u002Fmigrations","en\u002F3.kit\u002F6.migrations","i-lucide-file-stack",{"title":276,"path":277,"stem":278,"icon":111},"Social login","\u002Fen\u002Fkit\u002Fsocial-login","en\u002F3.kit\u002F7.social-login",{"title":280,"icon":281,"path":282,"stem":283,"children":284,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F4.cli",[285,288,293,298,303,308,313,318,323,328,333,337,342,347,351],{"title":52,"path":286,"stem":287,"icon":281},"\u002Fen\u002Fcli\u002Foverview","en\u002F4.cli\u002F1.overview",{"title":289,"path":290,"stem":291,"icon":292},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F4.cli\u002F10.add-db","i-lucide-database-zap",{"title":294,"path":295,"stem":296,"icon":297},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F4.cli\u002F11.add-compose","i-lucide-container",{"title":299,"path":300,"stem":301,"icon":302},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F4.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":304,"path":305,"stem":306,"icon":307},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F4.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":309,"path":310,"stem":311,"icon":312},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F4.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":314,"path":315,"stem":316,"icon":317},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F4.cli\u002F15.add-seeder","i-lucide-sprout",{"title":319,"path":320,"stem":321,"icon":322},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F4.cli\u002F2.new-project","i-lucide-folder-plus",{"title":324,"path":325,"stem":326,"icon":327},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F4.cli\u002F3.new-module","i-lucide-blocks",{"title":329,"path":330,"stem":331,"icon":332},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F4.cli\u002F4.add-surface","i-lucide-layers-2",{"title":334,"path":335,"stem":336,"icon":244},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F4.cli\u002F5.add-core",{"title":338,"path":339,"stem":340,"icon":341},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F4.cli\u002F6.add-handler","i-lucide-webhook",{"title":343,"path":344,"stem":345,"icon":346},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F4.cli\u002F7.new-migration","i-lucide-file-plus",{"title":348,"path":349,"stem":350,"icon":265},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F4.cli\u002F8.worker-generators",{"title":352,"path":353,"stem":354,"icon":355},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F4.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"title":357,"icon":227,"path":358,"stem":359,"children":360,"page":44},"errs","\u002Fen\u002Ferrs","en\u002F5.errs",[361,364,368],{"title":52,"path":362,"stem":363,"icon":227},"\u002Fen\u002Ferrs\u002Foverview","en\u002F5.errs\u002F1.overview",{"title":365,"path":366,"stem":367},"API","\u002Fen\u002Ferrs\u002Fapi","en\u002F5.errs\u002F2.api",{"title":369,"path":370,"stem":371,"icon":227},"Integration","\u002Fen\u002Ferrs\u002Fintegration","en\u002F5.errs\u002F3.integration",{"title":373,"icon":231,"path":374,"stem":375,"children":376,"page":44},"envconf","\u002Fen\u002Fenvconf","en\u002F6.envconf",[377,380],{"title":52,"path":378,"stem":379,"icon":231},"\u002Fen\u002Fenvconf\u002Foverview","en\u002F6.envconf\u002F1.overview",{"title":381,"path":382,"stem":383},"Recipes","\u002Fen\u002Fenvconf\u002Frecipes","en\u002F6.envconf\u002F2.recipes",{"title":385,"icon":386,"path":387,"stem":388,"children":389,"page":44},"httperr","i-lucide-globe","\u002Fen\u002Fhttperr","en\u002F7.httperr",[390,393,398],{"title":52,"path":391,"stem":392,"icon":386},"\u002Fen\u002Fhttperr\u002Foverview","en\u002F7.httperr\u002F1.overview",{"title":394,"path":395,"stem":396,"icon":397},"Error responses","\u002Fen\u002Fhttperr\u002Ferror-responses","en\u002F7.httperr\u002F2.error-responses","i-lucide-octagon-alert",{"title":399,"path":400,"stem":401,"icon":402},"Validation","\u002Fen\u002Fhttperr\u002Fvalidation","en\u002F7.httperr\u002F3.validation","i-lucide-badge-check",{"title":404,"icon":405,"path":406,"stem":407,"children":408,"page":44},"dbx","i-lucide-database","\u002Fen\u002Fdbx","en\u002F8.dbx",[409,412,416,420,425],{"title":52,"path":410,"stem":411,"icon":405},"\u002Fen\u002Fdbx\u002Foverview","en\u002F8.dbx\u002F1.overview",{"title":413,"path":414,"stem":415,"icon":106},"pgx","\u002Fen\u002Fdbx\u002Fpg","en\u002F8.dbx\u002F2.pg",{"title":417,"path":418,"stem":419,"icon":47},"bun","\u002Fen\u002Fdbx\u002Fbunx","en\u002F8.dbx\u002F3.bunx",{"title":421,"path":422,"stem":423,"icon":424},"Transactions","\u002Fen\u002Fdbx\u002Ftransactions","en\u002F8.dbx\u002F4.transactions","i-lucide-git-merge",{"title":426,"path":427,"stem":428,"icon":317},"Seeders","\u002Fen\u002Fdbx\u002Fseed","en\u002F8.dbx\u002F5.seed",{"title":430,"icon":55,"path":431,"stem":432,"children":433,"page":44},"paginate","\u002Fen\u002Fpaginate","en\u002F9.paginate",[434,437],{"title":52,"path":435,"stem":436,"icon":55},"\u002Fen\u002Fpaginate\u002Foverview","en\u002F9.paginate\u002F1.overview",{"title":438,"path":439,"stem":440,"icon":19},"Cursor pagination","\u002Fen\u002Fpaginate\u002Fcursor","en\u002F9.paginate\u002F2.cursor",{"id":442,"title":426,"body":443,"description":1486,"extension":1487,"links":1488,"meta":1489,"navigation":1490,"path":427,"seo":1491,"stem":428,"__hash__":1492},"docs_en\u002Fen\u002F8.dbx\u002F5.seed.md",{"type":444,"value":445,"toc":1479},"minimark",[446,471,521,526,553,687,758,788,792,802,902,931,942,946,963,1051,1061,1240,1244,1254,1429,1439,1457,1461,1475],[447,448,449,452,453,457,458,462,463,466,467,470],"p",{},[450,451,271],"a",{"href":272}," create the schema; ",[454,455,456],"strong",{},"seeders"," create the data: an admin user, roles, lookup tables. gpsystem generates the ",[459,460,461],"code",{},"seed"," package and a central ",[459,464,465],{},"seeds\u002F"," package in every project for this, run through the ",[459,468,469],{},"cmd\u002Fmigrate"," binary.",[472,473,478],"pre",{"className":474,"code":475,"language":476,"meta":477,"style":477},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go run .\u002Fcmd\u002Fmigrate up --seed   # migrate, then seed\ngo run .\u002Fcmd\u002Fmigrate seed        # seed only, no migration\n","sh","",[459,479,480,506],{"__ignoreMap":477},[481,482,485,489,493,496,499,502],"span",{"class":483,"line":484},"line",1,[481,486,488],{"class":487},"sBMFI","go",[481,490,492],{"class":491},"sfazB"," run",[481,494,495],{"class":491}," .\u002Fcmd\u002Fmigrate",[481,497,498],{"class":491}," up",[481,500,501],{"class":491}," --seed",[481,503,505],{"class":504},"sHwdD","   # migrate, then seed\n",[481,507,509,511,513,515,518],{"class":483,"line":508},2,[481,510,488],{"class":487},[481,512,492],{"class":491},[481,514,495],{"class":491},[481,516,517],{"class":491}," seed",[481,519,520],{"class":504},"        # seed only, no migration\n",[522,523,525],"h2",{"id":524},"the-registry-and-seeder","The Registry and Seeder",[447,527,528,529,532,533,536,537,540,541,544,545,549,550,552],{},"A seeder is a ",[459,530,531],{},"seed.Seeder"," value: a ",[454,534,535],{},"name",", an optional ",[454,538,539],{},"Guard"," (decides whether it runs at all), and the ",[454,542,543],{},"Run"," body. ",[450,546,547],{"href":315},[459,548,314],{}," generates one and registers it in ",[459,551,465],{},":",[472,554,558],{"className":555,"code":556,"filename":557,"language":488,"meta":477,"style":477},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","func adminUser(deps Deps) seed.Seeder {\n    return seed.Seeder{\n        Name: \"admin_user\",\n        Run: func(ctx context.Context) error {\n            return nil\n        },\n    }\n}\n","seeds\u002Fadmin_user.go",[459,559,560,594,609,630,660,669,675,681],{"__ignoreMap":477},[481,561,562,566,570,573,577,580,583,585,588,591],{"class":483,"line":484},[481,563,565],{"class":564},"sMK4o","func",[481,567,569],{"class":568},"s2Zo4"," adminUser",[481,571,572],{"class":564},"(",[481,574,576],{"class":575},"sHdIc","deps",[481,578,579],{"class":487}," Deps",[481,581,582],{"class":564},")",[481,584,517],{"class":487},[481,586,587],{"class":564},".",[481,589,590],{"class":487},"Seeder",[481,592,593],{"class":564}," {\n",[481,595,596,600,602,604,606],{"class":483,"line":508},[481,597,599],{"class":598},"s7zQu","    return",[481,601,517],{"class":487},[481,603,587],{"class":564},[481,605,590],{"class":487},[481,607,608],{"class":564},"{\n",[481,610,612,616,618,621,624,627],{"class":483,"line":611},3,[481,613,615],{"class":614},"sTEyZ","        Name",[481,617,552],{"class":564},[481,619,620],{"class":564}," \"",[481,622,623],{"class":491},"admin_user",[481,625,626],{"class":564},"\"",[481,628,629],{"class":564},",\n",[481,631,633,636,638,641,644,647,649,652,654,658],{"class":483,"line":632},4,[481,634,635],{"class":614},"        Run",[481,637,552],{"class":564},[481,639,640],{"class":564}," func(",[481,642,643],{"class":575},"ctx",[481,645,646],{"class":487}," context",[481,648,587],{"class":564},[481,650,651],{"class":487},"Context",[481,653,582],{"class":564},[481,655,657],{"class":656},"spNyl"," error",[481,659,593],{"class":564},[481,661,663,666],{"class":483,"line":662},5,[481,664,665],{"class":598},"            return",[481,667,668],{"class":564}," nil\n",[481,670,672],{"class":483,"line":671},6,[481,673,674],{"class":564},"        },\n",[481,676,678],{"class":483,"line":677},7,[481,679,680],{"class":564},"    }\n",[481,682,684],{"class":483,"line":683},8,[481,685,686],{"class":564},"}\n",[472,688,691],{"className":555,"code":689,"filename":690,"language":488,"meta":477,"style":477},"func Register(reg *seed.Registry, deps Deps) {\n    reg.Add(adminUser(deps))\n    \u002F\u002F gpsystem:seeds\n}\n","seeds\u002Fregister.go",[459,692,693,727,749,754],{"__ignoreMap":477},[481,694,695,697,700,702,705,708,710,712,715,718,721,723,725],{"class":483,"line":484},[481,696,565],{"class":564},[481,698,699],{"class":568}," Register",[481,701,572],{"class":564},[481,703,704],{"class":575},"reg",[481,706,707],{"class":564}," *",[481,709,461],{"class":487},[481,711,587],{"class":564},[481,713,714],{"class":487},"Registry",[481,716,717],{"class":564},",",[481,719,720],{"class":575}," deps",[481,722,579],{"class":487},[481,724,582],{"class":564},[481,726,593],{"class":564},[481,728,729,732,734,737,739,742,744,746],{"class":483,"line":508},[481,730,731],{"class":614},"    reg",[481,733,587],{"class":564},[481,735,736],{"class":568},"Add",[481,738,572],{"class":564},[481,740,741],{"class":568},"adminUser",[481,743,572],{"class":564},[481,745,576],{"class":614},[481,747,748],{"class":564},"))\n",[481,750,751],{"class":483,"line":611},[481,752,753],{"class":504},"    \u002F\u002F gpsystem:seeds\n",[481,755,756],{"class":483,"line":632},[481,757,686],{"class":564},[447,759,760,763,764,767,768,771,772,775,776,779,780,783,784,787],{},[459,761,762],{},"Deps"," mirrors a module's ",[459,765,766],{},"Dependencies",": the query surface (",[459,769,770],{},"*pg.DB"," or ",[459,773,774],{},"*bun.DB",", per the project's ",[459,777,778],{},"--db"," choice) and ",[459,781,782],{},"dbx.Transactor",". ",[459,785,786],{},"Registry.Run"," runs seeders in registration order: this matters when one references a row another creates (e.g. roles before the admin user that references one).",[522,789,791],{"id":790},"the-soul-of-it-first-or-create","The soul of it: first-or-create",[447,793,794,795,798,799,552],{},"Seeders are ",[454,796,797],{},"idempotent",": running one twice never duplicates its data. bun-based projects get a generic primitive for this, ",[459,800,801],{},"seed\u002Fbunx.FirstOrCreate",[472,803,805],{"className":555,"code":804,"language":488,"meta":477,"style":477},"user := &User{Email: \"admin@example.com\", Name: \"Admin\"}\ncreated, err := bunx.FirstOrCreate(ctx, deps.DB, user, \"email\")\n",[459,806,807,852],{"__ignoreMap":477},[481,808,809,812,815,818,821,824,827,829,831,834,836,838,841,843,845,848,850],{"class":483,"line":484},[481,810,811],{"class":614},"user ",[481,813,814],{"class":564},":=",[481,816,817],{"class":564}," &",[481,819,820],{"class":487},"User",[481,822,823],{"class":564},"{",[481,825,826],{"class":614},"Email",[481,828,552],{"class":564},[481,830,620],{"class":564},[481,832,833],{"class":491},"admin@example.com",[481,835,626],{"class":564},[481,837,717],{"class":564},[481,839,840],{"class":614}," Name",[481,842,552],{"class":564},[481,844,620],{"class":564},[481,846,847],{"class":491},"Admin",[481,849,626],{"class":564},[481,851,686],{"class":564},[481,853,854,857,859,862,864,867,869,872,874,876,878,880,882,885,887,890,892,894,897,899],{"class":483,"line":508},[481,855,856],{"class":614},"created",[481,858,717],{"class":564},[481,860,861],{"class":614}," err ",[481,863,814],{"class":564},[481,865,866],{"class":614}," bunx",[481,868,587],{"class":564},[481,870,871],{"class":568},"FirstOrCreate",[481,873,572],{"class":564},[481,875,643],{"class":614},[481,877,717],{"class":564},[481,879,720],{"class":614},[481,881,587],{"class":564},[481,883,884],{"class":614},"DB",[481,886,717],{"class":564},[481,888,889],{"class":614}," user",[481,891,717],{"class":564},[481,893,620],{"class":564},[481,895,896],{"class":491},"email",[481,898,626],{"class":564},[481,900,901],{"class":564},")\n",[447,903,904,905,907,908,911,912,914,915,918,919,922,923,926,927,930],{},"It looks up the existing row by the ",[459,906,896],{}," column; if one exists, it is scanned into ",[459,909,910],{},"user"," (the fields end up reflecting the real row), otherwise ",[459,913,910],{}," is inserted as-is. It runs through ",[459,916,917],{},"bunx.From",", so it joins a transaction opened by ",[459,920,921],{},"WithinTransaction",", if any. For a match condition more complex than a flat column-equals-value check, ",[459,924,925],{},"FirstOrCreateWhere"," takes an arbitrary ",[459,928,929],{},"*bun.SelectQuery"," predicate instead.",[447,932,933,934,937,938,941],{},"Native (pgx) projects have no kit-side helper for this: the seeder writes its own ",[459,935,936],{},"INSERT ... ON CONFLICT (column) DO NOTHING"," SQL against ",[459,939,940],{},"pg.DBTX",", the same as any other native repository.",[522,943,945],{"id":944},"conditional-runs-guard-and-errskip","Conditional runs: Guard and ErrSkip",[447,947,948,949,951,952,954,955,958,959,962],{},"A seeder needs to decide whether it runs at all: that's what ",[459,950,539],{}," is for. It is evaluated before ",[459,953,543],{},"; a ",[459,956,957],{},"false"," result is logged by the runner as a ",[454,960,961],{},"skip",", not a failure:",[472,964,966],{"className":555,"code":965,"language":488,"meta":477,"style":477},"seed.Seeder{\n    Name:  \"demo_data\",\n    Guard: seed.OnlyEnv(currentEnv, \"dev\", \"staging\"),\n    Run:   loadDemoData,\n}\n",[459,967,968,978,995,1035,1047],{"__ignoreMap":477},[481,969,970,972,974,976],{"class":483,"line":484},[481,971,461],{"class":487},[481,973,587],{"class":564},[481,975,590],{"class":487},[481,977,608],{"class":564},[481,979,980,983,985,988,991,993],{"class":483,"line":508},[481,981,982],{"class":614},"    Name",[481,984,552],{"class":564},[481,986,987],{"class":564},"  \"",[481,989,990],{"class":491},"demo_data",[481,992,626],{"class":564},[481,994,629],{"class":564},[481,996,997,1000,1002,1004,1006,1009,1011,1014,1016,1018,1021,1023,1025,1027,1030,1032],{"class":483,"line":611},[481,998,999],{"class":614},"    Guard",[481,1001,552],{"class":564},[481,1003,517],{"class":614},[481,1005,587],{"class":564},[481,1007,1008],{"class":568},"OnlyEnv",[481,1010,572],{"class":564},[481,1012,1013],{"class":614},"currentEnv",[481,1015,717],{"class":564},[481,1017,620],{"class":564},[481,1019,1020],{"class":491},"dev",[481,1022,626],{"class":564},[481,1024,717],{"class":564},[481,1026,620],{"class":564},[481,1028,1029],{"class":491},"staging",[481,1031,626],{"class":564},[481,1033,1034],{"class":564},"),\n",[481,1036,1037,1040,1042,1045],{"class":483,"line":632},[481,1038,1039],{"class":614},"    Run",[481,1041,552],{"class":564},[481,1043,1044],{"class":614},"   loadDemoData",[481,1046,629],{"class":564},[481,1048,1049],{"class":483,"line":662},[481,1050,686],{"class":564},[447,1052,1053,1054,1056,1057,1060],{},"When the condition only becomes clear at runtime (e.g. it depends on the tenant's own data), ",[459,1055,543],{}," itself can bail: returning ",[459,1058,1059],{},"seed.ErrSkip"," counts as a skip too, not a failure.",[472,1062,1064],{"className":555,"code":1063,"language":488,"meta":477,"style":477},"Run: func(ctx context.Context) error {\n    t, _ := seed.TenantFromContext(ctx)\n    if t.Data.(TenantConfig).Plan != \"enterprise\" {\n        return seed.ErrSkip\n    }\n    _, err := bunx.FirstOrCreate(ctx, deps.DB, &EnterpriseDefaults{TenantID: t.ID}, \"tenant_id\")\n    return err\n},\n",[459,1065,1066,1088,1113,1150,1162,1166,1228,1235],{"__ignoreMap":477},[481,1067,1068,1070,1072,1074,1076,1078,1080,1082,1084,1086],{"class":483,"line":484},[481,1069,543],{"class":614},[481,1071,552],{"class":564},[481,1073,640],{"class":564},[481,1075,643],{"class":575},[481,1077,646],{"class":487},[481,1079,587],{"class":564},[481,1081,651],{"class":487},[481,1083,582],{"class":564},[481,1085,657],{"class":656},[481,1087,593],{"class":564},[481,1089,1090,1093,1095,1098,1100,1102,1104,1107,1109,1111],{"class":483,"line":508},[481,1091,1092],{"class":614},"    t",[481,1094,717],{"class":564},[481,1096,1097],{"class":614}," _ ",[481,1099,814],{"class":564},[481,1101,517],{"class":614},[481,1103,587],{"class":564},[481,1105,1106],{"class":568},"TenantFromContext",[481,1108,572],{"class":564},[481,1110,643],{"class":614},[481,1112,901],{"class":564},[481,1114,1115,1118,1121,1123,1126,1129,1132,1135,1138,1141,1143,1146,1148],{"class":483,"line":611},[481,1116,1117],{"class":598},"    if",[481,1119,1120],{"class":614}," t",[481,1122,587],{"class":564},[481,1124,1125],{"class":614},"Data",[481,1127,1128],{"class":564},".(",[481,1130,1131],{"class":487},"TenantConfig",[481,1133,1134],{"class":564},").",[481,1136,1137],{"class":614},"Plan ",[481,1139,1140],{"class":564},"!=",[481,1142,620],{"class":564},[481,1144,1145],{"class":491},"enterprise",[481,1147,626],{"class":564},[481,1149,593],{"class":564},[481,1151,1152,1155,1157,1159],{"class":483,"line":632},[481,1153,1154],{"class":598},"        return",[481,1156,517],{"class":614},[481,1158,587],{"class":564},[481,1160,1161],{"class":614},"ErrSkip\n",[481,1163,1164],{"class":483,"line":662},[481,1165,680],{"class":564},[481,1167,1168,1171,1173,1175,1177,1179,1181,1183,1185,1187,1189,1191,1193,1195,1197,1199,1202,1204,1207,1209,1211,1213,1216,1219,1221,1224,1226],{"class":483,"line":671},[481,1169,1170],{"class":614},"    _",[481,1172,717],{"class":564},[481,1174,861],{"class":614},[481,1176,814],{"class":564},[481,1178,866],{"class":614},[481,1180,587],{"class":564},[481,1182,871],{"class":568},[481,1184,572],{"class":564},[481,1186,643],{"class":614},[481,1188,717],{"class":564},[481,1190,720],{"class":614},[481,1192,587],{"class":564},[481,1194,884],{"class":614},[481,1196,717],{"class":564},[481,1198,817],{"class":564},[481,1200,1201],{"class":487},"EnterpriseDefaults",[481,1203,823],{"class":564},[481,1205,1206],{"class":614},"TenantID",[481,1208,552],{"class":564},[481,1210,1120],{"class":614},[481,1212,587],{"class":564},[481,1214,1215],{"class":614},"ID",[481,1217,1218],{"class":564},"},",[481,1220,620],{"class":564},[481,1222,1223],{"class":491},"tenant_id",[481,1225,626],{"class":564},[481,1227,901],{"class":564},[481,1229,1230,1232],{"class":483,"line":677},[481,1231,599],{"class":598},[481,1233,1234],{"class":614}," err\n",[481,1236,1237],{"class":483,"line":683},[481,1238,1239],{"class":564},"},\n",[522,1241,1243],{"id":1242},"multi-tenant-different-content-per-tenant","Multi-tenant: different content per tenant",[447,1245,1246,1247,1249,1250,1253],{},"One seeder can be the same code for every tenant while producing different data for each: ",[459,1248,786],{}," with the ",[459,1251,1252],{},"seed.WithTenants"," option runs once per tenant, with the tenant placed in the context.",[472,1255,1257],{"className":555,"code":1256,"language":488,"meta":477,"style":477},"tenants := []seed.Tenant{\n    {ID: \"acme\", Data: TenantConfig{Plan: \"enterprise\"}},\n    {ID: \"globex\", Data: TenantConfig{Plan: \"starter\"}},\n}\nif err := reg.Run(ctx, seed.WithTenants(tenants)); err != nil {\n    log.Fatal(err)\n}\n",[459,1258,1259,1278,1320,1358,1362,1408,1425],{"__ignoreMap":477},[481,1260,1261,1264,1266,1269,1271,1273,1276],{"class":483,"line":484},[481,1262,1263],{"class":614},"tenants ",[481,1265,814],{"class":564},[481,1267,1268],{"class":564}," []",[481,1270,461],{"class":487},[481,1272,587],{"class":564},[481,1274,1275],{"class":487},"Tenant",[481,1277,608],{"class":564},[481,1279,1280,1283,1285,1287,1289,1292,1294,1296,1299,1301,1304,1306,1309,1311,1313,1315,1317],{"class":483,"line":508},[481,1281,1282],{"class":564},"    {",[481,1284,1215],{"class":614},[481,1286,552],{"class":564},[481,1288,620],{"class":564},[481,1290,1291],{"class":491},"acme",[481,1293,626],{"class":564},[481,1295,717],{"class":564},[481,1297,1298],{"class":614}," Data",[481,1300,552],{"class":564},[481,1302,1303],{"class":487}," TenantConfig",[481,1305,823],{"class":564},[481,1307,1308],{"class":614},"Plan",[481,1310,552],{"class":564},[481,1312,620],{"class":564},[481,1314,1145],{"class":491},[481,1316,626],{"class":564},[481,1318,1319],{"class":564},"}},\n",[481,1321,1322,1324,1326,1328,1330,1333,1335,1337,1339,1341,1343,1345,1347,1349,1351,1354,1356],{"class":483,"line":611},[481,1323,1282],{"class":564},[481,1325,1215],{"class":614},[481,1327,552],{"class":564},[481,1329,620],{"class":564},[481,1331,1332],{"class":491},"globex",[481,1334,626],{"class":564},[481,1336,717],{"class":564},[481,1338,1298],{"class":614},[481,1340,552],{"class":564},[481,1342,1303],{"class":487},[481,1344,823],{"class":564},[481,1346,1308],{"class":614},[481,1348,552],{"class":564},[481,1350,620],{"class":564},[481,1352,1353],{"class":491},"starter",[481,1355,626],{"class":564},[481,1357,1319],{"class":564},[481,1359,1360],{"class":483,"line":632},[481,1361,686],{"class":564},[481,1363,1364,1367,1369,1371,1374,1376,1378,1380,1382,1384,1386,1388,1391,1393,1396,1399,1401,1403,1406],{"class":483,"line":662},[481,1365,1366],{"class":598},"if",[481,1368,861],{"class":614},[481,1370,814],{"class":564},[481,1372,1373],{"class":614}," reg",[481,1375,587],{"class":564},[481,1377,543],{"class":568},[481,1379,572],{"class":564},[481,1381,643],{"class":614},[481,1383,717],{"class":564},[481,1385,517],{"class":614},[481,1387,587],{"class":564},[481,1389,1390],{"class":568},"WithTenants",[481,1392,572],{"class":564},[481,1394,1395],{"class":614},"tenants",[481,1397,1398],{"class":564},"));",[481,1400,861],{"class":614},[481,1402,1140],{"class":564},[481,1404,1405],{"class":564}," nil",[481,1407,593],{"class":564},[481,1409,1410,1413,1415,1418,1420,1423],{"class":483,"line":671},[481,1411,1412],{"class":614},"    log",[481,1414,587],{"class":564},[481,1416,1417],{"class":568},"Fatal",[481,1419,572],{"class":564},[481,1421,1422],{"class":614},"err",[481,1424,901],{"class":564},[481,1426,1427],{"class":483,"line":677},[481,1428,686],{"class":564},[447,1430,1431,1434,1435,1438],{},[459,1432,1433],{},"Tenant.Data"," is an arbitrary, project-specific payload; a seeder reaches it via a type assertion. ",[459,1436,1437],{},"seed.OnlyTenants(ids...)"," is a ready-made Guard for seeders that should only run for specific tenants.",[1440,1441,1442,1443,1446,1447,1450,1451,1453,1454,1456],"note",{},"The kit does ",[454,1444,1445],{},"not"," ship a tenant source (no tenant table, no ",[459,1448,1449],{},"search_path"," switching, no RLS): where the ",[459,1452,1275],{}," list comes from (an env var, a table, an admin API) is left to the project. ",[459,1455,1390],{}," is a hook, not a ready-made multi-tenant infrastructure.",[522,1458,1460],{"id":1459},"why-isnt-this-part-of-migrations","Why isn't this part of migrations?",[447,1462,1463,1464,1467,1468,1470,1471,1474],{},"Migrations and seeding often run on different lifecycles: a migration always runs, a seeder is frequently needed only in development or on first deploy. That's why ",[459,1465,1466],{},"--seed"," and the ",[459,1469,461],{}," subcommand are explicit: ",[459,1472,1473],{},"go run .\u002Fcmd\u002Fmigrate up"," on its own never writes data, only schema. In production, this means turning seeding on (or leaving it off) is a decision made by the deploy pipeline, not a silent side effect of the migration step.",[1476,1477,1478],"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 .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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":477,"searchDepth":508,"depth":508,"links":1480},[1481,1482,1483,1484,1485],{"id":524,"depth":508,"text":525},{"id":790,"depth":508,"text":791},{"id":944,"depth":508,"text":945},{"id":1242,"depth":508,"text":1243},{"id":1459,"depth":508,"text":1460},"Idempotent baseline data loading after migrations, built on first-or-create, with optional guards and multi-tenant support.","md",null,{},{"icon":317},{"title":426,"description":1486},"W5SqX89nvM7gh5_-YoiZIgleioPm-L35s_iPxCZQ61Q",[1494,1496],{"title":421,"path":422,"stem":423,"description":1495,"icon":424,"children":-1},"Cross-repository transactions carried by the context, no plumbing.",{"title":52,"path":435,"stem":436,"description":1497,"icon":55,"children":-1},"Offset (page\u002Fper-page) pagination with the paginate module, normalized parameters and a typed page wrapper.",1785445895187]