[{"data":1,"prerenderedAt":2636},["ShallowReactive",2],{"navigation_docs_en":3,"-en-http-fiber":342,"-en-http-fiber-surround":2631},[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":108,"body":344,"description":2624,"extension":2625,"links":2626,"meta":2627,"navigation":2628,"path":109,"seo":2629,"stem":110,"__hash__":2630},"docs_en\u002Fen\u002F3.http\u002F2.fiber.md",{"type":345,"value":346,"toc":2614},"minimark",[347,380,409,414,561,594,598,605,759,792,796,802,1394,1403,1407,1585,1644,1648,1666,1890,1893,1964,1968,1984,2343,2372,2402,2416,2420,2428,2548,2551,2555,2589,2598,2601,2610],[348,349,350,354,355,358,359,363,364,367,368,372,373,375,376,379],"p",{},[351,352,353],"code",{},"server\u002Ffiberx"," is the kit's Fiber v3 engine: it builds a ",[351,356,357],{},"*fiber.App"," with the kit defaults (RFC 9457 error handler, bind-time validation, panic recovery, OTel middleware, CORS) and runs it with the ",[360,361,362],"a",{"href":74},"shared lifecycle",". The ",[360,365,366],{"href":12},"\"centralize, don't abstract\""," principle means: your register function receives a ",[369,370,371],"strong",{},"native"," ",[351,374,357],{},", your handlers a native ",[351,377,378],{},"fiber.Ctx",". Fiber's documentation and every Stack Overflow answer stay valid for you.",[381,382,387],"pre",{"className":383,"code":384,"language":385,"meta":386,"style":386},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fgpsystem\u002Fserver\u002Ffiberx\"\n","go","",[351,388,389],{"__ignoreMap":386},[390,391,394,398,402,406],"span",{"class":392,"line":393},"line",1,[390,395,397],{"class":396},"s7zQu","import",[390,399,401],{"class":400},"sMK4o"," \"",[390,403,405],{"class":404},"sBMFI","github.com\u002Fgp-system\u002Fgpsystem\u002Fserver\u002Ffiberx",[390,407,408],{"class":400},"\"\n",[410,411,413],"h2",{"id":412},"api","API",[381,415,417],{"className":383,"code":416,"language":385,"meta":386,"style":386},"func Run(ctx context.Context, cfg server.Config, register RegisterFunc, opts ...Option) error\nfunc New(cfg server.Config, opts ...Option) *fiber.App \u002F\u002F for tests and special cases\n\ntype RegisterFunc func(app *fiber.App) error\n",[351,418,419,484,528,535],{"__ignoreMap":386},[390,420,421,424,428,431,435,438,441,444,447,450,453,455,458,460,463,466,468,471,474,477,480],{"class":392,"line":393},[390,422,423],{"class":400},"func",[390,425,427],{"class":426},"s2Zo4"," Run",[390,429,430],{"class":400},"(",[390,432,434],{"class":433},"sHdIc","ctx",[390,436,437],{"class":404}," context",[390,439,440],{"class":400},".",[390,442,443],{"class":404},"Context",[390,445,446],{"class":400},",",[390,448,449],{"class":433}," cfg",[390,451,452],{"class":404}," server",[390,454,440],{"class":400},[390,456,457],{"class":404},"Config",[390,459,446],{"class":400},[390,461,462],{"class":433}," register",[390,464,465],{"class":404}," RegisterFunc",[390,467,446],{"class":400},[390,469,470],{"class":433}," opts",[390,472,473],{"class":400}," ...",[390,475,476],{"class":404},"Option",[390,478,479],{"class":400},")",[390,481,483],{"class":482},"spNyl"," error\n",[390,485,487,489,492,494,497,499,501,503,505,507,509,511,513,516,519,521,524],{"class":392,"line":486},2,[390,488,423],{"class":400},[390,490,491],{"class":426}," New",[390,493,430],{"class":400},[390,495,496],{"class":433},"cfg",[390,498,452],{"class":404},[390,500,440],{"class":400},[390,502,457],{"class":404},[390,504,446],{"class":400},[390,506,470],{"class":433},[390,508,473],{"class":400},[390,510,476],{"class":404},[390,512,479],{"class":400},[390,514,515],{"class":400}," *",[390,517,518],{"class":404},"fiber",[390,520,440],{"class":400},[390,522,523],{"class":404},"App",[390,525,527],{"class":526},"sHwdD"," \u002F\u002F for tests and special cases\n",[390,529,531],{"class":392,"line":530},3,[390,532,534],{"emptyLinePlaceholder":533},true,"\n",[390,536,538,541,543,546,549,551,553,555,557,559],{"class":392,"line":537},4,[390,539,540],{"class":400},"type",[390,542,465],{"class":404},[390,544,545],{"class":400}," func(",[390,547,548],{"class":433},"app",[390,550,515],{"class":400},[390,552,518],{"class":404},[390,554,440],{"class":400},[390,556,523],{"class":404},[390,558,479],{"class":400},[390,560,483],{"class":482},[348,562,563,566,567,570,571,574,575,578,579,582,583,586,587,590,591,440],{},[351,564,565],{},"Run"," blocks until exit: telemetry bootstrap → app construction → ",[351,568,569],{},"register(app)"," → ",[351,572,573],{},"Listen"," → graceful shutdown on ",[351,576,577],{},"SIGINT","\u002F",[351,580,581],{},"SIGTERM",". It returns ",[351,584,585],{},"nil"," on clean shutdown. ",[351,588,589],{},"New"," returns the same fully wired app without running it or bootstrapping telemetry: in tests you pair it with Fiber's ",[351,592,593],{},"app.Test",[410,595,597],{"id":596},"what-run-wires","What Run wires",[348,599,600,601,604],{},"The following go into ",[351,602,603],{},"fiber.Config"," and the middleware chain, in this order:",[606,607,608,624],"table",{},[609,610,611],"thead",{},[612,613,614,618,621],"tr",{},[615,616,617],"th",{},"What",[615,619,620],{},"From",[615,622,623],{},"What it does",[625,626,627,645,666,685,700,713,730],"tbody",{},[612,628,629,635,642],{},[630,631,632],"td",{},[351,633,634],{},"ErrorHandler",[630,636,637],{},[360,638,639],{"href":119},[351,640,641],{},"httperr.NewErrorHandler",[630,643,644],{},"renders every handler error as problem+json; logs 5xx causes",[612,646,647,652,659],{},[630,648,649],{},[351,650,651],{},"StructValidator",[630,653,654],{},[360,655,656],{"href":124},[351,657,658],{},"validate.New()",[630,660,661,662,665],{},"every ",[351,663,664],{},"c.Bind().Body(&dto)"," validates automatically (including generated binding)",[612,667,668,671,674],{},[630,669,670],{},"recover middleware",[630,672,673],{},"kit",[630,675,676,677,680,681,684],{},"a panic becomes an ",[351,678,679],{},"errs"," error whose stack points at the ",[369,682,683],{},"panic site"," (Fiber's built-in recover would discard it); from there it flows down the normal error path",[612,686,687,690,695],{},[630,688,689],{},"OTel middleware",[630,691,692],{},[351,693,694],{},"gofiber\u002Fcontrib\u002Fotel",[630,696,697,698],{},"per-request server span + HTTP metrics: ",[360,699,232],{"href":233},[612,701,702,705,707],{},[630,703,704],{},"Sentry request hub",[630,706,673],{},[630,708,709,710,712],{},"an isolated Sentry hub per request, so breadcrumbs never mix across requests; no-op when ",[360,711,237],{"href":238}," is off",[612,714,715,718,723],{},[630,716,717],{},"dev logger",[630,719,720],{},[351,721,722],{},"fiber\u002Fmiddleware\u002Flogger",[630,724,725,726,729],{},"only with ",[351,727,728],{},"OTEL_DEV_MODE=true",": request log on the console",[612,731,732,735,740],{},[630,733,734],{},"CORS",[630,736,737],{},[351,738,739],{},"fiber\u002Fmiddleware\u002Fcors",[630,741,742,743,746,747,750,751,754,755,758],{},"from ",[351,744,745],{},"CORS_ORIGINS","; ",[351,748,749],{},"GET\u002FPOST\u002FPUT\u002FPATCH\u002FDELETE\u002FOPTIONS",", ",[351,752,753],{},"Content-Type"," + ",[351,756,757],{},"Authorization"," headers",[348,760,761,762,767,768,770,771,750,774,750,777,750,780,783,784,787,788,791],{},"The ",[360,763,764],{"href":104},[351,765,766],{},"server.Config"," timeouts and body limit translate into ",[351,769,603],{}," (",[351,772,773],{},"BodyLimit: cfg.EffectiveBodyLimit()",[351,775,776],{},"ReadTimeout",[351,778,779],{},"WriteTimeout",[351,781,782],{},"IdleTimeout","). Middleware added with ",[351,785,786],{},"WithMiddleware"," runs ",[369,789,790],{},"after"," the kit defaults and before route registration.",[410,793,795],{"id":794},"the-shop-entry-point","The shop entry point",[348,797,761,798,801],{},[360,799,800],{"href":41},"sample app's"," HTTP binary, every line of which was written by the generator:",[381,803,806],{"className":383,"code":804,"filename":805,"language":385,"meta":386,"style":386},"package main\n\nimport (\n    \"context\"\n    \"log\"\n\n    \"github.com\u002Fgofiber\u002Ffiber\u002Fv3\"\n\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fdbx\u002Fpg\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fenvconf\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fevents\u002Foutbox\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fserver\u002Ffiberx\"\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 := fiberx.Run(ctx, cfg.Server, func(app *fiber.App) error {\n        api := app.Group(\"\u002Fapi\u002Fv1\")\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        return nil\n    }, fiberx.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",[351,807,808,816,820,827,837,847,852,862,867,877,887,897,906,911,921,931,937,942,956,987,1005,1036,1041,1090,1119,1138,1163,1184,1226,1232,1254,1274,1283,1321,1334,1341,1347,1364,1382,1388],{"__ignoreMap":386},[390,809,810,813],{"class":392,"line":393},[390,811,812],{"class":400},"package",[390,814,815],{"class":404}," main\n",[390,817,818],{"class":392,"line":486},[390,819,534],{"emptyLinePlaceholder":533},[390,821,822,824],{"class":392,"line":530},[390,823,397],{"class":396},[390,825,826],{"class":400}," (\n",[390,828,829,832,835],{"class":392,"line":537},[390,830,831],{"class":400},"    \"",[390,833,834],{"class":404},"context",[390,836,408],{"class":400},[390,838,840,842,845],{"class":392,"line":839},5,[390,841,831],{"class":400},[390,843,844],{"class":404},"log",[390,846,408],{"class":400},[390,848,850],{"class":392,"line":849},6,[390,851,534],{"emptyLinePlaceholder":533},[390,853,855,857,860],{"class":392,"line":854},7,[390,856,831],{"class":400},[390,858,859],{"class":404},"github.com\u002Fgofiber\u002Ffiber\u002Fv3",[390,861,408],{"class":400},[390,863,865],{"class":392,"line":864},8,[390,866,534],{"emptyLinePlaceholder":533},[390,868,870,872,875],{"class":392,"line":869},9,[390,871,831],{"class":400},[390,873,874],{"class":404},"github.com\u002Fgp-system\u002Fgpsystem\u002Fdbx\u002Fpg",[390,876,408],{"class":400},[390,878,880,882,885],{"class":392,"line":879},10,[390,881,831],{"class":400},[390,883,884],{"class":404},"github.com\u002Fgp-system\u002Fgpsystem\u002Fenvconf",[390,886,408],{"class":400},[390,888,890,892,895],{"class":392,"line":889},11,[390,891,831],{"class":400},[390,893,894],{"class":404},"github.com\u002Fgp-system\u002Fgpsystem\u002Fevents\u002Foutbox",[390,896,408],{"class":400},[390,898,900,902,904],{"class":392,"line":899},12,[390,901,831],{"class":400},[390,903,405],{"class":404},[390,905,408],{"class":400},[390,907,909],{"class":392,"line":908},13,[390,910,534],{"emptyLinePlaceholder":533},[390,912,914,916,919],{"class":392,"line":913},14,[390,915,831],{"class":400},[390,917,918],{"class":404},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop",[390,920,408],{"class":400},[390,922,924,926,929],{"class":392,"line":923},15,[390,925,831],{"class":400},[390,927,928],{"class":404},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fplatform\u002Fconfig",[390,930,408],{"class":400},[390,932,934],{"class":392,"line":933},16,[390,935,936],{"class":400},")\n",[390,938,940],{"class":392,"line":939},17,[390,941,534],{"emptyLinePlaceholder":533},[390,943,945,947,950,953],{"class":392,"line":944},18,[390,946,423],{"class":400},[390,948,949],{"class":426}," main",[390,951,952],{"class":400},"()",[390,954,955],{"class":400}," {\n",[390,957,959,963,966,969,971,974,977,980,982,984],{"class":392,"line":958},19,[390,960,962],{"class":961},"sTEyZ","    cfg ",[390,964,965],{"class":400},":=",[390,967,968],{"class":961}," envconf",[390,970,440],{"class":400},[390,972,973],{"class":426},"MustLoad",[390,975,976],{"class":400},"[",[390,978,979],{"class":404},"config",[390,981,440],{"class":400},[390,983,457],{"class":404},[390,985,986],{"class":400},"]()\n",[390,988,990,993,995,997,999,1002],{"class":392,"line":989},20,[390,991,992],{"class":961},"    ctx ",[390,994,965],{"class":400},[390,996,437],{"class":961},[390,998,440],{"class":400},[390,1000,1001],{"class":426},"Background",[390,1003,1004],{"class":400},"()\n",[390,1006,1008,1011,1013,1016,1018,1021,1023,1025,1027,1029,1031,1034],{"class":392,"line":1007},21,[390,1009,1010],{"class":961},"    pool ",[390,1012,965],{"class":400},[390,1014,1015],{"class":961}," pg",[390,1017,440],{"class":400},[390,1019,1020],{"class":426},"MustNewPool",[390,1022,430],{"class":400},[390,1024,434],{"class":961},[390,1026,446],{"class":400},[390,1028,449],{"class":961},[390,1030,440],{"class":400},[390,1032,1033],{"class":961},"DB",[390,1035,936],{"class":400},[390,1037,1039],{"class":392,"line":1038},22,[390,1040,534],{"emptyLinePlaceholder":533},[390,1042,1044,1047,1049,1052,1054,1056,1058,1060,1062,1064,1066,1069,1071,1073,1075,1077,1079,1081,1083,1085,1088],{"class":392,"line":1043},23,[390,1045,1046],{"class":961},"    err ",[390,1048,965],{"class":400},[390,1050,1051],{"class":961}," fiberx",[390,1053,440],{"class":400},[390,1055,565],{"class":426},[390,1057,430],{"class":400},[390,1059,434],{"class":961},[390,1061,446],{"class":400},[390,1063,449],{"class":961},[390,1065,440],{"class":400},[390,1067,1068],{"class":961},"Server",[390,1070,446],{"class":400},[390,1072,545],{"class":400},[390,1074,548],{"class":433},[390,1076,515],{"class":400},[390,1078,518],{"class":404},[390,1080,440],{"class":400},[390,1082,523],{"class":404},[390,1084,479],{"class":400},[390,1086,1087],{"class":482}," error",[390,1089,955],{"class":400},[390,1091,1093,1096,1098,1101,1103,1106,1108,1111,1115,1117],{"class":392,"line":1092},24,[390,1094,1095],{"class":961},"        api ",[390,1097,965],{"class":400},[390,1099,1100],{"class":961}," app",[390,1102,440],{"class":400},[390,1104,1105],{"class":426},"Group",[390,1107,430],{"class":400},[390,1109,1110],{"class":400},"\"",[390,1112,1114],{"class":1113},"sfazB","\u002Fapi\u002Fv1",[390,1116,1110],{"class":400},[390,1118,936],{"class":400},[390,1120,1122,1125,1127,1130,1132,1135],{"class":392,"line":1121},25,[390,1123,1124],{"class":961},"        deps ",[390,1126,965],{"class":400},[390,1128,1129],{"class":404}," shop",[390,1131,440],{"class":400},[390,1133,1134],{"class":404},"Dependencies",[390,1136,1137],{"class":400},"{\n",[390,1139,1141,1144,1147,1150,1152,1155,1157,1160],{"class":392,"line":1140},26,[390,1142,1143],{"class":961},"            DB",[390,1145,1146],{"class":400},":",[390,1148,1149],{"class":961},"         pg",[390,1151,440],{"class":400},[390,1153,1154],{"class":426},"NewDB",[390,1156,430],{"class":400},[390,1158,1159],{"class":961},"pool",[390,1161,1162],{"class":400},"),\n",[390,1164,1166,1169,1171,1173,1175,1178,1180,1182],{"class":392,"line":1165},27,[390,1167,1168],{"class":961},"            Transactor",[390,1170,1146],{"class":400},[390,1172,1015],{"class":961},[390,1174,440],{"class":400},[390,1176,1177],{"class":426},"NewTransactor",[390,1179,430],{"class":400},[390,1181,1159],{"class":961},[390,1183,1162],{"class":400},[390,1185,1187,1190,1192,1195,1197,1200,1202,1205,1207,1210,1212,1215,1217,1219,1221,1223],{"class":392,"line":1186},28,[390,1188,1189],{"class":961},"            Dispatcher",[390,1191,1146],{"class":400},[390,1193,1194],{"class":961}," outbox",[390,1196,440],{"class":400},[390,1198,1199],{"class":426},"NewDispatcher",[390,1201,430],{"class":400},[390,1203,1204],{"class":961},"outbox",[390,1206,440],{"class":400},[390,1208,1209],{"class":426},"NewStore",[390,1211,430],{"class":400},[390,1213,1214],{"class":961},"pg",[390,1216,440],{"class":400},[390,1218,1154],{"class":426},[390,1220,430],{"class":400},[390,1222,1159],{"class":961},[390,1224,1225],{"class":400},"))),\n",[390,1227,1229],{"class":392,"line":1228},29,[390,1230,1231],{"class":400},"        }\n",[390,1233,1235,1238,1240,1243,1245,1247,1249,1252],{"class":392,"line":1234},30,[390,1236,1237],{"class":961},"        shop",[390,1239,440],{"class":400},[390,1241,1242],{"class":426},"RegisterApi",[390,1244,430],{"class":400},[390,1246,412],{"class":961},[390,1248,446],{"class":400},[390,1250,1251],{"class":961}," deps",[390,1253,936],{"class":400},[390,1255,1257,1259,1261,1264,1266,1268,1270,1272],{"class":392,"line":1256},31,[390,1258,1237],{"class":961},[390,1260,440],{"class":400},[390,1262,1263],{"class":426},"RegisterAdmin",[390,1265,430],{"class":400},[390,1267,412],{"class":961},[390,1269,446],{"class":400},[390,1271,1251],{"class":961},[390,1273,936],{"class":400},[390,1275,1277,1280],{"class":392,"line":1276},32,[390,1278,1279],{"class":396},"        return",[390,1281,1282],{"class":400}," nil\n",[390,1284,1286,1289,1291,1293,1296,1298,1300,1303,1305,1307,1309,1311,1313,1315,1317,1319],{"class":392,"line":1285},33,[390,1287,1288],{"class":400},"    },",[390,1290,1051],{"class":961},[390,1292,440],{"class":400},[390,1294,1295],{"class":426},"WithCloser",[390,1297,430],{"class":400},[390,1299,1110],{"class":400},[390,1301,1302],{"class":1113},"pgxpool",[390,1304,1110],{"class":400},[390,1306,446],{"class":400},[390,1308,545],{"class":400},[390,1310,834],{"class":404},[390,1312,440],{"class":400},[390,1314,443],{"class":404},[390,1316,479],{"class":400},[390,1318,1087],{"class":482},[390,1320,955],{"class":400},[390,1322,1324,1327,1329,1332],{"class":392,"line":1323},34,[390,1325,1326],{"class":961},"        pool",[390,1328,440],{"class":400},[390,1330,1331],{"class":426},"Close",[390,1333,1004],{"class":400},[390,1335,1337,1339],{"class":392,"line":1336},35,[390,1338,1279],{"class":396},[390,1340,1282],{"class":400},[390,1342,1344],{"class":392,"line":1343},36,[390,1345,1346],{"class":400},"    }))\n",[390,1348,1350,1353,1356,1359,1362],{"class":392,"line":1349},37,[390,1351,1352],{"class":396},"    if",[390,1354,1355],{"class":961}," err ",[390,1357,1358],{"class":400},"!=",[390,1360,1361],{"class":400}," nil",[390,1363,955],{"class":400},[390,1365,1367,1370,1372,1375,1377,1380],{"class":392,"line":1366},38,[390,1368,1369],{"class":961},"        log",[390,1371,440],{"class":400},[390,1373,1374],{"class":426},"Fatal",[390,1376,430],{"class":400},[390,1378,1379],{"class":961},"err",[390,1381,936],{"class":400},[390,1383,1385],{"class":392,"line":1384},39,[390,1386,1387],{"class":400},"    }\n",[390,1389,1391],{"class":392,"line":1390},40,[390,1392,1393],{"class":400},"}\n",[348,1395,1396,1397,1399,1400,1402],{},"The register function's job: build the ",[351,1398,1134],{}," and mount every surface on the ",[351,1401,1114],{}," group. Everything else (validation, error rendering, telemetry, shutdown) is already wired.",[410,1404,1406],{"id":1405},"options","Options",[381,1408,1410],{"className":383,"code":1409,"language":385,"meta":386,"style":386},"fiberx.WithCloser(\"pgxpool\", func(ctx context.Context) error { pool.Close(); return nil })\nfiberx.WithMiddleware(myRateLimiter, myRequestID)          \u002F\u002F ...fiber.Handler\nfiberx.WithConfig(func(c *fiber.Config) { c.ProxyHeader = \"X-Forwarded-For\" })\nfiberx.WithValidator(validate.New(validate.WithRegister(registerCustomTags)))\nfiberx.WithoutTelemetry()                                  \u002F\u002F tests \u002F external OTel setup\n",[351,1411,1412,1466,1489,1536,1571],{"__ignoreMap":386},[390,1413,1414,1417,1419,1421,1423,1425,1427,1429,1431,1433,1435,1437,1439,1441,1443,1445,1448,1451,1453,1455,1458,1461,1463],{"class":392,"line":393},[390,1415,1416],{"class":961},"fiberx",[390,1418,440],{"class":400},[390,1420,1295],{"class":426},[390,1422,430],{"class":400},[390,1424,1110],{"class":400},[390,1426,1302],{"class":1113},[390,1428,1110],{"class":400},[390,1430,446],{"class":400},[390,1432,545],{"class":400},[390,1434,434],{"class":433},[390,1436,437],{"class":404},[390,1438,440],{"class":400},[390,1440,443],{"class":404},[390,1442,479],{"class":400},[390,1444,1087],{"class":482},[390,1446,1447],{"class":400}," {",[390,1449,1450],{"class":961}," pool",[390,1452,440],{"class":400},[390,1454,1331],{"class":426},[390,1456,1457],{"class":400},"();",[390,1459,1460],{"class":396}," return",[390,1462,1361],{"class":400},[390,1464,1465],{"class":400}," })\n",[390,1467,1468,1470,1472,1474,1476,1479,1481,1484,1486],{"class":392,"line":486},[390,1469,1416],{"class":961},[390,1471,440],{"class":400},[390,1473,786],{"class":426},[390,1475,430],{"class":400},[390,1477,1478],{"class":961},"myRateLimiter",[390,1480,446],{"class":400},[390,1482,1483],{"class":961}," myRequestID",[390,1485,479],{"class":400},[390,1487,1488],{"class":526},"          \u002F\u002F ...fiber.Handler\n",[390,1490,1491,1493,1495,1498,1501,1504,1506,1508,1510,1512,1514,1516,1519,1521,1524,1527,1529,1532,1534],{"class":392,"line":530},[390,1492,1416],{"class":961},[390,1494,440],{"class":400},[390,1496,1497],{"class":426},"WithConfig",[390,1499,1500],{"class":400},"(func(",[390,1502,1503],{"class":433},"c",[390,1505,515],{"class":400},[390,1507,518],{"class":404},[390,1509,440],{"class":400},[390,1511,457],{"class":404},[390,1513,479],{"class":400},[390,1515,1447],{"class":400},[390,1517,1518],{"class":961}," c",[390,1520,440],{"class":400},[390,1522,1523],{"class":961},"ProxyHeader ",[390,1525,1526],{"class":400},"=",[390,1528,401],{"class":400},[390,1530,1531],{"class":1113},"X-Forwarded-For",[390,1533,1110],{"class":400},[390,1535,1465],{"class":400},[390,1537,1538,1540,1542,1545,1547,1550,1552,1554,1556,1558,1560,1563,1565,1568],{"class":392,"line":537},[390,1539,1416],{"class":961},[390,1541,440],{"class":400},[390,1543,1544],{"class":426},"WithValidator",[390,1546,430],{"class":400},[390,1548,1549],{"class":961},"validate",[390,1551,440],{"class":400},[390,1553,589],{"class":426},[390,1555,430],{"class":400},[390,1557,1549],{"class":961},[390,1559,440],{"class":400},[390,1561,1562],{"class":426},"WithRegister",[390,1564,430],{"class":400},[390,1566,1567],{"class":961},"registerCustomTags",[390,1569,1570],{"class":400},")))\n",[390,1572,1573,1575,1577,1580,1582],{"class":392,"line":839},[390,1574,1416],{"class":961},[390,1576,440],{"class":400},[390,1578,1579],{"class":426},"WithoutTelemetry",[390,1581,952],{"class":400},[390,1583,1584],{"class":526},"                                  \u002F\u002F tests \u002F external OTel setup\n",[1586,1587,1588,1601,1609,1620,1632],"ul",{},[1589,1590,1591,1596,1597,1600],"li",{},[369,1592,1593],{},[351,1594,1595],{},"WithCloser(name, fn)",": cleanup during graceful shutdown, after the server has stopped accepting requests. Closers run in ",[369,1598,1599],{},"LIFO"," order; telemetry flushes last, so a span emitted in a closer still gets exported.",[1589,1602,1603,1608],{},[369,1604,1605],{},[351,1606,1607],{},"WithMiddleware(...fiber.Handler)",": app-level middleware after the kit defaults. Anything needed by a single surface only should go on that surface's group instead (see below).",[1589,1610,1611,1616,1617,1619],{},[369,1612,1613],{},[351,1614,1615],{},"WithConfig(func(*fiber.Config))",": escape hatch for ",[351,1618,603],{}," fields the kit does not expose. You may also override the kit-set fields: your mutation runs last.",[1589,1621,1622,1627,1628,440],{},[369,1623,1624],{},[351,1625,1626],{},"WithValidator(*validate.Validator)",": replaces the default request validator, typically one carrying ",[360,1629,1631],{"href":1630},"\u002Fen\u002Fhttp\u002Fvalidation#custom-tags","custom validation tags",[1589,1633,1634,1639,1640,1643],{},[369,1635,1636],{},[351,1637,1638],{},"WithoutTelemetry()",": skips ",[351,1641,1642],{},"telemetry.Setup"," and the OTel middleware; for tests, or when the process configures telemetry itself.",[410,1645,1647],{"id":1646},"the-generated-wiring-registerapi","The generated wiring: RegisterApi",[348,1649,1650,1654,1655,1658,1659,1662,1663,1665],{},[360,1651,1652],{"href":315},[351,1653,314],{}," splices one ",[351,1656,1657],{},"Register\u003CSurface>"," function per surface into the module's ",[351,1660,1661],{},"register.go",". For the shop's ",[351,1664,412],{}," surface this is generated verbatim:",[381,1667,1670],{"className":383,"code":1668,"filename":1669,"language":385,"meta":386,"style":386},"func RegisterApi(router fiber.Router, deps Dependencies) {\n    apiSvc := apiservice.New()\n    apiHandler := apihttp.New(apiSvc)\n    apiPolicies := apipolicy.New()\n    apiGroup := router.Group(\"\u002Fshop\")\n    shopapigen.RegisterHandlersWithOptions(apiGroup, shopapigen.NewStrictHandler(apiHandler, []shopapigen.StrictMiddlewareFunc{\n        kitpolicy.FiberEnforcer[shopapigen.StrictHandlerFunc](apiPolicies, shopapigen.PermissionByOperation, shopapigen.PolicyByOperation),\n    }), shopapigen.FiberServerOptions{})\n}\n","internal\u002Fmodules\u002Fshop\u002Fregister.go",[351,1671,1672,1703,1719,1740,1756,1781,1826,1871,1886],{"__ignoreMap":386},[390,1673,1674,1676,1679,1681,1684,1687,1689,1692,1694,1696,1699,1701],{"class":392,"line":393},[390,1675,423],{"class":400},[390,1677,1678],{"class":426}," RegisterApi",[390,1680,430],{"class":400},[390,1682,1683],{"class":433},"router",[390,1685,1686],{"class":404}," fiber",[390,1688,440],{"class":400},[390,1690,1691],{"class":404},"Router",[390,1693,446],{"class":400},[390,1695,1251],{"class":433},[390,1697,1698],{"class":404}," Dependencies",[390,1700,479],{"class":400},[390,1702,955],{"class":400},[390,1704,1705,1708,1710,1713,1715,1717],{"class":392,"line":486},[390,1706,1707],{"class":961},"    apiSvc ",[390,1709,965],{"class":400},[390,1711,1712],{"class":961}," apiservice",[390,1714,440],{"class":400},[390,1716,589],{"class":426},[390,1718,1004],{"class":400},[390,1720,1721,1724,1726,1729,1731,1733,1735,1738],{"class":392,"line":530},[390,1722,1723],{"class":961},"    apiHandler ",[390,1725,965],{"class":400},[390,1727,1728],{"class":961}," apihttp",[390,1730,440],{"class":400},[390,1732,589],{"class":426},[390,1734,430],{"class":400},[390,1736,1737],{"class":961},"apiSvc",[390,1739,936],{"class":400},[390,1741,1742,1745,1747,1750,1752,1754],{"class":392,"line":537},[390,1743,1744],{"class":961},"    apiPolicies ",[390,1746,965],{"class":400},[390,1748,1749],{"class":961}," apipolicy",[390,1751,440],{"class":400},[390,1753,589],{"class":426},[390,1755,1004],{"class":400},[390,1757,1758,1761,1763,1766,1768,1770,1772,1774,1777,1779],{"class":392,"line":839},[390,1759,1760],{"class":961},"    apiGroup ",[390,1762,965],{"class":400},[390,1764,1765],{"class":961}," router",[390,1767,440],{"class":400},[390,1769,1105],{"class":426},[390,1771,430],{"class":400},[390,1773,1110],{"class":400},[390,1775,1776],{"class":1113},"\u002Fshop",[390,1778,1110],{"class":400},[390,1780,936],{"class":400},[390,1782,1783,1786,1788,1791,1793,1796,1798,1801,1803,1806,1808,1811,1813,1816,1819,1821,1824],{"class":392,"line":849},[390,1784,1785],{"class":961},"    shopapigen",[390,1787,440],{"class":400},[390,1789,1790],{"class":426},"RegisterHandlersWithOptions",[390,1792,430],{"class":400},[390,1794,1795],{"class":961},"apiGroup",[390,1797,446],{"class":400},[390,1799,1800],{"class":961}," shopapigen",[390,1802,440],{"class":400},[390,1804,1805],{"class":426},"NewStrictHandler",[390,1807,430],{"class":400},[390,1809,1810],{"class":961},"apiHandler",[390,1812,446],{"class":400},[390,1814,1815],{"class":400}," []",[390,1817,1818],{"class":404},"shopapigen",[390,1820,440],{"class":400},[390,1822,1823],{"class":404},"StrictMiddlewareFunc",[390,1825,1137],{"class":400},[390,1827,1828,1831,1833,1836,1838,1840,1842,1845,1848,1851,1853,1855,1857,1860,1862,1864,1866,1869],{"class":392,"line":854},[390,1829,1830],{"class":961},"        kitpolicy",[390,1832,440],{"class":400},[390,1834,1835],{"class":426},"FiberEnforcer",[390,1837,976],{"class":400},[390,1839,1818],{"class":404},[390,1841,440],{"class":400},[390,1843,1844],{"class":404},"StrictHandlerFunc",[390,1846,1847],{"class":400},"](",[390,1849,1850],{"class":961},"apiPolicies",[390,1852,446],{"class":400},[390,1854,1800],{"class":961},[390,1856,440],{"class":400},[390,1858,1859],{"class":961},"PermissionByOperation",[390,1861,446],{"class":400},[390,1863,1800],{"class":961},[390,1865,440],{"class":400},[390,1867,1868],{"class":961},"PolicyByOperation",[390,1870,1162],{"class":400},[390,1872,1873,1876,1878,1880,1883],{"class":392,"line":864},[390,1874,1875],{"class":400},"    }),",[390,1877,1800],{"class":404},[390,1879,440],{"class":400},[390,1881,1882],{"class":404},"FiberServerOptions",[390,1884,1885],{"class":400},"{})\n",[390,1887,1888],{"class":392,"line":869},[390,1889,1393],{"class":400},[348,1891,1892],{},"Line by line:",[1894,1895,1896,1906,1925,1945],"ol",{},[1589,1897,1898,1901,1902,1905],{},[369,1899,1900],{},"Service → handler → policy registry."," The surface's layers are built explicitly: no container, no autowiring; when the service needs a dependency, you pass it from ",[351,1903,1904],{},"deps"," and the diff shows it.",[1589,1907,1908,1913,1914,1916,1917,1920,1921,1924],{},[369,1909,1910],{},[351,1911,1912],{},"router.Group(\"\u002Fshop\")",": the ",[351,1915,412],{}," surface mounts at the module root (",[351,1918,1919],{},"\u002Fapi\u002Fv1\u002Fshop\u002F...","); every other surface under its own prefix (",[351,1922,1923],{},"\u002Fadmin\u002Fshop",").",[1589,1926,1927,1913,1931,1934,1935,1938,1939,1941,1942,440],{},[369,1928,1929],{},[351,1930,1805],{},[360,1932,1933],{"href":88},"generated"," strict server: it binds and types the request before calling your handler. Body binding goes through ",[351,1936,1937],{},"c.Bind().Body()",", so the ",[351,1940,651],{}," validates here ",[369,1943,1944],{},"for free",[1589,1946,1947,1952,1953,578,1956,1959,1960,1963],{},[369,1948,1949],{},[351,1950,1951],{},"kitpolicy.FiberEnforcer",": the outermost element of the strict middleware chain: based on the maps generated from the spec's ",[351,1954,1955],{},"@permission",[351,1957,1958],{},"@policy"," tags, it checks the RBAC permission and runs the ",[360,1961,1962],{"href":214},"policy"," before your business handler runs.",[410,1965,1967],{"id":1966},"surface-level-middleware-the-admin-jwt","Surface-level middleware: the admin JWT",[348,1969,1970,1971,1973,1974,1976,1977,1979,1980,1983],{},"Global middleware comes from ",[351,1972,786],{},"; anything scoped to one surface (like the JWT protection of the shop's admin surface) goes on the surface's group inside ",[351,1975,1657],{},". Extend ",[351,1978,1134],{}," with the auth config (there is room under the ",[351,1981,1982],{},"\u002F\u002F gpsystem:dependencies"," anchor), then:",[381,1985,1987],{"className":383,"code":1986,"filename":1669,"language":385,"meta":386,"style":386},"import (\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fauth\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Frbac\"\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 fiber.Router, deps Dependencies) {\n    adminSvc := adminservice.New()\n    adminHandler := adminhttp.New(adminSvc)\n    adminPolicies := adminpolicy.New()\n    adminGroup := router.Group(\"\u002Fadmin\u002Fshop\")\n    adminGroup.Use(auth.Middleware(deps.Auth), rbac.RequireRole(\"admin\"))\n    shopadmingen.RegisterHandlersWithOptions(adminGroup, shopadmingen.NewStrictHandler(adminHandler, []shopadmingen.StrictMiddlewareFunc{\n        kitpolicy.FiberEnforcer[shopadmingen.StrictHandlerFunc](adminPolicies, shopadmingen.PermissionByOperation, shopadmingen.PolicyByOperation),\n    }), shopadmingen.FiberServerOptions{})\n}\n",[351,1988,1989,1995,2004,2013,2018,2022,2026,2037,2052,2065,2080,2085,2089,2093,2120,2136,2157,2173,2196,2247,2288,2327,2339],{"__ignoreMap":386},[390,1990,1991,1993],{"class":392,"line":393},[390,1992,397],{"class":396},[390,1994,826],{"class":400},[390,1996,1997,1999,2002],{"class":392,"line":486},[390,1998,831],{"class":400},[390,2000,2001],{"class":404},"github.com\u002Fgp-system\u002Fgpsystem\u002Fauth",[390,2003,408],{"class":400},[390,2005,2006,2008,2011],{"class":392,"line":530},[390,2007,831],{"class":400},[390,2009,2010],{"class":404},"github.com\u002Fgp-system\u002Fgpsystem\u002Frbac",[390,2012,408],{"class":400},[390,2014,2015],{"class":392,"line":537},[390,2016,2017],{"class":526},"    \u002F\u002F ...\n",[390,2019,2020],{"class":392,"line":839},[390,2021,936],{"class":400},[390,2023,2024],{"class":392,"line":849},[390,2025,534],{"emptyLinePlaceholder":533},[390,2027,2028,2030,2032,2035],{"class":392,"line":854},[390,2029,540],{"class":400},[390,2031,1698],{"class":404},[390,2033,2034],{"class":400}," struct",[390,2036,955],{"class":400},[390,2038,2039,2042,2045,2047,2049],{"class":392,"line":864},[390,2040,2041],{"class":961},"    DB         ",[390,2043,2044],{"class":400},"*",[390,2046,1214],{"class":404},[390,2048,440],{"class":400},[390,2050,2051],{"class":404},"DB\n",[390,2053,2054,2057,2060,2062],{"class":392,"line":869},[390,2055,2056],{"class":961},"    Transactor ",[390,2058,2059],{"class":404},"dbx",[390,2061,440],{"class":400},[390,2063,2064],{"class":404},"Transactor\n",[390,2066,2067,2070,2073,2075,2077],{"class":392,"line":879},[390,2068,2069],{"class":961},"    Auth       ",[390,2071,2072],{"class":404},"auth",[390,2074,440],{"class":400},[390,2076,457],{"class":404},[390,2078,2079],{"class":526}," \u002F\u002F JWT_SECRET, JWT_ISSUER, ..., from the platform config\n",[390,2081,2082],{"class":392,"line":889},[390,2083,2084],{"class":526},"    \u002F\u002F gpsystem:dependencies\n",[390,2086,2087],{"class":392,"line":899},[390,2088,1393],{"class":400},[390,2090,2091],{"class":392,"line":908},[390,2092,534],{"emptyLinePlaceholder":533},[390,2094,2095,2097,2100,2102,2104,2106,2108,2110,2112,2114,2116,2118],{"class":392,"line":913},[390,2096,423],{"class":400},[390,2098,2099],{"class":426}," RegisterAdmin",[390,2101,430],{"class":400},[390,2103,1683],{"class":433},[390,2105,1686],{"class":404},[390,2107,440],{"class":400},[390,2109,1691],{"class":404},[390,2111,446],{"class":400},[390,2113,1251],{"class":433},[390,2115,1698],{"class":404},[390,2117,479],{"class":400},[390,2119,955],{"class":400},[390,2121,2122,2125,2127,2130,2132,2134],{"class":392,"line":923},[390,2123,2124],{"class":961},"    adminSvc ",[390,2126,965],{"class":400},[390,2128,2129],{"class":961}," adminservice",[390,2131,440],{"class":400},[390,2133,589],{"class":426},[390,2135,1004],{"class":400},[390,2137,2138,2141,2143,2146,2148,2150,2152,2155],{"class":392,"line":933},[390,2139,2140],{"class":961},"    adminHandler ",[390,2142,965],{"class":400},[390,2144,2145],{"class":961}," adminhttp",[390,2147,440],{"class":400},[390,2149,589],{"class":426},[390,2151,430],{"class":400},[390,2153,2154],{"class":961},"adminSvc",[390,2156,936],{"class":400},[390,2158,2159,2162,2164,2167,2169,2171],{"class":392,"line":939},[390,2160,2161],{"class":961},"    adminPolicies ",[390,2163,965],{"class":400},[390,2165,2166],{"class":961}," adminpolicy",[390,2168,440],{"class":400},[390,2170,589],{"class":426},[390,2172,1004],{"class":400},[390,2174,2175,2178,2180,2182,2184,2186,2188,2190,2192,2194],{"class":392,"line":944},[390,2176,2177],{"class":961},"    adminGroup ",[390,2179,965],{"class":400},[390,2181,1765],{"class":961},[390,2183,440],{"class":400},[390,2185,1105],{"class":426},[390,2187,430],{"class":400},[390,2189,1110],{"class":400},[390,2191,1923],{"class":1113},[390,2193,1110],{"class":400},[390,2195,936],{"class":400},[390,2197,2198,2201,2203,2206,2208,2210,2212,2215,2217,2219,2221,2224,2227,2230,2232,2235,2237,2239,2242,2244],{"class":392,"line":958},[390,2199,2200],{"class":961},"    adminGroup",[390,2202,440],{"class":400},[390,2204,2205],{"class":426},"Use",[390,2207,430],{"class":400},[390,2209,2072],{"class":961},[390,2211,440],{"class":400},[390,2213,2214],{"class":426},"Middleware",[390,2216,430],{"class":400},[390,2218,1904],{"class":961},[390,2220,440],{"class":400},[390,2222,2223],{"class":961},"Auth",[390,2225,2226],{"class":400},"),",[390,2228,2229],{"class":961}," rbac",[390,2231,440],{"class":400},[390,2233,2234],{"class":426},"RequireRole",[390,2236,430],{"class":400},[390,2238,1110],{"class":400},[390,2240,2241],{"class":1113},"admin",[390,2243,1110],{"class":400},[390,2245,2246],{"class":400},"))\n",[390,2248,2249,2252,2254,2256,2258,2261,2263,2266,2268,2270,2272,2275,2277,2279,2282,2284,2286],{"class":392,"line":989},[390,2250,2251],{"class":961},"    shopadmingen",[390,2253,440],{"class":400},[390,2255,1790],{"class":426},[390,2257,430],{"class":400},[390,2259,2260],{"class":961},"adminGroup",[390,2262,446],{"class":400},[390,2264,2265],{"class":961}," shopadmingen",[390,2267,440],{"class":400},[390,2269,1805],{"class":426},[390,2271,430],{"class":400},[390,2273,2274],{"class":961},"adminHandler",[390,2276,446],{"class":400},[390,2278,1815],{"class":400},[390,2280,2281],{"class":404},"shopadmingen",[390,2283,440],{"class":400},[390,2285,1823],{"class":404},[390,2287,1137],{"class":400},[390,2289,2290,2292,2294,2296,2298,2300,2302,2304,2306,2309,2311,2313,2315,2317,2319,2321,2323,2325],{"class":392,"line":1007},[390,2291,1830],{"class":961},[390,2293,440],{"class":400},[390,2295,1835],{"class":426},[390,2297,976],{"class":400},[390,2299,2281],{"class":404},[390,2301,440],{"class":400},[390,2303,1844],{"class":404},[390,2305,1847],{"class":400},[390,2307,2308],{"class":961},"adminPolicies",[390,2310,446],{"class":400},[390,2312,2265],{"class":961},[390,2314,440],{"class":400},[390,2316,1859],{"class":961},[390,2318,446],{"class":400},[390,2320,2265],{"class":961},[390,2322,440],{"class":400},[390,2324,1868],{"class":961},[390,2326,1162],{"class":400},[390,2328,2329,2331,2333,2335,2337],{"class":392,"line":1038},[390,2330,1875],{"class":400},[390,2332,2265],{"class":404},[390,2334,440],{"class":400},[390,2336,1882],{"class":404},[390,2338,1885],{"class":400},[390,2340,2341],{"class":392,"line":1043},[390,2342,1393],{"class":400},[348,2344,2345,2350,2351,2354,2355,2358,2359,2364,2365,2368,2369,2371],{},[360,2346,2347],{"href":204},[351,2348,2349],{},"auth.Middleware"," parses the ",[351,2352,2353],{},"Bearer"," token and puts an ",[351,2356,2357],{},"rbac.Identity"," into the context; ",[360,2360,2361],{"href":209},[351,2362,2363],{},"rbac.RequireRole(\"admin\")"," short-circuits with 403 without that role. Every ",[351,2366,2367],{},"\u002Fapi\u002Fv1\u002Fadmin\u002Fshop\u002F..."," route is protected. The ",[351,2370,412],{}," surface's public routes are untouched.",[2373,2374,2375,2376,2379,2380,746,2383,2386,2387,2390,2391,746,2393,2396,2397,578,2399,2401],"tip",{},"Rule of thumb for middleware levels: ",[369,2377,2378],{},"process-level"," (rate limit, request ID) → ",[351,2381,2382],{},"fiberx.WithMiddleware",[369,2384,2385],{},"surface-level"," (auth, role) → ",[351,2388,2389],{},"group.Use"," inside ",[351,2392,1657],{},[369,2394,2395],{},"operation-level"," (permission, ownership check) → ",[351,2398,1955],{},[351,2400,1958],{}," in the spec, enforced by the enforcer.",[348,2403,2404,2405,2407,2408,2411,2412,2415],{},"An important property: ",[351,2406,1657],{}," is a plain Go function, not a declarative file discovered by the framework: the call chain from ",[351,2409,2410],{},"main.go"," to the handler is ",[351,2413,2414],{},"cmd\u002Fshop\u002Fmain.go → RegisterApi → generated routing",", and every step of it is clickable in your editor.",[410,2417,2419],{"id":2418},"testing","Testing",[348,2421,2422,2424,2425,2427],{},[351,2423,589],{}," returns the fully wired app; with Fiber's ",[351,2426,593],{}," you test without a network:",[381,2429,2431],{"className":383,"code":2430,"language":385,"meta":386,"style":386},"app := fiberx.New(server.Config{}, fiberx.WithoutTelemetry())\napp.Post(\"\u002Fthings\", createThing)\n\nresp, err := app.Test(httptest.NewRequest(\"POST\", \"\u002Fthings\", body))\n",[351,2432,2433,2467,2492,2496],{"__ignoreMap":386},[390,2434,2435,2438,2440,2442,2444,2446,2448,2451,2453,2455,2458,2460,2462,2464],{"class":392,"line":393},[390,2436,2437],{"class":961},"app ",[390,2439,965],{"class":400},[390,2441,1051],{"class":961},[390,2443,440],{"class":400},[390,2445,589],{"class":426},[390,2447,430],{"class":400},[390,2449,2450],{"class":404},"server",[390,2452,440],{"class":400},[390,2454,457],{"class":404},[390,2456,2457],{"class":400},"{},",[390,2459,1051],{"class":961},[390,2461,440],{"class":400},[390,2463,1579],{"class":426},[390,2465,2466],{"class":400},"())\n",[390,2468,2469,2471,2473,2476,2478,2480,2483,2485,2487,2490],{"class":392,"line":486},[390,2470,548],{"class":961},[390,2472,440],{"class":400},[390,2474,2475],{"class":426},"Post",[390,2477,430],{"class":400},[390,2479,1110],{"class":400},[390,2481,2482],{"class":1113},"\u002Fthings",[390,2484,1110],{"class":400},[390,2486,446],{"class":400},[390,2488,2489],{"class":961}," createThing",[390,2491,936],{"class":400},[390,2493,2494],{"class":392,"line":530},[390,2495,534],{"emptyLinePlaceholder":533},[390,2497,2498,2501,2503,2505,2507,2509,2511,2514,2516,2519,2521,2524,2526,2528,2531,2533,2535,2537,2539,2541,2543,2546],{"class":392,"line":537},[390,2499,2500],{"class":961},"resp",[390,2502,446],{"class":400},[390,2504,1355],{"class":961},[390,2506,965],{"class":400},[390,2508,1100],{"class":961},[390,2510,440],{"class":400},[390,2512,2513],{"class":426},"Test",[390,2515,430],{"class":400},[390,2517,2518],{"class":961},"httptest",[390,2520,440],{"class":400},[390,2522,2523],{"class":426},"NewRequest",[390,2525,430],{"class":400},[390,2527,1110],{"class":400},[390,2529,2530],{"class":1113},"POST",[390,2532,1110],{"class":400},[390,2534,446],{"class":400},[390,2536,401],{"class":400},[390,2538,2482],{"class":1113},[390,2540,1110],{"class":400},[390,2542,446],{"class":400},[390,2544,2545],{"class":961}," body",[390,2547,2246],{"class":400},[348,2549,2550],{},"The error handler and the validator are active here too, so the test sees exactly the problem+json response the client will.",[410,2552,2554],{"id":2553},"patterns-used","Patterns used",[1586,2556,2557,2576],{},[1589,2558,2559,770,2562,750,2564,750,2566,750,2568,750,2570,2572,2573,440],{},[369,2560,2561],{},"Functional options",[351,2563,1295],{},[351,2565,786],{},[351,2567,1497],{},[351,2569,1544],{},[351,2571,1579],{},"): see ",[360,2574,92],{"href":2575},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#functional-options",[1589,2577,2578,2581,2582,2585,2586,440],{},[369,2579,2580],{},"Fixed-order middleware chain"," in ",[351,2583,2584],{},"newApp"," (recover → otel → sentry-hub → cors): ",[360,2587,92],{"href":2588},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#middleware-chain-with-a-fixed-order",[348,2590,2591,2592,440],{},"Fiber v3's official documentation: ",[360,2593,2597],{"href":2594,"rel":2595},"https:\u002F\u002Fdocs.gofiber.io\u002F",[2596],"nofollow","docs.gofiber.io",[2599,2600],"hr",{},[348,2602,2603,2604,2607,2608,440],{},"The same page for the other engine: ",[360,2605,2606],{"href":114},"the chi engine",". Error rendering in detail: ",[360,2609,118],{"href":119},[2611,2612,2613],"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 .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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .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}",{"title":386,"searchDepth":486,"depth":486,"links":2615},[2616,2617,2618,2619,2620,2621,2622,2623],{"id":412,"depth":486,"text":413},{"id":596,"depth":486,"text":597},{"id":794,"depth":486,"text":795},{"id":1405,"depth":486,"text":1406},{"id":1646,"depth":486,"text":1647},{"id":1966,"depth":486,"text":1967},{"id":2418,"depth":486,"text":2419},{"id":2553,"depth":486,"text":2554},"server\u002Ffiberx, a Fiber v3 app with the kit's error handling, validation and telemetry wired in, run with graceful shutdown.","md",null,{},{"icon":111},{"title":108,"description":2624},"ieR5SpJzlWloEWfUP6k0M81q9ckbfaY7PYI859BQYeU",[2632,2634],{"title":103,"path":104,"stem":105,"description":2633,"icon":106,"children":-1},"The engine-neutral server.Config (timeouts, CORS, body limit) and the shared lifecycle both engines build on.",{"title":113,"path":114,"stem":115,"description":2635,"icon":116,"children":-1},"server\u002Fchix, a chi router over the standard net\u002Fhttp with the kit's error handling and telemetry wired in, run with graceful shutdown.",1784668707015]