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