add surface
Ezt akkor futtasd, amikor egy modulnak a meglévő mellé egy második HTTP-felületre van szüksége, például egy admin surface-re a publikus api mellett.
go tool gpsystem add surface <modul> <surface> [--db <név>]
A surface-ök párhuzamos, célközönségenkénti felületkötegek egy modulon belül, például egy publikus api egy admin vagy backoffice felület mellett (lásd Projektstruktúra). A surface neve szabad (kisbetűk és számjegyek, betűvel kezdve); minden surface ugyanabból a minimális sablonból generálódik. Mindegyik saját TypeSpec service-t, generált csomagot, handlert és base path-t kap:
| Surface | Base path |
|---|---|
api | /api/v1/<modul> |
bármely más név, pl. admin | /api/v1/<surface>/<modul> |
A név nem hordoz viselkedést: az api csak annyiban különleges, hogy a modul gyökerére mountolódik, minden más surface a saját prefixe alá kerül, így a testvér-surface-ök sosem ütköznek.
Mit generál
Minimális vázat: a kontraktust (spec/typespec/modules/<modul>/<surface>.tsp + models/<surface>.tsp), az oapi-codegen konfigot (api/oapi-codegen/<modul>-<surface>.yaml), egy a generált szigorú interfészre kötött handlert (a minta List egy minimális service/ varratot hív, és a hibát errs.Wrap-pel csomagolja, így a surface-hibák első naptól stacket hordoznak), egy policy/ csomagot a @permission/@policy tagek érvényesítéséhez bekötött registry-stubbal, valamint egy üresen tartott http/mapper/ mappát (.gitkeep) a saját kódodnak. A generált fájlok nem hordoznak magyarázó kommentet, csak a gpsystem:* anchorokat, amelyekbe a generátor injektál. A generátor nem köt be autentikációt vagy migrációt: a kit auth és rbac csomagjai rendelkezésre állnak, ha kellenek; a policy-król lásd a Policy-k oldalt.
A modul első surface-e mellé a parancs a modul-szintű közös vázakat is odabélyegzi: a core/core.go + core/errors.go fájlokat (utóbbi egy ErrNotFound errs.Define példával) és a repository/doc.go-t. A későbbi surface-ök ezeket kihagyják, a már meglévő közös magot használják. Egy még közös mag nélküli modulhoz az add core adja ugyanezeket a vázakat.
A bekötés anchor-beszúrásokkal történik: a register.go file-szintű gpsystem:surfaces anchorán egy exportált Register<Surface>(router, deps) függvény jön létre (pl. RegisterAdmin), a cmd/<modul>/main.go gpsystem:registrations anchorán pedig a hozzá tartozó <modul>.Register<Surface>(api, deps) hívás. Így minden surface külön függvényben él: surface-enkénti middleware-t (pl. admin JWT: adminGroup.Use(server.AuthMiddleware(deps.Auth), server.RequireRole("admin")); lásd autentikáció) az adott Register<Surface> függvénybe tehetsz anélkül, hogy a többi surface-t érintenéd.
@permission és @policy a kontraktusban
A generált <surface>.tsp műveletei a @permission("...") / @policy("...") dekorátorokkal jelölhetők meg: a dekorátor-library-t (spec/typespec/lib/policy.tsp) a projekt-scaffold hozta, a main.tsp már importálja. A tagek x-permission / x-policy extensionként jutnak az OpenAPI-ba, majd a generált PermissionByOperation / PolicyByOperation mapekbe:
@post
@route("/orders")
@operationId("PlaceOrder")
@permission("orders.place")
@policy("orders.place")
placeOrder(@body body: PlaceOrderInput): Order | Unauthorized | Forbidden;
A kikényszerítés oldala is scaffoldolt: a policy/ csomag registry-stubja (policy.New(), benne a gpsystem:policies anchor) a Register<Surface> függvényben már be van fűzve a generált strict-middleware-be (policy.Enforcer, az önálló auth/policy modulból). Egy művelet levédéséhez így két lépés elég: tag a .tsp-ben, és egy reg.Register("...", ...) hívás az anchornál; a megjelölt, de nem regisztrált policy fail-closed hibázik. A teljes szemantika: Policy-k.
news + admin és a newsadmin + api egyaránt Shop.NewsAdmin.yaml / Shop.Newsadmin.yaml fájlt ad, ami case-insensitive fájlrendszeren ütközik. Olyan neveket válassz, amelyeknél az összefűzések különbözőek maradnak.Repository bekötése nevesített kapcsolathoz
Alapesetben a modul közös repository/-ja flat, a projekt default adatbázis-kapcsolatához kötve. A --db <név> egy korábban add db-vel hozzáadott nevesített kapcsolathoz köti, és a repository-vázat kapcsolatnév szerinti almappaként rendereli:
go tool gpsystem add db news analytics --connector bun
go tool gpsystem add surface news reports --db analytics
# -> internal/modules/news/repository/analytics/doc.go
A <név>-nek már léteznie kell a modulon (előbb add db); ha nem, a parancs azonnal hibázik, és felsorolja a modul elérhető kapcsolatait. A <Név>DB / <Név>Transactor mezők, amelyeket a kapcsolat a Dependencies-hez adott, már megvannak; csak a repository mappa változik. A --db nélküli surface-ök nem érintettek, a modul megtartja a flat repository/ elrendezést.
Generálás után
mise run generate
go run ./cmd/<modul>
Az új surface azonnal bootol és kiszolgál; az implementációhoz töltsd fel a service/ varratot (a közös szabályokat a modul core/ csomagjába téve, ahonnan minden surface hívhatja), és adj vissza valódi adatot: a handler már hívja a service-t és errs-szel csomagolja a hibáit.