skills/89jobrien/golang-enterprise-patterns/SKILL.md
Enterprise-level Go architecture patterns including clean architecture, hexagonal architecture, DDD, and production-ready application structure.
npx skillsauth add aiskillstore/marketplace golang-enterprise-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides guidance on enterprise-level Go application architecture, design patterns, and production-ready code organization.
/cmd
/api - HTTP/gRPC entry points
/worker - Background job runners
/internal
/domain - Business entities and interfaces
/application - Use cases and application services
/infrastructure
/persistence - Database implementations
/messaging - Queue implementations
/http - HTTP client implementations
/interfaces
/api - HTTP handlers
/grpc - gRPC handlers
/pkg - Shared libraries (public)
Dependencies flow inward only:
Interfaces → Application → Domain
↓ ↓
Infrastructure (implements domain interfaces)
// domain/user.go
package domain
import "time"
type UserID string
type User struct {
ID UserID
Email string
Name string
CreatedAt time.Time
}
// UserRepository defines the contract for user persistence
type UserRepository interface {
FindByID(ctx context.Context, id UserID) (*User, error)
FindByEmail(ctx context.Context, email string) (*User, error)
Save(ctx context.Context, user *User) error
Delete(ctx context.Context, id UserID) error
}
// UserService defines domain business logic
type UserService interface {
Register(ctx context.Context, email, name string) (*User, error)
Authenticate(ctx context.Context, email, password string) (*User, error)
}
// application/user_service.go
package application
type UserServiceImpl struct {
repo domain.UserRepository
hasher PasswordHasher
logger Logger
}
func NewUserService(repo domain.UserRepository, hasher PasswordHasher, logger Logger) *UserServiceImpl {
return &UserServiceImpl{repo: repo, hasher: hasher, logger: logger}
}
func (s *UserServiceImpl) Register(ctx context.Context, email, name string) (*domain.User, error) {
// Check if user exists
existing, err := s.repo.FindByEmail(ctx, email)
if err != nil && !errors.Is(err, domain.ErrNotFound) {
return nil, fmt.Errorf("checking existing user: %w", err)
}
if existing != nil {
return nil, domain.ErrUserAlreadyExists
}
user := &domain.User{
ID: domain.UserID(uuid.New().String()),
Email: email,
Name: name,
CreatedAt: time.Now(),
}
if err := s.repo.Save(ctx, user); err != nil {
return nil, fmt.Errorf("saving user: %w", err)
}
return user, nil
}
// ports/primary.go - Driving ports (input)
package ports
type UserAPI interface {
CreateUser(ctx context.Context, req CreateUserRequest) (*UserResponse, error)
GetUser(ctx context.Context, id string) (*UserResponse, error)
}
// ports/secondary.go - Driven ports (output)
type UserStorage interface {
Save(ctx context.Context, user *domain.User) error
FindByID(ctx context.Context, id string) (*domain.User, error)
}
type NotificationSender interface {
SendWelcomeEmail(ctx context.Context, user *domain.User) error
}
// adapters/postgres/user_repository.go
package postgres
type UserRepository struct {
db *sql.DB
}
func (r *UserRepository) Save(ctx context.Context, user *domain.User) error {
query := `INSERT INTO users (id, email, name, created_at) VALUES ($1, $2, $3, $4)`
_, err := r.db.ExecContext(ctx, query, user.ID, user.Email, user.Name, user.CreatedAt)
return err
}
// domain/order/aggregate.go
package order
type Order struct {
id OrderID
customerID CustomerID
items []OrderItem
status OrderStatus
events []DomainEvent
}
func NewOrder(customerID CustomerID) *Order {
o := &Order{
id: OrderID(uuid.New().String()),
customerID: customerID,
status: StatusPending,
}
o.recordEvent(OrderCreated{OrderID: o.id, CustomerID: customerID})
return o
}
func (o *Order) AddItem(productID ProductID, quantity int, price Money) error {
if o.status != StatusPending {
return ErrOrderNotModifiable
}
o.items = append(o.items, OrderItem{
ProductID: productID,
Quantity: quantity,
Price: price,
})
return nil
}
func (o *Order) Submit() error {
if len(o.items) == 0 {
return ErrEmptyOrder
}
o.status = StatusSubmitted
o.recordEvent(OrderSubmitted{OrderID: o.id})
return nil
}
// domain/money.go
type Money struct {
amount int64 // cents
currency string
}
func NewMoney(amount int64, currency string) (Money, error) {
if amount < 0 {
return Money{}, ErrNegativeAmount
}
return Money{amount: amount, currency: currency}, nil
}
func (m Money) Add(other Money) (Money, error) {
if m.currency != other.currency {
return Money{}, ErrCurrencyMismatch
}
return Money{amount: m.amount + other.amount, currency: m.currency}, nil
}
// domain/events.go
type DomainEvent interface {
EventName() string
OccurredAt() time.Time
}
type OrderCreated struct {
OrderID OrderID
CustomerID CustomerID
occurredAt time.Time
}
func (e OrderCreated) EventName() string { return "order.created" }
func (e OrderCreated) OccurredAt() time.Time { return e.occurredAt }
// wire.go
//+build wireinject
func InitializeApp(cfg *config.Config) (*App, error) {
wire.Build(
NewDatabase,
NewUserRepository,
NewUserService,
NewHTTPServer,
NewApp,
)
return nil, nil
}
// main.go
func main() {
cfg := config.Load()
db := database.Connect(cfg.DatabaseURL)
userRepo := postgres.NewUserRepository(db)
orderRepo := postgres.NewOrderRepository(db)
userService := application.NewUserService(userRepo)
orderService := application.NewOrderService(orderRepo, userRepo)
handler := api.NewHandler(userService, orderService)
server := http.NewServer(cfg.Port, handler)
server.Run()
}
// domain/errors.go
type Error struct {
Code string
Message string
Err error
}
func (e *Error) Error() string {
if e.Err != nil {
return fmt.Sprintf("%s: %s: %v", e.Code, e.Message, e.Err)
}
return fmt.Sprintf("%s: %s", e.Code, e.Message)
}
func (e *Error) Unwrap() error { return e.Err }
var (
ErrNotFound = &Error{Code: "NOT_FOUND", Message: "resource not found"}
ErrUserAlreadyExists = &Error{Code: "USER_EXISTS", Message: "user already exists"}
ErrInvalidInput = &Error{Code: "INVALID_INPUT", Message: "invalid input"}
)
// config/config.go
type Config struct {
Server ServerConfig
Database DatabaseConfig
Redis RedisConfig
}
func Load() (*Config, error) {
cfg := &Config{}
cfg.Server.Port = getEnvInt("PORT", 8080)
cfg.Server.ReadTimeout = getEnvDuration("READ_TIMEOUT", 30*time.Second)
cfg.Database.URL = mustGetEnv("DATABASE_URL")
cfg.Database.MaxConns = getEnvInt("DB_MAX_CONNS", 25)
return cfg, nil
}
development
Apple Human Interface Guidelines for content display components. Use this skill when the user asks about charts component, collection view, image view, web view, color well, image well, activity view, lockup, data visualization, content display, displaying images, rendering web content, color pickers, or presenting collections of items in Apple apps. Also use when the user says how should I display charts, what's the best way to show images, should I use a web view, how do I build a grid of items, what component shows media, or how do I present a share sheet. Cross-references: hig-foundations for color/typography/accessibility, hig-patterns for data visualization patterns, hig-components-layout for structural containers, hig-platforms for platform-specific component behavior.
tools
Automate HelpDesk tasks via Rube MCP (Composio): list tickets, manage views, use canned responses, and configure custom fields. Always search tools first for current schemas.
testing
Expert Haskell engineer specializing in advanced type systems, pure functional design, and high-reliability software. Use PROACTIVELY for type-level programming, concurrency, and architecture guidance.
tools
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.