Thank you for your interest in contributing to Datum! This document provides guidelines and instructions for contributing to the project.
- Be respectful and inclusive
- Welcome newcomers and help them get started
- Focus on constructive feedback
- Respect differing viewpoints and experiences
Before creating bug reports, please check existing issues. When creating a bug report, include:
Required Information:
- Clear, descriptive title
- Steps to reproduce the issue
- Expected behavior vs actual behavior
- Environment details (OS, Go version, Docker version if applicable)
- Relevant logs or error messages
- Screenshots if applicable
Example:
## Bug: Data ingestion fails with large payloads
**Environment:**
- OS: Ubuntu 22.04
- Go Version: 1.21.5
- Server Version: 1.0.0
**Steps to Reproduce:**
1. Send POST request to `/dev/data` with 10MB payload
2. Server returns 413 error
**Expected:** Data should be accepted up to 16MB
**Actual:** Request rejected at 10MB
**Logs:**
[error] payload size exceeds limitFeature suggestions are welcome! Please:
- Check existing feature requests first
- Provide clear use case and rationale
- Describe proposed API/interface changes
- Consider backward compatibility
- Discuss implementation approach if possible
- Go 1.21 or higher
- Git
- Make (optional but recommended)
- Docker and Docker Compose (for integration tests)
# 1. Fork and clone
git clone https://github.com/YOUR_USERNAME/datum-server.git
cd datum-server
# 2. Install dependencies
go mod download
# 3. Run tests
make test
# 4. Run server locally
make run
# 5. Verify installation
curl http://localhost:8000/health# Create feature branch
git checkout -b feature/my-new-feature
# Make changes and test frequently
go test ./...
# Format code
make fmt
# Run linters
make lint
# Build
make buildFollow official Go Code Review Comments and these project-specific guidelines:
Naming Conventions:
- Use descriptive names:
getUserByIDnotgetUsr - Interfaces:
StorageProvidernotIStorage - Test files:
module_test.goormodule_feature_test.go - No "coverage", "boost", "wins" in test file names
Code Organization:
// Package declaration and imports
package storage
import (
"context"
"errors"
"datum-go/internal/types"
)
// Constants and variables
const (
DefaultTimeout = 30 * time.Second
)
// Types
type Storage struct {
db *buntdb.DB
}
// Constructor
func New(path string) (*Storage, error) {
// implementation
}
// Methods (receiver, name, parameters, returns)
func (s *Storage) GetDevice(ctx context.Context, id string) (*types.Device, error) {
// implementation
}Error Handling:
// Good: Descriptive errors with context
if err != nil {
return fmt.Errorf("failed to create device %s: %w", deviceID, err)
}
// Bad: Generic error without context
if err != nil {
return err
}Comments:
// Good: Explains why, not what
// Use exponential backoff to avoid overwhelming the database
// during recovery from connection failures
func (s *Storage) retryOperation() error {
// Bad: States the obvious
// This function retries an operation
func (s *Storage) retryOperation() error {datum-server/
├── cmd/
│ ├── server/ # HTTP server and handlers
│ │ ├── main.go
│ │ ├── admin.go
│ │ ├── handlers_*.go
│ │ └── *_test.go
│ └── datumctl/ # CLI tool
│ └── main.go
├── internal/
│ ├── auth/ # Authentication & authorization
│ ├── storage/ # Data storage layer
│ └── logger/ # Logging utilities
├── docs/ # Documentation
├── examples/ # Integration examples
└── tests/ # Integration and load tests
- Minimum 60% coverage for new packages
- Handler tests for all new HTTP endpoints
- Integration tests for critical workflows
- Edge cases and error scenarios
Test File Naming:
handlers_data_test.go ✅ Good: Descriptive, clear scope
handlers_admin_extended_test.go ✅ Good: Extended tests for admin
critical_boost_test.go ❌ Bad: Vague, uses "boost"
coverage_test.go ❌ Bad: Too generic
Test Function Naming:
// Good: Descriptive test names
func TestGetDataHistoryHandlerWithRFC3339Times(t *testing.T)
func TestCreateUserHandlerDuplicateEmail(t *testing.T)
func TestRateLimiterExceedsLimit(t *testing.T)
// Bad: Vague or generic names
func TestHandler1(t *testing.T)
func TestError(t *testing.T)
func TestSuccess(t *testing.T)Test Structure:
func TestCreateDevice(t *testing.T) {
// Setup
store, cleanup := setupTestStorage(t)
defer cleanup()
user := createTestUser(t, store)
// Execute
device, err := store.CreateDevice(&storage.Device{
UserID: user.ID,
Name: "Test Device",
Type: "sensor",
})
// Assert
require.NoError(t, err)
assert.NotEmpty(t, device.ID)
assert.NotEmpty(t, device.APIKey)
assert.Equal(t, "Test Device", device.Name)
// Verify persistence
retrieved, err := store.GetDevice(device.ID)
require.NoError(t, err)
assert.Equal(t, device.ID, retrieved.ID)
}Run Tests:
# All tests
go test ./...
# Specific package
go test ./internal/storage
# With coverage
go test -cover ./...
# Verbose output
go test -v ./cmd/server
# Specific test
go test -v ./cmd/server -run TestCreateDevice
# Benchmarks
go test -bench=. ./internal/storage- Tests pass:
go test ./... - Code formatted:
make fmt - Linters pass:
make lint - Documentation updated (if applicable)
- CHANGELOG.md updated (if user-facing change)
- Commit messages follow conventions
type(scope): brief description
Detailed explanation of the change, including:
- Why the change is needed
- What was changed
- Any breaking changes or migration notes
Fixes #123
Types:
feat: New featurefix: Bug fixdocs: Documentation changestest: Adding or updating testsrefactor: Code refactoringperf: Performance improvementschore: Maintenance tasks
Examples:
feat(storage): add batch insert support for time-series data
Implements batch insertion to improve write performance by reducing
individual database transactions. Benchmark shows 3x improvement.
Closes #45
---
fix(auth): prevent race condition in rate limiter
The token bucket implementation had a race condition when multiple
goroutines accessed the same user's rate limit counter. Added mutex
protection to ensure thread-safety.
Fixes #67
---
docs(api): add examples for data aggregation endpoints
Added curl examples and response samples for all aggregation types
(avg, sum, min, max) to improve API documentation clarity.
When submitting a PR, ensure:
- Title: Clear, descriptive (
feat: add webhook supportnotupdates) - Description:
- What changed and why
- Link to related issues
- Screenshots/recordings if UI changes
- Breaking changes clearly marked
- Size: Keep PRs focused and reasonably sized
- Tests: Include tests for new functionality
- Docs: Update relevant documentation
- Review: Address review comments promptly
## Description
Brief description of what this PR does.
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Related Issues
Fixes #(issue number)
## Testing
- [ ] All tests pass
- [ ] Added new tests
- [ ] Manual testing completed
## Documentation
- [ ] Updated API docs
- [ ] Updated README
- [ ] Updated code comments
## Screenshots (if applicable)
[Add screenshots here]
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-reviewed my own code
- [ ] Commented complex logic
- [ ] Updated documentation
- [ ] No new warnings generated
- [ ] Added tests that prove fix/feature works
- [ ] New and existing tests passUpdate documentation when you:
- Add new features or APIs
- Change existing behavior
- Add configuration options
- Modify command-line flags
- Change deployment procedures
- README.md: Quick start and overview
- docs/guides/: Step-by-step guides
- docs/tutorials/: Hands-on tutorials
- docs/reference/: Technical reference
- Code comments: Explain complex logic
// 1. Define in appropriate file (admin.go, main.go, etc.)
func newFeatureHandler(c *gin.Context) {
// Implement handler
}
// 2. Add tests in handlers_<module>_test.go
func TestNewFeatureHandler(t *testing.T) {
// Test implementation
}
// 3. Update OpenAPI spec (openapi.yaml)
// 4. Update docs/reference/API.md// 1. Add method to storage interface
type Storage interface {
// Existing methods...
NewMethod(params) (result, error)
}
// 2. Implement in storage.go
func (s *Storage) NewMethod(params) (result, error) {
// Implementation
}
// 3. Add tests in storage_test.go
func TestNewMethod(t *testing.T) {
// Test cases
}- Version bump: Update version in relevant files
- CHANGELOG: Document all changes
- Testing: Full test suite + manual verification
- Tag:
git tag -a v1.0.0 -m "Release v1.0.0" - Push:
git push origin v1.0.0 - Build: Create release binaries
- Announce: Update documentation and notify users
New contributors should look for issues labeled:
good first issue- Easy to start withdocumentation- Improve docstesting- Add test coveragehelp wanted- Need assistance
- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: General questions and ideas
- Pull Requests: Code review and discussion
If you have questions:
- Check existing documentation
- Search closed issues
- Open a discussion on GitHub
- Ask in pull request if code-related
Thank you for contributing to Datum IoT Platform! 🙏