docs: Revise architecture and template documentation for GoodGo Platform
- Updated the architecture documentation to enhance clarity with detailed diagrams and descriptions for the GoodGo Microservices Platform. - Revised the .NET and Node.js template documentation to reflect new naming conventions, project structures, and setup instructions for local development. - Improved the guide documentation with verification checklists, troubleshooting steps, and real-world examples to assist developers in deploying and managing services effectively. - Ensured bilingual support in documentation to enhance accessibility for a wider audience.
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
# [Architecture Name] / [Tên Kiến trúc]
|
||||
# [Architecture Name]
|
||||
|
||||
> **EN**: Brief English description of this architectural component or system
|
||||
> **VI**: Mô tả ngắn gọn bằng tiếng Việt về thành phần kiến trúc hoặc hệ thống này
|
||||
> Brief English description of this architectural component or system
|
||||
|
||||
## Overview Diagram / Sơ đồ Tổng quan
|
||||
## Overview Diagram
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
@@ -17,9 +16,7 @@ graph TD
|
||||
style D fill:#e1ffe1
|
||||
```
|
||||
|
||||
## Architecture Description / Mô tả Kiến trúc
|
||||
|
||||
### EN: English Section
|
||||
## Architecture Description
|
||||
|
||||
Detailed English explanation of the architecture, including:
|
||||
- Purpose and goals
|
||||
@@ -28,50 +25,56 @@ Detailed English explanation of the architecture, including:
|
||||
- Technology choices
|
||||
- Trade-offs and considerations
|
||||
|
||||
### VI: Phần Tiếng Việt
|
||||
|
||||
Giải thích chi tiết bằng tiếng Việt về kiến trúc, bao gồm:
|
||||
- Mục đích và mục tiêu
|
||||
- Các thành phần chính
|
||||
- Quyết định thiết kế
|
||||
- Lựa chọn công nghệ
|
||||
- Đánh đổi và cân nhắc
|
||||
|
||||
## System Context / Bối cảnh Hệ thống
|
||||
## System Context
|
||||
|
||||
```mermaid
|
||||
C4Context
|
||||
title System Context Diagram for [System Name]
|
||||
title System Context Diagram for GoodGo Microservices Platform
|
||||
|
||||
Person(user, "User", "System user")
|
||||
System(system, "System Name", "System description")
|
||||
System_Ext(external, "External System", "External dependency")
|
||||
Person(user, "End User", "Platform users")
|
||||
Person(admin, "Administrator", "System administrators")
|
||||
|
||||
Rel(user, system, "Uses")
|
||||
Rel(system, external, "Calls", "HTTPS")
|
||||
System_Boundary(platform, "GoodGo Platform") {
|
||||
System(gateway, "Traefik Gateway", "API Gateway, routing, load balancing")
|
||||
System(services, "Microservices", "IAM, Storage, Chat, Membership, etc.")
|
||||
System(rabbitmq, "RabbitMQ", "Message broker for async events")
|
||||
}
|
||||
|
||||
System_Ext(neon, "Neon PostgreSQL", "Serverless database")
|
||||
System_Ext(redis, "Redis", "Cache and session store")
|
||||
System_Ext(minio, "MinIO/Aliyun OSS", "Object storage")
|
||||
System_Ext(monitoring, "Observability Stack", "Prometheus + Grafana + Loki + Jaeger")
|
||||
|
||||
Rel(user, gateway, "Uses", "HTTPS")
|
||||
Rel(admin, gateway, "Manages", "HTTPS")
|
||||
Rel(gateway, services, "Routes to", "HTTP")
|
||||
Rel(services, neon, "Stores data", "PostgreSQL")
|
||||
Rel(services, redis, "Caches data", "Redis Protocol")
|
||||
Rel(services, rabbitmq, "Pub/Sub events", "AMQP")
|
||||
Rel(services, minio, "Stores files", "S3 API")
|
||||
Rel(services, monitoring, "Sends telemetry", "HTTP/gRPC")
|
||||
```
|
||||
|
||||
## Components / Thành phần
|
||||
The GoodGo Platform uses microservices architecture where all client requests go through Traefik API Gateway. Services communicate synchronously via REST/HTTP and asynchronously via RabbitMQ events. Each service has its own database schema in Neon PostgreSQL and uses Redis for caching.
|
||||
|
||||
### Component A / Thành phần A
|
||||
## Components
|
||||
|
||||
**EN**: Description of Component A, its responsibilities, and how it fits into the overall architecture.
|
||||
### Component A
|
||||
|
||||
**VI**: Mô tả Thành phần A, trách nhiệm của nó và cách nó khớp vào kiến trúc tổng thể.
|
||||
Description of Component A, its responsibilities, and how it fits into the overall architecture.
|
||||
|
||||
**Key Features / Tính năng chính**:
|
||||
- Feature 1 / Tính năng 1
|
||||
- Feature 2 / Tính năng 2
|
||||
- Feature 3 / Tính năng 3
|
||||
**Key Features**:
|
||||
- Feature 1
|
||||
- Feature 2
|
||||
- Feature 3
|
||||
|
||||
**Technologies Used / Công nghệ sử dụng**:
|
||||
**Technologies Used**:
|
||||
- Technology 1
|
||||
- Technology 2
|
||||
|
||||
**Code Reference / Tham chiếu Code**:
|
||||
**Code Reference**:
|
||||
```typescript
|
||||
// EN: Example code showing how this component is implemented
|
||||
// VI: Ví dụ code cho thấy cách thành phần này được triển khai
|
||||
// Example code showing how this component is implemented
|
||||
import { ComponentA } from './component-a';
|
||||
|
||||
const componentA = new ComponentA({
|
||||
@@ -81,11 +84,69 @@ const componentA = new ComponentA({
|
||||
|
||||
**File Location**: [`component-a.ts`](file:///path/to/component-a.ts)
|
||||
|
||||
### Component B / Thành phần B
|
||||
---
|
||||
|
||||
(Repeat structure for each major component)
|
||||
### Real-World Example: Storage Service
|
||||
|
||||
## Data Flow / Luồng Dữ liệu
|
||||
File storage management service supporting multiple cloud providers (MinIO, Aliyun OSS).
|
||||
|
||||
**Key Features**:
|
||||
- Multi-provider pattern (MinIO/Aliyun OSS)
|
||||
- Pre-signed URL generation for secure uploads/downloads
|
||||
- User quota management
|
||||
- File sharing with time-limited tokens
|
||||
- Direct client upload pattern
|
||||
|
||||
**Technologies Used**:
|
||||
- .NET 10, Entity Framework Core
|
||||
- MinIO Client, Aliyun OSS SDK
|
||||
- Redis (caching)
|
||||
- PostgreSQL (Neon)
|
||||
|
||||
**Architecture Pattern**:
|
||||
```csharp
|
||||
// Provider abstraction
|
||||
public interface IStorageProvider
|
||||
{
|
||||
Task<string> UploadFileAsync(Stream fileStream, string fileName, CancellationToken ct);
|
||||
Task<string> GeneratePresignedUrlAsync(string objectKey, int expiryMinutes, CancellationToken ct);
|
||||
}
|
||||
|
||||
// Concrete implementations
|
||||
public class MinioStorageProvider : IStorageProvider { }
|
||||
public class AliyunOssStorageProvider : IStorageProvider { }
|
||||
|
||||
// Factory pattern for provider selection
|
||||
public class StorageProviderFactory
|
||||
{
|
||||
public IStorageProvider CreateProvider(string providerName) { }
|
||||
}
|
||||
```
|
||||
|
||||
**File Location**: [`services/storage-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/storage-service-net)
|
||||
|
||||
---
|
||||
|
||||
### Real-World Example: IAM Service
|
||||
|
||||
Identity and Access Management service handling authentication, authorization, and RBAC.
|
||||
|
||||
**Key Features**:
|
||||
- JWT authentication (RS256)
|
||||
- Role-Based Access Control (RBAC)
|
||||
- MFA support (TOTP)
|
||||
- Session management
|
||||
- Permission caching
|
||||
|
||||
**Technologies Used**:
|
||||
- .NET 10, Duende IdentityServer
|
||||
- Entity Framework Core
|
||||
- Redis (caching)
|
||||
- PostgreSQL (Neon)
|
||||
|
||||
**File Location**: [`services/iam-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service-net)
|
||||
|
||||
## Data Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
@@ -102,17 +163,12 @@ sequenceDiagram
|
||||
API-->>Client: JSON
|
||||
```
|
||||
|
||||
**EN**: Detailed explanation of the data flow:
|
||||
Detailed explanation of the data flow:
|
||||
1. Step 1: Description
|
||||
2. Step 2: Description
|
||||
3. Step 3: Description
|
||||
|
||||
**VI**: Giải thích chi tiết về luồng dữ liệu:
|
||||
1. Bước 1: Mô tả
|
||||
2. Bước 2: Mô tả
|
||||
3. Bước 3: Mô tả
|
||||
|
||||
## Database Architecture / Kiến trúc Database
|
||||
## Database Architecture
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
@@ -132,97 +188,135 @@ erDiagram
|
||||
}
|
||||
```
|
||||
|
||||
**EN**: Database schema description, relationships, and design decisions.
|
||||
Database schema description, relationships, and design decisions.
|
||||
|
||||
**VI**: Mô tả schema database, mối quan hệ và quyết định thiết kế.
|
||||
## Design Decisions
|
||||
|
||||
## Design Decisions / Quyết định Thiết kế
|
||||
### Decision 1: [Decision Title]
|
||||
|
||||
### Decision 1 / Quyết định 1: [Decision Title]
|
||||
**Context**: Why this decision was needed
|
||||
|
||||
**EN Context**: Why this decision was needed
|
||||
**Decision**: What was decided
|
||||
|
||||
**VI Bối cảnh**: Tại sao quyết định này cần thiết
|
||||
**Consequences**: Impact of the decision (positive and negative)
|
||||
|
||||
**EN Decision**: What was decided
|
||||
**Alternatives Considered**: Other options that were evaluated
|
||||
|
||||
**VI Quyết định**: Điều gì đã được quyết định
|
||||
## Performance Characteristics
|
||||
|
||||
**EN Consequences**: Impact of the decision (positive and negative)
|
||||
Description of performance expectations and optimizations based on GoodGo Platform standards.
|
||||
|
||||
**VI Hậu quả**: Tác động của quyết định (tích cực và tiêu cực)
|
||||
|
||||
**EN Alternatives Considered**: Other options that were evaluated
|
||||
|
||||
**VI Các lựa chọn thay thế**: Các tùy chọn khác đã được đánh giá
|
||||
|
||||
## Performance Characteristics / Đặc điểm Hiệu suất
|
||||
|
||||
**EN**: Description of performance expectations and optimizations
|
||||
|
||||
**VI**: Mô tả kỳ vọng hiệu suất và tối ưu hóa
|
||||
|
||||
| Metric / Chỉ số | Target / Mục tiêu | Notes / Ghi chú |
|
||||
| Metric | Target | Notes |
|
||||
|------------------|-------------------|-----------------|
|
||||
| Response Time / Thời gian phản hồi | < 100ms | P95 |
|
||||
| Throughput / Thông lượng | 1000 req/s | Peak load |
|
||||
| Memory Usage / Sử dụng RAM | < 512MB | Per instance |
|
||||
| API Response Time (P95) | < 200ms | Excluding external API calls |
|
||||
| API Response Time (P99) | < 500ms | Peak load scenarios |
|
||||
| Throughput | 1000 req/s | Per service instance |
|
||||
| Database Query Time (P95) | < 50ms | Simple queries with indexes |
|
||||
| Cache Hit Rate (L1) | > 40% | In-memory cache |
|
||||
| Cache Hit Rate (L2) | > 80% | Redis cache |
|
||||
| Service Availability | > 99.9% | Monthly uptime target |
|
||||
| Error Rate | < 1% | 4xx + 5xx errors |
|
||||
|
||||
## Security Considerations / Cân nhắc Bảo mật
|
||||
**Optimization Strategies**:
|
||||
- **Multi-layer caching**: L1 (Memory) + L2 (Redis)
|
||||
- **Connection pooling**: For PostgreSQL connections
|
||||
- **Pagination**: Max 100 items per page for list endpoints
|
||||
- **Database indexes**: On frequently queried fields
|
||||
- **Async events**: Fire-and-forget with RabbitMQ
|
||||
- **CDN**: For static assets (Next.js)
|
||||
|
||||
**EN**: Security features, authentication, authorization, data protection
|
||||
## Security Considerations
|
||||
|
||||
**VI**: Tính năng bảo mật, xác thực, phân quyền, bảo vệ dữ liệu
|
||||
Security features, authentication, authorization, data protection
|
||||
|
||||
- Security feature 1 / Tính năng bảo mật 1
|
||||
- Security feature 2 / Tính năng bảo mật 2
|
||||
- Security feature 1
|
||||
- Security feature 2
|
||||
|
||||
## Deployment / Triển khai
|
||||
## Deployment
|
||||
|
||||
**EN**: How this architecture is deployed and scaled
|
||||
How this architecture is deployed and scaled in GoodGo Platform.
|
||||
|
||||
**VI**: Cách kiến trúc này được triển khai và mở rộng
|
||||
### Traefik API Gateway Routing
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
storage-service-net:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.storage-service.rule=PathPrefix(`/api/v1/storage`)"
|
||||
- "traefik.http.services.storage-service.loadbalancer.server.port=8080"
|
||||
- "traefik.http.routers.storage-service.middlewares=strip-prefix@docker"
|
||||
```
|
||||
|
||||
### Kubernetes Deployment
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
LB[Load Balancer] --> A[Instance 1]
|
||||
LB --> B[Instance 2]
|
||||
LB --> C[Instance 3]
|
||||
A --> DB[(Database)]
|
||||
LB[Load Balancer] --> Traefik[Traefik Gateway<br/>2-3 replicas]
|
||||
Traefik --> A[Service A<br/>2-10 replicas HPA]
|
||||
Traefik --> B[Service B<br/>2-10 replicas HPA]
|
||||
Traefik --> C[Service C<br/>2-10 replicas HPA]
|
||||
A --> DB[(Neon PostgreSQL<br/>Serverless)]
|
||||
B --> DB
|
||||
C --> DB
|
||||
A --> Cache[(Redis)]
|
||||
A --> Cache[(Redis Cluster<br/>3 nodes)]
|
||||
B --> Cache
|
||||
C --> Cache
|
||||
|
||||
style LB fill:#1565c0,stroke:#fff,stroke-width:2px,color:#fff
|
||||
style Traefik fill:#0f4c81,stroke:#fff,stroke-width:2px,color:#fff
|
||||
style A fill:#283593,stroke:#fff,stroke-width:2px,color:#fff
|
||||
style B fill:#4527a0,stroke:#fff,stroke-width:2px,color:#fff
|
||||
style C fill:#4527a0,stroke:#fff,stroke-width:2px,color:#fff
|
||||
style DB fill:#5e35b1,stroke:#fff,stroke-width:2px,color:#fff
|
||||
style Cache fill:#ef6c00,stroke:#fff,stroke-width:2px,color:#fff
|
||||
```
|
||||
|
||||
## Monitoring & Observability / Giám sát & Khả năng quan sát
|
||||
**Resource Allocation**:
|
||||
|
||||
**EN**: How to monitor this architecture, key metrics, alerts
|
||||
| Service | Requests | Limits |
|
||||
|---------|----------|--------|
|
||||
| **Microservices** | 256Mi RAM, 250m CPU | 512Mi RAM, 500m CPU |
|
||||
| **Traefik** | 512Mi RAM, 500m CPU | 1Gi RAM, 1000m CPU |
|
||||
| **Redis** | 2Gi RAM, 1 CPU | 4Gi RAM, 2 CPU |
|
||||
|
||||
**VI**: Cách giám sát kiến trúc này, các chỉ số chính, cảnh báo
|
||||
## Monitoring & Observability
|
||||
|
||||
**Key Metrics / Chỉ số chính**:
|
||||
- Metric 1 / Chỉ số 1
|
||||
- Metric 2 / Chỉ số 2
|
||||
How to monitor this architecture, key metrics, alerts
|
||||
|
||||
**Health Checks / Kiểm tra Sức khỏe**:
|
||||
**Key Metrics**:
|
||||
- Metric 1
|
||||
- Metric 2
|
||||
|
||||
**Health Checks**:
|
||||
- `/health/live` - Liveness probe
|
||||
- `/health/ready` - Readiness probe
|
||||
|
||||
## Related Documentation / Tài liệu Liên quan
|
||||
## Related Documentation
|
||||
|
||||
- [Related Arch Doc 1](../architecture/related-doc-1.md) - EN: Description / VI: Mô tả
|
||||
- [Related Guide](../guides/related-guide.md) - EN: Description / VI: Mô tả
|
||||
- [Related Skill](../skills/related-skill.md) - EN: Description / VI: Mô tả
|
||||
### Architecture Documents
|
||||
- [System Design](../architecture/system-design.md) - Overall platform architecture
|
||||
- [Microservices Communication](../architecture/microservices-communication.md) - Service communication patterns
|
||||
- [Caching Architecture](../architecture/caching-architecture.md) - Redis caching strategies
|
||||
- [Event-Driven Architecture](../architecture/event-driven-architecture.md) - RabbitMQ event patterns
|
||||
|
||||
## References / Tham khảo
|
||||
### Skills Reference
|
||||
- [CQRS with MediatR](../skills/cqrs-mediatr.md) - CQRS pattern
|
||||
- [Repository Pattern](../skills/repository-pattern.md) - EF Core repository
|
||||
- [Domain-Driven Design](../skills/domain-driven-design.md) - DDD patterns
|
||||
|
||||
- [External Resource 1](https://example.com) - EN: Description
|
||||
- [External Resource 2](https://example.com) - EN: Description
|
||||
### Guides
|
||||
- [Local Development](../guides/local-development.md) - Setup dev environment
|
||||
- [Deployment](../guides/deployment.md) - Kubernetes deployment
|
||||
|
||||
## References
|
||||
|
||||
- [External Resource 1](https://example.com) - Description
|
||||
- [External Resource 2](https://example.com) - Description
|
||||
|
||||
---
|
||||
|
||||
**Last Updated / Cập nhật lần cuối**: YYYY-MM-DD
|
||||
**Authors / Tác giả**: Your Name
|
||||
**Reviewers / Người review**: Reviewer Names
|
||||
**Last Updated**: 2026-01-14
|
||||
**Authors**: VelikHo (hongochai10@icloud.com)
|
||||
**Reviewers**: Reviewer Names
|
||||
|
||||
@@ -29,14 +29,22 @@ This template provides a production-ready structure for .NET microservices based
|
||||
|
||||
```bash
|
||||
# Copy template to new service
|
||||
cp -r services/_template_dot_net services/your-service-name
|
||||
cd services/your-service-name
|
||||
cp -r services/_template_dot_net services/your-service-name-net
|
||||
cd services/your-service-name-net
|
||||
|
||||
# Rename all occurrences of "MyService" to "YourService"
|
||||
# Example: MyService → StorageService, UserService, PaymentService
|
||||
find . -type f -name "*.cs" -exec sed -i '' 's/MyService/YourService/g' {} +
|
||||
find . -type f -name "*.csproj" -exec sed -i '' 's/MyService/YourService/g' {} +
|
||||
find . -type f -name "*.sln" -exec sed -i '' 's/MyService/YourService/g' {} +
|
||||
```
|
||||
|
||||
**Naming Convention**:
|
||||
- Service folder: `{service-name}-net` (e.g., `storage-service-net`, `iam-service-net`)
|
||||
- Projects: `{ServiceName}.API`, `{ServiceName}.Domain`, `{ServiceName}.Infrastructure`
|
||||
- DbContext: `{ServiceName}Context` (e.g., `StorageServiceContext`)
|
||||
- Namespace: `GoodGo.Services.{ServiceName}` (e.g., `GoodGo.Services.StorageService`)
|
||||
|
||||
### 2. Configure Environment
|
||||
|
||||
```bash
|
||||
@@ -62,36 +70,54 @@ dotnet run --project src/MyService.API
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
_template_dot_net/
|
||||
{service-name}-net/ # Example: storage-service-net
|
||||
├── src/
|
||||
│ ├── MyService.API/ # Presentation Layer (Controllers, CQRS)
|
||||
│ ├── {ServiceName}.API/ # Presentation Layer (Controllers, CQRS)
|
||||
│ │ ├── Controllers/ # API endpoints
|
||||
│ │ ├── Application/ # CQRS Implementation
|
||||
│ │ │ ├── Commands/ # Write operations (MediatR)
|
||||
│ │ │ ├── Queries/ # Read operations
|
||||
│ │ │ ├── Behaviors/ # MediatR pipeline behaviors
|
||||
│ │ │ └── Validations/ # FluentValidation validators
|
||||
│ │ ├── Middlewares/ # Custom middlewares
|
||||
│ │ └── Program.cs # Application entry point
|
||||
│ │
|
||||
│ ├── MyService.Domain/ # Domain Layer (Pure business logic)
|
||||
│ ├── {ServiceName}.Domain/ # Domain Layer (Pure business logic)
|
||||
│ │ ├── AggregatesModel/ # Aggregate roots and entities
|
||||
│ │ ├── Events/ # Domain events
|
||||
│ │ ├── Exceptions/ # Domain exceptions
|
||||
│ │ └── SeedWork/ # Base classes
|
||||
│ │ └── SeedWork/ # Base classes (Entity, IAggregateRoot)
|
||||
│ │
|
||||
│ └── MyService.Infrastructure/ # Infrastructure Layer
|
||||
│ ├── EntityConfigurations/ # EF Core configurations
|
||||
│ └── {ServiceName}.Infrastructure/ # Infrastructure Layer
|
||||
│ ├── EntityConfigurations/ # EF Core configurations (Fluent API)
|
||||
│ ├── Repositories/ # Repository implementations
|
||||
│ └── MyServiceContext.cs # DbContext with Unit of Work
|
||||
│ ├── Providers/ # External service providers (if any)
|
||||
│ ├── Services/ # Infrastructure services
|
||||
│ ├── Migrations/ # EF Core migrations
|
||||
│ └── {ServiceName}Context.cs # DbContext with Unit of Work
|
||||
│
|
||||
├── tests/
|
||||
│ ├── MyService.UnitTests/ # Unit tests
|
||||
│ └── MyService.FunctionalTests/ # Integration tests
|
||||
│ ├── {ServiceName}.UnitTests/ # Unit tests
|
||||
│ └── {ServiceName}.FunctionalTests/ # Integration tests
|
||||
│
|
||||
├── docs/
|
||||
│ ├── en/ # English documentation
|
||||
│ │ ├── README.md
|
||||
│ │ └── ARCHITECTURE.md
|
||||
│ └── vi/ # Vietnamese documentation
|
||||
│ ├── README.md
|
||||
│ └── ARCHITECTURE.md
|
||||
│
|
||||
├── Dockerfile # Multi-stage Docker build
|
||||
└── docker-compose.yml # Local development setup
|
||||
├── docker-compose.yml # Local development setup
|
||||
└── README.md # Service overview (bilingual)
|
||||
```
|
||||
|
||||
**Real-World Examples**:
|
||||
- Storage Service: [`services/storage-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/storage-service-net)
|
||||
- IAM Service: [`services/iam-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service-net)
|
||||
- Chat Service: [`services/chat-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/chat-service-net)
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
@@ -204,12 +230,43 @@ Request → LoggingBehavior → ValidatorBehavior → TransactionBehavior → Ha
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Required
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `ASPNETCORE_ENVIRONMENT` | Environment name | `Development` |
|
||||
| `DATABASE_URL` | PostgreSQL connection | - |
|
||||
| `REDIS_URL` | Redis connection | - |
|
||||
| `JWT_SECRET` | JWT signing secret | - |
|
||||
| `DATABASE_URL` | Neon PostgreSQL connection | - |
|
||||
| `ConnectionStrings__DefaultConnection` | Standard connection string format | - |
|
||||
|
||||
### Optional
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `REDIS_URL` | Redis connection (cache) | - |
|
||||
| `RabbitMQ__Host` | RabbitMQ hostname | `localhost` |
|
||||
| `RabbitMQ__Port` | RabbitMQ port | `5672` |
|
||||
| `RabbitMQ__Username` | RabbitMQ username | `guest` |
|
||||
| `RabbitMQ__Password` | RabbitMQ password | `guest` |
|
||||
|
||||
### Inter-Service Communication
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `IamService__BaseUrl` | IAM Service URL | `http://iam-service-net:5001` |
|
||||
| `Services__InternalApiKey` | Shared secret for service-to-service auth | - |
|
||||
|
||||
### Multi-Provider Pattern (Example: Storage Service)
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `Storage__Provider` | Provider: `minio` or `aliyun` | `minio` |
|
||||
| `Storage__DefaultBucket` | Default bucket name | `storage` |
|
||||
| `Storage__MinIO__Endpoint` | MinIO endpoint | `localhost:9000` |
|
||||
| `Storage__MinIO__AccessKey` | MinIO access key | - |
|
||||
| `Storage__MinIO__SecretKey` | MinIO secret key | - |
|
||||
| `Storage__AliyunOSS__Endpoint` | Aliyun OSS endpoint | - |
|
||||
| `Storage__AliyunOSS__AccessKeyId` | Aliyun access key | - |
|
||||
| `Storage__AliyunOSS__AccessKeySecret` | Aliyun secret key | - |
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -257,23 +314,223 @@ spec:
|
||||
port: 8080
|
||||
```
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Multi-Provider Pattern
|
||||
|
||||
**Use when**: Service needs to support multiple external providers (storage, payment, SMS)
|
||||
|
||||
**Example**: Storage Service with MinIO and Aliyun OSS
|
||||
|
||||
```csharp
|
||||
// Domain - Interface
|
||||
public interface IStorageProvider
|
||||
{
|
||||
Task<string> UploadFileAsync(Stream fileStream, string fileName, CancellationToken ct);
|
||||
Task<Stream> DownloadFileAsync(string objectKey, CancellationToken ct);
|
||||
Task DeleteFileAsync(string objectKey, CancellationToken ct);
|
||||
Task<string> GeneratePresignedUrlAsync(string objectKey, int expiryMinutes, CancellationToken ct);
|
||||
}
|
||||
|
||||
// Infrastructure - MinIO Implementation
|
||||
public class MinioStorageProvider : IStorageProvider
|
||||
{
|
||||
private readonly MinioClient _client;
|
||||
// Implementation...
|
||||
}
|
||||
|
||||
// Infrastructure - Aliyun OSS Implementation
|
||||
public class AliyunOssStorageProvider : IStorageProvider
|
||||
{
|
||||
private readonly OssClient _client;
|
||||
// Implementation...
|
||||
}
|
||||
|
||||
// API - Provider Factory
|
||||
public class StorageProviderFactory
|
||||
{
|
||||
public IStorageProvider CreateProvider(IConfiguration config)
|
||||
{
|
||||
var provider = config["Storage:Provider"];
|
||||
return provider?.ToLower() switch
|
||||
{
|
||||
"minio" => new MinioStorageProvider(config),
|
||||
"aliyun" => new AliyunOssStorageProvider(config),
|
||||
_ => throw new InvalidOperationException($"Unknown provider: {provider}")
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**File Reference**: [`StorageService.Infrastructure/Providers/`](file:///Users/velikho/Desktop/WORKING/Base/services/storage-service-net/src/StorageService.Infrastructure/Providers)
|
||||
|
||||
---
|
||||
|
||||
### Inter-Service Authentication Pattern
|
||||
|
||||
**Use when**: Service needs to validate JWT tokens with IAM Service
|
||||
|
||||
```csharp
|
||||
// Infrastructure - IAM Service Client
|
||||
public class IamServiceClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
public IamServiceClient(HttpClient httpClient, IConfiguration config)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_config = config;
|
||||
_httpClient.BaseAddress = new Uri(_config["IamService:BaseUrl"]);
|
||||
}
|
||||
|
||||
public async Task<UserInfo> ValidateTokenAsync(string token, CancellationToken ct)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/auth/validate")
|
||||
{
|
||||
Headers = { { "Authorization", $"Bearer {token}" } }
|
||||
};
|
||||
|
||||
var response = await _httpClient.SendAsync(request, ct);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<UserInfo>(ct);
|
||||
}
|
||||
}
|
||||
|
||||
// API - Middleware
|
||||
public class JwtValidationMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IamServiceClient _iamClient;
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
var userInfo = await _iamClient.ValidateTokenAsync(token, context.RequestAborted);
|
||||
context.Items["UserId"] = userInfo.UserId;
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What's New in .NET 10
|
||||
|
||||
- **C# 14** language features
|
||||
- Improved **Native AOT** support
|
||||
- Better **async/await** performance
|
||||
- Enhanced **JSON serialization**
|
||||
- Enhanced **JSON serialization** (System.Text.Json)
|
||||
- 3-year **LTS** support (until November 2028)
|
||||
- **Entity Framework Core 10** with performance improvements
|
||||
|
||||
## Platform Integration
|
||||
|
||||
### Traefik Routing
|
||||
|
||||
Add labels to `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
your-service-net:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/your-service-net/Dockerfile
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.your-service.rule=PathPrefix(`/api/v1/your-service`)"
|
||||
- "traefik.http.services.your-service.loadbalancer.server.port=8080"
|
||||
- "traefik.http.routers.your-service.middlewares=strip-prefix@docker"
|
||||
```
|
||||
|
||||
### Neon PostgreSQL Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Host=ep-xxx.neon.tech;Database=your_service;Username=xxx;Password=xxx;SSL Mode=Require;Trust Server Certificate=true"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Best Practices**:
|
||||
- Use connection pooling: `Pooling=true;Maximum Pool Size=100`
|
||||
- Enable SSL: `SSL Mode=Require`
|
||||
- Set command timeout: `Command Timeout=30`
|
||||
|
||||
### RabbitMQ Integration (instead of Kafka)
|
||||
|
||||
```csharp
|
||||
// Domain Event
|
||||
public record FileUploadedEvent(string FileId, string UserId, long FileSize) : IDomainEvent;
|
||||
|
||||
// Infrastructure - Event Publisher
|
||||
public class RabbitMqEventPublisher : IEventPublisher
|
||||
{
|
||||
private readonly IConnection _connection;
|
||||
private readonly IModel _channel;
|
||||
|
||||
public async Task PublishAsync<T>(T @event, CancellationToken ct) where T : IDomainEvent
|
||||
{
|
||||
var message = JsonSerializer.Serialize(@event);
|
||||
var body = Encoding.UTF8.GetBytes(message);
|
||||
|
||||
_channel.BasicPublish(
|
||||
exchange: "domain_events",
|
||||
routingKey: typeof(T).Name,
|
||||
body: body
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Architecture Details](../architecture/microservices-communication.md)
|
||||
- [DDD Patterns](../architecture/system-design.md)
|
||||
- [Deployment Guide](../guides/deployment.md)
|
||||
### Architecture
|
||||
- [System Design](../architecture/system-design.md) - Overall GoodGo Platform architecture
|
||||
- [Microservices Communication](../architecture/microservices-communication.md) - Communication patterns
|
||||
- [Caching Architecture](../architecture/caching-architecture.md) - Redis caching strategies
|
||||
|
||||
## Resources
|
||||
### Skills
|
||||
- [CQRS with MediatR](../skills/cqrs-mediatr.md) - CQRS pattern implementation
|
||||
- [Repository Pattern](../skills/repository-pattern.md) - EF Core repository pattern
|
||||
- [Domain-Driven Design](../skills/domain-driven-design.md) - DDD tactical patterns
|
||||
- [Error Handling](../skills/error-handling-patterns.md) - Exception handling patterns
|
||||
|
||||
- [eShopOnContainers](https://github.com/dotnet-architecture/eShopOnContainers)
|
||||
### Guides
|
||||
- [Local Development](../guides/local-development.md) - Setup dev environment
|
||||
- [Deployment](../guides/deployment.md) - Deploy to Kubernetes
|
||||
|
||||
## Additional Resources
|
||||
|
||||
### Microsoft Official
|
||||
- [.NET 10 Documentation](https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10)
|
||||
- [MediatR](https://github.com/jbogard/MediatR)
|
||||
- [FluentValidation](https://docs.fluentvalidation.net/)
|
||||
- [Entity Framework Core 10](https://docs.microsoft.com/en-us/ef/core/)
|
||||
- [ASP.NET Core 10](https://docs.microsoft.com/en-us/aspnet/core/)
|
||||
|
||||
### Architecture References
|
||||
- [eShopOnContainers](https://github.com/dotnet-architecture/eShopOnContainers) - Microservices reference architecture
|
||||
- [.NET Microservices Architecture Book](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/)
|
||||
|
||||
### Libraries
|
||||
- [MediatR](https://github.com/jbogard/MediatR) - CQRS implementation
|
||||
- [FluentValidation](https://docs.fluentvalidation.net/) - Validation library
|
||||
- [Polly](https://github.com/App-vNext/Polly) - Resilience and transient-fault-handling
|
||||
|
||||
### Tools
|
||||
- [EF Core Tools](https://docs.microsoft.com/en-us/ef/core/cli/dotnet) - Migrations and scaffolding
|
||||
- [Neon PostgreSQL](https://neon.tech/docs) - Serverless Postgres documentation
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-01-14
|
||||
**Template Version**: 2.0
|
||||
**Maintained By**: GoodGo Architecture Team
|
||||
|
||||
@@ -45,6 +45,25 @@ Trước khi bắt đầu hướng dẫn này, hãy đảm bảo bạn có:
|
||||
# EN: Verify prerequisites / VI: Xác minh yêu cầu
|
||||
node --version # Should be 20 or higher / Phải là 20 hoặc cao hơn
|
||||
docker --version # Should be installed / Phải được cài đặt
|
||||
dotnet --version # Should be 10.0+ for .NET services / Phải là 10.0+ cho .NET services
|
||||
```
|
||||
|
||||
**Example: Local Development Setup for Storage Service**
|
||||
```bash
|
||||
# Clone repository
|
||||
cd /Users/velikho/Desktop/WORKING/Base
|
||||
|
||||
# Install dependencies (.NET)
|
||||
cd services/storage-service-net
|
||||
dotnet restore
|
||||
|
||||
# Setup infrastructure
|
||||
cd ../../deployments/local
|
||||
docker-compose up -d postgres redis minio
|
||||
|
||||
# Run migrations
|
||||
cd ../../services/storage-service-net
|
||||
dotnet ef database update --project src/StorageService.Infrastructure --startup-project src/StorageService.API
|
||||
```
|
||||
|
||||
## Overview / Tổng quan
|
||||
@@ -96,11 +115,53 @@ touch .env.local
|
||||
**Example Content / Nội dung ví dụ**:
|
||||
```env
|
||||
# EN: Environment variables / VI: Biến môi trường
|
||||
PORT=5000
|
||||
NODE_ENV=development
|
||||
ASPNETCORE_ENVIRONMENT=Development
|
||||
DATABASE_URL=postgresql://localhost:5432/mydb
|
||||
REDIS_URL=redis://localhost:6379
|
||||
Storage__Provider=minio
|
||||
Storage__MinIO__Endpoint=localhost:9000
|
||||
Storage__MinIO__AccessKey=minioadmin
|
||||
Storage__MinIO__SecretKey=minioadmin
|
||||
```
|
||||
|
||||
### Real-World Example / Ví dụ Thực tế: Traefik Routing Setup
|
||||
|
||||
**EN**: How to configure Traefik routing for a new service.
|
||||
|
||||
**VI**: Cách cấu hình Traefik routing cho service mới.
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
your-service-net:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/your-service-net/Dockerfile
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
labels:
|
||||
# Enable Traefik
|
||||
- "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=8080"
|
||||
# Strip prefix middleware
|
||||
- "traefik.http.routers.your-service.middlewares=strip-prefix@docker"
|
||||
networks:
|
||||
- goodgo-network
|
||||
|
||||
networks:
|
||||
goodgo-network:
|
||||
external: true
|
||||
```
|
||||
|
||||
**Expected Result / Kết quả mong đợi**:
|
||||
- ✅ Service accessible at `http://localhost/api/v1/your-service`
|
||||
- ✅ Traefik dashboard shows the service at `http://localhost:8080`
|
||||
- ✅ Health check endpoint works: `http://localhost/api/v1/your-service/health`
|
||||
|
||||
### Step 2 / Bước 2: [Action Title]
|
||||
|
||||
**EN**: Continue with next step explanation...
|
||||
@@ -142,9 +203,35 @@ curl http://localhost:5000/health
|
||||
|
||||
### Verification Checklist / Danh sách kiểm tra
|
||||
|
||||
- [ ] Check 1 / Kiểm tra 1: Description / Mô tả
|
||||
- [ ] Check 2 / Kiểm tra 2: Description / Mô tả
|
||||
- [ ] Check 3 / Kiểm tra 3: Description / Mô tả
|
||||
**For .NET Services**:
|
||||
- [ ] Check 1: Service builds successfully / Service build thành công
|
||||
```bash
|
||||
dotnet build
|
||||
```
|
||||
- [ ] Check 2: Database migrations applied / Migrations đã apply
|
||||
```bash
|
||||
dotnet ef database update --project src/{ServiceName}.Infrastructure --startup-project src/{ServiceName}.API
|
||||
```
|
||||
- [ ] Check 3: Service responds to health checks / Service phản hồi health checks
|
||||
```bash
|
||||
curl http://localhost:8080/health
|
||||
# Expected: {"status":"Healthy"}
|
||||
```
|
||||
- [ ] Check 4: Swagger UI accessible / Swagger UI truy cập được
|
||||
```bash
|
||||
open http://localhost:8080/swagger
|
||||
```
|
||||
|
||||
**For Traefik Integration**:
|
||||
- [ ] Check 5: Service registered in Traefik / Service đăng ký trong Traefik
|
||||
```bash
|
||||
curl http://localhost:8080/api/http/routers
|
||||
# Should see your-service router
|
||||
```
|
||||
- [ ] Check 6: API accessible via gateway / API truy cập được qua gateway
|
||||
```bash
|
||||
curl http://localhost/api/v1/your-service/health
|
||||
```
|
||||
|
||||
## Common Issues / Vấn đề Thường gặp
|
||||
|
||||
@@ -176,19 +263,26 @@ step-2
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Problem[Problem Occurs] --> Check1{Check 1:<br/>Condition?}
|
||||
Check1 -->|Yes| Solution1[Solution 1]
|
||||
Check1 -->|No| Check2{Check 2:<br/>Condition?}
|
||||
Check2 -->|Yes| Solution2[Solution 2]
|
||||
Check2 -->|No| Check3{Check 3:<br/>Condition?}
|
||||
Check3 -->|Yes| Solution3[Solution 3]
|
||||
Check3 -->|No| Support[Contact Support]
|
||||
Problem[Service not accessible] --> Check1{Traefik<br/>running?}
|
||||
Check1 -->|No| Solution1[Start Traefik:<br/>docker-compose up traefik]
|
||||
Check1 -->|Yes| Check2{Service<br/>container running?}
|
||||
Check2 -->|No| Solution2[Start service:<br/>docker-compose up your-service]
|
||||
Check2 -->|Yes| Check3{Database<br/>connection OK?}
|
||||
Check3 -->|No| Solution3[Check DATABASE_URL<br/>Run migrations]
|
||||
Check3 -->|Yes| Logs[Check service logs:<br/>docker-compose logs -f]
|
||||
|
||||
Solution1 --> Resolved{Resolved?}
|
||||
Solution2 --> Resolved
|
||||
Solution3 --> Resolved
|
||||
Resolved -->|No| Support
|
||||
Logs --> Resolved
|
||||
Resolved -->|No| Support[Check documentation:<br/>docs/vi/guides/troubleshooting.md]
|
||||
Resolved -->|Yes| Success([Success])
|
||||
|
||||
style Problem fill:#f8d7da,stroke:#721c24,stroke-width:2px
|
||||
style Success fill:#d4edda,stroke:#155724,stroke-width:2px
|
||||
style Check1 fill:#fff3cd,stroke:#856404,stroke-width:2px
|
||||
style Check2 fill:#fff3cd,stroke:#856404,stroke-width:2px
|
||||
style Check3 fill:#fff3cd,stroke:#856404,stroke-width:2px
|
||||
```
|
||||
|
||||
## Advanced Options / Tùy chọn Nâng cao
|
||||
@@ -214,9 +308,16 @@ advanced-command --option
|
||||
|
||||
**VI**: Làm gì sau khi hoàn thành hướng dẫn này.
|
||||
|
||||
- [ ] Next step 1 / Bước tiếp theo 1: [Related Guide](../guides/related-guide.md)
|
||||
- [ ] Next step 2 / Bước tiếp theo 2: [Another Guide](../guides/another-guide.md)
|
||||
- [ ] Next step 3 / Bước tiếp theo 3: [Deep Dive](../skills/deep-dive.md)
|
||||
**For .NET Services**:
|
||||
- [ ] Next step 1: [Implement CQRS Commands](../skills/cqrs-mediatr.md)
|
||||
- [ ] Next step 2: [Add Repository Pattern](../skills/repository-pattern.md)
|
||||
- [ ] Next step 3: [Setup Redis Caching](../skills/redis-caching.md)
|
||||
- [ ] Next step 4: [Configure Observability](../guides/observability.md)
|
||||
|
||||
**For Deployment**:
|
||||
- [ ] Next step 1: [Kubernetes Deployment](../guides/deployment.md)
|
||||
- [ ] Next step 2: [Configure CI/CD Pipeline](../guides/ci-cd.md)
|
||||
- [ ] Next step 3: [Setup Monitoring](../guides/observability.md)
|
||||
|
||||
## Additional Resources / Tài nguyên Bổ sung
|
||||
|
||||
@@ -251,7 +352,6 @@ Câu trả lời 2 bằng tiếng Việt.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated / Cập nhật lần cuối**: YYYY-MM-DD
|
||||
**Difficulty / Độ khó**: Beginner/Intermediate/Advanced
|
||||
**Estimated Time / Thời gian ước tính**: X minutes
|
||||
**Authors / Tác giả**: Your Name
|
||||
**Authors / Tác giả**: VelikHo (hongochai10@icloud.com)
|
||||
|
||||
@@ -1,482 +1,221 @@
|
||||
# Template Usage Guide / Hướng dẫn Sử dụng Templates
|
||||
# Hướng dẫn Sử dụng Templates Tài liệu
|
||||
|
||||
## Overview / Tổng quan
|
||||
> **Mục đích**: Hướng dẫn sử dụng các templates tài liệu để tạo documentation nhất quán cho project
|
||||
|
||||
**EN**: This guide explains how to use the documentation templates to maintain consistency across all documentation updates.
|
||||
## Templates Có sẵn
|
||||
|
||||
**VI**: Hướng dẫn này giải thích cách sử dụng các templates tài liệu để duy trì tính nhất quán trong tất cả các cập nhật tài liệu.
|
||||
### 1. Architecture Template - [`architecture.md`](./architecture.md)
|
||||
|
||||
## Available Templates / Templates Có sẵn
|
||||
**Sử dụng khi**: Tài liệu hóa kiến trúc hệ thống, thành phần, hoặc design decision
|
||||
|
||||
| Template | Use For | File |
|
||||
|----------|---------|------|
|
||||
| **Architecture** | System design, component architecture | [`architecture-doc-template.md`](./architecture-doc-template.md) |
|
||||
| **Guide** | Step-by-step howtos, tutorials | [`guide-doc-template.md`](./guide-doc-template.md) |
|
||||
| **Skill/Pattern** | Design patterns, coding standards | [`skill-pattern-template.md`](./skill-pattern-template.md) |
|
||||
| **Mermaid** | Diagram reference and examples | [`MERMAID_GUIDE.md`](./MERMAID_GUIDE.md) |
|
||||
**Bao gồm**:
|
||||
- Sơ đồ tổng quan (Mermaid diagrams)
|
||||
- Mô tả thành phần chi tiết
|
||||
- Quyết định thiết kế
|
||||
- Database architecture
|
||||
- Performance characteristics
|
||||
- Security considerations
|
||||
- Deployment strategy
|
||||
|
||||
---
|
||||
**Ví dụ**:
|
||||
- Storage Service Architecture: [`storage-architecture.md`](../architecture/storage-architecture.md)
|
||||
- IAM Architecture: [`iam-proposal.md`](../architecture/iam-proposal.md)
|
||||
- System Design: [`system-design.md`](../architecture/system-design.md)
|
||||
|
||||
## Quick Start / Bắt đầu Nhanh
|
||||
### 2. Guide Template - [`guide.md`](./guide.md)
|
||||
|
||||
### 1. Choose the Right Template / Chọn Template Phù hợp
|
||||
**Sử dụng khi**: Tạo hướng dẫn từng bước (getting started, deployment, troubleshooting)
|
||||
|
||||
**Decision Tree / Cây Quyết định**:
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start{What are you<br/>documenting?}
|
||||
Start -->|System design,<br/>components| Arch[Use Architecture<br/>Template]
|
||||
Start -->|How-to guide,<br/>setup steps| Guide[Use Guide<br/>Template]
|
||||
Start -->|Code pattern,<br/>best practice| Skill[Use Skill/Pattern<br/>Template]
|
||||
|
||||
Arch --> Mermaid[Add Mermaid<br/>Diagrams]
|
||||
Guide --> Mermaid
|
||||
Skill --> Mermaid
|
||||
|
||||
Mermaid --> Write[Write Bilingual<br/>Content]
|
||||
Write --> Review[Review & Test]
|
||||
|
||||
style Start fill:#fff3cd
|
||||
style Mermaid fill:#e1f5ff
|
||||
style Write fill:#d4edda
|
||||
style Review fill:#f0e1ff
|
||||
```
|
||||
**Bao gồm**:
|
||||
- Workflow diagram
|
||||
- Prerequisites
|
||||
- Hướng dẫn từng bước chi tiết
|
||||
- Verification steps
|
||||
- Common issues & troubleshooting
|
||||
- FAQ section
|
||||
|
||||
### 2. Copy Template / Sao chép Template
|
||||
**Ví dụ**:
|
||||
- Local Development: [`local-development.md`](../guides/local-development.md)
|
||||
- Deployment to Kubernetes: [`deployment.md`](../guides/deployment.md)
|
||||
- IAM Authentication Guide: [`iam-authentication.md`](../guides/iam-authentication.md)
|
||||
|
||||
### 3. Skill/Pattern Template - [`skill-pattern.md`](./skill-pattern.md)
|
||||
|
||||
**Sử dụng khi**: Tài liệu hóa coding patterns, best practices, hoặc kỹ thuật
|
||||
|
||||
**Bao gồm**:
|
||||
- Pattern overview
|
||||
- When to use / when not to use
|
||||
- Implementation examples
|
||||
- Class diagrams
|
||||
- Best practices
|
||||
- Common mistakes
|
||||
- Testing examples
|
||||
|
||||
**Ví dụ**:
|
||||
- CQRS with MediatR: [`cqrs-mediatr.md`](../skills/cqrs-mediatr.md)
|
||||
- Repository Pattern: [`repository-pattern.md`](../skills/repository-pattern.md)
|
||||
- Redis Caching: [`redis-caching.md`](../skills/redis-caching.md)
|
||||
- Domain-Driven Design: [`domain-driven-design.md`](../skills/domain-driven-design.md)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Bước 1: Chọn Template phù hợp
|
||||
|
||||
Xác định loại tài liệu bạn cần tạo:
|
||||
- **Kiến trúc** → `architecture.md`
|
||||
- **Hướng dẫn** → `guide.md`
|
||||
- **Pattern/Skill** → `skill-pattern.md`
|
||||
|
||||
### Bước 2: Copy Template
|
||||
|
||||
```bash
|
||||
# EN: Copy appropriate template
|
||||
# VI: Sao chép template phù hợp
|
||||
# Ví dụ: Tạo architecture document mới
|
||||
cp docs/vi/templates/architecture.md docs/vi/architecture/new-architecture-name.md
|
||||
|
||||
# For Architecture docs
|
||||
cp docs/templates/architecture-doc-template.md docs/en/architecture/your-doc.md
|
||||
cp docs/templates/architecture-doc-template.md docs/vi/architecture/your-doc.md
|
||||
# Ví dụ: Tạo guide document mới
|
||||
cp docs/vi/templates/guide.md docs/vi/guides/new-guide-name.md
|
||||
|
||||
# For Guides
|
||||
cp docs/templates/guide-doc-template.md docs/en/guides/your-guide.md
|
||||
cp docs/templates/guide-doc-template.md docs/vi/guides/your-guide.md
|
||||
|
||||
# For Skills
|
||||
cp docs/templates/skill-pattern-template.md docs/en/skills/your-skill.md
|
||||
cp docs/templates/skill-pattern-template.md docs/vi/skills/your-skill.md
|
||||
# Ví dụ: Tạo skill document mới
|
||||
cp docs/vi/templates/skill-pattern.md docs/vi/skills/new-skill-name.md
|
||||
```
|
||||
|
||||
### 3. Fill in Content / Điền Nội dung
|
||||
### Bước 3: Thay thế Placeholders
|
||||
|
||||
Replace all placeholders:
|
||||
- `[Architecture Name]` / `[Tên Kiến trúc]`
|
||||
- `[Guide Title]` / `[Tiêu đề Hướng dẫn]`
|
||||
- `[Pattern Name]` / `[Tên Pattern]`
|
||||
- Code examples
|
||||
- Mermaid diagrams
|
||||
Thay thế các placeholder trong template:
|
||||
- `[Tên Kiến trúc]` → Tên thực của document
|
||||
- `[Tiêu đề]` → Tiêu đề sections
|
||||
- `[Mô tả]` → Nội dung thực tế
|
||||
|
||||
---
|
||||
### Bước 4: Tùy chỉnh Nội dung
|
||||
|
||||
## Using Architecture Template / Sử dụng Architecture Template
|
||||
- Điền vào tất cả sections
|
||||
- Tạo Mermaid diagrams (xem [mermaid-guide.md](./mermaid-guide.md))
|
||||
- Thêm code examples với comments song ngữ
|
||||
- Cập nhật metadata (Last Updated, Authors)
|
||||
|
||||
### Sections to Complete / Sections Cần hoàn thành
|
||||
### Bước 5: Review Checklist
|
||||
|
||||
#### 1. Overview Diagram
|
||||
**EN**: Create a high-level diagram showing main components
|
||||
- [ ] Tất cả placeholders đã được thay thế
|
||||
- [ ] Mermaid diagrams hiển thị đúng
|
||||
- [ ] Code examples có syntax highlighting
|
||||
- [ ] Có đầy đủ nội dung tiếng Việt
|
||||
- [ ] Links hoạt động chính xác
|
||||
- [ ] Metadata được cập nhật
|
||||
|
||||
**VI**: Tạo sơ đồ cấp cao cho thấy các thành phần chính
|
||||
## Quy ước Viết Tài liệu
|
||||
|
||||
**Diagram Type**: Use `graph TD` or `C4Context`
|
||||
### Ngôn ngữ
|
||||
|
||||
**Example**:
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Component A] --> B[Component B]
|
||||
B --> C[Component C]
|
||||
```
|
||||
**Tiếng Việt**:
|
||||
- Sử dụng 100% tiếng Việt cho tất cả nội dung
|
||||
- Giữ thuật ngữ kỹ thuật bằng tiếng Anh khi cần (Docker, Kubernetes, etc.)
|
||||
- Code examples vẫn giữ nguyên tiếng Anh
|
||||
|
||||
#### 2. Architecture Description
|
||||
**EN**: Explain purpose, goals, and design decisions
|
||||
|
||||
**VI**: Giải thích mục đích, mục tiêu và quyết định thiết kế
|
||||
|
||||
**Content to Include**:
|
||||
- Purpose and goals / Mục đích và mục tiêu
|
||||
- Key components / Thành phần chính
|
||||
- Design decisions / Quyết định thiết kế
|
||||
- Technology choices / Lựa chọn công nghệ
|
||||
- Trade-offs / Đánh đổi
|
||||
|
||||
#### 3. Components Breakdown
|
||||
**EN**: Detail each major component with:
|
||||
- Description
|
||||
- Key features
|
||||
- Technologies used
|
||||
- Code references (links to actual source)
|
||||
- File location
|
||||
|
||||
**VI**: Chi tiết từng thành phần chính với:
|
||||
- Mô tả
|
||||
- Tính năng chính
|
||||
- Công nghệ sử dụng
|
||||
- Tham chiếu code (links tới source thực tế)
|
||||
- Vị trí file
|
||||
|
||||
**Code Reference Format**:
|
||||
**Code Comments**:
|
||||
```typescript
|
||||
// EN: Example code showing implementation
|
||||
// VI: Ví dụ code cho thấy cách triển khai
|
||||
import { Component } from './component';
|
||||
```
|
||||
|
||||
**File Link**: [`component.ts`](file:///absolute/path/to/component.ts)
|
||||
|
||||
#### 4. Data Flow Diagram
|
||||
**Diagram Type**: Use `sequenceDiagram`
|
||||
|
||||
**Shows**: How data flows through the system
|
||||
|
||||
#### 5. Database Architecture (if applicable)
|
||||
**Diagram Type**: Use `erDiagram`
|
||||
|
||||
**Shows**: Database schema and relationships
|
||||
|
||||
#### 6. Design Decisions
|
||||
**Format**:
|
||||
- **Context**: Why decision was needed
|
||||
- **Decision**: What was decided
|
||||
- **Consequences**: Impact (positive and negative)
|
||||
- **Alternatives**: Other options considered
|
||||
|
||||
---
|
||||
|
||||
## Using Guide Template / Sử dụng Guide Template
|
||||
|
||||
### Sections to Complete / Sections Cần hoàn thành
|
||||
|
||||
#### 1. Workflow Diagram
|
||||
**Diagram Type**: Use `flowchart LR` or `flowchart TD`
|
||||
|
||||
**Shows**: Overall workflow from start to finish
|
||||
|
||||
**Include**:
|
||||
- Start/End nodes (rounded)
|
||||
- Decision points (diamond)
|
||||
- Action steps (rectangle)
|
||||
- Error handling paths
|
||||
|
||||
#### 2. Prerequisites
|
||||
**List**:
|
||||
- Required software with versions
|
||||
- Required knowledge
|
||||
- Required access/credentials
|
||||
|
||||
**Include Quick Check**:
|
||||
```bash
|
||||
# Commands to verify prerequisites
|
||||
node --version
|
||||
docker --version
|
||||
```
|
||||
|
||||
#### 3. Step-by-Step Instructions
|
||||
**For Each Step**:
|
||||
- Clear title
|
||||
- Bilingual explanation
|
||||
- Commands with comments
|
||||
- Expected output
|
||||
- Important notes
|
||||
- File examples
|
||||
|
||||
**Format**:
|
||||
```markdown
|
||||
### Step 1: [Action]
|
||||
|
||||
**EN**: English explanation
|
||||
|
||||
**VI**: Giải thích tiếng Việt
|
||||
|
||||
\`\`\`bash
|
||||
# EN: Command description
|
||||
# VI: Mô tả lệnh
|
||||
command-here
|
||||
\`\`\`
|
||||
```
|
||||
|
||||
#### 4. Verification
|
||||
**Include**:
|
||||
- Quick test commands
|
||||
- Verification checklist
|
||||
- Expected results
|
||||
|
||||
#### 5. Troubleshooting
|
||||
**For Each Issue**:
|
||||
- Symptoms (what you see)
|
||||
- Solution (steps to fix)
|
||||
- Bilingual for both
|
||||
|
||||
**Optional**: Add troubleshooting decision tree
|
||||
|
||||
---
|
||||
|
||||
## Using Skill/Pattern Template / Sử dụng Skill/Pattern Template
|
||||
|
||||
### Sections to Complete / Sections Cần hoàn thành
|
||||
|
||||
#### 1. Pattern Overview Diagram
|
||||
**Diagram Type**: Use `graph LR` or `graph TD`
|
||||
|
||||
**Shows**: High-level pattern flow
|
||||
|
||||
#### 2. When to Use
|
||||
**Include**:
|
||||
- ✅ DO use for (scenarios)
|
||||
- ❌ DON'T use for (anti-patterns)
|
||||
|
||||
#### 3. Implementation
|
||||
**Provide**:
|
||||
- Basic implementation (simple)
|
||||
- Advanced implementation (with caching, error handling, etc.)
|
||||
- Bilingual code comments
|
||||
|
||||
**Code Format**:
|
||||
```typescript
|
||||
/**
|
||||
* EN: Class description
|
||||
* VI: Mô tả class
|
||||
*/
|
||||
export class ExamplePattern {
|
||||
// EN: Implementation details
|
||||
// VI: Chi tiết triển khai
|
||||
// Ví dụ code với comments tiếng Việt
|
||||
export class Example {
|
||||
/**
|
||||
* Khởi tạo service với dependencies
|
||||
*/
|
||||
constructor(private dependency: Dependency) {}
|
||||
}
|
||||
```
|
||||
|
||||
**Reference Actual Code**:
|
||||
- Link to `_template` for basic patterns
|
||||
- Link to `iam-service` for advanced patterns
|
||||
### Mermaid Diagrams
|
||||
|
||||
**Example**:
|
||||
```markdown
|
||||
**Template**: [`feature.service.ts`](file:///Users/velikho/Desktop/WORKING/Base/services/_template/src/modules/feature/feature.service.ts)
|
||||
|
||||
**IAM**: [`rbac.service.ts`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service/src/modules/rbac/rbac.service.ts)
|
||||
```
|
||||
|
||||
#### 4. Class Structure Diagram
|
||||
**Diagram Type**: Use `classDiagram`
|
||||
|
||||
**Shows**: Class relationships, inheritance, dependencies
|
||||
|
||||
#### 5. Sequence Flow
|
||||
**Diagram Type**: Use `sequenceDiagram`
|
||||
|
||||
**Shows**: Interaction between components
|
||||
|
||||
#### 6. Usage Examples
|
||||
**Provide**:
|
||||
- Example 1: Basic usage
|
||||
- Example 2: Advanced usage
|
||||
- Include setup, execution, and expected output
|
||||
|
||||
#### 7. Common Mistakes
|
||||
**For Each Mistake**:
|
||||
```markdown
|
||||
#### Mistake 1: [Description]
|
||||
|
||||
\`\`\`typescript
|
||||
// ❌ BAD: Incorrect implementation
|
||||
bad code here
|
||||
\`\`\`
|
||||
|
||||
\`\`\`typescript
|
||||
// ✅ GOOD: Correct implementation
|
||||
good code here
|
||||
\`\`\`
|
||||
|
||||
**EN Why**: Explanation
|
||||
|
||||
**VI Tại sao**: Giải thích
|
||||
```
|
||||
|
||||
#### 8. Unit Test Example
|
||||
**Include**:
|
||||
- Setup (before each)
|
||||
- Test cases (happy path + error cases)
|
||||
- Assertions
|
||||
|
||||
---
|
||||
|
||||
## Bilingual Content Guidelines / Hướng dẫn Nội dung Song ngữ
|
||||
|
||||
### Format Options / Tùy chọn Định dạng
|
||||
|
||||
#### Option 1: Side-by-side (for short content)
|
||||
```markdown
|
||||
> **EN**: Brief English description
|
||||
> **VI**: Mô tả ngắn gọn tiếng Việt
|
||||
```
|
||||
|
||||
#### Option 2: Separate sections (for detailed content)
|
||||
```markdown
|
||||
### EN: English Section
|
||||
|
||||
Detailed English content...
|
||||
|
||||
### VI: Phần Tiếng Việt
|
||||
|
||||
Nội dung chi tiết tiếng Việt...
|
||||
```
|
||||
|
||||
#### Option 3: Inline (for code comments)
|
||||
```typescript
|
||||
// EN: English comment
|
||||
// VI: Comment tiếng Việt
|
||||
const example = 'value';
|
||||
```
|
||||
|
||||
### Translation Consistency / Tính nhất quán Dịch thuật
|
||||
|
||||
**Common Technical Terms**:
|
||||
| EN | VI |
|
||||
|----|-----|
|
||||
| Authentication | Xác thực |
|
||||
| Authorization | Phân quyền |
|
||||
| Deployment | Triển khai |
|
||||
| Middleware | Middleware (giữ nguyên) |
|
||||
| Repository | Repository (giữ nguyên) |
|
||||
| Service | Service (giữ nguyên) |
|
||||
| Controller | Controller (giữ nguyên) |
|
||||
| Microservice | Microservice (giữ nguyên) |
|
||||
| Cache | Cache (giữ nguyên) |
|
||||
| Database | Database (giữ nguyên) |
|
||||
|
||||
**Note**: Some technical terms are kept in English for clarity and consistency with code.
|
||||
|
||||
---
|
||||
|
||||
## Adding Mermaid Diagrams / Thêm Sơ đồ Mermaid
|
||||
|
||||
### Step 1: Choose Diagram Type
|
||||
|
||||
Refer to [`MERMAID_GUIDE.md`](./MERMAID_GUIDE.md) for:
|
||||
- Diagram type selection
|
||||
- Syntax examples
|
||||
- Styling guidelines
|
||||
|
||||
### Step 2: Create Diagram
|
||||
|
||||
```markdown
|
||||
\`\`\`mermaid
|
||||
graph TD
|
||||
A[Start] --> B[Process]
|
||||
B --> C[End]
|
||||
\`\`\`
|
||||
```
|
||||
|
||||
### Step 3: Test Rendering
|
||||
|
||||
```bash
|
||||
# Install mermaid-cli
|
||||
npm install -g @mermaid-js/mermaid-cli
|
||||
|
||||
# Test render your doc
|
||||
mmdc -i docs/en/your-doc.md -o test-output.svg
|
||||
|
||||
# Check for errors
|
||||
echo $? # 0 = success
|
||||
```
|
||||
|
||||
### Step 4: Apply Consistent Styling
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Start([Start]) --> Process[Process]
|
||||
Process --> End([End])
|
||||
|
||||
style Start fill:#e1f5ff
|
||||
style End fill:#d4edda
|
||||
style Process fill:#f0e1ff
|
||||
```
|
||||
Tham khảo [Hướng dẫn Mermaid](./mermaid-guide.md) để biết:
|
||||
- Các loại diagrams có sẵn
|
||||
- Color scheme chuẩn
|
||||
- Best practices
|
||||
- Ví dụ cho mỗi loại diagram
|
||||
|
||||
**Color Palette**:
|
||||
- `#e1f5ff` - Blue (primary, start)
|
||||
- `#d4edda` - Green (success, end)
|
||||
- `#fff3cd` - Yellow (warning, decision)
|
||||
- `#f8d7da` - Red (error)
|
||||
- `#f0e1ff` - Purple (process)
|
||||
- `#fff4e1` - Beige (data)
|
||||
|
||||
---
|
||||
|
||||
## Quality Checklist / Checklist Chất lượng
|
||||
|
||||
### Before Committing / Trước khi Commit
|
||||
|
||||
- [ ] **Content Complete**: All sections filled
|
||||
- [ ] **Bilingual**: EN and VI content both complete
|
||||
- [ ] **Mermaid Diagrams**: At least 2-3 diagrams
|
||||
- [ ] **Diagrams Render**: Tested with mermaid-cli
|
||||
- [ ] **Code Examples**: From actual source code
|
||||
- [ ] **File Links**: All links valid (file:///)
|
||||
- [ ] **Consistent Styling**: Colors and formatting consistent
|
||||
- [ ] **No Placeholders**: All [brackets] replaced
|
||||
- [ ] **Tested Commands**: All bash commands tested
|
||||
- [ ] **Grammar Check**: Both EN and VI proofread
|
||||
- [ ] **Cross-references**: Links to related docs work
|
||||
- [ ] **Metadata**: Last updated date, author filled
|
||||
|
||||
### EN/VI Parity Check
|
||||
|
||||
```bash
|
||||
# Compare line counts (should be similar)
|
||||
wc -l docs/en/your-doc.md
|
||||
wc -l docs/vi/your-doc.md
|
||||
|
||||
# Compare diagram counts
|
||||
grep -c '```mermaid' docs/en/your-doc.md
|
||||
grep -c '```mermaid' docs/vi/your-doc.md
|
||||
```
|
||||
#4A90E2 - Xanh dương (Primary actions)
|
||||
#F5A623 - Cam vàng (Data/Cache)
|
||||
#9013FE - Tím (Processing)
|
||||
#50E3C2 - Xanh lá (Success)
|
||||
#E74C3C - Đỏ (Errors)
|
||||
#F39C12 - Vàng cam (Warnings)
|
||||
#7B68EE - Tím xanh (Info)
|
||||
#95A5A6 - Xám (Neutral)
|
||||
```
|
||||
|
||||
---
|
||||
### File Organization
|
||||
|
||||
## Examples / Ví dụ
|
||||
```
|
||||
docs/vi/
|
||||
├── templates/ # Templates (file này)
|
||||
├── architecture/ # Architecture docs
|
||||
├── guides/ # How-to guides
|
||||
└── skills/ # Patterns & skills
|
||||
```
|
||||
|
||||
### Good Example: Kubernetes Local Guide
|
||||
## Thực hành Tốt nhất
|
||||
|
||||
**File**: [`docs/vi/guides/kubernetes-local.md`](../vi/guides/kubernetes-local.md)
|
||||
### 1. Viết Ngắn gọn và Rõ ràng
|
||||
|
||||
**Why it's good**:
|
||||
- ✅ Clear workflow diagram
|
||||
- ✅ Step-by-step instructions
|
||||
- ✅ Bilingual content
|
||||
- ✅ Verification steps
|
||||
- ✅ Troubleshooting section
|
||||
- ✅ Tested commands
|
||||
- Ngắn gọn, súc tích
|
||||
- Một ý chính mỗi paragraph
|
||||
- Sử dụng bullet points cho lists
|
||||
|
||||
### Good Example: IAM Service README
|
||||
### 2. Ưu tiên Hình ảnh
|
||||
|
||||
**File**: [`services/iam-service/README.md`](../../services/iam-service/README.md)
|
||||
- Thêm diagrams cho mọi concepts phức tạp
|
||||
- Sử dụng code examples với output
|
||||
- Screenshots khi cần (UI, browser)
|
||||
|
||||
**Why it's good**:
|
||||
- ✅ Comprehensive architecture diagrams
|
||||
- ✅ Clear API documentation
|
||||
- ✅ Real code examples
|
||||
- ✅ Well-organized sections
|
||||
- ✅ Quick reference tables
|
||||
### 3. Khả năng Bảo trì
|
||||
|
||||
- Link tới related documentation
|
||||
- Cập nhật "Last Updated" date
|
||||
- Ghi rõ version nếu có
|
||||
|
||||
### 4. Khả năng Truy cập
|
||||
|
||||
- Alt text cho images
|
||||
- Descriptive link text (không dùng "click here")
|
||||
- Headings có cấu trúc logic
|
||||
|
||||
## Mẹo Hữu ích
|
||||
|
||||
### Tạo Diagrams nhanh
|
||||
|
||||
```bash
|
||||
# Sử dụng Mermaid Live Editor
|
||||
# https://mermaid.live/
|
||||
```
|
||||
|
||||
### Validate Markdown
|
||||
|
||||
```bash
|
||||
# Cài đặt markdownlint
|
||||
pnpm add -g markdownlint-cli
|
||||
|
||||
# Check markdown files
|
||||
markdownlint docs/vi/**/*.md
|
||||
```
|
||||
|
||||
### Link Format
|
||||
|
||||
```markdown
|
||||
# Relative links (ưu tiên)
|
||||
[Architecture](../architecture/system-design.md)
|
||||
|
||||
# Với line numbers (file links)
|
||||
[Code Example](file:///path/to/file.ts#L10-L20)
|
||||
```
|
||||
|
||||
## Khắc phục Sự cố
|
||||
|
||||
### Mermaid không hiển thị?
|
||||
|
||||
1. Kiểm tra syntax với [Mermaid Live Editor](https://mermaid.live/)
|
||||
2. Đảm bảo code block có `mermaid` language tag
|
||||
3. Không có ký tự đặc biệt chưa escape
|
||||
|
||||
---
|
||||
|
||||
## Getting Help / Nhận Trợ giúp
|
||||
|
||||
### Questions / Câu hỏi
|
||||
|
||||
1. **Which template to use?** → See decision tree above
|
||||
2. **How to create diagrams?** → See `MERMAID_GUIDE.md`
|
||||
3. **How to structure bilingual content?** → See "Bilingual Content Guidelines"
|
||||
4. **Where to find code examples?** → Look in `_template` or `iam-service`
|
||||
|
||||
### Resources / Tài nguyên
|
||||
|
||||
- [Mermaid Guide](./MERMAID_GUIDE.md) - Diagram reference
|
||||
- [Architecture Template](./architecture-doc-template.md) - Template file
|
||||
- [Guide Template](./guide-doc-template.md) - Template file
|
||||
- [Skill Template](./skill-pattern-template.md) - Template file
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-01-07
|
||||
**Maintained by**: VelikHo ([@hongochai10](https://github.com/hongochai10))
|
||||
**Tác giả**: VelikHo (hongochai10@icloud.com)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview / Tổng quan
|
||||
|
||||
**EN**: This guide helps you choose the right Mermaid diagram type for your documentation and provides examples for common use cases.
|
||||
**EN**: This guide helps you choose the right Mermaid diagram type for your documentation and provides examples for common use cases. All color schemes and patterns shown here are actively used in GoodGo Platform documentation.
|
||||
|
||||
**VI**: Hướng dẫn này giúp bạn chọn loại sơ đồ Mermaid phù hợp cho tài liệu của bạn và cung cấp ví dụ cho các trường hợp sử dụng phổ biến.
|
||||
|
||||
|
||||
@@ -1,71 +1,73 @@
|
||||
# Node.js Microservice Template
|
||||
# Template Microservice Node.js
|
||||
|
||||
> Standard template for creating new microservices in the @goodgo ecosystem using Node.js/TypeScript.
|
||||
> Template chuẩn để tạo các microservice mới trong hệ sinh thái @goodgo sử dụng Node.js/TypeScript.
|
||||
|
||||
## Overview
|
||||
## Tổng Quan
|
||||
|
||||
This template provides a complete, production-ready foundation for building individual microservices with:
|
||||
Template này cung cấp nền tảng hoàn chỉnh, sẵn sàng production để xây dựng các microservice với:
|
||||
|
||||
- **Framework**: Express.js with TypeScript
|
||||
- **Database**: Prisma ORM with PostgreSQL
|
||||
- **Validation**: Zod for environment & input validation
|
||||
- **Observability**: Prometheus metrics, structured logging, OpenTelemetry/Jaeger tracing
|
||||
> **Lưu ý**: Template này dành cho tương lai. Hiện tại dự án GoodGo chủ yếu sử dụng .NET services. Xem [dotnet-template.md](./dotnet-template.md) cho template đang sử dụng.
|
||||
|
||||
- **Framework**: Express.js với TypeScript
|
||||
- **Database**: Prisma ORM với PostgreSQL
|
||||
- **Validation**: Zod cho validation biến môi trường và đầu vào
|
||||
- **Observability**: Prometheus metrics, logging có cấu trúc, tích hợp OpenTelemetry/Jaeger
|
||||
- **Resilience**: Graceful shutdown, rate limiting (Redis), circuit breaker, health checks
|
||||
- **Caching**: Redis caching strategy
|
||||
- **Security**: Helmet & CORS configured
|
||||
- **Caching**: Chiến lược caching với Redis
|
||||
- **Security**: Đã cấu hình Helmet & CORS
|
||||
|
||||
## Project Structure
|
||||
## Cấu Trúc Dự Án
|
||||
|
||||
```
|
||||
src/
|
||||
├── config/ # Configuration & Env validation
|
||||
├── config/ # Cấu hình & Validate biến môi trường
|
||||
├── middlewares/ # Express middlewares (error, logger, metrics)
|
||||
├── modules/ # Feature modules (controller, service, repository)
|
||||
├── routes/ # API route definitions
|
||||
├── routes/ # Định nghĩa API routes
|
||||
└── main.ts # Entry point & App bootstrapping
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
## Bắt Đầu
|
||||
|
||||
### Prerequisites
|
||||
### Yêu Cầu
|
||||
|
||||
- Node.js >= 20
|
||||
- pnpm
|
||||
- Docker (Redis required)
|
||||
- Docker (yêu cầu Redis)
|
||||
|
||||
### Installation
|
||||
### Cài Đặt
|
||||
|
||||
1. **Clone & Install dependencies**:
|
||||
1. **Clone & Cài đặt dependencies**:
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
2. **Start infrastructure**:
|
||||
2. **Khởi động infrastructure**:
|
||||
```bash
|
||||
cd deployments/local
|
||||
docker-compose up -d redis
|
||||
```
|
||||
|
||||
3. **Setup database**:
|
||||
3. **Thiết lập database**:
|
||||
```bash
|
||||
pnpm prisma migrate dev
|
||||
pnpm prisma db seed
|
||||
```
|
||||
|
||||
4. **Start development server**:
|
||||
4. **Khởi động development server**:
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Architecture
|
||||
## Kiến Trúc
|
||||
|
||||
### Layer Architecture
|
||||
### Kiến Trúc Phân Lớp
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Request[HTTP Request] --> Middleware[Middleware Chain]
|
||||
|
||||
subgraph SingleService[Single Service Boundary]
|
||||
subgraph SingleService[Ranh Giới Service]
|
||||
Middleware --> Correlation[Correlation ID]
|
||||
Correlation --> Auth[Authentication]
|
||||
Auth --> Validation[Validation]
|
||||
@@ -87,66 +89,66 @@ graph TD
|
||||
style Validation fill:#e8f5e8
|
||||
```
|
||||
|
||||
### Middleware Chain
|
||||
### Chuỗi Middleware
|
||||
|
||||
1. **Correlation Middleware**: Generates/propagates correlation and request IDs
|
||||
2. **Authentication Middleware**: Validates JWT tokens
|
||||
3. **Validation Middleware**: Validates input data with Zod schemas
|
||||
4. **Error Handler**: Catches and formats errors
|
||||
5. **Logger Middleware**: Logs request/response
|
||||
6. **Metrics Middleware**: Collects Prometheus metrics
|
||||
1. **Correlation Middleware**: Tạo/truyền correlation và request IDs
|
||||
2. **Authentication Middleware**: Xác thực JWT tokens
|
||||
3. **Validation Middleware**: Validate dữ liệu đầu vào với Zod schemas
|
||||
4. **Error Handler**: Bắt và format lỗi
|
||||
5. **Logger Middleware**: Ghi log request/response
|
||||
6. **Metrics Middleware**: Thu thập Prometheus metrics
|
||||
|
||||
### Controller → Service → Repository Pattern
|
||||
### Pattern Controller → Service → Repository
|
||||
|
||||
- **Controller**: Handles HTTP requests, orchestrates services
|
||||
- **Service**: Contains business logic, independent of HTTP
|
||||
- **Repository**: Abstracts database operations with Prisma
|
||||
- **Controller**: Xử lý HTTP requests, điều phối services
|
||||
- **Service**: Chứa business logic, độc lập với HTTP
|
||||
- **Repository**: Trừu tượng hóa thao tác database với Prisma
|
||||
|
||||
## API Endpoints
|
||||
## Các API Endpoints
|
||||
|
||||
### Health Endpoints
|
||||
|
||||
| Endpoint | Purpose |
|
||||
|----------|---------|
|
||||
| `/health` | Full health status |
|
||||
| `/health/live` | Liveness probe |
|
||||
| `/health/ready` | Readiness probe |
|
||||
| Endpoint | Mục Đích |
|
||||
|----------|----------|
|
||||
| `/health` | Trạng thái health đầy đủ |
|
||||
| `/health/live` | Kiểm tra sống |
|
||||
| `/health/ready` | Kiểm tra sẵn sàng |
|
||||
|
||||
### Feature Management
|
||||
### Quản Lý Feature
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/v1/features` | Get all features |
|
||||
| `GET` | `/api/v1/features/{id}` | Get feature by ID |
|
||||
| `POST` | `/api/v1/features` | Create feature (admin) |
|
||||
| `PUT` | `/api/v1/features/{id}` | Update feature |
|
||||
| `DELETE` | `/api/v1/features/{id}` | Delete feature |
|
||||
| `PATCH` | `/api/v1/features/{id}/toggle` | Toggle status |
|
||||
| Method | Endpoint | Mô Tả |
|
||||
|--------|----------|-------|
|
||||
| `GET` | `/api/v1/features` | Lấy tất cả features |
|
||||
| `GET` | `/api/v1/features/{id}` | Lấy feature theo ID |
|
||||
| `POST` | `/api/v1/features` | Tạo feature (admin) |
|
||||
| `PUT` | `/api/v1/features/{id}` | Cập nhật feature |
|
||||
| `DELETE` | `/api/v1/features/{id}` | Xóa feature |
|
||||
| `PATCH` | `/api/v1/features/{id}/toggle` | Chuyển đổi trạng thái |
|
||||
|
||||
## Response Format
|
||||
## Định Dạng Response
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": { ... },
|
||||
"message": "Operation completed",
|
||||
"message": "Hoạt động hoàn thành",
|
||||
"timestamp": "2024-01-01T00:00:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
## Biến Môi Trường
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `PORT` | Server port | No (default: 5000) |
|
||||
| `DATABASE_URL` | PostgreSQL connection | **Yes** |
|
||||
| `REDIS_URL` | Redis connection | No |
|
||||
| `JWT_SECRET` | JWT secret key | **Yes** |
|
||||
| `TRACING_ENABLED` | Enable Jaeger tracing | No |
|
||||
| Biến | Mô Tả | Bắt buộc |
|
||||
|------|-------|----------|
|
||||
| `PORT` | Cổng server | Không (mặc định: 5000) |
|
||||
| `DATABASE_URL` | Kết nối PostgreSQL | **Có** |
|
||||
| `REDIS_URL` | Kết nối Redis | Không |
|
||||
| `JWT_SECRET` | Khóa bí mật JWT | **Có** |
|
||||
| `TRACING_ENABLED` | Bật Jaeger tracing | Không |
|
||||
|
||||
## Platform Integration
|
||||
## Tích Hợp Nền Tảng
|
||||
|
||||
### Add to docker-compose.yml
|
||||
### Thêm vào docker-compose.yml
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@@ -160,23 +162,23 @@ services:
|
||||
- "traefik.http.services.your-service.loadbalancer.server.port=5002"
|
||||
```
|
||||
|
||||
### Access Points
|
||||
### Điểm Truy Cập
|
||||
|
||||
- **API**: http://localhost/api/v1/your-service
|
||||
- **Health**: http://localhost/api/v1/your-service/health
|
||||
- **API Docs**: http://localhost/api/v1/your-service/api-docs
|
||||
- **Traefik Dashboard**: http://localhost:8080
|
||||
|
||||
## Testing
|
||||
## Kiểm Thử
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
# Chạy tất cả tests
|
||||
pnpm test
|
||||
|
||||
# Run with coverage
|
||||
# Chạy với coverage
|
||||
pnpm test:coverage
|
||||
|
||||
# Run E2E tests
|
||||
# Chạy E2E tests
|
||||
pnpm test:e2e
|
||||
```
|
||||
|
||||
@@ -186,29 +188,29 @@ pnpm test:e2e
|
||||
# Build image
|
||||
docker build -t your-service:latest .
|
||||
|
||||
# Run container
|
||||
# Chạy container
|
||||
docker run -p 5000:5000 --env-file .env your-service:latest
|
||||
```
|
||||
|
||||
## Creating a New Service
|
||||
## Tạo Service Mới
|
||||
|
||||
1. Copy template:
|
||||
1. Sao chép template:
|
||||
```bash
|
||||
cp -r services/_template_nodejs services/your-service-name
|
||||
```
|
||||
|
||||
2. Update `package.json` name
|
||||
2. Cập nhật tên trong `package.json`
|
||||
|
||||
3. Configure environment in `deployments/local/.env.local`
|
||||
3. Cấu hình môi trường trong `deployments/local/.env.local`
|
||||
|
||||
4. Update Prisma schema and run migrations
|
||||
4. Cập nhật Prisma schema và chạy migrations
|
||||
|
||||
5. Implement your modules in `src/modules/`
|
||||
5. Triển khai modules trong `src/modules/`
|
||||
|
||||
6. Register in `deployments/local/docker-compose.yml`
|
||||
6. Đăng ký trong `deployments/local/docker-compose.yml`
|
||||
|
||||
## Related Documentation
|
||||
## Tài Liệu Liên Quan
|
||||
|
||||
- [Architecture Details](../architecture/microservices-communication.md)
|
||||
- [API Design Standards](../guides/api-design.md)
|
||||
- [Testing Patterns](../guides/testing.md)
|
||||
- [Chi Tiết Kiến Trúc](../architecture/microservices-communication.md)
|
||||
- [Tiêu Chuẩn Thiết Kế API](../guides/api-design.md)
|
||||
- [Patterns Kiểm Thử](../guides/testing.md)
|
||||
|
||||
@@ -138,61 +138,45 @@ export class ExamplePattern {
|
||||
```
|
||||
|
||||
**File Location / Vị trí File**:
|
||||
- **Template**: [`_template/src/modules/example/example.pattern.ts`](file:///Users/velikho/Desktop/WORKING/Base/services/_template/src/modules/example/example.pattern.ts)
|
||||
- **Production**: [`iam-service/src/modules/example/example.pattern.ts`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service/src/modules/example/example.pattern.ts)
|
||||
- **Skill Template**: [`.agent/skills/skill-authoring/SKILL.md`](file:///Users/velikho/Desktop/WORKING/Base/.agent/skills/skill-authoring/SKILL.md)
|
||||
- **Example Skills**: [`.agent/skills/`](file:///Users/velikho/Desktop/WORKING/Base/.agent/skills)
|
||||
|
||||
### Advanced Implementation / Triển khai Nâng cao
|
||||
|
||||
**EN**: More complex implementation with additional features.
|
||||
**EN**: More complex implementation with additional features like caching and error handling.
|
||||
|
||||
**VI**: Triển khai phức tạp hơn với các tính năng bổ sung.
|
||||
**VI**: Triển khai phức tạp hơn với các tính năng bổ sung như caching và xử lý lỗi.
|
||||
|
||||
```typescript
|
||||
// EN: Advanced implementation with caching and error handling
|
||||
// VI: Triển khai nâng cao với caching và xử lý lỗi
|
||||
```csharp
|
||||
// EN: Advanced .NET implementation with caching
|
||||
// VI: Triển khai .NET nâng cao với caching
|
||||
|
||||
export class AdvancedExamplePattern extends ExamplePattern {
|
||||
constructor(
|
||||
dependency1: Dependency1,
|
||||
dependency2: Dependency2,
|
||||
private cache: CacheService,
|
||||
private logger: Logger
|
||||
) {
|
||||
super(dependency1, dependency2);
|
||||
}
|
||||
public class CachedStorageProvider : IStorageProvider
|
||||
{
|
||||
private readonly IStorageProvider _innerProvider;
|
||||
private readonly IDistributedCache _cache;
|
||||
private readonly ILogger<CachedStorageProvider> _logger;
|
||||
|
||||
async execute(input: InputType): Promise<OutputType> {
|
||||
// EN: Try cache first
|
||||
// VI: Thử cache trước
|
||||
const cacheKey = this.getCacheKey(input);
|
||||
const cached = await this.cache.get<OutputType>(cacheKey);
|
||||
|
||||
if (cached) {
|
||||
this.logger.info('Cache hit', { key: cacheKey });
|
||||
return cached;
|
||||
public async Task<string> UploadFileAsync(Stream fileStream, string fileName, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
// EN: Upload file
|
||||
// VI: Upload file
|
||||
var result = await _innerProvider.UploadFileAsync(fileStream, fileName, ct);
|
||||
|
||||
// EN: Invalidate cache
|
||||
// VI: Vô hiệu hóa cache
|
||||
await _cache.RemoveAsync($"file:{fileName}", ct);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to upload file {FileName}", fileName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// EN: Execute pattern logic
|
||||
// VI: Thực thi logic pattern
|
||||
const result = await super.execute(input);
|
||||
|
||||
// EN: Cache result
|
||||
// VI: Cache kết quả
|
||||
await this.cache.set(cacheKey, result, 300); // 5 minutes
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
// EN: Error handling
|
||||
// VI: Xử lý lỗi
|
||||
this.logger.error('Pattern execution failed', { error, input });
|
||||
throw new PatternExecutionError('Execution failed', { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
private getCacheKey(input: InputType): string {
|
||||
return `pattern:example:${JSON.stringify(input)}`;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -255,61 +239,77 @@ sequenceDiagram
|
||||
|
||||
## Usage Examples / Ví dụ Sử dụng
|
||||
|
||||
### Example 1 / Ví dụ 1: Basic Usage
|
||||
### Example 1: Multi-Provider Storage Pattern (Real-World)
|
||||
|
||||
**EN**: Basic usage scenario with explanation.
|
||||
**EN**: Real implementation from Storage Service.
|
||||
|
||||
**VI**: Tình huống sử dụng cơ bản với giải thích.
|
||||
**VI**: Triển khai thực tế từ Storage Service.
|
||||
|
||||
```typescript
|
||||
// EN: Setup
|
||||
// VI: Thiết lập
|
||||
const dependency1 = new Dependency1();
|
||||
const dependency2 = new Dependency2();
|
||||
const pattern = new ExamplePattern(dependency1, dependency2);
|
||||
```csharp
|
||||
// Domain interface
|
||||
public interface IStorageProvider
|
||||
{
|
||||
Task<string> UploadFileAsync(Stream fileStream, string fileName, CancellationToken ct);
|
||||
Task<string> GeneratePresignedUrlAsync(string objectKey, int expiryMinutes, CancellationToken ct);
|
||||
}
|
||||
|
||||
// EN: Execute pattern
|
||||
// VI: Thực thi pattern
|
||||
const input: InputType = {
|
||||
id: '123',
|
||||
data: 'example',
|
||||
};
|
||||
|
||||
const result = await pattern.execute(input);
|
||||
|
||||
console.log(result);
|
||||
// EN: Output / VI: Kết quả:
|
||||
// { success: true, data: { ... } }
|
||||
// Factory pattern
|
||||
public class StorageProviderFactory
|
||||
{
|
||||
public IStorageProvider CreateProvider(string providerName)
|
||||
{
|
||||
return providerName?.ToLower() switch
|
||||
{
|
||||
"minio" => _serviceProvider.GetRequiredService<MinioStorageProvider>(),
|
||||
"aliyun" => _serviceProvider.GetRequiredService<AliyunOssStorageProvider>(),
|
||||
_ => throw new InvalidOperationException($"Unknown provider: {providerName}")
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2 / Ví dụ 2: Advanced Usage with Caching
|
||||
**File Reference**: [`services/storage-service-net/src/StorageService.Infrastructure/Providers/`](file:///Users/velikho/Desktop/WORKING/Base/services/storage-service-net/src/StorageService.Infrastructure/Providers)
|
||||
|
||||
**EN**: Advanced usage with caching enabled.
|
||||
---
|
||||
|
||||
**VI**: Sử dụng nâng cao với caching được bật.
|
||||
### Example 2: CQRS with MediatR (Real-World)
|
||||
|
||||
```typescript
|
||||
// EN: Setup with additional dependencies
|
||||
// VI: Thiết lập với các dependencies bổ sung
|
||||
const cache = new CacheService();
|
||||
const logger = new Logger();
|
||||
const pattern = new AdvancedExamplePattern(
|
||||
dependency1,
|
||||
dependency2,
|
||||
cache,
|
||||
logger
|
||||
);
|
||||
**EN**: Command handler pattern from actual services.
|
||||
|
||||
// EN: First call (cache miss)
|
||||
// VI: Lần gọi đầu tiên (cache miss)
|
||||
const result1 = await pattern.execute(input);
|
||||
**VI**: Pattern command handler từ các services thực tế.
|
||||
|
||||
// EN: Second call (cache hit)
|
||||
// VI: Lần gọi thứ hai (cache hit)
|
||||
const result2 = await pattern.execute(input); // Returns cached result
|
||||
```csharp
|
||||
// Command
|
||||
public record CreateFileCommand(string FileName, Stream FileStream, string UserId)
|
||||
: IRequest<CreateFileCommandResult>;
|
||||
|
||||
// Handler
|
||||
public class CreateFileCommandHandler : IRequestHandler<CreateFileCommand, CreateFileCommandResult>
|
||||
{
|
||||
private readonly IStorageProvider _storageProvider;
|
||||
private readonly IFileRepository _fileRepository;
|
||||
|
||||
public async Task<CreateFileCommandResult> Handle(CreateFileCommand request, CancellationToken ct)
|
||||
{
|
||||
// Upload to storage
|
||||
var objectKey = await _storageProvider.UploadFileAsync(
|
||||
request.FileStream,
|
||||
request.FileName,
|
||||
ct
|
||||
);
|
||||
|
||||
// Save metadata
|
||||
var file = new File(request.FileName, objectKey, request.UserId);
|
||||
await _fileRepository.AddAsync(file, ct);
|
||||
|
||||
return new CreateFileCommandResult(file.Id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Best Practices
|
||||
**File Reference**: See [CQRS with MediatR Skill](../skills/cqrs-mediatr.md)
|
||||
|
||||
## Best Practices / Thực hành Tốt nhất
|
||||
|
||||
### EN: Recommended Practices
|
||||
|
||||
@@ -372,81 +372,79 @@ if (input) {
|
||||
|
||||
## Testing / Kiểm thử
|
||||
|
||||
### Unit Test Example / Ví dụ Unit Test
|
||||
### Unit Test Example for .NET / Ví dụ Unit Test cho .NET
|
||||
|
||||
```typescript
|
||||
// EN: Unit test for the pattern
|
||||
// VI: Unit test cho pattern
|
||||
```csharp
|
||||
// EN: Unit test for CQRS command handler
|
||||
// VI: Unit test cho CQRS command handler
|
||||
|
||||
describe('ExamplePattern', () => {
|
||||
let pattern: ExamplePattern;
|
||||
let mockDep1: jest.Mocked<Dependency1>;
|
||||
let mockDep2: jest.Mocked<Dependency2>;
|
||||
using Xunit;
|
||||
using NSubstitute;
|
||||
|
||||
beforeEach(() => {
|
||||
mockDep1 = {
|
||||
transform: jest.fn(),
|
||||
} as any;
|
||||
mockDep2 = {} as any;
|
||||
public class CreateFileCommandHandlerTests
|
||||
{
|
||||
private readonly IStorageProvider _storageProvider;
|
||||
private readonly IFileRepository _fileRepository;
|
||||
private readonly CreateFileCommandHandler _handler;
|
||||
|
||||
pattern = new ExamplePattern(mockDep1, mockDep2);
|
||||
});
|
||||
public CreateFileCommandHandlerTests()
|
||||
{
|
||||
_storageProvider = Substitute.For<IStorageProvider>();
|
||||
_fileRepository = Substitute.For<IFileRepository>();
|
||||
_handler = new CreateFileCommandHandler(_storageProvider, _fileRepository);
|
||||
}
|
||||
|
||||
it('should execute successfully', async () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const input = { id: '123', data: 'test' };
|
||||
const expectedProcessed = { transformed: true };
|
||||
mockDep1.transform.mockResolvedValue(expectedProcessed);
|
||||
[Fact]
|
||||
public async Task Handle_ValidCommand_CreatesFileSuccessfully()
|
||||
{
|
||||
// Arrange
|
||||
var command = new CreateFileCommand("test.txt", Stream.Null, "user-123");
|
||||
_storageProvider.UploadFileAsync(Arg.Any<Stream>(), Arg.Any<string>(), Arg.Any<CancellationToken>())
|
||||
.Returns("object-key-123");
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực thi
|
||||
const result = await pattern.execute(input);
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data).toEqual(expectedProcessed);
|
||||
expect(mockDep1.transform).toHaveBeenCalledWith(input);
|
||||
});
|
||||
|
||||
it('should throw error for invalid input', async () => {
|
||||
// EN: Expect error for null input
|
||||
// VI: Mong đợi lỗi cho đầu vào null
|
||||
await expect(pattern.execute(null as any))
|
||||
.rejects
|
||||
.toThrow('Input is required');
|
||||
});
|
||||
});
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.FileId);
|
||||
await _fileRepository.Received(1).AddAsync(Arg.Any<File>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Reference**: See [Testing Patterns Skill](../skills/testing-patterns.md)
|
||||
|
||||
## Related Patterns / Patterns Liên quan
|
||||
|
||||
**EN**: Other patterns that complement or relate to this one.
|
||||
|
||||
**VI**: Các patterns khác bổ sung hoặc liên quan đến pattern này.
|
||||
|
||||
- [Related Pattern 1](./related-pattern-1.md) - EN: How it relates / VI: Cách nó liên quan
|
||||
- [Related Pattern 2](./related-pattern-2.md) - EN: Comparison / VI: So sánh
|
||||
- [Alternative Pattern](./alternative-pattern.md) - EN: When to use instead / VI: Khi nào sử dụng thay thế
|
||||
**GoodGo Skills**:
|
||||
- [CQRS with MediatR](../skills/cqrs-mediatr.md) - EN: Command/Query separation / VI: Tách biệt Command/Query
|
||||
- [Repository Pattern](../skills/repository-pattern.md) - EN: Data access abstraction / VI: Trừa tượng hóa truy cập dữ liệu
|
||||
- [Domain-Driven Design](../skills/domain-driven-design.md) - EN: DDD tactical patterns / VI: Patterns chiến thuật DDD
|
||||
- [Redis Caching](../skills/redis-caching.md) - EN: Distributed caching / VI: Caching phân tán
|
||||
- [Error Handling](../skills/error-handling-patterns.md) - EN: Exception patterns / VI: Patterns exception
|
||||
|
||||
## Real-World Examples / Ví dụ Thực tế
|
||||
|
||||
**EN**: Examples of this pattern used in the codebase.
|
||||
**EN**: Examples of this pattern used in the GoodGo codebase.
|
||||
|
||||
**VI**: Ví dụ về pattern này được sử dụng trong codebase.
|
||||
**VI**: Ví dụ về pattern này được sử dụng trong codebase GoodGo.
|
||||
|
||||
### Example from IAM Service
|
||||
### Storage Service - Multi-Provider Pattern
|
||||
|
||||
**File**: [`iam-service/src/modules/rbac/rbac.service.ts`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service/src/modules/rbac/rbac.service.ts)
|
||||
**File**: [`services/storage-service-net/src/StorageService.Infrastructure/Providers/`](file:///Users/velikho/Desktop/WORKING/Base/services/storage-service-net/src/StorageService.Infrastructure/Providers)
|
||||
|
||||
```typescript
|
||||
// EN: Real implementation from IAM service
|
||||
// VI: Triển khai thực tế từ IAM service
|
||||
export class RBACService implements ExamplePattern {
|
||||
// ... implementation
|
||||
}
|
||||
```
|
||||
**Pattern**: Factory pattern for switching between MinIO and Aliyun OSS providers.
|
||||
|
||||
### IAM Service - RBAC Pattern
|
||||
|
||||
**File**: [`services/iam-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service-net)
|
||||
|
||||
**Pattern**: Role-Based Access Control implementation with permission caching.
|
||||
|
||||
## Additional Resources / Tài nguyên Bổ sung
|
||||
|
||||
@@ -469,7 +467,6 @@ export class RBACService implements ExamplePattern {
|
||||
|
||||
---
|
||||
|
||||
**Last Updated / Cập nhật lần cuối**: YYYY-MM-DD
|
||||
**Complexity / Độ phức tạp**: Beginner/Intermediate/Advanced
|
||||
**Category / Danh mục**: [Category Name]
|
||||
**Authors / Tác giả**: Your Name
|
||||
**Authors / Tác giả**: VelikHo (hongochai10@icloud.com)
|
||||
|
||||
@@ -89,74 +89,72 @@ hit rate hit rate rate
|
||||
|
||||
## Triển khai Cache
|
||||
|
||||
### Multi-Layer Cache Service
|
||||
### Multi-Layer Cache Service (.NET)
|
||||
|
||||
```typescript
|
||||
// Triển khai multi-layer cache
|
||||
export class MultiLayerCache {
|
||||
private l1Cache: NodeCache;
|
||||
private l2Cache: Redis;
|
||||
|
||||
constructor() {
|
||||
// L1: Memory cache
|
||||
this.l1Cache = new NodeCache({
|
||||
stdTTL: 60, // 60 giây mặc định
|
||||
maxKeys: 10000, // Tối đa 10k keys
|
||||
checkperiod: 120 // Kiểm tra expired keys mỗi 2 phút
|
||||
});
|
||||
```csharp
|
||||
// EN: Multi-layer cache implementation
|
||||
// VI: Triển khai cache đa lớp
|
||||
public class MultiLayerCacheService : ICacheService
|
||||
{
|
||||
private readonly IMemoryCache _l1Cache;
|
||||
private readonly IConnectionMultiplexer _redis;
|
||||
private readonly IDatabase _l2Cache;
|
||||
private readonly ILogger<MultiLayerCacheService> _logger;
|
||||
|
||||
// L2: Redis cache
|
||||
this.l2Cache = new Redis({
|
||||
host: process.env.REDIS_HOST,
|
||||
port: parseInt(process.env.REDIS_PORT),
|
||||
db: 0
|
||||
});
|
||||
}
|
||||
|
||||
async get<T>(key: string): Promise<T | null> {
|
||||
// Thử L1 trước
|
||||
const l1Value = this.l1Cache.get<T>(key);
|
||||
if (l1Value) {
|
||||
logger.debug('L1 cache hit', { key });
|
||||
return l1Value;
|
||||
public MultiLayerCacheService(
|
||||
IMemoryCache l1Cache,
|
||||
IConnectionMultiplexer redis,
|
||||
ILogger<MultiLayerCacheService> logger)
|
||||
{
|
||||
_l1Cache = l1Cache;
|
||||
_redis = redis;
|
||||
_l2Cache = redis.GetDatabase();
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
// Thử L2
|
||||
const l2Value = await this.l2Cache.get(key);
|
||||
if (l2Value) {
|
||||
logger.debug('L2 cache hit', { key });
|
||||
const parsed = JSON.parse(l2Value) as T;
|
||||
|
||||
// Làm ấm L1 cache
|
||||
this.l1Cache.set(key, parsed);
|
||||
return parsed;
|
||||
public async Task<T?> GetAsync<T>(string key, CancellationToken ct = default)
|
||||
{
|
||||
// L1: Memory cache check
|
||||
if (_l1Cache.TryGetValue(key, out T? l1Value))
|
||||
{
|
||||
_logger.LogDebug("L1 cache hit for key: {Key}", key);
|
||||
return l1Value;
|
||||
}
|
||||
|
||||
// L2: Redis cache check
|
||||
var l2Value = await _l2Cache.StringGetAsync(key);
|
||||
if (!l2Value.IsNullOrEmpty)
|
||||
{
|
||||
_logger.LogDebug("L2 cache hit for key: {Key}", key);
|
||||
var parsed = JsonSerializer.Deserialize<T>(l2Value!);
|
||||
|
||||
// Warm L1 cache
|
||||
_l1Cache.Set(key, parsed, TimeSpan.FromMinutes(1));
|
||||
return parsed;
|
||||
}
|
||||
|
||||
_logger.LogDebug("Cache miss for key: {Key}", key);
|
||||
return default;
|
||||
}
|
||||
|
||||
logger.debug('Cache miss', { key });
|
||||
return null;
|
||||
}
|
||||
|
||||
async set(key: string, value: any, ttl: number = 300): Promise<void> {
|
||||
// Lưu vào cả L1 và L2
|
||||
this.l1Cache.set(key, value, Math.min(ttl, 300)); // L1 tối đa 5 phút
|
||||
await this.l2Cache.setex(key, ttl, JSON.stringify(value));
|
||||
}
|
||||
|
||||
async del(key: string): Promise<void> {
|
||||
this.l1Cache.del(key);
|
||||
await this.l2Cache.del(key);
|
||||
}
|
||||
|
||||
async invalidatePattern(pattern: string): Promise<void> {
|
||||
// L1: Xóa tất cả (cách đơn giản)
|
||||
this.l1Cache.flushAll();
|
||||
|
||||
// L2: Xóa theo pattern
|
||||
const keys = await this.l2Cache.keys(pattern);
|
||||
if (keys.length > 0) {
|
||||
await this.l2Cache.del(...keys);
|
||||
public async Task SetAsync<T>(string key, T value, TimeSpan? ttl = null, CancellationToken ct = default)
|
||||
{
|
||||
var expiry = ttl ?? TimeSpan.FromMinutes(5);
|
||||
var l1Expiry = TimeSpan.FromMinutes(Math.Min(expiry.TotalMinutes, 5));
|
||||
|
||||
// L1: Memory cache (max 5 min)
|
||||
_l1Cache.Set(key, value, l1Expiry);
|
||||
|
||||
// L2: Redis cache
|
||||
var json = JsonSerializer.Serialize(value);
|
||||
await _l2Cache.StringSetAsync(key, json, expiry);
|
||||
}
|
||||
|
||||
public async Task RemoveAsync(string key, CancellationToken ct = default)
|
||||
{
|
||||
_l1Cache.Remove(key);
|
||||
await _l2Cache.KeyDeleteAsync(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -164,19 +162,21 @@ export class MultiLayerCache {
|
||||
|
||||
**Pattern**: `{service}:{entity}:{identifier}:{sub-resource}`
|
||||
|
||||
**Ví dụ**:
|
||||
```typescript
|
||||
// User cache keys
|
||||
const keys = {
|
||||
user: (userId: string) => `iam:user:${userId}`,
|
||||
userPermissions: (userId: string) => `iam:user:${userId}:permissions`,
|
||||
userRoles: (userId: string) => `iam:user:${userId}:roles`,
|
||||
session: (sessionId: string) => `iam:session:${sessionId}`,
|
||||
};
|
||||
**Ví dụ (C#)**:
|
||||
```csharp
|
||||
// Cache key constants
|
||||
public static class CacheKeys
|
||||
{
|
||||
public static string User(string userId) => $"iam:user:{userId}";
|
||||
public static string UserPermissions(string userId) => $"iam:user:{userId}:permissions";
|
||||
public static string UserRoles(string userId) => $"iam:user:{userId}:roles";
|
||||
public static string Session(string sessionId) => $"iam:session:{sessionId}";
|
||||
public static string UserQuota(string userId) => $"storage:quota:{userId}";
|
||||
}
|
||||
|
||||
// Sử dụng
|
||||
const user = await cache.get(keys.user('user_123'));
|
||||
const permissions = await cache.get(keys.userPermissions('user_123'));
|
||||
var user = await _cache.GetAsync<UserDto>(CacheKeys.User("user_123"));
|
||||
var permissions = await _cache.GetAsync<List<string>>(CacheKeys.UserPermissions("user_123"));
|
||||
```
|
||||
|
||||
## Chiến lược TTL
|
||||
@@ -611,7 +611,7 @@ async function checkRedisHealth(): Promise<boolean> {
|
||||
|
||||
---
|
||||
|
||||
**Cập nhật Lần cuối**: 2026-01-07
|
||||
**Cập nhật Lần cuối**: 2026-01-14
|
||||
**Tác giả**: GoodGo Architecture Team
|
||||
|
||||
## Quick Tips
|
||||
|
||||
@@ -198,51 +198,48 @@ sequenceDiagram
|
||||
|
||||
**Mô tả**: Đảm bảo event publishing bằng cách lưu events trong database cùng transaction với business data.
|
||||
|
||||
**Triển khai**:
|
||||
```typescript
|
||||
// Lưu event trong outbox
|
||||
async createUser(userData: CreateUserDto): Promise<User> {
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
// Business operation
|
||||
const user = await tx.user.create({ data: userData });
|
||||
**Triển khai (.NET với EF Core)**:
|
||||
```csharp
|
||||
// EN: Save event in outbox with business data
|
||||
// VI: Lưu event trong outbox cùng với business data
|
||||
public async Task<User> CreateUserAsync(CreateUserDto dto, CancellationToken ct)
|
||||
{
|
||||
await using var transaction = await _context.Database.BeginTransactionAsync(ct);
|
||||
|
||||
// Lưu event trong outbox (cùng transaction)
|
||||
await tx.outbox.create({
|
||||
data: {
|
||||
aggregateId: user.id,
|
||||
aggregateType: 'User',
|
||||
eventType: 'user.created.v1',
|
||||
payload: JSON.stringify(user),
|
||||
createdAt: new Date()
|
||||
}
|
||||
});
|
||||
|
||||
return user;
|
||||
});
|
||||
}
|
||||
|
||||
// Outbox processor (chạy định kỳ)
|
||||
async processOutbox(): Promise<void> {
|
||||
const events = await prisma.outbox.findMany({
|
||||
where: { publishedAt: null },
|
||||
take: 100
|
||||
});
|
||||
|
||||
for (const event of events) {
|
||||
try {
|
||||
await kafkaProducer.send({
|
||||
topic: event.eventType,
|
||||
messages: [{ value: event.payload }]
|
||||
});
|
||||
|
||||
await prisma.outbox.update({
|
||||
where: { id: event.id },
|
||||
data: { publishedAt: new Date() }
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to publish event', { event, error });
|
||||
try
|
||||
{
|
||||
// Business operation
|
||||
var user = new User
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = dto.Email,
|
||||
FirstName = dto.FirstName,
|
||||
LastName = dto.LastName
|
||||
};
|
||||
_context.Users.Add(user);
|
||||
|
||||
// Lưu event trong outbox (cùng transaction)
|
||||
var outboxEvent = new OutboxMessage
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AggregateId = user.Id.ToString(),
|
||||
AggregateType = nameof(User),
|
||||
EventType = "user.created.v1",
|
||||
Payload = JsonSerializer.Serialize(user),
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
_context.OutboxMessages.Add(outboxEvent);
|
||||
|
||||
await _context.SaveChangesAsync(ct);
|
||||
await transaction.CommitAsync(ct);
|
||||
|
||||
return user;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await transaction.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -344,36 +341,47 @@ sequenceDiagram
|
||||
|
||||
**Mô tả**: Ngăn chặn lost updates bằng cách kiểm tra version khi update.
|
||||
|
||||
**Triển khai**:
|
||||
```prisma
|
||||
// Prisma schema
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
name String
|
||||
version Int @default(1)
|
||||
**Triển khai (.NET với EF Core)**:
|
||||
```csharp
|
||||
// EN: Entity with concurrency token
|
||||
// VI: Entity với concurrency token
|
||||
public class User
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Email { get; set; } = default!;
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
[ConcurrencyCheck]
|
||||
public int Version { get; set; } = 1;
|
||||
|
||||
// Or use RowVersion for SQL Server
|
||||
// [Timestamp]
|
||||
// public byte[] RowVersion { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
// Update với optimistic locking
|
||||
async updateUser(userId: string, data: UpdateUserDto, currentVersion: number): Promise<User> {
|
||||
const result = await prisma.user.updateMany({
|
||||
where: {
|
||||
id: userId,
|
||||
version: currentVersion
|
||||
},
|
||||
data: {
|
||||
...data,
|
||||
version: { increment: 1 }
|
||||
// EN: Update with optimistic locking
|
||||
// VI: Update với optimistic locking
|
||||
public async Task<User> UpdateUserAsync(
|
||||
Guid userId,
|
||||
UpdateUserDto dto,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var user = await _context.Users.FindAsync([userId], ct)
|
||||
?? throw new UserNotFoundException(userId);
|
||||
|
||||
user.Name = dto.Name;
|
||||
user.Version++; // Increment version
|
||||
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync(ct);
|
||||
return user;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
throw new ConcurrencyConflictException(
|
||||
"Data was modified by another user. Please refresh and try again.");
|
||||
}
|
||||
});
|
||||
|
||||
if (result.count === 0) {
|
||||
throw new ConflictError('Version mismatch - data was modified by another user');
|
||||
}
|
||||
|
||||
return await prisma.user.findUnique({ where: { id: userId } });
|
||||
}
|
||||
```
|
||||
|
||||
@@ -707,7 +715,7 @@ async function executeStepWithTracing(
|
||||
|
||||
---
|
||||
|
||||
**Cập nhật Lần cuối**: 2026-01-10
|
||||
**Cập nhật Lần cuối**: 2026-01-14
|
||||
**Tác giả**: GoodGo Architecture Team
|
||||
|
||||
## Quick Tips
|
||||
|
||||
@@ -39,18 +39,22 @@ graph TD
|
||||
|
||||
Nền tảng GoodGo triển khai Kiến trúc Hướng Sự kiện (EDA) cho giao tiếp bất đồng bộ giữa microservices.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Trạng thái hiện tại**: Event Bus với RabbitMQ/Kafka chưa được triển khai. Hiện tại sử dụng MediatR cho domain events nội bộ trong mỗi service.
|
||||
|
||||
**Nguyên tắc Cốt lõi**:
|
||||
1. **Event-First Design**: Mọi thay đổi trạng thái phát ra domain events
|
||||
2. **Loose Coupling**: Services giao tiếp qua events
|
||||
2. **Loose Coupling**: Services giao tiếp qua events (nội bộ hoặc message broker)
|
||||
3. **Eventual Consistency**: Chấp nhận inconsistency tạm thời
|
||||
4. **Event Sourcing**: Lưu thay đổi dưới dạng chuỗi event
|
||||
5. **CQRS Pattern**: Tách biệt read/write operations
|
||||
4. **CQRS Pattern**: Tách biệt read/write operations với MediatR
|
||||
|
||||
**Công nghệ**:
|
||||
- **Apache Kafka** - Nền tảng event streaming
|
||||
- **Schema Registry** - Avro schemas để validation
|
||||
- **KafkaJS** - Thư viện Node.js client
|
||||
- **Event Sourcing** - Triển khai tùy chỉnh trong IAM
|
||||
**Công nghệ Hiện tại**:
|
||||
- **MediatR** - Domain events nội bộ service
|
||||
- **Entity Framework Core** - Domain event dispatch qua DbContext
|
||||
|
||||
**Công nghệ Planned**:
|
||||
- **RabbitMQ + MassTransit** - Inter-service events (Roadmap)
|
||||
- **Outbox Pattern** - Reliable event publishing
|
||||
|
||||
## Luồng Sự kiện
|
||||
|
||||
@@ -70,29 +74,42 @@ sequenceDiagram
|
||||
|
||||
## Cấu trúc Sự kiện
|
||||
|
||||
```typescript
|
||||
interface BaseEvent {
|
||||
eventId: string; // UUID
|
||||
eventType: string; // user.created.v1
|
||||
eventVersion: string; // 1.0.0
|
||||
timestamp: string; // ISO 8601
|
||||
source: string; // iam-service
|
||||
correlationId?: string; // Request correlation
|
||||
data: unknown; // Event payload
|
||||
}
|
||||
```
|
||||
### Domain Events (MediatR - Hiện tại)
|
||||
|
||||
**Ví dụ**:
|
||||
```json
|
||||
```csharp
|
||||
// EN: Base domain event interface
|
||||
// VI: Interface domain event cơ bản
|
||||
public interface IDomainEvent : INotification
|
||||
{
|
||||
"eventId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"eventType": "user.created.v1",
|
||||
"timestamp": "2024-01-15T10:30:00Z",
|
||||
"source": "iam-service",
|
||||
"data": {
|
||||
"userId": "user_123",
|
||||
"email": "user@example.com"
|
||||
}
|
||||
Guid EventId { get; }
|
||||
DateTime OccurredOn { get; }
|
||||
}
|
||||
|
||||
// EN: Example domain event
|
||||
// VI: Ví dụ domain event
|
||||
public record UserCreatedEvent : IDomainEvent
|
||||
{
|
||||
public Guid EventId { get; } = Guid.NewGuid();
|
||||
public DateTime OccurredOn { get; } = DateTime.UtcNow;
|
||||
|
||||
public required Guid UserId { get; init; }
|
||||
public required string Email { get; init; }
|
||||
public required string FirstName { get; init; }
|
||||
}
|
||||
|
||||
// EN: Event handler
|
||||
// VI: Handler xử lý event
|
||||
public class UserCreatedEventHandler : INotificationHandler<UserCreatedEvent>
|
||||
{
|
||||
private readonly ILogger<UserCreatedEventHandler> _logger;
|
||||
|
||||
public async Task Handle(UserCreatedEvent notification, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("User created: {UserId}, {Email}",
|
||||
notification.UserId, notification.Email);
|
||||
|
||||
// TODO: Send welcome email, create profile, etc.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -430,7 +447,7 @@ logger.info('Event consumed', {
|
||||
|
||||
---
|
||||
|
||||
**Cập nhật Lần cuối**: 2026-01-07
|
||||
**Cập nhật Lần cuối**: 2026-01-14
|
||||
**Tác giả**: GoodGo Architecture Team
|
||||
|
||||
## Mẹo Nhanh
|
||||
|
||||
@@ -4,17 +4,15 @@ Tài liệu này mô tả đề xuất kiến trúc cho IAM Service (Identity an
|
||||
|
||||
## Tổng Quan: Auth Service → IAM Service
|
||||
|
||||
**Auth Service hiện tại** tập trung vào:
|
||||
- Authentication (xác thực)
|
||||
- Authorization (phân quyền)
|
||||
- Session & Token management
|
||||
- RBAC/ABAC
|
||||
**IAM Service** cung cấp:
|
||||
- **OAuth2/OpenID Connect** với OpenIddict
|
||||
- **ASP.NET Core Identity** cho user management
|
||||
- **Role-Based Access Control (RBAC)**
|
||||
- **JWT Tokens** (Access 15min, Refresh 7 days)
|
||||
- **MFA Support** (TOTP)
|
||||
|
||||
**IAM Service** mở rộng thêm:
|
||||
- **Identity Management** (quản lý danh tính toàn diện)
|
||||
- **Access Governance** (quản trị truy cập)
|
||||
- **Compliance & Reporting** (tuân thủ và báo cáo)
|
||||
- **Lifecycle Management** (quản lý vòng đời tài khoản)
|
||||
> [!NOTE]
|
||||
> IAM Service đã được triển khai với .NET 10, Clean Architecture tại `services/iam-service-net/`
|
||||
|
||||
---
|
||||
|
||||
@@ -90,56 +88,36 @@ Tài liệu này mô tả đề xuất kiến trúc cho IAM Service (Identity an
|
||||
|
||||
---
|
||||
|
||||
## 2. Kiến Trúc Module Structure
|
||||
## 2. Kiến Trúc Module Structure (Thực Tế)
|
||||
|
||||
```
|
||||
services/iam-service/
|
||||
services/iam-service-net/
|
||||
├── src/
|
||||
│ ├── config/ # Các file cấu hình hệ thống
|
||||
│ ├── core/
|
||||
│ │ ├── cache/ # Cache đa lớp (Multi-layer cache)
|
||||
│ │ ├── security/ # Zero-trust, mã hóa
|
||||
│ │ ├── events/ # Xử lý sự kiện (Event sourcing)
|
||||
│ │ └── workflows/ # Workflow engine (MỚI)
|
||||
│ ├── modules/
|
||||
│ │ ├── auth/ # ✅ Xác thực cốt lõi (Core authentication)
|
||||
│ │ ├── rbac/ # ✅ Hệ thống phân quyền (RBAC)
|
||||
│ │ ├── social/ # ✅ Xác thực mạng xã hội
|
||||
│ │ ├── oidc/ # ✅ Triển khai OIDC
|
||||
│ │ ├── token/ # ✅ Quản lý JWT & Cookie
|
||||
│ │ ├── session/ # ✅ Quản lý phiên làm việc
|
||||
│ │ ├── mfa/ # ✅ Xác thực đa yếu tố
|
||||
│ │ │
|
||||
│ │ ├── identity/ # 🆕 Quản lý danh tính (Identity Management)
|
||||
│ │ │ ├── user/ # Vòng đời người dùng
|
||||
│ │ │ ├── profile/ # Quản lý hồ sơ
|
||||
│ │ │ ├── verification/ # Xác minh danh tính
|
||||
│ │ │ └── organization/ # Tổ chức & nhóm
|
||||
│ │ │
|
||||
│ │ ├── access/ # 🆕 Quản lý truy cập (Access Management)
|
||||
│ │ │ ├── request/ # Yêu cầu truy cập
|
||||
│ │ │ ├── review/ # Đánh giá truy cập
|
||||
│ │ │ ├── pam/ # Truy cập đặc quyền (PAM)
|
||||
│ │ │ └── analytics/ # Phân tích truy cập
|
||||
│ │ │
|
||||
│ │ ├── governance/ # 🆕 Quản trị & Tuân thủ (Governance & Compliance)
|
||||
│ │ │ ├── compliance/ # Báo cáo tuân thủ
|
||||
│ │ │ ├── policy/ # Quản trị chính sách
|
||||
│ │ │ ├── risk/ # Quản lý rủi ro
|
||||
│ │ │ └── reporting/ # Báo cáo & dashboards
|
||||
│ │ │
|
||||
│ │ └── workflow/ # 🆕 Workflow Engine
|
||||
│ │ ├── engine/ # Core engine
|
||||
│ │ ├── approval/ # Quy trình phê duyệt
|
||||
│ │ └── automation/ # Quy trình tự động
|
||||
│ │
|
||||
│ ├── middlewares/ # Express middlewares
|
||||
│ ├── repositories/ # Lớp truy cập dữ liệu
|
||||
│ └── routes/ # Định nghĩa routes
|
||||
└── prisma/
|
||||
└── schema.prisma # Cấu trúc CSDL (mở rộng)
|
||||
│ ├── IamService.API/ # Presentation Layer
|
||||
│ │ ├── Controllers/ # AuthController, UsersController, RolesController
|
||||
│ │ ├── Application/ # CQRS Commands, Queries, Handlers
|
||||
│ │ │ ├── Commands/ # RegisterUserCommand, ChangePasswordCommand
|
||||
│ │ │ ├── Queries/ # GetUserQuery, GetUsersQuery
|
||||
│ │ │ └── Validators/ # FluentValidation validators
|
||||
│ │ └── Program.cs # App entry point
|
||||
│ ├── IamService.Domain/ # Domain Layer
|
||||
│ │ ├── AggregatesModel/ # ApplicationUser, ApplicationRole
|
||||
│ │ ├── Events/ # UserCreatedEvent, UserDeletedEvent
|
||||
│ │ ├── Exceptions/ # UserNotFoundException, InvalidCredentialsException
|
||||
│ │ └── SeedWork/ # Entity, IAggregateRoot, IRepository
|
||||
│ └── IamService.Infrastructure/ # Infrastructure Layer
|
||||
│ ├── IamServiceContext.cs # DbContext with Identity + OpenIddict
|
||||
│ ├── Repositories/ # UserRepository, RoleRepository
|
||||
│ └── Services/ # EmailService, TokenService
|
||||
├── tests/
|
||||
│ ├── IamService.UnitTests/
|
||||
│ └── IamService.FunctionalTests/
|
||||
├── docs/
|
||||
├── Dockerfile
|
||||
└── IamService.slnx
|
||||
```
|
||||
|
||||
### Sơ Đồ Kiến Trúc Modules
|
||||
### Sơ Đồ Kiến Trúc Clean Architecture
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
@@ -222,39 +200,35 @@ graph TD
|
||||
|
||||
---
|
||||
|
||||
## 4. API Endpoints Mở Rộng
|
||||
## 4. API Endpoints (Thực Tế)
|
||||
|
||||
### 4.1 Identity Management APIs
|
||||
### 4.1 Authentication APIs
|
||||
|
||||
```
|
||||
# User Management
|
||||
GET /api/v1/identity/users
|
||||
POST /api/v1/identity/users
|
||||
GET /api/v1/identity/users/:id
|
||||
PUT /api/v1/identity/users/:id
|
||||
DELETE /api/v1/identity/users/:id
|
||||
POST /api/v1/identity/users/bulk-import
|
||||
GET /api/v1/identity/users/bulk-export
|
||||
| Method | Endpoint | Mô tả | Auth |
|
||||
|--------|----------|-------|------|
|
||||
| `POST` | `/api/v1/auth/register` | Đăng ký user mới | ❌ |
|
||||
| `POST` | `/connect/token` | OAuth2 token endpoint (login, refresh) | ❌ |
|
||||
| `POST` | `/api/v1/auth/change-password` | Đổi mật khẩu | ✅ |
|
||||
| `POST` | `/api/v1/auth/logout` | Đăng xuất (revoke tokens) | ✅ |
|
||||
|
||||
# Profile Management
|
||||
GET /api/v1/identity/users/:id/profile
|
||||
PUT /api/v1/identity/users/:id/profile
|
||||
POST /api/v1/identity/users/:id/profile/avatar
|
||||
### 4.2 User Management APIs
|
||||
|
||||
# Identity Verification
|
||||
POST /api/v1/identity/verification/email/request
|
||||
POST /api/v1/identity/verification/email/verify
|
||||
POST /api/v1/identity/verification/phone/request
|
||||
POST /api/v1/identity/verification/phone/verify
|
||||
| Method | Endpoint | Mô tả | Auth |
|
||||
|--------|----------|-------|------|
|
||||
| `GET` | `/api/v1/users` | Danh sách users (paginated) | ✅ |
|
||||
| `GET` | `/api/v1/users/me` | Thông tin user hiện tại | ✅ |
|
||||
| `GET` | `/api/v1/users/{id}` | Lấy user theo ID | ✅ |
|
||||
| `PUT` | `/api/v1/users/{id}` | Cập nhật user | ✅ |
|
||||
| `DELETE` | `/api/v1/users/{id}` | Xóa user (soft delete) | ✅ |
|
||||
|
||||
# Organizations & Groups
|
||||
GET /api/v1/identity/organizations
|
||||
POST /api/v1/identity/organizations
|
||||
GET /api/v1/identity/organizations/:id/groups
|
||||
POST /api/v1/identity/organizations/:id/groups
|
||||
GET /api/v1/identity/groups/:id/members
|
||||
POST /api/v1/identity/groups/:id/members
|
||||
```
|
||||
### 4.3 Role Management APIs
|
||||
|
||||
| Method | Endpoint | Mô tả | Auth |
|
||||
|--------|----------|-------|------|
|
||||
| `GET` | `/api/v1/roles` | Danh sách roles | ✅ |
|
||||
| `POST` | `/api/v1/roles` | Tạo role mới | ✅ Admin |
|
||||
| `PUT` | `/api/v1/roles/{id}` | Cập nhật role | ✅ Admin |
|
||||
| `DELETE` | `/api/v1/roles/{id}` | Xóa role | ✅ Admin |
|
||||
|
||||
### 4.2 Access Management APIs
|
||||
|
||||
|
||||
@@ -162,25 +162,48 @@ sequenceDiagram
|
||||
|
||||
Request-response đồng bộ sử dụng HTTP/REST.
|
||||
|
||||
**Triển khai**:
|
||||
```typescript
|
||||
// Service-to-service HTTP client
|
||||
import axios from 'axios';
|
||||
|
||||
export class UserServiceClient {
|
||||
private client = axios.create({
|
||||
baseURL: process.env.USER_SERVICE_URL,
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
'x-service-auth': process.env.INTERNAL_API_KEY
|
||||
**Triển khai (.NET với IHttpClientFactory)**:
|
||||
```csharp
|
||||
// EN: Service-to-service HTTP client
|
||||
// VI: HTTP client cho giao tiếp giữa services
|
||||
public class IamServiceClient : IIamServiceClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger<IamServiceClient> _logger;
|
||||
|
||||
public IamServiceClient(HttpClient httpClient, ILogger<IamServiceClient> logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<UserDto?> GetUserAsync(Guid userId, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"/api/v1/users/{userId}", ct);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<UserDto>(ct);
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to get user {UserId}", userId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async getUser(userId: string): Promise<User> {
|
||||
const response = await this.client.get(`/users/${userId}`);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
// EN: Registration in Program.cs
|
||||
// VI: Đăng ký trong Program.cs
|
||||
builder.Services.AddHttpClient<IIamServiceClient, IamServiceClient>(client =>
|
||||
{
|
||||
client.BaseAddress = new Uri("http://iam-service-net:8080");
|
||||
client.DefaultRequestHeaders.Add("X-Service-Name", "storage-service");
|
||||
client.Timeout = TimeSpan.FromSeconds(5);
|
||||
})
|
||||
.AddPolicyHandler(GetRetryPolicy())
|
||||
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||
```
|
||||
|
||||
### Pattern Event-Driven
|
||||
@@ -479,6 +502,6 @@ readinessProbe:
|
||||
|
||||
---
|
||||
|
||||
**Cập nhật lần cuối / Last Updated**: 2026-01-07
|
||||
**Cập nhật lần cuối / Last Updated**: 2026-01-14
|
||||
**Tác giả / Authors**: GoodGo Architecture Team
|
||||
**Reviewers**: To be assigned
|
||||
|
||||
@@ -145,19 +145,19 @@ export function metricsMiddleware(req, res, next) {
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Logging (Winston + Loki)
|
||||
### 2. Logging (Serilog + Loki)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Service
|
||||
participant Winston as Winston Logger
|
||||
participant Serilog as Serilog Logger
|
||||
participant Loki
|
||||
participant Grafana
|
||||
|
||||
Service->>Winston: Log event
|
||||
Winston->>Winston: Format JSON
|
||||
Winston->>Winston: Add metadata<br/>(correlation ID, trace ID)
|
||||
Winston->>Loki: Push logs
|
||||
Service->>Serilog: Log event
|
||||
Serilog->>Serilog: Format JSON
|
||||
Serilog->>Serilog: Add metadata<br/>(correlation ID, trace ID)
|
||||
Serilog->>Loki: Push logs
|
||||
Loki->>Loki: Index & store
|
||||
|
||||
User->>Grafana: Query logs
|
||||
@@ -167,50 +167,47 @@ sequenceDiagram
|
||||
|
||||
**Mô tả**: Structured logging với correlation IDs để tracing requests.
|
||||
|
||||
**Triển khai**:
|
||||
```typescript
|
||||
import winston from 'winston';
|
||||
**Triển khai (.NET)**:
|
||||
```csharp
|
||||
// Program.cs - Serilog configuration
|
||||
builder.Host.UseSerilog((context, config) => config
|
||||
.ReadFrom.Configuration(context.Configuration)
|
||||
.Enrich.FromLogContext()
|
||||
.Enrich.WithProperty("Service", serviceName)
|
||||
.Enrich.WithProperty("Environment", environment)
|
||||
.WriteTo.Console(new JsonFormatter())
|
||||
.WriteTo.GrafanaLoki(
|
||||
"http://loki:3100",
|
||||
labels: new [] { new LokiLabel { Key = "app", Value = serviceName } }
|
||||
));
|
||||
|
||||
export const logger = winston.createLogger({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.json()
|
||||
),
|
||||
defaultMeta: {
|
||||
service: process.env.SERVICE_NAME || 'unknown-service',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
},
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
// Loki transport (nếu configured)
|
||||
]
|
||||
});
|
||||
|
||||
// Logger middleware
|
||||
export function loggerMiddleware(req, res, next) {
|
||||
const correlationId = req.headers['x-correlation-id'] || generateId();
|
||||
|
||||
req.correlationId = correlationId;
|
||||
req.logger = logger.child({ correlationId });
|
||||
|
||||
req.logger.info('Incoming request', {
|
||||
method: req.method,
|
||||
path: req.path,
|
||||
ip: req.ip
|
||||
});
|
||||
|
||||
res.on('finish', () => {
|
||||
req.logger.info('Request completed', {
|
||||
method: req.method,
|
||||
path: req.path,
|
||||
status: res.statusCode,
|
||||
duration: Date.now() - req.startTime
|
||||
});
|
||||
});
|
||||
|
||||
next();
|
||||
// Middleware - Add correlation ID
|
||||
public class CorrelationIdMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<CorrelationIdMiddleware> _logger;
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
var correlationId = context.Request.Headers["X-Correlation-Id"].FirstOrDefault()
|
||||
?? Guid.NewGuid().ToString();
|
||||
|
||||
context.Items["CorrelationId"] = correlationId;
|
||||
context.Response.Headers["X-Correlation-Id"] = correlationId;
|
||||
|
||||
using (LogContext.PushProperty("CorrelationId", correlationId))
|
||||
{
|
||||
_logger.LogInformation("Request started: {Method} {Path}",
|
||||
context.Request.Method, context.Request.Path);
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
await _next(context);
|
||||
sw.Stop();
|
||||
|
||||
_logger.LogInformation("Request completed: {StatusCode} in {Duration}ms",
|
||||
context.Response.StatusCode, sw.ElapsedMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -240,77 +237,66 @@ graph LR
|
||||
|
||||
**Mô tả**: Distributed tracing để track requests giữa các services.
|
||||
|
||||
**Triển khai**:
|
||||
```typescript
|
||||
import { trace, SpanStatusCode } from '@opentelemetry/api';
|
||||
> [!NOTE]
|
||||
> Distributed Tracing với Jaeger đang trong kế hoạch triển khai. Hiện tại sử dụng correlation IDs cho request tracking.
|
||||
|
||||
// Tạo traced function
|
||||
export function traced<T>(
|
||||
name: string,
|
||||
fn: () => Promise<T>
|
||||
): Promise<T> {
|
||||
const tracer = trace.getTracer('app');
|
||||
const span = tracer.startSpan(name);
|
||||
|
||||
return fn()
|
||||
.then(result => {
|
||||
span.setStatus({ code: SpanStatusCode.OK });
|
||||
return result;
|
||||
})
|
||||
.catch(error => {
|
||||
span.setStatus({
|
||||
code: SpanStatusCode.ERROR,
|
||||
message: error.message
|
||||
});
|
||||
span.recordException(error);
|
||||
throw error;
|
||||
})
|
||||
.finally(() => {
|
||||
span.end();
|
||||
});
|
||||
}
|
||||
**Triển khai (.NET với OpenTelemetry)**:
|
||||
```csharp
|
||||
// Program.cs - OpenTelemetry configuration (planned)
|
||||
builder.Services.AddOpenTelemetry()
|
||||
.WithTracing(tracing => tracing
|
||||
.AddAspNetCoreInstrumentation()
|
||||
.AddHttpClientInstrumentation()
|
||||
.AddEntityFrameworkCoreInstrumentation()
|
||||
.AddJaegerExporter(options =>
|
||||
{
|
||||
options.AgentHost = "jaeger";
|
||||
options.AgentPort = 6831;
|
||||
}));
|
||||
|
||||
// Sử dụng
|
||||
async getUserWithTracing(userId: string): Promise<User> {
|
||||
return traced('getUserById', async () => {
|
||||
return await userRepository.findById(userId);
|
||||
});
|
||||
// Manual span creation
|
||||
public async Task<User?> GetUserByIdAsync(Guid userId, CancellationToken ct)
|
||||
{
|
||||
using var activity = ActivitySource.StartActivity("GetUserById");
|
||||
activity?.SetTag("user.id", userId.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
var user = await _context.Users.FindAsync([userId], ct);
|
||||
activity?.SetStatus(ActivityStatusCode.Ok);
|
||||
return user;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Kiểm tra Sức khỏe
|
||||
|
||||
```typescript
|
||||
// Liveness probe - service có đang chạy không?
|
||||
app.get('/health/live', (req, res) => {
|
||||
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||
// Health check (.NET)
|
||||
app.MapHealthChecks("/health", new HealthCheckOptions
|
||||
{
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
|
||||
// Readiness probe - service có sẵn sàng nhận traffic không?
|
||||
app.get('/health/ready', async (req, res) => {
|
||||
const checks = {
|
||||
database: await checkDatabase(),
|
||||
redis: await checkRedis(),
|
||||
disk: await checkDiskSpace()
|
||||
};
|
||||
|
||||
const ready = Object.values(checks).every(check => check === true);
|
||||
|
||||
res.status(ready ? 200 : 503).json({
|
||||
ready,
|
||||
checks,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
app.MapHealthChecks("/health/live", new HealthCheckOptions
|
||||
{
|
||||
Predicate = _ => false // Liveness - always return healthy
|
||||
});
|
||||
|
||||
async function checkDatabase(): Promise<boolean> {
|
||||
try {
|
||||
await prisma.$queryRaw`SELECT 1`;
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
app.MapHealthChecks("/health/ready", new HealthCheckOptions
|
||||
{
|
||||
Predicate = check => check.Tags.Contains("ready")
|
||||
});
|
||||
|
||||
// Health check registration
|
||||
builder.Services.AddHealthChecks()
|
||||
.AddNpgSql(connectionString, name: "database", tags: new[] { "ready" })
|
||||
.AddRedis(redisConnectionString, name: "redis", tags: new[] { "ready" });
|
||||
```
|
||||
|
||||
## Quy tắc Cảnh báo
|
||||
@@ -459,5 +445,5 @@ graph TD
|
||||
|
||||
---
|
||||
|
||||
**Cập nhật Lần cuối**: 2026-01-07
|
||||
**Cập nhật Lần cuối**: 2026-01-14
|
||||
**Tác giả**: GoodGo Architecture Team
|
||||
|
||||
@@ -40,12 +40,12 @@ Kiến trúc Bảo mật GoodGo triển khai defense-in-depth với nhiều tầ
|
||||
5. **Encryption**: Mã hóa dữ liệu at rest và in transit
|
||||
|
||||
**Thành phần Chính**:
|
||||
- ASP.NET Core Identity (User Management)
|
||||
- OpenIddict (OAuth2/OIDC Server)
|
||||
- JWT Authentication (15min access, 7 ngày refresh)
|
||||
- RBAC + ABAC Authorization
|
||||
- Zero-Trust Device Validation
|
||||
- AES-256-GCM Encryption
|
||||
- Event Sourcing cho Audit Trail
|
||||
- Compliance (GDPR, SOC2, ISO27001, HIPAA)
|
||||
- RBAC Authorization
|
||||
- MFA Support (TOTP)
|
||||
- Compliance (GDPR, SOC2, ISO27001)
|
||||
|
||||
### EN: English Section
|
||||
|
||||
@@ -59,12 +59,12 @@ The GoodGo Security Architecture implements defense-in-depth with multiple secur
|
||||
5. **Encryption**: Data encrypted at rest and in transit
|
||||
|
||||
**Key Components**:
|
||||
- ASP.NET Core Identity (User Management)
|
||||
- OpenIddict (OAuth2/OIDC Server)
|
||||
- JWT Authentication (15min access, 7d refresh)
|
||||
- RBAC + ABAC Authorization
|
||||
- Zero-Trust Device Validation
|
||||
- AES-256-GCM Encryption
|
||||
- Event Sourcing for Audit Trail
|
||||
- Compliance (GDPR, SOC2, ISO27001, HIPAA)
|
||||
- RBAC Authorization
|
||||
- MFA Support (TOTP)
|
||||
- Compliance (GDPR, SOC2, ISO27001)
|
||||
|
||||
## Luồng Xác thực / Authentication Flow
|
||||
|
||||
@@ -97,20 +97,19 @@ sequenceDiagram
|
||||
### VI: Chi tiết Xác thực
|
||||
|
||||
**1. Password Hashing**:
|
||||
- Thuật toán: bcrypt với cost factor 12
|
||||
- Không bao giờ lưu plaintext passwords
|
||||
- Thuật toán: ASP.NET Core Identity (PBKDF2 với HMAC-SHA256)
|
||||
- Cost factor: 100,000 iterations
|
||||
- Password tối thiểu: 8 ký tự với quy tắc phức tạp
|
||||
|
||||
**2. JWT Tokens**:
|
||||
**2. JWT Tokens (OpenIddict)**:
|
||||
- Access Token: 15 phút expiry
|
||||
- Refresh Token: 7 ngày expiry
|
||||
- Thuật toán: RS256 (asymmetric signing)
|
||||
- Payload: userId, roles, permissions
|
||||
- Payload: sub, name, email, roles
|
||||
|
||||
**3. Token Storage**:
|
||||
- Access: httpOnly cookie (secure, sameSite)
|
||||
- Refresh: Database SHA-256 hash
|
||||
- Rotation: Refresh token mới mỗi lần sử dụng
|
||||
- Access: Bearer token trong Authorization header
|
||||
- Refresh: Database SHA-256 hash (OpenIddict stores)
|
||||
|
||||
**4. MFA Support (Xác thực Hai yếu tố)**:
|
||||
- TOTP (RFC 6238) cho authenticator apps
|
||||
|
||||
@@ -107,18 +107,18 @@ GoodGo Platform được xây dựng theo kiến trúc microservices với các
|
||||
**Nguyên tắc Cốt lõi**:
|
||||
1. **Độc Lập Service**: Mỗi service có database riêng và có thể deploy độc lập
|
||||
2. **API Gateway Pattern**: Traefik xử lý routing, load balancing, và cross-cutting concerns
|
||||
3. **Shared Libraries**: Chức năng chung được trích xuất vào shared packages (`@goodgo/*`)
|
||||
3. **Clean Architecture**: Mỗi service tuân theo Clean Architecture (API, Domain, Infrastructure)
|
||||
4. **Infrastructure as Code**: Tất cả cấu hình infrastructure được version control
|
||||
5. **Observability First**: Đầy đủ metrics, logging, và distributed tracing
|
||||
5. **Observability First**: Đầy đủ metrics, logging, và health checks
|
||||
|
||||
**Công nghệ Stack**:
|
||||
- **Frontend**: Next.js 14+ (App Router), Flutter 3.x
|
||||
- **Backend**: Node.js 20+, TypeScript 5+, Express
|
||||
- **Database**: Neon PostgreSQL (serverless)
|
||||
- **Cache**: Redis (multi-layer caching)
|
||||
- **Message Broker**: Apache Kafka
|
||||
- **API Gateway**: Traefik
|
||||
- **Observability**: Prometheus, Grafana, Loki, Jaeger
|
||||
- **Backend**: .NET 10, ASP.NET Core, MediatR (CQRS)
|
||||
- **Database**: Neon PostgreSQL (serverless), Entity Framework Core
|
||||
- **Cache**: Redis (StackExchange.Redis)
|
||||
- **Message Broker**: MediatR Domain Events (RabbitMQ planned)
|
||||
- **API Gateway**: Traefik v3
|
||||
- **Observability**: Prometheus, Grafana, Loki, Serilog
|
||||
|
||||
## Bối cảnh Hệ thống
|
||||
|
||||
@@ -202,31 +202,33 @@ C4Context
|
||||
|
||||
### Services Layer
|
||||
|
||||
#### IAM Service
|
||||
#### IAM Service (.NET)
|
||||
**Mô tả**: Identity and Access Management service xử lý authentication và authorization
|
||||
|
||||
**Tính năng chính**:
|
||||
- OAuth2/OpenID Connect với OpenIddict
|
||||
- JWT authentication (RS256)
|
||||
- RBAC (Role-Based Access Control)
|
||||
- ABAC (Attribute-Based Access Control)
|
||||
- Event sourcing cho audit trail
|
||||
- Zero-trust device validation
|
||||
- ASP.NET Core Identity cho user management
|
||||
- MFA support (TOTP)
|
||||
|
||||
**Công nghệ sử dụng**:
|
||||
- Node.js, Express, TypeScript
|
||||
- Prisma ORM, bcrypt, jsonwebtoken
|
||||
- `@goodgo/logger`, `@goodgo/tracing`
|
||||
- .NET 10, ASP.NET Core, MediatR
|
||||
- Entity Framework Core, OpenIddict
|
||||
- Serilog, FluentValidation
|
||||
|
||||
**Vị trí File**: [`services/iam-service/`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service)
|
||||
**Vị trí File**: [`services/iam-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service-net)
|
||||
|
||||
#### Future Services
|
||||
**Mô tả**: Các services sẽ được phát triển trong tương lai
|
||||
#### Các Services Đã Triển Khai
|
||||
|
||||
**Dự kiến**:
|
||||
- Payment Service - Xử lý thanh toán
|
||||
- Order Service - Quản lý đơn hàng
|
||||
- Notification Service - Gửi thông báo
|
||||
- Analytics Service - Phân tích dữ liệu
|
||||
| Service | Mô tả | Vị trí |
|
||||
|---------|-------|--------|
|
||||
| **Storage Service** | File storage với MinIO/Aliyun OSS | `services/storage-service-net/` |
|
||||
| **Membership Service** | Quản lý membership và subscriptions | `services/membership-service-net/` |
|
||||
| **Organization Service** | Quản lý tổ chức | `services/organization-service-net/` |
|
||||
| **Chat Service** | Chat và messaging | `services/chat-service-net/` |
|
||||
| **Social Service** | Social features | `services/social-service-net/` |
|
||||
| **Wallet Service** | Ví điện tử | `services/wallet-service-net/` |
|
||||
|
||||
### Infrastructure Layer
|
||||
|
||||
@@ -707,7 +709,7 @@ graph TD
|
||||
|
||||
---
|
||||
|
||||
**Cập nhật Lần cuối**: 2026-01-07
|
||||
**Cập nhật Lần cuối**: 2026-01-14
|
||||
**Tác giả**: GoodGo Architecture Team
|
||||
**Người review**: GoodGo Development Team
|
||||
|
||||
|
||||
Reference in New Issue
Block a user