[{"data":1,"prerenderedAt":3853},["ShallowReactive",2],{"navigation_docs_en":3,"-en-kit-server":441,"-en-kit-server-surround":3848},[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":257,"body":443,"description":3841,"extension":3842,"links":3843,"meta":3844,"navigation":3845,"path":258,"seo":3846,"stem":259,"__hash__":3847},"docs_en\u002Fen\u002F3.kit\u002F3.server.md",{"type":444,"value":445,"toc":3819},"minimark",[446,490,519,537,542,555,624,627,864,870,875,878,907,911,974,999,1002,1037,1041,1077,1081,1103,1150,1159,1165,1169,1292,1330,1333,1498,1513,1517,1520,1565,1569,1575,2173,2181,2185,2363,2429,2433,2451,2798,2801,2884,2888,3006,3021,3046,3050,3068,3517,3545,3578,3581,3589,3743,3746,3750,3782,3786,3815],[447,448,449,453,454,461,462,465,466,469,470,474,475,477,478,481,482,485,486,489],"p",{},[450,451,452],"code",{},"server"," is the kit's HTTP chassis: a ",[455,456,460],"a",{"href":457,"rel":458},"https:\u002F\u002Fgithub.com\u002Fgo-chi\u002Fchi",[459],"nofollow","chi"," router over the standard ",[450,463,464],{},"net\u002Fhttp",", with the kit's error handling, validation and telemetry wired in, run under the ",[455,467,468],{"href":253},"shared lifecycle",". Its positioning is ",[471,472,473],"strong",{},"stdlib-first",": chi is not a framework, it is routing over ",[450,476,464],{},". Every middleware is a plain ",[450,479,480],{},"func(http.Handler) http.Handler",", every handler is ",[450,483,484],{},"http.HandlerFunc","-compatible, so any net\u002Fhttp tool in the Go ecosystem (middleware libraries, ",[450,487,488],{},"httptest",", profilers) works unmodified.",[491,492,497],"pre",{"className":493,"code":494,"language":495,"meta":496,"style":496},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fgpsystem\u002Fserver\"\n","go","",[450,498,499],{"__ignoreMap":496},[500,501,504,508,512,516],"span",{"class":502,"line":503},"line",1,[500,505,507],{"class":506},"s7zQu","import",[500,509,511],{"class":510},"sMK4o"," \"",[500,513,515],{"class":514},"sBMFI","github.com\u002Fgp-system\u002Fgpsystem\u002Fserver",[500,517,518],{"class":510},"\"\n",[447,520,521,522,525,526,528,529,532,533,536],{},"It is the chassis every ",[455,523,524],{"href":320},"generated"," project sits on; application code never talks to ",[450,527,464],{}," directly, it calls ",[450,530,531],{},"server.Run"," once, in ",[450,534,535],{},"main",".",[538,539,541],"h2",{"id":540},"config","Config",[447,543,544,545,548,549,554],{},"In a generated project, ",[450,546,547],{},"server.Config"," is embedded without a prefix in the application config and loaded from environment variables by ",[455,550,551],{"href":378},[450,552,553],{},"envconf.MustLoad",":",[491,556,559],{"className":493,"code":557,"filename":558,"language":495,"meta":496,"style":496},"type Config struct {\n    Server server.Config\n    DB     dbx.Config `envPrefix:\"DB_\"`\n    \u002F\u002F ...\n}\n","internal\u002Fplatform\u002Fconfig\u002Fconfig.go",[450,560,561,575,589,611,618],{"__ignoreMap":496},[500,562,563,566,569,572],{"class":502,"line":503},[500,564,565],{"class":510},"type",[500,567,568],{"class":514}," Config",[500,570,571],{"class":510}," struct",[500,573,574],{"class":510}," {\n",[500,576,578,582,584,586],{"class":502,"line":577},2,[500,579,581],{"class":580},"sTEyZ","    Server ",[500,583,452],{"class":514},[500,585,536],{"class":510},[500,587,588],{"class":514},"Config\n",[500,590,592,595,597,599,601,604,608],{"class":502,"line":591},3,[500,593,594],{"class":580},"    DB     ",[500,596,404],{"class":514},[500,598,536],{"class":510},[500,600,541],{"class":514},[500,602,603],{"class":510}," `",[500,605,607],{"class":606},"sfazB","envPrefix:\"DB_\"",[500,609,610],{"class":510},"`\n",[500,612,614],{"class":502,"line":613},4,[500,615,617],{"class":616},"sHwdD","    \u002F\u002F ...\n",[500,619,621],{"class":502,"line":620},5,[500,622,623],{"class":510},"}\n",[447,625,626],{},"The fields and their environment variables:",[628,629,630,649],"table",{},[631,632,633],"thead",{},[634,635,636,640,643,646],"tr",{},[637,638,639],"th",{},"Field",[637,641,642],{},"Env",[637,644,645],{},"Default",[637,647,648],{},"What it controls",[650,651,652,673,700,720,740,761,781,801,822,842],"tbody",{},[634,653,654,660,665,670],{},[655,656,657],"td",{},[450,658,659],{},"ListenAddr",[655,661,662],{},[450,663,664],{},"LISTEN_ADDR",[655,666,667],{},[450,668,669],{},":3000",[655,671,672],{},"the address the server listens on",[634,674,675,680,685,690],{},[655,676,677],{},[450,678,679],{},"ShutdownTimeout",[655,681,682],{},[450,683,684],{},"SHUTDOWN_TIMEOUT",[655,686,687],{},[450,688,689],{},"10s",[655,691,692,693,696,697],{},"how long in-flight requests get after ",[450,694,695],{},"SIGINT","\u002F",[450,698,699],{},"SIGTERM",[634,701,702,707,712,717],{},[655,703,704],{},[450,705,706],{},"ReadHeaderTimeout",[655,708,709],{},[450,710,711],{},"READ_HEADER_TIMEOUT",[655,713,714],{},[450,715,716],{},"5s",[655,718,719],{},"how long a client may take to send request headers (Slowloris defense)",[634,721,722,727,732,737],{},[655,723,724],{},[450,725,726],{},"ReadTimeout",[655,728,729],{},[450,730,731],{},"READ_TIMEOUT",[655,733,734],{},[450,735,736],{},"30s",[655,738,739],{},"budget for reading the whole request (headers + body)",[634,741,742,747,752,758],{},[655,743,744],{},[450,745,746],{},"WriteTimeout",[655,748,749],{},[450,750,751],{},"WRITE_TIMEOUT",[655,753,754,757],{},[450,755,756],{},"0s"," (disabled)",[655,759,760],{},"budget for writing the response",[634,762,763,768,773,778],{},[655,764,765],{},[450,766,767],{},"IdleTimeout",[655,769,770],{},[450,771,772],{},"IDLE_TIMEOUT",[655,774,775],{},[450,776,777],{},"120s",[655,779,780],{},"how long an idle keep-alive connection stays open",[634,782,783,788,793,798],{},[655,784,785],{},[450,786,787],{},"CORSOrigins",[655,789,790],{},[450,791,792],{},"CORS_ORIGINS",[655,794,795],{},[450,796,797],{},"*",[655,799,800],{},"allowed origins, comma-separated",[634,802,803,808,813,819],{},[655,804,805],{},[450,806,807],{},"BodyLimit",[655,809,810],{},[450,811,812],{},"BODY_LIMIT",[655,814,815,818],{},[450,816,817],{},"4194304"," (4 MiB)",[655,820,821],{},"max request body size in bytes",[634,823,824,829,834,839],{},[655,825,826],{},[450,827,828],{},"ExposeInternalErrors",[655,830,831],{},[450,832,833],{},"HTTP_EXPOSE_INTERNAL_ERRORS",[655,835,836],{},[450,837,838],{},"false",[655,840,841],{},"internal error details in 5xx responses (dev only!)",[634,843,844,849,855,858],{},[655,845,846],{},[450,847,848],{},"Telemetry",[655,850,851],{},[852,853,854],"em",{},"(embedded)",[655,856,857],{},"none",[655,859,860,863],{},[450,861,862],{},"telemetry.Config"," (OTel, logger, Sentry)",[447,865,866,867,536],{},"The full env reference (including the DB, worker and telemetry variables): ",[455,868,869],{"href":205},"Configuration reference",[871,872,874],"h3",{"id":873},"timeouts","Timeouts",[447,876,877],{},"The defaults are tuned for production traffic, not demos:",[879,880,881,889,896],"ul",{},[882,883,884,888],"li",{},[471,885,886],{},[450,887,706],{}," is the first line of Slowloris defense: a client that drips headers byte by byte gets disconnected after 5 seconds.",[882,890,891,895],{},[471,892,893],{},[450,894,726],{}," covers reading the whole request.",[882,897,898,902,903,906],{},[471,899,900],{},[450,901,746],{}," is deliberately ",[450,904,905],{},"0"," (disabled): it would also cut off slow or streaming responses (large downloads, SSE). Enable it when all your endpoints are short-lived.",[871,908,910],{"id":909},"body-limit-never-accidentally-disabled","Body limit: never accidentally disabled",[491,912,914],{"className":493,"code":913,"language":495,"meta":496,"style":496},"const DefaultBodyLimit = 4 \u003C\u003C 20 \u002F\u002F 4 MiB\n\nfunc (c Config) EffectiveBodyLimit() int\n",[450,915,916,940,946],{"__ignoreMap":496},[500,917,918,921,924,927,931,934,937],{"class":502,"line":503},[500,919,920],{"class":510},"const",[500,922,923],{"class":580}," DefaultBodyLimit ",[500,925,926],{"class":510},"=",[500,928,930],{"class":929},"sbssI"," 4",[500,932,933],{"class":510}," \u003C\u003C",[500,935,936],{"class":929}," 20",[500,938,939],{"class":616}," \u002F\u002F 4 MiB\n",[500,941,942],{"class":502,"line":577},[500,943,945],{"emptyLinePlaceholder":944},true,"\n",[500,947,948,951,954,958,960,963,967,970],{"class":502,"line":591},[500,949,950],{"class":510},"func",[500,952,953],{"class":510}," (",[500,955,957],{"class":956},"sHdIc","c ",[500,959,541],{"class":514},[500,961,962],{"class":510},")",[500,964,966],{"class":965},"s2Zo4"," EffectiveBodyLimit",[500,968,969],{"class":510},"()",[500,971,973],{"class":972},"spNyl"," int\n",[447,975,976,978,979,981,982,985,986,988,989,992,993,995,996,536],{},[450,977,452],{}," never reads the raw ",[450,980,807],{}," field; it calls ",[450,983,984],{},"EffectiveBodyLimit()",": a ",[450,987,905],{}," or negative value does ",[471,990,991],{},"not"," mean \"unlimited\", it falls back to the 4 MiB default. A typo'd or empty ",[450,994,812],{}," therefore cannot silently remove the cap. Exceeding the limit produces a 413 ",[455,997,998],{"href":395},"problem response",[871,1000,833],{"id":1001},"http_expose_internal_errors",[447,1003,1004,1005,1008,1009,1012,1013,1017,1018,1021,1022,1025,1026,1029,1030,1033,1034,1036],{},"With ",[450,1006,1007],{},"true",", 5xx responses carry the underlying error message in ",[450,1010,1011],{},"detail",", and, when the chain holds an ",[455,1014,1015],{"href":362},[450,1016,357],{}," error, the response also gains ",[450,1019,1020],{},"stack"," and ",[450,1023,1024],{},"chain"," extension members. It is deliberately a ",[471,1027,1028],{},"separate"," switch from ",[450,1031,1032],{},"OTEL_DEV_MODE",": turning on dev logging can never accidentally start leaking internals to clients. Keep it ",[450,1035,838],{}," in production: details go to the log and Sentry there, not into the response.",[871,1038,1040],{"id":1039},"the-embedded-telemetry-config","The embedded telemetry config",[447,1042,1043,1044,1046,1047,1049,1050,1053,1054,1057,1058,1057,1060,1057,1063,1066,1067,1069,1070,1073,1074,536],{},"The ",[450,1045,848],{}," field is a ",[450,1048,862],{},": settings for the OTel bootstrap, the default ",[450,1051,1052],{},"slog"," logger and the optional Sentry integration (",[450,1055,1056],{},"OTEL_SERVICE_NAME",", ",[450,1059,1032],{},[450,1061,1062],{},"LOG_LEVEL",[450,1064,1065],{},"SENTRY_DSN",", ..., all standard names, no prefix). ",[450,1068,531],{}," calls ",[450,1071,1072],{},"telemetry.Setup"," from it before anything else starts. Details: ",[455,1075,1076],{"href":180},"Observability",[538,1078,1080],{"id":1079},"the-shared-lifecycle","The shared lifecycle",[447,1082,1083,1085,1086,1091,1092,1021,1097,1102],{},[450,1084,452],{}," does not implement graceful shutdown itself: it delegates to the engine-agnostic ",[455,1087,1088],{"href":253},[450,1089,1090],{},"app"," package, the same one ",[455,1093,1094],{"href":263},[450,1095,1096],{},"worker",[455,1098,1099],{"href":268},[450,1100,1101],{},"realtime"," sit on. The flow is identical in every gpsystem process:",[1104,1105,1106,1111,1118,1121,1136,1147],"ol",{},[882,1107,1108,1110],{},[450,1109,1072],{},": OTel, logger, Sentry.",[882,1112,1113,1114,1117],{},"Route registration (your ",[450,1115,1116],{},"register"," function).",[882,1119,1120],{},"Listen: the process blocks from here.",[882,1122,1123,1124,696,1126,1128,1129,1131,1132,1135],{},"On ",[450,1125,695],{},[450,1127,699],{},": the server stops accepting requests and drains in-flight ones within ",[450,1130,679],{},". A ",[471,1133,1134],{},"second"," signal kills the process immediately.",[882,1137,1138,1139,1142,1143,1146],{},"Cleanups registered with ",[450,1140,1141],{},"WithCloser"," run in ",[471,1144,1145],{},"LIFO"," order (with their own grace period, even when the drain consumed the budget).",[882,1148,1149],{},"Telemetry flushes last: spans emitted by closers still get exported.",[447,1151,1152,1153,1155,1156,1158],{},"The exact ordering and signal-handling details live on the ",[455,1154,252],{"href":253}," page; this page covers what ",[450,1157,531],{}," itself wires on top of that shared skeleton.",[1160,1161,1162,1164],"note",{},[450,1163,547],{}," carries the full web-server configuration: every field is loaded from an environment variable, typed, and graceful shutdown is the binary's job, not an external process manager's.",[538,1166,1168],{"id":1167},"what-serverrun-wires","What server.Run wires",[491,1170,1172],{"className":493,"code":1171,"language":495,"meta":496,"style":496},"func Run(ctx context.Context, cfg Config, register RegisterFunc, opts ...Option) error\nfunc New(cfg Config, opts ...Option) *chi.Mux \u002F\u002F for tests and special cases\n\ntype RegisterFunc func(r chi.Router) error\n",[450,1173,1174,1227,1264,1268],{"__ignoreMap":496},[500,1175,1176,1178,1181,1184,1187,1190,1192,1195,1198,1201,1203,1205,1208,1211,1213,1216,1219,1222,1224],{"class":502,"line":503},[500,1177,950],{"class":510},[500,1179,1180],{"class":965}," Run",[500,1182,1183],{"class":510},"(",[500,1185,1186],{"class":956},"ctx",[500,1188,1189],{"class":514}," context",[500,1191,536],{"class":510},[500,1193,1194],{"class":514},"Context",[500,1196,1197],{"class":510},",",[500,1199,1200],{"class":956}," cfg",[500,1202,568],{"class":514},[500,1204,1197],{"class":510},[500,1206,1207],{"class":956}," register",[500,1209,1210],{"class":514}," RegisterFunc",[500,1212,1197],{"class":510},[500,1214,1215],{"class":956}," opts",[500,1217,1218],{"class":510}," ...",[500,1220,1221],{"class":514},"Option",[500,1223,962],{"class":510},[500,1225,1226],{"class":972}," error\n",[500,1228,1229,1231,1234,1236,1239,1241,1243,1245,1247,1249,1251,1254,1256,1258,1261],{"class":502,"line":577},[500,1230,950],{"class":510},[500,1232,1233],{"class":965}," New",[500,1235,1183],{"class":510},[500,1237,1238],{"class":956},"cfg",[500,1240,568],{"class":514},[500,1242,1197],{"class":510},[500,1244,1215],{"class":956},[500,1246,1218],{"class":510},[500,1248,1221],{"class":514},[500,1250,962],{"class":510},[500,1252,1253],{"class":510}," *",[500,1255,460],{"class":514},[500,1257,536],{"class":510},[500,1259,1260],{"class":514},"Mux",[500,1262,1263],{"class":616}," \u002F\u002F for tests and special cases\n",[500,1265,1266],{"class":502,"line":591},[500,1267,945],{"emptyLinePlaceholder":944},[500,1269,1270,1272,1274,1277,1280,1283,1285,1288,1290],{"class":502,"line":613},[500,1271,565],{"class":510},[500,1273,1210],{"class":514},[500,1275,1276],{"class":510}," func(",[500,1278,1279],{"class":956},"r",[500,1281,1282],{"class":514}," chi",[500,1284,536],{"class":510},[500,1286,1287],{"class":514},"Router",[500,1289,962],{"class":510},[500,1291,1226],{"class":972},[447,1293,1294,1297,1298,1301,1302,1305,1306,1309,1310,696,1312,1314,1315,1318,1319,1322,1323,1325,1326,1329],{},[450,1295,1296],{},"Run"," blocks until exit: telemetry bootstrap → router construction → ",[450,1299,1300],{},"register(r)"," → ",[450,1303,1304],{},"http.Server"," + ",[450,1307,1308],{},"ListenAndServe"," → graceful shutdown on ",[450,1311,695],{},[450,1313,699],{},". It returns ",[450,1316,1317],{},"nil"," on clean shutdown. ",[450,1320,1321],{},"New"," returns the fully wired router without running it or bootstrapping telemetry: you pair it with ",[450,1324,488],{}," (see ",[455,1327,169],{"href":1328},"#testing",").",[447,1331,1332],{},"The middleware chain and the router-level handlers, in this order:",[628,1334,1335,1348],{},[631,1336,1337],{},[634,1338,1339,1342,1345],{},[637,1340,1341],{},"What",[637,1343,1344],{},"From",[637,1346,1347],{},"What it does",[650,1349,1350,1372,1390,1405,1418,1435,1461,1482],{},[634,1351,1352,1355,1358],{},[655,1353,1354],{},"recoverer",[655,1356,1357],{},"kit",[655,1359,1360,1361,1363,1364,1367,1368,1371],{},"a panic becomes an ",[450,1362,357],{}," error whose stack points at the ",[471,1365,1366],{},"panic site",", rendered as a 500 problem response (it re-raises ",[450,1369,1370],{},"http.ErrAbortHandler",", net\u002Fhttp's flow-control signal)",[634,1373,1374,1377,1379],{},[655,1375,1376],{},"validator injector",[655,1378,1357],{},[655,1380,1381,1382,1385,1386,1389],{},"puts the validator given via ",[450,1383,1384],{},"WithValidator"," into the request context, where ",[450,1387,1388],{},"StrictValidator(nil)"," finds it (see below)",[634,1391,1392,1395,1400],{},[655,1393,1394],{},"OTel middleware",[655,1396,1397],{},[450,1398,1399],{},"otelhttp",[655,1401,1402,1403],{},"per-request server span + HTTP metrics: ",[455,1404,188],{"href":189},[634,1406,1407,1410,1412],{},[655,1408,1409],{},"Sentry request hub",[655,1411,1357],{},[655,1413,1414,1415,1417],{},"an isolated Sentry hub per request, so breadcrumbs never mix across requests; no-op when ",[455,1416,193],{"href":194}," is off",[634,1419,1420,1423,1428],{},[655,1421,1422],{},"dev logger",[655,1424,1425],{},[450,1426,1427],{},"chi\u002Fmiddleware.Logger",[655,1429,1430,1431,1434],{},"only with ",[450,1432,1433],{},"OTEL_DEV_MODE=true",": request log on the console",[634,1436,1437,1440,1445],{},[655,1438,1439],{},"CORS",[655,1441,1442],{},[450,1443,1444],{},"go-chi\u002Fcors",[655,1446,1447,1448,1450,1451,1057,1454,1305,1457,1460],{},"from ",[450,1449,792],{},"; ",[450,1452,1453],{},"GET\u002FPOST\u002FPUT\u002FPATCH\u002FDELETE\u002FOPTIONS",[450,1455,1456],{},"Content-Type",[450,1458,1459],{},"Authorization"," headers",[634,1462,1463,1466,1471],{},[655,1464,1465],{},"body limit",[655,1467,1468],{},[450,1469,1470],{},"chi\u002Fmiddleware.RequestSize",[655,1472,1473,1474,1477,1478,1481],{},"wraps the body in ",[450,1475,1476],{},"http.MaxBytesReader"," with ",[450,1479,1480],{},"cfg.EffectiveBodyLimit()",": exceeding it yields a 413 problem",[634,1483,1484,1493,1495],{},[655,1485,1486,1489,1490],{},[450,1487,1488],{},"NotFound"," \u002F ",[450,1491,1492],{},"MethodNotAllowed",[655,1494,1357],{},[655,1496,1497],{},"404\u002F405 as problem+json instead of chi's stock plain-text errors; mounted subrouters inherit them",[447,1499,1043,1500,1502,1503,953,1505,1057,1507,1057,1509,1057,1511,1329],{},[450,1501,547],{}," timeouts translate into the ",[450,1504,1304],{},[450,1506,706],{},[450,1508,726],{},[450,1510,746],{},[450,1512,767],{},[871,1514,1516],{"id":1515},"error-rendering-nethttp-has-no-central-error-handler","Error rendering: net\u002Fhttp has no central error handler",[447,1518,1519],{},"Unlike frameworks with a built-in error hook, net\u002Fhttp gives a handler no way to \"return\" an error to the framework: a handler writes the response itself. The kit bridges this at three points so the on-the-wire behavior is uniform everywhere:",[879,1521,1522,1545,1551],{},[882,1523,1524,1525,1528,1529,953,1534,1057,1537,1540,1541,1544],{},"the ",[471,1526,1527],{},"generated server code's error hooks"," are wired to the ",[455,1530,1531,1533],{"href":395},[450,1532,385],{}," net\u002Fhttp writers",[450,1535,1536],{},"WriteError",[450,1538,1539],{},"WriteBadRequest","): an error returned from your handler goes through the ",[455,1542,1543],{"href":395},"full mapping",";",[882,1546,1524,1547,1550],{},[471,1548,1549],{},"router-level cases"," (panic, 404, 405, body limit) are rendered as problems per the table above;",[882,1552,1553,1556,1557,1560,1561,1564],{},[471,1554,1555],{},"request validation"," does not run at bind time (the strict server decodes with ",[450,1558,1559],{},"json.Decoder",") but in the ",[450,1562,1563],{},"server.StrictValidator"," strict middleware (see below).",[538,1566,1568],{"id":1567},"the-shop-entry-point","The shop entry point",[447,1570,1043,1571,1574],{},[455,1572,1573],{"href":41},"sample app's"," HTTP binary, every line of which was written by the generator:",[491,1576,1579],{"className":493,"code":1577,"filename":1578,"language":495,"meta":496,"style":496},"package main\n\nimport (\n    \"context\"\n    \"log\"\n\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\"\n\n    \"github.com\u002Fgp-system\u002Fdbx\u002Fpg\"\n    \"github.com\u002Fgp-system\u002Fenvconf\"\n    \"github.com\u002Fgp-system\u002Fevents\u002Foutbox\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fserver\"\n\n    \"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\"\n    \"github.com\u002Facme\u002Fshop\u002Finternal\u002Fplatform\u002Fconfig\"\n)\n\nfunc main() {\n    cfg := envconf.MustLoad[config.Config]()\n    ctx := context.Background()\n    pool := pg.MustNewPool(ctx, cfg.DB)\n\n    err := server.Run(ctx, cfg.Server, func(r chi.Router) error {\n        api := chi.NewRouter()\n        deps := shop.Dependencies{\n            DB:         pg.NewDB(pool),\n            Transactor: pg.NewTransactor(pool),\n            Dispatcher: outbox.NewDispatcher(outbox.NewStore(pg.NewDB(pool))),\n        }\n        shop.RegisterApi(api, deps)\n        shop.RegisterAdmin(api, deps)\n        r.Mount(\"\u002Fapi\u002Fv1\", api)\n        return nil\n    }, server.WithCloser(\"pgxpool\", func(context.Context) error {\n        pool.Close()\n        return nil\n    }))\n    if err != nil {\n        log.Fatal(err)\n    }\n}\n","cmd\u002Fshop\u002Fmain.go",[450,1580,1581,1589,1593,1600,1610,1619,1624,1634,1639,1649,1659,1669,1678,1683,1693,1703,1709,1714,1726,1755,1773,1804,1809,1855,1872,1891,1915,1936,1978,1984,2007,2027,2055,2064,2101,2114,2121,2127,2144,2162,2168],{"__ignoreMap":496},[500,1582,1583,1586],{"class":502,"line":503},[500,1584,1585],{"class":510},"package",[500,1587,1588],{"class":514}," main\n",[500,1590,1591],{"class":502,"line":577},[500,1592,945],{"emptyLinePlaceholder":944},[500,1594,1595,1597],{"class":502,"line":591},[500,1596,507],{"class":506},[500,1598,1599],{"class":510}," (\n",[500,1601,1602,1605,1608],{"class":502,"line":613},[500,1603,1604],{"class":510},"    \"",[500,1606,1607],{"class":514},"context",[500,1609,518],{"class":510},[500,1611,1612,1614,1617],{"class":502,"line":620},[500,1613,1604],{"class":510},[500,1615,1616],{"class":514},"log",[500,1618,518],{"class":510},[500,1620,1622],{"class":502,"line":1621},6,[500,1623,945],{"emptyLinePlaceholder":944},[500,1625,1627,1629,1632],{"class":502,"line":1626},7,[500,1628,1604],{"class":510},[500,1630,1631],{"class":514},"github.com\u002Fgo-chi\u002Fchi\u002Fv5",[500,1633,518],{"class":510},[500,1635,1637],{"class":502,"line":1636},8,[500,1638,945],{"emptyLinePlaceholder":944},[500,1640,1642,1644,1647],{"class":502,"line":1641},9,[500,1643,1604],{"class":510},[500,1645,1646],{"class":514},"github.com\u002Fgp-system\u002Fdbx\u002Fpg",[500,1648,518],{"class":510},[500,1650,1652,1654,1657],{"class":502,"line":1651},10,[500,1653,1604],{"class":510},[500,1655,1656],{"class":514},"github.com\u002Fgp-system\u002Fenvconf",[500,1658,518],{"class":510},[500,1660,1662,1664,1667],{"class":502,"line":1661},11,[500,1663,1604],{"class":510},[500,1665,1666],{"class":514},"github.com\u002Fgp-system\u002Fevents\u002Foutbox",[500,1668,518],{"class":510},[500,1670,1672,1674,1676],{"class":502,"line":1671},12,[500,1673,1604],{"class":510},[500,1675,515],{"class":514},[500,1677,518],{"class":510},[500,1679,1681],{"class":502,"line":1680},13,[500,1682,945],{"emptyLinePlaceholder":944},[500,1684,1686,1688,1691],{"class":502,"line":1685},14,[500,1687,1604],{"class":510},[500,1689,1690],{"class":514},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop",[500,1692,518],{"class":510},[500,1694,1696,1698,1701],{"class":502,"line":1695},15,[500,1697,1604],{"class":510},[500,1699,1700],{"class":514},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fplatform\u002Fconfig",[500,1702,518],{"class":510},[500,1704,1706],{"class":502,"line":1705},16,[500,1707,1708],{"class":510},")\n",[500,1710,1712],{"class":502,"line":1711},17,[500,1713,945],{"emptyLinePlaceholder":944},[500,1715,1717,1719,1722,1724],{"class":502,"line":1716},18,[500,1718,950],{"class":510},[500,1720,1721],{"class":965}," main",[500,1723,969],{"class":510},[500,1725,574],{"class":510},[500,1727,1729,1732,1735,1738,1740,1743,1746,1748,1750,1752],{"class":502,"line":1728},19,[500,1730,1731],{"class":580},"    cfg ",[500,1733,1734],{"class":510},":=",[500,1736,1737],{"class":580}," envconf",[500,1739,536],{"class":510},[500,1741,1742],{"class":965},"MustLoad",[500,1744,1745],{"class":510},"[",[500,1747,540],{"class":514},[500,1749,536],{"class":510},[500,1751,541],{"class":514},[500,1753,1754],{"class":510},"]()\n",[500,1756,1758,1761,1763,1765,1767,1770],{"class":502,"line":1757},20,[500,1759,1760],{"class":580},"    ctx ",[500,1762,1734],{"class":510},[500,1764,1189],{"class":580},[500,1766,536],{"class":510},[500,1768,1769],{"class":965},"Background",[500,1771,1772],{"class":510},"()\n",[500,1774,1776,1779,1781,1784,1786,1789,1791,1793,1795,1797,1799,1802],{"class":502,"line":1775},21,[500,1777,1778],{"class":580},"    pool ",[500,1780,1734],{"class":510},[500,1782,1783],{"class":580}," pg",[500,1785,536],{"class":510},[500,1787,1788],{"class":965},"MustNewPool",[500,1790,1183],{"class":510},[500,1792,1186],{"class":580},[500,1794,1197],{"class":510},[500,1796,1200],{"class":580},[500,1798,536],{"class":510},[500,1800,1801],{"class":580},"DB",[500,1803,1708],{"class":510},[500,1805,1807],{"class":502,"line":1806},22,[500,1808,945],{"emptyLinePlaceholder":944},[500,1810,1812,1815,1817,1820,1822,1824,1826,1828,1830,1832,1834,1836,1838,1840,1842,1844,1846,1848,1850,1853],{"class":502,"line":1811},23,[500,1813,1814],{"class":580},"    err ",[500,1816,1734],{"class":510},[500,1818,1819],{"class":580}," server",[500,1821,536],{"class":510},[500,1823,1296],{"class":965},[500,1825,1183],{"class":510},[500,1827,1186],{"class":580},[500,1829,1197],{"class":510},[500,1831,1200],{"class":580},[500,1833,536],{"class":510},[500,1835,257],{"class":580},[500,1837,1197],{"class":510},[500,1839,1276],{"class":510},[500,1841,1279],{"class":956},[500,1843,1282],{"class":514},[500,1845,536],{"class":510},[500,1847,1287],{"class":514},[500,1849,962],{"class":510},[500,1851,1852],{"class":972}," error",[500,1854,574],{"class":510},[500,1856,1858,1861,1863,1865,1867,1870],{"class":502,"line":1857},24,[500,1859,1860],{"class":580},"        api ",[500,1862,1734],{"class":510},[500,1864,1282],{"class":580},[500,1866,536],{"class":510},[500,1868,1869],{"class":965},"NewRouter",[500,1871,1772],{"class":510},[500,1873,1875,1878,1880,1883,1885,1888],{"class":502,"line":1874},25,[500,1876,1877],{"class":580},"        deps ",[500,1879,1734],{"class":510},[500,1881,1882],{"class":514}," shop",[500,1884,536],{"class":510},[500,1886,1887],{"class":514},"Dependencies",[500,1889,1890],{"class":510},"{\n",[500,1892,1894,1897,1899,1902,1904,1907,1909,1912],{"class":502,"line":1893},26,[500,1895,1896],{"class":580},"            DB",[500,1898,554],{"class":510},[500,1900,1901],{"class":580},"         pg",[500,1903,536],{"class":510},[500,1905,1906],{"class":965},"NewDB",[500,1908,1183],{"class":510},[500,1910,1911],{"class":580},"pool",[500,1913,1914],{"class":510},"),\n",[500,1916,1918,1921,1923,1925,1927,1930,1932,1934],{"class":502,"line":1917},27,[500,1919,1920],{"class":580},"            Transactor",[500,1922,554],{"class":510},[500,1924,1783],{"class":580},[500,1926,536],{"class":510},[500,1928,1929],{"class":965},"NewTransactor",[500,1931,1183],{"class":510},[500,1933,1911],{"class":580},[500,1935,1914],{"class":510},[500,1937,1939,1942,1944,1947,1949,1952,1954,1957,1959,1962,1964,1967,1969,1971,1973,1975],{"class":502,"line":1938},28,[500,1940,1941],{"class":580},"            Dispatcher",[500,1943,554],{"class":510},[500,1945,1946],{"class":580}," outbox",[500,1948,536],{"class":510},[500,1950,1951],{"class":965},"NewDispatcher",[500,1953,1183],{"class":510},[500,1955,1956],{"class":580},"outbox",[500,1958,536],{"class":510},[500,1960,1961],{"class":965},"NewStore",[500,1963,1183],{"class":510},[500,1965,1966],{"class":580},"pg",[500,1968,536],{"class":510},[500,1970,1906],{"class":965},[500,1972,1183],{"class":510},[500,1974,1911],{"class":580},[500,1976,1977],{"class":510},"))),\n",[500,1979,1981],{"class":502,"line":1980},29,[500,1982,1983],{"class":510},"        }\n",[500,1985,1987,1990,1992,1995,1997,2000,2002,2005],{"class":502,"line":1986},30,[500,1988,1989],{"class":580},"        shop",[500,1991,536],{"class":510},[500,1993,1994],{"class":965},"RegisterApi",[500,1996,1183],{"class":510},[500,1998,1999],{"class":580},"api",[500,2001,1197],{"class":510},[500,2003,2004],{"class":580}," deps",[500,2006,1708],{"class":510},[500,2008,2010,2012,2014,2017,2019,2021,2023,2025],{"class":502,"line":2009},31,[500,2011,1989],{"class":580},[500,2013,536],{"class":510},[500,2015,2016],{"class":965},"RegisterAdmin",[500,2018,1183],{"class":510},[500,2020,1999],{"class":580},[500,2022,1197],{"class":510},[500,2024,2004],{"class":580},[500,2026,1708],{"class":510},[500,2028,2030,2033,2035,2038,2040,2043,2046,2048,2050,2053],{"class":502,"line":2029},32,[500,2031,2032],{"class":580},"        r",[500,2034,536],{"class":510},[500,2036,2037],{"class":965},"Mount",[500,2039,1183],{"class":510},[500,2041,2042],{"class":510},"\"",[500,2044,2045],{"class":606},"\u002Fapi\u002Fv1",[500,2047,2042],{"class":510},[500,2049,1197],{"class":510},[500,2051,2052],{"class":580}," api",[500,2054,1708],{"class":510},[500,2056,2058,2061],{"class":502,"line":2057},33,[500,2059,2060],{"class":506},"        return",[500,2062,2063],{"class":510}," nil\n",[500,2065,2067,2070,2072,2074,2076,2078,2080,2083,2085,2087,2089,2091,2093,2095,2097,2099],{"class":502,"line":2066},34,[500,2068,2069],{"class":510},"    },",[500,2071,1819],{"class":580},[500,2073,536],{"class":510},[500,2075,1141],{"class":965},[500,2077,1183],{"class":510},[500,2079,2042],{"class":510},[500,2081,2082],{"class":606},"pgxpool",[500,2084,2042],{"class":510},[500,2086,1197],{"class":510},[500,2088,1276],{"class":510},[500,2090,1607],{"class":514},[500,2092,536],{"class":510},[500,2094,1194],{"class":514},[500,2096,962],{"class":510},[500,2098,1852],{"class":972},[500,2100,574],{"class":510},[500,2102,2104,2107,2109,2112],{"class":502,"line":2103},35,[500,2105,2106],{"class":580},"        pool",[500,2108,536],{"class":510},[500,2110,2111],{"class":965},"Close",[500,2113,1772],{"class":510},[500,2115,2117,2119],{"class":502,"line":2116},36,[500,2118,2060],{"class":506},[500,2120,2063],{"class":510},[500,2122,2124],{"class":502,"line":2123},37,[500,2125,2126],{"class":510},"    }))\n",[500,2128,2130,2133,2136,2139,2142],{"class":502,"line":2129},38,[500,2131,2132],{"class":506},"    if",[500,2134,2135],{"class":580}," err ",[500,2137,2138],{"class":510},"!=",[500,2140,2141],{"class":510}," nil",[500,2143,574],{"class":510},[500,2145,2147,2150,2152,2155,2157,2160],{"class":502,"line":2146},39,[500,2148,2149],{"class":580},"        log",[500,2151,536],{"class":510},[500,2153,2154],{"class":965},"Fatal",[500,2156,1183],{"class":510},[500,2158,2159],{"class":580},"err",[500,2161,1708],{"class":510},[500,2163,2165],{"class":502,"line":2164},40,[500,2166,2167],{"class":510},"    }\n",[500,2169,2171],{"class":502,"line":2170},41,[500,2172,623],{"class":510},[447,2174,2175,2176,2178,2179,536],{},"Prefixing happens with ",[450,2177,2037],{},": each module's surfaces register on a fresh subrouter, which gets mounted under ",[450,2180,2045],{},[871,2182,2184],{"id":2183},"options","Options",[491,2186,2188],{"className":493,"code":2187,"language":495,"meta":496,"style":496},"server.WithCloser(\"pgxpool\", func(ctx context.Context) error { pool.Close(); return nil })\nserver.WithMiddleware(myRateLimiter, myRequestID)          \u002F\u002F ...func(http.Handler) http.Handler\nserver.WithHTTPServer(func(s *http.Server) { s.MaxHeaderBytes = 1 \u003C\u003C 16 })\nserver.WithValidator(validate.New(validate.WithRegister(registerCustomTags)))\nserver.WithoutTelemetry()                                  \u002F\u002F tests \u002F external OTel setup\n",[450,2189,2190,2243,2267,2315,2349],{"__ignoreMap":496},[500,2191,2192,2194,2196,2198,2200,2202,2204,2206,2208,2210,2212,2214,2216,2218,2220,2222,2225,2228,2230,2232,2235,2238,2240],{"class":502,"line":503},[500,2193,452],{"class":580},[500,2195,536],{"class":510},[500,2197,1141],{"class":965},[500,2199,1183],{"class":510},[500,2201,2042],{"class":510},[500,2203,2082],{"class":606},[500,2205,2042],{"class":510},[500,2207,1197],{"class":510},[500,2209,1276],{"class":510},[500,2211,1186],{"class":956},[500,2213,1189],{"class":514},[500,2215,536],{"class":510},[500,2217,1194],{"class":514},[500,2219,962],{"class":510},[500,2221,1852],{"class":972},[500,2223,2224],{"class":510}," {",[500,2226,2227],{"class":580}," pool",[500,2229,536],{"class":510},[500,2231,2111],{"class":965},[500,2233,2234],{"class":510},"();",[500,2236,2237],{"class":506}," return",[500,2239,2141],{"class":510},[500,2241,2242],{"class":510}," })\n",[500,2244,2245,2247,2249,2252,2254,2257,2259,2262,2264],{"class":502,"line":577},[500,2246,452],{"class":580},[500,2248,536],{"class":510},[500,2250,2251],{"class":965},"WithMiddleware",[500,2253,1183],{"class":510},[500,2255,2256],{"class":580},"myRateLimiter",[500,2258,1197],{"class":510},[500,2260,2261],{"class":580}," myRequestID",[500,2263,962],{"class":510},[500,2265,2266],{"class":616},"          \u002F\u002F ...func(http.Handler) http.Handler\n",[500,2268,2269,2271,2273,2276,2279,2282,2284,2287,2289,2291,2293,2295,2298,2300,2303,2305,2308,2310,2313],{"class":502,"line":591},[500,2270,452],{"class":580},[500,2272,536],{"class":510},[500,2274,2275],{"class":965},"WithHTTPServer",[500,2277,2278],{"class":510},"(func(",[500,2280,2281],{"class":956},"s",[500,2283,1253],{"class":510},[500,2285,2286],{"class":514},"http",[500,2288,536],{"class":510},[500,2290,257],{"class":514},[500,2292,962],{"class":510},[500,2294,2224],{"class":510},[500,2296,2297],{"class":580}," s",[500,2299,536],{"class":510},[500,2301,2302],{"class":580},"MaxHeaderBytes ",[500,2304,926],{"class":510},[500,2306,2307],{"class":929}," 1",[500,2309,933],{"class":510},[500,2311,2312],{"class":929}," 16",[500,2314,2242],{"class":510},[500,2316,2317,2319,2321,2323,2325,2328,2330,2332,2334,2336,2338,2341,2343,2346],{"class":502,"line":613},[500,2318,452],{"class":580},[500,2320,536],{"class":510},[500,2322,1384],{"class":965},[500,2324,1183],{"class":510},[500,2326,2327],{"class":580},"validate",[500,2329,536],{"class":510},[500,2331,1321],{"class":965},[500,2333,1183],{"class":510},[500,2335,2327],{"class":580},[500,2337,536],{"class":510},[500,2339,2340],{"class":965},"WithRegister",[500,2342,1183],{"class":510},[500,2344,2345],{"class":580},"registerCustomTags",[500,2347,2348],{"class":510},")))\n",[500,2350,2351,2353,2355,2358,2360],{"class":502,"line":620},[500,2352,452],{"class":580},[500,2354,536],{"class":510},[500,2356,2357],{"class":965},"WithoutTelemetry",[500,2359,969],{"class":510},[500,2361,2362],{"class":616},"                                  \u002F\u002F tests \u002F external OTel setup\n",[879,2364,2365,2376,2388,2403,2418],{},[882,2366,2367,2372,2373,2375],{},[471,2368,2369],{},[450,2370,2371],{},"WithCloser(name, fn)",": cleanup during graceful shutdown, after the server has stopped accepting requests. Closers run in ",[471,2374,1145],{}," order; telemetry flushes last, so a span emitted in a closer still gets exported.",[882,2377,2378,2383,2384,2387],{},[471,2379,2380],{},[450,2381,2382],{},"WithMiddleware(...func(http.Handler) http.Handler)",": router-level middleware after the kit defaults. The standard net\u002Fhttp middleware shape: any ecosystem middleware fits here. Anything needed by a single surface only should go on that surface's ",[450,2385,2386],{},"Route"," instead (see below).",[882,2389,2390,2395,2396,2398,2399,2402],{},[471,2391,2392],{},[450,2393,2394],{},"WithHTTPServer(func(*http.Server))",": escape hatch for ",[450,2397,1304],{}," fields the kit does not expose (TLS, ",[450,2400,2401],{},"MaxHeaderBytes",", ...). You may also override the kit-set fields: your mutation runs last.",[882,2404,2405,2410,2411,1450,2415,2417],{},[471,2406,2407],{},[450,2408,2409],{},"WithValidator(*validate.Validator)",": the application-wide request validator, typically one carrying ",[455,2412,2414],{"href":2413},"\u002Fen\u002Fhttperr\u002Fvalidation#custom-tags","custom validation tags",[450,2416,1388],{}," middlewares resolve it at request time.",[882,2419,2420,2425,2426,2428],{},[471,2421,2422],{},[450,2423,2424],{},"WithoutTelemetry()",": skips ",[450,2427,1072],{}," and the OTel middleware; for tests, or when the process configures telemetry itself.",[538,2430,2432],{"id":2431},"registerfunc-and-strictvalidator","RegisterFunc and StrictValidator",[447,2434,2435,2439,2440,2443,2444,2447,2448,2450],{},[455,2436,2437],{"href":330},[450,2438,329],{}," splices one ",[450,2441,2442],{},"Register\u003CSurface>"," function per surface into the module's ",[450,2445,2446],{},"register.go",". For the shop's ",[450,2449,1999],{}," surface this is generated verbatim:",[491,2452,2455],{"className":493,"code":2453,"filename":2454,"language":495,"meta":496,"style":496},"func RegisterApi(router chi.Router, deps Dependencies) {\n    apiSvc := apiservice.New()\n    apiHandler := apihttp.New(apiSvc)\n    apiPolicies := apipolicy.New()\n    router.Route(\"\u002Fshop\", func(r chi.Router) {\n        shopapigen.HandlerWithOptions(shopapigen.NewStrictHandlerWithOptions(\n            apiHandler,\n            []shopapigen.StrictMiddlewareFunc{\n                server.StrictValidator[shopapigen.StrictHandlerFunc](nil),\n                \u002F\u002F Last = outermost: authorization runs before validation.\n                kitpolicy.Enforcer[shopapigen.StrictHandlerFunc](apiPolicies, shopapigen.PermissionByOperation, shopapigen.PolicyByOperation),\n            },\n            shopapigen.StrictHTTPServerOptions{\n                RequestErrorHandlerFunc:  httperr.WriteBadRequest,\n                ResponseErrorHandlerFunc: server.WriteError,\n            },\n        ), shopapigen.ChiServerOptions{\n            BaseRouter:       r,\n            ErrorHandlerFunc: httperr.WriteBadRequest,\n        })\n    })\n}\n","internal\u002Fmodules\u002Fshop\u002Fregister.go",[450,2456,2457,2486,2502,2523,2539,2573,2596,2604,2618,2640,2645,2690,2695,2707,2723,2738,2742,2756,2768,2784,2789,2794],{"__ignoreMap":496},[500,2458,2459,2461,2464,2466,2469,2471,2473,2475,2477,2479,2482,2484],{"class":502,"line":503},[500,2460,950],{"class":510},[500,2462,2463],{"class":965}," RegisterApi",[500,2465,1183],{"class":510},[500,2467,2468],{"class":956},"router",[500,2470,1282],{"class":514},[500,2472,536],{"class":510},[500,2474,1287],{"class":514},[500,2476,1197],{"class":510},[500,2478,2004],{"class":956},[500,2480,2481],{"class":514}," Dependencies",[500,2483,962],{"class":510},[500,2485,574],{"class":510},[500,2487,2488,2491,2493,2496,2498,2500],{"class":502,"line":577},[500,2489,2490],{"class":580},"    apiSvc ",[500,2492,1734],{"class":510},[500,2494,2495],{"class":580}," apiservice",[500,2497,536],{"class":510},[500,2499,1321],{"class":965},[500,2501,1772],{"class":510},[500,2503,2504,2507,2509,2512,2514,2516,2518,2521],{"class":502,"line":591},[500,2505,2506],{"class":580},"    apiHandler ",[500,2508,1734],{"class":510},[500,2510,2511],{"class":580}," apihttp",[500,2513,536],{"class":510},[500,2515,1321],{"class":965},[500,2517,1183],{"class":510},[500,2519,2520],{"class":580},"apiSvc",[500,2522,1708],{"class":510},[500,2524,2525,2528,2530,2533,2535,2537],{"class":502,"line":613},[500,2526,2527],{"class":580},"    apiPolicies ",[500,2529,1734],{"class":510},[500,2531,2532],{"class":580}," apipolicy",[500,2534,536],{"class":510},[500,2536,1321],{"class":965},[500,2538,1772],{"class":510},[500,2540,2541,2544,2546,2548,2550,2552,2555,2557,2559,2561,2563,2565,2567,2569,2571],{"class":502,"line":620},[500,2542,2543],{"class":580},"    router",[500,2545,536],{"class":510},[500,2547,2386],{"class":965},[500,2549,1183],{"class":510},[500,2551,2042],{"class":510},[500,2553,2554],{"class":606},"\u002Fshop",[500,2556,2042],{"class":510},[500,2558,1197],{"class":510},[500,2560,1276],{"class":510},[500,2562,1279],{"class":956},[500,2564,1282],{"class":514},[500,2566,536],{"class":510},[500,2568,1287],{"class":514},[500,2570,962],{"class":510},[500,2572,574],{"class":510},[500,2574,2575,2578,2580,2583,2585,2588,2590,2593],{"class":502,"line":1621},[500,2576,2577],{"class":580},"        shopapigen",[500,2579,536],{"class":510},[500,2581,2582],{"class":965},"HandlerWithOptions",[500,2584,1183],{"class":510},[500,2586,2587],{"class":580},"shopapigen",[500,2589,536],{"class":510},[500,2591,2592],{"class":965},"NewStrictHandlerWithOptions",[500,2594,2595],{"class":510},"(\n",[500,2597,2598,2601],{"class":502,"line":1626},[500,2599,2600],{"class":580},"            apiHandler",[500,2602,2603],{"class":510},",\n",[500,2605,2606,2609,2611,2613,2616],{"class":502,"line":1636},[500,2607,2608],{"class":510},"            []",[500,2610,2587],{"class":514},[500,2612,536],{"class":510},[500,2614,2615],{"class":514},"StrictMiddlewareFunc",[500,2617,1890],{"class":510},[500,2619,2620,2623,2625,2628,2630,2632,2634,2637],{"class":502,"line":1641},[500,2621,2622],{"class":580},"                server",[500,2624,536],{"class":510},[500,2626,2627],{"class":965},"StrictValidator",[500,2629,1745],{"class":510},[500,2631,2587],{"class":514},[500,2633,536],{"class":510},[500,2635,2636],{"class":514},"StrictHandlerFunc",[500,2638,2639],{"class":510},"](nil),\n",[500,2641,2642],{"class":502,"line":1651},[500,2643,2644],{"class":616},"                \u002F\u002F Last = outermost: authorization runs before validation.\n",[500,2646,2647,2650,2652,2655,2657,2659,2661,2663,2666,2669,2671,2674,2676,2679,2681,2683,2685,2688],{"class":502,"line":1661},[500,2648,2649],{"class":580},"                kitpolicy",[500,2651,536],{"class":510},[500,2653,2654],{"class":965},"Enforcer",[500,2656,1745],{"class":510},[500,2658,2587],{"class":514},[500,2660,536],{"class":510},[500,2662,2636],{"class":514},[500,2664,2665],{"class":510},"](",[500,2667,2668],{"class":580},"apiPolicies",[500,2670,1197],{"class":510},[500,2672,2673],{"class":580}," shopapigen",[500,2675,536],{"class":510},[500,2677,2678],{"class":580},"PermissionByOperation",[500,2680,1197],{"class":510},[500,2682,2673],{"class":580},[500,2684,536],{"class":510},[500,2686,2687],{"class":580},"PolicyByOperation",[500,2689,1914],{"class":510},[500,2691,2692],{"class":502,"line":1671},[500,2693,2694],{"class":510},"            },\n",[500,2696,2697,2700,2702,2705],{"class":502,"line":1680},[500,2698,2699],{"class":514},"            shopapigen",[500,2701,536],{"class":510},[500,2703,2704],{"class":514},"StrictHTTPServerOptions",[500,2706,1890],{"class":510},[500,2708,2709,2712,2714,2717,2719,2721],{"class":502,"line":1685},[500,2710,2711],{"class":580},"                RequestErrorHandlerFunc",[500,2713,554],{"class":510},[500,2715,2716],{"class":580},"  httperr",[500,2718,536],{"class":510},[500,2720,1539],{"class":580},[500,2722,2603],{"class":510},[500,2724,2725,2728,2730,2732,2734,2736],{"class":502,"line":1695},[500,2726,2727],{"class":580},"                ResponseErrorHandlerFunc",[500,2729,554],{"class":510},[500,2731,1819],{"class":580},[500,2733,536],{"class":510},[500,2735,1536],{"class":580},[500,2737,2603],{"class":510},[500,2739,2740],{"class":502,"line":1705},[500,2741,2694],{"class":510},[500,2743,2744,2747,2749,2751,2754],{"class":502,"line":1711},[500,2745,2746],{"class":510},"        ),",[500,2748,2673],{"class":514},[500,2750,536],{"class":510},[500,2752,2753],{"class":514},"ChiServerOptions",[500,2755,1890],{"class":510},[500,2757,2758,2761,2763,2766],{"class":502,"line":1716},[500,2759,2760],{"class":580},"            BaseRouter",[500,2762,554],{"class":510},[500,2764,2765],{"class":580},"       r",[500,2767,2603],{"class":510},[500,2769,2770,2773,2775,2778,2780,2782],{"class":502,"line":1728},[500,2771,2772],{"class":580},"            ErrorHandlerFunc",[500,2774,554],{"class":510},[500,2776,2777],{"class":580}," httperr",[500,2779,536],{"class":510},[500,2781,1539],{"class":580},[500,2783,2603],{"class":510},[500,2785,2786],{"class":502,"line":1757},[500,2787,2788],{"class":510},"        })\n",[500,2790,2791],{"class":502,"line":1775},[500,2792,2793],{"class":510},"    })\n",[500,2795,2796],{"class":502,"line":1806},[500,2797,623],{"class":510},[447,2799,2800],{},"Line by line:",[1104,2802,2803,2809,2827,2870],{},[882,2804,2805,2808],{},[471,2806,2807],{},"Service → handler → policy registry",": an explicit construction, no container involved.",[882,2810,2811,2816,2817,2819,2820,2823,2824,1329],{},[471,2812,2813],{},[450,2814,2815],{},"router.Route(\"\u002Fshop\", ...)",": the ",[450,2818,1999],{}," surface sits at the module root (",[450,2821,2822],{},"\u002Fapi\u002Fv1\u002Fshop\u002F...","); every other surface under its own prefix (",[450,2825,2826],{},"\u002Fadmin\u002Fshop",[882,2828,2829,2816,2833,2835,2836,1057,2839,2842,2843,2846,2847,2850,2851,2854,2855,696,2857,696,2860,2863,2864,2867,2868,536],{},[471,2830,2831],{},[450,2832,2592],{},[455,2834,524],{"href":234}," strict server, plus the error hooks: request-decoding failures (",[450,2837,2838],{},"RequestErrorHandlerFunc",[450,2840,2841],{},"ErrorHandlerFunc",") render as 400 via ",[450,2844,2845],{},"httperr.WriteBadRequest",", your handler's errors (",[450,2848,2849],{},"ResponseErrorHandlerFunc",") via ",[450,2852,2853],{},"server.WriteError",", which maps the ",[450,2856,82],{},[450,2858,2859],{},"rbac",[450,2861,2862],{},"policy"," sentinels onto Problems and delegates everything else to ",[450,2865,2866],{},"httperr.WriteError",", through the ",[455,2869,1543],{"href":395},[882,2871,2872,2879,2880,2883],{},[471,2873,2874,1305,2876],{},[450,2875,1563],{},[450,2877,2878],{},"kitpolicy.Enforcer",": validation and ",[455,2881,2882],{"href":99},"policy enforcement"," as strict middleware; the last element of the slice wraps outermost, so the enforcer runs before the validator.",[871,2885,2887],{"id":2886},"strictvalidator-validation-before-the-handler","StrictValidator: validation before the handler",[491,2889,2891],{"className":493,"code":2890,"language":495,"meta":496,"style":496},"func StrictValidator[H ~func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)](\n    v *validate.Validator,\n) func(f H, operationID string) H\n",[450,2892,2893,2965,2981],{"__ignoreMap":496},[500,2894,2895,2897,2900,2902,2905,2908,2910,2912,2914,2916,2918,2921,2924,2926,2929,2931,2934,2936,2938,2940,2943,2945,2948,2951,2953,2955,2958,2960,2962],{"class":502,"line":503},[500,2896,950],{"class":510},[500,2898,2899],{"class":965}," StrictValidator",[500,2901,1745],{"class":510},[500,2903,2904],{"class":956},"H",[500,2906,2907],{"class":510}," ~func(",[500,2909,1186],{"class":956},[500,2911,1189],{"class":514},[500,2913,536],{"class":510},[500,2915,1194],{"class":514},[500,2917,1197],{"class":510},[500,2919,2920],{"class":956}," w",[500,2922,2923],{"class":514}," http",[500,2925,536],{"class":510},[500,2927,2928],{"class":514},"ResponseWriter",[500,2930,1197],{"class":510},[500,2932,2933],{"class":956}," r",[500,2935,1253],{"class":510},[500,2937,2286],{"class":514},[500,2939,536],{"class":510},[500,2941,2942],{"class":514},"Request",[500,2944,1197],{"class":510},[500,2946,2947],{"class":956}," request",[500,2949,2950],{"class":514}," any",[500,2952,962],{"class":510},[500,2954,953],{"class":510},[500,2956,2957],{"class":514},"any",[500,2959,1197],{"class":510},[500,2961,1852],{"class":972},[500,2963,2964],{"class":510},")](\n",[500,2966,2967,2970,2972,2974,2976,2979],{"class":502,"line":577},[500,2968,2969],{"class":956},"    v",[500,2971,1253],{"class":510},[500,2973,2327],{"class":514},[500,2975,536],{"class":510},[500,2977,2978],{"class":514},"Validator",[500,2980,2603],{"class":510},[500,2982,2983,2985,2987,2990,2993,2995,2998,3001,3003],{"class":502,"line":591},[500,2984,962],{"class":510},[500,2986,1276],{"class":510},[500,2988,2989],{"class":956},"f",[500,2991,2992],{"class":514}," H",[500,2994,1197],{"class":510},[500,2996,2997],{"class":956}," operationID",[500,2999,3000],{"class":972}," string",[500,3002,962],{"class":510},[500,3004,3005],{"class":514}," H\n",[447,3007,3008,3009,3011,3012,3014,3015,3017,3018,3020],{},"The strict server decodes with ",[450,3010,1559],{},", without validation. ",[450,3013,2627],{}," closes that gap: it validates the fully bound request object (parameters + body) with the kit validator before your handler runs; a failure surfaces as a 422 problem through ",[450,3016,2849],{},". The type parameter exists because oapi-codegen defines ",[450,3019,2636],{}," per generated package.",[447,3022,3023,3024,3027,3028,3031,3032,3035,3036,3038,3039,3041,3042,3045],{},"The validator is resolved per request, in this order: the explicit ",[450,3025,3026],{},"v"," argument → the one set via ",[450,3029,3030],{},"server.WithValidator"," (from the context) → ",[450,3033,3034],{},"validate.New()",". That's why the generated code passes ",[450,3037,1317],{},": a single ",[450,3040,1384],{}," option in ",[450,3043,3044],{},"main.go"," applies application-wide, and the generated files need no edits.",[538,3047,3049],{"id":3048},"surface-middleware","Surface middleware",[447,3051,3052,3053,3055,3056,3058,3059,3061,3062,1021,3065,554],{},"Router-level middleware comes from ",[450,3054,2251],{},"; anything scoped to one surface (like the JWT protection of the shop's admin surface) you wire inside the surface's ",[450,3057,2386],{}," block with the kit's ",[450,3060,464],{}," auth middleware pair, ",[450,3063,3064],{},"server.AuthMiddleware",[450,3066,3067],{},"server.RequireRole",[491,3069,3071],{"className":493,"code":3070,"filename":2454,"language":495,"meta":496,"style":496},"import (\n    \"github.com\u002Fgp-system\u002Fauth\"\n    \u002F\u002F ...\n)\n\ntype Dependencies struct {\n    DB         *pg.DB\n    Transactor dbx.Transactor\n    Auth       auth.Config \u002F\u002F JWT_SECRET, JWT_ISSUER, ..., from the platform config\n    \u002F\u002F gpsystem:dependencies\n}\n\nfunc RegisterAdmin(router chi.Router, deps Dependencies) {\n    adminSvc := adminservice.New()\n    adminHandler := adminhttp.New(adminSvc)\n    adminPolicies := adminpolicy.New()\n    router.Route(\"\u002Fadmin\u002Fshop\", func(r chi.Router) {\n        r.Use(server.AuthMiddleware(deps.Auth), server.RequireRole(\"admin\"))\n        shopadmingen.HandlerWithOptions(shopadmingen.NewStrictHandlerWithOptions(\n            adminHandler,\n            []shopadmingen.StrictMiddlewareFunc{\n                server.StrictValidator[shopadmingen.StrictHandlerFunc](nil),\n                kitpolicy.Enforcer[shopadmingen.StrictHandlerFunc](adminPolicies, shopadmingen.PermissionByOperation, shopadmingen.PolicyByOperation),\n            },\n            shopadmingen.StrictHTTPServerOptions{\n                RequestErrorHandlerFunc:  httperr.WriteBadRequest,\n                ResponseErrorHandlerFunc: server.WriteError,\n            },\n        ), shopadmingen.ChiServerOptions{\n            BaseRouter:       r,\n            ErrorHandlerFunc: httperr.WriteBadRequest,\n        })\n    })\n}\n",[450,3072,3073,3079,3088,3092,3096,3100,3110,3124,3136,3150,3155,3159,3163,3190,3206,3227,3243,3275,3325,3345,3352,3364,3382,3422,3426,3437,3451,3465,3469,3481,3491,3505,3509,3513],{"__ignoreMap":496},[500,3074,3075,3077],{"class":502,"line":503},[500,3076,507],{"class":506},[500,3078,1599],{"class":510},[500,3080,3081,3083,3086],{"class":502,"line":577},[500,3082,1604],{"class":510},[500,3084,3085],{"class":514},"github.com\u002Fgp-system\u002Fauth",[500,3087,518],{"class":510},[500,3089,3090],{"class":502,"line":591},[500,3091,617],{"class":616},[500,3093,3094],{"class":502,"line":613},[500,3095,1708],{"class":510},[500,3097,3098],{"class":502,"line":620},[500,3099,945],{"emptyLinePlaceholder":944},[500,3101,3102,3104,3106,3108],{"class":502,"line":1621},[500,3103,565],{"class":510},[500,3105,2481],{"class":514},[500,3107,571],{"class":510},[500,3109,574],{"class":510},[500,3111,3112,3115,3117,3119,3121],{"class":502,"line":1626},[500,3113,3114],{"class":580},"    DB         ",[500,3116,797],{"class":510},[500,3118,1966],{"class":514},[500,3120,536],{"class":510},[500,3122,3123],{"class":514},"DB\n",[500,3125,3126,3129,3131,3133],{"class":502,"line":1636},[500,3127,3128],{"class":580},"    Transactor ",[500,3130,404],{"class":514},[500,3132,536],{"class":510},[500,3134,3135],{"class":514},"Transactor\n",[500,3137,3138,3141,3143,3145,3147],{"class":502,"line":1641},[500,3139,3140],{"class":580},"    Auth       ",[500,3142,82],{"class":514},[500,3144,536],{"class":510},[500,3146,541],{"class":514},[500,3148,3149],{"class":616}," \u002F\u002F JWT_SECRET, JWT_ISSUER, ..., from the platform config\n",[500,3151,3152],{"class":502,"line":1651},[500,3153,3154],{"class":616},"    \u002F\u002F gpsystem:dependencies\n",[500,3156,3157],{"class":502,"line":1661},[500,3158,623],{"class":510},[500,3160,3161],{"class":502,"line":1671},[500,3162,945],{"emptyLinePlaceholder":944},[500,3164,3165,3167,3170,3172,3174,3176,3178,3180,3182,3184,3186,3188],{"class":502,"line":1680},[500,3166,950],{"class":510},[500,3168,3169],{"class":965}," RegisterAdmin",[500,3171,1183],{"class":510},[500,3173,2468],{"class":956},[500,3175,1282],{"class":514},[500,3177,536],{"class":510},[500,3179,1287],{"class":514},[500,3181,1197],{"class":510},[500,3183,2004],{"class":956},[500,3185,2481],{"class":514},[500,3187,962],{"class":510},[500,3189,574],{"class":510},[500,3191,3192,3195,3197,3200,3202,3204],{"class":502,"line":1685},[500,3193,3194],{"class":580},"    adminSvc ",[500,3196,1734],{"class":510},[500,3198,3199],{"class":580}," adminservice",[500,3201,536],{"class":510},[500,3203,1321],{"class":965},[500,3205,1772],{"class":510},[500,3207,3208,3211,3213,3216,3218,3220,3222,3225],{"class":502,"line":1695},[500,3209,3210],{"class":580},"    adminHandler ",[500,3212,1734],{"class":510},[500,3214,3215],{"class":580}," adminhttp",[500,3217,536],{"class":510},[500,3219,1321],{"class":965},[500,3221,1183],{"class":510},[500,3223,3224],{"class":580},"adminSvc",[500,3226,1708],{"class":510},[500,3228,3229,3232,3234,3237,3239,3241],{"class":502,"line":1705},[500,3230,3231],{"class":580},"    adminPolicies ",[500,3233,1734],{"class":510},[500,3235,3236],{"class":580}," adminpolicy",[500,3238,536],{"class":510},[500,3240,1321],{"class":965},[500,3242,1772],{"class":510},[500,3244,3245,3247,3249,3251,3253,3255,3257,3259,3261,3263,3265,3267,3269,3271,3273],{"class":502,"line":1711},[500,3246,2543],{"class":580},[500,3248,536],{"class":510},[500,3250,2386],{"class":965},[500,3252,1183],{"class":510},[500,3254,2042],{"class":510},[500,3256,2826],{"class":606},[500,3258,2042],{"class":510},[500,3260,1197],{"class":510},[500,3262,1276],{"class":510},[500,3264,1279],{"class":956},[500,3266,1282],{"class":514},[500,3268,536],{"class":510},[500,3270,1287],{"class":514},[500,3272,962],{"class":510},[500,3274,574],{"class":510},[500,3276,3277,3279,3281,3284,3286,3288,3290,3293,3295,3298,3300,3303,3306,3308,3310,3313,3315,3317,3320,3322],{"class":502,"line":1716},[500,3278,2032],{"class":580},[500,3280,536],{"class":510},[500,3282,3283],{"class":965},"Use",[500,3285,1183],{"class":510},[500,3287,452],{"class":580},[500,3289,536],{"class":510},[500,3291,3292],{"class":965},"AuthMiddleware",[500,3294,1183],{"class":510},[500,3296,3297],{"class":580},"deps",[500,3299,536],{"class":510},[500,3301,3302],{"class":580},"Auth",[500,3304,3305],{"class":510},"),",[500,3307,1819],{"class":580},[500,3309,536],{"class":510},[500,3311,3312],{"class":965},"RequireRole",[500,3314,1183],{"class":510},[500,3316,2042],{"class":510},[500,3318,3319],{"class":606},"admin",[500,3321,2042],{"class":510},[500,3323,3324],{"class":510},"))\n",[500,3326,3327,3330,3332,3334,3336,3339,3341,3343],{"class":502,"line":1728},[500,3328,3329],{"class":580},"        shopadmingen",[500,3331,536],{"class":510},[500,3333,2582],{"class":965},[500,3335,1183],{"class":510},[500,3337,3338],{"class":580},"shopadmingen",[500,3340,536],{"class":510},[500,3342,2592],{"class":965},[500,3344,2595],{"class":510},[500,3346,3347,3350],{"class":502,"line":1757},[500,3348,3349],{"class":580},"            adminHandler",[500,3351,2603],{"class":510},[500,3353,3354,3356,3358,3360,3362],{"class":502,"line":1775},[500,3355,2608],{"class":510},[500,3357,3338],{"class":514},[500,3359,536],{"class":510},[500,3361,2615],{"class":514},[500,3363,1890],{"class":510},[500,3365,3366,3368,3370,3372,3374,3376,3378,3380],{"class":502,"line":1806},[500,3367,2622],{"class":580},[500,3369,536],{"class":510},[500,3371,2627],{"class":965},[500,3373,1745],{"class":510},[500,3375,3338],{"class":514},[500,3377,536],{"class":510},[500,3379,2636],{"class":514},[500,3381,2639],{"class":510},[500,3383,3384,3386,3388,3390,3392,3394,3396,3398,3400,3403,3405,3408,3410,3412,3414,3416,3418,3420],{"class":502,"line":1811},[500,3385,2649],{"class":580},[500,3387,536],{"class":510},[500,3389,2654],{"class":965},[500,3391,1745],{"class":510},[500,3393,3338],{"class":514},[500,3395,536],{"class":510},[500,3397,2636],{"class":514},[500,3399,2665],{"class":510},[500,3401,3402],{"class":580},"adminPolicies",[500,3404,1197],{"class":510},[500,3406,3407],{"class":580}," shopadmingen",[500,3409,536],{"class":510},[500,3411,2678],{"class":580},[500,3413,1197],{"class":510},[500,3415,3407],{"class":580},[500,3417,536],{"class":510},[500,3419,2687],{"class":580},[500,3421,1914],{"class":510},[500,3423,3424],{"class":502,"line":1857},[500,3425,2694],{"class":510},[500,3427,3428,3431,3433,3435],{"class":502,"line":1874},[500,3429,3430],{"class":514},"            shopadmingen",[500,3432,536],{"class":510},[500,3434,2704],{"class":514},[500,3436,1890],{"class":510},[500,3438,3439,3441,3443,3445,3447,3449],{"class":502,"line":1893},[500,3440,2711],{"class":580},[500,3442,554],{"class":510},[500,3444,2716],{"class":580},[500,3446,536],{"class":510},[500,3448,1539],{"class":580},[500,3450,2603],{"class":510},[500,3452,3453,3455,3457,3459,3461,3463],{"class":502,"line":1917},[500,3454,2727],{"class":580},[500,3456,554],{"class":510},[500,3458,1819],{"class":580},[500,3460,536],{"class":510},[500,3462,1536],{"class":580},[500,3464,2603],{"class":510},[500,3466,3467],{"class":502,"line":1938},[500,3468,2694],{"class":510},[500,3470,3471,3473,3475,3477,3479],{"class":502,"line":1980},[500,3472,2746],{"class":510},[500,3474,3407],{"class":514},[500,3476,536],{"class":510},[500,3478,2753],{"class":514},[500,3480,1890],{"class":510},[500,3482,3483,3485,3487,3489],{"class":502,"line":1986},[500,3484,2760],{"class":580},[500,3486,554],{"class":510},[500,3488,2765],{"class":580},[500,3490,2603],{"class":510},[500,3492,3493,3495,3497,3499,3501,3503],{"class":502,"line":2009},[500,3494,2772],{"class":580},[500,3496,554],{"class":510},[500,3498,2777],{"class":580},[500,3500,536],{"class":510},[500,3502,1539],{"class":580},[500,3504,2603],{"class":510},[500,3506,3507],{"class":502,"line":2029},[500,3508,2788],{"class":510},[500,3510,3511],{"class":502,"line":2057},[500,3512,2793],{"class":510},[500,3514,3515],{"class":502,"line":2066},[500,3516,623],{"class":510},[447,3518,3519,3523,3524,3527,3528,3531,3532,3537,3538,3541,3542,3544],{},[455,3520,3521],{"href":89},[450,3522,3064],{}," parses the ",[450,3525,3526],{},"Bearer"," token and puts an ",[450,3529,3530],{},"rbac.Identity"," into the context; ",[455,3533,3534],{"href":94},[450,3535,3536],{},"server.RequireRole(\"admin\")"," short-circuits with a 403 problem without that role. Every ",[450,3539,3540],{},"\u002Fapi\u002Fv1\u002Fadmin\u002Fshop\u002F..."," route is protected. The ",[450,3543,1999],{}," surface's public routes are untouched.",[3546,3547,3548,3549,3552,3553,1450,3556,3559,3560,3563,3564,3566,3567,3570,3571,696,3574,3577],"tip",{},"Rule of thumb for middleware levels: ",[471,3550,3551],{},"process-level"," (rate limit, request ID) → ",[450,3554,3555],{},"server.WithMiddleware",[471,3557,3558],{},"surface-level"," (auth, role) → ",[450,3561,3562],{},"r.Use"," in the surface's ",[450,3565,2386],{}," block; ",[471,3568,3569],{},"operation-level"," (permission, ownership check) → ",[450,3572,3573],{},"@permission",[450,3575,3576],{},"@policy"," in the spec, enforced by the enforcer.",[538,3579,169],{"id":3580},"testing",[447,3582,3583,3585,3586,554],{},[450,3584,1321],{}," returns the fully wired router; you test with plain ",[450,3587,3588],{},"net\u002Fhttp\u002Fhttptest",[491,3590,3592],{"className":493,"code":3591,"language":495,"meta":496,"style":496},"r := server.New(server.Config{}, server.WithoutTelemetry())\nr.Post(\"\u002Fthings\", createThing)\n\nsrv := httptest.NewServer(r)\ndefer srv.Close()\nresp, err := http.Post(srv.URL+\"\u002Fthings\", \"application\u002Fjson\", body)\n",[450,3593,3594,3627,3652,3656,3677,3691],{"__ignoreMap":496},[500,3595,3596,3599,3601,3603,3605,3607,3609,3611,3613,3615,3618,3620,3622,3624],{"class":502,"line":503},[500,3597,3598],{"class":580},"r ",[500,3600,1734],{"class":510},[500,3602,1819],{"class":580},[500,3604,536],{"class":510},[500,3606,1321],{"class":965},[500,3608,1183],{"class":510},[500,3610,452],{"class":514},[500,3612,536],{"class":510},[500,3614,541],{"class":514},[500,3616,3617],{"class":510},"{},",[500,3619,1819],{"class":580},[500,3621,536],{"class":510},[500,3623,2357],{"class":965},[500,3625,3626],{"class":510},"())\n",[500,3628,3629,3631,3633,3636,3638,3640,3643,3645,3647,3650],{"class":502,"line":577},[500,3630,1279],{"class":580},[500,3632,536],{"class":510},[500,3634,3635],{"class":965},"Post",[500,3637,1183],{"class":510},[500,3639,2042],{"class":510},[500,3641,3642],{"class":606},"\u002Fthings",[500,3644,2042],{"class":510},[500,3646,1197],{"class":510},[500,3648,3649],{"class":580}," createThing",[500,3651,1708],{"class":510},[500,3653,3654],{"class":502,"line":591},[500,3655,945],{"emptyLinePlaceholder":944},[500,3657,3658,3661,3663,3666,3668,3671,3673,3675],{"class":502,"line":613},[500,3659,3660],{"class":580},"srv ",[500,3662,1734],{"class":510},[500,3664,3665],{"class":580}," httptest",[500,3667,536],{"class":510},[500,3669,3670],{"class":965},"NewServer",[500,3672,1183],{"class":510},[500,3674,1279],{"class":580},[500,3676,1708],{"class":510},[500,3678,3679,3682,3685,3687,3689],{"class":502,"line":620},[500,3680,3681],{"class":506},"defer",[500,3683,3684],{"class":580}," srv",[500,3686,536],{"class":510},[500,3688,2111],{"class":965},[500,3690,1772],{"class":510},[500,3692,3693,3696,3698,3700,3702,3704,3706,3708,3710,3713,3715,3718,3721,3723,3725,3727,3729,3731,3734,3736,3738,3741],{"class":502,"line":1621},[500,3694,3695],{"class":580},"resp",[500,3697,1197],{"class":510},[500,3699,2135],{"class":580},[500,3701,1734],{"class":510},[500,3703,2923],{"class":580},[500,3705,536],{"class":510},[500,3707,3635],{"class":965},[500,3709,1183],{"class":510},[500,3711,3712],{"class":580},"srv",[500,3714,536],{"class":510},[500,3716,3717],{"class":580},"URL",[500,3719,3720],{"class":510},"+",[500,3722,2042],{"class":510},[500,3724,3642],{"class":606},[500,3726,2042],{"class":510},[500,3728,1197],{"class":510},[500,3730,511],{"class":510},[500,3732,3733],{"class":606},"application\u002Fjson",[500,3735,2042],{"class":510},[500,3737,1197],{"class":510},[500,3739,3740],{"class":580}," body",[500,3742,1708],{"class":510},[447,3744,3745],{},"The panic recoverer, the 404\u002F405 problem handlers and the body limit are active here too, so the test sees exactly the problem+json response the client will.",[538,3747,3749],{"id":3748},"patterns-used","Patterns used",[879,3751,3752,3767],{},[882,3753,3754,953,3757,696,3760,3763,3764,536],{},[471,3755,3756],{},"Context-injected validator",[450,3758,3759],{},"injectValidator",[450,3761,3762],{},"validatorFromContext",", with an unexported context key): ",[455,3765,238],{"href":3766},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#context-injected-dependency",[882,3768,3769,953,3772,3775,3776,3778,3779,536],{},[471,3770,3771],{},"Generic middleware adapter",[450,3773,3774],{},"StrictValidator[H ~func(...)]",", fitting every generated ",[450,3777,2636],{},"): ",[455,3780,238],{"href":3781},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#generic-middleware-adapter",[538,3783,3785],{"id":3784},"related-pages","Related pages",[879,3787,3788,3800,3805,3810],{},[882,3789,3790,3792,3793,3796,3797,3799],{},[455,3791,252],{"href":253},": the shared ",[450,3794,3795],{},"app.Run"," skeleton ",[450,3798,531],{}," builds on.",[882,3801,3802,3804],{},[455,3803,394],{"href":395},": the full error-mapping table.",[882,3806,3807,3809],{},[455,3808,399],{"href":400},": custom validation tags.",[882,3811,3812,3814],{},[455,3813,98],{"href":99},": the enforcer used above.",[3816,3817,3818],"style",{},"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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":496,"searchDepth":577,"depth":577,"links":3820},[3821,3827,3828,3831,3834,3837,3838,3839,3840],{"id":540,"depth":577,"text":541,"children":3822},[3823,3824,3825,3826],{"id":873,"depth":591,"text":874},{"id":909,"depth":591,"text":910},{"id":1001,"depth":591,"text":833},{"id":1039,"depth":591,"text":1040},{"id":1079,"depth":577,"text":1080},{"id":1167,"depth":577,"text":1168,"children":3829},[3830],{"id":1515,"depth":591,"text":1516},{"id":1567,"depth":577,"text":1568,"children":3832},[3833],{"id":2183,"depth":591,"text":2184},{"id":2431,"depth":577,"text":2432,"children":3835},[3836],{"id":2886,"depth":591,"text":2887},{"id":3048,"depth":577,"text":3049},{"id":3580,"depth":577,"text":169},{"id":3748,"depth":577,"text":3749},{"id":3784,"depth":577,"text":3785},"The chi-based HTTP chassis: Config (timeouts, CORS, body limit), the shared lifecycle, and how server.Run wires a router.","md",null,{},{"icon":260},{"title":257,"description":3841},"SJxWv926vAI6ksjBSphhX8RO-F-wAY4DCSw_kg-j3k4",[3849,3851],{"title":252,"path":253,"stem":254,"description":3850,"icon":255,"children":-1},"The app package: the signal-driven graceful shutdown every gpsystem binary sits on.",{"title":262,"path":263,"stem":264,"description":3852,"icon":265,"children":-1},"The background-work chassis, asynq server, outbox relay and schedule runner in one binary, under a shared graceful shutdown.",1785445893630]