This project is a scaffold for a full-stack application using Go (with Gin framework) for the backend, PostgreSQL as the database, and Redis for caching/session management.
It includes Docker setup for containerization and Docker Compose for orchestrating services.
- Architecture: Designed following Clean Architecture, Domain-Driven Design (DDD), and CQRS principles for a scalable and maintainable structure.
- User Management: Full CRUD (Create, Read, Update, Delete) and List (with cursor-based pagination) operations for users.
- Backend API: Built with Go and Gin.
- Database: PostgreSQL with
pgxdriver. - ORM/Query Builder:
sqlcfor generating type-safe Go code from SQL queries. - Database Migrations:
golang-migrate/migratefor managing database schema changes. - Caching: Redis for caching user data to reduce database load.
- Testing:
- Unit Tests: Comprehensive unit tests for CQRS command/query handlers using
testify/mock. Build-tagged asunit. - Integration Tests:
testcontainers-goused for testing database (PostgreSQL) and cache (Redis) adapters in an isolated, production-like environment. Build-tagged asintegration.
- Unit Tests: Comprehensive unit tests for CQRS command/query handlers using
- Configuration: Environment variable-based configuration loading.
- Containerization:
- Multi-stage
Dockerfilefor development (with Air for live reload, Delve for debugging) and production. compose.ymlto run the application, PostgreSQL, and Redis together.- Entrypoint script (
scripts/entrypoint.sh) for the production container to check DB connection and run migrations.
- Multi-stage
- Live Reloading:
.air.tomlconfigured for development.
. ├── cmd/server/main.go # Application entry point ├── config/ # Configuration loading ├── db/ │ ├── migration/ # Database migration files (.sql) │ ├── queries/ # SQL queries for sqlc │ └── sqlc/ # Generated Go code by sqlc ├── internal/ │ └── user/ │ ├── adapters/ │ │ ├── cache/ # Cache adapter (e.g., Redis) │ │ ├── database/ # Repository adapter (e.g., Postgres) │ │ └── http/ # HTTP handlers (Gin) │ ├── app/ # Application service layer (CQRS handlers) │ ├── domain/ # Core domain entities and business logic │ └── ports/ # Interfaces (ports) for driven adapters ├── scripts/ │ └── entrypoint.sh # Docker entrypoint script for prod ├── .air.toml # Air configuration for live reload ├── Dockerfile # Docker build instructions ├── compose.yml # Docker Compose configuration ├── go.mod # Go module definition ├── sqlc.yaml # sqlc configuration └── README.md # This file - Docker Desktop (or Docker Engine + Docker Compose)
- Go (version 1.24+ for local development if not using Docker exclusively)
- Make (optional, for Makefile commands if added in the future)
git clone <your-repository-url> cd <your-project-directory>Copy the example environment file and customize it if necessary:
cp .env.example .envThis command builds the production-ready image and starts all services (app, db, redis). The entrypoint script will automatically run database migrations.
docker compose up --buildThe application will be accessible at http://localhost:${APP_PORT} (default: http://localhost:8080).
For development, you can use the dev override compose file to enable live reloading with Air.
docker compose -f compose.yml -f compose.dev.yml up --buildChanges to Go files (and other specified extensions in .air.toml) will trigger an automatic rebuild and restart of the application.
Similarly, for debugging with Delve, you can use the debug override compose file to enable delve debugger with breakpoints.
docker compose -f compose.yml -f compose.debug.yml up --buildYou can then attach your Go IDE's debugger to localhost:2345.
Migration files are located in db/postgres/migration/. The migrate CLI tool is included in the Docker images (dev-common and prod stages).
To create a new migration file (e.g., add_new_feature), run the following command locally if you have migrate installed, or execute it inside a running app container:
migrate create -ext sql -dir db/postgres/migration -seq add_new_featuredocker compose exec app migrate create -ext sql -dir /app/db/postgres/migration -seq add_new_featureThis will create two files in db/postgres/migration/ (e.g., 00000X_add_new_feature.up.sql and 00000X_add_new_feature.down.sql). Edit these files to define your schema changes.
The entrypoint.sh script in the prod target automatically runs migrate ... up on container startup. However, you can run migrations manually against the database service managed by Docker Compose.
Ensure your .env file is configured, especially DB_URL (or POSTGRES_URL from which DB_URL is derived for the entrypoint). The migrate command inside the container will use the DB_URL environment variable.
- Apply all pending up migrations:
docker compose exec app migrate -path /app/db/postgres/migration -database "$DB_URL" up
- Rollback the last down migration:
docker compose exec app migrate -path /app/db/postgres/migration -database "$DB_URL" down 1
- Migrate to a specific version:
docker compose exec app migrate -path /app/db/postgres/migration -database "$DB_URL" goto VERSION_NUMBER
- Force a specific version (useful for fixing dirty state):
docker compose exec app migrate -path /app/db/postgres/migration -database "$DB_URL" force VERSION_NUMBER
sqlc generates Go code from your SQL queries located in db/postgres/queries/. The sqlc CLI is included in the Docker images. Configuration is in sqlc.yaml.
After making changes to your SQL queries in db/postgres/queries/ or updating sqlc.yaml, you need to regenerate the Go code.
docker compose exec app sqlc generateThe generated Go files will be placed in db/postgres/sqlc/ as specified in sqlc.yaml. Remember to commit these generated files to your repository.
The project uses Go's build tags to separate unit and integration tests.
Unit tests mock all external dependencies and can be run without any services.
go test -tags=unit ./... -vIntegration tests require Docker to be running, as they spin up testcontainers for PostgreSQL and Redis.
go test -tags=integration ./... -vTo run both unit and integration tests:
go test -tags="unit,integration" ./... -vFull CRUD and List endpoints are implemented for users (base path /api/v1):
POST /users: Create a new user.GET /users/:id: Get a user by their ID.GET /users: List users with cursor-based pagination (e.g.,?limit=10&after=CURSOR).PUT /users/:id: Update a user's details.DELETE /users/:id: Delete a user.
- Add authentication (e.g., JWT).
- Implement authorization/roles.
- Add more services and features.
- Set up CI/CD pipeline.
- Improve error handling and logging.