From skills
Clean Architecture layer design and Google Wire dependency injection for Go services. Use when structuring a new service, wiring dependencies, defining layer interfaces, deciding where business logic belongs, or when a handler is accessing the database directly. Always apply this skill when the user writes or reviews handler/biz/store/model layers, Wire setup, or asks about Go service architecture.
How this skill is triggered — by the user, by Claude, or both
Slash command
/skills:golang-architectureThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
```
project/
├── cmd/ # main packages (one dir per binary)
│ └── apiserver/main.go
├── configs/ # config files (yaml, toml)
├── deployments/ # K8s, Docker, Helm charts
├── docs/ # generated API docs
├── hack/ # build scripts
│ └── include/ # *.mk files included by root Makefile
├── internal/ # private application code
│ └── apiserver/
│ ├── biz/ # business logic layer
│ ├── handler/http/ # HTTP handlers
│ ├── model/ # GORM models
│ └── store/ # DB access layer
├── pkg/ # public importable libraries
├── third_party/ # vendored non-Go assets
├── Makefile # thin dispatcher → hack/include/*.mk
└── go.mod
handler → biz → store → model
| Layer | Package | Responsibility |
|---|---|---|
handler | internal/<app>/handler/http/ | Parse request → validate → call biz → write response |
biz | internal/<app>/biz/v1/<domain>/ | Business rules, orchestration, no DB access |
store | internal/<app>/store/ | GORM/DB operations only, no business logic |
model | internal/<app>/model/ | Pure data structs (GORM models), zero dependencies |
Dependency direction: each layer depends only on the layer below's interface, never on the concrete type.
// biz/biz.go
//go:generate mockgen -destination mock_biz.go -package biz <module>/internal/apiserver/biz IBiz
var ProviderSet = wire.NewSet(NewBiz, wire.Bind(new(IBiz), new(*biz)))
type IBiz interface {
UserV1() userv1.UserBiz
PostV1() postv1.PostBiz
}
type biz struct {
store store.IStore
authz *authz.Authz
}
var _ IBiz = (*biz)(nil)
func NewBiz(store store.IStore, authz *authz.Authz) *biz {
return &biz{store: store, authz: authz}
}
func (b *biz) UserV1() userv1.UserBiz { return userv1.New(b.store, b.authz) }
func (b *biz) PostV1() postv1.PostBiz { return postv1.New(b.store) }
// store/store.go
//go:generate mockgen -destination mock_store.go -package store <module>/internal/apiserver/store IStore,UserStore,PostStore
var ProviderSet = wire.NewSet(NewStore, wire.Bind(new(IStore), new(*datastore)))
type IStore interface {
DB(ctx context.Context, wheres ...where.Where) *gorm.DB
TX(ctx context.Context, fn func(ctx context.Context) error) error
User() UserStore
Post() PostStore
}
var _ IStore = (*datastore)(nil)
Handler holds only biz.IBiz and a validator; all logic is in biz.
// handler/http/handler.go
type Handler struct {
biz biz.IBiz
val *validation.Validator
}
func NewHandler(biz biz.IBiz, val *validation.Validator) *Handler {
return &Handler{biz: biz, val: val}
}
// handler/http/user.go — one line per endpoint
func (h *Handler) Login(c *gin.Context) {
core.HandleJSONRequest(c, h.biz.UserV1().Login, h.val.ValidateLoginRequest)
}
func (h *Handler) CreateUser(c *gin.Context) {
core.HandleJSONRequest(c, h.biz.UserV1().Create, h.val.ValidateCreateUserRequest)
}
core.HandleJSONRequest does: bind JSON → run validators → call biz fn → write response. Handler adds zero logic.
//go:build wireinject
// +build wireinject
package apiserver
import "github.com/google/wire"
func InitializeWebServer(cfg *Config) (server.Server, error) {
wire.Build(
wire.NewSet(NewWebServer, wire.FieldsOf(new(*Config), "ServerMode")),
wire.Struct(new(ServerConfig), "*"),
wire.NewSet(store.ProviderSet, biz.ProviderSet),
ProvideDB,
validation.ProviderSet,
)
return nil, nil
}
//go:build !wireinject
// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
func InitializeWebServer(config *Config) (server.Server, error) {
db, err := ProvideDB(config)
// ... generated wiring ...
}
// Each layer exports one ProviderSet
var ProviderSet = wire.NewSet(
NewBiz,
wire.Bind(new(IBiz), new(*biz)), // bind interface → concrete
)
go generate ./internal/apiserver/...
handler imports anything from store directlybiz imports handler packagestore imports biz packagemodel imports any business packagemain instead of Wireif/else, DB calls, token signing)Provides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.
npx claudepluginhub shipengqi/skills --plugin database-redis