new project
Ez a belépési pont a gpsystembe: egy teljes fogyasztó-projektet generál a nulláról, és minden más CLI-parancs egy általa létrehozott projekten belül fut.
gpsystem new project <név> --module-path <go-module-path> [flagek]
Így készült a shop mintaalkalmazás is:
gpsystem new project shop --module-path github.com/acme/shop --dir ./shop
Flagek
| Flag | Kötelező | Default | Jelentés |
|---|---|---|---|
--module-path | igen | nincs | a projekt Go module path-ja: a go.mod-ba és minden generált importba bekerül |
--dir | nem | ./<név> | célmappa |
--db | nem | pgx | a generált backend adatbázis-stackje: pgx vagy bun |
A globális --dry-run (tervet nyomtat, nem ír semmit) és --force (meglévő fájlok felülírása) itt is működik, mint minden alparancson. Három további flag (--kit-replace, --replace, --replace-dev) létezik a gpsystem saját fejlesztéséhez; lásd a Contributor mód szakaszt lentebb, a hétköznapi projekt-setupnak nincs rájuk szüksége.
A projekt <név> kisbetű/számjegy, betűvel kezdve. Ez táplálja a TypeSpec namespace-eket, és megjelenik a generált konfigokban.
--module-pathvéglegesnek tekintendő: minden generált import erre épül, és minden későbbi generátor ezt írja az új fájlokba. Utólagos csere az összes import átírását jelenti, ezért válaszd meg az elején.Adatbázis-választás
Az adatbázis-stack projektenkénti és végleges döntés: a manifest rögzíti (db:), és minden későbbi generátor (new module, add surface, add handler) ehhez igazodik: a --db flaget csak egyszer, itt adod meg. Egy adott modul később is felvehet további, önálló kapcsolatot más connectorral az add db révén.
Mi különbözik adatbázisonként
A --db a repository-réteg alatti stacket dönti el; a pool mindkét esetben pgx:
// cmd/<modul>/main.go: deps-init
pool := pg.MustNewPool(ctx, cfg.DB)
deps := shop.Dependencies{
DB: pg.NewDB(pool),
Transactor: pg.NewTransactor(pool),
}
// register.go
type Dependencies struct {
DB *pg.DB
Transactor dbx.Transactor
}
// cmd/<modul>/main.go: deps-init
pool := pg.MustNewPool(ctx, cfg.DB)
bunDB := bunx.Open(pool) // bun query builder a pgx pool fölött
deps := shop.Dependencies{
DB: bunDB,
Transactor: bunx.NewTransactor(bunDB),
}
// register.go
type Dependencies struct {
DB *bun.DB
Transactor dbx.Transactor
}
Ugyanez a különbség jelenik meg a cmd/worker/main.go-ban és az add event által bedrótozott outbox-store-ban (outbox.NewStore(pg.NewDB(pool)) ↔ outbox/bunx.NewStore(bunDB)). A repository-sablonok pgx-nél SQL-t, bunnál query-builder-hívásokat adnak (lásd pgx és bun).
Mit generál
gpsystem.yamlmanifest (név, module path,db, kit-verzió, template-checksum)go.moda kittel és a szükséges önálló modulokkal mintrequire-ekkel, plusztooldirektívákkal (gpsystem, oapi-codegen), így a csapat minden tagja ugyanazt a CLI-verziót és ugyanazokat a publikált modul-verziókat futtatja- TypeSpec workspace:
spec/typespec/{main.tsp, shared/errors.tsp, shared/paginator.tsp, lib/policy.tsp},tspconfig.yaml(OpenAPI 3.0-ra rögzítve, kimenet azapi/openapi/-ba),package.jsonpinelt TypeSpec-fordítóval - A kit oapi-codegen template-jei az
api/oapi-codegen/templates/alá: egyetlen, chi-alapú készlet (az oapi-codegen beépítettchi-serversablonjai plusz a kit strict-handler override-jai) internal/platform/config/config.go: összerakott env-konfig (Server+DB+Worker+Outbox), envconf-fal töltvecmd/worker/main.go: a háttérfeldolgozó bináris (worker);cmd/migrate/main.go: a migrációfuttatómigrations/: beágyazott, időbélyeg-prefixes goose SQL, induló20200101000000_init.sql+20200101000100_outbox.sql(az outbox táblája)mise.tomltaskok (setup,spec,generate,dev,dev:deps,restart,dev:down,worker,migrate,logs,build,test,lint),Dockerfile(multi-stage, lásd lent),.dockerignore,compose.yml(teljes dev-stack, lásd lent),.env.example,.golangci.yml,.gitignore,README.md
A HTTP-oldali belépési pontot (cmd/<modul>/main.go) nem a new project, hanem az első new module hozza létre: modulonként egy bináris készül, és a new module a compose-service-ét is beszúrja.
A compose dev-stack
A generált compose.yml egy teljes, konténerizált dev-stack (egyetlen publikált port sincs benne): postgres, valkey, mailpit, rustfs (S3-kompatibilis object storage), a migrate/worker/modul-binárisok, mind a projekt Dockerfile-jából build-elve, mind kifelé Traefik-labelekkel az external proxynet hálózaton (dupla web/websecure router, tls.certresolver=letsEncrypt).
Előfeltétel: docker network create proxynet (egyszeri, workspace-szinten megosztott), docker compose ≥ 2.17 + BuildKit (az additional_contexts és a cache mountok miatt).
Dockerfile: négy stage
base:golang:1.25-alpine, csak aWORKDIR.development: a compose ezt build-eli (target: development); host-UID/GID-es user (USER_ID/GROUP_IDbuild-argok a.env-ből), a forrás bind-mountolva (.:/src),CMD ["sh", "-c", "exec go run ./cmd/${CMD}"]. Nincs forrás-másolás, nincsgo mod downloadbuild-time: kódváltozás után elégdocker compose restart <service>, ago runa mountolt forrásból újrafordít; a modul-cache-ek (gomodcache/gocache) named volume-on élnek, hogy a restart-újrafordítás gyors legyen.build:ARG CMD+go build ./cmd/${CMD}, cache mountokkal; ebből épül a prod image (docker build --target production --build-arg CMD=<x> .).production:alpine:3.22,USER nobody, csak a lefordított bináris.
Modul-routing: path-alapú, nem subdomain
A modul-service Traefik rule-ja Host(`${APP_HOST}`) && PathRegexp(`^/api/v1/([a-z0-9-]+/)?<modul>(/|$)`); ez lefedi az api surface /api/v1/<modul> és minden más surface /api/v1/<surface>/<modul> útvonalát is, így add surface után sem kell hozzányúlni.
Contributor mód: lokális modul-replace-ek
A fentiek mind a hétköznapi utat feltételezik: a kit és a 12 önálló modul sima publikus Go modul, a new project-nek egyik sem kell lokálisan, a go mod tidy a publikált verziókat oldja fel a modul-proxyból. Ha magát a gpsystemet fejleszted, vagy egy generált projektnek egy önálló modul még nem publikált változatával kell buildelnie, három további flag lehetővé teszi, hogy a new project go.mod replace direktívákat írjon lokális checkoutokra:
| Flag | Jelentés |
|---|---|
--kit-replace <útvonal> | replace-t ad hozzá, ami magát a kitet egy lokális checkoutra irányítja; hacsak egy explicit --replace errs=... felül nem írja, ez egyúttal az errs-hez is levezet egy replace-t, a checkout melletti testvérkönyvtárban |
--replace <név>=<útvonal> | ismételhető; egy konkrét önálló modulhoz (errs, vagy bármely modulnév a kit modul-regiszteréből) ad hozzá replace-t, a másik két flagtől függetlenül |
--replace-dev <mappa> | rövidítés arra az esetre, amikor a kit, az errs és minden regiszterbeli modul testvérkönyvtárként van kicheckoutolva a <mappa> alatt: ezzel egyenértékű, mintha mindegyikükre külön-külön megadnád a --kit-replace-t és a --replace-t |
Minden célútvonal a --dir-hez viszonyítva oldódik fel, így a kimenő go.mod, compose.yml és Dockerfile csak relatív útvonalakat hordoz, sosem gépspecifikusat: a generált projekt hordozható marad, amíg a lokális checkoutokhoz viszonyított pozíciója nem változik. E három flag nélkül a new project egy sima require-rel generálja a projektet minden szükséges modul publikált verziójára, replace nélkül: ez az alapértelmezés, és egy fogyasztó-projektnek egyedül ezt kellene használnia.
A generált compose.yml/Dockerfile ugyanezt a replace-térképet követi: minden replace-elt modulhoz a development target bind-mountolja a checkoutot egy fix, konténeren belüli útra (futásidejű mount, build-time másolás nélkül, így a checkout szerkesztése is csak docker compose restart-ot igényel), a build/production target pedig egy compose additional_contexts bejegyzést ad hozzá, amit a Dockerfile build stage-e COPY --from=<modul>-lal másol be a go mod download elé. Egy replace nélküli projekt egyik blokkot sem kapja meg.
Generálás után
cd <név>
go mod tidy # függőségek + tool directive-ek feloldása
mise run setup # TypeSpec toolchain (npm)
go tool gpsystem new module <első-modul>
mise run generate # tsp → OpenAPI → szerverkód → build
cp .env.example .env # USER_ID/GROUP_ID: id -u / id -g
docker network create proxynet # egyszeri
mise run dev # build + a teljes dev-stack indítása
Innen a CLI már a projektbe pinelt verzióként fut (go tool gpsystem), és a manifest alapján tudja, milyen adatbázis-stackhez generáljon.