Production‑oriented Go microservices with strict bounded contexts, isolated persistence, event streaming via Kafka, and metrics via Prometheus/Grafana. Each service follows a Clean Architecture layout (usecase → ports → adapters).
- Overview
- Architecture
- Service Map
- Run (Docker)
- Configuration
- Kafka Integration
- Observability
- API Quick Test
- Tests
- Troubleshooting
Services
product-service(port8081) — product CRUD, publishes domain eventscategory-service(port8082) — category CRUD, consumes product eventsuser-service(port8083) — auth + user CRUD, JWT issuer
Infrastructure
- PostgreSQL per service
- Kafka for event streaming
- Prometheus for metrics
- Grafana for dashboards
Repository layout
graph TD
A["services/product"] --> B["internal"]
C["services/category"] --> D["internal"]
E["services/user"] --> F["internal"]
G["shared"] --> B
G --> D
G --> F
Per‑service Clean Architecture
graph TD
A["cmd/api"] --> B["adapters/http"]
B --> C["usecase"]
C --> D["ports"]
E["adapters/postgresql"] --> D
F["adapters/kafka"] --> D
C --> G["domain"]
Event flow
sequenceDiagram
participant Client
participant User as user-service
participant Product as product-service
participant Kafka
participant Category as category-service
Client->>User: POST /auth/login
User-->>Client: JWT
Client->>Product: POST /products (JWT)
Product->>Kafka: product.created
Kafka-->>Category: product.created
Category-->>Category: handle event
| Service | Port | Database | DB Port |
|---|---|---|---|
| product-service | 8081 | product_db | 6433 |
| category-service | 8082 | category_db | 6434 |
| user-service | 8083 | user_db | 6435 |
Kafka UI: http://localhost:8089
Prometheus: http://localhost:9090
Grafana: http://localhost:3000 (admin/admin)
docker compose up --build \
kafka kafka-ui \
product product-db \
category category-db \
user user-db \
prometheus grafanaStop:
docker compose downAll services accept the same config keys:
| Variable | Example | Purpose |
|---|---|---|
DB_HOST |
product-db |
DB host inside compose network |
DB_PORT |
5432 |
DB port |
DB_USER |
postgres |
DB user |
DB_PASSWORD |
postgres |
DB password |
DB_NAME |
product_db |
DB name |
DB_MAX_CONNECTIONS |
10 |
Pool size |
DB_MAX_IDLE_SECONDS |
30 |
Pool idle timeout |
JWT_SECRET |
change-me-in-production |
JWT signing secret (shared) |
KAFKA_BROKERS |
kafka:9092 |
Kafka bootstrap |
Notes
- All services must share the same
JWT_SECRET. KAFKA_BROKERSdefaults tokafka:9092in compose.
Producer
product-servicepublishes to topicproduct.events.- Publish happens after product creation.
Consumer
category-serviceconsumesproduct.events.- Current handler logs messages; extend for projections/cache.
Current event payload
{
"name": "AirFryer",
"price": 1000,
"description": "Digital air fryer",
"discount": 10,
"store": "ABC TECH",
"image_urls": [],
"category_id": 1
}Recommended evolution
- Add envelope fields:
event_type,event_version,occurred_at. - Keep stable schema to avoid breaking consumers.
Metrics endpoints
http://localhost:8081/metricshttp://localhost:8082/metricshttp://localhost:8083/metrics
Prometheus
- Scrapes services using
observability/prometheus.yml.
Grafana
- Add Prometheus datasource:
http://prometheus:9090. - Import dashboards as needed.
Register
curl -X POST http://localhost:8083/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"john","email":"john@test.com","password":"secret123","first_name":"John","last_name":"Doe"}'Login
curl -X POST http://localhost:8083/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username_or_email":"john","password":"secret123"}'Create Category
curl -X POST http://localhost:8082/api/v1/categories \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"name":"Electronics","description":"Devices"}'Create Product
curl -X POST http://localhost:8081/api/v1/products \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"name":"AirFryer","price":1000,"description":"Digital air fryer","discount":10,"store":"ABC TECH","category_id":1}'Verify Kafka event
docker compose logs -f categoryExpected log:
category-service received: {...}
All services:
go test ./services/... -vPer service:
go test ./services/product/... -v
go test ./services/category/... -v
go test ./services/user/... -vKafka fails to start / unhealthy
docker compose down
docker compose up -d kafka kafka-uiEnsure CLUSTER_ID is set in compose.
JWT invalid between services
- All services must share the same
JWT_SECRET.
Prometheus shows DOWN
- Verify services are running and
/metricsendpoints are reachable.
- Build images locally:
docker compose build - Run tests in CI:
go test ./services/... -v - Release strategy: tag a commit and publish images from CI