Kezdő lépések

Laravelből érkezőknek

Fogalomról fogalomra megfeleltetés a Laravel és a gpsystem között.

Ha Laravelen dolgoztál, a gpsystem legtöbb építőköve ismerős lesz: több csomag kimondottan a Laravel-megfelelője mintájára készült. Ez az oldal megmutatja, mi minek felel meg, és őszintén azt is, mi nem transzferálódik.

Ami átjön: a gondolkodás az eventekről, listenerekről, policy-król, ütemezésről és a queue-król egy az egyben. Ami nem: nincs ORM-mágia (nincs Eloquent, a repository-kban SQL-t vagy bun query buildert írsz), nincs container-autowiring (a függőségek egy explicit Dependencies structban utaznak, amit a main.go-ban te töltesz ki), és nincs globális facade sem: minden függés látható és követhető.

Megfeleltetési tábla

LaravelgpsystemHol
Task Scheduling ($schedule->daily())scheduler.Schedule fluent API (sched.DailyAt(...), sched.Job(...))Ütemezés
Events & Listeners, ShouldQueueevents.Event + events.Listen (minden listener önálló, újrapróbált task)Események
Queues, queue:work, Horizonqueue (asynq + Valkey) + cmd/worker binárisQueue, Worker
Policies ($this->authorize())policy.Registry + generált enforcer middleware, fail-closedPolicy-k
Gates, szerepek (spatie/permission)rbac.Identity, RequireRole / RequirePermissionRBAC
Auth guardok, Sanctum tokenekauth (JWT kibocsátás és middleware)Autentikáció
Monolog (dev channel)logx/monolog (Monolog-formátumú konzol-handler)Logolás
php artisan migratego run ./cmd/migrate (beágyazott, számozott SQL)Migrációk
DB::transaction(fn)Transactor.WithinTransaction(ctx, fn) (a tranzakció a contextben utazik)Tranzakciók
FormRequest szabályokvalidator struct-tagek + generált request-típusokValidáció
Exception render() / report()errs kódok + public üzenet → RFC 9457 problem+json / SentryHibamodell
config() + .envenvconf.MustLoad[T] (típusos struct env-ből, .env-támogatással)Konfiguráció
Storage facade, flysystem diskeka storage modul Driver/Disk/Manager modellje + S3-driverTárolás
Mailables, markdown mailmail.Message builder + MJML template-ek; Mail::fake() ↔ memória-mailerE-mail
php artisan make:*go tool gpsystem new/add ...CLI
paginate() / cursorPaginate()paginate.Page[T] / paginate.CursorPage[T]Lapozás
Eloquent ORMpgx (SQL) vagy bun (query builder), nincs ActiveRecord-szimulációAdatbázis
Route regisztráció (routes/api.php, auto-discovery)Register<Surface>(router, deps) (explicit hívás a main.go-ban)Architektúra
Route-csoport / külön controller-készlet közönségenként (publikus API vs admin)surface (felület-köteg): surfaces/<surface>/, saját kontrakttal és middleware-reladd surface
Model-metódusok + közös service-logikaa modul core/ csomagja (egyszer leírt szabályok, minden surface hívja)Projektstruktúra
Query-réteg (Eloquent scope-ok, query builder hívások)a modul-szintű repository/: modulonként egy, minden surface közösen használjaProjektstruktúra

Két példa egymás mellett

Ütemezett feladat: a ->onOneServer() viselkedése itt alapértelmezés (Valkey-lease leader election):

Schedule::command('report:nightly-sales')
    ->dailyAt('03:00')
    ->onOneServer();

Policy (kérésenkénti tulajdonos-ellenőrzés, amikor a szerep önmagában kevés):

class OrderPolicy
{
    public function view(User $user, Order $order): bool
    {
        return $user->id === $order->user_id
            || $user->hasRole('admin');
    }
}

Egy lényegi különbség: Laravelben a policy-t a controllerből hívod ($this->authorize()), és el is felejthető. Itt a policy-t a TypeSpec-kontraktus @policy dekorátora rendeli a művelethez, az enforcer middleware pedig a generált táblából kényszeríti ki. A megjelölt, de nem regisztrált policy nem átenged, hanem hibázik (fail-closed).

Viselkedésbeli különbségek

A mapping-tábla azt mutatja, mi minek felel meg. Ez a szakasz azt mutatja meg, hol nem azonos a viselkedés, ha a felszíni hasonlóság mögé nézel.

  • Tranzakciók. Laravelben a tranzakciót egy globális connection-menedzser tartja számon: bármely modell-hívás automatikusan benne fut, a DB::transaction pedig deadlock esetén újrapróbálkozik (attempts paraméter), a rollbackot kivétel váltja ki. gpsystemben a tranzakciót a context hordozza (Transactor.WithinTransaction): csak az a hívás vesz részt benne, amelyik a closure ctx-ét kapja; nincs automatikus deadlock-retry (a döntés a tiéd); a rollbackot sima error visszaadása váltja ki, nem kivétel. Részletek: Tranzakciók.
  • Migrációk. A goose_db_version tábla a Laravel migrations táblájának felel meg, de nincs schema builder: sima SQL fut. Ez tudatos trade-off: a builder adatbázisok közti hordozhatóságot ad, amire itt nincs szükség (a kit PostgreSQL-re épül), cserébe elfedi a tényleges DDL-t. Sima SQL-lel elérhető PostgreSQL teljes felülete (partial indexek, GENERATED oszlopok, CTE-s backfillek), amit egy schema builder csak DB::statement-tel tudna. Részletek: Migrációk.
  • Események és a fan-out. A gpsystem minden listenert önálló, saját retry-kerettel futó asynq taskként kezel: egy event N listener-taskra terül szét, egy hibázó listener újrapróbálkozása sosem futtatja újra a többit. Ez a lényegi eltérés a Laravel szinkron event-loopjától (ahol egy listener kivétele megállíthatja a többit is), és az ára az idempotencia-követelmény minden listeneren. Részletek: Események.
  • Tranzakciós outbox. Laravelben nincs beépített megoldás a dual-write problémára: az afterCommit a rollback-esetet kezeli, de a commit-utáni crash-ablakot (a folyamat a DB-commit és az event-enqueue közt hal le) nem zárja be; aki garanciát akar, ott is egy külön outbox-csomagot húz be. gpsystemben ez gyárilag jön: az outbox az eventet ugyanabba az adatbázisba, ugyanabban a tranzakcióban írja, mint az üzleti változást. Részletek: Outbox.
  • OpenTelemetry. Ennek nincs igazi PHP-s megfelelője: a Laravel-ökoszisztémában a Telescope dev-only eszköz, a production APM pedig fizetős szolgáltatások (Blackfire, New Relic) területe. A Go-ökoszisztémában az elosztott trace-elés standard, gyártófüggetlen infrastruktúra, amit a kit egy hívással bekapcsol. Részletek: OpenTelemetry.

Mi nincs, és miért

  • Nincs Eloquent. A repository-réteg pgx-szel (SQL) vagy bunnal (query builder) dolgozik, a Go-ökoszisztémában az explicit lekérdezés a bevett út, és a kit nem próbál ActiveRecordot szimulálni. A bun opcionális adapter, ha a query builder kényelmét szeretnéd.
  • Nincs service container. A Dependencies struct kézzel épül a main.go-ban. Cserébe a "honnan jön ez a függőség?" kérdésre mindig egy cmd/<modul>/main.go-beli sor a válasz.
  • Nincs Blade. A kit API-backendekre fókuszál; a szerveroldali renderelés nem része.

Háttér

A kit szerzőjének motivációja pont az volt, hogy a Go-ökoszisztémában is legyen egy, a Laravelhez hasonlóan könnyen használható rendszer: ahol a projekt első napján üzleti logikát írsz, nem infrastruktúrát válogatsz. A Go-világ ereje a kis, egymástól független, jól tesztelt library-kben van. A gpsystem nem lecserélni akarja ezeket, hanem egyetlen, összecsiszolt és karbantartott kompozíciót adni belőlük, a Laravelből ismerős fogalmi kerettel. Ezért látod mindenhol a párhuzamokat, és ezért nem rejti el a kit az alatta lévő library-ket: a library-fél egy microservice chassis, a generált projekt egy service template (Richardson), nem egy futásidejű réteg, ami az app fölött él. A cél a kényelmes indulás, nem egy új, zárt keretrendszer.

Copyright © 2026