A production-ready Go boilerplate following Domain-Driven Design (DDD) principles with NestJS-like architecture patterns. Built with modern Go practices, microservice architecture, and comprehensive background job processing.
This project implements a clean, domain-driven architecture where each domain is a complete vertical slice owning its entire lifecycle - from HTTP endpoints to background processing.
- Domain-Driven Design: Each domain is self-contained and independently deployable
- Clean Architecture: Clear separation of concerns with dependency inversion
- NestJS-like Modules: Familiar patterns for developers coming from Node.js/NestJS
- Microservice Ready: Separate deployable API and Worker servers
- Production Ready: Comprehensive logging, graceful shutdown, and error handling
vibe-ddd-golang/
βββ cmd/ # Application entry points
β βββ api/main.go # API server startup
β βββ worker/main.go # Worker server startup
β βββ migration/main.go # Database migration server
β βββ grpc/main.go # gRPC server startup
βββ internal/ # Private application code
β βββ application/ # Domain layer (DDD)
β β βββ payment/ # Payment domain
β β β βββ dto/ # Data Transfer Objects
β β β β βββ payment.dto.go # Request/response models
β β β βββ entity/ # Domain entities
β β β β βββ payment.entity.go # Database models
β β β βββ repository/ # Data access layer
β β β β βββ payment.repo.go # Repository implementation
β β β βββ service/ # Business logic layer
β β β β βββ payment.service.go # Domain services
β β β βββ handler/ # HTTP layer
β β β β βββ payment.handler.go # REST endpoints + routes
β β β βββ worker/ # Background processing
β β β β βββ handler.go # Job handlers
β β β β βββ tasks.go # Job definitions
β β β βββ module.go # Domain DI configuration
β β βββ user/ # User domain
β β βββ dto/user.dto.go # User DTOs
β β βββ entity/user.entity.go # User entity
β β βββ repository/user.repo.go # User repository
β β βββ service/user.service.go # User services
β β βββ handler/user.handler.go # User endpoints
β β βββ module.go # User DI config
β βββ server/ # Server implementations
β β βββ api/ # HTTP API server
β β β βββ module.go # Route registration & setup
β β β βββ providers.go # API server DI providers
β β βββ worker/ # Background worker server
β β β βββ module.go # Worker handler registration
β β β βββ providers.go # Worker server DI providers
β β βββ migration/ # Database migration server
β β β βββ module.go # Migration operations
β β β βββ providers.go # Migration DI providers
β β βββ grpc/ # gRPC server
β β βββ module.go # gRPC service registration
β β βββ providers.go # gRPC server DI providers
β βββ middleware/ # HTTP middleware
β β βββ middleware.go # Logging, CORS, recovery
β βββ config/ # Configuration
β β βββ config.go # App configuration
β βββ pkg/ # Internal packages
β βββ database/database.go # DB connection
β βββ logger/logger.go # Structured logging
β βββ queue/ # Job queue infrastructure
β β βββ client.go # Redis queue client
β β βββ server.go # Worker server
β β βββ logger.go # Queue logging
β βββ testutil/ # Test utilities
β βββ database.go # Test database setup
β βββ fixtures.go # Test data fixtures
β βββ logger.go # Test logger setup
β βββ mocks.go # Mock implementations
βββ config.yaml # Configuration file
βββ Makefile # Build automation
βββ Dockerfile # Container image
βββ go.mod # Go modules
βββ README.md # This file
Each domain follows the same consistent pattern:
internal/application/{domain}/
βββ dto/ # Data Transfer Objects
βββ entity/ # Domain entities (database models)
βββ repository/ # Data access interfaces & implementations
βββ service/ # Business logic & domain services
βββ handler/ # HTTP handlers & route registration
βββ worker/ # Background job processing (optional)
βββ module.go # Dependency injection configuration
- Domain Ownership: Each domain owns its complete vertical slice
- Dependency Inversion: High-level modules don't depend on low-level modules
- Single Responsibility: Each layer has a clear, focused responsibility
- Interface Segregation: Small, focused interfaces
- Separation of Concerns: HTTP, business logic, and data access are separated
| Layer | Responsibility | Example |
|---|---|---|
| Handler | HTTP concerns, routing, request/response | payment.handler.go |
| Service | Business logic, validation, orchestration | payment.service.go |
| Repository | Data access, database operations | payment.repo.go |
| Entity | Domain models, business rules | payment.entity.go |
| DTO | Data transfer, validation, serialization | payment.dto.go |
| Worker | Background processing, async jobs | payment/worker/ |
- Go 1.21+
- Redis 6.0+ (for background jobs)
- PostgreSQL 12+ (for database)
-
Clone the repository
git clone <repository-url> cd vibe-ddd-golang
-
Install dependencies
make deps
-
Setup configuration
cp config.sample.yaml config.yaml # Edit config.yaml with your settings -
Start required services
# Start Redis (for background jobs) redis-api # Start PostgreSQL (for database) # Use your preferred method
# Terminal 1: Start API api
make run
# Terminal 2: Start worker api (for background jobs)
make run-worker# Build both servers
make build
make build-worker
# Run API api
./bin/vibe-ddd-golang
# Run worker api
./bin/worker# Build and run with Docker
make docker-build
make docker-runFor a complete list of all available commands, run:
make helpmake build # Build API api
make build-worker # Build worker api
make build-migration # Build migration api
make build-grpc # Build gRPC api
make build-all # Build all serversmake run # Run API api
make run-worker # Run worker api
make run-grpc # Run gRPC api
make run-migration # Run database migrations
make run-seed # Seed database with initial data
make run-drop # Drop all database tablesmake test # Run all tests
make test-coverage # Run tests with coverage report
make test-unit # Run unit tests only
make test-integration # Run integration tests only
make test-repo # Run repository layer tests
make test-service # Run service layer tests
make test-handler # Run handler layer tests
make test-worker # Run worker layer tests
make test-user # Run user domain tests
make test-payment # Run payment domain tests
make test-verbose # Run tests with verbose outputmake lint # Run golangci-lint (includes nil detection)
make lint-fix # Run golangci-lint with auto-fix
make lint-verbose # Run golangci-lint with verbose output
make lint-new # Lint only new/changed files
make lint-linter # Run specific linter (LINTER=name)
make lint-nil-info # Show enabled nil detection linters
make format # Format code with go fmt
make format-strict # Format with stricter rules (gofumpt + goimports)make tools # Install development tools (golangci-lint, etc.)
make dev-setup # Setup complete development environment
make deps # Install and tidy dependencies
make clean # Clean build artifactsmake quality # Run comprehensive quality checks
make pre-commit # Run pre-commit checks
make install-hooks # Install pre-commit hooks
make ci # Run CI checks (linting, tests, build)make proto-gen # Generate gRPC code from proto files
make proto-clean # Clean generated proto files
make proto-tools # Install proto generation toolsmake docker-build # Build Docker image
make docker-run # Run Docker containerThe API is fully documented using Swagger/OpenAPI 2.0 with interactive documentation available at runtime.
When the server is running, you can access the interactive API documentation at:
- Swagger UI:
http://localhost:8080/swagger/index.html - Redirect endpoint:
http://localhost:8080/docs(redirects to Swagger UI) - OpenAPI JSON:
http://localhost:8080/swagger/doc.json
# Generate swagger documentation from code annotations
make swagger-gen
# Clean generated swagger files
make swagger-clean
# Install swagger tools
make swagger-toolshttp://localhost:8080/api/v1
GET /health # Server health status
GET /health/ready # Server readiness checkPOST /users # Create user
GET /users # List users (with pagination & filtering)
GET /users/:id # Get user by ID
PUT /users/:id # Update user
DELETE /users/:id # Delete user
PUT /users/:id/password # Update passwordPOST /payments # Create payment
GET /payments # List payments (with filtering & pagination)
GET /payments/:id # Get payment by ID
PUT /payments/:id # Update payment
DELETE /payments/:id # Delete payment
GET /users/:user_id/payments # Get user payments- OpenAPI/Swagger Documentation: Interactive API docs with try-it-out functionality
- Request/Response Validation: Automatic validation using struct tags
- Error Handling: Consistent error responses across all endpoints
- Filtering & Pagination: Query parameter support for list endpoints
- Content Negotiation: JSON request/response format
- Status Codes: RESTful HTTP status codes
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"password": "securepassword"
}'curl -X POST http://localhost:8080/api/v1/payments \
-H "Content-Type: application/json" \
-d '{
"amount": 100.00,
"currency": "USD",
"description": "Test payment",
"user_id": 1
}'The application follows a multi-server architecture where different concerns are separated into independent, deployable servers:
| Server | Purpose | Entry Point | Default Port |
|---|---|---|---|
| API Server | HTTP REST API | main.go |
8080 |
| Worker Server | Background job processing | cmd/worker/main.go |
- |
| Migration Server | Database operations | cmd/migration/main.go |
- |
| gRPC Server | gRPC services (User & Payment) | cmd/grpc/main.go |
9090 |
# Build all servers
make build-all
# Or build individually
make build # API api
make build-worker # Worker api
make build-migration # Migration api
make build-grpc # gRPC api
# Run servers
make run # Start API api
make run-worker # Start worker api
make run-grpc # Start gRPC api
# Database operations
make run-migration # Run migrations
make run-seed # Seed initial data
make run-drop # Drop all tables
# Proto generation
make proto-gen # Generate gRPC code from proto files
make proto-clean # Clean generated proto files
make proto-tools # Install proto generation tools
# Swagger/OpenAPI documentation
make swagger-gen # Generate Swagger/OpenAPI documentation
make swagger-clean # Clean generated swagger files
make swagger-tools # Install swagger generation toolsThe project includes comprehensive linting and code quality tools:
# Primary linting with golangci-lint
make lint # Run golangci-lint
make lint-fix # Run golangci-lint with auto-fix
make lint-verbose # Run golangci-lint with verbose output
make lint-new # Lint only new/changed files
# Specialized linting
make lint-linter LINTER=name # Run specific linter (e.g., LINTER=errcheck)
make lint-security # Security analysis with gosec
make lint-style # Format and style checking
make lint-misspell # Check for spelling errors
# Code formatting
make format # Format code with go fmt
make format-strict # Stricter formatting with gofumpt
# Development tools
make tools # Install all linting toolsSet up automated code quality checks before commits using golangci-lint:
# Install pre-commit hooks
make install-hooks
# Run pre-commit checks manually (golangci-lint + tests)
make pre-commit
# Run comprehensive quality checks
make quality- golangci-lint: Primary comprehensive linter with multiple checkers
- gofmt: Standard Go code formatting
- goimports: Import organization and formatting
- misspell: Spelling error detection
- whitespace: Whitespace formatting
- gocyclo: Cyclomatic complexity analysis
- funlen: Function length checking
- lll: Line length checking
- gosec: Security vulnerability scanner
- ineffassign: Inefficient assignment detection
- staticcheck: Advanced static analysis (via tools target)
# Complete CI pipeline
make ci # Runs linting, tests, and buildsThe gRPC server provides efficient, type-safe APIs for both User and Payment services:
User Service (api/proto/user/user.proto):
CreateUser- Create a new userGetUser- Get user by IDListUsers- List users with paginationUpdateUser- Update user informationDeleteUser- Delete a userUpdateUserPassword- Update user password
Payment Service (api/proto/payment/payment.proto):
CreatePayment- Create a new paymentGetPayment- Get payment by IDListPayments- List payments with filteringUpdatePayment- Update payment informationDeletePayment- Delete a paymentGetUserPayments- Get payments for a specific user
# Install proto tools
make proto-tools
# Generate gRPC code from proto files
make proto-gen
# Clean generated files
make proto-cleanimport (
"google.golang.org/grpc"
"vibe-ddd-golang/api/proto/user"
"vibe-ddd-golang/api/proto/payment"
)
// Connect to gRPC api
conn, err := grpc.Dial("localhost:9090", grpc.WithInsecure())
defer conn.Close()
// Create clients
userClient := user.NewUserServiceClient(conn)
paymentClient := payment.NewPaymentServiceClient(conn)
// Use the services
userResp, err := userClient.CreateUser(ctx, &user.CreateUserRequest{
Name: "John Doe",
Email: "john@example.com",
Password: "securepassword",
})- Independent Scaling: Scale API and Worker servers independently based on load
- Deployment Flexibility: Deploy servers to different environments (API to web tier, workers to background tier)
- Technology Diversity: Each server can use different technologies (HTTP, gRPC, message queues)
- Fault Isolation: Issues in one server don't affect others
- Development Workflow: Developers can work on specific servers without affecting others
- Graceful Shutdown: All servers handle SIGINT/SIGTERM signals for clean shutdown
# Server
SERVER_HOST=localhost
SERVER_PORT=8080
# Database
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=postgres
DATABASE_DB_NAME=vibe_db
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=""
REDIS_DB=0
# Worker
WORKER_CONCURRENCY=10
WORKER_PAYMENT_CHECK_INTERVAL=5m
WORKER_RETRY_MAX_ATTEMPTS=3
# Logging
LOGGER_LEVEL=info
LOGGER_FORMAT=jsonEdit config.yaml with your settings:
server:
host: localhost
port: 8080
read_timeout: 10s
write_timeout: 10s
idle_timeout: 60s
database:
host: localhost
port: 5432
user: postgres
password: postgres
db_name: vibe_db
ssl_mode: disable
redis:
host: localhost
port: 6379
password: ""
db: 0
worker:
concurrency: 10
payment_check_interval: 5m
retry_max_attempts: 3
retry_delay: 30s
logger:
level: info
format: json
output_path: stdout| Job Type | Description | Queue | Retry |
|---|---|---|---|
payment:check_status |
Check payment status with gateway | default |
3x |
payment:process |
Process payment transaction | critical |
3x |
- Critical: High priority jobs (payment processing)
- Default: Normal priority jobs (status checks)
- Low: Background maintenance jobs
- Automatic Retry: Failed jobs retry with exponential backoff
- Graceful Shutdown: Workers complete current jobs before shutdown
- Dead Letter Queue: Failed jobs after max retries
- Job Monitoring: Comprehensive logging and metrics
// Domain module example
var Module = fx.Options(
fx.Provide(
repository.NewPaymentRepository,
service.NewPaymentService,
handler.NewPaymentHandler,
worker.NewPaymentWorker,
),
)// Service handles business logic
func (s *paymentService) CreatePayment(req *dto.CreatePaymentRequest) (*dto.PaymentResponse, error) {
// 1. Validate user exists (cross-domain call)
_, err := s.userService.GetUserByID(req.UserID)
if err != nil {
return nil, errors.New("user not found")
}
// 2. Create payment entity
payment := &entity.Payment{...}
// 3. Save to database
err = s.repo.Create(payment)
// 4. Schedule background job
s.scheduler.SchedulePaymentProcessing(payment.ID)
return s.entityToResponse(payment), nil
}type PaymentRepository interface {
Create(payment *entity.Payment) error
GetByID(id uint) (*entity.Payment, error)
GetAll(filter *dto.PaymentFilter) ([]entity.Payment, int64, error)
Update(payment *entity.Payment) error
Delete(id uint) error
}internal/application/payment/
βββ service/
β βββ payment.service.go
β βββ payment.service_test.go
βββ repository/
β βββ payment.repo.go
β βββ payment.repo_test.go
βββ handler/
βββ payment.handler.go
βββ payment.handler_test.go
# Run all tests
make test
# Run tests with coverage
make test-coverage
# Run specific domain tests
go test ./internal/application/payment/...
# Run with verbose output
go test -v ./...Multi-stage build for production optimization:
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o main .
# Production stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]version: '3.8'
services:
api:
build: .
ports:
- "8080:8080"
environment:
- DATABASE_HOST=postgres
- REDIS_HOST=redis
depends_on:
- postgres
- redis
worker:
build: .
command: ["./worker"]
environment:
- DATABASE_HOST=postgres
- REDIS_HOST=redis
depends_on:
- postgres
- redis
postgres:
image: postgres:15
environment:
POSTGRES_DB: vibe_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
redis:
image: redis:7-alpinemkdir -p internal/application/order/{dto,entity,repository,service,handler,worker}// internal/application/order/module.go
package order
import "go.uber.org/fx"
var Module = fx.Options(
fx.Provide(
repository.NewOrderRepository,
service.NewOrderService,
handler.NewOrderHandler,
worker.NewOrderWorker, // optional
),
)// internal/domain/providers.go
var Module = fx.Options(
user.Module,
payment.Module,
order.Module, // Add new domain
fx.Provide(NewModuleRegistry),
)// internal/application/order/handler/order.handler.go
func (h *OrderHandler) RegisterRoutes(api *gin.RouterGroup) {
orders := api.Group("/orders")
{
orders.POST("", h.CreateOrder)
orders.GET("", h.GetOrders)
// ... more routes
}
}- One domain per directory: Keep related code together
- Interface-driven design: Define interfaces in the domain layer
- Dependency injection: Use fx for clean dependency management
- Error handling: Wrap errors with context
- Logging: Use structured logging throughout
- Migrations: Use GORM auto-migrate or migration tools
- Transactions: Handle transactions in service layer
- Connection pooling: Configure appropriate pool sizes
- Indexing: Add indexes for frequently queried fields
- Input validation: Validate all inputs using DTO bindings
- Password hashing: Use bcrypt for password storage
- SQL injection: Use parameterized queries (GORM handles this)
- CORS: Configure CORS headers appropriately
- Database queries: Use efficient queries and avoid N+1 problems
- Caching: Implement Redis caching for frequently accessed data
- Background jobs: Use workers for heavy processing
- Connection limits: Configure appropriate timeouts and limits
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Follow the domain-driven design patterns
- Add tests for new functionality
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Built with β€οΈ using Go, following Domain-Driven Design principles