. # Repository root
├── .github/ # CI/CD workflows configurations
│ └── workflows/
│ ├── ci.yml # Test and lint pipeline
│ └── cd.yml # Deploy pipeline
├── docs/ # Project documentation
│ ├── architecture.md # General architecture description
│ ├── api.md # REST API documentation
│ └── deployment.md # Deployment and infrastructure guide
├── src/ # Main module source code
│ ├── cmd/ # Entry points (executables)
│ │ ├── api/ # HTTP server
│ │ │ └── main.go # API server initialization
│ │ ├── worker/ # Worker for SQS queue processing
│ │ │ └── main.go # Worker initialization
│ │ └── cli/ # Command line tool
│ │ └── main.go # CLI initialization
│ ├── configs/ # Configuration files (YAML, JSON, TOML)
│ │ ├── config.yaml # Generic configuration
│ │ ├── config.dev.yaml # Development environment configuration
│ │ └── config.prod.yaml # Production environment configuration
│ ├── internal/ # Internal code (not exportable)
│ │ ├── domain/ # Pure domain layer
│ │ │ ├── entities/ # Business entities and models
│ │ │ │ └── order.go # Order struct
│ │ │ │── repositories/ # Abstract repository interfaces
│ │ │ │ └── i_order_repository.go # IOrderRepository contract
│ │ │ ├── services/ # Domain Services (business rules)
│ │ │ │ ├── interfaces/ # Domain Service contracts
│ │ │ │ │ └── i_order_service_domain.go # IOrderServiceDomain contract
│ │ │ │ └── implementations/ # Concrete Domain Service implementations
│ │ │ │ └── order_service_domain.go # Concrete Domain Service
│ │ │ └── valueobjects/ # Value Objects (e.g., Money, Address)
│ │ │ └── money.go # VO for monetary values
│ │ ├── application/ # Use cases and logic orchestration
│ │ │ ├── dto/ # Data Transfer Objects grouped by type
│ │ │ │ ├── requests/ # Request DTOs
│ │ │ │ │ ├── create_order_request.go # CreateOrder request
│ │ │ │ │ └── list_orders_request.go # ListOrders request
│ │ │ │ └── responses/ # Response DTOs
│ │ │ │ ├── create_order_response.go # CreateOrder response
│ │ │ │ └── list_orders_response.go # ListOrders response
│ │ │ ├── interfaces/ # Use Case contracts
│ │ │ │ ├── i_create_order_usecase.go # ICreateOrderUseCase contract
│ │ │ │ └── i_list_orders_usecase.go # IListOrdersUseCase contract
│ │ │ ├── usecases/ # Use Case implementations
│ │ │ │ ├── create_order_usecase.go # CreateOrderUseCase implementation
│ │ │ │ └── list_orders_usecase.go # ListOrdersUseCase implementation
│ │ ├── adapters/ # Input/output adapters
│ │ │ ├── http/ # HTTP/REST adapters
│ │ │ │ ├── handlers/ # Handlers invoking Use Cases
│ │ │ │ │ └── order_handler.go # Concrete REST handler
│ │ │ │ └── router.go # HTTP routing
│ │ │ ├── sqs/ # AWS SQS queue adapters
│ │ │ │ └── order_events.go # SQS event processing
│ │ │ ├── aws_lambda/ # AWS Lambda adapters
│ │ │ │ └── lambda_handler.go # Lambda handler
│ │ │ └── grpc/ # gRPC adapters (optional)
│ │ │ ├── proto/ # .proto files for gRPC
│ │ │ └── server.go # gRPC server
│ │ ├── infrastructure/ # Concrete infrastructure implementations
│ │ │ ├── config/ # Configuration loader
│ │ │ │ └── loader.go # Loads config.yaml files
│ │ │ ├── mongodb/ # MongoDB client and repository
│ │ │ │ ├── client.go # Initializes MongoDB connection
│ │ │ │ └── order_repository.go # Concrete MongoDB repository
│ │ │ ├── aws/ # Generic AWS SDK
│ │ │ │ ├── sqs/ # SQS client/wrapper
│ │ │ │ │ └── client.go # Message enqueueing and consumption
│ │ │ │ └── s3/ # S3 client/wrapper
│ │ │ │ └── client.go # Object upload/download
│ │ │ ├── cache/ # Cache implementation (Redis)
│ │ │ │ └── client.go # Redis client
│ │ │ ├── logger/ # Logger configuration (Zap, Logrus…)
│ │ │ │ └── zap.go # Logger initialization
│ │ │ └── metrics/ # Prometheus instrumentation and metrics
│ │ │ └── prometheus.go # Exposes metrics
│ │── shared/ # Reusable exportable packages
│ │ ├── errors/ # Custom error handling
│ │ │ └── error.go # Common error definitions
│ │ └── utilities/ # Generic helper functions
│ │ └── datetime_util.go # General helpers
├── scripts/ # Auxiliary scripts (migrations, seeds, deploy)
│ ├── migrate.sh # Database migrations via script
│ ├── seed.sh # Populate initial data
│ └── docker-entrypoint.sh # Custom Docker entrypoint
├── migrations/ # Versioned MongoDB migrations
│ └── 20250529_create_orders_collection.js
├── test/ # Automated tests
│ ├── units/ # Unit tests
│ ├── integrations/ # Integration tests (MongoDB, SQS)
├── Makefile # Build, test, lint, run shortcuts
├── Dockerfile # Docker image definition for the application
├── docker-compose.yml # Service orchestration for local dev
├── README.md # Quick start guide and overview
└── go.mod / go.sum # Go module definitions and dependencies
Brief description of the layers:
- .github/workflows/: CI/CD pipelines for lint, tests, and deploy.
- docs/: Architecture, API, and deployment documentation.
- cmd/: Application entry points (e.g., HTTP server, workers, CLI).
- configs/: Configuration files (YAML, JSON).
- internal/domain/: Entities and abstract interfaces without external dependencies.
- internal/application/: Use cases and business logic orchestration.
- internal/adapters/: Input/output adapters (HTTP, SQS, Lambda).
- internal/infrastructure/: Concrete implementations (MongoDB, AWS SQS, AWS S3, logger).
- shared/: General-purpose libraries and utilities.
- scripts/: Auxiliary scripts for database operations and deployment.
- migrations/: Versioned scripts to create/alter MongoDB collections.
- test/: Separates integration and unit tests.
- Makefile: Development workflow conveniences.
- Dockerfile/docker-compose.yml: Containerization and service orchestration.
- go.mod/go.sum: Project dependencies and versioning.
Disclaimer: I know that in Go it's not idiomatic to prefix interface names with 'I', but I prefer to use this pattern because it has always provided me with faster file identification when using my development IDE.
- Protocol isolation: Translates requests (HTTP, SQS, etc.) into the formats expected by use cases without contaminating application with transport details.
- Dependency rule: Outer layers (interfaces) depend on inner layers (application and domain), but not vice versa.
- Flexibility: Allows exposing the same use cases via multiple channels (REST, CLI, Lambda) by creating new adapters without touching business logic.
- Separation of responsibilities: Each layer focuses on its responsibility: pure domain, use case orchestration, and I/O adaptation.
- Testability: Well-isolated adapters make it easier to write unit tests for use cases and domain services by mocking inputs/outputs without raising real HTTP servers, queues, or connections.
The cmd/ convention groups the application entry points. Each subfolder represents a distinct executable:
cmd/
├── api/
│ └── main.go
├── worker/
│ └── main.go
├── cli/
│ └── main.go
In the main.go of cmd/api, for example (example for aws lambda):
package main
import (
"net/http"
"myproject/internal/interfaces/http"
"myproject/internal/infrastructure/config"
"myproject/internal/infrastructure/logger"
)
func main() {
cfg := config.Load()
log := logger.New(cfg.LogLevel)
router := http.NewRouter(log, cfg)
log.Info("Starting API on port: ", cfg.Port)
http.ListenAndServe(":"+cfg.Port, router)
}
- Responsibility: Assemble the application, load configurations, initialize clients (MongoDB, SQS, S3), instantiate handlers, and start the server or worker.
- Inverted dependency: cmd/ imports internal layers, but they must not import cmd/, keeping business logic independent of how it’s executed.