CLI referencia

new project

Teljes fogyasztó-projektváz generálása, adatbázis-választással.

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 <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

FlagKötelezőDefaultJelentés
--module-pathigennincsa projekt Go module path-ja: a go.mod-ba és minden generált importba bekerül
--dirnem./<név>célmappa
--dbnempgxa 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.

A --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
}

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.yaml manifest (név, module path, db, kit-verzió, template-checksum)
  • go.mod a kittel és a szükséges önálló modulokkal mint require-ekkel, plusz tool direktí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 az api/openapi/-ba), package.json pinelt 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ített chi-server sablonjai plusz a kit strict-handler override-jai)
  • internal/platform/config/config.go: összerakott env-konfig (Server + DB + Worker + Outbox), envconf-fal töltve
  • cmd/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.toml taskok (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 a WORKDIR.
  • development: a compose ezt build-eli (target: development); host-UID/GID-es user (USER_ID/GROUP_ID build-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, nincs go mod download build-time: kódváltozás után elég docker compose restart <service>, a go run a 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:

FlagJelenté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 <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.

Copyright © 2026