An event-driven microservices platform for an auction system built with Go 1.25.3. Each microservice owns its database and communicates asynchronously via RabbitMQ using a standardized event schema. The architecture emphasizes service isolation, horizontal scalability, and observability.
This is a multi-service monorepo where each service:
- Has a dedicated PostgreSQL database (database-per-service pattern)
- Communicates asynchronously via RabbitMQ with standardized event schemas
- Is independently deployable via Docker Compose
- Routes public traffic through a Traefik API gateway
- Uses JWT-based authentication validated at the gateway level
- Service Isolation: Each service has its own database, Docker network, and independent deployment
- Event-Driven Communication: Services publish/consume events via RabbitMQ with standardized headers (trace IDs, correlation IDs)
- API Gateway Pattern: Traefik handles routing, JWT validation, and request forwarding
- Worker Pattern: Services can split into API and Worker binaries for async processing
- Horizontal Scalability: Workers can be replicated with connection pool tuning
auction/
βββ auction/ # Auction item management (dual-binary: API + Worker)
β βββ cmd/
β β βββ api/ # HTTP REST API
β β βββ worker/ # Event consumer (3 replicas, 20 workers each)
β βββ app/ # Business logic handlers
β βββ domain/ # Domain entities
β βββ internal/ # Private code (middleware, consumers)
β βββ infra/ # Infrastructure (postgres, rabbitmq)
β βββ pkg/ # Shared utilities
βββ identity/ # Authentication & JWT issuance service
β βββ app/ # Registration, login, 2FA handlers
β βββ domain/ # User entity
β βββ internal/ # JWT middleware
β βββ infra/ # Database layer
βββ infra/docker/ # Shared infrastructure
β βββ docker-compose.yaml # RabbitMQ + Traefik
β βββ traefik/ # API gateway routing config
βββ bid/ # (Future) Bid management service
βββ payment/ # (Future) Payment processing service
βββ notification/ # (Future) Notification service
βββ order/ # (Future) Order fulfillment service
βββ CLAUDE.md # Comprehensive development guide
Each service follows the same internal structure:
<service>/
βββ cmd/ # Entry points (main.go for binaries)
βββ app/<domain>/ # HTTP handlers (business logic layer)
βββ domain/ # Domain entities
βββ internal/ # Private code (middleware, consumers)
βββ infra/ # Infrastructure (postgres, rabbitmq)
β βββ postgres/migrations/
βββ pkg/ # Shared utilities (config, events, errors)
βββ docker-compose.yaml # Service-specific orchestration
βββ Dockerfile # Multi-stage build
βββ .env # Environment variables
First, start the RabbitMQ message broker and Traefik API gateway:
docker compose -f infra/docker/docker-compose.yaml up -dThis starts:
- RabbitMQ (AMQP:
localhost:5672, Management UI:http://localhost:15672) - Traefik Gateway (HTTP:
localhost:9191, Dashboard:http://localhost:18080)
Start the Identity service (authentication):
cd identity
docker compose --profile dev upStart the Auction service (API + Worker):
cd auction
docker compose --profile dev up- API Gateway:
http://localhost:9191 - Identity API:
http://localhost:9191/identity/... - Auction API:
http://localhost:9191/api/v1/... - Traefik Dashboard:
http://localhost:18080 - RabbitMQ Management:
http://localhost:15672(guest/guest)
Purpose: User authentication, JWT issuance, TOTP-based two-factor authentication
Key Endpoints:
POST /registerβ Create user accountPOST /loginβ Authenticate and receive JWTGET /meβ Get user profile (requires Bearer token)POST /2fa/enableβ Enable TOTP-based 2FAPOST /2fa/verifyβ Verify OTP and receive recovery codesPOST /2fa/challengeβ Complete 2FA challenge for final access token
Documentation: See identity/README.md
Purpose: Auction item management with event-driven bid processing
Architecture:
- API Binary (
cmd/api/main.go): HTTP REST API for CRUD operations, publishes events - Worker Binary (
cmd/worker/main.go): Consumes bid events, updates item state (3 replicas Γ 20 workers = 60 concurrent processors)
Public Endpoints:
GET /api/v1/itemsβ List all itemsGET /api/v1/items/:idβ Get item by ID
Private Endpoints (requires authentication):
POST /api/v1/itemsβ Create itemPUT /api/v1/items/:idβ Update itemDELETE /api/v1/items/:idβ Delete item
Events:
- Publishes:
item.created.v1,item.updated.v1,item.deleted.v1(toauction.itemexchange) - Consumes:
bid.placed.v1,bid.won.v1(fromauction.bidexchange)
Documentation: See auction/README.md
All services use a standardized event schema:
type Event struct {
Event string // e.g., "item.created"
Version string // e.g., "v1"
Timestamp time.Time
Payload interface{} // Domain-specific data
TraceID string // Distributed tracing
CorrelationID string // Request correlation
}- Exchange:
auction.{domain}(e.g.,auction.item,auction.bid) - Routing Key:
{domain}.{event}.{version}(e.g.,item.created.v1) - Queue:
{consumer-service}.{event}.{version}(e.g.,payment.item.created.v1) - Dead Letter Queue:
{queue}.dlq
All events include RabbitMQ headers:
x-trace-id: Distributed tracing IDx-correlation-id: Request correlation IDx-service: Publishing service name
Traefik acts as the API gateway with:
- JWT validation middleware: Validates tokens via Identity service
- Automatic header injection: Adds
X-User-Id,X-User-Emailfor downstream services - Request routing: Routes
/identity/*and/api/*to respective services
Configuration files:
infra/docker/traefik/traefik.yamlβ Static config (entrypoints, providers)infra/docker/traefik/gateway.yamlβ Dynamic routing rules
Auction API:
cd auction
POSTGRES_HOST=localhost \
POSTGRES_PORT=5433 \
RABBITMQ_URL=amqp://guest:guest@localhost:5672/ \
SERVICE_NAME=auction \
PORT=8080 \
go run cmd/api/main.goAuction Worker:
cd auction
POSTGRES_HOST=localhost \
POSTGRES_PORT=5433 \
RABBITMQ_URL=amqp://guest:guest@localhost:5672/ \
SERVICE_NAME=auction \
go run cmd/worker/main.goIdentity Service:
cd identity
POSTGRES_HOST=localhost \
POSTGRES_PORT=5432 \
JWT_SECRET=your-secret-key \
PORT=8080 \
go run main.go# Run tests for a specific service
cd auction # or identity
go test ./...
# Run tests with verbose output
go test -v ./...
# Run a specific package
go test -v ./app/itemMigrations are automatically applied on container startup via PostgreSQL's docker-entrypoint-initdb.d.
Location: <service>/infra/postgres/migrations/
Reset database:
cd auction # or identity
docker compose down -v
docker compose up-
Scaffold directory structure:
mkdir <service-name> cd <service-name> go mod init auction # Use "auction" module name
-
Copy structure from existing service:
- Use
identity/as template for HTTP-only services - Use
auction/as template for services with event consumers
- Use
-
Create
docker-compose.yaml:- Add dedicated PostgreSQL container (
<service>-postgres) - Join
auction-rabbitmq-networkandauction-traefik-network - Mount migrations to
/docker-entrypoint-initdb.d
- Add dedicated PostgreSQL container (
-
Define database migrations in
infra/postgres/migrations/ -
Add Traefik routes in
infra/docker/traefik/gateway.yaml -
Start the service:
docker compose --profile dev up
Example: See CLAUDE.md for detailed step-by-step instructions
Worker services log connection pool stats every 30 seconds:
docker compose logs -f auction-worker | grep "pool stats"Alert if wait_count > 0 (indicates DB connection bottleneck)
# RabbitMQ
docker exec auction-rabbitmq rabbitmq-diagnostics -q ping
# PostgreSQL
docker exec auction-postgres pg_isready -U postgres
# View active DB connections
docker exec auction-postgres psql -U postgres -d auction \
-c "SELECT count(*) FROM pg_stat_activity WHERE datname='auction';"All events include TraceID and CorrelationID for request tracing across services. Use these IDs to correlate logs:
# Find all logs for a specific trace
docker compose logs | grep "trace-id-12345"All services use Viper for configuration. Settings are loaded from:
config/config.yaml(default values)- Environment variables (override YAML, auto-uppercased)
# Server
PORT=8080 # HTTP listener port
# Database
POSTGRES_HOST=<service>-postgres
POSTGRES_PORT=5432
POSTGRES_DATABASE=auction
POSTGRES_USERNAME=postgres
POSTGRES_PASSWORD=postgres
# Message Broker
RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/
SERVICE_NAME=<service-name>
# Identity-specific
JWT_SECRET=your-secret-key- Comprehensive Development Guide:
CLAUDE.md - Infrastructure Setup:
infra/README.md - Identity Service:
identity/README.md - Auction Service:
auction/README.md
- Auction API:
8081 - Identity API:
8080 - Auction Postgres:
5433 - Identity Postgres:
5432 - RabbitMQ AMQP:
5672 - RabbitMQ Management:
15672 - Traefik Gateway:
9191 - Traefik Dashboard:
18080
# Recreate networks
docker compose -f infra/docker/docker-compose.yaml down
docker compose -f infra/docker/docker-compose.yaml up -d# Check worker logs
docker compose logs -f auction-worker
# Verify RabbitMQ connectivity
docker exec auction-rabbitmq rabbitmqctl list_queuesThis is an internal educational project demonstrating microservices architecture patterns.
This documentation was generated with assistance from Claude Code, an AI-powered development assistant.