[{"data":1,"prerenderedAt":1647},["ShallowReactive",2],{"navigation_docs_en":3,"-en-getting-started-introduction":342,"-en-getting-started-introduction-surround":1644},[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":11,"body":344,"description":1637,"extension":1638,"links":1639,"meta":1640,"navigation":1641,"path":12,"seo":1642,"stem":13,"__hash__":1643},"docs_en\u002Fen\u002F1.getting-started\u002F1.introduction.md",{"type":345,"value":346,"toc":1628},"minimark",[347,351,393,398,401,410,413,529,536,540,589,593,600,656,659,693,710,714,717,1521,1528,1532,1583,1587,1601,1605,1624],[348,349,350],"p",{},"gpsystem is a service toolkit for building modular Go backends. It has two halves:",[352,353,354,384],"ul",{},[355,356,357,361,362,366,367,374,375,374,378,383],"li",{},[358,359,360],"strong",{},"A library"," (",[363,364,365],"code",{},"github.com\u002Fgp-system\u002Fgpsystem","): the service chassis, application lifecycle, an HTTP layer on ",[368,369,373],"a",{"href":370,"rel":371},"https:\u002F\u002Fgofiber.io",[372],"nofollow","Fiber v3"," ",[358,376,377],{},"or",[368,379,382],{"href":380,"rel":381},"https:\u002F\u002Fgo-chi.io",[372],"chi",", telemetry, an error model, validation, configuration, database access with context-carried transactions, background processing (queue, events, scheduler, worker), JWT auth, RBAC and a policy layer, object storage, e-mail, pagination.",[355,385,386,361,389,392],{},[358,387,388],{},"A CLI",[363,390,391],{},"go tool gpsystem","): generators that scaffold projects, modules, surfaces, handlers, events, listeners and jobs, including their TypeSpec contract files.",[394,395,397],"h2",{"id":396},"why-it-exists","Why it exists",[348,399,400],{},"The Go ecosystem's strength is its small, independent, well-tested libraries. The tradeoff is that every project makes the same ten decisions from scratch: which HTTP engine, which logger, what graceful shutdown looks like, how you model errors. gpsystem does that work once, for everyone: it pulls the Go ecosystem's established libraries together into a single, maintained composition, instead of writing its own in their place.",[348,402,403,404,406,407,409],{},"Coming from a PHP background? The ",[368,405,16],{"href":17}," and ",[368,408,21],{"href":22}," pages map the two worlds concept by concept.",[348,411,412],{},"The kit covers all the base functionality you meet on most sites:",[352,414,415,420,427,433,438,444,451,456,462,468,474,483,488,494,504,514,523],{},[355,416,417,419],{},[368,418,208],{"href":209},": role- and permission-based access control",[355,421,422,423,426],{},"A ",[368,424,425],{"href":214},"policy layer"," for when RBAC isn't enough: per-request ownership and state checks",[355,428,429,432],{},[368,430,431],{"href":74},"Graceful shutdown",": orderly termination that drains in-flight requests",[355,434,435,437],{},[368,436,187],{"href":188},": cron and intervals, replica-safe",[355,439,440,443],{},[368,441,442],{"href":193},"Background workers",": an asynq-based processing binary",[355,445,446,447,450],{},"Scalability: the ",[368,448,449],{"href":183},"transactional outbox"," and the scheduler's leader election behave correctly across replicas",[355,452,453,455],{},[368,454,152],{"href":153},": context-carried, cross-repository transaction handling",[355,457,458,461],{},[368,459,460],{"href":249},"Network file storage",": S3-compatible object storage (AWS, MinIO, RustFS)",[355,463,464,467],{},[368,465,466],{"href":233},"Detailed metrics",": HTTP, database and queue instrumentation over OTLP",[355,469,470,473],{},[368,471,472],{"href":228},"Monolog-style dev logging",": the readable console log you know from PHP, during development",[355,475,476,478,479,482],{},[368,477,237],{"href":238},": error tracking with issue grouping by ",[363,480,481],{},"errs"," code",[355,484,485,487],{},[368,486,232],{"href":233},": traces, metrics and logs with one call",[355,489,422,490,493],{},[368,491,492],{"href":124},"validator",": struct-tag based request validation with RFC 9457 error responses",[355,495,496,499,500,503],{},[368,497,498],{"href":83},"Typed configuration",": env vars loaded into structs, with ",[363,501,502],{},".env"," support",[355,505,506,509,510,513],{},[368,507,508],{"href":79},"Stackable error handling",": errors that compose like ",[363,511,512],{},"fmt.Errorf",", carrying stacks, error codes and client-safe messages",[355,515,516,518,519,522],{},[368,517,157],{"href":158},": embedded SQL with its own ",[363,520,521],{},"cmd\u002Fmigrate"," binary",[355,524,525,528],{},[368,526,527],{"href":88},"Code generation",": typed server code from a TypeSpec contract",[348,530,531,532,535],{},"Each is written and tested once in the kit; your projects upgrade by bumping a single version in ",[363,533,534],{},"go.mod",".",[394,537,539],{"id":538},"what-gpsystem-is-not","What gpsystem is NOT",[352,541,542,559,573,579],{},[355,543,544,547,548,551,552,555,556,558],{},[358,545,546],{},"Not a framework."," There is no IoC container, no mandatory Module interface, no kit-owned lifecycle hook that a bootstrap discovers and calls. You write ",[363,549,550],{},"main()","; every dependency is wired by hand, in explicit code. The kit's one inversion is the process lifecycle (",[363,553,554],{},"Run(ctx, cfg, register)","): it signals, shuts down, flushes, and never touches business wiring. See ",[368,557,68],{"href":69}," for exactly where that boundary sits.",[355,560,561,564,565,568,569,572],{},[358,562,563],{},"Not a platform."," gpsystem doesn't own your infrastructure: no proprietary deploy model, no cloud, no runtime; ",[363,566,567],{},"fiber.App",", ",[363,570,571],{},"chi.Router"," and the pgx pool remain yours.",[355,574,575,578],{},[358,576,577],{},"Not an ORM."," There is no Eloquent- or Doctrine-style simulation; the repository layer writes SQL (pgx) or uses a query builder (bun), with explicit queries.",[355,580,581,584,585,588],{},[358,582,583],{},"Generated code is yours."," What the CLI scaffolds, you edit like any other code, except for the narrow, deliberately regenerated zone (the TypeSpec→OpenAPI→oapi-codegen transport stubs under ",[363,586,587],{},"gen\u002F","), which you don't hand-edit but drive by changing the spec.",[394,590,592],{"id":591},"it-does-not-hide-your-dependencies","It does not hide your dependencies",[348,594,595,596,599],{},"The kit's principle: ",[358,597,598],{},"centralize, don't abstract."," Access to external dependencies is concentrated in one kit package each, but their types flow freely through the public API:",[352,601,602,620,639],{},[355,603,604,605,608,609,612,613,616,617,619],{},"the register function of ",[363,606,607],{},"fiberx.Run"," hands you a ",[363,610,611],{},"*fiber.App",", that of ",[363,614,615],{},"chix.Run"," a ",[363,618,571],{},": your handlers use the native API;",[355,621,622,625,626,406,629,568,632,616,635,638],{},[363,623,624],{},"dbx\u002Fpg"," returns ",[363,627,628],{},"pgx.Rows",[363,630,631],{},"pgxpool.Pool",[363,633,634],{},"dbx\u002Fbunx",[363,636,637],{},"bun.DB",";",[355,640,641,644,645,648,649,568,652,655],{},[363,642,643],{},"queue"," works with ",[363,646,647],{},"*asynq.Task",", and the worker's escape hatches (",[363,650,651],{},"WithAsynqConfig",[363,653,654],{},"WithMux",") hand you raw asynq.",[348,657,658],{},"This is deliberate: upstream documentation and Stack Overflow answers stay valid for you, and there is no kit-specific wrapper API to learn. The kit departs from this in three places, each for a stated reason:",[352,660,661,670,682],{},[355,662,663,664,669],{},"the ",[368,665,666],{"href":249},[363,667,668],{},"storage.Store"," interface hides the AWS SDK, so your application code doesn't have to import the AWS SDK for a file upload;",[355,671,672,677,678,681],{},[368,673,674],{"href":238},[363,675,676],{},"sentryx"," wraps sentry-go: Sentry is switchable via env (",[363,679,680],{},"SENTRY_DSN"," empty = fully off), and a binary that doesn't use it never links it;",[355,683,663,684,374,689,692],{},[368,685,686],{"href":253},[363,687,688],{},"mail",[363,690,691],{},"Mailer"," interface fronts go-mail and mjml-go, so tests can swap in an in-memory mailer.",[348,694,695,696,699,700,702,703,706,707,709],{},"The parts are ",[358,697,698],{},"replaceable and omittable",": ",[363,701,624],{}," works without ",[363,704,705],{},"server"," (say, in a CLI tool), Sentry and OTel can be switched off via env, the engine is chosen per project, pgx\u002Fbun by import. The ",[368,708,68],{"href":69}," page shows package by package what depends on what.",[394,711,713],{"id":712},"the-20-line-maingo","The ~20-line main.go",[348,715,716],{},"A module's entry point is this (graceful shutdown, telemetry, error rendering and validation already wired):",[718,719,720,1168],"code-group",{},[721,722,728],"pre",{"className":723,"code":724,"filename":725,"language":726,"meta":727,"style":727},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","func 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        }\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 (Fiber)","go","",[363,729,730,749,782,801,837,844,902,931,950,975,996,1002,1025,1045,1055,1095,1108,1115,1121,1138,1156,1162],{"__ignoreMap":727},[731,732,735,739,743,746],"span",{"class":733,"line":734},"line",1,[731,736,738],{"class":737},"sMK4o","func",[731,740,742],{"class":741},"s2Zo4"," main",[731,744,745],{"class":737},"()",[731,747,748],{"class":737}," {\n",[731,750,752,756,759,762,764,767,770,774,776,779],{"class":733,"line":751},2,[731,753,755],{"class":754},"sTEyZ","    cfg ",[731,757,758],{"class":737},":=",[731,760,761],{"class":754}," envconf",[731,763,535],{"class":737},[731,765,766],{"class":741},"MustLoad",[731,768,769],{"class":737},"[",[731,771,773],{"class":772},"sBMFI","config",[731,775,535],{"class":737},[731,777,778],{"class":772},"Config",[731,780,781],{"class":737},"]()\n",[731,783,785,788,790,793,795,798],{"class":733,"line":784},3,[731,786,787],{"class":754},"    ctx ",[731,789,758],{"class":737},[731,791,792],{"class":754}," context",[731,794,535],{"class":737},[731,796,797],{"class":741},"Background",[731,799,800],{"class":737},"()\n",[731,802,804,807,809,812,814,817,820,823,826,829,831,834],{"class":733,"line":803},4,[731,805,806],{"class":754},"    pool ",[731,808,758],{"class":737},[731,810,811],{"class":754}," pg",[731,813,535],{"class":737},[731,815,816],{"class":741},"MustNewPool",[731,818,819],{"class":737},"(",[731,821,822],{"class":754},"ctx",[731,824,825],{"class":737},",",[731,827,828],{"class":754}," cfg",[731,830,535],{"class":737},[731,832,833],{"class":754},"DB",[731,835,836],{"class":737},")\n",[731,838,840],{"class":733,"line":839},5,[731,841,843],{"emptyLinePlaceholder":842},true,"\n",[731,845,847,850,852,855,857,860,862,864,866,868,870,873,875,878,882,885,888,890,893,896,900],{"class":733,"line":846},6,[731,848,849],{"class":754},"    err ",[731,851,758],{"class":737},[731,853,854],{"class":754}," fiberx",[731,856,535],{"class":737},[731,858,859],{"class":741},"Run",[731,861,819],{"class":737},[731,863,822],{"class":754},[731,865,825],{"class":737},[731,867,828],{"class":754},[731,869,535],{"class":737},[731,871,872],{"class":754},"Server",[731,874,825],{"class":737},[731,876,877],{"class":737}," func(",[731,879,881],{"class":880},"sHdIc","app",[731,883,884],{"class":737}," *",[731,886,887],{"class":772},"fiber",[731,889,535],{"class":737},[731,891,892],{"class":772},"App",[731,894,895],{"class":737},")",[731,897,899],{"class":898},"spNyl"," error",[731,901,748],{"class":737},[731,903,905,908,910,913,915,918,920,923,927,929],{"class":733,"line":904},7,[731,906,907],{"class":754},"        api ",[731,909,758],{"class":737},[731,911,912],{"class":754}," app",[731,914,535],{"class":737},[731,916,917],{"class":741},"Group",[731,919,819],{"class":737},[731,921,922],{"class":737},"\"",[731,924,926],{"class":925},"sfazB","\u002Fapi\u002Fv1",[731,928,922],{"class":737},[731,930,836],{"class":737},[731,932,934,937,939,942,944,947],{"class":733,"line":933},8,[731,935,936],{"class":754},"        deps ",[731,938,758],{"class":737},[731,940,941],{"class":772}," shop",[731,943,535],{"class":737},[731,945,946],{"class":772},"Dependencies",[731,948,949],{"class":737},"{\n",[731,951,953,956,959,962,964,967,969,972],{"class":733,"line":952},9,[731,954,955],{"class":754},"            DB",[731,957,958],{"class":737},":",[731,960,961],{"class":754},"         pg",[731,963,535],{"class":737},[731,965,966],{"class":741},"NewDB",[731,968,819],{"class":737},[731,970,971],{"class":754},"pool",[731,973,974],{"class":737},"),\n",[731,976,978,981,983,985,987,990,992,994],{"class":733,"line":977},10,[731,979,980],{"class":754},"            Transactor",[731,982,958],{"class":737},[731,984,811],{"class":754},[731,986,535],{"class":737},[731,988,989],{"class":741},"NewTransactor",[731,991,819],{"class":737},[731,993,971],{"class":754},[731,995,974],{"class":737},[731,997,999],{"class":733,"line":998},11,[731,1000,1001],{"class":737},"        }\n",[731,1003,1005,1008,1010,1013,1015,1018,1020,1023],{"class":733,"line":1004},12,[731,1006,1007],{"class":754},"        shop",[731,1009,535],{"class":737},[731,1011,1012],{"class":741},"RegisterApi",[731,1014,819],{"class":737},[731,1016,1017],{"class":754},"api",[731,1019,825],{"class":737},[731,1021,1022],{"class":754}," deps",[731,1024,836],{"class":737},[731,1026,1028,1030,1032,1035,1037,1039,1041,1043],{"class":733,"line":1027},13,[731,1029,1007],{"class":754},[731,1031,535],{"class":737},[731,1033,1034],{"class":741},"RegisterAdmin",[731,1036,819],{"class":737},[731,1038,1017],{"class":754},[731,1040,825],{"class":737},[731,1042,1022],{"class":754},[731,1044,836],{"class":737},[731,1046,1048,1052],{"class":733,"line":1047},14,[731,1049,1051],{"class":1050},"s7zQu","        return",[731,1053,1054],{"class":737}," nil\n",[731,1056,1058,1061,1063,1065,1068,1070,1072,1075,1077,1079,1081,1084,1086,1089,1091,1093],{"class":733,"line":1057},15,[731,1059,1060],{"class":737},"    },",[731,1062,854],{"class":754},[731,1064,535],{"class":737},[731,1066,1067],{"class":741},"WithCloser",[731,1069,819],{"class":737},[731,1071,922],{"class":737},[731,1073,1074],{"class":925},"pgxpool",[731,1076,922],{"class":737},[731,1078,825],{"class":737},[731,1080,877],{"class":737},[731,1082,1083],{"class":772},"context",[731,1085,535],{"class":737},[731,1087,1088],{"class":772},"Context",[731,1090,895],{"class":737},[731,1092,899],{"class":898},[731,1094,748],{"class":737},[731,1096,1098,1101,1103,1106],{"class":733,"line":1097},16,[731,1099,1100],{"class":754},"        pool",[731,1102,535],{"class":737},[731,1104,1105],{"class":741},"Close",[731,1107,800],{"class":737},[731,1109,1111,1113],{"class":733,"line":1110},17,[731,1112,1051],{"class":1050},[731,1114,1054],{"class":737},[731,1116,1118],{"class":733,"line":1117},18,[731,1119,1120],{"class":737},"    }))\n",[731,1122,1124,1127,1130,1133,1136],{"class":733,"line":1123},19,[731,1125,1126],{"class":1050},"    if",[731,1128,1129],{"class":754}," err ",[731,1131,1132],{"class":737},"!=",[731,1134,1135],{"class":737}," nil",[731,1137,748],{"class":737},[731,1139,1141,1144,1146,1149,1151,1154],{"class":733,"line":1140},20,[731,1142,1143],{"class":754},"        log",[731,1145,535],{"class":737},[731,1147,1148],{"class":741},"Fatal",[731,1150,819],{"class":737},[731,1152,1153],{"class":754},"err",[731,1155,836],{"class":737},[731,1157,1159],{"class":733,"line":1158},21,[731,1160,1161],{"class":737},"    }\n",[731,1163,1165],{"class":733,"line":1164},22,[731,1166,1167],{"class":737},"}\n",[721,1169,1172],{"className":723,"code":1170,"filename":1171,"language":726,"meta":727,"style":727},"func main() {\n    cfg := envconf.MustLoad[config.Config]()\n    ctx := context.Background()\n    pool := pg.MustNewPool(ctx, cfg.DB)\n\n    err := chix.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        }\n        shop.RegisterApi(api, deps)\n        shop.RegisterAdmin(api, deps)\n        r.Mount(\"\u002Fapi\u002Fv1\", api)\n        return nil\n    }, chix.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 (chi)",[363,1173,1174,1184,1206,1220,1246,1250,1296,1311,1325,1343,1361,1365,1383,1401,1426,1432,1466,1476,1482,1486,1498,1512,1516],{"__ignoreMap":727},[731,1175,1176,1178,1180,1182],{"class":733,"line":734},[731,1177,738],{"class":737},[731,1179,742],{"class":741},[731,1181,745],{"class":737},[731,1183,748],{"class":737},[731,1185,1186,1188,1190,1192,1194,1196,1198,1200,1202,1204],{"class":733,"line":751},[731,1187,755],{"class":754},[731,1189,758],{"class":737},[731,1191,761],{"class":754},[731,1193,535],{"class":737},[731,1195,766],{"class":741},[731,1197,769],{"class":737},[731,1199,773],{"class":772},[731,1201,535],{"class":737},[731,1203,778],{"class":772},[731,1205,781],{"class":737},[731,1207,1208,1210,1212,1214,1216,1218],{"class":733,"line":784},[731,1209,787],{"class":754},[731,1211,758],{"class":737},[731,1213,792],{"class":754},[731,1215,535],{"class":737},[731,1217,797],{"class":741},[731,1219,800],{"class":737},[731,1221,1222,1224,1226,1228,1230,1232,1234,1236,1238,1240,1242,1244],{"class":733,"line":803},[731,1223,806],{"class":754},[731,1225,758],{"class":737},[731,1227,811],{"class":754},[731,1229,535],{"class":737},[731,1231,816],{"class":741},[731,1233,819],{"class":737},[731,1235,822],{"class":754},[731,1237,825],{"class":737},[731,1239,828],{"class":754},[731,1241,535],{"class":737},[731,1243,833],{"class":754},[731,1245,836],{"class":737},[731,1247,1248],{"class":733,"line":839},[731,1249,843],{"emptyLinePlaceholder":842},[731,1251,1252,1254,1256,1259,1261,1263,1265,1267,1269,1271,1273,1275,1277,1279,1282,1285,1287,1290,1292,1294],{"class":733,"line":846},[731,1253,849],{"class":754},[731,1255,758],{"class":737},[731,1257,1258],{"class":754}," chix",[731,1260,535],{"class":737},[731,1262,859],{"class":741},[731,1264,819],{"class":737},[731,1266,822],{"class":754},[731,1268,825],{"class":737},[731,1270,828],{"class":754},[731,1272,535],{"class":737},[731,1274,872],{"class":754},[731,1276,825],{"class":737},[731,1278,877],{"class":737},[731,1280,1281],{"class":880},"r",[731,1283,1284],{"class":772}," chi",[731,1286,535],{"class":737},[731,1288,1289],{"class":772},"Router",[731,1291,895],{"class":737},[731,1293,899],{"class":898},[731,1295,748],{"class":737},[731,1297,1298,1300,1302,1304,1306,1309],{"class":733,"line":904},[731,1299,907],{"class":754},[731,1301,758],{"class":737},[731,1303,1284],{"class":754},[731,1305,535],{"class":737},[731,1307,1308],{"class":741},"NewRouter",[731,1310,800],{"class":737},[731,1312,1313,1315,1317,1319,1321,1323],{"class":733,"line":933},[731,1314,936],{"class":754},[731,1316,758],{"class":737},[731,1318,941],{"class":772},[731,1320,535],{"class":737},[731,1322,946],{"class":772},[731,1324,949],{"class":737},[731,1326,1327,1329,1331,1333,1335,1337,1339,1341],{"class":733,"line":952},[731,1328,955],{"class":754},[731,1330,958],{"class":737},[731,1332,961],{"class":754},[731,1334,535],{"class":737},[731,1336,966],{"class":741},[731,1338,819],{"class":737},[731,1340,971],{"class":754},[731,1342,974],{"class":737},[731,1344,1345,1347,1349,1351,1353,1355,1357,1359],{"class":733,"line":977},[731,1346,980],{"class":754},[731,1348,958],{"class":737},[731,1350,811],{"class":754},[731,1352,535],{"class":737},[731,1354,989],{"class":741},[731,1356,819],{"class":737},[731,1358,971],{"class":754},[731,1360,974],{"class":737},[731,1362,1363],{"class":733,"line":998},[731,1364,1001],{"class":737},[731,1366,1367,1369,1371,1373,1375,1377,1379,1381],{"class":733,"line":1004},[731,1368,1007],{"class":754},[731,1370,535],{"class":737},[731,1372,1012],{"class":741},[731,1374,819],{"class":737},[731,1376,1017],{"class":754},[731,1378,825],{"class":737},[731,1380,1022],{"class":754},[731,1382,836],{"class":737},[731,1384,1385,1387,1389,1391,1393,1395,1397,1399],{"class":733,"line":1027},[731,1386,1007],{"class":754},[731,1388,535],{"class":737},[731,1390,1034],{"class":741},[731,1392,819],{"class":737},[731,1394,1017],{"class":754},[731,1396,825],{"class":737},[731,1398,1022],{"class":754},[731,1400,836],{"class":737},[731,1402,1403,1406,1408,1411,1413,1415,1417,1419,1421,1424],{"class":733,"line":1047},[731,1404,1405],{"class":754},"        r",[731,1407,535],{"class":737},[731,1409,1410],{"class":741},"Mount",[731,1412,819],{"class":737},[731,1414,922],{"class":737},[731,1416,926],{"class":925},[731,1418,922],{"class":737},[731,1420,825],{"class":737},[731,1422,1423],{"class":754}," api",[731,1425,836],{"class":737},[731,1427,1428,1430],{"class":733,"line":1057},[731,1429,1051],{"class":1050},[731,1431,1054],{"class":737},[731,1433,1434,1436,1438,1440,1442,1444,1446,1448,1450,1452,1454,1456,1458,1460,1462,1464],{"class":733,"line":1097},[731,1435,1060],{"class":737},[731,1437,1258],{"class":754},[731,1439,535],{"class":737},[731,1441,1067],{"class":741},[731,1443,819],{"class":737},[731,1445,922],{"class":737},[731,1447,1074],{"class":925},[731,1449,922],{"class":737},[731,1451,825],{"class":737},[731,1453,877],{"class":737},[731,1455,1083],{"class":772},[731,1457,535],{"class":737},[731,1459,1088],{"class":772},[731,1461,895],{"class":737},[731,1463,899],{"class":898},[731,1465,748],{"class":737},[731,1467,1468,1470,1472,1474],{"class":733,"line":1110},[731,1469,1100],{"class":754},[731,1471,535],{"class":737},[731,1473,1105],{"class":741},[731,1475,800],{"class":737},[731,1477,1478,1480],{"class":733,"line":1117},[731,1479,1051],{"class":1050},[731,1481,1054],{"class":737},[731,1483,1484],{"class":733,"line":1123},[731,1485,1120],{"class":737},[731,1487,1488,1490,1492,1494,1496],{"class":733,"line":1140},[731,1489,1126],{"class":1050},[731,1491,1129],{"class":754},[731,1493,1132],{"class":737},[731,1495,1135],{"class":737},[731,1497,748],{"class":737},[731,1499,1500,1502,1504,1506,1508,1510],{"class":733,"line":1158},[731,1501,1143],{"class":754},[731,1503,535],{"class":737},[731,1505,1148],{"class":741},[731,1507,819],{"class":737},[731,1509,1153],{"class":754},[731,1511,836],{"class":737},[731,1513,1514],{"class":733,"line":1164},[731,1515,1161],{"class":737},[731,1517,1519],{"class":733,"line":1518},23,[731,1520,1167],{"class":737},[348,1522,1523,1524,1527],{},"This is the entry point of the ",[368,1525,1526],{"href":41},"shop sample application",". The documentation's examples build on that project throughout.",[394,1529,1531],{"id":1530},"what-stays-in-your-hands","What stays in your hands",[352,1533,1534,1554,1563],{},[355,1535,1536,1539,1540,1543,1544,1547,1548,1550,1551,1553],{},[358,1537,1538],{},"The engine API stays native."," On Fiber your handlers receive ",[363,1541,1542],{},"fiber.Ctx",", on chi ",[363,1545,1546],{},"net\u002Fhttp","; ",[363,1549,607],{}," \u002F ",[363,1552,615],{}," wire middleware and lifecycle but do not wrap routing or request handling. Whatever the engine can do, your app can do.",[355,1555,1556,1558,1559,1562],{},[358,1557,583],{}," The scaffold lands in your repo and you edit it like any other code. The generators never overwrite an existing file and only touch marked anchor points (",[363,1560,1561],{},"\u002F\u002F gpsystem:*","). There is no runtime interpreting your project.",[355,1564,1565,374,1568,1550,1570,1572,1573,1576,1577,1582],{},[358,1566,1567],{},"Thin by design.",[363,1569,607],{},[363,1571,615],{}," are a composition of ",[363,1574,1575],{},"signal.NotifyContext",", listen, drain and an ordered cleanup list (the engine-agnostic ",[368,1578,1579,1581],{"href":74},[363,1580,881],{}," lifecycle","), exactly the code you'd otherwise write per service, maintained in one place.",[394,1584,1586],{"id":1585},"the-shape-of-a-consumer-project","The shape of a consumer project",[348,1588,1589,1590,361,1593,1596,1597,1600],{},"Every module gets ",[358,1591,1592],{},"its own entry point",[363,1594,1595],{},"cmd\u002F\u003Cmodule>\u002Fmain.go",") and runs as its own process. Deploy them separately or together, as you like. The API contract is ",[358,1598,1599],{},"spec-first",": TypeSpec compiles to OpenAPI 3.0, from which a strict, typed server interface is generated (for Fiber and chi alike). Your handler implements a generated interface, so drifting from the spec is a compile error.",[394,1602,1604],{"id":1603},"where-to-next","Where to next",[352,1606,1607,1613,1619],{},[355,1608,403,1609,406,1611,409],{},[368,1610,16],{"href":17},[368,1612,21],{"href":22},[355,1614,1615,1616,1618],{},"The ",[368,1617,1526],{"href":41}," shows how it all comes together as one project.",[355,1620,1621,1622,535],{},"Or dive straight in with ",[368,1623,25],{"href":26},[1625,1626,1627],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .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);}",{"title":727,"searchDepth":751,"depth":751,"links":1629},[1630,1631,1632,1633,1634,1635,1636],{"id":396,"depth":751,"text":397},{"id":538,"depth":751,"text":539},{"id":591,"depth":751,"text":592},{"id":712,"depth":751,"text":713},{"id":1530,"depth":751,"text":1531},{"id":1585,"depth":751,"text":1586},{"id":1603,"depth":751,"text":1604},"What gpsystem is, who it's for, and what it leaves in your hands.","md",null,{},{"icon":14},{"title":11,"description":1637},"cxq0KpoRzGIkZaRiZBC3QPoATZpo6tvGHH2uMsBCgGc",[1639,1645],{"title":16,"path":17,"stem":18,"description":1646,"icon":19,"children":-1},"A concept-by-concept mapping between Laravel and gpsystem.",1784668701128]