# ADR-0030: Service Communication Strategy ## Status Accepted ## Context Services need to communicate with each other in a microservices architecture. All communication must go through well-defined interfaces that support network calls. ## Decision Use a **service client-based communication strategy** with API Gateway as the entry point: 1. **API Gateway** (Entry Point): - All external traffic enters through API Gateway - Gateway routes requests to backend services via service discovery - Gateway handles authentication (JWT validation via Auth Service) - Gateway handles rate limiting, CORS, request transformation 2. **Service Client Interfaces** (Primary for synchronous calls): - Define interfaces in `pkg/services/` for all services - All implementations are network-based: - `internal/services/grpc/client/` - gRPC clients (primary) - `internal/services/http/client/` - HTTP clients (fallback) - Gateway uses service clients to communicate with backend services - Services use service clients for inter-service communication 3. **Event Bus** (Primary for asynchronous communication): - Distributed via Kafka - Preferred for cross-service communication - Event-driven architecture for loose coupling 4. **Shared Infrastructure** (For state): - Redis for cache and distributed state - PostgreSQL instance for persistent data (each service has its own schema) - Kafka for events ## Service Client Pattern ```go // Interface in pkg/services/ type IdentityServiceClient interface { GetUser(ctx context.Context, id string) (*User, error) CreateUser(ctx context.Context, user *User) (*User, error) } // gRPC implementation (primary) type grpcIdentityClient struct { conn *grpc.ClientConn client pb.IdentityServiceClient } // HTTP implementation (fallback) type httpIdentityClient struct { baseURL string httpClient *http.Client } ``` ## Communication Flow ``` Client → API Gateway → Backend Service (via service client) Backend Service → Other Service (via service client) ``` All communication goes through service clients - no direct in-process calls even in development mode. ## Development Mode For local development, services run in the same repository but as separate processes: - Each service has its own entry point (`cmd/{service}/`) - Services communicate via service clients (gRPC or HTTP) - no direct in-process calls - Docker Compose orchestrates all services - This ensures the architecture is consistent with production ## Consequences ### Positive - **Unified Interface**: Consistent interface across all services - **Easy Testing**: Can mock service clients - **Type Safety**: gRPC provides type-safe contracts - **Clear Boundaries**: Service boundaries are explicit - **Scalability**: Services can be scaled independently ### Negative - **Network Overhead**: All calls go over network - **Interface Evolution**: Changes require coordination - **Versioning**: Need service versioning strategy - **Development Complexity**: More setup required for local development ## Implementation - All services use gRPC clients (primary) - HTTP clients as fallback option - Service registry for service discovery - Circuit breakers and retries for resilience