- Deleted obsolete service architecture templates in both English and Vietnamese to streamline content. - Updated the Vietnamese architecture documentation with improved Mermaid diagrams for better visual clarity. - Enhanced color coding in diagrams to improve readability and consistency across documentation. - Added a new section detailing visual indicators for better understanding of architecture components.
17 KiB
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
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:
- Correlation Middleware: Generates/propagates correlation and request IDs
- Authentication Middleware: Validates JWT tokens (optional for public routes)
- Validation Middleware: Sanitizes and validates input data with Zod schemas
- Error Handler: Catches and formats errors into structured responses
- Logger Middleware: Logs request/response with correlation IDs
- 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
-
Request Entry:
- Client sends HTTP request to ingress/load balancer
- Request includes optional correlation ID header (
x-correlation-id)
-
Correlation Middleware:
- Generates or propagates correlation ID for request tracing
- Adds request ID for unique request identification
- Sets correlation headers on response
-
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
-
Validation Middleware:
- Sanitizes input data (trimming, normalization)
- Validates request data using Zod schemas
- Returns structured validation errors
-
Router & Controller:
- Routes request to appropriate controller
- Controller orchestrates business logic execution
- Input validation and response formatting
-
Service Layer:
- Contains pure business logic
- Independent of HTTP transport layer
- Orchestrates data access and external service calls
-
Repository Layer:
- Implements repository pattern for data access
- Abstracts database operations with Prisma ORM
- Provides consistent error handling
-
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
// 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
// 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
// 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
// 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.localoverrides.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
{
"success": true,
"data": { ... },
"message": "Operation completed successfully",
"timestamp": "2024-01-01T00:00:00.000Z"
}
Error Responses
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [...]
},
"timestamp": "2024-01-01T00:00:00.000Z"
}
Development Workflow
Local Development
- Setup Infrastructure:
docker-compose up -d - Install Dependencies:
pnpm install - Database Setup:
pnpm prisma migrate dev && pnpm prisma db seed - Start Development:
pnpm dev - Run Tests:
pnpm test
Testing Strategy
- Unit Tests: Test individual functions and classes
- Integration Tests: Test middleware chains and service interactions
- E2E Tests: Test complete API workflows
- Performance Tests: Load testing and performance validation
Deployment Pipeline
- Linting: Code quality checks with ESLint and Prettier
- Testing: Full test suite execution (unit, integration, E2E)
- Security Scanning: Dependency audit, SAST, and container scanning
- Build: Multi-stage Docker image creation with security scanning
- Deploy: Container orchestration deployment with health checks
- 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
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:
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_URLenvironment variable - Migrations: Managed per-service with Prisma
Redis Cache
- Shared Instance: Common Redis instance for all services
- Connection: Via
REDIS_URLorREDIS_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:
// 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
- Client authenticates with Auth Service
- Auth Service issues JWT token
- Client includes JWT in requests to other services
- Services validate JWT using
@goodgo/auth-sdk - 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
# 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:
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:
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
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:
- Platform Level:
deployments/local/.env.local - Service Level: Service-specific environment in docker-compose.yml
- Defaults: Service's
.env.examplefor development
Operational Excellence
Incident Response
- Detection: Automated monitoring alerts
- Assessment: Incident severity classification
- Communication: Stakeholder notification
- Investigation: Root cause analysis
- Resolution: Fix deployment and verification
- 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