- Overview
- Architecture
- Features
- Quick Start
- API Documentation
- Development Guide
- Deployment
- Configuration
- Troubleshooting
- Contributing
DTMS is a microservices-based distributed task management system built with Go, gRPC, and PostgreSQL. The system consists of three main services:
- User Service: Manages user operations (CRUD)
- Task Service: Handles task management (CRUD)
- API Gateway: Provides HTTP/REST interface to the gRPC services
The system uses Docker and Docker Compose for containerization and orchestration, making it easy to deploy and scale.
┌─────────────────┐
│ Client/UI │
└────────┬────────┘
│ HTTP/REST
┌────────▼────────┐
│ API Gateway │
│ (Port 8080) │
│ - gRPC-Gateway│
└────────┬────────┘
│ gRPC
┌────────▼────────┐ ┌─────────────────┐
│ User Service │ │ Task Service │
│ (Port 50051) │ │ (Port 50052) │
│ - gRPC Server │ │ - gRPC Server │
└────────┬────────┘ └────────┬────────┘
│ │
┌────────▼────────┐ ┌─────────────────┐
│ PostgreSQL User │ │ PostgreSQL Task │
│ Database │ │ Database │
└─────────────────┘ └─────────────────┘
- Backend: Go 1.22.5
- Communication: gRPC + HTTP/REST (via gRPC-Gateway)
- Database: PostgreSQL
- ORM: GORM
- Containerization: Docker & Docker Compose
- Protocol Buffers: v3
- Health Checks: gRPC Health Checking Protocol
- Create new users with username and email
- Retrieve user information by ID
- Delete users
- List all users
- Unique constraints on username and email
- Create tasks with title and description
- Assign tasks to users
- Retrieve task information
- Delete tasks
- List all tasks
- Health checks for all services
- Docker containerization
- Environment-based configuration
- Auto-migration for database schemas
- UUID-based primary keys
- Timestamp tracking (created_at, updated_at)
- Docker and Docker Compose
- Make utility
- Git
-
Clone the repository
git clone https://github.com/bit-web24/DTMS.git cd DTMS -
Compile Protocol Buffer files
make
This command generates Go code from the .proto files for both services.
-
Configure Environment Variables
Create
.envfile in the root directory:SERVICE_USER_ADDR=user_service SERVICE_TASK_ADDR=task_service
Create
services/user/.env:DB_HOST=postgres_user DB_USER=bittu DB_PASSWORD=bittu DB_NAME=users DB_PORT=5432 DB_SSLMODE=disable DB_TIME_ZONE=UTC RPC_PORT=50051 HTTP_PORT=8081
Create
services/task/.env:DB_HOST=postgres_task DB_USER=bittu DB_PASSWORD=bittu DB_NAME=tasks DB_PORT=5432 DB_SSLMODE=disable DB_TIME_ZONE=UTC RPC_PORT=50052 HTTP_PORT=8082
-
Start the System
sudo docker-compose up --build
This will:
- Build Docker images for all services
- Start PostgreSQL databases
- Initialize databases with required extensions
- Start User and Task services
- Start the API Gateway
-
Verify the System
Check health of services:
# User Service Health curl http://localhost:8081/health # Task Service Health curl http://localhost:8082/health # API Gateway (should list all available endpoints) curl http://localhost:8080/
sudo docker-compose downhttp://localhost:8080
- Endpoint:
POST /v1/users - Request Body:
{ "username": "john_doe", "email": "john@example.com" } - Response:
{ "user": { "id": "uuid-string", "username": "john_doe", "email": "john@example.com" } }
- Endpoint:
GET /v1/users/{id} - Path Parameters:
id: User UUID
- Response:
{ "user": { "id": "uuid-string", "username": "john_doe", "email": "john@example.com" } }
- Endpoint:
DELETE /v1/users/{id} - Path Parameters:
id: User UUID
- Response:
{ "success": true }
- Endpoint:
GET /v1/users - Response:
{ "users": [ { "id": "uuid-string", "username": "john_doe", "email": "john@example.com" } ] }
- Endpoint:
POST /v1/tasks - Request Body:
{ "title": "Complete project documentation", "description": "Write comprehensive documentation for the DTMS project", "user_id": "user-uuid" } - Response:
{ "task": { "id": "uuid-string", "title": "Complete project documentation", "description": "Write comprehensive documentation for the DTMS project", "user_id": "user-uuid" } }
- Endpoint:
GET /v1/tasks/{id} - Path Parameters:
id: Task UUID
- Response:
{ "task": { "id": "uuid-string", "title": "Complete project documentation", "description": "Write comprehensive documentation for the DTMS project", "user_id": "user-uuid" } }
- Endpoint:
DELETE /v1/tasks/{id} - Path Parameters:
id: Task UUID
- Response:
{ "success": true }
- Endpoint:
GET /v1/tasks - Response:
{ "tasks": [ { "id": "uuid-string", "title": "Complete project documentation", "description": "Write comprehensive documentation for the DTMS project", "user_id": "user-uuid" } ] }
DTMS/
├── docs/ # Documentation
├── health/ # Health check utilities
├── initdb/ # Database initialization scripts
├── proto/ # Protocol Buffer definitions
│ ├── google/ # Google API annotations
│ ├── task.proto # Task service definition
│ └── user.proto # User service definition
├── services/ # Microservices
│ ├── task/ # Task service
│ │ ├── Dockerfile
│ │ ├── main.go
│ │ └── proto/ # Generated Go code
│ └── user/ # User service
│ ├── Dockerfile
│ ├── main.go
│ └── proto/ # Generated Go code
├── docker-compose.yml # Docker orchestration
├── Dockerfile # API Gateway Dockerfile
├── go.mod # Go modules
├── go.sum # Go dependencies
├── main.go # API Gateway entry point
└── Makefile # Build automation
-
Define Protocol Buffers
- Create a new .proto file in the
proto/directory - Define your service and messages
- Include Google API annotations for HTTP mapping
- Create a new .proto file in the
-
Update Makefile
- Add your service directory to the Makefile variables
- Update the protoc command to include your .proto file
-
Generate Go Code
make
-
Implement Service
- Create a new directory under
services/ - Implement the gRPC server
- Add health checks
- Create Dockerfile
- Create a new directory under
-
Update Docker Compose
- Add your service to docker-compose.yml
- Configure networking and dependencies
- Add health checks
-
Update API Gateway
- Import your generated package in main.go
- Register your service handler
The system uses GORM's AutoMigrate feature. When you modify your model structs:
- Update the struct definition in your service's main.go
- The migration will run automatically on service startup
For manual migrations:
-- Connect to your database
psql -h localhost -U bittu -d users
-- View tables
\dt
-- View schema
\d users# Run tests for a specific service
cd services/user
go test ./...
cd services/task
go test ./...# Test API endpoints
curl -X POST http://localhost:8080/v1/users \
-H "Content-Type: application/json" \
-d '{"username":"test_user","email":"test@example.com"}'
# Verify response
curl http://localhost:8080/v1/users/{user-id}# View logs for all services
docker-compose logs
# View logs for specific service
docker-compose logs user_service
docker-compose logs task_service
docker-compose logs dtms# User database
docker exec -it dtms_postgres_user_1 psql -U bittu -d users
# Task database
docker exec -it dtms_postgres_task_1 psql -U bittu -d tasks-
Security
- Change default passwords
- Use environment-specific secrets
- Enable SSL/TLS for database connections
- Implement authentication/authorization
-
Scalability
- Use Docker Swarm or Kubernetes for orchestration
- Implement load balancing
- Configure connection pooling
- Add caching layer (Redis)
-
Monitoring
- Implement metrics collection (Prometheus)
- Add distributed tracing (Jaeger)
- Set up alerting
- Configure log aggregation (ELK stack)
-
Data Persistence
- Configure persistent volumes for databases
- Set up regular backups
- Implement disaster recovery
# Use local Docker Compose
docker-compose -f docker-compose.yml up# Use staging configuration
docker-compose -f docker-compose.staging.yml up# Use production configuration with overrides
docker-compose -f docker-compose.yml -f docker-compose.prod.yml upSERVICE_USER_ADDR=user_service # Address of user service
SERVICE_TASK_ADDR=task_service # Address of task serviceDB_HOST=postgres_user # Database host
DB_USER=bittu # Database user
DB_PASSWORD=bittu # Database password
DB_NAME=users # Database name
DB_PORT=5432 # Database port
DB_SSLMODE=disable # SSL mode
DB_TIME_ZONE=UTC # Timezone
RPC_PORT=50051 # gRPC port
HTTP_PORT=8081 # Health check portDB_HOST=postgres_task # Database host
DB_USER=bittu # Database user
DB_PASSWORD=bittu # Database password
DB_NAME=tasks # Database name
DB_PORT=5432 # Database port
DB_SSLMODE=disable # SSL mode
DB_TIME_ZONE=UTC # Timezone
RPC_PORT=50052 # gRPC port
HTTP_PORT=8082 # Health check port- API Gateway: 8080 (HTTP)
- User Service: 50051 (gRPC), 8081 (Health)
- Task Service: 50052 (gRPC), 8082 (Health)
- PostgreSQL User: 5432
- PostgreSQL Task: 5432
service_net: Communication between gateway and servicesuser_net: User service and its databasetask_net: Task service and its database
- Check if ports are in use:
netstat -tulpn | grep :8080 - Check Docker logs:
docker-compose logs
- Verify database is healthy:
docker exec -it dtms_postgres_user_1 pg_isready -U bittu - Check connection string in .env files
- Verify service addresses in docker-compose.yml
- Check network configuration
- Ensure services are healthy before starting gateway
If health checks fail:
- Check if services are running:
docker ps
- Verify health endpoint:
curl http://localhost:8081/health
- Check service logs for errors
If make fails:
- Install protoc:
# Ubuntu/Debian sudo apt-get install protobuf-compiler # macOS brew install protobuf
- Install Go plugins:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
- Ensure $GOPATH/bin is in PATH
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
- Follow Go formatting conventions
- Use meaningful variable names
- Add comments for complex logic
- Keep functions small and focused
- Update documentation for any API changes
- Add/update protocol buffer definitions if needed
- Test with Docker Compose
- Ensure backward compatibility
This project is licensed under the MIT License - see the LICENSE file for details.
For support and questions:
- Create an issue on GitHub
- Check the troubleshooting section
- Review the API documentation