Architecture

Package Map

Every bkgo package has exactly one place in the generated project. This map shows which packages belong in which file — so you always know what to import.


The CLI generates all imports automatically

When you run bkgo g module user, every file is generated with the correct bkgo imports already in place. You only write your entity fields, business rules, and SQL migrations — nothing else.

Layer → Package mapping

Wirecmd/api/main.go

Entry point — connects all adapters together

bkgo/configbkgo/adapter/gormbkgo/adapter/redisbkgo/adapter/jwtbkgo/loggerbkgo/middleware

💡 Only place that imports concrete adapters

Deliveryinternal/<module>/handler.go

HTTP handler — parses requests, sends responses

bkgo/responsebkgo/errsbkgo/middlewarebkgo/i18nbkgo/validator

💡 Calls usecase, never touches DB directly

Business Logicinternal/<module>/usecase.go

Pure business rules — no framework, no DB driver

bkgo/errsbkgo/validatorbkgo/paginate

💡 Depends only on the Repository interface (PORT)

Portinternal/<module>/domain.go

Entity struct + Repository interface — pure Go

no imports — pure Go

💡 Zero bkgo imports — stays framework-free forever

Adapterinternal/<module>/repository.go

PostgreSQL implementation of the Repository interface

bkgo/contractbkgo/errs

💡 Implements the PORT defined in domain.go

Testsinternal/<module>/usecase_test.go

Unit tests — mocks the Repository, no real DB needed

bkgo/mock

💡 mock/ ships function-override test doubles for every contract


Packages you add manually

Three packages are not generated by the CLI because they are only needed in specific situations. Add them yourself when the condition below applies to your module.

bkgo/hashadd manually
📁 internal/auth/usecase.go
When:Building an auth or user module
import "github.com/BounkhongDev/bkgo/hash"

hashed, err := hash.Password(input.Password)
ok          := hash.CheckPassword(input.Password, user.HashedPassword)
bkgo/adapter/minioadd manually
📁 cmd/api/main.go + internal/storage/repository.go
When:Building a file upload module
import "github.com/BounkhongDev/bkgo/adapter/minio"

store, err  := minio.New(ctx, cfg.MinIO)
url, err    := store.Upload(ctx, "avatar.png", fileBytes, "image/png")
presigned   := store.PresignedURL(ctx, "avatar.png", time.Hour)
bkgo/adapter/postgresadd manually
📁 cmd/api/main.go (replaces adapter/gorm)
When:You prefer raw SQL over GORM
import "github.com/BounkhongDev/bkgo/adapter/postgres"

// Use instead of adapter/gorm — satisfies contract.Database
db, err := postgres.New(ctx, cfg.Postgres)

The one rule

Dependencies only point inward. Outer layers know about inner ones — inner layers never import outer ones.

main.go       → knows about handler, repository, adapters
handler.go    → knows about usecase
usecase.go    → knows about domain.Repository (interface only)
repository.go → implements domain.Repository
domain.go     → knows nothing — pure structs + interfaces

Swap PostgreSQL for any other database by writing a new repository.go — zero changes to usecase or handler.