Thank you for your interest in contributing to the Order Service. This document provides guidelines for contributors.
- Code of Conduct
- Getting Started
- Development Setup
- Project Structure
- Making Changes
- Testing
- Submitting Changes
- Style Guide
- Architecture Guidelines
- Release Process
By participating in this project, you agree to maintain a respectful and inclusive environment. We expect all contributors to:
- Be respectful and constructive in discussions
- Welcome newcomers and help them learn
- Focus on what is best for the community
- Show empathy towards other community members
| Tool | Version | Purpose |
|---|---|---|
| Go | 1.26+ | Application build and test |
| Docker | 24+ | Container runtime |
| Docker Compose | v2+ | Multi-container orchestration |
| Make | any | Build automation |
| Git | any | Source control |
| golangci-lint | latest | Code linting |
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/order-service.git
cd order-service- Add the upstream remote:
git remote add upstream https://github.com/telemetryflow/order-service.git# Download Go modules
go mod download
# Configure environment
cp .env.example .env
# Edit .env — set at minimum: DB_PASSWORD, JWT_SECRET
# Start database
docker compose --profile db up -d
# Run migrations
make migrate-up
# Build and run
make run# Health check
curl http://localhost:8080/health
# Generate a token
curl -X POST http://localhost:8080/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"email": "dev@example.com", "role": "admin"}'
# Run tests
make test
# Run linter
make lint
# Build binary
make buildRecommended setup:
- VS Code / Kiro with Go extension (
golang.go) - GoLand by JetBrains
- Vim/Neovim with
goplsLSP
Useful VS Code settings:
{
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--fast"],
"go.formatTool": "goimports",
"editor.formatOnSave": true
}order-service/
├── cmd/
│ └── api/
│ └── main.go # Application entry point
├── internal/
│ ├── domain/ # Domain Layer
│ │ ├── domain.go # Domain types and interfaces
│ │ ├── entity/ # Domain entities (Order, OrderItem)
│ │ └── repository/ # Repository interfaces (contracts)
│ ├── application/ # Application Layer (CQRS)
│ │ ├── command/ # Write operations (Create, Update, Delete)
│ │ ├── query/ # Read operations (Get, List)
│ │ ├── handler/ # Command & Query handlers
│ │ └── dto/ # Data Transfer Objects
│ └── infrastructure/ # Infrastructure Layer
│ ├── config/ # Configuration loading (env, YAML)
│ ├── http/ # HTTP transport
│ │ ├── server.go # Echo server setup
│ │ ├── router.go # Route registration
│ │ ├── handler/ # HTTP handlers (auth, order, swagger, health)
│ │ └── middleware/ # Middleware (JWT auth, CORS, rate limit, logger)
│ └── persistence/ # Database implementations (GORM/PostgreSQL)
├── pkg/ # Shared packages
│ ├── logger/ # Structured logging
│ ├── response/ # HTTP response helpers
│ ├── safefile/ # Safe file operations
│ └── validator/ # Request validation (Echo-compatible)
├── telemetry/ # TelemetryFlow SDK integration
│ ├── init.go # SDK initialization and shutdown
│ ├── logs/ # Log signal configuration
│ ├── metrics/ # Metric signal configuration
│ └── traces/ # Trace signal configuration
├── configs/ # Service configurations
│ ├── config.yaml # Application defaults
│ ├── otel/ # TFO Collector pipeline config
│ ├── prometheus/ # Prometheus scrape config + alerting rules
│ ├── alertmanager/ # Alertmanager routing config
│ ├── grafana/ # Dashboard JSON models
│ └── jaeger/ # Sampling strategies
├── docs/ # Documentation
│ ├── api/ # OpenAPI spec (openapi.yaml, swagger.json)
│ ├── diagrams/ # ERD, DFD (Mermaid)
│ ├── postman/ # Postman collection + environment
│ ├── githooks/ # Git hook scripts
│ └── wiki/ # Wiki pages (Getting Started, Architecture, etc.)
├── tests/ # Tests (external test packages)
│ ├── unit/ # Unit tests (no I/O)
│ │ ├── application/ # Command/query handler tests
│ │ ├── domain/ # Entity and domain logic tests
│ │ ├── infrastructure/ # Middleware, config, HTTP handler tests
│ │ ├── observability/ # Prometheus rule validation tests
│ │ ├── pkg/ # Validator, response helper tests
│ │ └── telemetry/ # SDK initialization tests
│ ├── integration/ # Integration tests (require Docker)
│ │ ├── observability/ # Live Prometheus/Alertmanager queries
│ │ ├── api_test.go # API endpoint integration tests
│ │ └── order_api_test.go # Order CRUD integration tests
│ ├── e2e/ # End-to-end tests
│ ├── mocks/ # Shared mock implementations
│ └── fixtures/ # Test data fixtures
├── migrations/ # Database migration files
├── scripts/ # Utility scripts (hooks, run, test)
├── .github/ # GitHub Actions (CI, Docker, Release)
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Profile-based orchestration (db, app, monitoring, platform, all)
├── docker-compose.prometheus.yml # Prometheus-only compose override
├── Makefile # Build, test, lint, migrate automation
├── .golangci.yml # Linter configuration
├── go.mod # Go module definition
└── go.sum # Dependency checksums
Use descriptive branch names:
feature/add-order-status-historyfix/auth-middleware-public-routesdocs/update-api-documentationrefactor/simplify-order-handlertest/add-integration-coverage
# Sync with upstream
git fetch upstream
git checkout main
git merge upstream/main
# Create feature branch
git checkout -b feature/your-feature-nameFollow conventional commits format:
type(scope): short description
Longer description if needed.
Fixes #123
Types:
| Type | Purpose |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation changes |
test |
Adding or updating tests |
refactor |
Code refactoring |
chore |
Maintenance tasks |
ci |
CI/CD changes |
Examples:
feat(auth): add auto-generated user_id to token endpoint
Remove user_id from request body and auto-generate a UUID
for the JWT claims. Only email and role are now required.
Fixes #45
fix(router): prevent auth middleware from intercepting public routes
Split v1 group into independent v1Public and v1Protected groups
to avoid Echo sub-group middleware bleed.
# Run all unit tests
make test
# Run with verbose output
go test -v ./...
# Run specific package
go test -v ./internal/application/handler/...
# Run integration tests (requires docker stack)
docker compose --profile monitoring up -d
INTEGRATION_TEST=true go test -v -timeout 5m ./tests/integration/...
# Run with coverage
make test-coverage
# Run short tests only (skip integration)
make test-shortGuidelines:
- Use external test packages (
package foo_test) to test the public API surface - Use
testify/assertandtestify/requirefor assertions - Use table-driven tests for multiple cases
- Use
pgregory.net/rapidfor property-based tests - Mock external dependencies via interfaces
Example:
func TestCreateOrder(t *testing.T) {
tests := []struct {
name string
input command.CreateOrderCommand
wantErr bool
}{
{
name: "valid order",
input: command.CreateOrderCommand{CustomerID: uuid.New(), Total: 99.99},
wantErr: false,
},
{
name: "zero total",
input: command.CreateOrderCommand{CustomerID: uuid.New(), Total: 0},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// arrange, act, assert
})
}
}| Directory | Scope | Requires Infrastructure |
|---|---|---|
tests/unit/ |
Pure logic, no I/O | No |
tests/integration/ |
Database, HTTP, Prometheus | Yes (Docker) |
tests/e2e/ |
Full API workflows | Yes (full stack) |
tests/unit/observability/ |
Prometheus rule validation | No (reads YAML files) |
tests/integration/observability/ |
Live Prometheus queries | Yes (monitoring stack) |
# Format code
make fmt
# Run vet
go vet ./...
# Run linter (must pass with 0 issues)
make lint
# Run tests
make test
# Build successfully
make build- Push your branch to your fork:
git push origin feature/your-feature-name-
Create a Pull Request on GitHub
-
Fill in the PR template with:
- Summary of changes
- What was tested
- Related issue numbers
-
Wait for CI to pass and address review feedback
Same format as commit messages:
feat(orders): add order status history tracking
fix(middleware): handle rate limit edge case
docs(wiki): update observability page
- Follow standard Go conventions (
gofmt,goimports) - Use
golangci-lintwith the project's.golangci.ymlconfig - Keep functions short and focused (< 40 lines preferred)
- Return errors, don't panic
| Type | Convention | Example |
|---|---|---|
| Packages | lowercase | handler, middleware, config |
| Interfaces | -er suffix | OrderRepository, Logger |
| Structs | PascalCase | OrderHandler, JWTClaims |
| Functions | PascalCase | NewOrderHandler, CreateToken |
| Variables | camelCase | orderID, httpClient |
| Constants | PascalCase | DefaultTimeout, MaxRetries |
| Files | snake_case | order_handler.go, auth_test.go |
| Test files | _test suffix | order_handler_test.go |
- Always handle errors explicitly
- Wrap errors with context using
fmt.Errorf("...: %w", err) - Use custom error types for domain errors
- Return appropriate HTTP status codes
// Good
if err := repo.Create(ctx, order); err != nil {
return fmt.Errorf("creating order: %w", err)
}
// Bad
repo.Create(ctx, order) // error ignored- Document all exported types, functions, and methods
- Use godoc conventions (comment starts with the name)
- Keep comments concise and useful
// OrderHandler handles HTTP requests for order operations.
type OrderHandler struct {
repo repository.OrderRepository
}
// Create handles POST /api/v1/orders.
func (h *OrderHandler) Create(c echo.Context) error {
// ...
}- Entities (
internal/domain/entity/): Core business objects with identity - Repository Interfaces (
internal/domain/repository/): Define persistence contracts - Value Objects: Immutable types that validate on creation
- Commands (
internal/application/command/): Write operations that change state - Queries (
internal/application/query/): Read operations that return data - Handlers (
internal/application/handler/): Execute commands and queries - DTOs (
internal/application/dto/): Data transfer between layers
HTTP Handler → Application Handler → Domain Entity
→ Repository Interface
↑
Infrastructure (implements)
Dependencies always point inward. Infrastructure implements domain interfaces.
- Define the entity in
internal/domain/entity/ - Define repository interface in
internal/domain/repository/ - Create commands/queries in
internal/application/command/andquery/ - Implement handlers in
internal/application/handler/ - Implement persistence in
internal/infrastructure/persistence/ - Add HTTP handler in
internal/infrastructure/http/handler/ - Register routes in
internal/infrastructure/http/router.go - Write tests in
tests/unit/andtests/integration/ - Update OpenAPI spec in
docs/api/openapi.yamlandswagger.json
Releases follow semantic versioning (SemVer):
- MAJOR: Breaking API changes
- MINOR: New features, backward compatible
- PATCH: Bug fixes, backward compatible
| Workflow | Trigger | Purpose |
|---|---|---|
ci.yml |
Push/PR | Lint, test, build verification |
docker.yml |
Push to main/tags | Build Docker images |
release.yml |
Tags (v*.*.*) | Create GitHub release |
- Update
VERSIONinMakefile - Update version badges in
README.md,CHANGELOG.md,CODE_OF_CONDUCT.md,CONTRIBUTING.md - Add release entry to
CHANGELOG.md - Update
TELEMETRYFLOW_SERVICE_VERSIONindocker-compose.yml,.env.example,configs/config.yaml - Create and push tag:
git tag v1.4.4
git push origin v1.4.4GitHub Actions will automatically:
- Run tests and linter
- Build Docker images
- Create GitHub release with binaries
- Questions: Open a GitHub Discussion
- Bugs: Open a GitHub Issue with the bug template
- Features: Open a GitHub Issue with the feature request template
- Security: Email security@telemetryflow.id (do not open public issues)
Contributors are recognized in:
- GitHub Contributors page
- CHANGELOG.md for significant contributions
Thank you for contributing to the Order Service!
Built with care by the Telemetri Data Indonesia community