553 lines
17 KiB
Markdown
553 lines
17 KiB
Markdown
# Service Template Architecture
|
|
|
|
This document describes the architecture of a single microservice built from this template and how it integrates with the GoodGo microservices platform.
|
|
|
|
## Overview
|
|
|
|
This template provides a complete, production-ready foundation for building individual microservices with:
|
|
|
|
- **Security**: Authentication, authorization, input validation, and security headers
|
|
- **Observability**: Comprehensive logging, metrics, tracing, and health checks
|
|
- **Data Management**: Repository pattern, database migrations, and seeding
|
|
- **API Documentation**: OpenAPI/Swagger documentation with interactive UI
|
|
- **Error Handling**: Structured error responses with proper HTTP status codes
|
|
- **Docker Support**: Multi-stage builds and production optimization
|
|
|
|
**Important Context**: This template represents a **single microservice**. For platform-level deployment and orchestration, services are registered in `deployments/local/docker-compose.yml` and routed through the Traefik API Gateway configured in `infra/traefik/`.
|
|
|
|
---
|
|
|
|
# Part 1: Single Service Architecture (Internal)
|
|
|
|
This section describes the internal architecture of a single microservice built from this template.
|
|
|
|
## Internal Service Components
|
|
|
|
```mermaid
|
|
graph TD
|
|
Request[HTTP Request] -->|From Traefik| Middleware[Middleware Chain]
|
|
|
|
subgraph SingleService[Single Service Boundary]
|
|
Middleware --> Correlation[Correlation ID Middleware]
|
|
Correlation --> Auth[Authentication Middleware]
|
|
Auth --> Validation[Validation Middleware]
|
|
Validation --> Error[Error Handler]
|
|
Error --> Logger[Request Logger]
|
|
Logger --> Metrics[Metrics Collector]
|
|
|
|
Metrics --> Router[Router Layer]
|
|
Router --> Controller[Controller Layer]
|
|
Controller --> Service[Service Layer]
|
|
Service --> Repository[Repository Layer]
|
|
|
|
Repository --> Database[(PostgreSQL)]
|
|
Service --> Cache[(Redis)]
|
|
|
|
Service -.->|Health Status| Health[Health Checks]
|
|
Service -.->|API Docs| OpenAPI[OpenAPI/Swagger]
|
|
end
|
|
|
|
Service -.->|Metrics| Prometheus[Prometheus]
|
|
Service -.->|Traces| Jaeger[Jaeger]
|
|
|
|
style Correlation fill:#e1f5fe
|
|
style Auth fill:#f3e5f5
|
|
style Validation fill:#e8f5e8
|
|
style Error fill:#fff3e0
|
|
style Logger fill:#f3e5f5
|
|
style Metrics fill:#e8f5e8
|
|
```
|
|
|
|
## Layer Architecture
|
|
|
|
### Middleware Chain
|
|
|
|
The middleware chain processes every incoming request in order:
|
|
|
|
1. **Correlation Middleware**: Generates/propagates correlation and request IDs
|
|
2. **Authentication Middleware**: Validates JWT tokens (optional for public routes)
|
|
3. **Validation Middleware**: Sanitizes and validates input data with Zod schemas
|
|
4. **Error Handler**: Catches and formats errors into structured responses
|
|
5. **Logger Middleware**: Logs request/response with correlation IDs
|
|
6. **Metrics Middleware**: Collects Prometheus metrics (duration, status, payload size)
|
|
|
|
### Controller Layer
|
|
|
|
- Handles HTTP requests and responses
|
|
- Orchestrates service layer calls
|
|
- Formats API responses
|
|
- Wraps async handlers for error propagation
|
|
|
|
### Service Layer
|
|
|
|
- Contains pure business logic
|
|
- Independent of HTTP transport
|
|
- Orchestrates repository calls
|
|
- Implements caching strategies
|
|
- Throws domain-specific errors
|
|
|
|
### Repository Layer
|
|
|
|
- Abstracts database operations
|
|
- Uses Prisma ORM for type-safe queries
|
|
- Implements repository pattern
|
|
- Provides consistent error handling
|
|
- Supports transactions
|
|
|
|
## Request Flow
|
|
|
|
1. **Request Entry**:
|
|
- Client sends HTTP request to ingress/load balancer
|
|
- Request includes optional correlation ID header (`x-correlation-id`)
|
|
|
|
2. **Correlation Middleware**:
|
|
- Generates or propagates correlation ID for request tracing
|
|
- Adds request ID for unique request identification
|
|
- Sets correlation headers on response
|
|
|
|
3. **Security Middleware**:
|
|
- **Authentication**: Validates JWT tokens (optional for public routes)
|
|
- **Authorization**: Checks user roles and permissions
|
|
- **Rate Limiting**: Prevents abuse with Redis-backed rate limiting
|
|
- **Helmet**: Secures HTTP headers
|
|
|
|
4. **Validation Middleware**:
|
|
- Sanitizes input data (trimming, normalization)
|
|
- Validates request data using Zod schemas
|
|
- Returns structured validation errors
|
|
|
|
5. **Router & Controller**:
|
|
- Routes request to appropriate controller
|
|
- Controller orchestrates business logic execution
|
|
- Input validation and response formatting
|
|
|
|
6. **Service Layer**:
|
|
- Contains pure business logic
|
|
- Independent of HTTP transport layer
|
|
- Orchestrates data access and external service calls
|
|
|
|
7. **Repository Layer**:
|
|
- Implements repository pattern for data access
|
|
- Abstracts database operations with Prisma ORM
|
|
- Provides consistent error handling
|
|
|
|
8. **Response & Observability**:
|
|
- Formats structured JSON responses
|
|
- Records comprehensive metrics (duration, errors, payload sizes)
|
|
- Logs with correlation IDs for distributed tracing
|
|
- Sends traces to Jaeger if enabled
|
|
|
|
## Architecture Patterns
|
|
|
|
### Repository Pattern
|
|
|
|
```typescript
|
|
// Base repository with common CRUD operations
|
|
class BaseRepository<T, CreateInput, UpdateInput> {
|
|
async findById(id: string): Promise<T | null>
|
|
async create(data: CreateInput): Promise<T>
|
|
async update(id: string, data: UpdateInput): Promise<T>
|
|
// ... more common methods
|
|
}
|
|
|
|
// Specific repository extends base
|
|
class FeatureRepository extends BaseRepository<Feature, CreateFeatureInput, UpdateFeatureInput> {
|
|
async findByName(name: string): Promise<Feature | null>
|
|
async findByTags(tags: string[]): Promise<Feature[]>
|
|
// ... feature-specific methods
|
|
}
|
|
```
|
|
|
|
### Middleware Chain
|
|
|
|
```typescript
|
|
// Request processing pipeline
|
|
app.use(correlationMiddleware()); // Add correlation IDs
|
|
app.use(authenticate()); // JWT validation
|
|
app.use(authorize('admin')); // Role checking
|
|
app.use(validateDto(schema)); // Input validation
|
|
app.use(errorHandler); // Error handling
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
```typescript
|
|
// Custom error classes
|
|
class NotFoundError extends HttpError {
|
|
constructor(resource: string) {
|
|
super(`${resource} not found`, 404, 'NOT_FOUND');
|
|
}
|
|
}
|
|
|
|
// Usage in services
|
|
if (!feature) {
|
|
throw new NotFoundError('Feature');
|
|
}
|
|
```
|
|
|
|
### Dependency Injection
|
|
|
|
```typescript
|
|
// Constructor injection for testability
|
|
export class FeatureService {
|
|
constructor(private repository: IRepository<Feature>) {}
|
|
|
|
async create(data: CreateFeatureInput): Promise<Feature> {
|
|
return this.repository.create(data);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Code Organization
|
|
|
|
- **Separation of Concerns**: Clear boundaries between layers (Controller → Service → Repository)
|
|
- **Single Responsibility**: Each class/method has one clear purpose
|
|
- **Dependency Injection**: Constructor injection for better testability
|
|
- **Error Boundaries**: Proper error handling at each layer
|
|
|
|
### Security
|
|
|
|
- **Input Validation**: All inputs validated with Zod schemas
|
|
- **Authentication**: JWT tokens with proper expiration
|
|
- **Authorization**: Role-based access control (RBAC)
|
|
- **Rate Limiting**: Distributed rate limiting with Redis
|
|
- **Security Headers**: Helmet.js for HTTP security headers
|
|
|
|
### Observability
|
|
|
|
- **Structured Logging**: Consistent log format with correlation IDs
|
|
- **Metrics**: Comprehensive Prometheus metrics
|
|
- **Tracing**: Distributed tracing with Jaeger
|
|
- **Health Checks**: Liveness and readiness probes
|
|
- **Correlation IDs**: Request tracing across service boundaries
|
|
|
|
### Error Handling
|
|
|
|
- **Custom Error Classes**: Specific error types for different scenarios
|
|
- **HTTP Status Mapping**: Proper status codes for different error types
|
|
- **Structured Responses**: Consistent error response format
|
|
- **Operational Errors**: Clear distinction between programming and operational errors
|
|
|
|
### Testing
|
|
|
|
- **Unit Tests**: Test individual functions and classes
|
|
- **Integration Tests**: Test component interactions
|
|
- **E2E Tests**: Test complete request/response cycles
|
|
- **Test Utilities**: Shared test helpers and mocks
|
|
- **Coverage Goals**: >70% code coverage target
|
|
|
|
### Docker & Deployment
|
|
|
|
- **Multi-stage Builds**: Optimized for production image size
|
|
- **Security**: Non-root users, minimal attack surface
|
|
- **Health Checks**: Container health monitoring
|
|
- **Compose Files**: Development, testing, and production configurations
|
|
- **Resource Limits**: Proper CPU and memory constraints
|
|
|
|
## Configuration Management
|
|
|
|
### Environment Variables
|
|
|
|
- **Typed Configuration**: Zod schemas for env validation
|
|
- **Default Values**: Sensible defaults for development
|
|
- **Override Support**: `.env.local` overrides `.env`
|
|
- **Documentation**: Comprehensive env variable documentation
|
|
|
|
### Feature Flags
|
|
|
|
- **Runtime Configuration**: Database-backed feature flags
|
|
- **Admin Control**: Admin API for feature management
|
|
- **Gradual Rollout**: Enable/disable features without deployment
|
|
- **Audit Trail**: Track feature flag changes
|
|
|
|
## API Design
|
|
|
|
### RESTful Conventions
|
|
|
|
- **Resource Naming**: Plural nouns for resource endpoints
|
|
- **HTTP Methods**: GET, POST, PUT, DELETE, PATCH appropriately
|
|
- **Status Codes**: Proper HTTP status codes for all responses
|
|
- **Content Negotiation**: JSON responses with proper content-type
|
|
|
|
### Response Format
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": { ... },
|
|
"message": "Operation completed successfully",
|
|
"timestamp": "2024-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
### Error Responses
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Validation failed",
|
|
"details": [...]
|
|
},
|
|
"timestamp": "2024-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
## Development Workflow
|
|
|
|
### Local Development
|
|
|
|
1. **Setup Infrastructure**: `docker-compose up -d`
|
|
2. **Install Dependencies**: `pnpm install`
|
|
3. **Database Setup**: `pnpm prisma migrate dev && pnpm prisma db seed`
|
|
4. **Start Development**: `pnpm dev`
|
|
5. **Run Tests**: `pnpm test`
|
|
|
|
### Testing Strategy
|
|
|
|
1. **Unit Tests**: Test individual functions and classes
|
|
2. **Integration Tests**: Test middleware chains and service interactions
|
|
3. **E2E Tests**: Test complete API workflows
|
|
4. **Performance Tests**: Load testing and performance validation
|
|
|
|
### Deployment Pipeline
|
|
|
|
1. **Linting**: Code quality checks with ESLint and Prettier
|
|
2. **Testing**: Full test suite execution (unit, integration, E2E)
|
|
3. **Security Scanning**: Dependency audit, SAST, and container scanning
|
|
4. **Build**: Multi-stage Docker image creation with security scanning
|
|
5. **Deploy**: Container orchestration deployment with health checks
|
|
6. **Verification**: Automated post-deployment health and performance verification
|
|
|
|
---
|
|
|
|
# Part 2: Platform Integration (External)
|
|
|
|
This section describes how a service built from this template integrates with the GoodGo microservices platform.
|
|
|
|
## Platform Architecture
|
|
|
|
```mermaid
|
|
graph TD
|
|
Client[Client / Browser] --> Traefik[Traefik API Gateway]
|
|
|
|
subgraph Platform[GoodGo Microservices Platform]
|
|
Traefik --> AuthService[Auth Service]
|
|
Traefik --> YourService[Your Service from Template]
|
|
Traefik --> OtherServices[Other Services...]
|
|
|
|
YourService --> SharedDB[(Shared PostgreSQL)]
|
|
YourService --> SharedRedis[(Shared Redis)]
|
|
|
|
AuthService -.->|JWT Validation| YourService
|
|
YourService -.->|Inter-Service Calls| OtherServices
|
|
end
|
|
|
|
subgraph Observability[Observability Stack]
|
|
Prometheus[Prometheus]
|
|
Grafana[Grafana]
|
|
Jaeger[Jaeger]
|
|
Loki[Loki]
|
|
end
|
|
|
|
YourService -.->|Metrics| Prometheus
|
|
YourService -.->|Traces| Jaeger
|
|
YourService -.->|Logs| Loki
|
|
Prometheus --> Grafana
|
|
|
|
style Traefik fill:#ffecb3
|
|
style YourService fill:#e1f5fe
|
|
```
|
|
|
|
## Service Discovery & Registration
|
|
|
|
Services are registered with Traefik via Docker labels in `deployments/local/docker-compose.yml`:
|
|
|
|
```yaml
|
|
services:
|
|
your-service:
|
|
build:
|
|
context: ../..
|
|
dockerfile: services/your-service/Dockerfile
|
|
labels:
|
|
# Enable Traefik for this service
|
|
- "traefik.enable=true"
|
|
|
|
# Define routing rule
|
|
- "traefik.http.routers.your-service.rule=PathPrefix(`/api/v1/your-service`)"
|
|
|
|
# Specify service port
|
|
- "traefik.http.services.your-service.loadbalancer.server.port=5002"
|
|
|
|
# Health check configuration
|
|
- "traefik.http.services.your-service.loadbalancer.healthcheck.path=/health/live"
|
|
- "traefik.http.services.your-service.loadbalancer.healthcheck.interval=10s"
|
|
```
|
|
|
|
## Shared Infrastructure
|
|
|
|
### Traefik API Gateway (infra/traefik/)
|
|
|
|
- **Location**: `infra/traefik/` - Platform-level configuration
|
|
- **Static Config**: `traefik.yml` - Entry points, providers, API dashboard
|
|
- **Dynamic Config**: `dynamic/middlewares.yml`, `dynamic/routes.yml`
|
|
- **Features**: Load balancing, rate limiting, SSL/TLS, CORS, security headers
|
|
|
|
### PostgreSQL Database
|
|
|
|
- **Shared or Isolated**: Can be shared database with schema isolation or separate databases
|
|
- **Connection**: Via `DATABASE_URL` environment variable
|
|
- **Migrations**: Managed per-service with Prisma
|
|
|
|
### Redis Cache
|
|
|
|
- **Shared Instance**: Common Redis instance for all services
|
|
- **Connection**: Via `REDIS_URL` or `REDIS_HOST`/`REDIS_PORT`
|
|
- **Use Cases**: Caching, rate limiting, session storage
|
|
|
|
### Observability Stack (infra/observability/)
|
|
|
|
- **Prometheus**: Metrics collection from all services
|
|
- **Grafana**: Visualization and dashboards
|
|
- **Jaeger**: Distributed tracing
|
|
- **Loki**: Log aggregation
|
|
|
|
## Inter-Service Communication
|
|
|
|
### HTTP/REST Communication
|
|
|
|
Services communicate via HTTP through Traefik or direct service-to-service calls:
|
|
|
|
```typescript
|
|
// Example: Calling another service
|
|
const response = await fetch('http://auth-service:5001/api/v1/users/validate', {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'X-Correlation-ID': correlationId
|
|
}
|
|
});
|
|
```
|
|
|
|
### Authentication Flow
|
|
|
|
1. Client authenticates with Auth Service
|
|
2. Auth Service issues JWT token
|
|
3. Client includes JWT in requests to other services
|
|
4. Services validate JWT using `@goodgo/auth-sdk`
|
|
5. Services extract user info from validated token
|
|
|
|
---
|
|
|
|
# Part 3: Deployment Context
|
|
|
|
This section explains how to deploy a service built from this template to the platform.
|
|
|
|
## Adding Service to Platform
|
|
|
|
### Step 1: Create Service from Template
|
|
|
|
```bash
|
|
# Use the create-service script
|
|
./scripts/utils/create-service.sh my-new-service
|
|
|
|
# Or manually copy the template
|
|
cp -r services/_template services/my-new-service
|
|
```
|
|
|
|
### Step 2: Register in deployments/local/docker-compose.yml
|
|
|
|
Add your service to the platform compose file:
|
|
|
|
```yaml
|
|
services:
|
|
my-new-service:
|
|
build:
|
|
context: ../..
|
|
dockerfile: services/my-new-service/Dockerfile
|
|
container_name: my-new-service-local
|
|
environment:
|
|
- NODE_ENV=development
|
|
- PORT=5003
|
|
- DATABASE_URL=${DATABASE_URL}
|
|
- REDIS_HOST=redis
|
|
- REDIS_PORT=6379
|
|
- JWT_SECRET=${JWT_SECRET}
|
|
- SERVICE_NAME=my-new-service
|
|
- API_VERSION=v1
|
|
depends_on:
|
|
redis:
|
|
condition: service_healthy
|
|
networks:
|
|
- microservices-network
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.my-new-service.rule=PathPrefix(`/api/v1/my-new-service`)"
|
|
- "traefik.http.services.my-new-service.loadbalancer.server.port=5003"
|
|
```
|
|
|
|
### Step 3: Configure Traefik Routes (Optional)
|
|
|
|
For advanced routing, add to `infra/traefik/dynamic/routes.yml`:
|
|
|
|
```yaml
|
|
http:
|
|
routers:
|
|
my-new-service:
|
|
rule: "PathPrefix(`/api/v1/my-new-service`)"
|
|
service: my-new-service
|
|
middlewares:
|
|
- secure-headers
|
|
- cors
|
|
- compress
|
|
```
|
|
|
|
### Step 4: Start the Platform
|
|
|
|
```bash
|
|
cd deployments/local
|
|
docker-compose up -d
|
|
```
|
|
|
|
### Step 5: Access Your Service
|
|
|
|
- **API**: http://localhost/api/v1/my-new-service
|
|
- **Health**: http://localhost/api/v1/my-new-service/health
|
|
- **API Docs**: http://localhost/api/v1/my-new-service/api-docs
|
|
- **Traefik Dashboard**: http://localhost:8080
|
|
|
|
## Environment Configuration
|
|
|
|
Services inherit environment variables from:
|
|
|
|
1. **Platform Level**: `deployments/local/.env.local`
|
|
2. **Service Level**: Service-specific environment in docker-compose.yml
|
|
3. **Defaults**: Service's `.env.example` for development
|
|
|
|
## Operational Excellence
|
|
|
|
### Incident Response
|
|
|
|
1. **Detection**: Automated monitoring alerts
|
|
2. **Assessment**: Incident severity classification
|
|
3. **Communication**: Stakeholder notification
|
|
4. **Investigation**: Root cause analysis
|
|
5. **Resolution**: Fix deployment and verification
|
|
6. **Post-mortem**: Incident review and improvement
|
|
|
|
### Capacity Planning
|
|
|
|
- **Resource Monitoring**: Track CPU, memory, disk, and network usage
|
|
- **Performance Benchmarks**: Regular performance testing
|
|
- **Scaling Triggers**: Automated scaling based on metrics
|
|
- **Cost Optimization**: Right-sizing resources
|
|
|
|
### Compliance & Security
|
|
|
|
- **Security Audits**: Regular security assessments
|
|
- **Compliance Checks**: GDPR, HIPAA, SOC2 compliance
|
|
- **Data Encryption**: At-rest and in-transit encryption
|
|
- **Access Controls**: Least privilege access principles
|