Refactor auth-service to iam-service and update related documentation
- Renamed auth-service to iam-service across various files for consistency. - Updated Dockerfiles, deployment configurations, and documentation to reflect the service name change. - Enhanced testing commands in documentation to point to the new iam-service. - Removed outdated auth-service files and configurations to streamline the project structure. - Improved bilingual documentation for clarity on the new service structure and usage.
This commit is contained in:
@@ -11,13 +11,15 @@ docs/
|
||||
│ ├── architecture/
|
||||
│ ├── guides/
|
||||
│ ├── onboarding/
|
||||
│ └── runbooks/
|
||||
│ ├── runbooks/
|
||||
│ └── skills/ # Cursor AI skills documentation
|
||||
├── vi/ # Vietnamese documentation (Tiếng Việt)
|
||||
│ ├── api/
|
||||
│ ├── architecture/
|
||||
│ ├── guides/
|
||||
│ ├── onboarding/
|
||||
│ └── runbooks/
|
||||
│ ├── runbooks/
|
||||
│ └── skills/ # Tài liệu Cursor AI skills
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
@@ -29,6 +31,7 @@ docs/
|
||||
- **Guides**: Development, deployment, getting started, troubleshooting
|
||||
- **Onboarding**: New developer guide
|
||||
- **Runbooks**: Incident response and rollback procedures
|
||||
- **Skills**: Cursor AI skills documentation (API design, testing, security, etc.)
|
||||
|
||||
### Vietnamese (`/vi`)
|
||||
- **API**: OpenAPI specifications
|
||||
@@ -36,6 +39,23 @@ docs/
|
||||
- **Guides**: Development, deployment, bắt đầu, xử lý sự cố
|
||||
- **Onboarding**: Hướng dẫn cho developer mới
|
||||
- **Runbooks**: Phản ứng sự cố và quy trình rollback
|
||||
- **Skills**: Tài liệu Cursor AI skills (API design, testing, security, v.v.)
|
||||
|
||||
## Cursor Skills
|
||||
|
||||
The project uses **Cursor AI Skills** to guide AI assistants in following project-specific patterns and standards. See the [Skills Documentation](./en/skills/) for detailed information about each skill:
|
||||
|
||||
- [API Design](./en/skills/api-design.md) - RESTful API standards
|
||||
- [Database & Prisma](./en/skills/database-prisma.md) - Database patterns
|
||||
- [Testing Patterns](./en/skills/testing-patterns.md) - Testing best practices
|
||||
- [Code Comments](./en/skills/comment-code.md) - Bilingual commenting guidelines
|
||||
- [Kubernetes Deployment](./en/skills/deployment-kubernetes.md) - K8s deployment patterns
|
||||
- [Observability & Monitoring](./en/skills/observability-monitoring.md) - Monitoring patterns
|
||||
- [Project Rules](./en/skills/project-rules.md) - Coding standards
|
||||
- [Security](./en/skills/security.md) - Security best practices
|
||||
- [Documentation](./en/skills/documentation.md) - Documentation guidelines
|
||||
|
||||
See [Skills Index](./en/skills/README.md) for complete list and quick reference.
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -43,3 +63,8 @@ When adding new documentation:
|
||||
1. Add the English version to `/en`
|
||||
2. Add the Vietnamese translation to `/vi`
|
||||
3. Keep both versions in sync
|
||||
|
||||
When updating Cursor Skills:
|
||||
1. Update the skill source file in `.cursor/skills/{skill-name}/SKILL.md`
|
||||
2. Update the documentation in `docs/en/skills/{skill-name}.md` and `docs/vi/skills/{skill-name}.md`
|
||||
3. Update the skills index files if needed
|
||||
|
||||
339
docs/en/architecture/iam-proposal.md
Normal file
339
docs/en/architecture/iam-proposal.md
Normal file
@@ -0,0 +1,339 @@
|
||||
# Đề Xuất Kiến Trúc IAM Service
|
||||
|
||||
Tài liệu này mô tả đề xuất kiến trúc cho IAM Service (Identity and Access Management Service), mở rộng từ auth-service hiện tại.
|
||||
|
||||
## 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** 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)
|
||||
|
||||
---
|
||||
|
||||
## 1. Phạm Vi IAM Service
|
||||
|
||||
### 1.1 Identity Management (Quản Lý Danh Tính)
|
||||
|
||||
#### A. User Lifecycle Management
|
||||
- User CRUD operations
|
||||
- User provisioning/deprovisioning workflows
|
||||
- Bulk user operations (import/export)
|
||||
- User deactivation/reactivation với approval workflow
|
||||
- Account merging/deduplication
|
||||
- User archival (soft delete với retention policy)
|
||||
|
||||
#### B. Profile Management
|
||||
- Extended attributes (custom fields)
|
||||
- Profile picture upload & management
|
||||
- Contact information (phone, address)
|
||||
- Preferences & settings
|
||||
- Profile versioning/audit trail
|
||||
|
||||
#### C. Identity Verification
|
||||
- Email verification
|
||||
- Phone/SMS verification
|
||||
- Identity document verification (KYC)
|
||||
- Multi-level verification (verified, pending, rejected)
|
||||
|
||||
#### D. Organizations & Groups
|
||||
- Organization management (multi-tenant)
|
||||
- Group/Team management
|
||||
- Organization hierarchy
|
||||
- Group-based access control
|
||||
- Organization-level policies
|
||||
|
||||
### 1.2 Access Management (Quản Lý Truy Cập)
|
||||
|
||||
#### A. Advanced Access Control
|
||||
- Just-In-Time (JIT) access provisioning
|
||||
- Privileged Access Management (PAM)
|
||||
- Temporary access grants
|
||||
- Access request/approval workflows
|
||||
- Delegation & impersonation (admin view)
|
||||
- Conditional access policies (location, time, device)
|
||||
|
||||
#### B. Access Reviews & Certifications
|
||||
- Periodic access reviews
|
||||
- Access certification campaigns
|
||||
- Access analytics & reporting
|
||||
- Risk scoring for access decisions
|
||||
- Anomaly detection (unusual access patterns)
|
||||
|
||||
### 1.3 Governance & Compliance (Quản Trị & Tuân Thủ)
|
||||
|
||||
#### A. Audit & Logging
|
||||
- Compliance reporting (GDPR, SOC2, ISO 27001)
|
||||
- Data retention policies
|
||||
- Audit log search & analytics
|
||||
- Export audit logs
|
||||
|
||||
#### B. Policy Governance
|
||||
- Policy versioning & rollback
|
||||
- Policy templates library
|
||||
- Policy testing & validation
|
||||
- Policy compliance checks
|
||||
|
||||
#### C. Risk Management
|
||||
- Risk scoring engine
|
||||
- Risk-based authentication
|
||||
- Threat detection
|
||||
- Incident response workflows
|
||||
- Security posture dashboard
|
||||
|
||||
---
|
||||
|
||||
## 2. Kiến Trúc Module Structure
|
||||
|
||||
```
|
||||
services/iam-service/
|
||||
├── src/
|
||||
│ ├── config/ # Configuration files
|
||||
│ ├── core/
|
||||
│ │ ├── cache/ # Multi-layer cache
|
||||
│ │ ├── security/ # Zero-trust, encryption
|
||||
│ │ ├── events/ # Event sourcing
|
||||
│ │ └── workflows/ # Workflow engine (NEW)
|
||||
│ ├── modules/
|
||||
│ │ ├── auth/ # ✅ Core authentication
|
||||
│ │ ├── rbac/ # ✅ RBAC system
|
||||
│ │ ├── social/ # ✅ Social authentication
|
||||
│ │ ├── oidc/ # ✅ OIDC implementation
|
||||
│ │ ├── token/ # ✅ JWT & Cookie management
|
||||
│ │ ├── session/ # ✅ Session management
|
||||
│ │ ├── mfa/ # ✅ Multi-factor auth
|
||||
│ │ │
|
||||
│ │ ├── identity/ # 🆕 Identity Management
|
||||
│ │ │ ├── user/ # User lifecycle
|
||||
│ │ │ ├── profile/ # Profile management
|
||||
│ │ │ ├── verification/ # Identity verification
|
||||
│ │ │ └── organization/ # Organizations & groups
|
||||
│ │ │
|
||||
│ │ ├── access/ # 🆕 Access Management
|
||||
│ │ │ ├── request/ # Access requests
|
||||
│ │ │ ├── review/ # Access reviews
|
||||
│ │ │ ├── pam/ # Privileged access
|
||||
│ │ │ └── analytics/ # Access analytics
|
||||
│ │ │
|
||||
│ │ ├── governance/ # 🆕 Governance & Compliance
|
||||
│ │ │ ├── compliance/ # Compliance reporting
|
||||
│ │ │ ├── policy/ # Policy governance
|
||||
│ │ │ ├── risk/ # Risk management
|
||||
│ │ │ └── reporting/ # Reporting & dashboards
|
||||
│ │ │
|
||||
│ │ └── workflow/ # 🆕 Workflow Engine
|
||||
│ │ ├── engine/ # Workflow engine
|
||||
│ │ ├── approval/ # Approval workflows
|
||||
│ │ └── automation/ # Automated workflows
|
||||
│ │
|
||||
│ ├── middlewares/ # Express middlewares
|
||||
│ ├── repositories/ # Data access layer
|
||||
│ └── routes/ # Route definitions
|
||||
└── prisma/
|
||||
└── schema.prisma # Database schema (mở rộng)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Database Schema Mở Rộng
|
||||
|
||||
### 3.1 Identity Management Models
|
||||
|
||||
- **Organization**: Quản lý tổ chức với hierarchy
|
||||
- **Group**: Quản lý nhóm trong organization
|
||||
- **GroupMember**: Thành viên của group
|
||||
- **GroupPermission**: Permissions cho group
|
||||
- **UserProfile**: Thông tin profile mở rộng của user
|
||||
- **IdentityVerification**: Xác thực danh tính (email, phone, document)
|
||||
|
||||
### 3.2 Access Management Models
|
||||
|
||||
- **AccessRequest**: Yêu cầu truy cập
|
||||
- **AccessRequestApprover**: Người phê duyệt request
|
||||
- **AccessReview**: Đánh giá truy cập định kỳ
|
||||
- **AccessReviewItem**: Item trong review
|
||||
|
||||
### 3.3 Governance Models
|
||||
|
||||
- **ComplianceReport**: Báo cáo tuân thủ (GDPR, SOC2, ISO27001)
|
||||
- **PolicyTemplate**: Template cho policies
|
||||
- **RiskScore**: Điểm rủi ro của user
|
||||
|
||||
---
|
||||
|
||||
## 4. API Endpoints Mở Rộng
|
||||
|
||||
### 4.1 Identity Management 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
|
||||
|
||||
# Profile Management
|
||||
GET /api/v1/identity/users/:id/profile
|
||||
PUT /api/v1/identity/users/:id/profile
|
||||
POST /api/v1/identity/users/:id/profile/avatar
|
||||
|
||||
# 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
|
||||
|
||||
# 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.2 Access Management APIs
|
||||
|
||||
```
|
||||
# Access Requests
|
||||
GET /api/v1/access/requests
|
||||
POST /api/v1/access/requests
|
||||
PUT /api/v1/access/requests/:id/approve
|
||||
PUT /api/v1/access/requests/:id/reject
|
||||
|
||||
# Access Reviews
|
||||
GET /api/v1/access/reviews
|
||||
POST /api/v1/access/reviews
|
||||
POST /api/v1/access/reviews/:id/start
|
||||
POST /api/v1/access/reviews/:id/complete
|
||||
GET /api/v1/access/reviews/:id/items
|
||||
|
||||
# Access Analytics
|
||||
GET /api/v1/access/analytics/usage
|
||||
GET /api/v1/access/analytics/permissions
|
||||
GET /api/v1/access/analytics/risks
|
||||
```
|
||||
|
||||
### 4.3 Governance APIs
|
||||
|
||||
```
|
||||
# Compliance Reports
|
||||
GET /api/v1/governance/compliance/reports
|
||||
POST /api/v1/governance/compliance/reports/generate
|
||||
GET /api/v1/governance/compliance/reports/:id/export
|
||||
|
||||
# Policy Governance
|
||||
GET /api/v1/governance/policies/templates
|
||||
POST /api/v1/governance/policies/templates
|
||||
GET /api/v1/governance/policies/:id/versions
|
||||
POST /api/v1/governance/policies/:id/test
|
||||
|
||||
# Risk Management
|
||||
GET /api/v1/governance/risk/scores
|
||||
GET /api/v1/governance/risk/scores/:userId
|
||||
POST /api/v1/governance/risk/calculate
|
||||
|
||||
# Reporting
|
||||
GET /api/v1/governance/reports/access-summary
|
||||
GET /api/v1/governance/reports/user-activity
|
||||
GET /api/v1/governance/reports/security-events
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Implementation Roadmap
|
||||
|
||||
### Phase 1: Foundation (Weeks 1-4)
|
||||
- ✅ Migrate từ auth-service sang iam-service
|
||||
- 🔄 Tổ chức lại modules theo IAM structure
|
||||
- 🔄 Mở rộng database schema với identity models
|
||||
- 🔄 Implement User Profile module
|
||||
|
||||
### Phase 2: Identity Management (Weeks 5-8)
|
||||
- 🔄 User lifecycle management
|
||||
- 🔄 Identity verification (email, phone, document)
|
||||
- 🔄 Organization & Group management
|
||||
- 🔄 Profile management with extended attributes
|
||||
|
||||
### Phase 3: Access Management (Weeks 9-12)
|
||||
- 🔄 Access request/approval workflows
|
||||
- 🔄 Access review & certification system
|
||||
- 🔄 Access analytics
|
||||
- 🔄 Privileged Access Management (PAM)
|
||||
|
||||
### Phase 4: Governance (Weeks 13-16)
|
||||
- 🔄 Compliance reporting engine
|
||||
- 🔄 Policy governance & versioning
|
||||
- 🔄 Risk scoring & management
|
||||
- 🔄 Reporting dashboards
|
||||
|
||||
### Phase 5: Advanced Features (Weeks 17-20)
|
||||
- 🔄 Workflow engine
|
||||
- 🔄 Advanced analytics & ML-based insights
|
||||
- 🔄 Integration APIs (SCIM, LDAP sync)
|
||||
- 🔄 Performance optimization & scaling
|
||||
|
||||
---
|
||||
|
||||
## 6. Lợi Ích Của IAM Service
|
||||
|
||||
### 6.1 Cho Doanh Nghiệp
|
||||
- ✅ Tuân thủ (GDPR, SOC2, ISO 27001)
|
||||
- ✅ Quản lý rủi ro bảo mật tốt hơn
|
||||
- ✅ Tự động hóa quy trình quản lý truy cập
|
||||
- ✅ Báo cáo và audit trail đầy đủ
|
||||
- ✅ Hỗ trợ multi-tenant/organization
|
||||
|
||||
### 6.2 Cho Developers
|
||||
- ✅ API thống nhất cho identity & access
|
||||
- ✅ Workflow engine linh hoạt
|
||||
- ✅ Extensible architecture
|
||||
- ✅ Comprehensive documentation
|
||||
- ✅ SDK support
|
||||
|
||||
### 6.3 Cho End Users
|
||||
- ✅ Self-service profile management
|
||||
- ✅ Transparent access requests
|
||||
- ✅ Better user experience
|
||||
- ✅ Enhanced security với MFA & verification
|
||||
|
||||
---
|
||||
|
||||
## 7. Migration Strategy
|
||||
|
||||
### Từ Auth Service → IAM Service
|
||||
|
||||
1. **Rename Service**: `services/auth-service` → `services/iam-service`
|
||||
2. **Update Package Name**: `@goodgo/auth-service` → `@goodgo/iam-service`
|
||||
3. **Update Routes**:
|
||||
- Giữ backward compatibility với `/api/v1/auth/*`
|
||||
- Thêm routes mới cho `/api/v1/identity/*`, `/api/v1/access/*`, `/api/v1/governance/*`
|
||||
4. **Database Migration**:
|
||||
- Thêm schema mới cho identity, access, governance
|
||||
- Giữ nguyên các tables hiện có (backward compatible)
|
||||
5. **Gradual Rollout**:
|
||||
- Phase 1: Deploy cùng auth-service (dual deployment)
|
||||
- Phase 2: Migrate clients dần dần
|
||||
- Phase 3: Deprecate auth-service khi migration hoàn tất
|
||||
|
||||
---
|
||||
|
||||
## Kết Luận
|
||||
|
||||
Đề xuất này mở rộng `auth-service` thành `IAM Service` với đầy đủ các tính năng:
|
||||
- **Identity Management** đầy đủ
|
||||
- **Access Management** nâng cao
|
||||
- **Governance & Compliance** toàn diện
|
||||
- **Workflow automation** linh hoạt
|
||||
|
||||
Điều này biến service từ authentication/authorization cơ bản thành một IAM platform toàn diện, phù hợp cho enterprise.
|
||||
@@ -38,7 +38,7 @@ docker-compose up -d
|
||||
|
||||
```bash
|
||||
# Create Kubernetes secret
|
||||
kubectl create secret generic auth-service-secrets \
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='postgresql://user:pass@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true' \
|
||||
--from-literal=jwt-secret='your-staging-jwt-secret' \
|
||||
--from-literal=jwt-refresh-secret='your-staging-refresh-secret' \
|
||||
@@ -72,7 +72,7 @@ kubectl apply -f deployments/staging/kubernetes/
|
||||
|
||||
```bash
|
||||
# Create Kubernetes secret
|
||||
kubectl create secret generic auth-service-secrets \
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='postgresql://user:pass@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true' \
|
||||
--from-literal=jwt-secret='your-production-jwt-secret' \
|
||||
--from-literal=jwt-refresh-secret='your-production-refresh-secret' \
|
||||
@@ -90,7 +90,7 @@ kubectl create secret generic auth-service-secrets \
|
||||
### Rollback
|
||||
|
||||
```bash
|
||||
kubectl rollout undo deployment/auth-service -n production
|
||||
kubectl rollout undo deployment/iam-service -n production
|
||||
```
|
||||
|
||||
## Health Checks
|
||||
|
||||
@@ -33,7 +33,7 @@ git checkout -b feature/my-feature
|
||||
pnpm test
|
||||
|
||||
# Specific service
|
||||
pnpm --filter @goodgo/auth-service test
|
||||
pnpm --filter @goodgo/iam-service test
|
||||
```
|
||||
|
||||
### 4. Lint and Format
|
||||
@@ -75,14 +75,14 @@ pnpm format
|
||||
|
||||
```bash
|
||||
# Create migration (dev)
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# Apply migrations (production)
|
||||
./scripts/db/migrate.sh auth-service deploy
|
||||
./scripts/db/migrate.sh iam-service deploy
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
- Use logger from `@goodgo/logger`
|
||||
- Check Traefik logs: `docker logs traefik-local`
|
||||
- Check service logs: `./scripts/dev/logs.sh auth-service`
|
||||
- Check service logs: `./scripts/dev/logs.sh iam-service`
|
||||
|
||||
@@ -44,12 +44,12 @@
|
||||
|
||||
5. **Run database migrations**
|
||||
```bash
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
6. **Seed the database**
|
||||
```bash
|
||||
./scripts/db/seed.sh auth-service
|
||||
./scripts/db/seed.sh iam-service
|
||||
```
|
||||
|
||||
7. **Start all services**
|
||||
|
||||
209
docs/en/guides/iam-migration.md
Normal file
209
docs/en/guides/iam-migration.md
Normal file
@@ -0,0 +1,209 @@
|
||||
# Migration Guide: Auth Service → IAM Service
|
||||
|
||||
Tài liệu này hướng dẫn cách migrate từ `auth-service` sang `iam-service`.
|
||||
|
||||
## Tổng Quan
|
||||
|
||||
IAM Service là phiên bản mở rộng của Auth Service với các tính năng bổ sung về Identity Management, Access Management, và Governance & Compliance. Tất cả các API endpoints của Auth Service vẫn được giữ nguyên để đảm bảo backward compatibility.
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
✅ **Tất cả các endpoints hiện tại vẫn hoạt động bình thường:**
|
||||
|
||||
- `/api/v1/auth/*` - Authentication endpoints
|
||||
- `/api/v1/rbac/*` - RBAC endpoints
|
||||
- `/api/v1/mfa/*` - MFA endpoints
|
||||
- `/api/v1/sessions/*` - Session management endpoints
|
||||
- `/api/v1/oidc/*` - OIDC endpoints
|
||||
|
||||
Không có breaking changes. Các clients hiện tại có thể tiếp tục sử dụng các endpoints này mà không cần thay đổi.
|
||||
|
||||
## Các Thay Đổi
|
||||
|
||||
### 1. Service Name
|
||||
|
||||
- **Cũ**: `auth-service`
|
||||
- **Mới**: `iam-service`
|
||||
|
||||
### 2. Package Name
|
||||
|
||||
- **Cũ**: `@goodgo/auth-service`
|
||||
- **Mới**: `@goodgo/iam-service`
|
||||
|
||||
### 3. Database Schema
|
||||
|
||||
Database schema được mở rộng với các models mới nhưng **không xóa hoặc thay đổi** các models hiện có:
|
||||
|
||||
**Models mới được thêm:**
|
||||
- `Organization` - Quản lý tổ chức
|
||||
- `Group` - Quản lý nhóm
|
||||
- `GroupMember` - Thành viên nhóm
|
||||
- `GroupPermission` - Quyền nhóm
|
||||
- `UserProfile` - Profile mở rộng
|
||||
- `IdentityVerification` - Xác thực danh tính
|
||||
- `AccessRequest` - Yêu cầu truy cập
|
||||
- `AccessReview` - Đánh giá truy cập
|
||||
- `ComplianceReport` - Báo cáo tuân thủ
|
||||
- `PolicyTemplate` - Template policy
|
||||
- `RiskScore` - Điểm rủi ro
|
||||
|
||||
**User model được mở rộng:**
|
||||
- Thêm field `organizationId` (optional)
|
||||
- Thêm các relations mới (optional)
|
||||
|
||||
### 4. API Endpoints Mới
|
||||
|
||||
#### Identity Management
|
||||
- `/api/v1/identity/users/*` - User lifecycle management
|
||||
- `/api/v1/identity/users/:id/profile` - Profile management
|
||||
- `/api/v1/identity/verification/*` - Identity verification
|
||||
- `/api/v1/identity/organizations/*` - Organization management
|
||||
- `/api/v1/identity/groups/*` - Group management
|
||||
|
||||
#### Access Management
|
||||
- `/api/v1/access/requests/*` - Access requests
|
||||
- `/api/v1/access/reviews/*` - Access reviews
|
||||
- `/api/v1/access/analytics/*` - Access analytics
|
||||
|
||||
#### Governance
|
||||
- `/api/v1/governance/compliance/*` - Compliance reports
|
||||
- `/api/v1/governance/policies/*` - Policy governance
|
||||
- `/api/v1/governance/risk/*` - Risk management
|
||||
- `/api/v1/governance/reports/*` - Reporting dashboard
|
||||
|
||||
### 5. Environment Variables
|
||||
|
||||
Một số biến môi trường mới có thể được thêm trong tương lai cho các tính năng IAM nâng cao (email service, SMS service, file storage), nhưng không ảnh hưởng đến các biến hiện tại.
|
||||
|
||||
### 6. Deployment Configuration
|
||||
|
||||
**Docker Compose:**
|
||||
- Service name: `auth-service` → `iam-service`
|
||||
- Container name: `auth-service-local` → `iam-service-local`
|
||||
- Traefik labels: Thêm routes mới cho `/api/v1/identity/*`, `/api/v1/access/*`, `/api/v1/governance/*`
|
||||
|
||||
**Kubernetes:**
|
||||
- Deployment name: `auth-service` → `iam-service`
|
||||
- Service name: `auth-service` → `iam-service`
|
||||
- ConfigMap: `auth-service-config` → `iam-service-config`
|
||||
- Secrets: `auth-service-secrets` → `iam-service-secrets`
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Bước 1: Backup
|
||||
|
||||
```bash
|
||||
# Backup database
|
||||
pg_dump $DATABASE_URL > auth-service-backup.sql
|
||||
|
||||
# Backup code
|
||||
cp -r services/auth-service services/auth-service.backup
|
||||
```
|
||||
|
||||
### Bước 2: Database Migration
|
||||
|
||||
```bash
|
||||
cd services/iam-service
|
||||
|
||||
# Generate Prisma client với schema mới
|
||||
pnpm prisma generate
|
||||
|
||||
# Tạo migration
|
||||
pnpm prisma migrate dev --name add_iam_models
|
||||
|
||||
# Verify migration
|
||||
pnpm prisma studio # Check database structure
|
||||
```
|
||||
|
||||
### Bước 3: Update Dependencies
|
||||
|
||||
```bash
|
||||
# Install dependencies (nếu có package mới)
|
||||
pnpm install
|
||||
|
||||
# Verify types compile
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
### Bước 4: Update Deployment
|
||||
|
||||
**Local Development:**
|
||||
```bash
|
||||
cd deployments/local
|
||||
# Update docker-compose.yml (đã được cập nhật)
|
||||
docker-compose up -d iam-service
|
||||
```
|
||||
|
||||
**Staging/Production:**
|
||||
- Update Kubernetes manifests
|
||||
- Update ingress routes
|
||||
- Update ConfigMaps và Secrets
|
||||
|
||||
### Bước 5: Verify Backward Compatibility
|
||||
|
||||
Test tất cả các endpoints cũ vẫn hoạt động:
|
||||
|
||||
```bash
|
||||
# Test auth endpoints
|
||||
curl http://localhost/api/v1/auth/me
|
||||
|
||||
# Test RBAC endpoints
|
||||
curl http://localhost/api/v1/rbac/permissions
|
||||
|
||||
# Test MFA endpoints
|
||||
curl http://localhost/api/v1/mfa/devices
|
||||
```
|
||||
|
||||
### Bước 6: Gradual Rollout
|
||||
|
||||
1. **Dual Deployment** (Optional):
|
||||
- Deploy cả `auth-service` và `iam-service` cùng lúc
|
||||
- Route traffic dần dần sang `iam-service`
|
||||
- Monitor errors và performance
|
||||
|
||||
2. **Update Clients**:
|
||||
- Update clients để sử dụng các endpoints mới nếu cần
|
||||
- Clients không cần update nếu chỉ dùng endpoints cũ
|
||||
|
||||
3. **Deprecate Old Service**:
|
||||
- Sau khi verify mọi thứ hoạt động tốt, có thể deprecate `auth-service`
|
||||
- Đảm bảo tất cả clients đã migrate sang `iam-service`
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
Nếu cần rollback:
|
||||
|
||||
1. **Database Rollback**:
|
||||
```bash
|
||||
# Revert Prisma migration
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate resolve --rolled-back <migration_name>
|
||||
|
||||
# Hoặc restore từ backup
|
||||
psql $DATABASE_URL < auth-service-backup.sql
|
||||
```
|
||||
|
||||
2. **Service Rollback**:
|
||||
```bash
|
||||
# Switch back to auth-service in docker-compose
|
||||
# Hoặc revert Kubernetes deployment
|
||||
kubectl rollout undo deployment/auth-service
|
||||
```
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
**Không có breaking changes** trong migration này. Tất cả các API endpoints và database models hiện có đều được giữ nguyên.
|
||||
|
||||
## Notes
|
||||
|
||||
- Migration này là **additive** - chỉ thêm các tính năng mới, không xóa hoặc thay đổi tính năng cũ
|
||||
- Database migrations là **non-destructive** - không xóa hoặc modify dữ liệu hiện có
|
||||
- Clients có thể tiếp tục sử dụng các endpoints cũ mà không cần thay đổi
|
||||
|
||||
## Support
|
||||
|
||||
Nếu gặp vấn đề trong quá trình migration, vui lòng:
|
||||
1. Check logs: `docker-compose logs iam-service`
|
||||
2. Verify database connection
|
||||
3. Check environment variables
|
||||
4. Review error messages và stack traces
|
||||
@@ -38,7 +38,7 @@ docker-compose logs -f
|
||||
|
||||
### Backend Services
|
||||
|
||||
- **auth-service** (Port 5001): Authentication and user management
|
||||
- **iam-service** (Port 5001): Authentication and user management
|
||||
- Routes: `/api/v1/auth`, `/api/v1/users`
|
||||
- Health: http://localhost/api/v1/auth/health
|
||||
|
||||
@@ -84,7 +84,7 @@ CORS_ORIGIN=http://localhost:3000,http://localhost:3001
|
||||
docker-compose up -d
|
||||
|
||||
# Start specific service
|
||||
docker-compose up -d auth-service
|
||||
docker-compose up -d iam-service
|
||||
|
||||
# Stop all services
|
||||
docker-compose down
|
||||
@@ -96,19 +96,19 @@ docker-compose down -v
|
||||
docker-compose logs -f
|
||||
|
||||
# View logs (specific service)
|
||||
docker-compose logs -f auth-service
|
||||
docker-compose logs -f iam-service
|
||||
|
||||
# Restart service
|
||||
docker-compose restart auth-service
|
||||
docker-compose restart iam-service
|
||||
|
||||
# Rebuild service
|
||||
docker-compose up -d --build auth-service
|
||||
docker-compose up -d --build iam-service
|
||||
|
||||
# Check service status
|
||||
docker-compose ps
|
||||
|
||||
# Execute command in container
|
||||
docker-compose exec auth-service sh
|
||||
docker-compose exec iam-service sh
|
||||
```
|
||||
|
||||
## Adding New Service
|
||||
@@ -196,7 +196,7 @@ docker-compose up -d service-name
|
||||
cat .env.local | grep DATABASE_URL
|
||||
|
||||
# Test connection from service
|
||||
docker-compose exec auth-service sh
|
||||
docker-compose exec iam-service sh
|
||||
# Inside container:
|
||||
# curl $DATABASE_URL (won't work, but shows if var is set)
|
||||
```
|
||||
@@ -242,7 +242,7 @@ docker-compose logs traefik
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ auth-service │ │ web-admin │ │ web-client │
|
||||
│ iam-service │ │ web-admin │ │ web-client │
|
||||
│ :5001 │ │ :3000 │ │ :3001 │
|
||||
└──────┬───────┘ └──────────────┘ └──────────────┘
|
||||
│
|
||||
|
||||
@@ -64,13 +64,13 @@ JWT_REFRESH_SECRET=dev-refresh-secret-change-in-production
|
||||
### 4. Run Database Migrations
|
||||
|
||||
```bash
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
### 5. Seed Database (Optional)
|
||||
|
||||
```bash
|
||||
./scripts/db/seed.sh auth-service
|
||||
./scripts/db/seed.sh iam-service
|
||||
```
|
||||
|
||||
## Ways to Run the Project
|
||||
@@ -107,10 +107,10 @@ Best when working on a single service:
|
||||
|
||||
```bash
|
||||
# Using script
|
||||
./scripts/dev/start-service.sh auth-service
|
||||
./scripts/dev/start-service.sh iam-service
|
||||
|
||||
# Or run directly
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
@@ -124,7 +124,7 @@ pnpm --filter "./services/*" dev
|
||||
pnpm --filter "./apps/*" dev
|
||||
|
||||
# Run specific service
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
```
|
||||
|
||||
### Method 4: Run With Docker Compose (Full Stack)
|
||||
@@ -147,8 +147,11 @@ When services are running, you can access:
|
||||
| Service | URL | Description |
|
||||
|---------|-----|-------------|
|
||||
| **API Gateway** | http://localhost/api/v1 | Main entry point via Traefik |
|
||||
| **Auth Service** | http://localhost:5001 | Direct auth service access |
|
||||
| **Auth API** | http://localhost/api/v1/auth | Auth API via gateway |
|
||||
| **IAM Service** | http://localhost:5001 | Direct IAM service access |
|
||||
| **Auth API** | http://localhost/api/v1/auth | Auth API via gateway (backward compatible) |
|
||||
| **Identity API** | http://localhost/api/v1/identity | Identity management API |
|
||||
| **Access API** | http://localhost/api/v1/access | Access management API |
|
||||
| **Governance API** | http://localhost/api/v1/governance | Governance API |
|
||||
| **Web Admin** | http://admin.localhost or http://localhost:3000 | Admin dashboard |
|
||||
| **Web Client** | http://localhost or http://localhost:3001 | Client web app |
|
||||
| **Traefik Dashboard** | http://localhost:8080 | View routing and services |
|
||||
@@ -160,9 +163,9 @@ When services are running, you can access:
|
||||
Backend services use `tsx watch` or `nodemon` for automatic restart on code changes:
|
||||
|
||||
```bash
|
||||
# In services/auth-service/package.json
|
||||
# In services/iam-service/package.json
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/index.ts"
|
||||
"dev": "tsx watch src/main.ts"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -209,7 +212,7 @@ pnpm --filter @goodgo/logger dev
|
||||
**Terminal 2: View Logs**
|
||||
```bash
|
||||
# View specific service logs
|
||||
./scripts/dev/logs.sh auth-service
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Or view Docker logs
|
||||
docker logs -f redis-cache-local
|
||||
@@ -219,10 +222,10 @@ docker logs -f traefik-local
|
||||
**Terminal 3: Development Tasks**
|
||||
```bash
|
||||
# Run tests
|
||||
pnpm --filter @goodgo/auth-service test --watch
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
|
||||
# Run migrations
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# Format code
|
||||
pnpm format
|
||||
@@ -257,7 +260,7 @@ Access http://localhost:8080 to view:
|
||||
```bash
|
||||
# 1. Edit prisma/schema.prisma
|
||||
# 2. Create and apply migration
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate dev --name add_new_field
|
||||
|
||||
# 3. Prisma Client auto-regenerates
|
||||
@@ -266,7 +269,7 @@ pnpm prisma migrate dev --name add_new_field
|
||||
### Reset Database (Development Only!)
|
||||
|
||||
```bash
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate reset
|
||||
```
|
||||
|
||||
@@ -274,7 +277,7 @@ pnpm prisma migrate reset
|
||||
|
||||
```bash
|
||||
# Open Prisma Studio
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma studio
|
||||
# Access: http://localhost:5555
|
||||
```
|
||||
@@ -294,7 +297,7 @@ Create `.vscode/launch.json`:
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["--filter", "@goodgo/auth-service", "dev"],
|
||||
"runtimeArgs": ["--filter", "@goodgo/iam-service", "dev"],
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
@@ -306,10 +309,10 @@ Create `.vscode/launch.json`:
|
||||
|
||||
```bash
|
||||
# Service logs
|
||||
./scripts/dev/logs.sh auth-service
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Docker logs
|
||||
docker logs -f auth-service-local
|
||||
docker logs -f iam-service-local
|
||||
docker logs -f redis-cache-local
|
||||
docker logs -f traefik-local
|
||||
|
||||
@@ -352,7 +355,7 @@ docker-compose -f deployments/local/docker-compose.yml restart
|
||||
cat deployments/local/.env.local | grep DATABASE_URL
|
||||
|
||||
# Test connection
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma db pull
|
||||
```
|
||||
|
||||
@@ -379,7 +382,7 @@ pnpm install
|
||||
pnpm dev
|
||||
|
||||
# Or restart Docker container
|
||||
docker-compose -f deployments/local/docker-compose.yml restart auth-service
|
||||
docker-compose -f deployments/local/docker-compose.yml restart iam-service
|
||||
```
|
||||
|
||||
## Tips & Best Practices
|
||||
@@ -401,18 +404,18 @@ pnpm dev
|
||||
No need to run everything if working on one service:
|
||||
|
||||
```bash
|
||||
# Run only auth-service
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
# Run only iam-service
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Run auth-service with dependencies
|
||||
pnpm --filter @goodgo/auth-service... dev
|
||||
# Run iam-service with dependencies
|
||||
pnpm --filter @goodgo/iam-service... dev
|
||||
```
|
||||
|
||||
### 3. Watch Tests
|
||||
|
||||
```bash
|
||||
# Run tests automatically on code changes
|
||||
pnpm --filter @goodgo/auth-service test --watch
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
```
|
||||
|
||||
### 4. Auto-format Code
|
||||
@@ -452,7 +455,7 @@ LOG_LEVEL=debug
|
||||
Create `.env.local` file in service directory:
|
||||
|
||||
```bash
|
||||
# services/auth-service/.env.local
|
||||
# services/iam-service/.env.local
|
||||
PORT=5001
|
||||
LOG_LEVEL=debug
|
||||
```
|
||||
@@ -472,9 +475,9 @@ pnpm clean # Remove build artifacts
|
||||
./scripts/utils/cleanup.sh # Full cleanup
|
||||
|
||||
# Database
|
||||
./scripts/db/migrate.sh auth-service dev # Migration
|
||||
./scripts/db/seed.sh auth-service # Seed data
|
||||
./scripts/db/backup.sh auth-service # Backup
|
||||
./scripts/db/migrate.sh iam-service dev # Migration
|
||||
./scripts/db/seed.sh iam-service # Seed data
|
||||
./scripts/db/backup.sh iam-service # Backup
|
||||
|
||||
# Docker
|
||||
docker-compose -f deployments/local/docker-compose.yml up -d # Start
|
||||
|
||||
@@ -44,7 +44,7 @@ DATABASE_URL=postgresql://user:pass@ep-xxx.region.neon.tech/dbname?sslmode=requi
|
||||
### 5. Run Migrations
|
||||
|
||||
```bash
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
## Connection String Format
|
||||
@@ -73,7 +73,7 @@ Store in GitHub Secrets: `NEON_DATABASE_URL_STAGING`
|
||||
|
||||
Or in Kubernetes:
|
||||
```bash
|
||||
kubectl create secret generic auth-service-secrets \
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='postgresql://...' \
|
||||
-n staging
|
||||
```
|
||||
@@ -84,7 +84,7 @@ Store in GitHub Secrets: `NEON_DATABASE_URL_PRODUCTION`
|
||||
|
||||
Or in Kubernetes:
|
||||
```bash
|
||||
kubectl create secret generic auth-service-secrets \
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='postgresql://...' \
|
||||
-n production
|
||||
```
|
||||
@@ -95,7 +95,7 @@ kubectl create secret generic auth-service-secrets \
|
||||
|
||||
```bash
|
||||
# Create new migration
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# This will:
|
||||
# 1. Create migration file
|
||||
@@ -111,7 +111,7 @@ Migrations run automatically in CI/CD:
|
||||
|
||||
Manual migration:
|
||||
```bash
|
||||
./scripts/db/migrate.sh auth-service deploy
|
||||
./scripts/db/migrate.sh iam-service deploy
|
||||
```
|
||||
|
||||
## Backup & Restore
|
||||
@@ -126,7 +126,7 @@ Neon provides automatic backups. Access via Neon Console:
|
||||
### Manual Backup
|
||||
|
||||
```bash
|
||||
./scripts/db/backup.sh auth-service
|
||||
./scripts/db/backup.sh iam-service
|
||||
```
|
||||
|
||||
This creates a SQL dump file in `backups/` directory.
|
||||
|
||||
@@ -66,13 +66,13 @@ In the **Explore** view with **Loki** selected:
|
||||
|
||||
1. Click **Label browser**.
|
||||
2. Select a label, e.g., `container`.
|
||||
3. Choose a specific container (e.g., `auth-service` or `traefik`).
|
||||
3. Choose a specific container (e.g., `iam-service` or `traefik`).
|
||||
4. Click **Show logs**.
|
||||
|
||||
You can also write LogQL queries manually, for example:
|
||||
|
||||
```logql
|
||||
{container="auth-service"}
|
||||
{container="iam-service"}
|
||||
```
|
||||
|
||||
### Viewing Metrics (Prometheus)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma generate
|
||||
```
|
||||
|
||||
|
||||
@@ -51,13 +51,13 @@ Welcome to the GoodGo Microservices Platform team!
|
||||
./scripts/dev/start-all.sh
|
||||
|
||||
# Start specific service
|
||||
./scripts/dev/start-service.sh auth-service
|
||||
./scripts/dev/start-service.sh iam-service
|
||||
|
||||
# View logs
|
||||
./scripts/dev/logs.sh auth-service
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Run migrations
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# Run tests
|
||||
pnpm test
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
|
||||
1. **Identify current version**
|
||||
```bash
|
||||
kubectl get deployment auth-service -n production -o jsonpath='{.spec.template.spec.containers[0].image}'
|
||||
kubectl get deployment iam-service -n production -o jsonpath='{.spec.template.spec.containers[0].image}'
|
||||
```
|
||||
|
||||
2. **Rollback to previous version**
|
||||
```bash
|
||||
kubectl rollout undo deployment/auth-service -n production
|
||||
kubectl rollout undo deployment/iam-service -n production
|
||||
```
|
||||
|
||||
3. **Verify rollback**
|
||||
```bash
|
||||
kubectl rollout status deployment/auth-service -n production
|
||||
kubectl rollout status deployment/iam-service -n production
|
||||
```
|
||||
|
||||
4. **Check service health**
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
1. Create reverse migration:
|
||||
```bash
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate dev --name rollback_previous_change
|
||||
```
|
||||
|
||||
|
||||
129
docs/en/skills/README.md
Normal file
129
docs/en/skills/README.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Cursor Skills Documentation
|
||||
|
||||
> **EN**: Comprehensive documentation for all Cursor AI skills used in the GoodGo Microservices Platform
|
||||
> **VI**: Tài liệu đầy đủ cho tất cả Cursor AI skills được sử dụng trong GoodGo Microservices Platform
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: Cursor Skills are specialized knowledge modules that guide AI assistants in following project-specific patterns, standards, and best practices. This directory contains detailed documentation for each skill, including when to use them, key concepts, common patterns, and real-world examples from the codebase.
|
||||
|
||||
**VI**: Cursor Skills là các module kiến thức chuyên biệt hướng dẫn AI assistants tuân theo các patterns, tiêu chuẩn và best practices cụ thể của dự án. Thư mục này chứa tài liệu chi tiết cho từng skill, bao gồm khi nào sử dụng, khái niệm chính, các pattern thường dùng, và ví dụ thực tế từ codebase.
|
||||
|
||||
## Available Skills / Các Skills Có Sẵn
|
||||
|
||||
The GoodGo platform includes **9 Cursor Skills** organized by category:
|
||||
|
||||
### API & Data Layer
|
||||
|
||||
#### [API Design](./api-design.md)
|
||||
**EN**: RESTful API design standards for GoodGo microservices. Use when creating new API endpoints, designing DTOs, implementing controllers, writing OpenAPI documentation, or standardizing API responses.
|
||||
|
||||
**VI**: Tiêu chuẩn thiết kế RESTful API cho GoodGo microservices. Sử dụng khi tạo API endpoints mới, thiết kế DTOs, implement controllers, viết OpenAPI documentation, hoặc chuẩn hóa API responses.
|
||||
|
||||
#### [Database & Prisma](./database-prisma.md)
|
||||
**EN**: Prisma ORM and database patterns for GoodGo microservices. Use when working with databases, creating Prisma schemas, writing migrations, implementing repositories, or optimizing queries.
|
||||
|
||||
**VI**: Prisma ORM và database patterns cho GoodGo microservices. Sử dụng khi làm việc với databases, tạo Prisma schemas, viết migrations, implement repositories, hoặc optimize queries.
|
||||
|
||||
### Code Quality & Testing
|
||||
|
||||
#### [Testing Patterns](./testing-patterns.md)
|
||||
**EN**: Testing best practices for GoodGo microservices. Use when writing unit tests, integration tests, E2E tests, setting up Jest, mocking dependencies, or debugging test failures.
|
||||
|
||||
**VI**: Best practices về testing cho GoodGo microservices. Sử dụng khi viết unit tests, integration tests, E2E tests, setup Jest, mocking dependencies, hoặc debug test failures.
|
||||
|
||||
#### [Code Comments](./comment-code.md)
|
||||
**EN**: Add bilingual code comments in Vietnamese and English for better documentation. Use when adding comments to code, documenting functions/classes, or when user requests Vietnamese/English documentation.
|
||||
|
||||
**VI**: Thêm code comments song ngữ bằng tiếng Việt và tiếng Anh để tài liệu tốt hơn. Sử dụng khi thêm comments vào code, document functions/classes, hoặc khi user yêu cầu tài liệu tiếng Việt/Anh.
|
||||
|
||||
### Infrastructure & Operations
|
||||
|
||||
#### [Kubernetes Deployment](./deployment-kubernetes.md)
|
||||
**EN**: Kubernetes deployment patterns for GoodGo microservices. Use when deploying to staging/production, creating K8s manifests, configuring HPA, setting up ingress, or troubleshooting K8s deployments.
|
||||
|
||||
**VI**: Kubernetes deployment patterns cho GoodGo microservices. Sử dụng khi deploy lên staging/production, tạo K8s manifests, config HPA, setup ingress, hoặc troubleshoot K8s deployments.
|
||||
|
||||
#### [Observability & Monitoring](./observability-monitoring.md)
|
||||
**EN**: Observability and monitoring patterns for GoodGo microservices. Use when adding metrics, implementing logging, setting up tracing, creating health checks, or debugging production issues.
|
||||
|
||||
**VI**: Observability và monitoring patterns cho GoodGo microservices. Sử dụng khi thêm metrics, implement logging, setup tracing, tạo health checks, hoặc debug production issues.
|
||||
|
||||
### Standards & Security
|
||||
|
||||
#### [Project Rules](./project-rules.md)
|
||||
**EN**: GoodGo Microservices Platform coding standards and architecture patterns. Use when working with services, apps, packages, or infrastructure.
|
||||
|
||||
**VI**: Tiêu chuẩn coding và architecture patterns của GoodGo Microservices Platform. Sử dụng khi làm việc với services, apps, packages, hoặc infrastructure.
|
||||
|
||||
#### [Security](./security.md)
|
||||
**EN**: Security best practices and patterns for GoodGo microservices platform. Use when implementing authentication, authorization, data protection, input validation, rate limiting, secrets management, or security testing across all services.
|
||||
|
||||
**VI**: Security best practices và patterns cho GoodGo microservices platform. Sử dụng khi implement authentication, authorization, data protection, input validation, rate limiting, secrets management, hoặc security testing trên tất cả services.
|
||||
|
||||
#### [Documentation](./documentation.md)
|
||||
**EN**: Guidelines for writing technical documentation in the GoodGo project. Use when creating or updating README files, guides, architecture docs, or API documentation. Ensures bilingual (EN/VI) consistency and proper structure.
|
||||
|
||||
**VI**: Hướng dẫn viết technical documentation trong dự án GoodGo. Sử dụng khi tạo hoặc cập nhật README files, guides, architecture docs, hoặc API documentation. Đảm bảo tính nhất quán song ngữ (EN/VI) và cấu trúc phù hợp.
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### By Use Case / Theo Use Case
|
||||
|
||||
| Task | Recommended Skills |
|
||||
|------|-------------------|
|
||||
| Creating a new API endpoint | API Design, Security, Testing Patterns |
|
||||
| Setting up a new service | Project Rules, Database & Prisma, Observability |
|
||||
| Writing tests | Testing Patterns, Comment Code |
|
||||
| Deploying to production | Kubernetes Deployment, Observability, Security |
|
||||
| Debugging production issues | Observability & Monitoring, Security |
|
||||
| Writing documentation | Documentation, Comment Code |
|
||||
| Implementing authentication | Security, API Design, Database & Prisma |
|
||||
| Optimizing database queries | Database & Prisma, Observability |
|
||||
|
||||
### Skill Dependencies / Phụ Thuộc Giữa Các Skills
|
||||
|
||||
```
|
||||
Project Rules (Foundation)
|
||||
├── API Design
|
||||
├── Database & Prisma
|
||||
├── Security
|
||||
└── Testing Patterns
|
||||
└── Comment Code
|
||||
Documentation (Cross-cutting)
|
||||
└── All skills
|
||||
Observability (Cross-cutting)
|
||||
└── All services
|
||||
Kubernetes Deployment (Infrastructure)
|
||||
└── All services
|
||||
```
|
||||
|
||||
## How to Use Skills / Cách Sử Dụng Skills
|
||||
|
||||
1. **When starting a new task**: Review relevant skills in this directory
|
||||
2. **During development**: Reference skill documentation for patterns and examples
|
||||
3. **When stuck**: Check skill docs for best practices and common solutions
|
||||
4. **For code review**: Use skills as checklist for standards compliance
|
||||
|
||||
## Related Documentation / Tài Liệu Liên Quan
|
||||
|
||||
- [Architecture Overview](../architecture/system-design.md) - System design patterns
|
||||
- [Development Guide](../guides/development.md) - Development workflow
|
||||
- [Deployment Guide](../guides/deployment.md) - Deployment procedures
|
||||
- [API Documentation](../api/openapi/) - OpenAPI specifications
|
||||
|
||||
## Contributing / Đóng Góp
|
||||
|
||||
When updating or adding new skills:
|
||||
|
||||
1. Update the skill source file in `.cursor/skills/{skill-name}/SKILL.md`
|
||||
2. Update the corresponding documentation in `docs/en/skills/{skill-name}.md`
|
||||
3. Update the Vietnamese translation in `docs/vi/skills/{skill-name}.md`
|
||||
4. Update this index file with any changes
|
||||
5. Ensure bilingual consistency
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
- [Cursor Skills Documentation](https://cursor.sh/docs) - Official Cursor documentation
|
||||
- [Cursor AI](https://cursor.sh) - Cursor IDE homepage
|
||||
- Project Skills: `.cursor/skills/` - Source skill files
|
||||
455
docs/en/skills/api-design.md
Normal file
455
docs/en/skills/api-design.md
Normal file
@@ -0,0 +1,455 @@
|
||||
# RESTful API Design / Thiết Kế API RESTful
|
||||
|
||||
> **EN**: RESTful API design standards for GoodGo microservices. Use when creating new API endpoints, designing DTOs, implementing controllers, writing OpenAPI documentation, or standardizing API responses.
|
||||
> **VI**: Tiêu chuẩn thiết kế API RESTful cho các microservices của GoodGo. Sử dụng khi tạo endpoint API mới, thiết kế DTOs, triển khai controllers, viết tài liệu OpenAPI, hoặc chuẩn hóa response API.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: This skill covers the RESTful API design patterns and standards used across all GoodGo microservices. It ensures consistency, predictability, and maintainability of APIs through standardized URL structures, HTTP methods, response formats, error handling, and DTO validation.
|
||||
|
||||
**VI**: Skill này bao gồm các pattern và tiêu chuẩn thiết kế API RESTful được sử dụng trong tất cả các microservices của GoodGo. Nó đảm bảo tính nhất quán, dự đoán được và dễ bảo trì của APIs thông qua cấu trúc URL chuẩn hóa, HTTP methods, định dạng response, xử lý lỗi và validation DTO.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Creating new API endpoints
|
||||
- Designing request/response DTOs
|
||||
- Implementing controllers and routes
|
||||
- Writing OpenAPI/Swagger documentation
|
||||
- Standardizing error responses
|
||||
- Implementing pagination, filtering, and sorting
|
||||
- Setting up API versioning
|
||||
- Designing resource relationships
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Tạo endpoint API mới
|
||||
- Thiết kế DTOs cho request/response
|
||||
- Triển khai controllers và routes
|
||||
- Viết tài liệu OpenAPI/Swagger
|
||||
- Chuẩn hóa error responses
|
||||
- Triển khai pagination, filtering và sorting
|
||||
- Thiết lập API versioning
|
||||
- Thiết kế quan hệ giữa các resources
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### 1. URL Structure / Cấu Trúc URL
|
||||
|
||||
**EN**: URLs follow a hierarchical resource-based structure with versioning.
|
||||
|
||||
**VI**: URLs tuân theo cấu trúc phân cấp dựa trên resource với versioning.
|
||||
|
||||
```
|
||||
https://api.goodgo.com/v1/{resource}/{id}/{sub-resource}
|
||||
|
||||
Examples:
|
||||
GET /v1/users # List users
|
||||
POST /v1/users # Create user
|
||||
GET /v1/users/123 # Get user by ID
|
||||
PUT /v1/users/123 # Update user
|
||||
DELETE /v1/users/123 # Delete user
|
||||
GET /v1/users/123/orders # Get user's orders
|
||||
POST /v1/users/123/orders # Create order for user
|
||||
```
|
||||
|
||||
### 2. HTTP Methods / Phương Thức HTTP
|
||||
|
||||
- **GET**: Retrieve resource(s) - Safe, Idempotent
|
||||
- **POST**: Create new resource - Not idempotent
|
||||
- **PUT**: Full update - Idempotent
|
||||
- **PATCH**: Partial update - Idempotent
|
||||
- **DELETE**: Remove resource - Idempotent
|
||||
|
||||
### 3. Standard Response Format / Định Dạng Response Chuẩn
|
||||
|
||||
All API responses follow a consistent structure with `success`, `data`, and optional `metadata` fields.
|
||||
|
||||
Tất cả API responses tuân theo cấu trúc nhất quán với các trường `success`, `data`, và `metadata` tùy chọn.
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Success Response Pattern
|
||||
|
||||
```typescript
|
||||
interface SuccessResponse<T> {
|
||||
success: true;
|
||||
data: T;
|
||||
message?: string;
|
||||
timestamp?: string;
|
||||
pagination?: {
|
||||
total: number;
|
||||
skip: number;
|
||||
take: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/identity/user/user.controller.ts
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
users: result.users,
|
||||
pagination: {
|
||||
total: result.total,
|
||||
skip: filters.skip,
|
||||
take: filters.take,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Error Response Pattern
|
||||
|
||||
```typescript
|
||||
interface ErrorResponse {
|
||||
success: false;
|
||||
error: {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: any;
|
||||
field?: string;
|
||||
};
|
||||
timestamp?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/identity/user/user.controller.ts
|
||||
if (error instanceof z.ZodError) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Invalid filters',
|
||||
details: error.errors,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP Status Codes / Mã Trạng Thái HTTP
|
||||
|
||||
```typescript
|
||||
// Success codes
|
||||
200 OK // GET, PUT, PATCH success
|
||||
201 Created // POST success with resource creation
|
||||
204 No Content // DELETE success
|
||||
|
||||
// Client errors
|
||||
400 Bad Request // Invalid request data
|
||||
401 Unauthorized // Missing/invalid authentication
|
||||
403 Forbidden // Valid auth but no permission
|
||||
404 Not Found // Resource doesn't exist
|
||||
409 Conflict // Resource conflict (duplicate)
|
||||
422 Unprocessable // Validation errors
|
||||
|
||||
// Server errors
|
||||
500 Internal Error // Unexpected server error
|
||||
502 Bad Gateway // External service error
|
||||
503 Service Unavailable // Service temporarily down
|
||||
```
|
||||
|
||||
### DTOs with Zod Validation / DTOs với Zod Validation
|
||||
|
||||
**EN**: DTOs use Zod for runtime validation with bilingual error messages.
|
||||
|
||||
**VI**: DTOs sử dụng Zod cho validation runtime với thông báo lỗi song ngữ.
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/identity/identity.dto.ts
|
||||
import { z } from 'zod';
|
||||
|
||||
export const CreateOrganizationDto = z.object({
|
||||
name: z.string().min(1, 'Organization name is required / Tên tổ chức là bắt buộc').max(255),
|
||||
domain: z.string().email().optional().or(z.string().min(1).max(255).optional()),
|
||||
parentId: z.string().optional(),
|
||||
settings: z.record(z.any()).optional(),
|
||||
});
|
||||
|
||||
export type CreateOrganizationDto = z.infer<typeof CreateOrganizationDto>;
|
||||
|
||||
export const UserFiltersDto = z.object({
|
||||
organizationId: z.string().optional(),
|
||||
isActive: z.boolean().optional(),
|
||||
emailVerified: z.boolean().optional(),
|
||||
search: z.string().optional(),
|
||||
skip: z.number().int().min(0).default(0),
|
||||
take: z.number().int().min(1).max(100).default(20),
|
||||
});
|
||||
```
|
||||
|
||||
### Controller Implementation Pattern / Pattern Triển Khai Controller
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/identity/user/user.controller.ts
|
||||
export class UserManagementController {
|
||||
/**
|
||||
* EN: List users
|
||||
* VI: Liệt kê users
|
||||
*/
|
||||
async list(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const filters = UserFiltersDto.parse({
|
||||
organizationId: req.query.organizationId as string,
|
||||
isActive: req.query.isActive === 'true' ? true : req.query.isActive === 'false' ? false : undefined,
|
||||
emailVerified: req.query.emailVerified === 'true' ? true : req.query.emailVerified === 'false' ? false : undefined,
|
||||
search: req.query.search as string,
|
||||
skip: parseInt(req.query.skip as string) || 0,
|
||||
take: parseInt(req.query.take as string) || 20,
|
||||
});
|
||||
|
||||
const result = await userManagementService.searchUsers(filters);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
users: result.users,
|
||||
pagination: {
|
||||
total: result.total,
|
||||
skip: filters.skip,
|
||||
take: filters.take,
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
if (error instanceof z.ZodError) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Invalid filters',
|
||||
details: error.errors,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'LIST_USERS_FAILED',
|
||||
message: error.message || 'Failed to list users',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Get user by ID
|
||||
* VI: Lấy user theo ID
|
||||
*/
|
||||
async get(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const user = await userManagementService.getUser(id);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: user,
|
||||
});
|
||||
} catch (error: any) {
|
||||
if (error instanceof NotFoundError) {
|
||||
res.status(404).json(error.toApiResponse());
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'GET_USER_FAILED',
|
||||
message: error.message || 'Failed to get user',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling with Custom Error Classes / Xử Lý Lỗi với Custom Error Classes
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/errors/http-error.ts
|
||||
export class HttpError extends Error {
|
||||
public readonly statusCode: number;
|
||||
public readonly errorCode: string;
|
||||
public readonly isOperational: boolean;
|
||||
public readonly details?: any;
|
||||
|
||||
constructor(
|
||||
message: string,
|
||||
statusCode: number = 500,
|
||||
errorCode: string = 'INTERNAL_ERROR',
|
||||
isOperational: boolean = true,
|
||||
details?: any
|
||||
) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
this.statusCode = statusCode;
|
||||
this.errorCode = errorCode;
|
||||
this.isOperational = isOperational;
|
||||
this.details = details;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
|
||||
toApiResponse() {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: this.errorCode,
|
||||
message: this.message,
|
||||
...(this.details && { details: this.details }),
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class NotFoundError extends HttpError {
|
||||
constructor(resource: string = 'Resource / Tài nguyên', details?: any) {
|
||||
super(`${resource} not found / ${resource} không tìm thấy`, 404, 'NOT_FOUND', true, details);
|
||||
}
|
||||
}
|
||||
|
||||
export class ValidationError extends HttpError {
|
||||
constructor(message: string = 'Validation failed / Validation thất bại', details?: any) {
|
||||
super(message, 422, 'VALIDATION_ERROR', true, details);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### 1. Resource Naming / Đặt Tên Resource
|
||||
|
||||
- ✅ Use plural nouns (`/users` not `/user`)
|
||||
- ✅ Use kebab-case for multi-word resources (`/user-profiles`)
|
||||
- ✅ Keep URLs as short as possible
|
||||
- ❌ Avoid verbs in URLs (use HTTP methods instead)
|
||||
|
||||
### 2. Versioning / Phiên Bản Hóa
|
||||
|
||||
- ✅ Include version in URL (`/v1/users`)
|
||||
- ✅ Maintain backward compatibility
|
||||
- ✅ Deprecate old versions gracefully with warnings
|
||||
|
||||
### 3. Security / Bảo Mật
|
||||
|
||||
- ✅ Always use HTTPS
|
||||
- ✅ Implement rate limiting
|
||||
- ✅ Validate all inputs with DTOs
|
||||
- ✅ Use proper authentication/authorization middleware
|
||||
- ✅ Never expose sensitive data in responses
|
||||
|
||||
### 4. Performance / Hiệu Năng
|
||||
|
||||
- ✅ Implement pagination for lists (use `skip` and `take`)
|
||||
- ✅ Use field filtering when possible (`select` in Prisma)
|
||||
- ✅ Cache responses appropriately
|
||||
- ✅ Compress responses (gzip)
|
||||
|
||||
### 5. Documentation / Tài Liệu
|
||||
|
||||
- ✅ Keep OpenAPI spec up to date
|
||||
- ✅ Include examples in documentation
|
||||
- ✅ Document error responses
|
||||
- ✅ Version your documentation
|
||||
|
||||
### 6. Error Handling / Xử Lý Lỗi
|
||||
|
||||
- ✅ Use consistent error response format
|
||||
- ✅ Provide actionable error messages
|
||||
- ✅ Include error codes for programmatic handling
|
||||
- ✅ Log errors server-side, don't expose stack traces in production
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Controller Examples / Ví Dụ Controller
|
||||
|
||||
- **User Management**: [`services/iam-service/src/modules/identity/user/user.controller.ts`](../../../services/iam-service/src/modules/identity/user/user.controller.ts)
|
||||
- **Feature Controller**: [`services/iam-service/src/modules/feature/feature.controller.ts`](../../../services/iam-service/src/modules/feature/feature.controller.ts)
|
||||
- **RBAC Controller**: [`services/iam-service/src/modules/rbac/rbac.controller.ts`](../../../services/iam-service/src/modules/rbac/rbac.controller.ts)
|
||||
|
||||
### DTO Examples / Ví Dụ DTO
|
||||
|
||||
- **Identity DTOs**: [`services/iam-service/src/modules/identity/identity.dto.ts`](../../../services/iam-service/src/modules/identity/identity.dto.ts)
|
||||
- **Auth DTOs**: [`services/iam-service/src/modules/auth/auth.dto.ts`](../../../services/iam-service/src/modules/auth/auth.dto.ts)
|
||||
- **RBAC DTOs**: [`services/iam-service/src/modules/rbac/rbac.dto.ts`](../../../services/iam-service/src/modules/rbac/rbac.dto.ts)
|
||||
|
||||
### Error Handling Examples / Ví Dụ Xử Lý Lỗi
|
||||
|
||||
- **HTTP Error Classes**: [`services/iam-service/src/errors/http-error.ts`](../../../services/iam-service/src/errors/http-error.ts)
|
||||
- **Error Middleware**: [`services/iam-service/src/middlewares/error.middleware.ts`](../../../services/iam-service/src/middlewares/error.middleware.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Response Format Cheat Sheet / Bảng Tra Cứu Định Dạng Response
|
||||
|
||||
| Scenario | Status Code | Response Structure |
|
||||
|----------|-------------|-------------------|
|
||||
| Success (GET) | 200 | `{ success: true, data: {...} }` |
|
||||
| Success (POST) | 201 | `{ success: true, data: {...} }` |
|
||||
| Success (DELETE) | 200 | `{ success: true, message: "..." }` |
|
||||
| Validation Error | 400/422 | `{ success: false, error: { code, message, details } }` |
|
||||
| Not Found | 404 | `{ success: false, error: { code: "NOT_FOUND", message } }` |
|
||||
| Unauthorized | 401 | `{ success: false, error: { code: "UNAUTHORIZED", message } }` |
|
||||
| Forbidden | 403 | `{ success: false, error: { code: "FORBIDDEN", message } }` |
|
||||
| Server Error | 500 | `{ success: false, error: { code: "INTERNAL_ERROR", message } }` |
|
||||
|
||||
### Common DTO Patterns / Pattern DTO Thường Dùng
|
||||
|
||||
```typescript
|
||||
// Create DTO
|
||||
const CreateDto = z.object({
|
||||
requiredField: z.string().min(1),
|
||||
optionalField: z.string().optional(),
|
||||
});
|
||||
|
||||
// Update DTO (all fields optional)
|
||||
const UpdateDto = z.object({
|
||||
field1: z.string().optional(),
|
||||
field2: z.number().optional(),
|
||||
});
|
||||
|
||||
// Query/Filter DTO
|
||||
const QueryDto = z.object({
|
||||
page: z.number().int().min(1).default(1),
|
||||
limit: z.number().int().min(1).max(100).default(20),
|
||||
search: z.string().optional(),
|
||||
sortBy: z.string().optional(),
|
||||
order: z.enum(['asc', 'desc']).default('desc'),
|
||||
});
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Database Prisma](./database-prisma.md)**: For database operations and repository patterns
|
||||
- **[Security](./security.md)**: For authentication, authorization, and security best practices
|
||||
- **[Testing Patterns](./testing-patterns.md)**: For testing API endpoints
|
||||
- **[Documentation](./documentation.md)**: For writing API documentation
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### External Documentation / Tài Liệu Bên Ngoài
|
||||
|
||||
- [REST API Design Best Practices](https://restfulapi.net/)
|
||||
- [HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
|
||||
- [Zod Documentation](https://zod.dev/)
|
||||
- [OpenAPI Specification](https://swagger.io/specification/)
|
||||
|
||||
### Internal Documentation / Tài Liệu Nội Bộ
|
||||
|
||||
- [API Reference](../api/openapi/iam-service.yaml)
|
||||
- [Service Communication](../architecture/service-communication.md)
|
||||
- [Project Rules](./project-rules.md)
|
||||
562
docs/en/skills/comment-code.md
Normal file
562
docs/en/skills/comment-code.md
Normal file
@@ -0,0 +1,562 @@
|
||||
# Comment Code / Viết Comment Code
|
||||
|
||||
> **EN**: Guidelines for adding comprehensive bilingual code comments (English and Vietnamese) to improve code readability for international and Vietnamese teams.
|
||||
> **VI**: Hướng dẫn thêm comments song ngữ (tiếng Anh và tiếng Việt) để cải thiện khả năng đọc code cho các đội quốc tế và Việt Nam.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: Code comments are essential for maintaining and understanding codebase, especially in a bilingual development environment. This guide provides comprehensive patterns for writing clear, consistent, and helpful comments in both English and Vietnamese across the GoodGo microservices platform. It covers JSDoc documentation, inline comments, special comment types, and best practices for effective code documentation.
|
||||
|
||||
**VI**: Comments code là điều cần thiết để bảo trì và hiểu codebase, đặc biệt trong môi trường phát triển song ngữ. Hướng dẫn này cung cấp các patterns toàn diện để viết comments rõ ràng, nhất quán và hữu ích bằng cả tiếng Anh và tiếng Việt trên nền tảng microservices GoodGo. Nó bao gồm tài liệu JSDoc, inline comments, các loại comment đặc biệt, và best practices cho tài liệu code hiệu quả.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use bilingual commenting patterns when:
|
||||
- Adding comments to new code
|
||||
- Documenting existing code
|
||||
- Creating JSDoc/TSDoc documentation
|
||||
- Writing function/class descriptions
|
||||
- Explaining complex logic or algorithms
|
||||
- Adding inline comments for clarification
|
||||
- Documenting API endpoints and interfaces
|
||||
- Explaining configuration and setup code
|
||||
- Writing security-critical code documentation
|
||||
- Creating error handling documentation
|
||||
|
||||
**VI**: Sử dụng các patterns comment song ngữ khi:
|
||||
- Thêm comments vào code mới
|
||||
- Tài liệu hóa code hiện có
|
||||
- Tạo tài liệu JSDoc/TSDoc
|
||||
- Viết mô tả functions/classes
|
||||
- Giải thích logic hoặc thuật toán phức tạp
|
||||
- Thêm inline comments để làm rõ
|
||||
- Tài liệu hóa API endpoints và interfaces
|
||||
- Giải thích code cấu hình và setup
|
||||
- Viết tài liệu code bảo mật quan trọng
|
||||
- Tạo tài liệu xử lý lỗi
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Comment Format / Định Dạng Comment
|
||||
|
||||
All comments in the GoodGo project should be bilingual, with English (EN) followed by Vietnamese (VI) translations.
|
||||
|
||||
**Pattern**:
|
||||
```
|
||||
// EN: [English explanation]
|
||||
// VI: [Vietnamese explanation]
|
||||
```
|
||||
|
||||
### Comment Types / Các Loại Comment
|
||||
|
||||
1. **Single-line Comments** (`//`): For brief explanations
|
||||
2. **Multi-line Comments** (`/* */`): For longer explanations
|
||||
3. **JSDoc Comments** (`/** */`): For function, class, and API documentation
|
||||
4. **Prisma Comments** (`///`): For database schema documentation
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Single-line Comments / Comments Một Dòng
|
||||
|
||||
Use single-line comments for brief explanations of code behavior.
|
||||
|
||||
```typescript
|
||||
// EN: Initialize database connection
|
||||
// VI: Khởi tạo kết nối database
|
||||
const db = await createConnection();
|
||||
|
||||
// EN: Enable detailed logging in development, minimal in production
|
||||
// VI: Bật ghi log chi tiết trong development, tối thiểu trong production
|
||||
const logLevel = process.env.NODE_ENV === 'development' ? 'debug' : 'error';
|
||||
```
|
||||
|
||||
**Real Example**: [`services/iam-service/src/config/database.config.ts`](../../../services/iam-service/src/config/database.config.ts)
|
||||
|
||||
### Multi-line Comments / Comments Nhiều Dòng
|
||||
|
||||
Use multi-line comments for detailed explanations or step-by-step processes.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Validates user credentials and returns JWT token
|
||||
* VI: Xác thực thông tin đăng nhập và trả về JWT token
|
||||
*
|
||||
* @param email - User email address / Địa chỉ email người dùng
|
||||
* @param password - User password / Mật khẩu người dùng
|
||||
* @returns JWT token / Mã JWT token
|
||||
* @throws AuthenticationError if credentials invalid / Lỗi xác thực nếu thông tin không hợp lệ
|
||||
*/
|
||||
async function login(email: string, password: string): Promise<string> {
|
||||
// EN: Implementation here
|
||||
// VI: Implementation ở đây
|
||||
}
|
||||
```
|
||||
|
||||
### Function Documentation / Tài Liệu Function
|
||||
|
||||
Use JSDoc format for all public functions with bilingual descriptions.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Calculates the total price including tax and discount
|
||||
* VI: Tính tổng giá bao gồm thuế và giảm giá
|
||||
*
|
||||
* @param basePrice - Original price / Giá gốc
|
||||
* @param taxRate - Tax rate (0-1) / Tỷ lệ thuế (0-1)
|
||||
* @param discount - Discount amount / Số tiền giảm giá
|
||||
* @returns Final price / Giá cuối cùng
|
||||
*/
|
||||
function calculateTotal(
|
||||
basePrice: number,
|
||||
taxRate: number,
|
||||
discount: number
|
||||
): number {
|
||||
// EN: Apply discount first
|
||||
// VI: Áp dụng giảm giá trước
|
||||
const discountedPrice = basePrice - discount;
|
||||
|
||||
// EN: Then calculate tax
|
||||
// VI: Sau đó tính thuế
|
||||
const tax = discountedPrice * taxRate;
|
||||
|
||||
return discountedPrice + tax;
|
||||
}
|
||||
```
|
||||
|
||||
**Real Example**: [`services/iam-service/src/modules/feature/feature.service.ts`](../../../services/iam-service/src/modules/feature/feature.service.ts)
|
||||
|
||||
### Class Documentation / Tài Liệu Class
|
||||
|
||||
Document classes with bilingual descriptions and explain their purpose.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Service for managing features in the system
|
||||
* VI: Service để quản lý các features trong hệ thống
|
||||
*/
|
||||
export class FeatureService {
|
||||
/**
|
||||
* EN: Create a new feature
|
||||
* VI: Tạo một feature mới
|
||||
*
|
||||
* @param data - Feature data / Dữ liệu feature
|
||||
* @returns Created feature / Feature đã tạo
|
||||
*/
|
||||
async create(data: { name: string; title?: string }) {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Real Example**: [`services/iam-service/src/modules/feature/feature.service.ts`](../../../services/iam-service/src/modules/feature/feature.service.ts)
|
||||
|
||||
### Interface/Type Documentation / Tài Liệu Interface/Type
|
||||
|
||||
Document interfaces and types to explain their structure and purpose.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: User data transfer object
|
||||
* VI: Đối tượng truyền dữ liệu người dùng
|
||||
*/
|
||||
interface UserDto {
|
||||
/** EN: Unique user identifier / VI: Mã định danh duy nhất */
|
||||
id: string;
|
||||
|
||||
/** EN: User email address / VI: Địa chỉ email người dùng */
|
||||
email: string;
|
||||
|
||||
/** EN: User display name / VI: Tên hiển thị người dùng */
|
||||
name: string;
|
||||
|
||||
/** EN: User role for authorization / VI: Vai trò người dùng để phân quyền */
|
||||
role: 'admin' | 'user' | 'guest';
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Comments / Comments Cấu Hình
|
||||
|
||||
Document configuration files and environment variables with clear explanations.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Prisma client instance configured for the application
|
||||
* VI: Instance Prisma client được cấu hình cho ứng dụng
|
||||
*/
|
||||
export const prisma = new PrismaClient({
|
||||
// EN: Enable detailed logging in development, minimal in production
|
||||
// VI: Bật ghi log chi tiết trong development, tối thiểu trong production
|
||||
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
|
||||
});
|
||||
|
||||
/**
|
||||
* EN: Establish database connection on application startup
|
||||
* VI: Thiết lập kết nối database khi khởi động ứng dụng
|
||||
*/
|
||||
export const connectDatabase = async (): Promise<void> => {
|
||||
try {
|
||||
// EN: Connect to database using Prisma
|
||||
// VI: Kết nối tới database sử dụng Prisma
|
||||
await prisma.$connect();
|
||||
logger.info('Database connected successfully / Kết nối database thành công');
|
||||
} catch (error) {
|
||||
// EN: Log error and exit if database connection fails
|
||||
// VI: Ghi log lỗi và thoát nếu kết nối database thất bại
|
||||
logger.error('Database connection failed / Kết nối database thất bại', { error });
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Real Example**: [`services/iam-service/src/config/database.config.ts`](../../../services/iam-service/src/config/database.config.ts)
|
||||
|
||||
### Middleware Documentation / Tài Liệu Middleware
|
||||
|
||||
Document middleware functions with their purpose and behavior.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Authentication middleware to verify JWT tokens
|
||||
* VI: Middleware xác thực để kiểm tra JWT token
|
||||
*/
|
||||
export function authMiddleware(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) {
|
||||
// EN: Extract token from Authorization header
|
||||
// VI: Lấy token từ header Authorization
|
||||
const authHeader = req.headers.authorization;
|
||||
const token = authHeader?.replace('Bearer ', '');
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'NO_TOKEN',
|
||||
message: 'Authentication required / Yêu cầu xác thực',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// EN: Verify token and extract payload
|
||||
// VI: Xác minh token và lấy payload
|
||||
const payload = jwt.verify(token, JWT_SECRET);
|
||||
req.user = payload;
|
||||
next();
|
||||
} catch (error) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INVALID_TOKEN',
|
||||
message: 'Invalid or expired token / Token không hợp lệ hoặc hết hạn',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Prisma Schema Comments / Comments Schema Prisma
|
||||
|
||||
Use triple-slash comments (`///`) for Prisma schema documentation.
|
||||
|
||||
```prisma
|
||||
/// EN: User model for authentication and profile
|
||||
/// VI: Model người dùng cho xác thực và hồ sơ
|
||||
model User {
|
||||
/// EN: Unique identifier / VI: Mã định danh duy nhất
|
||||
id String @id @default(cuid())
|
||||
|
||||
/// EN: User email (unique) / VI: Email người dùng (duy nhất)
|
||||
email String @unique
|
||||
|
||||
/// EN: Hashed password / VI: Mật khẩu đã mã hóa
|
||||
password String
|
||||
|
||||
/// EN: Display name / VI: Tên hiển thị
|
||||
name String
|
||||
|
||||
/// EN: Account creation timestamp / VI: Thời gian tạo tài khoản
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
/// EN: Last update timestamp / VI: Thời gian cập nhật cuối
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
```
|
||||
|
||||
### Test Comments / Comments Test
|
||||
|
||||
Document test setup and explain test scenarios in both languages.
|
||||
|
||||
```typescript
|
||||
// EN: Mock environment variables for tests
|
||||
// VI: Mock biến môi trường cho tests
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.DATABASE_URL = 'postgresql://test:test@localhost:5432/test_db';
|
||||
|
||||
// EN: Mock external services to avoid real network calls
|
||||
// VI: Mock các service bên ngoài để tránh gọi mạng thật
|
||||
jest.mock('@goodgo/logger', () => ({
|
||||
logger: {
|
||||
info: jest.fn(),
|
||||
error: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('FeatureService', () => {
|
||||
it('should create a feature successfully', async () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const testData = { name: 'test-feature' };
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực hiện
|
||||
const result = await service.create(testData);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Real Example**: [`services/iam-service/src/__tests__/setupTests.ts`](../../../services/iam-service/src/__tests__/setupTests.ts)
|
||||
|
||||
### Complex Logic Comments / Comments Logic Phức Tạp
|
||||
|
||||
When explaining complex algorithms or business logic, break it down into steps.
|
||||
|
||||
```typescript
|
||||
// EN: Step 1: Validate input parameters
|
||||
// VI: Bước 1: Xác thực tham số đầu vào
|
||||
if (!email || !password) {
|
||||
throw new ValidationError('Email and password required');
|
||||
}
|
||||
|
||||
// EN: Step 2: Check if user exists in database
|
||||
// VI: Bước 2: Kiểm tra xem người dùng có tồn tại trong database
|
||||
const user = await prisma.user.findUnique({ where: { email } });
|
||||
if (!user) {
|
||||
throw new NotFoundError('User not found');
|
||||
}
|
||||
|
||||
// EN: Step 3: Verify password hash
|
||||
// VI: Bước 3: Xác minh hash mật khẩu
|
||||
const isValidPassword = await bcrypt.compare(password, user.password);
|
||||
if (!isValidPassword) {
|
||||
throw new AuthenticationError('Invalid credentials');
|
||||
}
|
||||
|
||||
// EN: Step 4: Generate and return JWT token
|
||||
// VI: Bước 4: Tạo và trả về JWT token
|
||||
const token = jwt.sign({ userId: user.id }, JWT_SECRET);
|
||||
return { token, user };
|
||||
```
|
||||
|
||||
## Special Comment Types / Các Loại Comment Đặc Biệt
|
||||
|
||||
### TODO Comments / Comments TODO
|
||||
|
||||
Use TODO comments for future improvements with bilingual descriptions.
|
||||
|
||||
```typescript
|
||||
// TODO EN: Implement caching for better performance
|
||||
// TODO VI: Triển khai caching để cải thiện hiệu suất
|
||||
|
||||
// TODO EN: Add rate limiting to prevent abuse
|
||||
// TODO VI: Thêm rate limiting để ngăn chặn lạm dụng
|
||||
```
|
||||
|
||||
### FIXME Comments / Comments FIXME
|
||||
|
||||
Use FIXME comments for code that needs fixing.
|
||||
|
||||
```typescript
|
||||
// FIXME EN: This causes memory leak, needs refactoring
|
||||
// FIXME VI: Đoạn này gây rò rỉ bộ nhớ, cần refactor
|
||||
|
||||
// FIXME EN: Temporary workaround, should implement proper solution
|
||||
// FIXME VI: Giải pháp tạm thời, nên triển khai giải pháp đúng đắn
|
||||
```
|
||||
|
||||
### WARNING Comments / Comments CẢNH BÁO
|
||||
|
||||
Use WARNING comments for code that requires special attention.
|
||||
|
||||
```typescript
|
||||
// WARNING EN: Do not modify this without updating the database schema
|
||||
// WARNING VI: Không sửa đổi phần này mà không cập nhật schema database
|
||||
|
||||
// WARNING EN: This function modifies global state, use with caution
|
||||
// WARNING VI: Function này thay đổi global state, sử dụng cẩn thận
|
||||
```
|
||||
|
||||
### NOTE Comments / Comments GHI CHÚ
|
||||
|
||||
Use NOTE comments for important information or explanations.
|
||||
|
||||
```typescript
|
||||
// NOTE EN: This is intentionally async to avoid blocking the event loop
|
||||
// NOTE VI: Đây là async có chủ ý để tránh block event loop
|
||||
|
||||
// NOTE EN: Priority: Docker Compose > .env.local > .env > System environment
|
||||
// NOTE VI: Ưu tiên: Docker Compose > .env.local > .env > Môi trường hệ thống
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Comment Placement / Vị Trí Comment
|
||||
|
||||
- ✅ Place bilingual comments together (EN first, then VI) / Đặt comments song ngữ cùng nhau (EN trước, sau đó VI)
|
||||
- ✅ Keep comments close to the code they describe / Giữ comments gần với code mà chúng mô tả
|
||||
- ✅ Use JSDoc format for functions and classes / Sử dụng format JSDoc cho functions và classes
|
||||
- ✅ Update comments when code changes / Cập nhật comments khi code thay đổi
|
||||
|
||||
### Comment Content / Nội Dung Comment
|
||||
|
||||
- ✅ **DO**: Explain WHY, not WHAT (code shows what) / Giải thích TẠI SAO, không phải CÁI GÌ
|
||||
- ✅ **DO**: Document complex logic and business rules / Tài liệu hóa logic phức tạp và quy tắc nghiệp vụ
|
||||
- ✅ **DO**: Include parameter descriptions and return types / Bao gồm mô tả tham số và kiểu trả về
|
||||
- ✅ **DO**: Document error conditions and exceptions / Tài liệu hóa điều kiện lỗi và ngoại lệ
|
||||
- ✅ **DON'T**: State the obvious / Không nói điều hiển nhiên
|
||||
- ✅ **DON'T**: Write redundant comments / Không viết comments thừa
|
||||
- ✅ **DON'T**: Comment out code (use version control instead) / Không comment code (sử dụng version control)
|
||||
|
||||
### Language Guidelines / Hướng Dẫn Ngôn Ngữ
|
||||
|
||||
**English / Tiếng Anh**:
|
||||
- Use clear, concise technical English / Sử dụng tiếng Anh kỹ thuật rõ ràng, ngắn gọn
|
||||
- Use proper technical terminology / Sử dụng thuật ngữ kỹ thuật đúng
|
||||
- Be specific and actionable / Cụ thể và có thể thực hiện
|
||||
|
||||
**Vietnamese / Tiếng Việt**:
|
||||
- Use proper Vietnamese technical terms / Sử dụng thuật ngữ kỹ thuật tiếng Việt đúng
|
||||
- Keep translations accurate and natural / Giữ bản dịch chính xác và tự nhiên
|
||||
- Use consistent terminology across codebase / Sử dụng thuật ngữ nhất quán trên codebase
|
||||
- Prefer technical Vietnamese terms over literal translations / Ưu tiên thuật ngữ kỹ thuật Việt hơn dịch theo nghĩa đen
|
||||
|
||||
### Documentation Priority / Ưu Tiên Tài Liệu
|
||||
|
||||
**High Priority** (Always document / Luôn tài liệu hóa):
|
||||
- Public APIs and exported functions / API công khai và functions được export
|
||||
- Complex algorithms and business logic / Thuật toán phức tạp và logic nghiệp vụ
|
||||
- Security-critical code / Code bảo mật quan trọng
|
||||
- Configuration and environment setup / Cấu hình và thiết lập môi trường
|
||||
- Error handling strategies / Chiến lược xử lý lỗi
|
||||
|
||||
**Medium Priority** (Document when helpful / Tài liệu khi hữu ích):
|
||||
- Helper functions with non-obvious behavior / Helper functions có hành vi không rõ ràng
|
||||
- Data transformations / Chuyển đổi dữ liệu
|
||||
- Integration points with external services / Điểm tích hợp với services bên ngoài
|
||||
|
||||
**Low Priority** (Optional / Tùy chọn):
|
||||
- Simple getters/setters / Getters/setters đơn giản
|
||||
- Self-explanatory code / Code tự giải thích
|
||||
- Standard CRUD operations / Các thao tác CRUD tiêu chuẩn
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Real Comment Examples / Ví Dụ Comment Thực Tế
|
||||
|
||||
1. **Service Comments**: [`services/iam-service/src/modules/feature/feature.service.ts`](../../../services/iam-service/src/modules/feature/feature.service.ts)
|
||||
2. **Config Comments**: [`services/iam-service/src/config/database.config.ts`](../../../services/iam-service/src/config/database.config.ts)
|
||||
3. **Test Comments**: [`services/iam-service/src/__tests__/setupTests.ts`](../../../services/iam-service/src/__tests__/setupTests.ts)
|
||||
4. **Jest Config Comments**: [`services/iam-service/jest.config.ts`](../../../services/iam-service/jest.config.ts)
|
||||
|
||||
### Comment Patterns in Different Contexts / Patterns Comment Trong Các Ngữ Cảnh Khác Nhau
|
||||
|
||||
- **Controllers**: Document API endpoints and request/response handling
|
||||
- **Services**: Document business logic and data processing
|
||||
- **Middleware**: Document authentication, authorization, and request processing
|
||||
- **Repositories**: Document database operations and query logic
|
||||
- **Config Files**: Document configuration options and environment variables
|
||||
- **Tests**: Document test scenarios and setup procedures
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Function Comment Template / Template Comment Function
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: [Brief description in English]
|
||||
* VI: [Mô tả ngắn gọn bằng tiếng Việt]
|
||||
*
|
||||
* @param paramName - EN description / VI mô tả
|
||||
* @returns EN description / VI mô tả
|
||||
* @throws ErrorType EN when / VI khi nào
|
||||
*/
|
||||
```
|
||||
|
||||
### Inline Comment Template / Template Inline Comment
|
||||
|
||||
```typescript
|
||||
// EN: [English explanation]
|
||||
// VI: [Giải thích tiếng Việt]
|
||||
```
|
||||
|
||||
### Complex Block Template / Template Block Phức Tạp
|
||||
|
||||
```typescript
|
||||
// EN: Step N: [What this block does]
|
||||
// VI: Bước N: [Block này làm gì]
|
||||
```
|
||||
|
||||
### Class Comment Template / Template Comment Class
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: [Class purpose in English]
|
||||
* VI: [Mục đích class bằng tiếng Việt]
|
||||
*/
|
||||
export class ClassName {
|
||||
/**
|
||||
* EN: [Property description]
|
||||
* VI: [Mô tả property]
|
||||
*/
|
||||
private property: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Interface Comment Template / Template Comment Interface
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: [Interface purpose in English]
|
||||
* VI: [Mục đích interface bằng tiếng Việt]
|
||||
*/
|
||||
interface InterfaceName {
|
||||
/** EN: Property description / VI: Mô tả property */
|
||||
property: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Testing Patterns](./testing-patterns.md)**: Writing comments in test files / Viết comments trong file test
|
||||
- **[API Design](./api-design.md)**: Documenting API endpoints / Tài liệu hóa API endpoints
|
||||
- **[Documentation](./documentation.md)**: Writing technical documentation / Viết tài liệu kỹ thuật
|
||||
- **[Project Rules](./project-rules.md)**: Code organization and standards / Tổ chức code và tiêu chuẩn
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### Documentation Standards / Tiêu Chuẩn Tài Liệu
|
||||
|
||||
- [JSDoc Documentation](https://jsdoc.app/)
|
||||
- [TypeScript JSDoc](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
|
||||
- [TSDoc Specification](https://tsdoc.org/)
|
||||
|
||||
### Internal Documentation / Tài Liệu Nội Bộ
|
||||
|
||||
- [Documentation Writing Guidelines](./documentation.md)
|
||||
- [API Design Standards](./api-design.md)
|
||||
- [Project Coding Standards](./project-rules.md)
|
||||
|
||||
### Tools / Công Cụ
|
||||
|
||||
- **JSDoc**: Generate API documentation from comments
|
||||
- **ESLint**: Enforce comment style and completeness
|
||||
- **Prettier**: Format comments consistently
|
||||
- **VS Code**: IntelliSense uses JSDoc comments for better autocomplete
|
||||
584
docs/en/skills/database-prisma.md
Normal file
584
docs/en/skills/database-prisma.md
Normal file
@@ -0,0 +1,584 @@
|
||||
# Database & Prisma / Cơ Sở Dữ Liệu & Prisma
|
||||
|
||||
> **EN**: Prisma ORM and database patterns for GoodGo microservices. Use when working with databases, creating Prisma schemas, writing migrations, implementing repositories, or optimizing queries.
|
||||
> **VI**: Pattern Prisma ORM và database cho các microservices của GoodGo. Sử dụng khi làm việc với databases, tạo Prisma schemas, viết migrations, triển khai repositories, hoặc tối ưu queries.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: This skill covers Prisma ORM patterns, database schema design, repository patterns, query optimization, and transaction handling used across GoodGo microservices. It ensures type-safe database operations, consistent data access patterns, and optimal performance.
|
||||
|
||||
**VI**: Skill này bao gồm các pattern Prisma ORM, thiết kế database schema, repository patterns, tối ưu queries, và xử lý transactions được sử dụng trong các microservices của GoodGo. Nó đảm bảo các thao tác database type-safe, pattern truy cập dữ liệu nhất quán, và hiệu năng tối ưu.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Setting up Prisma for a new service
|
||||
- Creating or modifying database schemas
|
||||
- Writing database migrations
|
||||
- Implementing repository patterns
|
||||
- Optimizing database queries
|
||||
- Setting up database connections
|
||||
- Implementing transactions
|
||||
- Working with Neon PostgreSQL
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Thiết lập Prisma cho service mới
|
||||
- Tạo hoặc sửa đổi database schemas
|
||||
- Viết database migrations
|
||||
- Triển khai repository patterns
|
||||
- Tối ưu database queries
|
||||
- Thiết lập kết nối database
|
||||
- Triển khai transactions
|
||||
- Làm việc với Neon PostgreSQL
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### 1. Repository Pattern / Pattern Repository
|
||||
|
||||
**EN**: All database operations go through repository classes that extend `BaseRepository`, providing consistent CRUD operations and error handling.
|
||||
|
||||
**VI**: Tất cả các thao tác database đi qua các repository classes kế thừa `BaseRepository`, cung cấp các CRUD operations nhất quán và xử lý lỗi.
|
||||
|
||||
### 2. Prisma Schema / Schema Prisma
|
||||
|
||||
**EN**: Database schema is defined in `prisma/schema.prisma` with models, relations, indexes, and constraints.
|
||||
|
||||
**VI**: Database schema được định nghĩa trong `prisma/schema.prisma` với models, relations, indexes, và constraints.
|
||||
|
||||
### 3. Type Safety / An Toàn Kiểu
|
||||
|
||||
**EN**: Prisma generates TypeScript types from schema, ensuring type-safe database operations.
|
||||
|
||||
**VI**: Prisma generate TypeScript types từ schema, đảm bảo các thao tác database type-safe.
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Prisma Schema Pattern / Pattern Schema Prisma
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```prisma
|
||||
// services/iam-service/prisma/schema.prisma
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// EN: User model - Core user entity
|
||||
// VI: Model User - Entity người dùng cốt lõi
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
username String? @unique
|
||||
passwordHash String? // Nullable for social-only users
|
||||
isActive Boolean @default(true)
|
||||
emailVerified Boolean @default(false)
|
||||
mfaEnabled Boolean @default(false)
|
||||
mfaSecret String?
|
||||
lastLoginAt DateTime?
|
||||
loginCount Int @default(0)
|
||||
organizationId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
userRoles UserRole[]
|
||||
userPermissions UserPermission[]
|
||||
sessions Session[]
|
||||
organization Organization? @relation(fields: [organizationId], references: [id])
|
||||
profile UserProfile?
|
||||
|
||||
@@index([email])
|
||||
@@index([username])
|
||||
@@index([createdAt])
|
||||
@@index([organizationId])
|
||||
@@map("users")
|
||||
}
|
||||
```
|
||||
|
||||
### Database Connection Pattern / Pattern Kết Nối Database
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/config/database.config.ts
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
/**
|
||||
* EN: Prisma client instance configured for the application
|
||||
* VI: Instance Prisma client được cấu hình cho ứng dụng
|
||||
*/
|
||||
export const prisma = new PrismaClient({
|
||||
// EN: Enable detailed logging in development, minimal in production
|
||||
// VI: Bật ghi log chi tiết trong development, tối thiểu trong production
|
||||
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
|
||||
});
|
||||
|
||||
/**
|
||||
* EN: Establish database connection on application startup
|
||||
* VI: Thiết lập kết nối database khi khởi động ứng dụng
|
||||
*/
|
||||
export const connectDatabase = async (): Promise<void> => {
|
||||
try {
|
||||
await prisma.$connect();
|
||||
logger.info('Database connected successfully / Kết nối database thành công');
|
||||
} catch (error) {
|
||||
logger.error('Database connection failed / Kết nối database thất bại', { error });
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* EN: Close database connection on application shutdown
|
||||
* VI: Đóng kết nối database khi tắt ứng dụng
|
||||
*/
|
||||
export const disconnectDatabase = async (): Promise<void> => {
|
||||
await prisma.$disconnect();
|
||||
logger.info('Database disconnected / Đã ngắt kết nối database');
|
||||
};
|
||||
```
|
||||
|
||||
### Base Repository Pattern / Pattern Base Repository
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/common/repository.ts
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { logger } from '@goodgo/logger';
|
||||
import { DatabaseError } from '../../errors/http-error';
|
||||
|
||||
/**
|
||||
* EN: Base repository class providing common database operations
|
||||
* VI: Base repository class cung cấp các thao tác database chung
|
||||
*/
|
||||
export abstract class BaseRepository<T, CreateInput, UpdateInput> {
|
||||
protected prisma: PrismaClient;
|
||||
protected modelName: string;
|
||||
|
||||
constructor(prisma: PrismaClient, modelName: string) {
|
||||
this.prisma = prisma;
|
||||
this.modelName = modelName;
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find entity by ID
|
||||
* VI: Tìm entity theo ID
|
||||
*/
|
||||
async findById(id: string): Promise<T | null> {
|
||||
try {
|
||||
logger.debug(`Finding ${this.modelName} by ID / Tìm ${this.modelName} theo ID`, { id });
|
||||
|
||||
const entity = await (this.prisma as any)[this.modelName].findUnique({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
logger.debug(`${this.modelName} ${entity ? 'found' : 'not found'} / ${this.modelName} ${entity ? 'đã tìm thấy' : 'không tìm thấy'}`, { id });
|
||||
return entity;
|
||||
} catch (error: any) {
|
||||
logger.error(`Failed to find ${this.modelName} by ID / Không thể tìm ${this.modelName} theo ID`, { error, id });
|
||||
throw new DatabaseError(`Failed to find ${this.modelName}`, { id, originalError: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find all entities with optional filtering
|
||||
* VI: Tìm tất cả entities với filtering tùy chọn
|
||||
*/
|
||||
async findAll(options?: {
|
||||
where?: any;
|
||||
orderBy?: any;
|
||||
skip?: number;
|
||||
take?: number;
|
||||
include?: any;
|
||||
}): Promise<T[]> {
|
||||
try {
|
||||
logger.debug(`Finding all ${this.modelName} / Tìm tất cả ${this.modelName}`, options);
|
||||
|
||||
const entities = await (this.prisma as any)[this.modelName].findMany(options || {});
|
||||
|
||||
logger.debug(`Found ${entities.length} ${this.modelName} entities / Đã tìm thấy ${entities.length} ${this.modelName} entities`);
|
||||
return entities;
|
||||
} catch (error: any) {
|
||||
logger.error(`Failed to find all ${this.modelName} / Không thể tìm tất cả ${this.modelName}`, { error, options });
|
||||
throw new DatabaseError(`Failed to find ${this.modelName} entities`, { options, originalError: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Create new entity
|
||||
* VI: Tạo entity mới
|
||||
*/
|
||||
async create(data: CreateInput): Promise<T> {
|
||||
try {
|
||||
logger.debug(`Creating new ${this.modelName} / Tạo ${this.modelName} mới`, { data });
|
||||
|
||||
const entity = await (this.prisma as any)[this.modelName].create({
|
||||
data,
|
||||
});
|
||||
|
||||
logger.debug(`${this.modelName} created successfully / ${this.modelName} đã được tạo thành công`, { id: (entity as any).id });
|
||||
return entity;
|
||||
} catch (error: any) {
|
||||
logger.error(`Failed to create ${this.modelName} / Không thể tạo ${this.modelName}`, { error, data });
|
||||
throw new DatabaseError(`Failed to create ${this.modelName}`, { data, originalError: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Update entity by ID
|
||||
* VI: Cập nhật entity theo ID
|
||||
*/
|
||||
async update(id: string, data: UpdateInput): Promise<T> {
|
||||
try {
|
||||
logger.debug(`Updating ${this.modelName} / Cập nhật ${this.modelName}`, { id, data });
|
||||
|
||||
const entity = await (this.prisma as any)[this.modelName].update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
|
||||
logger.debug(`${this.modelName} updated successfully / ${this.modelName} đã được cập nhật thành công`, { id });
|
||||
return entity;
|
||||
} catch (error: any) {
|
||||
if (error.code === 'P2025') {
|
||||
logger.warn(`${this.modelName} not found for update / ${this.modelName} không tìm thấy để cập nhật`, { id });
|
||||
throw new DatabaseError(`${this.modelName} not found`, { id });
|
||||
}
|
||||
logger.error(`Failed to update ${this.modelName} / Không thể cập nhật ${this.modelName}`, { error, id, data });
|
||||
throw new DatabaseError(`Failed to update ${this.modelName}`, { id, data, originalError: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Execute transaction with multiple operations
|
||||
* VI: Thực thi transaction với nhiều operations
|
||||
*/
|
||||
async transaction<R>(callback: (tx: any) => Promise<R>): Promise<R> {
|
||||
try {
|
||||
logger.debug(`Starting ${this.modelName} transaction / Bắt đầu transaction ${this.modelName}`);
|
||||
|
||||
const result = await this.prisma.$transaction(async (tx) => {
|
||||
return await callback(tx);
|
||||
});
|
||||
|
||||
logger.debug(`${this.modelName} transaction completed successfully / Transaction ${this.modelName} đã hoàn thành thành công`);
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
logger.error(`${this.modelName} transaction failed / Transaction ${this.modelName} thất bại`, { error });
|
||||
throw new DatabaseError(`${this.modelName} transaction failed`, { originalError: error });
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Specific Repository Implementation / Triển Khai Repository Cụ Thể
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/repositories/user.repository.ts
|
||||
import { PrismaClient, User } from '@prisma/client';
|
||||
import { BaseRepository } from '../modules/common/repository';
|
||||
|
||||
/**
|
||||
* EN: User repository for database operations
|
||||
* VI: Repository người dùng cho các thao tác database
|
||||
*/
|
||||
export class UserRepository extends BaseRepository<User, any, any> {
|
||||
constructor(prisma: PrismaClient) {
|
||||
super(prisma, 'user');
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find user by email
|
||||
* VI: Tìm người dùng theo email
|
||||
*/
|
||||
async findByEmail(email: string): Promise<User | null> {
|
||||
return this.prisma.user.findUnique({
|
||||
where: { email },
|
||||
include: {
|
||||
userRoles: {
|
||||
include: { role: true },
|
||||
},
|
||||
userPermissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find user by username
|
||||
* VI: Tìm người dùng theo username
|
||||
*/
|
||||
async findByUsername(username: string): Promise<User | null> {
|
||||
return this.prisma.user.findUnique({
|
||||
where: { username },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find user with roles and permissions
|
||||
* VI: Tìm người dùng với roles và permissions
|
||||
*/
|
||||
async findWithPermissions(userId: string): Promise<User | null> {
|
||||
return this.prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
include: {
|
||||
userRoles: {
|
||||
where: {
|
||||
OR: [
|
||||
{ expiresAt: null },
|
||||
{ expiresAt: { gte: new Date() } },
|
||||
],
|
||||
},
|
||||
include: {
|
||||
role: {
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
userPermissions: {
|
||||
where: {
|
||||
OR: [
|
||||
{ expiresAt: null },
|
||||
{ expiresAt: { gte: new Date() } },
|
||||
],
|
||||
},
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Upsert Pattern / Pattern Upsert
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/repositories/user-profile.repository.ts
|
||||
export class UserProfileRepository extends BaseRepository<UserProfile, any, any> {
|
||||
/**
|
||||
* EN: Create or update profile for user
|
||||
* VI: Tạo hoặc cập nhật profile cho user
|
||||
*/
|
||||
async upsert(userId: string, data: any): Promise<UserProfile> {
|
||||
return this.prisma.userProfile.upsert({
|
||||
where: { userId },
|
||||
update: {
|
||||
...data,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
create: {
|
||||
userId,
|
||||
...data,
|
||||
},
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
username: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Query Optimization Patterns / Pattern Tối Ưu Query
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/feature/feature.repository.ts
|
||||
export class FeatureRepository extends BaseRepository<Feature, CreateFeatureInput, UpdateFeatureInput> {
|
||||
/**
|
||||
* EN: Find features by tags
|
||||
* VI: Tìm features theo tags
|
||||
*/
|
||||
async findByTags(tags: string[]): Promise<Feature[]> {
|
||||
try {
|
||||
logger.debug('Finding features by tags / Tìm features theo tags', { tags });
|
||||
|
||||
const features = await this.prisma.feature.findMany({
|
||||
where: {
|
||||
tags: {
|
||||
hasSome: tags,
|
||||
},
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
logger.debug(`Found ${features.length} features by tags / Đã tìm thấy ${features.length} features theo tags`, { tags });
|
||||
return features;
|
||||
} catch (error) {
|
||||
logger.error('Failed to find features by tags / Không thể tìm features theo tags', { error, tags });
|
||||
throw this.handleDatabaseError(error, { tags });
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### 1. Schema Design / Thiết Kế Schema
|
||||
|
||||
- ✅ Use appropriate field types (String, Int, Boolean, DateTime, Json)
|
||||
- ✅ Add indexes for frequently queried fields (`@@index([email])`)
|
||||
- ✅ Use relations instead of storing JSON when possible
|
||||
- ✅ Implement soft deletes with `deletedAt` field when needed
|
||||
- ✅ Use `@default()` for default values
|
||||
- ✅ Use `@updatedAt` for automatic timestamp updates
|
||||
|
||||
### 2. Repository Pattern / Pattern Repository
|
||||
|
||||
- ✅ Extend `BaseRepository` for common CRUD operations
|
||||
- ✅ Add custom methods for domain-specific queries
|
||||
- ✅ Use `include` and `select` to control data fetching
|
||||
- ✅ Handle Prisma errors and convert to domain errors
|
||||
- ✅ Log database operations for debugging
|
||||
|
||||
### 3. Query Optimization / Tối Ưu Query
|
||||
|
||||
- ✅ Use `select` to fetch only needed fields
|
||||
- ✅ Implement pagination with `skip` and `take`
|
||||
- ✅ Use indexes for frequently queried fields
|
||||
- ✅ Avoid N+1 queries by using `include` strategically
|
||||
- ✅ Use `findUnique` instead of `findFirst` when possible
|
||||
- ✅ Use transactions for multiple related operations
|
||||
|
||||
### 4. Error Handling / Xử Lý Lỗi
|
||||
|
||||
- ✅ Catch Prisma errors and convert to domain errors
|
||||
- ✅ Handle unique constraint violations (P2002)
|
||||
- ✅ Handle record not found (P2025)
|
||||
- ✅ Log errors with context
|
||||
- ✅ Provide meaningful error messages
|
||||
|
||||
### 5. Migrations / Migrations
|
||||
|
||||
- ✅ Keep migrations small and focused
|
||||
- ✅ Test migrations before production
|
||||
- ✅ Backup before major changes
|
||||
- ✅ Use descriptive migration names
|
||||
- ✅ Review generated SQL before applying
|
||||
|
||||
### 6. Connection Management / Quản Lý Kết Nối
|
||||
|
||||
- ✅ Use connection pooling for production
|
||||
- ✅ Close connections on application shutdown
|
||||
- ✅ Handle connection errors gracefully
|
||||
- ✅ Monitor connection pool usage
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Schema Examples / Ví Dụ Schema
|
||||
|
||||
- **IAM Service Schema**: [`services/iam-service/prisma/schema.prisma`](../../../services/iam-service/prisma/schema.prisma)
|
||||
- **Auth Service Schema**: [`services/iam-service/prisma/schema.prisma`](../../../services/iam-service/prisma/schema.prisma)
|
||||
|
||||
### Repository Examples / Ví Dụ Repository
|
||||
|
||||
- **Base Repository**: [`services/iam-service/src/modules/common/repository.ts`](../../../services/iam-service/src/modules/common/repository.ts)
|
||||
- **User Repository**: [`services/iam-service/src/repositories/user.repository.ts`](../../../services/iam-service/src/repositories/user.repository.ts)
|
||||
- **User Profile Repository**: [`services/iam-service/src/repositories/user-profile.repository.ts`](../../../services/iam-service/src/repositories/user-profile.repository.ts)
|
||||
- **Feature Repository**: [`services/iam-service/src/modules/feature/feature.repository.ts`](../../../services/iam-service/src/modules/feature/feature.repository.ts)
|
||||
|
||||
### Database Config Examples / Ví Dụ Cấu Hình Database
|
||||
|
||||
- **Database Config**: [`services/iam-service/src/config/database.config.ts`](../../../services/iam-service/src/config/database.config.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Common Prisma Operations / Các Thao Tác Prisma Thường Dùng
|
||||
|
||||
```typescript
|
||||
// Find by ID / Tìm theo ID
|
||||
const user = await prisma.user.findUnique({ where: { id } });
|
||||
|
||||
// Find with relations / Tìm với relations
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: { profile: true, roles: true },
|
||||
});
|
||||
|
||||
// Find many with filters / Tìm nhiều với filters
|
||||
const users = await prisma.user.findMany({
|
||||
where: { isActive: true },
|
||||
skip: 0,
|
||||
take: 10,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
// Create / Tạo
|
||||
const user = await prisma.user.create({
|
||||
data: { email, passwordHash },
|
||||
});
|
||||
|
||||
// Update / Cập nhật
|
||||
const user = await prisma.user.update({
|
||||
where: { id },
|
||||
data: { isActive: false },
|
||||
});
|
||||
|
||||
// Delete / Xóa
|
||||
await prisma.user.delete({ where: { id } });
|
||||
|
||||
// Upsert / Tạo hoặc cập nhật
|
||||
const profile = await prisma.userProfile.upsert({
|
||||
where: { userId },
|
||||
update: { ...data },
|
||||
create: { userId, ...data },
|
||||
});
|
||||
|
||||
// Transaction / Transaction
|
||||
await prisma.$transaction(async (tx) => {
|
||||
const user = await tx.user.create({ data: userData });
|
||||
await tx.userProfile.create({ data: { userId: user.id, ...profileData } });
|
||||
});
|
||||
```
|
||||
|
||||
### Prisma Error Codes / Mã Lỗi Prisma
|
||||
|
||||
| Code | Description / Mô Tả |
|
||||
|------|-------------------|
|
||||
| P2002 | Unique constraint violation / Vi phạm ràng buộc duy nhất |
|
||||
| P2025 | Record not found / Không tìm thấy bản ghi |
|
||||
| P2003 | Foreign key constraint violation / Vi phạm ràng buộc khóa ngoại |
|
||||
| P2014 | Required relation violation / Vi phạm quan hệ bắt buộc |
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[API Design](./api-design.md)**: For designing API endpoints that use repositories
|
||||
- **[Testing Patterns](./testing-patterns.md)**: For testing database operations
|
||||
- **[Security](./security.md)**: For securing database operations and preventing SQL injection
|
||||
- **[Observability](./observability-monitoring.md)**: For monitoring database performance
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### External Documentation / Tài Liệu Bên Ngoài
|
||||
|
||||
- [Prisma Documentation](https://www.prisma.io/docs)
|
||||
- [Prisma Schema Reference](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference)
|
||||
- [Prisma Client API](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference)
|
||||
- [PostgreSQL Documentation](https://www.postgresql.org/docs/)
|
||||
- [Neon Documentation](https://neon.tech/docs)
|
||||
|
||||
### Internal Documentation / Tài Liệu Nội Bộ
|
||||
|
||||
- [Neon Database Guide](../guides/neon-database.md)
|
||||
- [Development Guide](../guides/development.md)
|
||||
468
docs/en/skills/deployment-kubernetes.md
Normal file
468
docs/en/skills/deployment-kubernetes.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# Kubernetes Deployment / Triển Khai Kubernetes
|
||||
|
||||
> **EN**: Kubernetes deployment patterns for GoodGo microservices. Use when deploying to staging/production, creating K8s manifests, configuring HPA, setting up ingress, or troubleshooting K8s deployments.
|
||||
> **VI**: Các pattern triển khai Kubernetes cho microservices GoodGo. Sử dụng khi triển khai lên staging/production, tạo K8s manifests, cấu hình HPA, thiết lập ingress, hoặc xử lý sự cố triển khai K8s.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: This skill covers Kubernetes deployment patterns and best practices for GoodGo microservices. It includes creating deployment manifests, configuring autoscaling, managing secrets and configmaps, setting up ingress, and implementing health checks.
|
||||
|
||||
**VI**: Skill này bao gồm các pattern triển khai Kubernetes và best practices cho microservices GoodGo. Nó bao gồm tạo deployment manifests, cấu hình autoscaling, quản lý secrets và configmaps, thiết lập ingress, và triển khai health checks.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Deploying services to staging/production environments
|
||||
- Creating or updating Kubernetes manifests
|
||||
- Configuring autoscaling (HPA/VPA)
|
||||
- Setting up ingress and load balancing
|
||||
- Managing secrets and configmaps
|
||||
- Troubleshooting deployment issues
|
||||
- Implementing health checks and probes
|
||||
- Setting up monitoring and logging
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Triển khai services lên môi trường staging/production
|
||||
- Tạo hoặc cập nhật Kubernetes manifests
|
||||
- Cấu hình autoscaling (HPA/VPA)
|
||||
- Thiết lập ingress và load balancing
|
||||
- Quản lý secrets và configmaps
|
||||
- Xử lý sự cố triển khai
|
||||
- Triển khai health checks và probes
|
||||
- Thiết lập monitoring và logging
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Deployment Strategy / Chiến Lược Triển Khai
|
||||
|
||||
**EN**:
|
||||
- Rolling updates for zero-downtime deployments
|
||||
- Resource limits and requests for stability
|
||||
- Health checks (liveness/readiness probes)
|
||||
- Horizontal Pod Autoscaler (HPA) for auto-scaling
|
||||
- ConfigMaps for configuration
|
||||
- Secrets for sensitive data
|
||||
|
||||
**VI**:
|
||||
- Rolling updates để triển khai không downtime
|
||||
- Resource limits và requests để đảm bảo ổn định
|
||||
- Health checks (liveness/readiness probes)
|
||||
- Horizontal Pod Autoscaler (HPA) để tự động scale
|
||||
- ConfigMaps cho cấu hình
|
||||
- Secrets cho dữ liệu nhạy cảm
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Service Deployment Manifest / Manifest Triển Khai Service
|
||||
|
||||
**EN**: Standard deployment manifest structure for GoodGo services.
|
||||
|
||||
**VI**: Cấu trúc deployment manifest chuẩn cho các services GoodGo.
|
||||
|
||||
**Example from codebase**: [`deployments/production/kubernetes/iam-service.yaml`](../../../deployments/production/kubernetes/iam-service.yaml)
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: iam-service
|
||||
namespace: production
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: iam-service
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: iam-service
|
||||
spec:
|
||||
containers:
|
||||
- name: iam-service
|
||||
image: goodgo/iam-service:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 5001
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: iam-service-config
|
||||
- secretRef:
|
||||
name: iam-service-secrets
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "1000m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health/live
|
||||
port: 5001
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health/ready
|
||||
port: 5001
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: iam-service
|
||||
namespace: production
|
||||
spec:
|
||||
selector:
|
||||
app: iam-service
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5001
|
||||
targetPort: 5001
|
||||
type: ClusterIP
|
||||
```
|
||||
|
||||
### Horizontal Pod Autoscaler / Tự Động Scale Pod
|
||||
|
||||
**EN**: Configure HPA to automatically scale pods based on CPU and memory utilization.
|
||||
|
||||
**VI**: Cấu hình HPA để tự động scale pods dựa trên CPU và memory utilization.
|
||||
|
||||
**Example from codebase**: [`deployments/production/kubernetes/iam-service.yaml`](../../../deployments/production/kubernetes/iam-service.yaml)
|
||||
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: iam-service-hpa
|
||||
namespace: production
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: iam-service
|
||||
minReplicas: 3
|
||||
maxReplicas: 10
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 70
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 80
|
||||
```
|
||||
|
||||
### ConfigMap & Secrets / ConfigMap và Secrets
|
||||
|
||||
**EN**: Use ConfigMaps for non-sensitive configuration and Secrets for sensitive data.
|
||||
|
||||
**VI**: Sử dụng ConfigMaps cho cấu hình không nhạy cảm và Secrets cho dữ liệu nhạy cảm.
|
||||
|
||||
**Example from codebase**:
|
||||
- ConfigMap: [`deployments/production/kubernetes/iam-service-configmap.yaml`](../../../deployments/production/kubernetes/iam-service-configmap.yaml)
|
||||
- Secrets: [`deployments/production/kubernetes/secrets.yaml.example`](../../../deployments/production/kubernetes/secrets.yaml.example)
|
||||
|
||||
```yaml
|
||||
# ConfigMap
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: iam-service-config
|
||||
namespace: production
|
||||
data:
|
||||
NODE_ENV: "production"
|
||||
PORT: "5001"
|
||||
API_VERSION: "v1"
|
||||
CORS_ORIGIN: "https://goodgo.vn"
|
||||
LOG_LEVEL: "warn"
|
||||
SERVICE_NAME: "iam-service"
|
||||
TRACING_ENABLED: "true"
|
||||
|
||||
---
|
||||
# Secret (example - use sealed-secrets in production)
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: iam-service-secrets
|
||||
namespace: production
|
||||
type: Opaque
|
||||
stringData:
|
||||
database-url: "postgresql://user:password@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true"
|
||||
jwt-secret: "your-production-jwt-secret-min-32-chars"
|
||||
jwt-refresh-secret: "your-production-refresh-secret-min-32-chars"
|
||||
redis-password: ""
|
||||
```
|
||||
|
||||
### Ingress Configuration / Cấu Hình Ingress
|
||||
|
||||
**EN**: Configure ingress for external access with TLS and path-based routing.
|
||||
|
||||
**VI**: Cấu hình ingress để truy cập từ bên ngoài với TLS và path-based routing.
|
||||
|
||||
**Example from codebase**: [`deployments/production/kubernetes/ingress.yaml`](../../../deployments/production/kubernetes/ingress.yaml)
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: api-ingress
|
||||
namespace: production
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/rule-type: PathPrefix
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- api.goodgo.vn
|
||||
secretName: api-tls-cert
|
||||
rules:
|
||||
- host: api.goodgo.vn
|
||||
http:
|
||||
paths:
|
||||
- path: /api/v1/auth
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: iam-service
|
||||
port:
|
||||
number: 5001
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Resource Management / Quản Lý Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- Always set resource requests and limits
|
||||
- Monitor actual usage and adjust accordingly
|
||||
- Use HPA for automatic scaling
|
||||
- Set appropriate CPU and memory based on service requirements
|
||||
|
||||
**VI**:
|
||||
- Luôn đặt resource requests và limits
|
||||
- Theo dõi sử dụng thực tế và điều chỉnh phù hợp
|
||||
- Sử dụng HPA để tự động scale
|
||||
- Đặt CPU và memory phù hợp dựa trên yêu cầu service
|
||||
|
||||
### Configuration / Cấu Hình
|
||||
|
||||
**EN**:
|
||||
- Use ConfigMaps for non-sensitive config
|
||||
- Use Secrets for sensitive data
|
||||
- Never hardcode configuration in images
|
||||
- Use `envFrom` to load entire ConfigMap/Secret
|
||||
|
||||
**VI**:
|
||||
- Sử dụng ConfigMaps cho cấu hình không nhạy cảm
|
||||
- Sử dụng Secrets cho dữ liệu nhạy cảm
|
||||
- Không bao giờ hardcode cấu hình trong images
|
||||
- Sử dụng `envFrom` để load toàn bộ ConfigMap/Secret
|
||||
|
||||
### Health Checks / Kiểm Tra Sức Khỏe
|
||||
|
||||
**EN**:
|
||||
- Implement both liveness and readiness probes
|
||||
- Set appropriate timeouts and thresholds
|
||||
- Include dependency checks in readiness probe
|
||||
- Use HTTP probes for web services
|
||||
|
||||
**VI**:
|
||||
- Triển khai cả liveness và readiness probes
|
||||
- Đặt timeouts và thresholds phù hợp
|
||||
- Bao gồm kiểm tra dependencies trong readiness probe
|
||||
- Sử dụng HTTP probes cho web services
|
||||
|
||||
**Example from codebase**: [`services/iam-service/src/modules/health/health.controller.ts`](../../../services/iam-service/src/modules/health/health.controller.ts)
|
||||
|
||||
```typescript
|
||||
// Liveness probe - is the service alive?
|
||||
health = async (_req: Request, res: Response): Promise<void> => {
|
||||
res.json({
|
||||
success: true,
|
||||
data: { status: 'ok', timestamp: new Date().toISOString() },
|
||||
});
|
||||
};
|
||||
|
||||
// Readiness probe - is the service ready to accept traffic?
|
||||
ready = async (_req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
// Check database connection
|
||||
await prisma.$queryRaw`SELECT 1`;
|
||||
res.json({
|
||||
success: true,
|
||||
data: { status: 'ready' },
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(503).json({
|
||||
success: false,
|
||||
error: { code: 'HEALTH_001', message: 'Service not ready' },
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Deployment / Triển Khai
|
||||
|
||||
**EN**:
|
||||
- Use rolling updates for zero-downtime
|
||||
- Set maxSurge and maxUnavailable appropriately
|
||||
- Test deployments in staging first
|
||||
- Use image tags instead of `latest` in production
|
||||
|
||||
**VI**:
|
||||
- Sử dụng rolling updates để không downtime
|
||||
- Đặt maxSurge và maxUnavailable phù hợp
|
||||
- Test triển khai trong staging trước
|
||||
- Sử dụng image tags thay vì `latest` trong production
|
||||
|
||||
### Security / Bảo Mật
|
||||
|
||||
**EN**:
|
||||
- Run containers as non-root user
|
||||
- Use network policies to restrict traffic
|
||||
- Regularly update base images
|
||||
- Use sealed-secrets or external secret manager
|
||||
- Never commit secrets to Git
|
||||
|
||||
**VI**:
|
||||
- Chạy containers với user không phải root
|
||||
- Sử dụng network policies để hạn chế traffic
|
||||
- Cập nhật base images thường xuyên
|
||||
- Sử dụng sealed-secrets hoặc external secret manager
|
||||
- Không bao giờ commit secrets vào Git
|
||||
|
||||
### Monitoring / Giám Sát
|
||||
|
||||
**EN**:
|
||||
- Expose metrics endpoint (`/metrics`)
|
||||
- Set up alerts for critical issues
|
||||
- Monitor resource usage and performance
|
||||
- Use ServiceMonitor for Prometheus integration
|
||||
|
||||
**VI**:
|
||||
- Expose metrics endpoint (`/metrics`)
|
||||
- Thiết lập alerts cho các vấn đề quan trọng
|
||||
- Theo dõi sử dụng tài nguyên và hiệu suất
|
||||
- Sử dụng ServiceMonitor cho tích hợp Prometheus
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Production Deployment / Triển Khai Production
|
||||
|
||||
- **IAM Service**: [`deployments/production/kubernetes/iam-service.yaml`](../../../deployments/production/kubernetes/iam-service.yaml)
|
||||
- **ConfigMap**: [`deployments/production/kubernetes/iam-service-configmap.yaml`](../../../deployments/production/kubernetes/iam-service-configmap.yaml)
|
||||
- **Ingress**: [`deployments/production/kubernetes/ingress.yaml`](../../../deployments/production/kubernetes/ingress.yaml)
|
||||
|
||||
### Staging Deployment / Triển Khai Staging
|
||||
|
||||
- **IAM Service**: [`deployments/staging/kubernetes/iam-service.yaml`](../../../deployments/staging/kubernetes/iam-service.yaml)
|
||||
- **ConfigMap**: [`deployments/staging/kubernetes/iam-service-configmap.yaml`](../../../deployments/staging/kubernetes/iam-service-configmap.yaml)
|
||||
|
||||
### Health Check Implementation / Triển Khai Health Check
|
||||
|
||||
- **Health Controller**: [`services/iam-service/src/modules/health/health.controller.ts`](../../../services/iam-service/src/modules/health/health.controller.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Common Commands / Lệnh Thường Dùng
|
||||
|
||||
```bash
|
||||
# Deploy to production
|
||||
kubectl apply -f deployments/production/kubernetes/ -n production
|
||||
|
||||
# Check deployment status
|
||||
kubectl get deployments -n production
|
||||
kubectl get pods -n production
|
||||
kubectl get svc -n production
|
||||
|
||||
# View logs
|
||||
kubectl logs -f deployment/iam-service -n production
|
||||
kubectl logs -f pod-name -n production --tail=100
|
||||
|
||||
# Scale manually
|
||||
kubectl scale deployment iam-service --replicas=5 -n production
|
||||
|
||||
# Update image
|
||||
kubectl set image deployment/iam-service iam-service=goodgo/iam-service:v1.2.3 -n production
|
||||
|
||||
# Rollback
|
||||
kubectl rollout undo deployment/iam-service -n production
|
||||
|
||||
# Port forward for debugging
|
||||
kubectl port-forward service/iam-service 5001:5001 -n production
|
||||
|
||||
# Execute command in pod
|
||||
kubectl exec -it pod-name -n production -- /bin/sh
|
||||
|
||||
# View HPA status
|
||||
kubectl get hpa -n production
|
||||
kubectl describe hpa iam-service-hpa -n production
|
||||
|
||||
# View resource usage
|
||||
kubectl top nodes
|
||||
kubectl top pods -n production
|
||||
```
|
||||
|
||||
### Troubleshooting / Xử Lý Sự Cố
|
||||
|
||||
**Pod Not Starting / Pod Không Khởi Động**:
|
||||
```bash
|
||||
# Check pod status
|
||||
kubectl describe pod pod-name -n production
|
||||
|
||||
# Check events
|
||||
kubectl get events -n production --sort-by='.lastTimestamp'
|
||||
|
||||
# Check logs
|
||||
kubectl logs pod-name -n production --previous
|
||||
```
|
||||
|
||||
**ImagePullBackOff**:
|
||||
```bash
|
||||
# Check image name and tag
|
||||
kubectl describe pod pod-name -n production | grep -i image
|
||||
|
||||
# Check image pull secrets
|
||||
kubectl get secrets -n production
|
||||
```
|
||||
|
||||
**CrashLoopBackOff**:
|
||||
```bash
|
||||
# Check logs of crashed container
|
||||
kubectl logs pod-name -n production --previous
|
||||
|
||||
# Check resource limits
|
||||
kubectl describe pod pod-name -n production | grep -A 5 Limits
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- [Observability & Monitoring](./observability-monitoring.md) - For monitoring deployed services
|
||||
- [Security](./security.md) - For securing Kubernetes deployments
|
||||
- [Project Rules](./project-rules.md) - For service structure and standards
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### Official Documentation / Tài Liệu Chính Thức
|
||||
|
||||
- [Kubernetes Documentation](https://kubernetes.io/docs/)
|
||||
- [Kubernetes API Reference](https://kubernetes.io/docs/reference/kubernetes-api/)
|
||||
- [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)
|
||||
|
||||
### GoodGo Resources / Tài Nguyên GoodGo
|
||||
|
||||
- [Deployment Guide](../guides/deployment.md)
|
||||
- [Local Deployment Guide](../guides/local-deployment.md)
|
||||
- [Troubleshooting Guide](../guides/troubleshooting.md)
|
||||
535
docs/en/skills/documentation.md
Normal file
535
docs/en/skills/documentation.md
Normal file
@@ -0,0 +1,535 @@
|
||||
# Documentation / Tài Liệu
|
||||
|
||||
> **EN**: Guidelines for writing technical documentation in the GoodGo project. Use when creating or updating README files, guides, architecture docs, or API documentation. Ensures bilingual (EN/VI) consistency and proper structure.
|
||||
> **VI**: Hướng dẫn viết tài liệu kỹ thuật trong dự án GoodGo. Sử dụng khi tạo hoặc cập nhật file README, hướng dẫn, tài liệu kiến trúc hoặc tài liệu API. Đảm bảo tính nhất quán song ngữ (EN/VI) và cấu trúc phù hợp.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: The Documentation skill provides comprehensive guidelines for writing, structuring, and maintaining technical documentation in the GoodGo Microservices Platform. It covers documentation structure, bilingual formatting, templates, writing style, and best practices for maintaining documentation quality.
|
||||
|
||||
**VI**: Skill Documentation cung cấp hướng dẫn toàn diện để viết, cấu trúc và duy trì tài liệu kỹ thuật trong GoodGo Microservices Platform. Nó bao gồm cấu trúc tài liệu, định dạng song ngữ, template, phong cách viết và thực hành tốt nhất để duy trì chất lượng tài liệu.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Creating new documentation files
|
||||
- Updating existing documentation
|
||||
- Writing README files for services or packages
|
||||
- Creating guides or tutorials
|
||||
- Documenting API endpoints
|
||||
- Writing architecture documentation
|
||||
- Creating deployment documentation
|
||||
- Writing runbooks or operational guides
|
||||
- Ensuring bilingual consistency
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Tạo file tài liệu mới
|
||||
- Cập nhật tài liệu hiện có
|
||||
- Viết file README cho services hoặc packages
|
||||
- Tạo hướng dẫn hoặc tutorial
|
||||
- Tài liệu hóa API endpoints
|
||||
- Viết tài liệu kiến trúc
|
||||
- Tạo tài liệu triển khai
|
||||
- Viết runbook hoặc hướng dẫn vận hành
|
||||
- Đảm bảo tính nhất quán song ngữ
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Documentation Structure / Cấu Trúc Tài Liệu
|
||||
|
||||
**EN**: The project follows a structured documentation hierarchy:
|
||||
|
||||
```
|
||||
docs/
|
||||
├── en/ # English documentation
|
||||
│ ├── guides/ # How-to guides
|
||||
│ ├── architecture/ # System design docs
|
||||
│ ├── api/ # API documentation
|
||||
│ ├── onboarding/ # New developer guides
|
||||
│ ├── runbooks/ # Operational guides
|
||||
│ └── skills/ # Skill documentation
|
||||
├── vi/ # Vietnamese documentation (mirror structure)
|
||||
└── README.md # Documentation index
|
||||
```
|
||||
|
||||
**VI**: Dự án tuân theo hệ thống phân cấp tài liệu có cấu trúc:
|
||||
|
||||
```
|
||||
docs/
|
||||
├── en/ # Tài liệu tiếng Anh
|
||||
│ ├── guides/ # Hướng dẫn cách làm
|
||||
│ ├── architecture/ # Tài liệu thiết kế hệ thống
|
||||
│ ├── api/ # Tài liệu API
|
||||
│ ├── onboarding/ # Hướng dẫn cho developer mới
|
||||
│ ├── runbooks/ # Hướng dẫn vận hành
|
||||
│ └── skills/ # Tài liệu skills
|
||||
├── vi/ # Tài liệu tiếng Việt (cấu trúc tương tự)
|
||||
└── README.md # Mục lục tài liệu
|
||||
```
|
||||
|
||||
### Bilingual Documentation Rules / Quy Tắc Tài Liệu Song Ngữ
|
||||
|
||||
**EN**: The project maintains bilingual documentation (English and Vietnamese). Three formats are used:
|
||||
|
||||
1. **Side-by-side**: Short content with EN and VI on the same line
|
||||
2. **Separate files**: Long content in separate EN and VI files
|
||||
3. **Sections**: Mixed content with separate EN and VI sections
|
||||
|
||||
**VI**: Dự án duy trì tài liệu song ngữ (Tiếng Anh và Tiếng Việt). Ba định dạng được sử dụng:
|
||||
|
||||
1. **Side-by-side**: Nội dung ngắn với EN và VI trên cùng một dòng
|
||||
2. **Separate files**: Nội dung dài trong các file EN và VI riêng biệt
|
||||
3. **Sections**: Nội dung hỗn hợp với các phần EN và VI riêng biệt
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Service README Template / Template README Service
|
||||
|
||||
**EN**: Example structure from `services/iam-service/README.md`:
|
||||
|
||||
```markdown
|
||||
# Service Name / Tên Dịch Vụ
|
||||
|
||||
> **EN**: Brief description in English
|
||||
> **VI**: Mô tả ngắn gọn bằng tiếng Việt
|
||||
|
||||
## Features / Tính Năng
|
||||
|
||||
- Feature 1 / Tính năng 1
|
||||
- Feature 2 / Tính năng 2
|
||||
|
||||
## Prerequisites / Yêu Cầu
|
||||
|
||||
- Node.js 20+
|
||||
- PostgreSQL (Neon)
|
||||
- Redis
|
||||
|
||||
## Quick Start / Bắt Đầu Nhanh
|
||||
|
||||
```bash
|
||||
# Install dependencies / Cài đặt dependencies
|
||||
pnpm install
|
||||
|
||||
# Setup environment / Thiết lập môi trường
|
||||
cp .env.example .env
|
||||
|
||||
# Start service / Khởi động service
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Configuration / Cấu Hình
|
||||
|
||||
| Variable | Description / Mô Tả | Default | Required |
|
||||
|----------|---------------------|---------|----------|
|
||||
| PORT | Server port / Cổng server | 5000 | No |
|
||||
|
||||
## API Endpoints
|
||||
|
||||
See [API Documentation](../api/openapi/iam-service.yaml)
|
||||
```
|
||||
|
||||
**VI**: Ví dụ cấu trúc từ `services/iam-service/README.md`:
|
||||
|
||||
```markdown
|
||||
# Service Name / Tên Dịch Vụ
|
||||
|
||||
> **EN**: Brief description in English
|
||||
> **VI**: Mô tả ngắn gọn bằng tiếng Việt
|
||||
|
||||
## Features / Tính Năng
|
||||
|
||||
- Feature 1 / Tính năng 1
|
||||
- Feature 2 / Tính năng 2
|
||||
|
||||
## Prerequisites / Yêu Cầu
|
||||
|
||||
- Node.js 20+
|
||||
- PostgreSQL (Neon)
|
||||
- Redis
|
||||
|
||||
## Quick Start / Bắt Đầu Nhanh
|
||||
|
||||
```bash
|
||||
# Install dependencies / Cài đặt dependencies
|
||||
pnpm install
|
||||
|
||||
# Setup environment / Thiết lập môi trường
|
||||
cp .env.example .env
|
||||
|
||||
# Start service / Khởi động service
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Configuration / Cấu Hình
|
||||
|
||||
| Variable | Description / Mô Tả | Default | Required |
|
||||
|----------|---------------------|---------|----------|
|
||||
| PORT | Server port / Cổng server | 5000 | No |
|
||||
|
||||
## API Endpoints
|
||||
|
||||
See [API Documentation](../api/openapi/iam-service.yaml)
|
||||
```
|
||||
|
||||
### Guide Template / Template Hướng Dẫn
|
||||
|
||||
**EN**: Example from `docs/en/guides/getting-started.md`:
|
||||
|
||||
```markdown
|
||||
# Getting Started
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js >= 20.0.0
|
||||
- PNPM >= 8.0.0
|
||||
- Docker & Docker Compose
|
||||
- Git
|
||||
- Neon account (https://neon.tech) - for database
|
||||
|
||||
## Initial Setup
|
||||
|
||||
1. **Clone the repository**
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
```
|
||||
|
||||
2. **Setup Neon Database**
|
||||
```bash
|
||||
# Run setup script
|
||||
./scripts/db/setup-neon.sh
|
||||
```
|
||||
|
||||
See [Neon Setup Guide](../../../infra/databases/neon/README.md) for details.
|
||||
|
||||
3. **Initialize the project**
|
||||
```bash
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Read [Development Guide](../guides/development.md)
|
||||
- Check [API Documentation](../api/openapi/)
|
||||
- Review [Architecture Overview](../architecture/system-design.md)
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `docs/vi/guides/getting-started.md`:
|
||||
|
||||
```markdown
|
||||
# Bắt Đầu
|
||||
|
||||
## Yêu Cầu
|
||||
|
||||
- Node.js >= 20.0.0
|
||||
- PNPM >= 8.0.0
|
||||
- Docker & Docker Compose
|
||||
- Git
|
||||
- Tài khoản Neon (https://neon.tech) - cho database
|
||||
|
||||
## Thiết Lập Ban Đầu
|
||||
|
||||
1. **Clone repository**
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
```
|
||||
|
||||
2. **Thiết lập Neon Database**
|
||||
```bash
|
||||
# Chạy script setup
|
||||
./scripts/db/setup-neon.sh
|
||||
```
|
||||
|
||||
Xem [Hướng Dẫn Thiết Lập Neon](../../../infra/databases/neon/README.md) để biết chi tiết.
|
||||
|
||||
3. **Khởi tạo dự án**
|
||||
```bash
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
|
||||
## Bước Tiếp Theo
|
||||
|
||||
- Đọc [Hướng Dẫn Phát Triển](../guides/development.md)
|
||||
- Xem [Tài Liệu API](../api/openapi/)
|
||||
- Xem lại [Tổng Quan Kiến Trúc](../architecture/system-design.md)
|
||||
```
|
||||
|
||||
### Architecture Document Template / Template Tài Liệu Kiến Trúc
|
||||
|
||||
**EN**: Example from `docs/en/architecture/system-design.md`:
|
||||
|
||||
```markdown
|
||||
# System Design
|
||||
|
||||
## Overview
|
||||
|
||||
GoodGo Microservices Platform is built using a microservices architecture pattern with the following principles:
|
||||
|
||||
- **Service Independence**: Each service has its own database and can be deployed independently
|
||||
- **API Gateway**: Traefik handles routing, load balancing, and cross-cutting concerns
|
||||
- **Shared Libraries**: Common functionality is extracted into shared packages
|
||||
- **Infrastructure as Code**: All infrastructure configurations are versioned
|
||||
- **Observability**: Full monitoring, logging, and tracing capabilities
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Web App │ │ Mobile App │
|
||||
│ (Next.js) │ │ (React Native)
|
||||
└──────┬──────┘ └──────┬──────┘
|
||||
│ │
|
||||
└──────────┬────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ Traefik │
|
||||
│ (API Gateway) │
|
||||
└────────┬─────────┘
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### Frontend Layer
|
||||
- **Web App**: Next.js application with App Router
|
||||
- **Mobile App**: React Native application
|
||||
|
||||
### API Gateway
|
||||
- **Traefik**: Reverse proxy, load balancer, SSL termination
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `docs/vi/architecture/system-design.md`:
|
||||
|
||||
```markdown
|
||||
# Thiết Kế Hệ Thống
|
||||
|
||||
## Tổng Quan
|
||||
|
||||
GoodGo Microservices Platform được xây dựng bằng mẫu kiến trúc microservices với các nguyên tắc sau:
|
||||
|
||||
- **Độc Lập Dịch Vụ**: Mỗi service có database riêng và có thể triển khai độc lập
|
||||
- **API Gateway**: Traefik xử lý routing, load balancing và các mối quan tâm chéo
|
||||
- **Thư Viện Dùng Chung**: Chức năng chung được trích xuất thành packages dùng chung
|
||||
- **Infrastructure as Code**: Tất cả cấu hình infrastructure được version
|
||||
- **Observability**: Khả năng giám sát, logging và tracing đầy đủ
|
||||
|
||||
## Sơ Đồ Kiến Trúc
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Web App │ │ Mobile App │
|
||||
│ (Next.js) │ │ (React Native)
|
||||
└──────┬──────┘ └──────┬──────┘
|
||||
│ │
|
||||
└──────────┬────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ Traefik │
|
||||
│ (API Gateway) │
|
||||
└────────┬─────────┘
|
||||
```
|
||||
|
||||
## Thành Phần
|
||||
|
||||
### Lớp Frontend
|
||||
- **Web App**: Ứng dụng Next.js với App Router
|
||||
- **Mobile App**: Ứng dụng React Native
|
||||
|
||||
### API Gateway
|
||||
- **Traefik**: Reverse proxy, load balancer, SSL termination
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Writing Style / Phong Cách Viết
|
||||
|
||||
**EN**:
|
||||
1. **Clear and Concise**: Use simple language, avoid jargon
|
||||
2. **Action-Oriented**: Start with verbs (Install, Configure, Deploy)
|
||||
3. **Structured**: Use headings, lists, and tables
|
||||
4. **Examples**: Provide code examples and commands
|
||||
5. **Visual**: Use diagrams where helpful
|
||||
|
||||
**VI**:
|
||||
1. **Rõ Ràng và Súc Tích**: Sử dụng ngôn ngữ đơn giản, tránh thuật ngữ
|
||||
2. **Hướng Hành Động**: Bắt đầu bằng động từ (Cài đặt, Cấu hình, Triển khai)
|
||||
3. **Có Cấu Trúc**: Sử dụng tiêu đề, danh sách và bảng
|
||||
4. **Ví Dụ**: Cung cấp ví dụ code và lệnh
|
||||
5. **Trực Quan**: Sử dụng sơ đồ khi hữu ích
|
||||
|
||||
### Code Examples / Ví Dụ Code
|
||||
|
||||
**EN**: Always provide context and explanation:
|
||||
|
||||
```markdown
|
||||
# Good: With context and explanation
|
||||
Install dependencies using pnpm:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
# Bad: No context
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
```
|
||||
|
||||
**VI**: Luôn cung cấp ngữ cảnh và giải thích:
|
||||
|
||||
```markdown
|
||||
# Tốt: Có ngữ cảnh và giải thích
|
||||
Cài đặt dependencies sử dụng pnpm:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
# Không tốt: Không có ngữ cảnh
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
```
|
||||
|
||||
### Links / Liên Kết
|
||||
|
||||
**EN**:
|
||||
- Use relative links for internal docs
|
||||
- Use descriptive link text (not "click here")
|
||||
- Example: `See the [Deployment Guide](../guides/deployment.md) for details.`
|
||||
|
||||
**VI**:
|
||||
- Sử dụng liên kết tương đối cho tài liệu nội bộ
|
||||
- Sử dụng văn bản liên kết mô tả (không phải "click here")
|
||||
- Ví dụ: `Xem [Hướng Dẫn Triển Khai](../guides/deployment.md) để biết chi tiết.`
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Good Documentation Examples / Ví Dụ Tài Liệu Tốt
|
||||
|
||||
**EN**:
|
||||
- `docs/en/guides/getting-started.md` - Clear step-by-step guide
|
||||
- `services/iam-service/README.md` - Comprehensive service README
|
||||
- `docs/en/architecture/system-design.md` - Architecture documentation
|
||||
- `docs/README.md` - Documentation index
|
||||
|
||||
**VI**:
|
||||
- `docs/vi/guides/getting-started.md` - Hướng dẫn từng bước rõ ràng
|
||||
- `services/iam-service/README.md` - README service toàn diện
|
||||
- `docs/vi/architecture/system-design.md` - Tài liệu kiến trúc
|
||||
- `docs/README.md` - Mục lục tài liệu
|
||||
|
||||
### Documentation Locations Reference / Tham Chiếu Vị Trí Tài Liệu
|
||||
|
||||
**EN**:
|
||||
|
||||
| Content Type | Location | Format |
|
||||
|--------------|----------|--------|
|
||||
| Getting Started | `docs/en/guides/getting-started.md` | Separate files |
|
||||
| Service Setup | `services/[name]/README.md` | Side-by-side |
|
||||
| Deployment | `docs/en/guides/deployment.md` | Separate files |
|
||||
| Architecture | `docs/en/architecture/` | Separate files |
|
||||
| API Specs | `docs/en/api/openapi/` | OpenAPI YAML |
|
||||
| Runbooks | `docs/en/runbooks/` | Separate files |
|
||||
| Infrastructure | `infra/[component]/README.md` | Side-by-side |
|
||||
|
||||
**VI**:
|
||||
|
||||
| Loại Nội Dung | Vị Trí | Định Dạng |
|
||||
|--------------|--------|----------|
|
||||
| Bắt Đầu | `docs/vi/guides/getting-started.md` | File riêng biệt |
|
||||
| Thiết Lập Service | `services/[name]/README.md` | Side-by-side |
|
||||
| Triển Khai | `docs/vi/guides/deployment.md` | File riêng biệt |
|
||||
| Kiến Trúc | `docs/vi/architecture/` | File riêng biệt |
|
||||
| Spec API | `docs/vi/api/openapi/` | OpenAPI YAML |
|
||||
| Runbooks | `docs/vi/runbooks/` | File riêng biệt |
|
||||
| Infrastructure | `infra/[component]/README.md` | Side-by-side |
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### File Naming / Đặt Tên File
|
||||
|
||||
**EN**:
|
||||
- Use kebab-case: `getting-started.md`
|
||||
- Be descriptive: `local-development.md` not `dev.md`
|
||||
- Match EN and VI filenames
|
||||
|
||||
**VI**:
|
||||
- Sử dụng kebab-case: `getting-started.md`
|
||||
- Mô tả rõ ràng: `local-development.md` không phải `dev.md`
|
||||
- Khớp tên file EN và VI
|
||||
|
||||
### Heading Levels / Cấp Độ Tiêu Đề
|
||||
|
||||
```markdown
|
||||
# H1: Document Title (only one per file)
|
||||
## H2: Major Sections
|
||||
### H3: Subsections
|
||||
#### H4: Details (use sparingly)
|
||||
```
|
||||
|
||||
### Bilingual Patterns / Mẫu Song Ngữ
|
||||
|
||||
```markdown
|
||||
# Pattern 1: Inline
|
||||
Description / Mô tả
|
||||
|
||||
# Pattern 2: After slash
|
||||
PORT=5000 # Server port / Cổng server
|
||||
|
||||
# Pattern 3: Table
|
||||
| Variable | Description / Mô Tả |
|
||||
|
||||
# Pattern 4: Code comments
|
||||
# EN: Install dependencies
|
||||
# VI: Cài đặt dependencies
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Documentation Checklist / Danh Sách Kiểm Tra Tài Liệu
|
||||
|
||||
**EN**: Before publishing documentation:
|
||||
- [ ] Determine correct location (docs/ vs service README)
|
||||
- [ ] Choose bilingual format (side-by-side vs separate)
|
||||
- [ ] Review existing docs for consistency
|
||||
- [ ] Use clear, concise language
|
||||
- [ ] Include code examples
|
||||
- [ ] Add diagrams where helpful
|
||||
- [ ] Provide troubleshooting section
|
||||
- [ ] Link to related documentation
|
||||
- [ ] Test all commands and code examples
|
||||
- [ ] Check all links work
|
||||
- [ ] Ensure bilingual consistency
|
||||
- [ ] Update documentation index
|
||||
|
||||
**VI**: Trước khi xuất bản tài liệu:
|
||||
- [ ] Xác định vị trí đúng (docs/ vs service README)
|
||||
- [ ] Chọn định dạng song ngữ (side-by-side vs separate)
|
||||
- [ ] Xem lại tài liệu hiện có để đảm bảo tính nhất quán
|
||||
- [ ] Sử dụng ngôn ngữ rõ ràng, súc tích
|
||||
- [ ] Bao gồm ví dụ code
|
||||
- [ ] Thêm sơ đồ khi hữu ích
|
||||
- [ ] Cung cấp phần xử lý sự cố
|
||||
- [ ] Liên kết đến tài liệu liên quan
|
||||
- [ ] Kiểm tra tất cả lệnh và ví dụ code
|
||||
- [ ] Kiểm tra tất cả liên kết hoạt động
|
||||
- [ ] Đảm bảo tính nhất quán song ngữ
|
||||
- [ ] Cập nhật mục lục tài liệu
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Project Rules](./project-rules.md)** - Project structure and standards
|
||||
- **[API Design](./api-design.md)** - API documentation patterns
|
||||
- **[Comment Code](./comment-code.md)** - Code commenting guidelines
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- [Markdown Guide](https://www.markdownguide.org/)
|
||||
- [Mermaid Diagrams](https://mermaid.js.org/)
|
||||
- [Documentation Best Practices](https://www.writethedocs.org/guide/)
|
||||
|
||||
**VI**:
|
||||
- [Hướng Dẫn Markdown](https://www.markdownguide.org/)
|
||||
- [Sơ Đồ Mermaid](https://mermaid.js.org/)
|
||||
- [Thực Hành Tốt Nhất Tài Liệu](https://www.writethedocs.org/guide/)
|
||||
565
docs/en/skills/observability-monitoring.md
Normal file
565
docs/en/skills/observability-monitoring.md
Normal file
@@ -0,0 +1,565 @@
|
||||
# Observability & Monitoring / Khả Năng Quan Sát & Giám Sát
|
||||
|
||||
> **EN**: Observability and monitoring patterns for GoodGo microservices. Use when adding metrics, implementing logging, setting up tracing, creating health checks, or debugging production issues.
|
||||
> **VI**: Các pattern observability và monitoring cho microservices GoodGo. Sử dụng khi thêm metrics, triển khai logging, thiết lập tracing, tạo health checks, hoặc debug các vấn đề production.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: This skill covers the three pillars of observability (logs, metrics, traces) and how to implement them in GoodGo microservices. It includes structured logging, Prometheus metrics, distributed tracing with OpenTelemetry, health checks, and error tracking.
|
||||
|
||||
**VI**: Skill này bao gồm ba trụ cột của observability (logs, metrics, traces) và cách triển khai chúng trong microservices GoodGo. Nó bao gồm structured logging, Prometheus metrics, distributed tracing với OpenTelemetry, health checks, và error tracking.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Setting up logging infrastructure
|
||||
- Implementing metrics collection
|
||||
- Adding distributed tracing
|
||||
- Creating health check endpoints
|
||||
- Setting up monitoring dashboards
|
||||
- Debugging production issues
|
||||
- Implementing alerting rules
|
||||
- Analyzing performance bottlenecks
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Thiết lập hạ tầng logging
|
||||
- Triển khai thu thập metrics
|
||||
- Thêm distributed tracing
|
||||
- Tạo health check endpoints
|
||||
- Thiết lập monitoring dashboards
|
||||
- Debug các vấn đề production
|
||||
- Triển khai alerting rules
|
||||
- Phân tích performance bottlenecks
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Three Pillars of Observability / Ba Trụ Cột Của Observability
|
||||
|
||||
**EN**:
|
||||
1. **Logs**: Event records for debugging and auditing
|
||||
2. **Metrics**: Numerical measurements over time (counters, gauges, histograms)
|
||||
3. **Traces**: Request flow across services (distributed tracing)
|
||||
|
||||
**VI**:
|
||||
1. **Logs**: Bản ghi sự kiện để debug và audit
|
||||
2. **Metrics**: Đo lường số học theo thời gian (counters, gauges, histograms)
|
||||
3. **Traces**: Luồng request qua các services (distributed tracing)
|
||||
|
||||
### Tech Stack / Công Nghệ
|
||||
|
||||
**EN**:
|
||||
- **Logging**: `@goodgo/logger` (Pino-based structured logging)
|
||||
- **Metrics**: Prometheus + Grafana
|
||||
- **Tracing**: OpenTelemetry + Jaeger (`@goodgo/tracing`)
|
||||
- **Correlation IDs**: Request tracking across services
|
||||
|
||||
**VI**:
|
||||
- **Logging**: `@goodgo/logger` (structured logging dựa trên Pino)
|
||||
- **Metrics**: Prometheus + Grafana
|
||||
- **Tracing**: OpenTelemetry + Jaeger (`@goodgo/tracing`)
|
||||
- **Correlation IDs**: Theo dõi request qua các services
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Structured Logging / Logging Có Cấu Trúc
|
||||
|
||||
**EN**: Use structured logging with correlation IDs for request tracking.
|
||||
|
||||
**VI**: Sử dụng structured logging với correlation IDs để theo dõi request.
|
||||
|
||||
**Example from codebase**: [`services/iam-service/src/middlewares/logger.middleware.ts`](../../../services/iam-service/src/middlewares/logger.middleware.ts)
|
||||
|
||||
```typescript
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { logger } from '@goodgo/logger';
|
||||
import { getCorrelationId, getRequestId } from './correlation.middleware';
|
||||
|
||||
export const requestLogger = (req: Request, res: Response, next: NextFunction): void => {
|
||||
// Skip detailed logging for health checks and metrics
|
||||
if (req.path.startsWith('/health') || req.path.startsWith('/metrics')) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
res.on('finish', () => {
|
||||
const duration = Date.now() - start;
|
||||
const correlationId = getCorrelationId(req);
|
||||
const requestId = getRequestId(req);
|
||||
|
||||
logger.info('Request processed / Request đã xử lý', {
|
||||
correlationId,
|
||||
requestId,
|
||||
method: req.method,
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
statusCode: res.statusCode,
|
||||
duration: `${duration}ms`,
|
||||
contentLength: res.get('Content-Length') || 0,
|
||||
userAgent: req.get('User-Agent'),
|
||||
ip: req.ip,
|
||||
userId: (req as any).user?.userId,
|
||||
});
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
```
|
||||
|
||||
### Correlation IDs / Correlation IDs
|
||||
|
||||
**EN**: Use correlation IDs to track requests across services.
|
||||
|
||||
**VI**: Sử dụng correlation IDs để theo dõi request qua các services.
|
||||
|
||||
**Example from codebase**: [`services/iam-service/src/middlewares/correlation.middleware.ts`](../../../services/iam-service/src/middlewares/correlation.middleware.ts)
|
||||
|
||||
```typescript
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
export const CORRELATION_ID_HEADER = 'x-correlation-id';
|
||||
export const REQUEST_ID_HEADER = 'x-request-id';
|
||||
|
||||
export const correlationMiddleware = (
|
||||
options: {
|
||||
headerName?: string;
|
||||
generateId?: () => string;
|
||||
skipPaths?: string[];
|
||||
} = {}
|
||||
) => {
|
||||
const {
|
||||
headerName = CORRELATION_ID_HEADER,
|
||||
generateId = randomUUID,
|
||||
skipPaths = ['/health', '/metrics', '/favicon.ico'],
|
||||
} = options;
|
||||
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
// Get correlation ID from header or generate new one
|
||||
const correlationId = req.headers[headerName.toLowerCase()] as string || generateId();
|
||||
const requestId = generateId();
|
||||
|
||||
// Attach to request object
|
||||
req.correlationId = correlationId;
|
||||
req.requestId = requestId;
|
||||
|
||||
// Add to response headers
|
||||
res.setHeader(headerName, correlationId);
|
||||
res.setHeader(REQUEST_ID_HEADER, requestId);
|
||||
|
||||
// Log request start
|
||||
logger.info('Request started / Request bắt đầu', {
|
||||
correlationId,
|
||||
requestId,
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
userAgent: req.get('User-Agent'),
|
||||
ip: req.ip,
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Metrics Collection / Thu Thập Metrics
|
||||
|
||||
**EN**: Expose Prometheus metrics for monitoring and alerting.
|
||||
|
||||
**VI**: Expose Prometheus metrics để monitoring và alerting.
|
||||
|
||||
**Example from codebase**: [`services/iam-service/src/middlewares/metrics.middleware.ts`](../../../services/iam-service/src/middlewares/metrics.middleware.ts)
|
||||
|
||||
```typescript
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import client from 'prom-client';
|
||||
import { getCorrelationId } from './correlation.middleware';
|
||||
|
||||
// Create a Registry which registers the metrics
|
||||
const register = client.register;
|
||||
|
||||
// Collect default metrics
|
||||
client.collectDefaultMetrics({ register });
|
||||
|
||||
// Create histogram for HTTP request duration
|
||||
const httpRequestDurationSeconds = new client.Histogram({
|
||||
name: 'http_request_duration_seconds',
|
||||
help: 'Duration of HTTP requests in seconds',
|
||||
labelNames: ['method', 'route', 'status_code', 'correlation_id'],
|
||||
buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5, 10],
|
||||
});
|
||||
|
||||
// Create counter for total HTTP requests
|
||||
const httpRequestsTotal = new client.Counter({
|
||||
name: 'http_requests_total',
|
||||
help: 'Total number of HTTP requests',
|
||||
labelNames: ['method', 'route', 'status_code'],
|
||||
});
|
||||
|
||||
// Create gauge for active requests
|
||||
const activeRequests = new client.Gauge({
|
||||
name: 'http_active_requests',
|
||||
help: 'Number of active HTTP requests',
|
||||
});
|
||||
|
||||
// Create counter for HTTP request errors
|
||||
const httpRequestErrors = new client.Counter({
|
||||
name: 'http_request_errors_total',
|
||||
help: 'Total number of HTTP request errors',
|
||||
labelNames: ['method', 'route', 'error_type'],
|
||||
});
|
||||
|
||||
export const metricsMiddleware = (req: Request, res: Response, next: NextFunction) => {
|
||||
// Increment active requests
|
||||
activeRequests.inc();
|
||||
|
||||
// Start timer
|
||||
const start = process.hrtime.bigint();
|
||||
|
||||
res.on('finish', () => {
|
||||
// Decrement active requests
|
||||
activeRequests.dec();
|
||||
|
||||
// Calculate duration
|
||||
const end = process.hrtime.bigint();
|
||||
const durationInSeconds = Number(end - start) / 1e9;
|
||||
|
||||
// Normalize path to avoid high cardinality
|
||||
const route = normalizeRoutePath(req);
|
||||
const correlationId = getCorrelationId(req) || 'unknown';
|
||||
|
||||
// Record duration
|
||||
httpRequestDurationSeconds
|
||||
.labels(req.method, route, res.statusCode.toString(), correlationId)
|
||||
.observe(durationInSeconds);
|
||||
|
||||
// Increment request counter
|
||||
httpRequestsTotal
|
||||
.labels(req.method, route, res.statusCode.toString())
|
||||
.inc();
|
||||
|
||||
// Track errors
|
||||
if (res.statusCode >= 400) {
|
||||
const errorType = res.statusCode >= 500 ? 'server_error' : 'client_error';
|
||||
httpRequestErrors
|
||||
.labels(req.method, route, errorType)
|
||||
.inc();
|
||||
}
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
// Normalize route path to prevent high cardinality metrics
|
||||
function normalizeRoutePath(req: Request): string {
|
||||
if (req.route && req.route.path) {
|
||||
return req.route.path;
|
||||
}
|
||||
|
||||
let path = req.path;
|
||||
// Replace UUIDs and numeric IDs with placeholders
|
||||
path = path.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ':uuid');
|
||||
path = path.replace(/\d+/g, ':id');
|
||||
|
||||
return path;
|
||||
}
|
||||
```
|
||||
|
||||
### Distributed Tracing / Distributed Tracing
|
||||
|
||||
**EN**: Use OpenTelemetry for distributed tracing across services.
|
||||
|
||||
**VI**: Sử dụng OpenTelemetry cho distributed tracing qua các services.
|
||||
|
||||
**Example from codebase**: [`packages/tracing/src/index.ts`](../../../packages/tracing/src/index.ts)
|
||||
|
||||
```typescript
|
||||
import { NodeSDK } from '@opentelemetry/sdk-node';
|
||||
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
||||
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';
|
||||
import { Resource } from '@opentelemetry/resources';
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
||||
|
||||
export interface TracingConfig {
|
||||
serviceName: string;
|
||||
jaegerEndpoint?: string;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export const initTracing = (config: TracingConfig): NodeSDK | null => {
|
||||
if (config.enabled === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create Jaeger exporter if endpoint is provided
|
||||
const jaegerExporter = config.jaegerEndpoint
|
||||
? new JaegerExporter({
|
||||
endpoint: config.jaegerEndpoint,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
// Initialize OpenTelemetry NodeSDK with auto-instrumentations
|
||||
const sdk = new NodeSDK({
|
||||
resource: new Resource({
|
||||
[SemanticResourceAttributes.SERVICE_NAME]: config.serviceName,
|
||||
}),
|
||||
traceExporter: jaegerExporter,
|
||||
instrumentations: [getNodeAutoInstrumentations()],
|
||||
});
|
||||
|
||||
// Start the tracing SDK
|
||||
sdk.start();
|
||||
|
||||
return sdk;
|
||||
};
|
||||
```
|
||||
|
||||
**Usage in service**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/main.ts
|
||||
import { initTracing } from '@goodgo/tracing';
|
||||
|
||||
// Initialize tracing
|
||||
if (process.env.TRACING_ENABLED === 'true') {
|
||||
initTracing({
|
||||
serviceName: process.env.SERVICE_NAME || 'iam-service',
|
||||
jaegerEndpoint: process.env.JAEGER_ENDPOINT,
|
||||
enabled: true,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Health Checks / Kiểm Tra Sức Khỏe
|
||||
|
||||
**EN**: Implement liveness and readiness probes for Kubernetes.
|
||||
|
||||
**VI**: Triển khai liveness và readiness probes cho Kubernetes.
|
||||
|
||||
**Example from codebase**: [`services/iam-service/src/modules/health/health.controller.ts`](../../../services/iam-service/src/modules/health/health.controller.ts)
|
||||
|
||||
```typescript
|
||||
import { Request, Response } from 'express';
|
||||
import { prisma } from '../../config/database.config';
|
||||
import { ApiResponse } from '@goodgo/types';
|
||||
|
||||
export class HealthController {
|
||||
/**
|
||||
* EN: Basic liveness probe
|
||||
* VI: Kiểm tra liveness cơ bản
|
||||
*/
|
||||
health = async (_req: Request, res: Response): Promise<void> => {
|
||||
const response: ApiResponse<{ status: string; timestamp: string }> = {
|
||||
success: true,
|
||||
data: {
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
res.json(response);
|
||||
};
|
||||
|
||||
/**
|
||||
* EN: Readiness probe (checks database connection)
|
||||
* VI: Kiểm tra readiness (kiểm tra kết nối database)
|
||||
*/
|
||||
ready = async (_req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
// Check database connection
|
||||
await prisma.$queryRaw`SELECT 1`;
|
||||
res.json({
|
||||
success: true,
|
||||
data: { status: 'ready' },
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
} catch (error) {
|
||||
// Return 503 if database is not ready
|
||||
res.status(503).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'HEALTH_001',
|
||||
message: 'Service not ready',
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* EN: Alias for health check
|
||||
* VI: Alias cho kiểm tra sức khỏe
|
||||
*/
|
||||
live = async (_req: Request, res: Response): Promise<void> => {
|
||||
res.json({
|
||||
success: true,
|
||||
data: { status: 'live' },
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Logging / Logging
|
||||
|
||||
**EN**:
|
||||
- Use structured logging (JSON format)
|
||||
- Include correlation IDs for request tracing
|
||||
- Log at appropriate levels (ERROR, WARN, INFO, DEBUG)
|
||||
- Avoid logging sensitive data (passwords, tokens, PII)
|
||||
- Use consistent log format across services
|
||||
|
||||
**VI**:
|
||||
- Sử dụng structured logging (định dạng JSON)
|
||||
- Bao gồm correlation IDs để theo dõi request
|
||||
- Log ở mức độ phù hợp (ERROR, WARN, INFO, DEBUG)
|
||||
- Tránh log dữ liệu nhạy cảm (mật khẩu, tokens, PII)
|
||||
- Sử dụng format log nhất quán giữa các services
|
||||
|
||||
### Metrics / Metrics
|
||||
|
||||
**EN**:
|
||||
- Use standard metric types (Counter, Gauge, Histogram)
|
||||
- Keep cardinality low (avoid high-cardinality labels)
|
||||
- Define SLIs and SLOs for critical paths
|
||||
- Monitor business metrics, not just technical ones
|
||||
- Normalize route paths to prevent high cardinality
|
||||
|
||||
**VI**:
|
||||
- Sử dụng các loại metric chuẩn (Counter, Gauge, Histogram)
|
||||
- Giữ cardinality thấp (tránh high-cardinality labels)
|
||||
- Định nghĩa SLIs và SLOs cho các đường dẫn quan trọng
|
||||
- Giám sát business metrics, không chỉ technical metrics
|
||||
- Chuẩn hóa route paths để tránh high cardinality
|
||||
|
||||
### Tracing / Tracing
|
||||
|
||||
**EN**:
|
||||
- Add traces for critical operations
|
||||
- Include relevant context in spans
|
||||
- Sample appropriately to control costs
|
||||
- Use distributed tracing for microservices
|
||||
- Propagate correlation IDs across service boundaries
|
||||
|
||||
**VI**:
|
||||
- Thêm traces cho các thao tác quan trọng
|
||||
- Bao gồm context liên quan trong spans
|
||||
- Sample phù hợp để kiểm soát chi phí
|
||||
- Sử dụng distributed tracing cho microservices
|
||||
- Truyền correlation IDs qua ranh giới service
|
||||
|
||||
### Alerting / Cảnh Báo
|
||||
|
||||
**EN**:
|
||||
- Alert on symptoms, not causes
|
||||
- Include runbook links in alerts
|
||||
- Avoid alert fatigue with proper thresholds
|
||||
- Test alerting rules regularly
|
||||
- Use correlation IDs in alert context
|
||||
|
||||
**VI**:
|
||||
- Cảnh báo về triệu chứng, không phải nguyên nhân
|
||||
- Bao gồm links runbook trong alerts
|
||||
- Tránh alert fatigue với thresholds phù hợp
|
||||
- Test alerting rules thường xuyên
|
||||
- Sử dụng correlation IDs trong alert context
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Logging Implementation / Triển Khai Logging
|
||||
|
||||
- **Request Logger**: [`services/iam-service/src/middlewares/logger.middleware.ts`](../../../services/iam-service/src/middlewares/logger.middleware.ts)
|
||||
- **Correlation Middleware**: [`services/iam-service/src/middlewares/correlation.middleware.ts`](../../../services/iam-service/src/middlewares/correlation.middleware.ts)
|
||||
|
||||
### Metrics Implementation / Triển Khai Metrics
|
||||
|
||||
- **Metrics Middleware**: [`services/iam-service/src/middlewares/metrics.middleware.ts`](../../../services/iam-service/src/middlewares/metrics.middleware.ts)
|
||||
- **Metrics Endpoint**: Exposed at `/metrics` in all services
|
||||
|
||||
### Tracing Implementation / Triển Khai Tracing
|
||||
|
||||
- **Tracing Package**: [`packages/tracing/src/index.ts`](../../../packages/tracing/src/index.ts)
|
||||
- **Service Integration**: [`services/iam-service/src/main.ts`](../../../services/iam-service/src/main.ts)
|
||||
|
||||
### Health Checks / Health Checks
|
||||
|
||||
- **Health Controller**: [`services/iam-service/src/modules/health/health.controller.ts`](../../../services/iam-service/src/modules/health/health.controller.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Log Levels / Mức Độ Log
|
||||
|
||||
**EN**:
|
||||
- `ERROR`: Errors that require immediate attention
|
||||
- `WARN`: Warnings that may indicate issues
|
||||
- `INFO`: Informational messages (default)
|
||||
- `DEBUG`: Detailed debugging information
|
||||
|
||||
**VI**:
|
||||
- `ERROR`: Lỗi cần chú ý ngay lập tức
|
||||
- `WARN`: Cảnh báo có thể chỉ ra vấn đề
|
||||
- `INFO`: Thông điệp thông tin (mặc định)
|
||||
- `DEBUG`: Thông tin debug chi tiết
|
||||
|
||||
### Metric Types / Loại Metrics
|
||||
|
||||
**EN**:
|
||||
- **Counter**: Monotonically increasing value (e.g., request count)
|
||||
- **Gauge**: Value that can go up or down (e.g., active connections)
|
||||
- **Histogram**: Distribution of values (e.g., request duration)
|
||||
|
||||
**VI**:
|
||||
- **Counter**: Giá trị tăng đơn điệu (ví dụ: số lượng request)
|
||||
- **Gauge**: Giá trị có thể tăng hoặc giảm (ví dụ: kết nối đang hoạt động)
|
||||
- **Histogram**: Phân phối giá trị (ví dụ: thời lượng request)
|
||||
|
||||
### Health Check Endpoints / Endpoints Health Check
|
||||
|
||||
**EN**:
|
||||
- `/health` or `/health/live`: Liveness probe (service is running)
|
||||
- `/health/ready`: Readiness probe (service is ready to accept traffic)
|
||||
|
||||
**VI**:
|
||||
- `/health` hoặc `/health/live`: Liveness probe (service đang chạy)
|
||||
- `/health/ready`: Readiness probe (service sẵn sàng nhận traffic)
|
||||
|
||||
### Prometheus Queries / Truy Vấn Prometheus
|
||||
|
||||
```promql
|
||||
# Request rate
|
||||
rate(http_requests_total[5m])
|
||||
|
||||
# Error rate
|
||||
rate(http_requests_total{status_code=~"5.."}[5m])
|
||||
|
||||
# 95th percentile latency
|
||||
histogram_quantile(0.95, http_request_duration_seconds)
|
||||
|
||||
# Active requests
|
||||
http_active_requests
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- [Kubernetes Deployment](./deployment-kubernetes.md) - For configuring health checks in K8s
|
||||
- [Security](./security.md) - For secure logging and monitoring
|
||||
- [Project Rules](./project-rules.md) - For service structure and standards
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### Official Documentation / Tài Liệu Chính Thức
|
||||
|
||||
- [OpenTelemetry Documentation](https://opentelemetry.io/docs/)
|
||||
- [Prometheus Documentation](https://prometheus.io/docs/)
|
||||
- [Jaeger Documentation](https://www.jaegertracing.io/docs/)
|
||||
|
||||
### GoodGo Resources / Tài Nguyên GoodGo
|
||||
|
||||
- [Observability Guide](../guides/observability.md)
|
||||
- [Troubleshooting Guide](../guides/troubleshooting.md)
|
||||
- [Logger Package](../../../packages/logger/README.md)
|
||||
- [Tracing Package](../../../packages/tracing/README.md)
|
||||
425
docs/en/skills/project-rules.md
Normal file
425
docs/en/skills/project-rules.md
Normal file
@@ -0,0 +1,425 @@
|
||||
# Project Rules / Quy Tắc Dự Án
|
||||
|
||||
> **EN**: GoodGo Microservices Platform coding standards and architecture patterns. Use when working with services, apps, packages, or infrastructure.
|
||||
> **VI**: Tiêu chuẩn mã hóa và mẫu kiến trúc của GoodGo Microservices Platform. Sử dụng khi làm việc với services, apps, packages, hoặc infrastructure.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: The Project Rules skill provides comprehensive guidelines for the GoodGo Microservices Platform architecture, coding standards, naming conventions, workflows, and best practices. This skill ensures consistency across all services, packages, and applications in the monorepo.
|
||||
|
||||
**VI**: Skill Project Rules cung cấp hướng dẫn toàn diện về kiến trúc GoodGo Microservices Platform, tiêu chuẩn mã hóa, quy ước đặt tên, quy trình làm việc và thực hành tốt nhất. Skill này đảm bảo tính nhất quán trên tất cả services, packages và applications trong monorepo.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Creating a new service or package
|
||||
- Setting up project structure
|
||||
- Following naming conventions
|
||||
- Understanding deployment patterns
|
||||
- Working with dependencies
|
||||
- Configuring Docker containers
|
||||
- Setting up CI/CD workflows
|
||||
- Understanding the monorepo structure
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Tạo service hoặc package mới
|
||||
- Thiết lập cấu trúc dự án
|
||||
- Tuân theo quy ước đặt tên
|
||||
- Hiểu các mẫu triển khai
|
||||
- Làm việc với dependencies
|
||||
- Cấu hình Docker containers
|
||||
- Thiết lập CI/CD workflows
|
||||
- Hiểu cấu trúc monorepo
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Architecture / Kiến Trúc
|
||||
|
||||
**EN**: The platform follows a microservices architecture with:
|
||||
- **Apps**: Next.js (web) + Flutter (mobile)
|
||||
- **Services**: Node.js/TypeScript microservices (Express)
|
||||
- **Packages**: Shared libraries (logger, types, http-client, auth-sdk, tracing)
|
||||
- **Infrastructure**: Traefik (API Gateway), Redis, Neon PostgreSQL, Observability
|
||||
- **Deployments**: Local (Docker Compose), Staging/Production (Kubernetes)
|
||||
|
||||
**VI**: Nền tảng tuân theo kiến trúc microservices với:
|
||||
- **Apps**: Next.js (web) + Flutter (mobile)
|
||||
- **Services**: Node.js/TypeScript microservices (Express)
|
||||
- **Packages**: Thư viện dùng chung (logger, types, http-client, auth-sdk, tracing)
|
||||
- **Infrastructure**: Traefik (API Gateway), Redis, Neon PostgreSQL, Observability
|
||||
- **Deployments**: Local (Docker Compose), Staging/Production (Kubernetes)
|
||||
|
||||
### Tech Stack / Công Nghệ
|
||||
|
||||
**Frontend:**
|
||||
- Next.js 14+ (App Router), TypeScript, Tailwind CSS, Zustand
|
||||
- Flutter 3.x with Provider pattern
|
||||
- Use `@goodgo/types` and `@goodgo/http-client`
|
||||
|
||||
**Backend:**
|
||||
- Node.js 20+, TypeScript 5+, Express
|
||||
- Prisma ORM + Neon PostgreSQL
|
||||
- Zod validation, `@goodgo/logger`, `@goodgo/tracing`, `@goodgo/auth-sdk`
|
||||
|
||||
**Infrastructure:**
|
||||
- Traefik (path-based routing), Redis (cache), Prometheus + Grafana + Loki
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Service Structure / Cấu Trúc Service
|
||||
|
||||
**EN**: Standard service structure:
|
||||
```
|
||||
services/[service-name]/
|
||||
├── src/
|
||||
│ ├── config/ # Configuration files
|
||||
│ ├── modules/ # Feature modules
|
||||
│ ├── middlewares/ # Express middlewares
|
||||
│ ├── repositories/ # Data access layer
|
||||
│ ├── routes/ # Route definitions
|
||||
│ └── main.ts # Entry point
|
||||
├── prisma/ # Database schema
|
||||
├── Dockerfile # Container definition
|
||||
└── package.json # Dependencies
|
||||
```
|
||||
|
||||
**VI**: Cấu trúc service chuẩn:
|
||||
```
|
||||
services/[service-name]/
|
||||
├── src/
|
||||
│ ├── config/ # File cấu hình
|
||||
│ ├── modules/ # Module tính năng
|
||||
│ ├── middlewares/ # Express middlewares
|
||||
│ ├── repositories/ # Lớp truy cập dữ liệu
|
||||
│ ├── routes/ # Định nghĩa routes
|
||||
│ └── main.ts # Điểm vào
|
||||
├── prisma/ # Database schema
|
||||
├── Dockerfile # Định nghĩa container
|
||||
└── package.json # Dependencies
|
||||
```
|
||||
|
||||
### Module Pattern / Pattern Module
|
||||
|
||||
**EN**: Controller → Service → Repository pattern:
|
||||
|
||||
```typescript
|
||||
// DTO with Zod
|
||||
export const CreateFeatureDto = z.object({
|
||||
name: z.string().min(1),
|
||||
email: z.string().email()
|
||||
});
|
||||
export type CreateFeatureDto = z.infer<typeof CreateFeatureDto>;
|
||||
|
||||
// Controller
|
||||
export class FeatureController {
|
||||
constructor(private service: FeatureService) {}
|
||||
async create(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const dto = CreateFeatureDto.parse(req.body);
|
||||
const result = await this.service.create(dto);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (error) { next(error); }
|
||||
}
|
||||
}
|
||||
|
||||
// Service
|
||||
export class FeatureService {
|
||||
constructor(private repository: FeatureRepository) {}
|
||||
async create(dto: CreateFeatureDto) {
|
||||
return this.repository.create(dto);
|
||||
}
|
||||
}
|
||||
|
||||
// Repository
|
||||
export class FeatureRepository extends BaseRepository<Feature> {
|
||||
async create(data: CreateFeatureDto) {
|
||||
return this.prisma.feature.create({ data });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Pattern Controller → Service → Repository:
|
||||
|
||||
```typescript
|
||||
// DTO với Zod
|
||||
export const CreateFeatureDto = z.object({
|
||||
name: z.string().min(1),
|
||||
email: z.string().email()
|
||||
});
|
||||
export type CreateFeatureDto = z.infer<typeof CreateFeatureDto>;
|
||||
|
||||
// Controller
|
||||
export class FeatureController {
|
||||
constructor(private service: FeatureService) {}
|
||||
async create(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const dto = CreateFeatureDto.parse(req.body);
|
||||
const result = await this.service.create(dto);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (error) { next(error); }
|
||||
}
|
||||
}
|
||||
|
||||
// Service
|
||||
export class FeatureService {
|
||||
constructor(private repository: FeatureRepository) {}
|
||||
async create(dto: CreateFeatureDto) {
|
||||
return this.repository.create(dto);
|
||||
}
|
||||
}
|
||||
|
||||
// Repository
|
||||
export class FeatureRepository extends BaseRepository<Feature> {
|
||||
async create(data: CreateFeatureDto) {
|
||||
return this.prisma.feature.create({ data });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### API Response Pattern / Pattern Phản Hồi API
|
||||
|
||||
**EN**: Standardized API responses:
|
||||
|
||||
```typescript
|
||||
// Success response
|
||||
{
|
||||
success: true,
|
||||
data: any,
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
// Error response
|
||||
{
|
||||
success: false,
|
||||
error: {
|
||||
code: string,
|
||||
message: string,
|
||||
details?: any
|
||||
},
|
||||
timestamp: string
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Phản hồi API chuẩn hóa:
|
||||
|
||||
```typescript
|
||||
// Phản hồi thành công
|
||||
{
|
||||
success: true,
|
||||
data: any,
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
// Phản hồi lỗi
|
||||
{
|
||||
success: false,
|
||||
error: {
|
||||
code: string,
|
||||
message: string,
|
||||
details?: any
|
||||
},
|
||||
timestamp: string
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Naming Conventions / Quy Ước Đặt Tên
|
||||
|
||||
**EN**:
|
||||
- **Services/Packages**: `kebab-case` (e.g., `iam-service`, `http-client`)
|
||||
- **Files**: `kebab-case.type.ts` (e.g., `user.controller.ts`)
|
||||
- **Components**: `PascalCase.tsx` (React), `snake_case.dart` (Flutter)
|
||||
- **Classes**: `PascalCase`
|
||||
- **Functions**: `camelCase`
|
||||
- **Constants**: `UPPER_SNAKE_CASE`
|
||||
- **Package Names**: `@goodgo/package-name`
|
||||
|
||||
**VI**:
|
||||
- **Services/Packages**: `kebab-case` (ví dụ: `iam-service`, `http-client`)
|
||||
- **Files**: `kebab-case.type.ts` (ví dụ: `user.controller.ts`)
|
||||
- **Components**: `PascalCase.tsx` (React), `snake_case.dart` (Flutter)
|
||||
- **Classes**: `PascalCase`
|
||||
- **Functions**: `camelCase`
|
||||
- **Constants**: `UPPER_SNAKE_CASE`
|
||||
- **Package Names**: `@goodgo/package-name`
|
||||
|
||||
### TypeScript Standards / Tiêu Chuẩn TypeScript
|
||||
|
||||
**EN**:
|
||||
- Strict mode enabled
|
||||
- No `any` type (use `unknown` instead)
|
||||
- Zod for runtime validation
|
||||
- Export shared types from `@goodgo/types`
|
||||
|
||||
**VI**:
|
||||
- Bật strict mode
|
||||
- Không dùng type `any` (dùng `unknown` thay thế)
|
||||
- Zod cho runtime validation
|
||||
- Export shared types từ `@goodgo/types`
|
||||
|
||||
### Logging / Ghi Log
|
||||
|
||||
**EN**: Use `@goodgo/logger`:
|
||||
|
||||
```typescript
|
||||
import { logger } from '@goodgo/logger';
|
||||
logger.info('Message', { context });
|
||||
logger.error('Error', { error, context });
|
||||
```
|
||||
|
||||
**VI**: Sử dụng `@goodgo/logger`:
|
||||
|
||||
```typescript
|
||||
import { logger } from '@goodgo/logger';
|
||||
logger.info('Message', { context });
|
||||
logger.error('Error', { error, context });
|
||||
```
|
||||
|
||||
### Environment Variables / Biến Môi Trường
|
||||
|
||||
**EN**:
|
||||
- Use `.env.example` template
|
||||
- Never commit `.env` files
|
||||
- Validate with Zod at startup
|
||||
- Document all variables in README
|
||||
|
||||
**VI**:
|
||||
- Sử dụng template `.env.example`
|
||||
- Không bao giờ commit file `.env`
|
||||
- Validate với Zod khi khởi động
|
||||
- Tài liệu hóa tất cả biến trong README
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Service Template / Template Service
|
||||
|
||||
**EN**: See `services/_template/` for a complete service template with:
|
||||
- Standard structure
|
||||
- Middleware setup
|
||||
- Error handling
|
||||
- Health checks
|
||||
- Swagger documentation
|
||||
|
||||
**VI**: Xem `services/_template/` để có template service hoàn chỉnh với:
|
||||
- Cấu trúc chuẩn
|
||||
- Thiết lập middleware
|
||||
- Xử lý lỗi
|
||||
- Health checks
|
||||
- Tài liệu Swagger
|
||||
|
||||
### Traefik Configuration / Cấu Hình Traefik
|
||||
|
||||
**EN**: Services are registered in `deployments/local/docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-service:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/my-service/Dockerfile
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.my-service.rule=PathPrefix(`/api/v1/my-service`)"
|
||||
- "traefik.http.services.my-service.loadbalancer.server.port=5002"
|
||||
- "traefik.http.services.my-service.loadbalancer.healthcheck.path=/health/live"
|
||||
```
|
||||
|
||||
**VI**: Services được đăng ký trong `deployments/local/docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-service:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/my-service/Dockerfile
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.my-service.rule=PathPrefix(`/api/v1/my-service`)"
|
||||
- "traefik.http.services.my-service.loadbalancer.server.port=5002"
|
||||
- "traefik.http.services.my-service.loadbalancer.healthcheck.path=/health/live"
|
||||
```
|
||||
|
||||
### Real Service Examples / Ví Dụ Service Thực Tế
|
||||
|
||||
**EN**:
|
||||
- `services/iam-service/` - Identity and Access Management service (RBAC, OIDC, MFA, Identity, Access, Governance)
|
||||
- `packages/logger/` - Shared logging package
|
||||
- `packages/types/` - Shared TypeScript types
|
||||
|
||||
**VI**:
|
||||
- `services/iam-service/` - Service quản lý danh tính và quyền truy cập (RBAC, OIDC, MFA, Identity, Access, Governance)
|
||||
- `packages/logger/` - Package logging dùng chung
|
||||
- `packages/types/` - TypeScript types dùng chung
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Creating New Service / Tạo Service Mới
|
||||
|
||||
```bash
|
||||
# 1. Copy template
|
||||
cp -r services/_template services/my-service
|
||||
|
||||
# 2. Update package.json name
|
||||
# Change to: "@goodgo/my-service"
|
||||
|
||||
# 3. Add to docker-compose.yml
|
||||
# Add service configuration with Traefik labels
|
||||
|
||||
# 4. Configure Prisma schema
|
||||
cd services/my-service
|
||||
pnpm prisma migrate dev
|
||||
|
||||
# 5. Add health check endpoint
|
||||
# Already included in template
|
||||
```
|
||||
|
||||
### Working with Dependencies / Làm Việc Với Dependencies
|
||||
|
||||
```bash
|
||||
# Add external package
|
||||
pnpm --filter @goodgo/service-name add package-name
|
||||
|
||||
# Add workspace package
|
||||
pnpm --filter @goodgo/service-name add @goodgo/logger
|
||||
|
||||
# Add dev dependency
|
||||
pnpm --filter @goodgo/service-name add -D @types/pkg
|
||||
```
|
||||
|
||||
### Database Commands / Lệnh Database
|
||||
|
||||
```bash
|
||||
# Run migrations
|
||||
pnpm --filter @goodgo/service-name prisma migrate dev
|
||||
|
||||
# Generate Prisma client
|
||||
pnpm --filter @goodgo/service-name prisma generate
|
||||
|
||||
# Seed database
|
||||
pnpm --filter @goodgo/service-name prisma db seed
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[API Design](./api-design.md)** - RESTful API design standards
|
||||
- **[Database Prisma](./database-prisma.md)** - Prisma ORM patterns
|
||||
- **[Security](./security.md)** - Security best practices
|
||||
- **[Testing Patterns](./testing-patterns.md)** - Testing guidelines
|
||||
- **[Documentation](./documentation.md)** - Documentation writing guidelines
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- [Architecture Docs](../architecture/system-design.md)
|
||||
- [API Specs](../api/openapi/)
|
||||
- [Development Guide](../guides/development.md)
|
||||
- [Deployment Guide](../guides/deployment.md)
|
||||
- [Contributing Guide](../../../CONTRIBUTING.md)
|
||||
|
||||
**VI**:
|
||||
- [Tài Liệu Kiến Trúc](../architecture/system-design.md)
|
||||
- [Spec API](../api/openapi/)
|
||||
- [Hướng Dẫn Phát Triển](../guides/development.md)
|
||||
- [Hướng Dẫn Triển Khai](../guides/deployment.md)
|
||||
- [Hướng Dẫn Đóng Góp](../../../CONTRIBUTING.md)
|
||||
742
docs/en/skills/security.md
Normal file
742
docs/en/skills/security.md
Normal file
@@ -0,0 +1,742 @@
|
||||
# Security / Bảo Mật
|
||||
|
||||
> **EN**: Security best practices and patterns for GoodGo microservices platform. Use when implementing authentication, authorization, data protection, input validation, rate limiting, secrets management, or security testing across all services.
|
||||
> **VI**: Thực hành và mẫu bảo mật tốt nhất cho nền tảng microservices GoodGo. Sử dụng khi triển khai xác thực, phân quyền, bảo vệ dữ liệu, xác thực đầu vào, giới hạn tốc độ, quản lý bí mật hoặc kiểm tra bảo mật trên tất cả các dịch vụ.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: The Security skill provides comprehensive security patterns, best practices, and implementation examples for protecting GoodGo microservices. It covers authentication, authorization, data protection, input validation, rate limiting, secrets management, and security testing.
|
||||
|
||||
**VI**: Skill Security cung cấp các mẫu bảo mật toàn diện, thực hành tốt nhất và ví dụ triển khai để bảo vệ các microservices GoodGo. Nó bao gồm xác thực, phân quyền, bảo vệ dữ liệu, xác thực đầu vào, giới hạn tốc độ, quản lý bí mật và kiểm tra bảo mật.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Implementing authentication and authorization in any service
|
||||
- Protecting sensitive data (PII, credentials, tokens)
|
||||
- Validating user inputs and file uploads
|
||||
- Implementing rate limiting and DDoS protection
|
||||
- Setting up audit logging and security monitoring
|
||||
- Encrypting data at rest and in transit
|
||||
- Managing secrets and credentials
|
||||
- Implementing security testing
|
||||
- Handling security incidents
|
||||
- Designing secure API endpoints
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Triển khai xác thực và phân quyền trong bất kỳ service nào
|
||||
- Bảo vệ dữ liệu nhạy cảm (PII, thông tin đăng nhập, token)
|
||||
- Xác thực đầu vào người dùng và tải lên tệp
|
||||
- Triển khai giới hạn tốc độ và bảo vệ DDoS
|
||||
- Thiết lập ghi nhật ký kiểm toán và giám sát bảo mật
|
||||
- Mã hóa dữ liệu khi nghỉ và khi truyền
|
||||
- Quản lý bí mật và thông tin đăng nhập
|
||||
- Triển khai kiểm tra bảo mật
|
||||
- Xử lý sự cố bảo mật
|
||||
- Thiết kế các endpoint API an toàn
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Core Security Principles / Nguyên Tắc Bảo Mật Cốt Lõi
|
||||
|
||||
**EN**:
|
||||
1. **Defense in Depth**: Multiple layers of security controls
|
||||
2. **Least Privilege**: Grant minimum required permissions
|
||||
3. **Fail Secure**: Default to deny access
|
||||
4. **Separation of Duties**: Critical operations require multiple approvals
|
||||
5. **Audit Everything**: Log all security-relevant events
|
||||
6. **Encrypt Sensitive Data**: PII, tokens, credentials must be encrypted
|
||||
7. **Validate All Inputs**: Never trust user input
|
||||
8. **Principle of Least Exposure**: Minimize attack surface
|
||||
9. **Secure by Default**: Security built-in, not bolted on
|
||||
10. **Assume Breach**: Design for detection and response
|
||||
|
||||
**VI**:
|
||||
1. **Defense in Depth**: Nhiều lớp kiểm soát bảo mật
|
||||
2. **Least Privilege**: Cấp quyền tối thiểu cần thiết
|
||||
3. **Fail Secure**: Mặc định từ chối truy cập
|
||||
4. **Separation of Duties**: Các thao tác quan trọng yêu cầu nhiều phê duyệt
|
||||
5. **Audit Everything**: Ghi log tất cả sự kiện liên quan đến bảo mật
|
||||
6. **Encrypt Sensitive Data**: PII, token, thông tin đăng nhập phải được mã hóa
|
||||
7. **Validate All Inputs**: Không bao giờ tin tưởng đầu vào người dùng
|
||||
8. **Principle of Least Exposure**: Giảm thiểu bề mặt tấn công
|
||||
9. **Secure by Default**: Bảo mật được tích hợp sẵn, không phải thêm vào sau
|
||||
10. **Assume Breach**: Thiết kế để phát hiện và phản ứng
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Authentication & Authorization / Xác Thực & Phân Quyền
|
||||
|
||||
#### JWT Token Validation / Xác Thực Token JWT
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/auth.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { jwtService } from '../modules/token/jwt.service';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
export const authenticate = () => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Extract token from Authorization header or cookie
|
||||
let token: string | null = null;
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
if (authHeader?.startsWith('Bearer ')) {
|
||||
token = authHeader.substring(7);
|
||||
} else if (req.cookies?.access_token) {
|
||||
token = req.cookies.access_token;
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_001', message: 'Authentication required' }
|
||||
});
|
||||
}
|
||||
|
||||
// Verify token
|
||||
const payload = await jwtService.verifyAccessToken(token);
|
||||
|
||||
// Attach user to request
|
||||
req.user = {
|
||||
id: payload.sub,
|
||||
userId: payload.sub,
|
||||
email: payload.email,
|
||||
roles: payload.roles || [],
|
||||
permissions: payload.permissions || []
|
||||
};
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.warn('Authentication failed', { error: error.message });
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_002', message: 'Invalid or expired token' }
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/auth.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { jwtService } from '../modules/token/jwt.service';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
export const authenticate = () => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Trích xuất token từ header Authorization hoặc cookie
|
||||
let token: string | null = null;
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
if (authHeader?.startsWith('Bearer ')) {
|
||||
token = authHeader.substring(7);
|
||||
} else if (req.cookies?.access_token) {
|
||||
token = req.cookies.access_token;
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_001', message: 'Yêu cầu xác thực' }
|
||||
});
|
||||
}
|
||||
|
||||
// Xác minh token
|
||||
const payload = await jwtService.verifyAccessToken(token);
|
||||
|
||||
// Gắn user vào request
|
||||
req.user = {
|
||||
id: payload.sub,
|
||||
userId: payload.sub,
|
||||
email: payload.email,
|
||||
roles: payload.roles || [],
|
||||
permissions: payload.permissions || []
|
||||
};
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.warn('Xác thực thất bại', { error: error.message });
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_002', message: 'Token không hợp lệ hoặc hết hạn' }
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
#### Permission-Based Authorization / Phân Quyền Dựa Trên Quyền
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/rbac.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
export const requirePermission = (
|
||||
resource: string,
|
||||
action: string,
|
||||
scope?: string
|
||||
) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'UNAUTHORIZED', message: 'Authentication required' }
|
||||
});
|
||||
}
|
||||
|
||||
const hasPermission = await rbacService.hasPermission(
|
||||
userId,
|
||||
resource,
|
||||
action,
|
||||
scope
|
||||
);
|
||||
|
||||
if (!hasPermission) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INSUFFICIENT_PERMISSIONS',
|
||||
message: `Requires ${action} permission on ${resource}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/rbac.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
export const requirePermission = (
|
||||
resource: string,
|
||||
action: string,
|
||||
scope?: string
|
||||
) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'UNAUTHORIZED', message: 'Yêu cầu xác thực' }
|
||||
});
|
||||
}
|
||||
|
||||
const hasPermission = await rbacService.hasPermission(
|
||||
userId,
|
||||
resource,
|
||||
action,
|
||||
scope
|
||||
);
|
||||
|
||||
if (!hasPermission) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INSUFFICIENT_PERMISSIONS',
|
||||
message: `Yêu cầu quyền ${action} trên ${resource}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Input Validation / Xác Thực Đầu Vào
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/validation.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { AnyZodObject, ZodError } from 'zod';
|
||||
|
||||
export const validateDto = (
|
||||
schema: AnyZodObject,
|
||||
property: 'body' | 'query' | 'params' = 'body'
|
||||
) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Sanitize input by trimming strings
|
||||
const sanitizedData = sanitizeInput(req[property]);
|
||||
|
||||
// Validate the sanitized data
|
||||
const validatedData = schema.parse(sanitizedData);
|
||||
|
||||
// Replace original data with validated data
|
||||
(req as any)[property] = validatedData;
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Invalid request data',
|
||||
details: error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message,
|
||||
code: err.code
|
||||
}))
|
||||
}
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function sanitizeInput(data: any): any {
|
||||
if (typeof data === 'string') {
|
||||
return data.trim();
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(sanitizeInput);
|
||||
}
|
||||
if (data !== null && typeof data === 'object') {
|
||||
const sanitized: any = {};
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
sanitized[key] = sanitizeInput(value);
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/validation.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { AnyZodObject, ZodError } from 'zod';
|
||||
|
||||
export const validateDto = (
|
||||
schema: AnyZodObject,
|
||||
property: 'body' | 'query' | 'params' = 'body'
|
||||
) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Làm sạch đầu vào bằng cách cắt chuỗi
|
||||
const sanitizedData = sanitizeInput(req[property]);
|
||||
|
||||
// Xác thực dữ liệu đã được làm sạch
|
||||
const validatedData = schema.parse(sanitizedData);
|
||||
|
||||
// Thay thế dữ liệu gốc bằng dữ liệu đã xác thực
|
||||
(req as any)[property] = validatedData;
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Dữ liệu request không hợp lệ',
|
||||
details: error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message,
|
||||
code: err.code
|
||||
}))
|
||||
}
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function sanitizeInput(data: any): any {
|
||||
if (typeof data === 'string') {
|
||||
return data.trim();
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(sanitizeInput);
|
||||
}
|
||||
if (data !== null && typeof data === 'object') {
|
||||
const sanitized: any = {};
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
sanitized[key] = sanitizeInput(value);
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting / Giới Hạn Tốc Độ
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/rate-limit.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { RateLimiterRedis } from 'rate-limit-redis';
|
||||
import { getRedisClient } from '../config/redis.config';
|
||||
|
||||
export const dynamicRateLimit = async (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
// Default limits
|
||||
let windowMs = 15 * 60 * 1000; // 15 minutes
|
||||
let max = 100; // 100 requests
|
||||
|
||||
if (userId) {
|
||||
const roles = await rbacService.getUserRoles(userId);
|
||||
|
||||
// Set limits based on role
|
||||
if (roles.includes('SUPER_ADMIN')) {
|
||||
max = 1000;
|
||||
} else if (roles.includes('ADMIN')) {
|
||||
max = 500;
|
||||
} else if (roles.includes('MODERATOR')) {
|
||||
max = 300;
|
||||
}
|
||||
} else {
|
||||
// Unauthenticated users - stricter limits
|
||||
max = 50;
|
||||
}
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
store: new RateLimiterRedis({
|
||||
client: getRedisClient(),
|
||||
prefix: 'rl:'
|
||||
}),
|
||||
handler: (req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
limiter(req, res, next);
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/rate-limit.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { RateLimiterRedis } from 'rate-limit-redis';
|
||||
import { getRedisClient } from '../config/redis.config';
|
||||
|
||||
export const dynamicRateLimit = async (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
// Giới hạn mặc định
|
||||
let windowMs = 15 * 60 * 1000; // 15 phút
|
||||
let max = 100; // 100 requests
|
||||
|
||||
if (userId) {
|
||||
const roles = await rbacService.getUserRoles(userId);
|
||||
|
||||
// Đặt giới hạn dựa trên vai trò
|
||||
if (roles.includes('SUPER_ADMIN')) {
|
||||
max = 1000;
|
||||
} else if (roles.includes('ADMIN')) {
|
||||
max = 500;
|
||||
} else if (roles.includes('MODERATOR')) {
|
||||
max = 300;
|
||||
}
|
||||
} else {
|
||||
// Người dùng chưa xác thực - giới hạn nghiêm ngặt hơn
|
||||
max = 50;
|
||||
}
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
store: new RateLimiterRedis({
|
||||
client: getRedisClient(),
|
||||
prefix: 'rl:'
|
||||
}),
|
||||
handler: (req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Quá nhiều yêu cầu, vui lòng thử lại sau'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
limiter(req, res, next);
|
||||
};
|
||||
```
|
||||
|
||||
### Security Headers / Header Bảo Mật
|
||||
|
||||
**EN**: Example from `services/iam-service/src/main.ts`:
|
||||
|
||||
```typescript
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
|
||||
// Security middleware
|
||||
app.use(helmet());
|
||||
app.use(cors({
|
||||
origin: appConfig.corsOrigin,
|
||||
credentials: true
|
||||
}));
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/main.ts`:
|
||||
|
||||
```typescript
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
|
||||
// Middleware bảo mật
|
||||
app.use(helmet());
|
||||
app.use(cors({
|
||||
origin: appConfig.corsOrigin,
|
||||
credentials: true
|
||||
}));
|
||||
```
|
||||
|
||||
**EN**: Traefik security headers from `infra/traefik/dynamic/middlewares.yml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
middlewares:
|
||||
secure-headers:
|
||||
headers:
|
||||
sslRedirect: true
|
||||
stsSeconds: 31536000
|
||||
contentTypeNosniff: true
|
||||
browserXssFilter: true
|
||||
frameDeny: true
|
||||
customRequestHeaders:
|
||||
X-Forwarded-Proto: "https"
|
||||
```
|
||||
|
||||
**VI**: Header bảo mật Traefik từ `infra/traefik/dynamic/middlewares.yml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
middlewares:
|
||||
secure-headers:
|
||||
headers:
|
||||
sslRedirect: true
|
||||
stsSeconds: 31536000
|
||||
contentTypeNosniff: true
|
||||
browserXssFilter: true
|
||||
frameDeny: true
|
||||
customRequestHeaders:
|
||||
X-Forwarded-Proto: "https"
|
||||
```
|
||||
|
||||
### Audit Logging / Ghi Log Kiểm Toán
|
||||
|
||||
**EN**: Example from `services/iam-service/src/core/events/audit.service.ts`:
|
||||
|
||||
```typescript
|
||||
export class AuditService {
|
||||
async logAuthEvent(
|
||||
eventType: string,
|
||||
data: {
|
||||
userId?: string;
|
||||
success: boolean;
|
||||
errorMessage?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
metadata?: any;
|
||||
}
|
||||
): Promise<void> {
|
||||
await this.prisma.authEvent.create({
|
||||
data: {
|
||||
userId: data.userId || null,
|
||||
eventType,
|
||||
eventData: data.metadata || {},
|
||||
ipAddress: data.ipAddress,
|
||||
userAgent: data.userAgent,
|
||||
success: data.success,
|
||||
errorMessage: data.errorMessage
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/core/events/audit.service.ts`:
|
||||
|
||||
```typescript
|
||||
export class AuditService {
|
||||
async logAuthEvent(
|
||||
eventType: string,
|
||||
data: {
|
||||
userId?: string;
|
||||
success: boolean;
|
||||
errorMessage?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
metadata?: any;
|
||||
}
|
||||
): Promise<void> {
|
||||
await this.prisma.authEvent.create({
|
||||
data: {
|
||||
userId: data.userId || null,
|
||||
eventType,
|
||||
eventData: data.metadata || {},
|
||||
ipAddress: data.ipAddress,
|
||||
userAgent: data.userAgent,
|
||||
success: data.success,
|
||||
errorMessage: data.errorMessage
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Password Security / Bảo Mật Mật Khẩu
|
||||
|
||||
**EN**:
|
||||
- Always use bcrypt with cost factor 12+ in production
|
||||
- Never log passwords or password hashes
|
||||
- Use strong password requirements (min 8 chars, uppercase, lowercase, number, special char)
|
||||
- Implement password reset with secure tokens
|
||||
|
||||
**VI**:
|
||||
- Luôn sử dụng bcrypt với hệ số chi phí 12+ trong production
|
||||
- Không bao giờ ghi log mật khẩu hoặc hash mật khẩu
|
||||
- Sử dụng yêu cầu mật khẩu mạnh (tối thiểu 8 ký tự, chữ hoa, chữ thường, số, ký tự đặc biệt)
|
||||
- Triển khai đặt lại mật khẩu với token an toàn
|
||||
|
||||
### Token Security / Bảo Mật Token
|
||||
|
||||
**EN**:
|
||||
- Hash tokens before storing in database
|
||||
- Use short-lived access tokens (15 minutes)
|
||||
- Use longer-lived refresh tokens (7 days) with rotation
|
||||
- Store refresh tokens securely (httpOnly cookies)
|
||||
- Implement token revocation
|
||||
|
||||
**VI**:
|
||||
- Hash token trước khi lưu vào database
|
||||
- Sử dụng access token có thời gian sống ngắn (15 phút)
|
||||
- Sử dụng refresh token có thời gian sống dài hơn (7 ngày) với xoay vòng
|
||||
- Lưu trữ refresh token an toàn (httpOnly cookies)
|
||||
- Triển khai thu hồi token
|
||||
|
||||
### SQL Injection Prevention / Ngăn Chặn SQL Injection
|
||||
|
||||
**EN**:
|
||||
- Always use Prisma parameterized queries (automatic)
|
||||
- Never use string concatenation for queries
|
||||
- Validate and sanitize all inputs
|
||||
|
||||
**VI**:
|
||||
- Luôn sử dụng truy vấn tham số hóa của Prisma (tự động)
|
||||
- Không bao giờ sử dụng nối chuỗi cho truy vấn
|
||||
- Xác thực và làm sạch tất cả đầu vào
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Authentication Middleware / Middleware Xác Thực
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/auth.middleware.ts` for complete authentication implementation.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/auth.middleware.ts` để có implementation xác thực hoàn chỉnh.
|
||||
|
||||
### RBAC Middleware / Middleware RBAC
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/rbac.middleware.ts` for permission-based authorization.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/rbac.middleware.ts` để có phân quyền dựa trên quyền.
|
||||
|
||||
### Validation Middleware / Middleware Xác Thực
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/validation.middleware.ts` for input validation patterns.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/validation.middleware.ts` để có các mẫu xác thực đầu vào.
|
||||
|
||||
### Rate Limiting / Giới Hạn Tốc Độ
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/rate-limit.middleware.ts` for dynamic rate limiting.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/rate-limit.middleware.ts` để có giới hạn tốc độ động.
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Security Checklist / Danh Sách Kiểm Tra Bảo Mật
|
||||
|
||||
**EN**: Before deploying any service:
|
||||
- [ ] All endpoints require authentication (except public)
|
||||
- [ ] Authorization checks implemented (RBAC/ABAC)
|
||||
- [ ] Input validation with Zod schemas
|
||||
- [ ] Rate limiting configured
|
||||
- [ ] Error messages sanitized (no info disclosure)
|
||||
- [ ] PII encrypted at rest
|
||||
- [ ] Passwords hashed with bcrypt (cost 12+)
|
||||
- [ ] Tokens hashed before storing
|
||||
- [ ] Secrets in environment variables (never hardcoded)
|
||||
- [ ] HTTPS enforced (TLS 1.2+)
|
||||
- [ ] CORS configured correctly
|
||||
- [ ] Security headers set (helmet)
|
||||
- [ ] Audit logging enabled
|
||||
- [ ] SQL injection prevented (use Prisma)
|
||||
- [ ] XSS prevention (input sanitization)
|
||||
- [ ] File upload validation
|
||||
- [ ] Security tests passing
|
||||
|
||||
**VI**: Trước khi triển khai bất kỳ service nào:
|
||||
- [ ] Tất cả endpoint yêu cầu xác thực (trừ public)
|
||||
- [ ] Kiểm tra phân quyền đã triển khai (RBAC/ABAC)
|
||||
- [ ] Xác thực đầu vào với Zod schemas
|
||||
- [ ] Giới hạn tốc độ đã cấu hình
|
||||
- [ ] Thông báo lỗi đã được làm sạch (không tiết lộ thông tin)
|
||||
- [ ] PII được mã hóa khi nghỉ
|
||||
- [ ] Mật khẩu được hash với bcrypt (chi phí 12+)
|
||||
- [ ] Token được hash trước khi lưu
|
||||
- [ ] Bí mật trong biến môi trường (không bao giờ hardcode)
|
||||
- [ ] HTTPS được bắt buộc (TLS 1.2+)
|
||||
- [ ] CORS được cấu hình đúng
|
||||
- [ ] Header bảo mật được đặt (helmet)
|
||||
- [ ] Ghi log kiểm toán được bật
|
||||
- [ ] SQL injection được ngăn chặn (sử dụng Prisma)
|
||||
- [ ] Ngăn chặn XSS (làm sạch đầu vào)
|
||||
- [ ] Xác thực tải lên tệp
|
||||
- [ ] Kiểm tra bảo mật đã vượt qua
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Project Rules](./project-rules.md)** - Coding standards and architecture
|
||||
- **[API Design](./api-design.md)** - Secure API design patterns
|
||||
- **[Testing Patterns](./testing-patterns.md)** - Security testing
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
|
||||
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
|
||||
- [Express Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html)
|
||||
|
||||
**VI**:
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
|
||||
- [Thực Hành Bảo Mật Node.js](https://nodejs.org/en/docs/guides/security/)
|
||||
- [Thực Hành Bảo Mật Express](https://expressjs.com/en/advanced/best-practice-security.html)
|
||||
738
docs/en/skills/testing-patterns.md
Normal file
738
docs/en/skills/testing-patterns.md
Normal file
@@ -0,0 +1,738 @@
|
||||
# Testing Patterns
|
||||
|
||||
> **EN**: Comprehensive testing best practices for GoodGo microservices including unit tests, integration tests, E2E tests, Jest configuration, mocking strategies, and debugging techniques.
|
||||
> **VI**: Các thực hành tốt nhất về testing cho microservices GoodGo bao gồm unit tests, integration tests, E2E tests, cấu hình Jest, strategies mocking, và kỹ thuật debugging.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: Testing is a critical component of the GoodGo microservices platform. This guide provides comprehensive patterns and best practices for writing maintainable, reliable tests across all services. It covers test types, Jest configuration, mocking strategies, test utilities, and debugging techniques that ensure code quality and reliability.
|
||||
|
||||
**VI**: Testing là thành phần quan trọng của nền tảng microservices GoodGo. Hướng dẫn này cung cấp các patterns và best practices toàn diện để viết các test có thể bảo trì và đáng tin cậy trên tất cả các services. Nó bao gồm các loại test, cấu hình Jest, strategies mocking, test utilities, và kỹ thuật debugging để đảm bảo chất lượng và độ tin cậy của code.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use these testing patterns when:
|
||||
- Writing unit tests for services, controllers, or repositories
|
||||
- Creating integration tests for middleware chains
|
||||
- Building E2E tests for API endpoints
|
||||
- Setting up Jest configuration for a new service
|
||||
- Mocking external dependencies (Prisma, Redis, Auth SDK)
|
||||
- Debugging test failures
|
||||
- Improving test coverage
|
||||
- Creating test utilities and factories
|
||||
|
||||
**VI**: Sử dụng các testing patterns này khi:
|
||||
- Viết unit tests cho services, controllers, hoặc repositories
|
||||
- Tạo integration tests cho middleware chains
|
||||
- Xây dựng E2E tests cho API endpoints
|
||||
- Thiết lập cấu hình Jest cho service mới
|
||||
- Mocking các dependencies bên ngoài (Prisma, Redis, Auth SDK)
|
||||
- Debugging test failures
|
||||
- Cải thiện test coverage
|
||||
- Tạo test utilities và factories
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Test Types / Các Loại Test
|
||||
|
||||
#### 1. Unit Tests / Unit Tests
|
||||
|
||||
**EN**: Test individual functions or classes in isolation with all dependencies mocked.
|
||||
|
||||
**VI**: Test các functions hoặc classes riêng lẻ một cách cô lập với tất cả dependencies được mock.
|
||||
|
||||
**Characteristics**:
|
||||
- **Location**: Next to source files (`*.test.ts`) or in `__tests__/` directory
|
||||
- **Scope**: Single function, method, or class
|
||||
- **Dependencies**: All external dependencies mocked
|
||||
- **Speed**: Fast (<1s per test)
|
||||
- **Purpose**: Verify logic correctness
|
||||
|
||||
**Example**: [`services/iam-service/src/modules/feature/__tests__/feature.service.test.ts`](../../../services/iam-service/src/modules/feature/__tests__/feature.service.test.ts)
|
||||
|
||||
#### 2. Integration Tests / Integration Tests
|
||||
|
||||
**EN**: Test multiple components working together with some real dependencies.
|
||||
|
||||
**VI**: Test nhiều components làm việc cùng nhau với một số dependencies thật.
|
||||
|
||||
**Characteristics**:
|
||||
- **Location**: `__tests__/` directory (`*.test.ts`)
|
||||
- **Scope**: Multiple components interacting
|
||||
- **Dependencies**: Mix of real and mocked dependencies
|
||||
- **Speed**: Medium (1-5s per test)
|
||||
- **Purpose**: Verify component integration
|
||||
|
||||
**Example**: [`services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts`](../../../services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts)
|
||||
|
||||
#### 3. E2E Tests / E2E Tests
|
||||
|
||||
**EN**: Test complete request/response cycles through the entire application stack.
|
||||
|
||||
**VI**: Test các chu kỳ request/response hoàn chỉnh qua toàn bộ application stack.
|
||||
|
||||
**Characteristics**:
|
||||
- **Location**: `__tests__/*.e2e.ts`
|
||||
- **Scope**: Full API workflow from HTTP request to response
|
||||
- **Dependencies**: Test database, mocked external services
|
||||
- **Speed**: Slow (5-10s per test)
|
||||
- **Purpose**: Verify end-to-end functionality
|
||||
|
||||
**Example**: [`services/iam-service/src/__tests__/feature.e2e.ts`](../../../services/iam-service/src/__tests__/feature.e2e.ts)
|
||||
|
||||
## Jest Configuration / Cấu Hình Jest
|
||||
|
||||
### Standard Configuration
|
||||
|
||||
The standard Jest configuration for GoodGo services includes TypeScript support, coverage thresholds, and proper test environment setup.
|
||||
|
||||
**Location**: [`services/iam-service/jest.config.ts`](../../../services/iam-service/jest.config.ts)
|
||||
|
||||
```typescript
|
||||
import type { Config } from 'jest';
|
||||
|
||||
const config: Config = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
roots: ['<rootDir>/src'],
|
||||
testMatch: [
|
||||
'**/__tests__/**/*.test.ts',
|
||||
'**/__tests__/**/*.spec.ts',
|
||||
'**/__tests__/**/*.e2e.ts',
|
||||
'**/?(*.)+(spec|test).ts'
|
||||
],
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.ts',
|
||||
'!src/**/*.d.ts',
|
||||
'!src/main.ts',
|
||||
'!src/config/**/*.ts',
|
||||
'!src/**/*.config.ts'
|
||||
],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['text', 'lcov', 'html'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 70,
|
||||
functions: 70,
|
||||
lines: 70,
|
||||
statements: 70
|
||||
}
|
||||
},
|
||||
setupFilesAfterEnv: ['<rootDir>/src/__tests__/setupTests.ts'],
|
||||
testTimeout: 10000,
|
||||
clearMocks: true,
|
||||
resetModules: true
|
||||
};
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
### Key Configuration Points
|
||||
|
||||
- **preset: 'ts-jest'**: Enables TypeScript support
|
||||
- **testEnvironment: 'node'**: Sets Node.js environment (not browser)
|
||||
- **coverageThreshold**: Enforces minimum 70% coverage across all metrics
|
||||
- **setupFilesAfterEnv**: Loads test setup file before each test suite
|
||||
- **clearMocks**: Automatically clears mock calls between tests
|
||||
- **resetModules**: Resets module cache for test isolation
|
||||
|
||||
## Setup Files / Files Thiết Lập
|
||||
|
||||
### Test Setup File
|
||||
|
||||
The setup file (`setupTests.ts`) configures global mocks and test utilities that are available across all tests.
|
||||
|
||||
**Location**: [`services/iam-service/src/__tests__/setupTests.ts`](../../../services/iam-service/src/__tests__/setupTests.ts)
|
||||
|
||||
**Key Features**:
|
||||
- Mock external services (logger, tracing, database, Redis)
|
||||
- Configure test environment variables
|
||||
- Set up global test utilities
|
||||
- Initialize Prometheus mocks
|
||||
|
||||
**Example**:
|
||||
```typescript
|
||||
import { jest } from '@jest/globals';
|
||||
|
||||
// EN: Mock environment variables for tests
|
||||
// VI: Mock biến môi trường cho tests
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.DATABASE_URL = 'postgresql://test:test@localhost:5432/test_db';
|
||||
process.env.REDIS_URL = 'redis://localhost:6379/1';
|
||||
|
||||
// EN: Mock external services to avoid real network calls
|
||||
// VI: Mock các service bên ngoài để tránh gọi mạng thật
|
||||
jest.mock('@goodgo/logger', () => ({
|
||||
logger: {
|
||||
info: jest.fn(),
|
||||
error: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
debug: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
// EN: Global test utilities
|
||||
// VI: Utilities test toàn cục
|
||||
global.testUtils = {
|
||||
createMockReq: (overrides = {}) => ({
|
||||
body: {},
|
||||
params: {},
|
||||
query: {},
|
||||
headers: {},
|
||||
...overrides,
|
||||
}),
|
||||
createMockRes: () => {
|
||||
const res: any = {};
|
||||
res.status = jest.fn().mockReturnValue(res);
|
||||
res.json = jest.fn().mockReturnValue(res);
|
||||
res.send = jest.fn().mockReturnValue(res);
|
||||
return res;
|
||||
},
|
||||
createMockNext: () => jest.fn(),
|
||||
};
|
||||
```
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Unit Test Pattern
|
||||
|
||||
**Structure**: Follow the AAA (Arrange-Act-Assert) pattern for clarity.
|
||||
|
||||
```typescript
|
||||
describe('FeatureService', () => {
|
||||
let service: FeatureService;
|
||||
let mockRepository: any;
|
||||
|
||||
beforeEach(() => {
|
||||
// EN: Clear all mocks before each test
|
||||
// VI: Xóa tất cả mocks trước mỗi test
|
||||
jest.clearAllMocks();
|
||||
|
||||
mockRepository = {
|
||||
findById: jest.fn(),
|
||||
create: jest.fn(),
|
||||
};
|
||||
service = new FeatureService(mockRepository);
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should create a feature successfully', async () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const testData = { name: 'test-feature', title: 'Test Feature' };
|
||||
const mockFeature = {
|
||||
id: 'test-id',
|
||||
name: testData.name,
|
||||
// ... other fields
|
||||
};
|
||||
mockRepository.create.mockResolvedValue(mockFeature);
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực hiện
|
||||
const result = await service.create(testData);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(mockRepository.create).toHaveBeenCalledWith(testData);
|
||||
expect(result).toEqual(mockFeature);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Real Example**: [`services/iam-service/src/modules/feature/__tests__/feature.service.test.ts`](../../../services/iam-service/src/modules/feature/__tests__/feature.service.test.ts)
|
||||
|
||||
### Integration Test Pattern
|
||||
|
||||
Integration tests verify that multiple components work together correctly.
|
||||
|
||||
```typescript
|
||||
describe('Auth Middleware', () => {
|
||||
const mockNext = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should authenticate valid token and attach user to request', () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const mockReq = createMockReq({
|
||||
headers: { authorization: 'Bearer valid-token' },
|
||||
});
|
||||
const mockRes = createMockRes();
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực hiện
|
||||
const middleware = authenticate({ secret: jwtSecret });
|
||||
middleware(mockReq as Request, mockRes as Response, mockNext);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(mockNext).toHaveBeenCalled();
|
||||
expect(mockReq.user).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Real Example**: [`services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts`](../../../services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts)
|
||||
|
||||
### E2E Test Pattern
|
||||
|
||||
E2E tests use supertest to test complete HTTP request/response cycles.
|
||||
|
||||
```typescript
|
||||
import request from 'supertest';
|
||||
import express from 'express';
|
||||
import { createRouter } from '../routes';
|
||||
|
||||
describe('Feature Endpoints E2E', () => {
|
||||
let app: express.Application;
|
||||
|
||||
beforeAll(() => {
|
||||
// EN: Set up test environment
|
||||
// VI: Thiết lập môi trường test
|
||||
process.env.NODE_ENV = 'test';
|
||||
app = express();
|
||||
app.use(express.json());
|
||||
app.use(createRouter());
|
||||
});
|
||||
|
||||
describe('POST /api/v1/features', () => {
|
||||
it('should create a feature successfully', async () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const featureData = {
|
||||
name: 'test-feature',
|
||||
title: 'Test Feature',
|
||||
description: 'A test feature for E2E testing'
|
||||
};
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực hiện
|
||||
const response = await request(app)
|
||||
.post('/api/v1/features')
|
||||
.send(featureData)
|
||||
.expect(201);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(response.body).toMatchObject({
|
||||
success: true,
|
||||
message: 'Feature created successfully / Feature đã được tạo thành công',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Real Example**: [`services/iam-service/src/__tests__/feature.e2e.ts`](../../../services/iam-service/src/__tests__/feature.e2e.ts)
|
||||
|
||||
## Mocking Strategies / Chiến Lược Mocking
|
||||
|
||||
### Mock Prisma Database
|
||||
|
||||
Mock Prisma client to avoid real database connections in unit tests.
|
||||
|
||||
```typescript
|
||||
// In setupTests.ts or individual test files
|
||||
jest.mock('../config/database.config', () => ({
|
||||
connectDatabase: jest.fn(),
|
||||
prisma: {
|
||||
$queryRaw: jest.fn(),
|
||||
$disconnect: jest.fn(),
|
||||
feature: {
|
||||
create: jest.fn(),
|
||||
findMany: jest.fn(),
|
||||
findUnique: jest.fn(),
|
||||
update: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
// Usage in tests
|
||||
const { prisma } = require('../config/database.config');
|
||||
|
||||
test('should create user', async () => {
|
||||
prisma.feature.create.mockResolvedValue({
|
||||
id: 'test-id',
|
||||
name: 'test-feature',
|
||||
// ... other fields
|
||||
});
|
||||
|
||||
const result = await createFeature({ name: 'test-feature' });
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
```
|
||||
|
||||
### Mock Redis
|
||||
|
||||
Mock Redis client for caching and session management tests.
|
||||
|
||||
```typescript
|
||||
jest.mock('../config/redis.config', () => ({
|
||||
getRedisClient: jest.fn().mockReturnValue({
|
||||
call: jest.fn(),
|
||||
connect: jest.fn(),
|
||||
disconnect: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
```
|
||||
|
||||
### Mock External APIs
|
||||
|
||||
Mock external HTTP calls using Jest mocks.
|
||||
|
||||
```typescript
|
||||
jest.mock('axios');
|
||||
import axios from 'axios';
|
||||
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
||||
|
||||
test('should fetch external data', async () => {
|
||||
mockedAxios.get.mockResolvedValue({
|
||||
data: { result: 'success' }
|
||||
});
|
||||
|
||||
const result = await fetchExternalData();
|
||||
expect(result).toEqual({ result: 'success' });
|
||||
});
|
||||
```
|
||||
|
||||
### Mock Auth SDK
|
||||
|
||||
Mock authentication SDK functions for middleware and service tests.
|
||||
|
||||
```typescript
|
||||
jest.mock('@goodgo/auth-sdk', () => ({
|
||||
createToken: jest.fn(),
|
||||
verifyToken: jest.fn(),
|
||||
extractTokenFromHeader: jest.fn(),
|
||||
}));
|
||||
|
||||
// Setup mock implementations
|
||||
(verifyToken as jest.Mock).mockImplementation((token) => {
|
||||
if (token === 'valid-token') {
|
||||
return { userId: '123', role: 'user' };
|
||||
}
|
||||
throw new Error('Invalid token');
|
||||
});
|
||||
```
|
||||
|
||||
## Testing Utilities / Utilities Test
|
||||
|
||||
### Test Factory Pattern
|
||||
|
||||
Create reusable test data factories for consistent test data.
|
||||
|
||||
```typescript
|
||||
export class TestFactory {
|
||||
static createUser(overrides = {}) {
|
||||
return {
|
||||
id: 'test-user-1',
|
||||
email: 'test@example.com',
|
||||
name: 'Test User',
|
||||
createdAt: new Date(),
|
||||
...overrides
|
||||
};
|
||||
}
|
||||
|
||||
static createAuthToken(userId: string) {
|
||||
return jwt.sign({ userId }, 'test-secret');
|
||||
}
|
||||
|
||||
static async cleanDatabase() {
|
||||
await prisma.user.deleteMany();
|
||||
await prisma.feature.deleteMany();
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
const user = TestFactory.createUser({ name: 'Custom Name' });
|
||||
const token = TestFactory.createAuthToken(user.id);
|
||||
```
|
||||
|
||||
### Mock Request/Response Helpers
|
||||
|
||||
Use global test utilities for creating mock Express request/response objects.
|
||||
|
||||
```typescript
|
||||
// Available via global.testUtils (from setupTests.ts)
|
||||
const mockReq = global.testUtils.createMockReq({
|
||||
headers: { authorization: 'Bearer token' },
|
||||
params: { id: '123' },
|
||||
});
|
||||
|
||||
const mockRes = global.testUtils.createMockRes();
|
||||
const mockNext = global.testUtils.createMockNext();
|
||||
```
|
||||
|
||||
## Common Test Scenarios / Các Tình Huống Test Thường Gặp
|
||||
|
||||
### Testing Error Handling
|
||||
|
||||
```typescript
|
||||
it('should handle database errors gracefully', async () => {
|
||||
// EN: Arrange - Mock database error
|
||||
// VI: Chuẩn bị - Mock lỗi database
|
||||
prismaMock.user.findUnique.mockRejectedValue(
|
||||
new Error('Database connection failed')
|
||||
);
|
||||
|
||||
// EN: Act & Assert
|
||||
// VI: Thực hiện & Kiểm tra
|
||||
await expect(userService.findById('123')).rejects.toThrow();
|
||||
|
||||
// Or for HTTP endpoints
|
||||
const response = await request(app)
|
||||
.get('/api/users/123')
|
||||
.expect(500);
|
||||
|
||||
expect(response.body).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INTERNAL_ERROR',
|
||||
message: 'Internal server error / Lỗi máy chủ nội bộ',
|
||||
},
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Testing Validation
|
||||
|
||||
```typescript
|
||||
describe('Validation', () => {
|
||||
it('should reject invalid email', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send({ email: 'invalid-email', password: '123456' })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.error.code).toBe('VALIDATION_ERROR');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Testing Authorization
|
||||
|
||||
```typescript
|
||||
it('should deny access for user with incorrect role', () => {
|
||||
const mockReq = createMockReq({
|
||||
user: { userId: 'user-123', role: 'user' },
|
||||
});
|
||||
|
||||
const middleware = authorize('admin');
|
||||
middleware(mockReq as Request, mockRes as Response, mockNext);
|
||||
|
||||
expect(mockNext).not.toHaveBeenCalled();
|
||||
expect(mockStatus).toHaveBeenCalledWith(403);
|
||||
});
|
||||
```
|
||||
|
||||
## Test Commands / Lệnh Test
|
||||
|
||||
Add these scripts to `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:unit": "jest --testPathPattern=\\.test\\.ts$",
|
||||
"test:e2e": "jest --testPathPattern=\\.e2e\\.ts$",
|
||||
"test:ci": "jest --coverage --silent --maxWorkers=2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
- `pnpm test`: Run all tests
|
||||
- `pnpm test:watch`: Run tests in watch mode
|
||||
- `pnpm test:coverage`: Generate coverage report
|
||||
- `pnpm test:unit`: Run only unit tests
|
||||
- `pnpm test:e2e`: Run only E2E tests
|
||||
- `pnpm test:ci`: Run tests optimized for CI/CD
|
||||
|
||||
## Debugging Tests / Debugging Tests
|
||||
|
||||
### VS Code Debug Configuration
|
||||
|
||||
Create `.vscode/launch.json` for debugging tests:
|
||||
|
||||
```json
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Debug Jest Tests",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["test", "--", "--runInBand"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Tips
|
||||
|
||||
1. **Use `test.only()`** to run a single test:
|
||||
```typescript
|
||||
it.only('should test specific behavior', () => {
|
||||
// Only this test will run
|
||||
});
|
||||
```
|
||||
|
||||
2. **Use `--detectOpenHandles`** for async issues:
|
||||
```bash
|
||||
pnpm test --detectOpenHandles
|
||||
```
|
||||
|
||||
3. **Use `--runInBand`** for sequential execution:
|
||||
```bash
|
||||
pnpm test --runInBand
|
||||
```
|
||||
|
||||
4. **Add temporary console.log**:
|
||||
```typescript
|
||||
console.log('Debug value:', someValue);
|
||||
```
|
||||
|
||||
5. **Use debugger breakpoints** in VS Code
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Test Organization
|
||||
|
||||
- ✅ Each test is independent and isolated
|
||||
- ✅ Tests follow AAA pattern (Arrange-Act-Assert)
|
||||
- ✅ Use descriptive test names that explain what is being tested
|
||||
- ✅ Group related tests using `describe` blocks
|
||||
- ✅ Use `beforeEach`/`afterEach` for setup/cleanup
|
||||
|
||||
### Mocking
|
||||
|
||||
- ✅ Mock external dependencies (database, APIs, services)
|
||||
- ✅ Use `jest.clearAllMocks()` in `beforeEach` to reset mocks
|
||||
- ✅ Verify mock calls to ensure correct behavior
|
||||
- ✅ Keep mocks simple and focused
|
||||
|
||||
### Coverage
|
||||
|
||||
- ✅ Maintain >70% code coverage (as per Jest config)
|
||||
- ✅ Focus on covering critical business logic
|
||||
- ✅ Don't sacrifice test quality for coverage percentage
|
||||
- ✅ Review coverage reports regularly
|
||||
|
||||
### Test Data
|
||||
|
||||
- ✅ Use factories for creating test data
|
||||
- ✅ Keep test data realistic and representative
|
||||
- ✅ Clean up test data after tests (if using real database)
|
||||
- ✅ Use meaningful test values, not just `'test'` or `123`
|
||||
|
||||
### Error Testing
|
||||
|
||||
- ✅ Test both success and error scenarios
|
||||
- ✅ Test edge cases and boundary conditions
|
||||
- ✅ Test validation errors
|
||||
- ✅ Test error messages and error codes
|
||||
|
||||
### Performance
|
||||
|
||||
- ✅ Keep unit tests fast (<1s each)
|
||||
- ✅ Avoid unnecessary async operations in unit tests
|
||||
- ✅ Use `--maxWorkers` in CI for parallel execution
|
||||
- ✅ Don't test implementation details, test behavior
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Real Test Examples
|
||||
|
||||
1. **Unit Test**: [`services/iam-service/src/modules/feature/__tests__/feature.service.test.ts`](../../../services/iam-service/src/modules/feature/__tests__/feature.service.test.ts)
|
||||
2. **Integration Test**: [`services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts`](../../../services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts)
|
||||
3. **E2E Test**: [`services/iam-service/src/__tests__/feature.e2e.ts`](../../../services/iam-service/src/__tests__/feature.e2e.ts)
|
||||
4. **Setup File**: [`services/iam-service/src/__tests__/setupTests.ts`](../../../services/iam-service/src/__tests__/setupTests.ts)
|
||||
5. **Jest Config**: [`services/iam-service/jest.config.ts`](../../../services/iam-service/jest.config.ts)
|
||||
|
||||
### Test Structure Examples
|
||||
|
||||
- **Repository Tests**: [`services/iam-service/src/modules/feature/__tests__/feature.repository.test.ts`](../../../services/iam-service/src/modules/feature/__tests__/feature.repository.test.ts)
|
||||
- **Controller Tests**: [`services/iam-service/src/modules/health/__tests__/health.controller.test.ts`](../../../services/iam-service/src/modules/health/__tests__/health.controller.test.ts)
|
||||
- **Middleware Tests**: [`services/iam-service/src/middlewares/__tests__/correlation.middleware.test.ts`](../../../services/iam-service/src/middlewares/__tests__/correlation.middleware.test.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Test Type Decision Tree
|
||||
|
||||
```
|
||||
Need to test complete HTTP flow?
|
||||
├─ Yes → E2E Test (*.e2e.ts)
|
||||
└─ No → Multiple components interacting?
|
||||
├─ Yes → Integration Test (*.test.ts)
|
||||
└─ No → Unit Test (*.test.ts)
|
||||
```
|
||||
|
||||
### Common Jest Matchers
|
||||
|
||||
| Matcher | Purpose | Example |
|
||||
|---------|---------|---------|
|
||||
| `toBe()` | Exact equality | `expect(value).toBe(5)` |
|
||||
| `toEqual()` | Deep equality | `expect(obj).toEqual({a: 1})` |
|
||||
| `toMatchObject()` | Partial match | `expect(obj).toMatchObject({a: 1})` |
|
||||
| `toHaveBeenCalled()` | Function called | `expect(mockFn).toHaveBeenCalled()` |
|
||||
| `toHaveBeenCalledWith()` | Called with args | `expect(mockFn).toHaveBeenCalledWith('arg')` |
|
||||
| `toThrow()` | Throws error | `expect(() => fn()).toThrow()` |
|
||||
| `toBeDefined()` | Not undefined | `expect(value).toBeDefined()` |
|
||||
| `toBeNull()` | Is null | `expect(value).toBeNull()` |
|
||||
| `toContain()` | Array/string contains | `expect(array).toContain('item')` |
|
||||
|
||||
### Mock Function Helpers
|
||||
|
||||
```typescript
|
||||
// Create mock
|
||||
const mockFn = jest.fn();
|
||||
|
||||
// Set return value
|
||||
mockFn.mockReturnValue('value');
|
||||
mockFn.mockResolvedValue('async value');
|
||||
mockFn.mockRejectedValue(new Error('error'));
|
||||
|
||||
// Set implementation
|
||||
mockFn.mockImplementation((arg) => arg * 2);
|
||||
|
||||
// Clear/reset
|
||||
mockFn.mockClear(); // Clear call history
|
||||
mockFn.mockReset(); // Reset to initial state
|
||||
jest.clearAllMocks(); // Clear all mocks
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Comment Code](./comment-code.md)**: Writing bilingual comments in tests
|
||||
- **[Security](./security.md)**: Testing security-critical code
|
||||
- **[API Design](./api-design.md)**: Testing API endpoints and responses
|
||||
- **[Project Rules](./project-rules.md)**: Code organization for tests
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### Official Documentation
|
||||
|
||||
- [Jest Documentation](https://jestjs.io/docs/getting-started)
|
||||
- [Supertest Documentation](https://github.com/visionmedia/supertest)
|
||||
- [jest-mock-extended](https://github.com/marchaos/jest-mock-extended)
|
||||
|
||||
### Internal Documentation
|
||||
|
||||
- [Service Development Guide](../guides/development.md)
|
||||
- [Local Development Setup](../guides/local-development.md)
|
||||
- [Troubleshooting Guide](../guides/troubleshooting.md)
|
||||
|
||||
### Tools
|
||||
|
||||
- **Jest**: JavaScript testing framework
|
||||
- **Supertest**: HTTP assertion library
|
||||
- **jest-mock-extended**: Enhanced mocking for TypeScript
|
||||
- **ioredis-mock**: Redis mock for testing
|
||||
339
docs/vi/architecture/iam-proposal.md
Normal file
339
docs/vi/architecture/iam-proposal.md
Normal file
@@ -0,0 +1,339 @@
|
||||
# Đề Xuất Kiến Trúc IAM Service
|
||||
|
||||
Tài liệu này mô tả đề xuất kiến trúc cho IAM Service (Identity and Access Management Service), mở rộng từ auth-service hiện tại.
|
||||
|
||||
## 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** 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)
|
||||
|
||||
---
|
||||
|
||||
## 1. Phạm Vi IAM Service
|
||||
|
||||
### 1.1 Identity Management (Quản Lý Danh Tính)
|
||||
|
||||
#### A. User Lifecycle Management
|
||||
- User CRUD operations
|
||||
- User provisioning/deprovisioning workflows
|
||||
- Bulk user operations (import/export)
|
||||
- User deactivation/reactivation với approval workflow
|
||||
- Account merging/deduplication
|
||||
- User archival (soft delete với retention policy)
|
||||
|
||||
#### B. Profile Management
|
||||
- Extended attributes (custom fields)
|
||||
- Profile picture upload & management
|
||||
- Contact information (phone, address)
|
||||
- Preferences & settings
|
||||
- Profile versioning/audit trail
|
||||
|
||||
#### C. Identity Verification
|
||||
- Email verification
|
||||
- Phone/SMS verification
|
||||
- Identity document verification (KYC)
|
||||
- Multi-level verification (verified, pending, rejected)
|
||||
|
||||
#### D. Organizations & Groups
|
||||
- Organization management (multi-tenant)
|
||||
- Group/Team management
|
||||
- Organization hierarchy
|
||||
- Group-based access control
|
||||
- Organization-level policies
|
||||
|
||||
### 1.2 Access Management (Quản Lý Truy Cập)
|
||||
|
||||
#### A. Advanced Access Control
|
||||
- Just-In-Time (JIT) access provisioning
|
||||
- Privileged Access Management (PAM)
|
||||
- Temporary access grants
|
||||
- Access request/approval workflows
|
||||
- Delegation & impersonation (admin view)
|
||||
- Conditional access policies (location, time, device)
|
||||
|
||||
#### B. Access Reviews & Certifications
|
||||
- Periodic access reviews
|
||||
- Access certification campaigns
|
||||
- Access analytics & reporting
|
||||
- Risk scoring for access decisions
|
||||
- Anomaly detection (unusual access patterns)
|
||||
|
||||
### 1.3 Governance & Compliance (Quản Trị & Tuân Thủ)
|
||||
|
||||
#### A. Audit & Logging
|
||||
- Compliance reporting (GDPR, SOC2, ISO 27001)
|
||||
- Data retention policies
|
||||
- Audit log search & analytics
|
||||
- Export audit logs
|
||||
|
||||
#### B. Policy Governance
|
||||
- Policy versioning & rollback
|
||||
- Policy templates library
|
||||
- Policy testing & validation
|
||||
- Policy compliance checks
|
||||
|
||||
#### C. Risk Management
|
||||
- Risk scoring engine
|
||||
- Risk-based authentication
|
||||
- Threat detection
|
||||
- Incident response workflows
|
||||
- Security posture dashboard
|
||||
|
||||
---
|
||||
|
||||
## 2. Kiến Trúc Module Structure
|
||||
|
||||
```
|
||||
services/iam-service/
|
||||
├── src/
|
||||
│ ├── config/ # Configuration files
|
||||
│ ├── core/
|
||||
│ │ ├── cache/ # Multi-layer cache
|
||||
│ │ ├── security/ # Zero-trust, encryption
|
||||
│ │ ├── events/ # Event sourcing
|
||||
│ │ └── workflows/ # Workflow engine (NEW)
|
||||
│ ├── modules/
|
||||
│ │ ├── auth/ # ✅ Core authentication
|
||||
│ │ ├── rbac/ # ✅ RBAC system
|
||||
│ │ ├── social/ # ✅ Social authentication
|
||||
│ │ ├── oidc/ # ✅ OIDC implementation
|
||||
│ │ ├── token/ # ✅ JWT & Cookie management
|
||||
│ │ ├── session/ # ✅ Session management
|
||||
│ │ ├── mfa/ # ✅ Multi-factor auth
|
||||
│ │ │
|
||||
│ │ ├── identity/ # 🆕 Identity Management
|
||||
│ │ │ ├── user/ # User lifecycle
|
||||
│ │ │ ├── profile/ # Profile management
|
||||
│ │ │ ├── verification/ # Identity verification
|
||||
│ │ │ └── organization/ # Organizations & groups
|
||||
│ │ │
|
||||
│ │ ├── access/ # 🆕 Access Management
|
||||
│ │ │ ├── request/ # Access requests
|
||||
│ │ │ ├── review/ # Access reviews
|
||||
│ │ │ ├── pam/ # Privileged access
|
||||
│ │ │ └── analytics/ # Access analytics
|
||||
│ │ │
|
||||
│ │ ├── governance/ # 🆕 Governance & Compliance
|
||||
│ │ │ ├── compliance/ # Compliance reporting
|
||||
│ │ │ ├── policy/ # Policy governance
|
||||
│ │ │ ├── risk/ # Risk management
|
||||
│ │ │ └── reporting/ # Reporting & dashboards
|
||||
│ │ │
|
||||
│ │ └── workflow/ # 🆕 Workflow Engine
|
||||
│ │ ├── engine/ # Workflow engine
|
||||
│ │ ├── approval/ # Approval workflows
|
||||
│ │ └── automation/ # Automated workflows
|
||||
│ │
|
||||
│ ├── middlewares/ # Express middlewares
|
||||
│ ├── repositories/ # Data access layer
|
||||
│ └── routes/ # Route definitions
|
||||
└── prisma/
|
||||
└── schema.prisma # Database schema (mở rộng)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Database Schema Mở Rộng
|
||||
|
||||
### 3.1 Identity Management Models
|
||||
|
||||
- **Organization**: Quản lý tổ chức với hierarchy
|
||||
- **Group**: Quản lý nhóm trong organization
|
||||
- **GroupMember**: Thành viên của group
|
||||
- **GroupPermission**: Permissions cho group
|
||||
- **UserProfile**: Thông tin profile mở rộng của user
|
||||
- **IdentityVerification**: Xác thực danh tính (email, phone, document)
|
||||
|
||||
### 3.2 Access Management Models
|
||||
|
||||
- **AccessRequest**: Yêu cầu truy cập
|
||||
- **AccessRequestApprover**: Người phê duyệt request
|
||||
- **AccessReview**: Đánh giá truy cập định kỳ
|
||||
- **AccessReviewItem**: Item trong review
|
||||
|
||||
### 3.3 Governance Models
|
||||
|
||||
- **ComplianceReport**: Báo cáo tuân thủ (GDPR, SOC2, ISO27001)
|
||||
- **PolicyTemplate**: Template cho policies
|
||||
- **RiskScore**: Điểm rủi ro của user
|
||||
|
||||
---
|
||||
|
||||
## 4. API Endpoints Mở Rộng
|
||||
|
||||
### 4.1 Identity Management 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
|
||||
|
||||
# Profile Management
|
||||
GET /api/v1/identity/users/:id/profile
|
||||
PUT /api/v1/identity/users/:id/profile
|
||||
POST /api/v1/identity/users/:id/profile/avatar
|
||||
|
||||
# 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
|
||||
|
||||
# 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.2 Access Management APIs
|
||||
|
||||
```
|
||||
# Access Requests
|
||||
GET /api/v1/access/requests
|
||||
POST /api/v1/access/requests
|
||||
PUT /api/v1/access/requests/:id/approve
|
||||
PUT /api/v1/access/requests/:id/reject
|
||||
|
||||
# Access Reviews
|
||||
GET /api/v1/access/reviews
|
||||
POST /api/v1/access/reviews
|
||||
POST /api/v1/access/reviews/:id/start
|
||||
POST /api/v1/access/reviews/:id/complete
|
||||
GET /api/v1/access/reviews/:id/items
|
||||
|
||||
# Access Analytics
|
||||
GET /api/v1/access/analytics/usage
|
||||
GET /api/v1/access/analytics/permissions
|
||||
GET /api/v1/access/analytics/risks
|
||||
```
|
||||
|
||||
### 4.3 Governance APIs
|
||||
|
||||
```
|
||||
# Compliance Reports
|
||||
GET /api/v1/governance/compliance/reports
|
||||
POST /api/v1/governance/compliance/reports/generate
|
||||
GET /api/v1/governance/compliance/reports/:id/export
|
||||
|
||||
# Policy Governance
|
||||
GET /api/v1/governance/policies/templates
|
||||
POST /api/v1/governance/policies/templates
|
||||
GET /api/v1/governance/policies/:id/versions
|
||||
POST /api/v1/governance/policies/:id/test
|
||||
|
||||
# Risk Management
|
||||
GET /api/v1/governance/risk/scores
|
||||
GET /api/v1/governance/risk/scores/:userId
|
||||
POST /api/v1/governance/risk/calculate
|
||||
|
||||
# Reporting
|
||||
GET /api/v1/governance/reports/access-summary
|
||||
GET /api/v1/governance/reports/user-activity
|
||||
GET /api/v1/governance/reports/security-events
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Implementation Roadmap
|
||||
|
||||
### Phase 1: Foundation (Weeks 1-4)
|
||||
- ✅ Migrate từ auth-service sang iam-service
|
||||
- 🔄 Tổ chức lại modules theo IAM structure
|
||||
- 🔄 Mở rộng database schema với identity models
|
||||
- 🔄 Implement User Profile module
|
||||
|
||||
### Phase 2: Identity Management (Weeks 5-8)
|
||||
- 🔄 User lifecycle management
|
||||
- 🔄 Identity verification (email, phone, document)
|
||||
- 🔄 Organization & Group management
|
||||
- 🔄 Profile management with extended attributes
|
||||
|
||||
### Phase 3: Access Management (Weeks 9-12)
|
||||
- 🔄 Access request/approval workflows
|
||||
- 🔄 Access review & certification system
|
||||
- 🔄 Access analytics
|
||||
- 🔄 Privileged Access Management (PAM)
|
||||
|
||||
### Phase 4: Governance (Weeks 13-16)
|
||||
- 🔄 Compliance reporting engine
|
||||
- 🔄 Policy governance & versioning
|
||||
- 🔄 Risk scoring & management
|
||||
- 🔄 Reporting dashboards
|
||||
|
||||
### Phase 5: Advanced Features (Weeks 17-20)
|
||||
- 🔄 Workflow engine
|
||||
- 🔄 Advanced analytics & ML-based insights
|
||||
- 🔄 Integration APIs (SCIM, LDAP sync)
|
||||
- 🔄 Performance optimization & scaling
|
||||
|
||||
---
|
||||
|
||||
## 6. Lợi Ích Của IAM Service
|
||||
|
||||
### 6.1 Cho Doanh Nghiệp
|
||||
- ✅ Tuân thủ (GDPR, SOC2, ISO 27001)
|
||||
- ✅ Quản lý rủi ro bảo mật tốt hơn
|
||||
- ✅ Tự động hóa quy trình quản lý truy cập
|
||||
- ✅ Báo cáo và audit trail đầy đủ
|
||||
- ✅ Hỗ trợ multi-tenant/organization
|
||||
|
||||
### 6.2 Cho Developers
|
||||
- ✅ API thống nhất cho identity & access
|
||||
- ✅ Workflow engine linh hoạt
|
||||
- ✅ Extensible architecture
|
||||
- ✅ Comprehensive documentation
|
||||
- ✅ SDK support
|
||||
|
||||
### 6.3 Cho End Users
|
||||
- ✅ Self-service profile management
|
||||
- ✅ Transparent access requests
|
||||
- ✅ Better user experience
|
||||
- ✅ Enhanced security với MFA & verification
|
||||
|
||||
---
|
||||
|
||||
## 7. Migration Strategy
|
||||
|
||||
### Từ Auth Service → IAM Service
|
||||
|
||||
1. **Rename Service**: `services/auth-service` → `services/iam-service`
|
||||
2. **Update Package Name**: `@goodgo/auth-service` → `@goodgo/iam-service`
|
||||
3. **Update Routes**:
|
||||
- Giữ backward compatibility với `/api/v1/auth/*`
|
||||
- Thêm routes mới cho `/api/v1/identity/*`, `/api/v1/access/*`, `/api/v1/governance/*`
|
||||
4. **Database Migration**:
|
||||
- Thêm schema mới cho identity, access, governance
|
||||
- Giữ nguyên các tables hiện có (backward compatible)
|
||||
5. **Gradual Rollout**:
|
||||
- Phase 1: Deploy cùng auth-service (dual deployment)
|
||||
- Phase 2: Migrate clients dần dần
|
||||
- Phase 3: Deprecate auth-service khi migration hoàn tất
|
||||
|
||||
---
|
||||
|
||||
## Kết Luận
|
||||
|
||||
Đề xuất này mở rộng `auth-service` thành `IAM Service` với đầy đủ các tính năng:
|
||||
- **Identity Management** đầy đủ
|
||||
- **Access Management** nâng cao
|
||||
- **Governance & Compliance** toàn diện
|
||||
- **Workflow automation** linh hoạt
|
||||
|
||||
Điều này biến service từ authentication/authorization cơ bản thành một IAM platform toàn diện, phù hợp cho enterprise.
|
||||
@@ -38,7 +38,7 @@ docker-compose up -d
|
||||
|
||||
```bash
|
||||
# Tạo Kubernetes secret
|
||||
kubectl create secret generic auth-service-secrets \
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='postgresql://user:pass@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true' \
|
||||
--from-literal=jwt-secret='your-staging-jwt-secret' \
|
||||
--from-literal=jwt-refresh-secret='your-staging-refresh-secret' \
|
||||
@@ -72,7 +72,7 @@ kubectl apply -f deployments/staging/kubernetes/
|
||||
|
||||
```bash
|
||||
# Tạo Kubernetes secret
|
||||
kubectl create secret generic auth-service-secrets \
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='postgresql://user:pass@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true' \
|
||||
--from-literal=jwt-secret='your-production-jwt-secret' \
|
||||
--from-literal=jwt-refresh-secret='your-production-refresh-secret' \
|
||||
@@ -90,7 +90,7 @@ kubectl create secret generic auth-service-secrets \
|
||||
### Rollback
|
||||
|
||||
```bash
|
||||
kubectl rollout undo deployment/auth-service -n production
|
||||
kubectl rollout undo deployment/iam-service -n production
|
||||
```
|
||||
|
||||
## Health Checks
|
||||
|
||||
@@ -33,7 +33,7 @@ git checkout -b feature/my-feature
|
||||
pnpm test
|
||||
|
||||
# Service cụ thể
|
||||
pnpm --filter @goodgo/auth-service test
|
||||
pnpm --filter @goodgo/iam-service test
|
||||
```
|
||||
|
||||
### 4. Lint và Format
|
||||
@@ -75,14 +75,14 @@ pnpm format
|
||||
|
||||
```bash
|
||||
# Tạo migration (dev)
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# Áp dụng migrations (production)
|
||||
./scripts/db/migrate.sh auth-service deploy
|
||||
./scripts/db/migrate.sh iam-service deploy
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
- Sử dụng logger từ `@goodgo/logger`
|
||||
- Kiểm tra Traefik logs: `docker logs traefik-local`
|
||||
- Kiểm tra service logs: `./scripts/dev/logs.sh auth-service`
|
||||
- Kiểm tra service logs: `./scripts/dev/logs.sh iam-service`
|
||||
|
||||
@@ -44,12 +44,12 @@
|
||||
|
||||
5. **Chạy database migrations**
|
||||
```bash
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
6. **Seed database**
|
||||
```bash
|
||||
./scripts/db/seed.sh auth-service
|
||||
./scripts/db/seed.sh iam-service
|
||||
```
|
||||
|
||||
7. **Khởi động tất cả services**
|
||||
|
||||
204
docs/vi/guides/iam-migration.md
Normal file
204
docs/vi/guides/iam-migration.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# Hướng Dẫn Migration: Auth Service → IAM Service
|
||||
|
||||
Tài liệu này hướng dẫn cách migrate từ `auth-service` sang `iam-service`.
|
||||
|
||||
## Tổng Quan
|
||||
|
||||
IAM Service là phiên bản mở rộng của Auth Service với các tính năng bổ sung về Identity Management, Access Management, và Governance & Compliance. Tất cả các API endpoints của Auth Service vẫn được giữ nguyên để đảm bảo backward compatibility.
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
✅ **Tất cả các endpoints hiện tại vẫn hoạt động bình thường:**
|
||||
|
||||
- `/api/v1/auth/*` - Authentication endpoints
|
||||
- `/api/v1/rbac/*` - RBAC endpoints
|
||||
- `/api/v1/mfa/*` - MFA endpoints
|
||||
- `/api/v1/sessions/*` - Session management endpoints
|
||||
- `/api/v1/oidc/*` - OIDC endpoints
|
||||
|
||||
Không có breaking changes. Các clients hiện tại có thể tiếp tục sử dụng các endpoints này mà không cần thay đổi.
|
||||
|
||||
## Các Thay Đổi
|
||||
|
||||
### 1. Service Name
|
||||
|
||||
- **Cũ**: `auth-service`
|
||||
- **Mới**: `iam-service`
|
||||
|
||||
### 2. Package Name
|
||||
|
||||
- **Cũ**: `@goodgo/auth-service`
|
||||
- **Mới**: `@goodgo/iam-service`
|
||||
|
||||
### 3. Database Schema
|
||||
|
||||
Database schema được mở rộng với các models mới nhưng **không xóa hoặc thay đổi** các models hiện có:
|
||||
|
||||
**Models mới được thêm:**
|
||||
- `Organization` - Quản lý tổ chức
|
||||
- `Group` - Quản lý nhóm
|
||||
- `GroupMember` - Thành viên nhóm
|
||||
- `GroupPermission` - Quyền nhóm
|
||||
- `UserProfile` - Profile mở rộng
|
||||
- `IdentityVerification` - Xác thực danh tính
|
||||
- `AccessRequest` - Yêu cầu truy cập
|
||||
- `AccessReview` - Đánh giá truy cập
|
||||
- `ComplianceReport` - Báo cáo tuân thủ
|
||||
- `PolicyTemplate` - Template policy
|
||||
- `RiskScore` - Điểm rủi ro
|
||||
|
||||
**User model được mở rộng:**
|
||||
- Thêm field `organizationId` (optional)
|
||||
- Thêm các relations mới (optional)
|
||||
|
||||
### 4. API Endpoints Mới
|
||||
|
||||
#### Identity Management
|
||||
- `/api/v1/identity/users/*` - User lifecycle management
|
||||
- `/api/v1/identity/users/:id/profile` - Profile management
|
||||
- `/api/v1/identity/verification/*` - Identity verification
|
||||
- `/api/v1/identity/organizations/*` - Organization management
|
||||
- `/api/v1/identity/groups/*` - Group management
|
||||
|
||||
#### Access Management
|
||||
- `/api/v1/access/requests/*` - Access requests
|
||||
- `/api/v1/access/reviews/*` - Access reviews
|
||||
- `/api/v1/access/analytics/*` - Access analytics
|
||||
|
||||
#### Governance
|
||||
- `/api/v1/governance/compliance/*` - Compliance reports
|
||||
- `/api/v1/governance/policies/*` - Policy governance
|
||||
- `/api/v1/governance/risk/*` - Risk management
|
||||
- `/api/v1/governance/reports/*` - Reporting dashboard
|
||||
|
||||
### 5. Environment Variables
|
||||
|
||||
Một số biến môi trường mới có thể được thêm trong tương lai cho các tính năng IAM nâng cao (email service, SMS service, file storage), nhưng không ảnh hưởng đến các biến hiện tại.
|
||||
|
||||
### 6. Deployment Configuration
|
||||
|
||||
**Docker Compose:**
|
||||
- Service name: `auth-service` → `iam-service`
|
||||
- Container name: `auth-service-local` → `iam-service-local`
|
||||
|
||||
**Kubernetes:**
|
||||
- Deployment name: `auth-service` → `iam-service`
|
||||
- Service name: `auth-service` → `iam-service`
|
||||
- ConfigMap: `auth-service-config` → `iam-service-config`
|
||||
- Secrets: `auth-service-secrets` → `iam-service-secrets`
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Step 1: Backup (Quan Trọng!)
|
||||
|
||||
```bash
|
||||
# Backup database
|
||||
pg_dump $DATABASE_URL > auth-service-backup.sql
|
||||
|
||||
# Backup code (nếu cần rollback)
|
||||
cp -r services/auth-service services/auth-service.backup
|
||||
```
|
||||
|
||||
### Step 2: Update Codebase
|
||||
|
||||
1. **Update package references:**
|
||||
```bash
|
||||
# Tìm và thay thế trong code
|
||||
find . -type f -name "*.ts" -o -name "*.js" -o -name "*.json" | xargs sed -i '' 's/@goodgo\/auth-service/@goodgo\/iam-service/g'
|
||||
```
|
||||
|
||||
2. **Update environment variables:**
|
||||
- Update `SERVICE_NAME=iam-service` trong tất cả env files
|
||||
- Update Docker Compose và Kubernetes configs
|
||||
|
||||
3. **Run Prisma migration:**
|
||||
```bash
|
||||
cd services/iam-service
|
||||
pnpm prisma generate
|
||||
pnpm prisma migrate dev --name add_iam_models
|
||||
```
|
||||
|
||||
### Step 3: Deployment
|
||||
|
||||
#### Option A: Blue-Green Deployment (Khuyến Nghị)
|
||||
|
||||
1. **Deploy iam-service mới:**
|
||||
```bash
|
||||
kubectl apply -f deployments/staging/kubernetes/iam-service.yaml
|
||||
```
|
||||
|
||||
2. **Verify iam-service hoạt động tốt**
|
||||
|
||||
3. **Switch traffic:**
|
||||
- Update Ingress để point đến `iam-service`
|
||||
- Hoặc dùng weighted routing để gradually migrate
|
||||
|
||||
4. **Monitor và verify**
|
||||
|
||||
5. **Decommission auth-service cũ sau khi verify**
|
||||
|
||||
#### Option B: In-Place Migration
|
||||
|
||||
1. **Deploy cả `auth-service` và `iam-service` cùng lúc**
|
||||
|
||||
2. **Gradually route traffic từ auth-service sang iam-service**
|
||||
|
||||
3. **Monitor performance và errors**
|
||||
|
||||
4. **Sau khi verify mọi thứ hoạt động tốt, có thể deprecate `auth-service`**
|
||||
|
||||
### Step 4: Rollback (Nếu Cần)
|
||||
|
||||
```bash
|
||||
# Restore database
|
||||
psql $DATABASE_URL < auth-service-backup.sql
|
||||
|
||||
# Switch back to auth-service in docker-compose
|
||||
# hoặc
|
||||
kubectl rollout undo deployment/auth-service
|
||||
```
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
- [ ] All existing endpoints still work
|
||||
- [ ] Database migration successful
|
||||
- [ ] New IAM endpoints working
|
||||
- [ ] No breaking changes in responses
|
||||
- [ ] Performance metrics acceptable
|
||||
- [ ] Error rates normal
|
||||
- [ ] All clients can connect successfully
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Database Migration Issues
|
||||
|
||||
```bash
|
||||
# Check migration status
|
||||
pnpm prisma migrate status
|
||||
|
||||
# Reset migration (DEV ONLY!)
|
||||
pnpm prisma migrate reset
|
||||
```
|
||||
|
||||
### Service Connection Issues
|
||||
|
||||
```bash
|
||||
# Check service health
|
||||
curl http://localhost:5001/health
|
||||
|
||||
# Check logs
|
||||
docker logs iam-service-local
|
||||
# hoặc
|
||||
kubectl logs deployment/iam-service
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
Nếu gặp vấn đề trong quá trình migration, vui lòng:
|
||||
1. Check logs và error messages
|
||||
2. Review migration guide này
|
||||
3. Contact team lead hoặc DevOps team
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2024-12-30
|
||||
@@ -38,7 +38,7 @@ docker-compose logs -f
|
||||
|
||||
### Backend Services
|
||||
|
||||
- **auth-service** (Port 5001): Xác thực và quản lý người dùng
|
||||
- **iam-service** (Port 5001): Xác thực và quản lý người dùng
|
||||
- Routes: `/api/v1/auth`, `/api/v1/users`
|
||||
- Health: http://localhost/api/v1/auth/health
|
||||
|
||||
@@ -84,7 +84,7 @@ CORS_ORIGIN=http://localhost:3000,http://localhost:3001
|
||||
docker-compose up -d
|
||||
|
||||
# Khởi động service cụ thể
|
||||
docker-compose up -d auth-service
|
||||
docker-compose up -d iam-service
|
||||
|
||||
# Dừng tất cả services
|
||||
docker-compose down
|
||||
@@ -96,19 +96,19 @@ docker-compose down -v
|
||||
docker-compose logs -f
|
||||
|
||||
# Xem logs (service cụ thể)
|
||||
docker-compose logs -f auth-service
|
||||
docker-compose logs -f iam-service
|
||||
|
||||
# Restart service
|
||||
docker-compose restart auth-service
|
||||
docker-compose restart iam-service
|
||||
|
||||
# Rebuild service
|
||||
docker-compose up -d --build auth-service
|
||||
docker-compose up -d --build iam-service
|
||||
|
||||
# Kiểm tra trạng thái service
|
||||
docker-compose ps
|
||||
|
||||
# Thực thi lệnh trong container
|
||||
docker-compose exec auth-service sh
|
||||
docker-compose exec iam-service sh
|
||||
```
|
||||
|
||||
## Thêm Service Mới
|
||||
@@ -196,7 +196,7 @@ docker-compose up -d service-name
|
||||
cat .env.local | grep DATABASE_URL
|
||||
|
||||
# Test connection từ service
|
||||
docker-compose exec auth-service sh
|
||||
docker-compose exec iam-service sh
|
||||
```
|
||||
|
||||
### Vấn Đề Kết Nối Redis
|
||||
@@ -240,7 +240,7 @@ docker-compose logs traefik
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ auth-service │ │ web-admin │ │ web-client │
|
||||
│ iam-service │ │ web-admin │ │ web-client │
|
||||
│ :5001 │ │ :3000 │ │ :3001 │
|
||||
└──────┬───────┘ └──────────────┘ └──────────────┘
|
||||
│
|
||||
|
||||
@@ -75,18 +75,18 @@ Mỗi service cần file `.env.local` riêng cho DATABASE_URL và configs cụ t
|
||||
|
||||
```bash
|
||||
# Ví dụ: Auth Service
|
||||
cp services/auth-service/env.local.example services/auth-service/.env.local
|
||||
cp services/iam-service/env.local.example services/iam-service/.env.local
|
||||
```
|
||||
|
||||
Chỉnh sửa `services/auth-service/.env.local`:
|
||||
Chỉnh sửa `services/iam-service/.env.local`:
|
||||
|
||||
```bash
|
||||
# Database riêng cho auth-service
|
||||
# Database riêng cho iam-service
|
||||
DATABASE_URL=postgresql://user:password@ep-xxx.region.neon.tech/goodgo_auth_dev?sslmode=require&pgbouncer=true
|
||||
|
||||
# Service configs
|
||||
PORT=5001
|
||||
SERVICE_NAME=auth-service
|
||||
SERVICE_NAME=iam-service
|
||||
|
||||
# Redis override (native dev - Redis in Docker)
|
||||
REDIS_HOST=localhost
|
||||
@@ -100,13 +100,13 @@ REDIS_HOST=localhost
|
||||
### 4. Chạy Database Migrations
|
||||
|
||||
```bash
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
### 5. Seed Database (Tùy chọn)
|
||||
|
||||
```bash
|
||||
./scripts/db/seed.sh auth-service
|
||||
./scripts/db/seed.sh iam-service
|
||||
```
|
||||
|
||||
## Các Cách Chạy Dự Án
|
||||
@@ -143,10 +143,10 @@ Cách này phù hợp khi bạn chỉ làm việc với 1 service:
|
||||
|
||||
```bash
|
||||
# Sử dụng script
|
||||
./scripts/dev/start-service.sh auth-service
|
||||
./scripts/dev/start-service.sh iam-service
|
||||
|
||||
# Hoặc chạy trực tiếp
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
@@ -169,7 +169,7 @@ docker-compose up -d redis traefik
|
||||
cd ../..
|
||||
|
||||
# Bước 2: Chạy service đang dev với native (hot reload nhanh)
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Bước 3: (Tùy chọn) Chạy services khác trong Docker nếu cần
|
||||
docker-compose -f deployments/local/docker-compose.yml up -d user-service payment-service
|
||||
@@ -178,17 +178,17 @@ docker-compose -f deployments/local/docker-compose.yml up -d user-service paymen
|
||||
**Ví dụ workflow thực tế:**
|
||||
|
||||
```bash
|
||||
# Scenario 1: Chỉ dev auth-service
|
||||
# Scenario 1: Chỉ dev iam-service
|
||||
cd deployments/local && docker-compose up -d redis traefik && cd ../..
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Scenario 2: Dev auth-service + cần web-admin để test
|
||||
# Scenario 2: Dev iam-service + cần web-admin để test
|
||||
cd deployments/local && docker-compose up -d redis traefik && cd ../..
|
||||
pnpm --filter @goodgo/auth-service dev &
|
||||
pnpm --filter @goodgo/iam-service dev &
|
||||
pnpm --filter @goodgo/web-admin dev
|
||||
|
||||
# Scenario 3: Dev frontend, backend chạy Docker
|
||||
cd deployments/local && docker-compose up -d redis traefik auth-service && cd ../..
|
||||
cd deployments/local && docker-compose up -d redis traefik iam-service && cd ../..
|
||||
pnpm --filter @goodgo/web-admin dev
|
||||
```
|
||||
|
||||
@@ -208,7 +208,7 @@ pnpm --filter "./services/*" dev
|
||||
pnpm --filter "./apps/*" dev
|
||||
|
||||
# Chạy service cụ thể với dependencies
|
||||
pnpm --filter @goodgo/auth-service... dev
|
||||
pnpm --filter @goodgo/iam-service... dev
|
||||
```
|
||||
|
||||
### Cách 5: Chạy Với Docker Compose (Full Stack)
|
||||
@@ -262,7 +262,7 @@ Khi các services đang chạy, bạn có thể truy cập:
|
||||
Backend services sử dụng `tsx watch` hoặc `nodemon` để tự động restart khi code thay đổi:
|
||||
|
||||
```bash
|
||||
# Trong services/auth-service/package.json
|
||||
# Trong services/iam-service/package.json
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/index.ts"
|
||||
}
|
||||
@@ -313,19 +313,19 @@ pnpm --filter @goodgo/logger dev
|
||||
**Terminal 2: Watch Tests**
|
||||
```bash
|
||||
# Auto-run tests khi code thay đổi
|
||||
pnpm --filter @goodgo/auth-service test --watch
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
```
|
||||
|
||||
**Terminal 3: Development Tasks**
|
||||
```bash
|
||||
# Prisma Studio
|
||||
pnpm --filter @goodgo/auth-service prisma studio
|
||||
pnpm --filter @goodgo/iam-service prisma studio
|
||||
|
||||
# Xem logs
|
||||
./scripts/dev/logs.sh auth-service
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Migrations
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
#### Option B: Hybrid Development (Selective Services)
|
||||
@@ -336,7 +336,7 @@ pnpm --filter @goodgo/auth-service prisma studio
|
||||
cd deployments/local && docker-compose up -d redis traefik && cd ../..
|
||||
|
||||
# Dev service cụ thể với hot reload
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
```
|
||||
|
||||
**Terminal 2: Frontend (nếu cần)**
|
||||
@@ -347,7 +347,7 @@ pnpm --filter @goodgo/web-admin dev
|
||||
**Terminal 3: Tools & Logs**
|
||||
```bash
|
||||
# Watch tests
|
||||
pnpm --filter @goodgo/auth-service test --watch
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
|
||||
# Xem Docker logs
|
||||
docker logs -f redis-cache-local
|
||||
@@ -363,20 +363,20 @@ pnpm format
|
||||
```bash
|
||||
# Terminal 1
|
||||
cd deployments/local && docker-compose up -d redis traefik && cd ../..
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Terminal 2
|
||||
pnpm --filter @goodgo/auth-service test --watch
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
|
||||
# Terminal 3
|
||||
pnpm --filter @goodgo/auth-service prisma studio
|
||||
pnpm --filter @goodgo/iam-service prisma studio
|
||||
```
|
||||
|
||||
#### Use Case 2: Dev Frontend + Backend
|
||||
|
||||
```bash
|
||||
# Terminal 1: Backend
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Terminal 2: Frontend
|
||||
pnpm --filter @goodgo/web-admin dev
|
||||
@@ -427,7 +427,7 @@ Truy cập http://localhost:8080 để xem:
|
||||
```bash
|
||||
# 1. Chỉnh sửa prisma/schema.prisma
|
||||
# 2. Tạo và áp dụng migration
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate dev --name add_new_field
|
||||
|
||||
# 3. Prisma Client sẽ tự động regenerate
|
||||
@@ -436,7 +436,7 @@ pnpm prisma migrate dev --name add_new_field
|
||||
### Reset Database (Development Only!)
|
||||
|
||||
```bash
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate reset
|
||||
```
|
||||
|
||||
@@ -444,7 +444,7 @@ pnpm prisma migrate reset
|
||||
|
||||
```bash
|
||||
# Mở Prisma Studio
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma studio
|
||||
# Truy cập: http://localhost:5555
|
||||
```
|
||||
@@ -464,7 +464,7 @@ Tạo file `.vscode/launch.json`:
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["--filter", "@goodgo/auth-service", "dev"],
|
||||
"runtimeArgs": ["--filter", "@goodgo/iam-service", "dev"],
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
@@ -476,10 +476,10 @@ Tạo file `.vscode/launch.json`:
|
||||
|
||||
```bash
|
||||
# Service logs
|
||||
./scripts/dev/logs.sh auth-service
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Docker logs
|
||||
docker logs -f auth-service-local
|
||||
docker logs -f iam-service-local
|
||||
docker logs -f redis-cache-local
|
||||
docker logs -f traefik-local
|
||||
|
||||
@@ -519,16 +519,16 @@ docker-compose -f deployments/local/docker-compose.yml restart
|
||||
|
||||
```bash
|
||||
# Kiểm tra DATABASE_URL trong service-specific env
|
||||
cat services/auth-service/.env.local | grep DATABASE_URL
|
||||
cat services/iam-service/.env.local | grep DATABASE_URL
|
||||
|
||||
# Nếu chưa có file .env.local, tạo từ example
|
||||
cp services/auth-service/env.local.example services/auth-service/.env.local
|
||||
cp services/iam-service/env.local.example services/iam-service/.env.local
|
||||
|
||||
# Chỉnh sửa DATABASE_URL với connection string từ Neon
|
||||
# DATABASE_URL=postgresql://user:pass@ep-xxx.neon.tech/goodgo_auth_dev?sslmode=require&pgbouncer=true
|
||||
|
||||
# Test connection
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma db pull
|
||||
```
|
||||
|
||||
@@ -557,7 +557,7 @@ pnpm install
|
||||
pnpm dev
|
||||
|
||||
# Hoặc restart Docker container
|
||||
docker-compose -f deployments/local/docker-compose.yml restart auth-service
|
||||
docker-compose -f deployments/local/docker-compose.yml restart iam-service
|
||||
```
|
||||
|
||||
## Tips & Best Practices
|
||||
@@ -579,18 +579,18 @@ pnpm dev
|
||||
Không cần chạy tất cả nếu chỉ làm 1 service:
|
||||
|
||||
```bash
|
||||
# Chỉ chạy auth-service
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
# Chỉ chạy iam-service
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Chạy auth-service và dependencies
|
||||
pnpm --filter @goodgo/auth-service... dev
|
||||
# Chạy iam-service và dependencies
|
||||
pnpm --filter @goodgo/iam-service... dev
|
||||
```
|
||||
|
||||
### 3. Watch Tests
|
||||
|
||||
```bash
|
||||
# Chạy tests tự động khi code thay đổi
|
||||
pnpm --filter @goodgo/auth-service test --watch
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
```
|
||||
|
||||
### 4. Format Code Tự Động
|
||||
@@ -613,7 +613,7 @@ Kết hợp Docker và Native để tối ưu workflow:
|
||||
cd deployments/local && docker-compose up -d redis traefik
|
||||
|
||||
# Service đang dev chạy native (hot reload nhanh)
|
||||
pnpm --filter @goodgo/auth-service dev
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Services khác có thể chạy Docker nếu cần
|
||||
docker-compose up -d user-service payment-service
|
||||
@@ -629,7 +629,7 @@ docker-compose up -d user-service payment-service
|
||||
|
||||
```bash
|
||||
# Chạy selective services với pnpm workspace
|
||||
pnpm --filter "@goodgo/auth-service" --filter "@goodgo/user-service" dev
|
||||
pnpm --filter "@goodgo/iam-service" --filter "@goodgo/user-service" dev
|
||||
|
||||
# Hoặc dùng pattern
|
||||
pnpm --filter "./services/{auth,user}-service" dev
|
||||
@@ -673,14 +673,14 @@ cp deployments/local/env.local.example deployments/local/.env.local
|
||||
Configs riêng cho từng service:
|
||||
|
||||
```bash
|
||||
# services/auth-service/.env.local
|
||||
# services/iam-service/.env.local
|
||||
|
||||
# Database riêng cho service này
|
||||
DATABASE_URL=postgresql://user:pass@ep-xxx.neon.tech/goodgo_auth_dev?sslmode=require&pgbouncer=true
|
||||
|
||||
# Service configs
|
||||
PORT=5001
|
||||
SERVICE_NAME=auth-service
|
||||
SERVICE_NAME=iam-service
|
||||
API_VERSION=v1
|
||||
|
||||
# Redis override (native dev - Redis in Docker)
|
||||
@@ -693,7 +693,7 @@ PROMETHEUS_PORT=9090
|
||||
|
||||
**Tạo file:**
|
||||
```bash
|
||||
cp services/auth-service/env.local.example services/auth-service/.env.local
|
||||
cp services/iam-service/env.local.example services/iam-service/.env.local
|
||||
```
|
||||
|
||||
### Cách Hoạt Động
|
||||
@@ -737,9 +737,9 @@ pnpm clean # Xóa build artifacts
|
||||
./scripts/utils/cleanup.sh # Cleanup toàn bộ
|
||||
|
||||
# Database
|
||||
./scripts/db/migrate.sh auth-service dev # Migration
|
||||
./scripts/db/seed.sh auth-service # Seed data
|
||||
./scripts/db/backup.sh auth-service # Backup
|
||||
./scripts/db/migrate.sh iam-service dev # Migration
|
||||
./scripts/db/seed.sh iam-service # Seed data
|
||||
./scripts/db/backup.sh iam-service # Backup
|
||||
|
||||
# Docker
|
||||
docker-compose -f deployments/local/docker-compose.yml up -d # Start
|
||||
|
||||
@@ -44,7 +44,7 @@ DATABASE_URL=postgresql://user:pass@ep-xxx.region.neon.tech/dbname?sslmode=requi
|
||||
### 5. Chạy Migrations
|
||||
|
||||
```bash
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
## Định Dạng Connection String
|
||||
@@ -73,7 +73,7 @@ Lưu trong GitHub Secrets: `NEON_DATABASE_URL_STAGING`
|
||||
|
||||
Hoặc trong Kubernetes:
|
||||
```bash
|
||||
kubectl create secret generic auth-service-secrets \
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='postgresql://...' \
|
||||
-n staging
|
||||
```
|
||||
@@ -84,7 +84,7 @@ Lưu trong GitHub Secrets: `NEON_DATABASE_URL_PRODUCTION`
|
||||
|
||||
Hoặc trong Kubernetes:
|
||||
```bash
|
||||
kubectl create secret generic auth-service-secrets \
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='postgresql://...' \
|
||||
-n production
|
||||
```
|
||||
@@ -95,7 +95,7 @@ kubectl create secret generic auth-service-secrets \
|
||||
|
||||
```bash
|
||||
# Tạo migration mới
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# Điều này sẽ:
|
||||
# 1. Tạo migration file
|
||||
@@ -111,7 +111,7 @@ Migrations chạy tự động trong CI/CD:
|
||||
|
||||
Migration thủ công:
|
||||
```bash
|
||||
./scripts/db/migrate.sh auth-service deploy
|
||||
./scripts/db/migrate.sh iam-service deploy
|
||||
```
|
||||
|
||||
## Backup & Restore
|
||||
@@ -126,7 +126,7 @@ Neon cung cấp backup tự động. Truy cập qua Neon Console:
|
||||
### Backup Thủ Công
|
||||
|
||||
```bash
|
||||
./scripts/db/backup.sh auth-service
|
||||
./scripts/db/backup.sh iam-service
|
||||
```
|
||||
|
||||
Điều này tạo file SQL dump trong thư mục `backups/`.
|
||||
|
||||
@@ -66,13 +66,13 @@ Trong giao diện **Explore** với **Loki** đã chọn:
|
||||
|
||||
1. Nhấn nút **Label browser**.
|
||||
2. Chọn một label, ví dụ: `container`.
|
||||
3. Chọn tên container cụ thể (ví dụ: `auth-service` hoặc `traefik`).
|
||||
3. Chọn tên container cụ thể (ví dụ: `iam-service` hoặc `traefik`).
|
||||
4. Nhấn **Show logs**.
|
||||
|
||||
Bạn cũng có thể viết truy vấn LogQL thủ công, ví dụ:
|
||||
|
||||
```logql
|
||||
{container="auth-service"}
|
||||
{container="iam-service"}
|
||||
```
|
||||
|
||||
### Xem Metrics (Prometheus)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
**Giải pháp**:
|
||||
```bash
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma generate
|
||||
```
|
||||
|
||||
|
||||
@@ -51,13 +51,13 @@ Chào mừng đến với team GoodGo Microservices Platform!
|
||||
./scripts/dev/start-all.sh
|
||||
|
||||
# Khởi động service cụ thể
|
||||
./scripts/dev/start-service.sh auth-service
|
||||
./scripts/dev/start-service.sh iam-service
|
||||
|
||||
# Xem logs
|
||||
./scripts/dev/logs.sh auth-service
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Chạy migrations
|
||||
./scripts/db/migrate.sh auth-service dev
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# Chạy tests
|
||||
pnpm test
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
|
||||
1. **Xác định phiên bản hiện tại**
|
||||
```bash
|
||||
kubectl get deployment auth-service -n production -o jsonpath='{.spec.template.spec.containers[0].image}'
|
||||
kubectl get deployment iam-service -n production -o jsonpath='{.spec.template.spec.containers[0].image}'
|
||||
```
|
||||
|
||||
2. **Rollback về phiên bản trước**
|
||||
```bash
|
||||
kubectl rollout undo deployment/auth-service -n production
|
||||
kubectl rollout undo deployment/iam-service -n production
|
||||
```
|
||||
|
||||
3. **Xác minh rollback**
|
||||
```bash
|
||||
kubectl rollout status deployment/auth-service -n production
|
||||
kubectl rollout status deployment/iam-service -n production
|
||||
```
|
||||
|
||||
4. **Kiểm tra health của service**
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
1. Tạo migration đảo ngược:
|
||||
```bash
|
||||
cd services/auth-service
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate dev --name rollback_previous_change
|
||||
```
|
||||
|
||||
|
||||
129
docs/vi/skills/README.md
Normal file
129
docs/vi/skills/README.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Tài Liệu Cursor Skills
|
||||
|
||||
> **EN**: Comprehensive documentation for all Cursor AI skills used in the GoodGo Microservices Platform
|
||||
> **VI**: Tài liệu đầy đủ cho tất cả Cursor AI skills được sử dụng trong GoodGo Microservices Platform
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: Cursor Skills are specialized knowledge modules that guide AI assistants in following project-specific patterns, standards, and best practices. This directory contains detailed documentation for each skill, including when to use them, key concepts, common patterns, and real-world examples from the codebase.
|
||||
|
||||
**VI**: Cursor Skills là các module kiến thức chuyên biệt hướng dẫn AI assistants tuân theo các patterns, tiêu chuẩn và best practices cụ thể của dự án. Thư mục này chứa tài liệu chi tiết cho từng skill, bao gồm khi nào sử dụng, khái niệm chính, các pattern thường dùng, và ví dụ thực tế từ codebase.
|
||||
|
||||
## Available Skills / Các Skills Có Sẵn
|
||||
|
||||
GoodGo platform bao gồm **9 Cursor Skills** được tổ chức theo danh mục:
|
||||
|
||||
### API & Data Layer
|
||||
|
||||
#### [API Design](./api-design.md)
|
||||
**EN**: RESTful API design standards for GoodGo microservices. Use when creating new API endpoints, designing DTOs, implementing controllers, writing OpenAPI documentation, or standardizing API responses.
|
||||
|
||||
**VI**: Tiêu chuẩn thiết kế RESTful API cho GoodGo microservices. Sử dụng khi tạo API endpoints mới, thiết kế DTOs, implement controllers, viết OpenAPI documentation, hoặc chuẩn hóa API responses.
|
||||
|
||||
#### [Database & Prisma](./database-prisma.md)
|
||||
**EN**: Prisma ORM and database patterns for GoodGo microservices. Use when working with databases, creating Prisma schemas, writing migrations, implementing repositories, or optimizing queries.
|
||||
|
||||
**VI**: Prisma ORM và database patterns cho GoodGo microservices. Sử dụng khi làm việc với databases, tạo Prisma schemas, viết migrations, implement repositories, hoặc optimize queries.
|
||||
|
||||
### Code Quality & Testing
|
||||
|
||||
#### [Testing Patterns](./testing-patterns.md)
|
||||
**EN**: Testing best practices for GoodGo microservices. Use when writing unit tests, integration tests, E2E tests, setting up Jest, mocking dependencies, or debugging test failures.
|
||||
|
||||
**VI**: Best practices về testing cho GoodGo microservices. Sử dụng khi viết unit tests, integration tests, E2E tests, setup Jest, mocking dependencies, hoặc debug test failures.
|
||||
|
||||
#### [Code Comments](./comment-code.md)
|
||||
**EN**: Add bilingual code comments in Vietnamese and English for better documentation. Use when adding comments to code, documenting functions/classes, or when user requests Vietnamese/English documentation.
|
||||
|
||||
**VI**: Thêm code comments song ngữ bằng tiếng Việt và tiếng Anh để tài liệu tốt hơn. Sử dụng khi thêm comments vào code, document functions/classes, hoặc khi user yêu cầu tài liệu tiếng Việt/Anh.
|
||||
|
||||
### Infrastructure & Operations
|
||||
|
||||
#### [Kubernetes Deployment](./deployment-kubernetes.md)
|
||||
**EN**: Kubernetes deployment patterns for GoodGo microservices. Use when deploying to staging/production, creating K8s manifests, configuring HPA, setting up ingress, or troubleshooting K8s deployments.
|
||||
|
||||
**VI**: Kubernetes deployment patterns cho GoodGo microservices. Sử dụng khi deploy lên staging/production, tạo K8s manifests, config HPA, setup ingress, hoặc troubleshoot K8s deployments.
|
||||
|
||||
#### [Observability & Monitoring](./observability-monitoring.md)
|
||||
**EN**: Observability and monitoring patterns for GoodGo microservices. Use when adding metrics, implementing logging, setting up tracing, creating health checks, or debugging production issues.
|
||||
|
||||
**VI**: Observability và monitoring patterns cho GoodGo microservices. Sử dụng khi thêm metrics, implement logging, setup tracing, tạo health checks, hoặc debug production issues.
|
||||
|
||||
### Standards & Security
|
||||
|
||||
#### [Project Rules](./project-rules.md)
|
||||
**EN**: GoodGo Microservices Platform coding standards and architecture patterns. Use when working with services, apps, packages, or infrastructure.
|
||||
|
||||
**VI**: Tiêu chuẩn coding và architecture patterns của GoodGo Microservices Platform. Sử dụng khi làm việc với services, apps, packages, hoặc infrastructure.
|
||||
|
||||
#### [Security](./security.md)
|
||||
**EN**: Security best practices and patterns for GoodGo microservices platform. Use when implementing authentication, authorization, data protection, input validation, rate limiting, secrets management, or security testing across all services.
|
||||
|
||||
**VI**: Security best practices và patterns cho GoodGo microservices platform. Sử dụng khi implement authentication, authorization, data protection, input validation, rate limiting, secrets management, hoặc security testing trên tất cả services.
|
||||
|
||||
#### [Documentation](./documentation.md)
|
||||
**EN**: Guidelines for writing technical documentation in the GoodGo project. Use when creating or updating README files, guides, architecture docs, or API documentation. Ensures bilingual (EN/VI) consistency and proper structure.
|
||||
|
||||
**VI**: Hướng dẫn viết technical documentation trong dự án GoodGo. Sử dụng khi tạo hoặc cập nhật README files, guides, architecture docs, hoặc API documentation. Đảm bảo tính nhất quán song ngữ (EN/VI) và cấu trúc phù hợp.
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### By Use Case / Theo Use Case
|
||||
|
||||
| Tác Vụ | Skills Đề Xuất |
|
||||
|--------|----------------|
|
||||
| Tạo API endpoint mới | API Design, Security, Testing Patterns |
|
||||
| Setup service mới | Project Rules, Database & Prisma, Observability |
|
||||
| Viết tests | Testing Patterns, Comment Code |
|
||||
| Deploy lên production | Kubernetes Deployment, Observability, Security |
|
||||
| Debug production issues | Observability & Monitoring, Security |
|
||||
| Viết documentation | Documentation, Comment Code |
|
||||
| Implement authentication | Security, API Design, Database & Prisma |
|
||||
| Optimize database queries | Database & Prisma, Observability |
|
||||
|
||||
### Skill Dependencies / Phụ Thuộc Giữa Các Skills
|
||||
|
||||
```
|
||||
Project Rules (Foundation)
|
||||
├── API Design
|
||||
├── Database & Prisma
|
||||
├── Security
|
||||
└── Testing Patterns
|
||||
└── Comment Code
|
||||
Documentation (Cross-cutting)
|
||||
└── All skills
|
||||
Observability (Cross-cutting)
|
||||
└── All services
|
||||
Kubernetes Deployment (Infrastructure)
|
||||
└── All services
|
||||
```
|
||||
|
||||
## How to Use Skills / Cách Sử Dụng Skills
|
||||
|
||||
1. **Khi bắt đầu task mới**: Xem lại các skills liên quan trong thư mục này
|
||||
2. **Trong quá trình development**: Tham khảo skill documentation để xem patterns và examples
|
||||
3. **Khi gặp khó khăn**: Kiểm tra skill docs để xem best practices và solutions thường dùng
|
||||
4. **Khi code review**: Sử dụng skills như checklist để đảm bảo tuân thủ standards
|
||||
|
||||
## Related Documentation / Tài Liệu Liên Quan
|
||||
|
||||
- [Tổng Quan Kiến Trúc](../architecture/system-design.md) - System design patterns
|
||||
- [Hướng Dẫn Development](../guides/development.md) - Development workflow
|
||||
- [Hướng Dẫn Deployment](../guides/deployment.md) - Deployment procedures
|
||||
- [Tài Liệu API](../api/openapi/) - OpenAPI specifications
|
||||
|
||||
## Contributing / Đóng Góp
|
||||
|
||||
Khi cập nhật hoặc thêm skills mới:
|
||||
|
||||
1. Cập nhật skill source file trong `.cursor/skills/{skill-name}/SKILL.md`
|
||||
2. Cập nhật documentation tương ứng trong `docs/en/skills/{skill-name}.md`
|
||||
3. Cập nhật bản dịch tiếng Việt trong `docs/vi/skills/{skill-name}.md`
|
||||
4. Cập nhật file index này với mọi thay đổi
|
||||
5. Đảm bảo tính nhất quán song ngữ
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
- [Cursor Skills Documentation](https://cursor.sh/docs) - Tài liệu chính thức của Cursor
|
||||
- [Cursor AI](https://cursor.sh) - Trang chủ Cursor IDE
|
||||
- Project Skills: `.cursor/skills/` - Source skill files
|
||||
455
docs/vi/skills/api-design.md
Normal file
455
docs/vi/skills/api-design.md
Normal file
@@ -0,0 +1,455 @@
|
||||
# RESTful API Design / Thiết Kế API RESTful
|
||||
|
||||
> **EN**: RESTful API design standards for GoodGo microservices. Use when creating new API endpoints, designing DTOs, implementing controllers, writing OpenAPI documentation, or standardizing API responses.
|
||||
> **VI**: Tiêu chuẩn thiết kế API RESTful cho các microservices của GoodGo. Sử dụng khi tạo endpoint API mới, thiết kế DTOs, triển khai controllers, viết tài liệu OpenAPI, hoặc chuẩn hóa response API.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: This skill covers the RESTful API design patterns and standards used across all GoodGo microservices. It ensures consistency, predictability, and maintainability of APIs through standardized URL structures, HTTP methods, response formats, error handling, and DTO validation.
|
||||
|
||||
**VI**: Skill này bao gồm các pattern và tiêu chuẩn thiết kế API RESTful được sử dụng trong tất cả các microservices của GoodGo. Nó đảm bảo tính nhất quán, dự đoán được và dễ bảo trì của APIs thông qua cấu trúc URL chuẩn hóa, HTTP methods, định dạng response, xử lý lỗi và validation DTO.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Creating new API endpoints
|
||||
- Designing request/response DTOs
|
||||
- Implementing controllers and routes
|
||||
- Writing OpenAPI/Swagger documentation
|
||||
- Standardizing error responses
|
||||
- Implementing pagination, filtering, and sorting
|
||||
- Setting up API versioning
|
||||
- Designing resource relationships
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Tạo endpoint API mới
|
||||
- Thiết kế DTOs cho request/response
|
||||
- Triển khai controllers và routes
|
||||
- Viết tài liệu OpenAPI/Swagger
|
||||
- Chuẩn hóa error responses
|
||||
- Triển khai pagination, filtering và sorting
|
||||
- Thiết lập API versioning
|
||||
- Thiết kế quan hệ giữa các resources
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### 1. URL Structure / Cấu Trúc URL
|
||||
|
||||
**EN**: URLs follow a hierarchical resource-based structure with versioning.
|
||||
|
||||
**VI**: URLs tuân theo cấu trúc phân cấp dựa trên resource với versioning.
|
||||
|
||||
```
|
||||
https://api.goodgo.com/v1/{resource}/{id}/{sub-resource}
|
||||
|
||||
Examples:
|
||||
GET /v1/users # List users / Liệt kê users
|
||||
POST /v1/users # Create user / Tạo user
|
||||
GET /v1/users/123 # Get user by ID / Lấy user theo ID
|
||||
PUT /v1/users/123 # Update user / Cập nhật user
|
||||
DELETE /v1/users/123 # Delete user / Xóa user
|
||||
GET /v1/users/123/orders # Get user's orders / Lấy orders của user
|
||||
POST /v1/users/123/orders # Create order for user / Tạo order cho user
|
||||
```
|
||||
|
||||
### 2. HTTP Methods / Phương Thức HTTP
|
||||
|
||||
- **GET**: Retrieve resource(s) - Safe, Idempotent / Lấy resource(s) - An toàn, Idempotent
|
||||
- **POST**: Create new resource - Not idempotent / Tạo resource mới - Không idempotent
|
||||
- **PUT**: Full update - Idempotent / Cập nhật toàn bộ - Idempotent
|
||||
- **PATCH**: Partial update - Idempotent / Cập nhật một phần - Idempotent
|
||||
- **DELETE**: Remove resource - Idempotent / Xóa resource - Idempotent
|
||||
|
||||
### 3. Standard Response Format / Định Dạng Response Chuẩn
|
||||
|
||||
**EN**: All API responses follow a consistent structure with `success`, `data`, and optional `metadata` fields.
|
||||
|
||||
**VI**: Tất cả API responses tuân theo cấu trúc nhất quán với các trường `success`, `data`, và `metadata` tùy chọn.
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Success Response Pattern / Pattern Response Thành Công
|
||||
|
||||
```typescript
|
||||
interface SuccessResponse<T> {
|
||||
success: true;
|
||||
data: T;
|
||||
message?: string;
|
||||
timestamp?: string;
|
||||
pagination?: {
|
||||
total: number;
|
||||
skip: number;
|
||||
take: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/identity/user/user.controller.ts
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
users: result.users,
|
||||
pagination: {
|
||||
total: result.total,
|
||||
skip: filters.skip,
|
||||
take: filters.take,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Error Response Pattern / Pattern Response Lỗi
|
||||
|
||||
```typescript
|
||||
interface ErrorResponse {
|
||||
success: false;
|
||||
error: {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: any;
|
||||
field?: string;
|
||||
};
|
||||
timestamp?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/identity/user/user.controller.ts
|
||||
if (error instanceof z.ZodError) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Invalid filters',
|
||||
details: error.errors,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP Status Codes / Mã Trạng Thái HTTP
|
||||
|
||||
```typescript
|
||||
// Success codes / Mã thành công
|
||||
200 OK // GET, PUT, PATCH success
|
||||
201 Created // POST success with resource creation
|
||||
204 No Content // DELETE success
|
||||
|
||||
// Client errors / Lỗi client
|
||||
400 Bad Request // Invalid request data / Dữ liệu request không hợp lệ
|
||||
401 Unauthorized // Missing/invalid authentication / Thiếu/sai xác thực
|
||||
403 Forbidden // Valid auth but no permission / Xác thực hợp lệ nhưng không có quyền
|
||||
404 Not Found // Resource doesn't exist / Resource không tồn tại
|
||||
409 Conflict // Resource conflict (duplicate) / Xung đột resource (trùng lặp)
|
||||
422 Unprocessable // Validation errors / Lỗi validation
|
||||
|
||||
// Server errors / Lỗi server
|
||||
500 Internal Error // Unexpected server error / Lỗi server không mong đợi
|
||||
502 Bad Gateway // External service error / Lỗi dịch vụ bên ngoài
|
||||
503 Service Unavailable // Service temporarily down / Dịch vụ tạm thời không khả dụng
|
||||
```
|
||||
|
||||
### DTOs with Zod Validation / DTOs với Zod Validation
|
||||
|
||||
**EN**: DTOs use Zod for runtime validation with bilingual error messages.
|
||||
|
||||
**VI**: DTOs sử dụng Zod cho validation runtime với thông báo lỗi song ngữ.
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/identity/identity.dto.ts
|
||||
import { z } from 'zod';
|
||||
|
||||
export const CreateOrganizationDto = z.object({
|
||||
name: z.string().min(1, 'Organization name is required / Tên tổ chức là bắt buộc').max(255),
|
||||
domain: z.string().email().optional().or(z.string().min(1).max(255).optional()),
|
||||
parentId: z.string().optional(),
|
||||
settings: z.record(z.any()).optional(),
|
||||
});
|
||||
|
||||
export type CreateOrganizationDto = z.infer<typeof CreateOrganizationDto>;
|
||||
|
||||
export const UserFiltersDto = z.object({
|
||||
organizationId: z.string().optional(),
|
||||
isActive: z.boolean().optional(),
|
||||
emailVerified: z.boolean().optional(),
|
||||
search: z.string().optional(),
|
||||
skip: z.number().int().min(0).default(0),
|
||||
take: z.number().int().min(1).max(100).default(20),
|
||||
});
|
||||
```
|
||||
|
||||
### Controller Implementation Pattern / Pattern Triển Khai Controller
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/identity/user/user.controller.ts
|
||||
export class UserManagementController {
|
||||
/**
|
||||
* EN: List users
|
||||
* VI: Liệt kê users
|
||||
*/
|
||||
async list(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const filters = UserFiltersDto.parse({
|
||||
organizationId: req.query.organizationId as string,
|
||||
isActive: req.query.isActive === 'true' ? true : req.query.isActive === 'false' ? false : undefined,
|
||||
emailVerified: req.query.emailVerified === 'true' ? true : req.query.emailVerified === 'false' ? false : undefined,
|
||||
search: req.query.search as string,
|
||||
skip: parseInt(req.query.skip as string) || 0,
|
||||
take: parseInt(req.query.take as string) || 20,
|
||||
});
|
||||
|
||||
const result = await userManagementService.searchUsers(filters);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
users: result.users,
|
||||
pagination: {
|
||||
total: result.total,
|
||||
skip: filters.skip,
|
||||
take: filters.take,
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
if (error instanceof z.ZodError) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Invalid filters',
|
||||
details: error.errors,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'LIST_USERS_FAILED',
|
||||
message: error.message || 'Failed to list users',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Get user by ID
|
||||
* VI: Lấy user theo ID
|
||||
*/
|
||||
async get(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const user = await userManagementService.getUser(id);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: user,
|
||||
});
|
||||
} catch (error: any) {
|
||||
if (error instanceof NotFoundError) {
|
||||
res.status(404).json(error.toApiResponse());
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'GET_USER_FAILED',
|
||||
message: error.message || 'Failed to get user',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling with Custom Error Classes / Xử Lý Lỗi với Custom Error Classes
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/errors/http-error.ts
|
||||
export class HttpError extends Error {
|
||||
public readonly statusCode: number;
|
||||
public readonly errorCode: string;
|
||||
public readonly isOperational: boolean;
|
||||
public readonly details?: any;
|
||||
|
||||
constructor(
|
||||
message: string,
|
||||
statusCode: number = 500,
|
||||
errorCode: string = 'INTERNAL_ERROR',
|
||||
isOperational: boolean = true,
|
||||
details?: any
|
||||
) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
this.statusCode = statusCode;
|
||||
this.errorCode = errorCode;
|
||||
this.isOperational = isOperational;
|
||||
this.details = details;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
|
||||
toApiResponse() {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: this.errorCode,
|
||||
message: this.message,
|
||||
...(this.details && { details: this.details }),
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class NotFoundError extends HttpError {
|
||||
constructor(resource: string = 'Resource / Tài nguyên', details?: any) {
|
||||
super(`${resource} not found / ${resource} không tìm thấy`, 404, 'NOT_FOUND', true, details);
|
||||
}
|
||||
}
|
||||
|
||||
export class ValidationError extends HttpError {
|
||||
constructor(message: string = 'Validation failed / Validation thất bại', details?: any) {
|
||||
super(message, 422, 'VALIDATION_ERROR', true, details);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### 1. Resource Naming / Đặt Tên Resource
|
||||
|
||||
- ✅ Use plural nouns (`/users` not `/user`) / Sử dụng danh từ số nhiều
|
||||
- ✅ Use kebab-case for multi-word resources (`/user-profiles`) / Sử dụng kebab-case cho resource nhiều từ
|
||||
- ✅ Keep URLs as short as possible / Giữ URLs ngắn gọn nhất có thể
|
||||
- ❌ Avoid verbs in URLs (use HTTP methods instead) / Tránh động từ trong URLs (dùng HTTP methods thay thế)
|
||||
|
||||
### 2. Versioning / Phiên Bản Hóa
|
||||
|
||||
- ✅ Include version in URL (`/v1/users`) / Bao gồm version trong URL
|
||||
- ✅ Maintain backward compatibility / Duy trì tương thích ngược
|
||||
- ✅ Deprecate old versions gracefully with warnings / Ngừng hỗ trợ các version cũ một cách lịch sự với cảnh báo
|
||||
|
||||
### 3. Security / Bảo Mật
|
||||
|
||||
- ✅ Always use HTTPS / Luôn sử dụng HTTPS
|
||||
- ✅ Implement rate limiting / Triển khai rate limiting
|
||||
- ✅ Validate all inputs with DTOs / Validate tất cả inputs với DTOs
|
||||
- ✅ Use proper authentication/authorization middleware / Sử dụng middleware xác thực/ủy quyền phù hợp
|
||||
- ✅ Never expose sensitive data in responses / Không bao giờ expose dữ liệu nhạy cảm trong responses
|
||||
|
||||
### 4. Performance / Hiệu Năng
|
||||
|
||||
- ✅ Implement pagination for lists (use `skip` and `take`) / Triển khai pagination cho danh sách
|
||||
- ✅ Use field filtering when possible (`select` in Prisma) / Sử dụng field filtering khi có thể
|
||||
- ✅ Cache responses appropriately / Cache responses phù hợp
|
||||
- ✅ Compress responses (gzip) / Nén responses (gzip)
|
||||
|
||||
### 5. Documentation / Tài Liệu
|
||||
|
||||
- ✅ Keep OpenAPI spec up to date / Giữ OpenAPI spec cập nhật
|
||||
- ✅ Include examples in documentation / Bao gồm ví dụ trong tài liệu
|
||||
- ✅ Document error responses / Tài liệu hóa error responses
|
||||
- ✅ Version your documentation / Phiên bản hóa tài liệu
|
||||
|
||||
### 6. Error Handling / Xử Lý Lỗi
|
||||
|
||||
- ✅ Use consistent error response format / Sử dụng định dạng error response nhất quán
|
||||
- ✅ Provide actionable error messages / Cung cấp thông báo lỗi có thể hành động
|
||||
- ✅ Include error codes for programmatic handling / Bao gồm error codes cho xử lý lập trình
|
||||
- ✅ Log errors server-side, don't expose stack traces in production / Log lỗi phía server, không expose stack traces trong production
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Controller Examples / Ví Dụ Controller
|
||||
|
||||
- **User Management**: [`services/iam-service/src/modules/identity/user/user.controller.ts`](../../../services/iam-service/src/modules/identity/user/user.controller.ts)
|
||||
- **Feature Controller**: [`services/iam-service/src/modules/feature/feature.controller.ts`](../../../services/iam-service/src/modules/feature/feature.controller.ts)
|
||||
- **RBAC Controller**: [`services/iam-service/src/modules/rbac/rbac.controller.ts`](../../../services/iam-service/src/modules/rbac/rbac.controller.ts)
|
||||
|
||||
### DTO Examples / Ví Dụ DTO
|
||||
|
||||
- **Identity DTOs**: [`services/iam-service/src/modules/identity/identity.dto.ts`](../../../services/iam-service/src/modules/identity/identity.dto.ts)
|
||||
- **Auth DTOs**: [`services/iam-service/src/modules/auth/auth.dto.ts`](../../../services/iam-service/src/modules/auth/auth.dto.ts)
|
||||
- **RBAC DTOs**: [`services/iam-service/src/modules/rbac/rbac.dto.ts`](../../../services/iam-service/src/modules/rbac/rbac.dto.ts)
|
||||
|
||||
### Error Handling Examples / Ví Dụ Xử Lý Lỗi
|
||||
|
||||
- **HTTP Error Classes**: [`services/iam-service/src/errors/http-error.ts`](../../../services/iam-service/src/errors/http-error.ts)
|
||||
- **Error Middleware**: [`services/iam-service/src/middlewares/error.middleware.ts`](../../../services/iam-service/src/middlewares/error.middleware.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Response Format Cheat Sheet / Bảng Tra Cứu Định Dạng Response
|
||||
|
||||
| Scenario / Tình Huống | Status Code | Response Structure / Cấu Trúc Response |
|
||||
|----------------------|-------------|----------------------------------------|
|
||||
| Success (GET) | 200 | `{ success: true, data: {...} }` |
|
||||
| Success (POST) | 201 | `{ success: true, data: {...} }` |
|
||||
| Success (DELETE) | 200 | `{ success: true, message: "..." }` |
|
||||
| Validation Error / Lỗi Validation | 400/422 | `{ success: false, error: { code, message, details } }` |
|
||||
| Not Found | 404 | `{ success: false, error: { code: "NOT_FOUND", message } }` |
|
||||
| Unauthorized | 401 | `{ success: false, error: { code: "UNAUTHORIZED", message } }` |
|
||||
| Forbidden | 403 | `{ success: false, error: { code: "FORBIDDEN", message } }` |
|
||||
| Server Error / Lỗi Server | 500 | `{ success: false, error: { code: "INTERNAL_ERROR", message } }` |
|
||||
|
||||
### Common DTO Patterns / Pattern DTO Thường Dùng
|
||||
|
||||
```typescript
|
||||
// Create DTO / DTO Tạo
|
||||
const CreateDto = z.object({
|
||||
requiredField: z.string().min(1),
|
||||
optionalField: z.string().optional(),
|
||||
});
|
||||
|
||||
// Update DTO (all fields optional) / DTO Cập Nhật (tất cả fields tùy chọn)
|
||||
const UpdateDto = z.object({
|
||||
field1: z.string().optional(),
|
||||
field2: z.number().optional(),
|
||||
});
|
||||
|
||||
// Query/Filter DTO / DTO Query/Filter
|
||||
const QueryDto = z.object({
|
||||
page: z.number().int().min(1).default(1),
|
||||
limit: z.number().int().min(1).max(100).default(20),
|
||||
search: z.string().optional(),
|
||||
sortBy: z.string().optional(),
|
||||
order: z.enum(['asc', 'desc']).default('desc'),
|
||||
});
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Database Prisma](./database-prisma.md)**: For database operations and repository patterns / Cho các thao tác database và repository patterns
|
||||
- **[Security](./security.md)**: For authentication, authorization, and security best practices / Cho xác thực, ủy quyền và thực hành bảo mật tốt nhất
|
||||
- **[Testing Patterns](./testing-patterns.md)**: For testing API endpoints / Cho test API endpoints
|
||||
- **[Documentation](./documentation.md)**: For writing API documentation / Cho viết tài liệu API
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### External Documentation / Tài Liệu Bên Ngoài
|
||||
|
||||
- [REST API Design Best Practices](https://restfulapi.net/)
|
||||
- [HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
|
||||
- [Zod Documentation](https://zod.dev/)
|
||||
- [OpenAPI Specification](https://swagger.io/specification/)
|
||||
|
||||
### Internal Documentation / Tài Liệu Nội Bộ
|
||||
|
||||
- [API Reference](../api/openapi/iam-service.yaml)
|
||||
- [Service Communication](../architecture/service-communication.md)
|
||||
- [Project Rules](./project-rules.md)
|
||||
562
docs/vi/skills/comment-code.md
Normal file
562
docs/vi/skills/comment-code.md
Normal file
@@ -0,0 +1,562 @@
|
||||
# Comment Code / Viết Comment Code
|
||||
|
||||
> **EN**: Guidelines for adding comprehensive bilingual code comments (English and Vietnamese) to improve code readability for international and Vietnamese teams.
|
||||
> **VI**: Hướng dẫn thêm comments song ngữ (tiếng Anh và tiếng Việt) để cải thiện khả năng đọc code cho các đội quốc tế và Việt Nam.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: Code comments are essential for maintaining and understanding codebase, especially in a bilingual development environment. This guide provides comprehensive patterns for writing clear, consistent, and helpful comments in both English and Vietnamese across the GoodGo microservices platform. It covers JSDoc documentation, inline comments, special comment types, and best practices for effective code documentation.
|
||||
|
||||
**VI**: Comments code là điều cần thiết để bảo trì và hiểu codebase, đặc biệt trong môi trường phát triển song ngữ. Hướng dẫn này cung cấp các patterns toàn diện để viết comments rõ ràng, nhất quán và hữu ích bằng cả tiếng Anh và tiếng Việt trên nền tảng microservices GoodGo. Nó bao gồm tài liệu JSDoc, inline comments, các loại comment đặc biệt, và best practices cho tài liệu code hiệu quả.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use bilingual commenting patterns when:
|
||||
- Adding comments to new code
|
||||
- Documenting existing code
|
||||
- Creating JSDoc/TSDoc documentation
|
||||
- Writing function/class descriptions
|
||||
- Explaining complex logic or algorithms
|
||||
- Adding inline comments for clarification
|
||||
- Documenting API endpoints and interfaces
|
||||
- Explaining configuration and setup code
|
||||
- Writing security-critical code documentation
|
||||
- Creating error handling documentation
|
||||
|
||||
**VI**: Sử dụng các patterns comment song ngữ khi:
|
||||
- Thêm comments vào code mới
|
||||
- Tài liệu hóa code hiện có
|
||||
- Tạo tài liệu JSDoc/TSDoc
|
||||
- Viết mô tả functions/classes
|
||||
- Giải thích logic hoặc thuật toán phức tạp
|
||||
- Thêm inline comments để làm rõ
|
||||
- Tài liệu hóa API endpoints và interfaces
|
||||
- Giải thích code cấu hình và setup
|
||||
- Viết tài liệu code bảo mật quan trọng
|
||||
- Tạo tài liệu xử lý lỗi
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Comment Format / Định Dạng Comment
|
||||
|
||||
All comments in the GoodGo project should be bilingual, with English (EN) followed by Vietnamese (VI) translations.
|
||||
|
||||
**Pattern / Mẫu**:
|
||||
```
|
||||
// EN: [English explanation]
|
||||
// VI: [Vietnamese explanation]
|
||||
```
|
||||
|
||||
### Comment Types / Các Loại Comment
|
||||
|
||||
1. **Single-line Comments** (`//`) / **Comments Một Dòng**: For brief explanations / Cho giải thích ngắn gọn
|
||||
2. **Multi-line Comments** (`/* */`) / **Comments Nhiều Dòng**: For longer explanations / Cho giải thích dài hơn
|
||||
3. **JSDoc Comments** (`/** */`) / **Comments JSDoc**: For function, class, and API documentation / Cho tài liệu function, class và API
|
||||
4. **Prisma Comments** (`///`) / **Comments Prisma**: For database schema documentation / Cho tài liệu schema database
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Single-line Comments / Comments Một Dòng
|
||||
|
||||
Use single-line comments for brief explanations of code behavior / Sử dụng single-line comments cho giải thích ngắn gọn về hành vi code.
|
||||
|
||||
```typescript
|
||||
// EN: Initialize database connection
|
||||
// VI: Khởi tạo kết nối database
|
||||
const db = await createConnection();
|
||||
|
||||
// EN: Enable detailed logging in development, minimal in production
|
||||
// VI: Bật ghi log chi tiết trong development, tối thiểu trong production
|
||||
const logLevel = process.env.NODE_ENV === 'development' ? 'debug' : 'error';
|
||||
```
|
||||
|
||||
**Real Example / Ví dụ Thực tế**: [`services/iam-service/src/config/database.config.ts`](../../../services/iam-service/src/config/database.config.ts)
|
||||
|
||||
### Multi-line Comments / Comments Nhiều Dòng
|
||||
|
||||
Use multi-line comments for detailed explanations or step-by-step processes / Sử dụng multi-line comments cho giải thích chi tiết hoặc quy trình từng bước.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Validates user credentials and returns JWT token
|
||||
* VI: Xác thực thông tin đăng nhập và trả về JWT token
|
||||
*
|
||||
* @param email - User email address / Địa chỉ email người dùng
|
||||
* @param password - User password / Mật khẩu người dùng
|
||||
* @returns JWT token / Mã JWT token
|
||||
* @throws AuthenticationError if credentials invalid / Lỗi xác thực nếu thông tin không hợp lệ
|
||||
*/
|
||||
async function login(email: string, password: string): Promise<string> {
|
||||
// EN: Implementation here
|
||||
// VI: Implementation ở đây
|
||||
}
|
||||
```
|
||||
|
||||
### Function Documentation / Tài Liệu Function
|
||||
|
||||
Use JSDoc format for all public functions with bilingual descriptions / Sử dụng format JSDoc cho tất cả public functions với mô tả song ngữ.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Calculates the total price including tax and discount
|
||||
* VI: Tính tổng giá bao gồm thuế và giảm giá
|
||||
*
|
||||
* @param basePrice - Original price / Giá gốc
|
||||
* @param taxRate - Tax rate (0-1) / Tỷ lệ thuế (0-1)
|
||||
* @param discount - Discount amount / Số tiền giảm giá
|
||||
* @returns Final price / Giá cuối cùng
|
||||
*/
|
||||
function calculateTotal(
|
||||
basePrice: number,
|
||||
taxRate: number,
|
||||
discount: number
|
||||
): number {
|
||||
// EN: Apply discount first
|
||||
// VI: Áp dụng giảm giá trước
|
||||
const discountedPrice = basePrice - discount;
|
||||
|
||||
// EN: Then calculate tax
|
||||
// VI: Sau đó tính thuế
|
||||
const tax = discountedPrice * taxRate;
|
||||
|
||||
return discountedPrice + tax;
|
||||
}
|
||||
```
|
||||
|
||||
**Real Example / Ví dụ Thực tế**: [`services/iam-service/src/modules/feature/feature.service.ts`](../../../services/iam-service/src/modules/feature/feature.service.ts)
|
||||
|
||||
### Class Documentation / Tài Liệu Class
|
||||
|
||||
Document classes with bilingual descriptions and explain their purpose / Tài liệu hóa classes với mô tả song ngữ và giải thích mục đích của chúng.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Service for managing features in the system
|
||||
* VI: Service để quản lý các features trong hệ thống
|
||||
*/
|
||||
export class FeatureService {
|
||||
/**
|
||||
* EN: Create a new feature
|
||||
* VI: Tạo một feature mới
|
||||
*
|
||||
* @param data - Feature data / Dữ liệu feature
|
||||
* @returns Created feature / Feature đã tạo
|
||||
*/
|
||||
async create(data: { name: string; title?: string }) {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Real Example / Ví dụ Thực tế**: [`services/iam-service/src/modules/feature/feature.service.ts`](../../../services/iam-service/src/modules/feature/feature.service.ts)
|
||||
|
||||
### Interface/Type Documentation / Tài Liệu Interface/Type
|
||||
|
||||
Document interfaces and types to explain their structure and purpose / Tài liệu hóa interfaces và types để giải thích cấu trúc và mục đích của chúng.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: User data transfer object
|
||||
* VI: Đối tượng truyền dữ liệu người dùng
|
||||
*/
|
||||
interface UserDto {
|
||||
/** EN: Unique user identifier / VI: Mã định danh duy nhất */
|
||||
id: string;
|
||||
|
||||
/** EN: User email address / VI: Địa chỉ email người dùng */
|
||||
email: string;
|
||||
|
||||
/** EN: User display name / VI: Tên hiển thị người dùng */
|
||||
name: string;
|
||||
|
||||
/** EN: User role for authorization / VI: Vai trò người dùng để phân quyền */
|
||||
role: 'admin' | 'user' | 'guest';
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Comments / Comments Cấu Hình
|
||||
|
||||
Document configuration files and environment variables with clear explanations / Tài liệu hóa file cấu hình và biến môi trường với giải thích rõ ràng.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Prisma client instance configured for the application
|
||||
* VI: Instance Prisma client được cấu hình cho ứng dụng
|
||||
*/
|
||||
export const prisma = new PrismaClient({
|
||||
// EN: Enable detailed logging in development, minimal in production
|
||||
// VI: Bật ghi log chi tiết trong development, tối thiểu trong production
|
||||
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
|
||||
});
|
||||
|
||||
/**
|
||||
* EN: Establish database connection on application startup
|
||||
* VI: Thiết lập kết nối database khi khởi động ứng dụng
|
||||
*/
|
||||
export const connectDatabase = async (): Promise<void> => {
|
||||
try {
|
||||
// EN: Connect to database using Prisma
|
||||
// VI: Kết nối tới database sử dụng Prisma
|
||||
await prisma.$connect();
|
||||
logger.info('Database connected successfully / Kết nối database thành công');
|
||||
} catch (error) {
|
||||
// EN: Log error and exit if database connection fails
|
||||
// VI: Ghi log lỗi và thoát nếu kết nối database thất bại
|
||||
logger.error('Database connection failed / Kết nối database thất bại', { error });
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Real Example / Ví dụ Thực tế**: [`services/iam-service/src/config/database.config.ts`](../../../services/iam-service/src/config/database.config.ts)
|
||||
|
||||
### Middleware Documentation / Tài Liệu Middleware
|
||||
|
||||
Document middleware functions with their purpose and behavior / Tài liệu hóa middleware functions với mục đích và hành vi của chúng.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Authentication middleware to verify JWT tokens
|
||||
* VI: Middleware xác thực để kiểm tra JWT token
|
||||
*/
|
||||
export function authMiddleware(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) {
|
||||
// EN: Extract token from Authorization header
|
||||
// VI: Lấy token từ header Authorization
|
||||
const authHeader = req.headers.authorization;
|
||||
const token = authHeader?.replace('Bearer ', '');
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'NO_TOKEN',
|
||||
message: 'Authentication required / Yêu cầu xác thực',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// EN: Verify token and extract payload
|
||||
// VI: Xác minh token và lấy payload
|
||||
const payload = jwt.verify(token, JWT_SECRET);
|
||||
req.user = payload;
|
||||
next();
|
||||
} catch (error) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INVALID_TOKEN',
|
||||
message: 'Invalid or expired token / Token không hợp lệ hoặc hết hạn',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Prisma Schema Comments / Comments Schema Prisma
|
||||
|
||||
Use triple-slash comments (`///`) for Prisma schema documentation / Sử dụng triple-slash comments (`///`) cho tài liệu Prisma schema.
|
||||
|
||||
```prisma
|
||||
/// EN: User model for authentication and profile
|
||||
/// VI: Model người dùng cho xác thực và hồ sơ
|
||||
model User {
|
||||
/// EN: Unique identifier / VI: Mã định danh duy nhất
|
||||
id String @id @default(cuid())
|
||||
|
||||
/// EN: User email (unique) / VI: Email người dùng (duy nhất)
|
||||
email String @unique
|
||||
|
||||
/// EN: Hashed password / VI: Mật khẩu đã mã hóa
|
||||
password String
|
||||
|
||||
/// EN: Display name / VI: Tên hiển thị
|
||||
name String
|
||||
|
||||
/// EN: Account creation timestamp / VI: Thời gian tạo tài khoản
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
/// EN: Last update timestamp / VI: Thời gian cập nhật cuối
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
```
|
||||
|
||||
### Test Comments / Comments Test
|
||||
|
||||
Document test setup and explain test scenarios in both languages / Tài liệu hóa test setup và giải thích test scenarios bằng cả hai ngôn ngữ.
|
||||
|
||||
```typescript
|
||||
// EN: Mock environment variables for tests
|
||||
// VI: Mock biến môi trường cho tests
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.DATABASE_URL = 'postgresql://test:test@localhost:5432/test_db';
|
||||
|
||||
// EN: Mock external services to avoid real network calls
|
||||
// VI: Mock các service bên ngoài để tránh gọi mạng thật
|
||||
jest.mock('@goodgo/logger', () => ({
|
||||
logger: {
|
||||
info: jest.fn(),
|
||||
error: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('FeatureService', () => {
|
||||
it('should create a feature successfully', async () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const testData = { name: 'test-feature' };
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực hiện
|
||||
const result = await service.create(testData);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Real Example / Ví dụ Thực tế**: [`services/iam-service/src/__tests__/setupTests.ts`](../../../services/iam-service/src/__tests__/setupTests.ts)
|
||||
|
||||
### Complex Logic Comments / Comments Logic Phức Tạp
|
||||
|
||||
When explaining complex algorithms or business logic, break it down into steps / Khi giải thích thuật toán phức tạp hoặc logic nghiệp vụ, chia nhỏ thành các bước.
|
||||
|
||||
```typescript
|
||||
// EN: Step 1: Validate input parameters
|
||||
// VI: Bước 1: Xác thực tham số đầu vào
|
||||
if (!email || !password) {
|
||||
throw new ValidationError('Email and password required');
|
||||
}
|
||||
|
||||
// EN: Step 2: Check if user exists in database
|
||||
// VI: Bước 2: Kiểm tra xem người dùng có tồn tại trong database
|
||||
const user = await prisma.user.findUnique({ where: { email } });
|
||||
if (!user) {
|
||||
throw new NotFoundError('User not found');
|
||||
}
|
||||
|
||||
// EN: Step 3: Verify password hash
|
||||
// VI: Bước 3: Xác minh hash mật khẩu
|
||||
const isValidPassword = await bcrypt.compare(password, user.password);
|
||||
if (!isValidPassword) {
|
||||
throw new AuthenticationError('Invalid credentials');
|
||||
}
|
||||
|
||||
// EN: Step 4: Generate and return JWT token
|
||||
// VI: Bước 4: Tạo và trả về JWT token
|
||||
const token = jwt.sign({ userId: user.id }, JWT_SECRET);
|
||||
return { token, user };
|
||||
```
|
||||
|
||||
## Special Comment Types / Các Loại Comment Đặc Biệt
|
||||
|
||||
### TODO Comments / Comments TODO
|
||||
|
||||
Use TODO comments for future improvements with bilingual descriptions / Sử dụng TODO comments cho cải tiến trong tương lai với mô tả song ngữ.
|
||||
|
||||
```typescript
|
||||
// TODO EN: Implement caching for better performance
|
||||
// TODO VI: Triển khai caching để cải thiện hiệu suất
|
||||
|
||||
// TODO EN: Add rate limiting to prevent abuse
|
||||
// TODO VI: Thêm rate limiting để ngăn chặn lạm dụng
|
||||
```
|
||||
|
||||
### FIXME Comments / Comments FIXME
|
||||
|
||||
Use FIXME comments for code that needs fixing / Sử dụng FIXME comments cho code cần sửa.
|
||||
|
||||
```typescript
|
||||
// FIXME EN: This causes memory leak, needs refactoring
|
||||
// FIXME VI: Đoạn này gây rò rỉ bộ nhớ, cần refactor
|
||||
|
||||
// FIXME EN: Temporary workaround, should implement proper solution
|
||||
// FIXME VI: Giải pháp tạm thời, nên triển khai giải pháp đúng đắn
|
||||
```
|
||||
|
||||
### WARNING Comments / Comments CẢNH BÁO
|
||||
|
||||
Use WARNING comments for code that requires special attention / Sử dụng WARNING comments cho code cần chú ý đặc biệt.
|
||||
|
||||
```typescript
|
||||
// WARNING EN: Do not modify this without updating the database schema
|
||||
// WARNING VI: Không sửa đổi phần này mà không cập nhật schema database
|
||||
|
||||
// WARNING EN: This function modifies global state, use with caution
|
||||
// WARNING VI: Function này thay đổi global state, sử dụng cẩn thận
|
||||
```
|
||||
|
||||
### NOTE Comments / Comments GHI CHÚ
|
||||
|
||||
Use NOTE comments for important information or explanations / Sử dụng NOTE comments cho thông tin hoặc giải thích quan trọng.
|
||||
|
||||
```typescript
|
||||
// NOTE EN: This is intentionally async to avoid blocking the event loop
|
||||
// NOTE VI: Đây là async có chủ ý để tránh block event loop
|
||||
|
||||
// NOTE EN: Priority: Docker Compose > .env.local > .env > System environment
|
||||
// NOTE VI: Ưu tiên: Docker Compose > .env.local > .env > Môi trường hệ thống
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Comment Placement / Vị Trí Comment
|
||||
|
||||
- ✅ Place bilingual comments together (EN first, then VI) / Đặt comments song ngữ cùng nhau (EN trước, sau đó VI)
|
||||
- ✅ Keep comments close to the code they describe / Giữ comments gần với code mà chúng mô tả
|
||||
- ✅ Use JSDoc format for functions and classes / Sử dụng format JSDoc cho functions và classes
|
||||
- ✅ Update comments when code changes / Cập nhật comments khi code thay đổi
|
||||
|
||||
### Comment Content / Nội Dung Comment
|
||||
|
||||
- ✅ **DO**: Explain WHY, not WHAT (code shows what) / Giải thích TẠI SAO, không phải CÁI GÌ
|
||||
- ✅ **DO**: Document complex logic and business rules / Tài liệu hóa logic phức tạp và quy tắc nghiệp vụ
|
||||
- ✅ **DO**: Include parameter descriptions and return types / Bao gồm mô tả tham số và kiểu trả về
|
||||
- ✅ **DO**: Document error conditions and exceptions / Tài liệu hóa điều kiện lỗi và ngoại lệ
|
||||
- ✅ **DON'T**: State the obvious / Không nói điều hiển nhiên
|
||||
- ✅ **DON'T**: Write redundant comments / Không viết comments thừa
|
||||
- ✅ **DON'T**: Comment out code (use version control instead) / Không comment code (sử dụng version control)
|
||||
|
||||
### Language Guidelines / Hướng Dẫn Ngôn Ngữ
|
||||
|
||||
**English / Tiếng Anh**:
|
||||
- Use clear, concise technical English / Sử dụng tiếng Anh kỹ thuật rõ ràng, ngắn gọn
|
||||
- Use proper technical terminology / Sử dụng thuật ngữ kỹ thuật đúng
|
||||
- Be specific and actionable / Cụ thể và có thể thực hiện
|
||||
|
||||
**Vietnamese / Tiếng Việt**:
|
||||
- Use proper Vietnamese technical terms / Sử dụng thuật ngữ kỹ thuật tiếng Việt đúng
|
||||
- Keep translations accurate and natural / Giữ bản dịch chính xác và tự nhiên
|
||||
- Use consistent terminology across codebase / Sử dụng thuật ngữ nhất quán trên codebase
|
||||
- Prefer technical Vietnamese terms over literal translations / Ưu tiên thuật ngữ kỹ thuật Việt hơn dịch theo nghĩa đen
|
||||
|
||||
### Documentation Priority / Ưu Tiên Tài Liệu
|
||||
|
||||
**High Priority** (Always document / Luôn tài liệu hóa):
|
||||
- Public APIs and exported functions / API công khai và functions được export
|
||||
- Complex algorithms and business logic / Thuật toán phức tạp và logic nghiệp vụ
|
||||
- Security-critical code / Code bảo mật quan trọng
|
||||
- Configuration and environment setup / Cấu hình và thiết lập môi trường
|
||||
- Error handling strategies / Chiến lược xử lý lỗi
|
||||
|
||||
**Medium Priority** (Document when helpful / Tài liệu khi hữu ích):
|
||||
- Helper functions with non-obvious behavior / Helper functions có hành vi không rõ ràng
|
||||
- Data transformations / Chuyển đổi dữ liệu
|
||||
- Integration points with external services / Điểm tích hợp với services bên ngoài
|
||||
|
||||
**Low Priority** (Optional / Tùy chọn):
|
||||
- Simple getters/setters / Getters/setters đơn giản
|
||||
- Self-explanatory code / Code tự giải thích
|
||||
- Standard CRUD operations / Các thao tác CRUD tiêu chuẩn
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Real Comment Examples / Ví Dụ Comment Thực Tế
|
||||
|
||||
1. **Service Comments**: [`services/iam-service/src/modules/feature/feature.service.ts`](../../../services/iam-service/src/modules/feature/feature.service.ts)
|
||||
2. **Config Comments**: [`services/iam-service/src/config/database.config.ts`](../../../services/iam-service/src/config/database.config.ts)
|
||||
3. **Test Comments**: [`services/iam-service/src/__tests__/setupTests.ts`](../../../services/iam-service/src/__tests__/setupTests.ts)
|
||||
4. **Jest Config Comments**: [`services/iam-service/jest.config.ts`](../../../services/iam-service/jest.config.ts)
|
||||
|
||||
### Comment Patterns in Different Contexts / Patterns Comment Trong Các Ngữ Cảnh Khác Nhau
|
||||
|
||||
- **Controllers**: Document API endpoints and request/response handling / Tài liệu hóa API endpoints và xử lý request/response
|
||||
- **Services**: Document business logic and data processing / Tài liệu hóa logic nghiệp vụ và xử lý dữ liệu
|
||||
- **Middleware**: Document authentication, authorization, and request processing / Tài liệu hóa xác thực, phân quyền và xử lý request
|
||||
- **Repositories**: Document database operations and query logic / Tài liệu hóa các thao tác database và logic query
|
||||
- **Config Files**: Document configuration options and environment variables / Tài liệu hóa tùy chọn cấu hình và biến môi trường
|
||||
- **Tests**: Document test scenarios and setup procedures / Tài liệu hóa test scenarios và quy trình setup
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Function Comment Template / Template Comment Function
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: [Brief description in English]
|
||||
* VI: [Mô tả ngắn gọn bằng tiếng Việt]
|
||||
*
|
||||
* @param paramName - EN description / VI mô tả
|
||||
* @returns EN description / VI mô tả
|
||||
* @throws ErrorType EN when / VI khi nào
|
||||
*/
|
||||
```
|
||||
|
||||
### Inline Comment Template / Template Inline Comment
|
||||
|
||||
```typescript
|
||||
// EN: [English explanation]
|
||||
// VI: [Giải thích tiếng Việt]
|
||||
```
|
||||
|
||||
### Complex Block Template / Template Block Phức Tạp
|
||||
|
||||
```typescript
|
||||
// EN: Step N: [What this block does]
|
||||
// VI: Bước N: [Block này làm gì]
|
||||
```
|
||||
|
||||
### Class Comment Template / Template Comment Class
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: [Class purpose in English]
|
||||
* VI: [Mục đích class bằng tiếng Việt]
|
||||
*/
|
||||
export class ClassName {
|
||||
/**
|
||||
* EN: [Property description]
|
||||
* VI: [Mô tả property]
|
||||
*/
|
||||
private property: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Interface Comment Template / Template Comment Interface
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: [Interface purpose in English]
|
||||
* VI: [Mục đích interface bằng tiếng Việt]
|
||||
*/
|
||||
interface InterfaceName {
|
||||
/** EN: Property description / VI: Mô tả property */
|
||||
property: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Testing Patterns](./testing-patterns.md)**: Writing comments in test files / Viết comments trong file test
|
||||
- **[API Design](./api-design.md)**: Documenting API endpoints / Tài liệu hóa API endpoints
|
||||
- **[Documentation](./documentation.md)**: Writing technical documentation / Viết tài liệu kỹ thuật
|
||||
- **[Project Rules](./project-rules.md)**: Code organization and standards / Tổ chức code và tiêu chuẩn
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### Documentation Standards / Tiêu Chuẩn Tài Liệu
|
||||
|
||||
- [JSDoc Documentation](https://jsdoc.app/)
|
||||
- [TypeScript JSDoc](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
|
||||
- [TSDoc Specification](https://tsdoc.org/)
|
||||
|
||||
### Internal Documentation / Tài Liệu Nội Bộ
|
||||
|
||||
- [Documentation Writing Guidelines](./documentation.md)
|
||||
- [API Design Standards](./api-design.md)
|
||||
- [Project Coding Standards](./project-rules.md)
|
||||
|
||||
### Tools / Công Cụ
|
||||
|
||||
- **JSDoc**: Generate API documentation from comments / Tạo tài liệu API từ comments
|
||||
- **ESLint**: Enforce comment style and completeness / Thực thi style và tính đầy đủ của comments
|
||||
- **Prettier**: Format comments consistently / Định dạng comments nhất quán
|
||||
- **VS Code**: IntelliSense uses JSDoc comments for better autocomplete / IntelliSense sử dụng JSDoc comments cho autocomplete tốt hơn
|
||||
584
docs/vi/skills/database-prisma.md
Normal file
584
docs/vi/skills/database-prisma.md
Normal file
@@ -0,0 +1,584 @@
|
||||
# Database & Prisma / Cơ Sở Dữ Liệu & Prisma
|
||||
|
||||
> **EN**: Prisma ORM and database patterns for GoodGo microservices. Use when working with databases, creating Prisma schemas, writing migrations, implementing repositories, or optimizing queries.
|
||||
> **VI**: Pattern Prisma ORM và database cho các microservices của GoodGo. Sử dụng khi làm việc với databases, tạo Prisma schemas, viết migrations, triển khai repositories, hoặc tối ưu queries.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: This skill covers Prisma ORM patterns, database schema design, repository patterns, query optimization, and transaction handling used across GoodGo microservices. It ensures type-safe database operations, consistent data access patterns, and optimal performance.
|
||||
|
||||
**VI**: Skill này bao gồm các pattern Prisma ORM, thiết kế database schema, repository patterns, tối ưu queries, và xử lý transactions được sử dụng trong các microservices của GoodGo. Nó đảm bảo các thao tác database type-safe, pattern truy cập dữ liệu nhất quán, và hiệu năng tối ưu.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Setting up Prisma for a new service
|
||||
- Creating or modifying database schemas
|
||||
- Writing database migrations
|
||||
- Implementing repository patterns
|
||||
- Optimizing database queries
|
||||
- Setting up database connections
|
||||
- Implementing transactions
|
||||
- Working with Neon PostgreSQL
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Thiết lập Prisma cho service mới
|
||||
- Tạo hoặc sửa đổi database schemas
|
||||
- Viết database migrations
|
||||
- Triển khai repository patterns
|
||||
- Tối ưu database queries
|
||||
- Thiết lập kết nối database
|
||||
- Triển khai transactions
|
||||
- Làm việc với Neon PostgreSQL
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### 1. Repository Pattern / Pattern Repository
|
||||
|
||||
**EN**: All database operations go through repository classes that extend `BaseRepository`, providing consistent CRUD operations and error handling.
|
||||
|
||||
**VI**: Tất cả các thao tác database đi qua các repository classes kế thừa `BaseRepository`, cung cấp các CRUD operations nhất quán và xử lý lỗi.
|
||||
|
||||
### 2. Prisma Schema / Schema Prisma
|
||||
|
||||
**EN**: Database schema is defined in `prisma/schema.prisma` with models, relations, indexes, and constraints.
|
||||
|
||||
**VI**: Database schema được định nghĩa trong `prisma/schema.prisma` với models, relations, indexes, và constraints.
|
||||
|
||||
### 3. Type Safety / An Toàn Kiểu
|
||||
|
||||
**EN**: Prisma generates TypeScript types from schema, ensuring type-safe database operations.
|
||||
|
||||
**VI**: Prisma generate TypeScript types từ schema, đảm bảo các thao tác database type-safe.
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Prisma Schema Pattern / Pattern Schema Prisma
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```prisma
|
||||
// services/iam-service/prisma/schema.prisma
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// EN: User model - Core user entity
|
||||
// VI: Model User - Entity người dùng cốt lõi
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
username String? @unique
|
||||
passwordHash String? // Nullable for social-only users
|
||||
isActive Boolean @default(true)
|
||||
emailVerified Boolean @default(false)
|
||||
mfaEnabled Boolean @default(false)
|
||||
mfaSecret String?
|
||||
lastLoginAt DateTime?
|
||||
loginCount Int @default(0)
|
||||
organizationId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
userRoles UserRole[]
|
||||
userPermissions UserPermission[]
|
||||
sessions Session[]
|
||||
organization Organization? @relation(fields: [organizationId], references: [id])
|
||||
profile UserProfile?
|
||||
|
||||
@@index([email])
|
||||
@@index([username])
|
||||
@@index([createdAt])
|
||||
@@index([organizationId])
|
||||
@@map("users")
|
||||
}
|
||||
```
|
||||
|
||||
### Database Connection Pattern / Pattern Kết Nối Database
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/config/database.config.ts
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
/**
|
||||
* EN: Prisma client instance configured for the application
|
||||
* VI: Instance Prisma client được cấu hình cho ứng dụng
|
||||
*/
|
||||
export const prisma = new PrismaClient({
|
||||
// EN: Enable detailed logging in development, minimal in production
|
||||
// VI: Bật ghi log chi tiết trong development, tối thiểu trong production
|
||||
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
|
||||
});
|
||||
|
||||
/**
|
||||
* EN: Establish database connection on application startup
|
||||
* VI: Thiết lập kết nối database khi khởi động ứng dụng
|
||||
*/
|
||||
export const connectDatabase = async (): Promise<void> => {
|
||||
try {
|
||||
await prisma.$connect();
|
||||
logger.info('Database connected successfully / Kết nối database thành công');
|
||||
} catch (error) {
|
||||
logger.error('Database connection failed / Kết nối database thất bại', { error });
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* EN: Close database connection on application shutdown
|
||||
* VI: Đóng kết nối database khi tắt ứng dụng
|
||||
*/
|
||||
export const disconnectDatabase = async (): Promise<void> => {
|
||||
await prisma.$disconnect();
|
||||
logger.info('Database disconnected / Đã ngắt kết nối database');
|
||||
};
|
||||
```
|
||||
|
||||
### Base Repository Pattern / Pattern Base Repository
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/common/repository.ts
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { logger } from '@goodgo/logger';
|
||||
import { DatabaseError } from '../../errors/http-error';
|
||||
|
||||
/**
|
||||
* EN: Base repository class providing common database operations
|
||||
* VI: Base repository class cung cấp các thao tác database chung
|
||||
*/
|
||||
export abstract class BaseRepository<T, CreateInput, UpdateInput> {
|
||||
protected prisma: PrismaClient;
|
||||
protected modelName: string;
|
||||
|
||||
constructor(prisma: PrismaClient, modelName: string) {
|
||||
this.prisma = prisma;
|
||||
this.modelName = modelName;
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find entity by ID
|
||||
* VI: Tìm entity theo ID
|
||||
*/
|
||||
async findById(id: string): Promise<T | null> {
|
||||
try {
|
||||
logger.debug(`Finding ${this.modelName} by ID / Tìm ${this.modelName} theo ID`, { id });
|
||||
|
||||
const entity = await (this.prisma as any)[this.modelName].findUnique({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
logger.debug(`${this.modelName} ${entity ? 'found' : 'not found'} / ${this.modelName} ${entity ? 'đã tìm thấy' : 'không tìm thấy'}`, { id });
|
||||
return entity;
|
||||
} catch (error: any) {
|
||||
logger.error(`Failed to find ${this.modelName} by ID / Không thể tìm ${this.modelName} theo ID`, { error, id });
|
||||
throw new DatabaseError(`Failed to find ${this.modelName}`, { id, originalError: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find all entities with optional filtering
|
||||
* VI: Tìm tất cả entities với filtering tùy chọn
|
||||
*/
|
||||
async findAll(options?: {
|
||||
where?: any;
|
||||
orderBy?: any;
|
||||
skip?: number;
|
||||
take?: number;
|
||||
include?: any;
|
||||
}): Promise<T[]> {
|
||||
try {
|
||||
logger.debug(`Finding all ${this.modelName} / Tìm tất cả ${this.modelName}`, options);
|
||||
|
||||
const entities = await (this.prisma as any)[this.modelName].findMany(options || {});
|
||||
|
||||
logger.debug(`Found ${entities.length} ${this.modelName} entities / Đã tìm thấy ${entities.length} ${this.modelName} entities`);
|
||||
return entities;
|
||||
} catch (error: any) {
|
||||
logger.error(`Failed to find all ${this.modelName} / Không thể tìm tất cả ${this.modelName}`, { error, options });
|
||||
throw new DatabaseError(`Failed to find ${this.modelName} entities`, { options, originalError: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Create new entity
|
||||
* VI: Tạo entity mới
|
||||
*/
|
||||
async create(data: CreateInput): Promise<T> {
|
||||
try {
|
||||
logger.debug(`Creating new ${this.modelName} / Tạo ${this.modelName} mới`, { data });
|
||||
|
||||
const entity = await (this.prisma as any)[this.modelName].create({
|
||||
data,
|
||||
});
|
||||
|
||||
logger.debug(`${this.modelName} created successfully / ${this.modelName} đã được tạo thành công`, { id: (entity as any).id });
|
||||
return entity;
|
||||
} catch (error: any) {
|
||||
logger.error(`Failed to create ${this.modelName} / Không thể tạo ${this.modelName}`, { error, data });
|
||||
throw new DatabaseError(`Failed to create ${this.modelName}`, { data, originalError: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Update entity by ID
|
||||
* VI: Cập nhật entity theo ID
|
||||
*/
|
||||
async update(id: string, data: UpdateInput): Promise<T> {
|
||||
try {
|
||||
logger.debug(`Updating ${this.modelName} / Cập nhật ${this.modelName}`, { id, data });
|
||||
|
||||
const entity = await (this.prisma as any)[this.modelName].update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
|
||||
logger.debug(`${this.modelName} updated successfully / ${this.modelName} đã được cập nhật thành công`, { id });
|
||||
return entity;
|
||||
} catch (error: any) {
|
||||
if (error.code === 'P2025') {
|
||||
logger.warn(`${this.modelName} not found for update / ${this.modelName} không tìm thấy để cập nhật`, { id });
|
||||
throw new DatabaseError(`${this.modelName} not found`, { id });
|
||||
}
|
||||
logger.error(`Failed to update ${this.modelName} / Không thể cập nhật ${this.modelName}`, { error, id, data });
|
||||
throw new DatabaseError(`Failed to update ${this.modelName}`, { id, data, originalError: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Execute transaction with multiple operations
|
||||
* VI: Thực thi transaction với nhiều operations
|
||||
*/
|
||||
async transaction<R>(callback: (tx: any) => Promise<R>): Promise<R> {
|
||||
try {
|
||||
logger.debug(`Starting ${this.modelName} transaction / Bắt đầu transaction ${this.modelName}`);
|
||||
|
||||
const result = await this.prisma.$transaction(async (tx) => {
|
||||
return await callback(tx);
|
||||
});
|
||||
|
||||
logger.debug(`${this.modelName} transaction completed successfully / Transaction ${this.modelName} đã hoàn thành thành công`);
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
logger.error(`${this.modelName} transaction failed / Transaction ${this.modelName} thất bại`, { error });
|
||||
throw new DatabaseError(`${this.modelName} transaction failed`, { originalError: error });
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Specific Repository Implementation / Triển Khai Repository Cụ Thể
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/repositories/user.repository.ts
|
||||
import { PrismaClient, User } from '@prisma/client';
|
||||
import { BaseRepository } from '../modules/common/repository';
|
||||
|
||||
/**
|
||||
* EN: User repository for database operations
|
||||
* VI: Repository người dùng cho các thao tác database
|
||||
*/
|
||||
export class UserRepository extends BaseRepository<User, any, any> {
|
||||
constructor(prisma: PrismaClient) {
|
||||
super(prisma, 'user');
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find user by email
|
||||
* VI: Tìm người dùng theo email
|
||||
*/
|
||||
async findByEmail(email: string): Promise<User | null> {
|
||||
return this.prisma.user.findUnique({
|
||||
where: { email },
|
||||
include: {
|
||||
userRoles: {
|
||||
include: { role: true },
|
||||
},
|
||||
userPermissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find user by username
|
||||
* VI: Tìm người dùng theo username
|
||||
*/
|
||||
async findByUsername(username: string): Promise<User | null> {
|
||||
return this.prisma.user.findUnique({
|
||||
where: { username },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* EN: Find user with roles and permissions
|
||||
* VI: Tìm người dùng với roles và permissions
|
||||
*/
|
||||
async findWithPermissions(userId: string): Promise<User | null> {
|
||||
return this.prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
include: {
|
||||
userRoles: {
|
||||
where: {
|
||||
OR: [
|
||||
{ expiresAt: null },
|
||||
{ expiresAt: { gte: new Date() } },
|
||||
],
|
||||
},
|
||||
include: {
|
||||
role: {
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
userPermissions: {
|
||||
where: {
|
||||
OR: [
|
||||
{ expiresAt: null },
|
||||
{ expiresAt: { gte: new Date() } },
|
||||
],
|
||||
},
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Upsert Pattern / Pattern Upsert
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/repositories/user-profile.repository.ts
|
||||
export class UserProfileRepository extends BaseRepository<UserProfile, any, any> {
|
||||
/**
|
||||
* EN: Create or update profile for user
|
||||
* VI: Tạo hoặc cập nhật profile cho user
|
||||
*/
|
||||
async upsert(userId: string, data: any): Promise<UserProfile> {
|
||||
return this.prisma.userProfile.upsert({
|
||||
where: { userId },
|
||||
update: {
|
||||
...data,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
create: {
|
||||
userId,
|
||||
...data,
|
||||
},
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
username: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Query Optimization Patterns / Pattern Tối Ưu Query
|
||||
|
||||
**Example from codebase / Ví dụ từ codebase**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/modules/feature/feature.repository.ts
|
||||
export class FeatureRepository extends BaseRepository<Feature, CreateFeatureInput, UpdateFeatureInput> {
|
||||
/**
|
||||
* EN: Find features by tags
|
||||
* VI: Tìm features theo tags
|
||||
*/
|
||||
async findByTags(tags: string[]): Promise<Feature[]> {
|
||||
try {
|
||||
logger.debug('Finding features by tags / Tìm features theo tags', { tags });
|
||||
|
||||
const features = await this.prisma.feature.findMany({
|
||||
where: {
|
||||
tags: {
|
||||
hasSome: tags,
|
||||
},
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
logger.debug(`Found ${features.length} features by tags / Đã tìm thấy ${features.length} features theo tags`, { tags });
|
||||
return features;
|
||||
} catch (error) {
|
||||
logger.error('Failed to find features by tags / Không thể tìm features theo tags', { error, tags });
|
||||
throw this.handleDatabaseError(error, { tags });
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### 1. Schema Design / Thiết Kế Schema
|
||||
|
||||
- ✅ Use appropriate field types (String, Int, Boolean, DateTime, Json) / Sử dụng field types phù hợp
|
||||
- ✅ Add indexes for frequently queried fields (`@@index([email])`) / Thêm indexes cho các fields thường query
|
||||
- ✅ Use relations instead of storing JSON when possible / Sử dụng relations thay vì lưu JSON khi có thể
|
||||
- ✅ Implement soft deletes with `deletedAt` field when needed / Triển khai soft deletes với field `deletedAt` khi cần
|
||||
- ✅ Use `@default()` for default values / Sử dụng `@default()` cho giá trị mặc định
|
||||
- ✅ Use `@updatedAt` for automatic timestamp updates / Sử dụng `@updatedAt` cho cập nhật timestamp tự động
|
||||
|
||||
### 2. Repository Pattern / Pattern Repository
|
||||
|
||||
- ✅ Extend `BaseRepository` for common CRUD operations / Kế thừa `BaseRepository` cho CRUD operations chung
|
||||
- ✅ Add custom methods for domain-specific queries / Thêm methods tùy chỉnh cho queries đặc thù domain
|
||||
- ✅ Use `include` and `select` to control data fetching / Sử dụng `include` và `select` để kiểm soát việc lấy dữ liệu
|
||||
- ✅ Handle Prisma errors and convert to domain errors / Xử lý lỗi Prisma và chuyển đổi sang domain errors
|
||||
- ✅ Log database operations for debugging / Log các thao tác database để debug
|
||||
|
||||
### 3. Query Optimization / Tối Ưu Query
|
||||
|
||||
- ✅ Use `select` to fetch only needed fields / Sử dụng `select` để chỉ lấy các fields cần thiết
|
||||
- ✅ Implement pagination with `skip` and `take` / Triển khai pagination với `skip` và `take`
|
||||
- ✅ Use indexes for frequently queried fields / Sử dụng indexes cho các fields thường query
|
||||
- ✅ Avoid N+1 queries by using `include` strategically / Tránh N+1 queries bằng cách sử dụng `include` chiến lược
|
||||
- ✅ Use `findUnique` instead of `findFirst` when possible / Sử dụng `findUnique` thay vì `findFirst` khi có thể
|
||||
- ✅ Use transactions for multiple related operations / Sử dụng transactions cho nhiều operations liên quan
|
||||
|
||||
### 4. Error Handling / Xử Lý Lỗi
|
||||
|
||||
- ✅ Catch Prisma errors and convert to domain errors / Bắt lỗi Prisma và chuyển đổi sang domain errors
|
||||
- ✅ Handle unique constraint violations (P2002) / Xử lý vi phạm ràng buộc duy nhất
|
||||
- ✅ Handle record not found (P2025) / Xử lý không tìm thấy bản ghi
|
||||
- ✅ Log errors with context / Log lỗi kèm context
|
||||
- ✅ Provide meaningful error messages / Cung cấp thông báo lỗi có ý nghĩa
|
||||
|
||||
### 5. Migrations / Migrations
|
||||
|
||||
- ✅ Keep migrations small and focused / Giữ migrations nhỏ và tập trung
|
||||
- ✅ Test migrations before production / Test migrations trước khi production
|
||||
- ✅ Backup before major changes / Backup trước khi thay đổi lớn
|
||||
- ✅ Use descriptive migration names / Sử dụng tên migration mô tả
|
||||
- ✅ Review generated SQL before applying / Xem xét SQL được generate trước khi áp dụng
|
||||
|
||||
### 6. Connection Management / Quản Lý Kết Nối
|
||||
|
||||
- ✅ Use connection pooling for production / Sử dụng connection pooling cho production
|
||||
- ✅ Close connections on application shutdown / Đóng kết nối khi tắt ứng dụng
|
||||
- ✅ Handle connection errors gracefully / Xử lý lỗi kết nối một cách lịch sự
|
||||
- ✅ Monitor connection pool usage / Giám sát việc sử dụng connection pool
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Schema Examples / Ví Dụ Schema
|
||||
|
||||
- **IAM Service Schema**: [`services/iam-service/prisma/schema.prisma`](../../../services/iam-service/prisma/schema.prisma)
|
||||
- **Auth Service Schema**: [`services/iam-service/prisma/schema.prisma`](../../../services/iam-service/prisma/schema.prisma)
|
||||
|
||||
### Repository Examples / Ví Dụ Repository
|
||||
|
||||
- **Base Repository**: [`services/iam-service/src/modules/common/repository.ts`](../../../services/iam-service/src/modules/common/repository.ts)
|
||||
- **User Repository**: [`services/iam-service/src/repositories/user.repository.ts`](../../../services/iam-service/src/repositories/user.repository.ts)
|
||||
- **User Profile Repository**: [`services/iam-service/src/repositories/user-profile.repository.ts`](../../../services/iam-service/src/repositories/user-profile.repository.ts)
|
||||
- **Feature Repository**: [`services/iam-service/src/modules/feature/feature.repository.ts`](../../../services/iam-service/src/modules/feature/feature.repository.ts)
|
||||
|
||||
### Database Config Examples / Ví Dụ Cấu Hình Database
|
||||
|
||||
- **Database Config**: [`services/iam-service/src/config/database.config.ts`](../../../services/iam-service/src/config/database.config.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Common Prisma Operations / Các Thao Tác Prisma Thường Dùng
|
||||
|
||||
```typescript
|
||||
// Find by ID / Tìm theo ID
|
||||
const user = await prisma.user.findUnique({ where: { id } });
|
||||
|
||||
// Find with relations / Tìm với relations
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: { profile: true, roles: true },
|
||||
});
|
||||
|
||||
// Find many with filters / Tìm nhiều với filters
|
||||
const users = await prisma.user.findMany({
|
||||
where: { isActive: true },
|
||||
skip: 0,
|
||||
take: 10,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
// Create / Tạo
|
||||
const user = await prisma.user.create({
|
||||
data: { email, passwordHash },
|
||||
});
|
||||
|
||||
// Update / Cập nhật
|
||||
const user = await prisma.user.update({
|
||||
where: { id },
|
||||
data: { isActive: false },
|
||||
});
|
||||
|
||||
// Delete / Xóa
|
||||
await prisma.user.delete({ where: { id } });
|
||||
|
||||
// Upsert / Tạo hoặc cập nhật
|
||||
const profile = await prisma.userProfile.upsert({
|
||||
where: { userId },
|
||||
update: { ...data },
|
||||
create: { userId, ...data },
|
||||
});
|
||||
|
||||
// Transaction / Transaction
|
||||
await prisma.$transaction(async (tx) => {
|
||||
const user = await tx.user.create({ data: userData });
|
||||
await tx.userProfile.create({ data: { userId: user.id, ...profileData } });
|
||||
});
|
||||
```
|
||||
|
||||
### Prisma Error Codes / Mã Lỗi Prisma
|
||||
|
||||
| Code | Description / Mô Tả |
|
||||
|------|-------------------|
|
||||
| P2002 | Unique constraint violation / Vi phạm ràng buộc duy nhất |
|
||||
| P2025 | Record not found / Không tìm thấy bản ghi |
|
||||
| P2003 | Foreign key constraint violation / Vi phạm ràng buộc khóa ngoại |
|
||||
| P2014 | Required relation violation / Vi phạm quan hệ bắt buộc |
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[API Design](./api-design.md)**: For designing API endpoints that use repositories / Cho thiết kế API endpoints sử dụng repositories
|
||||
- **[Testing Patterns](./testing-patterns.md)**: For testing database operations / Cho test các thao tác database
|
||||
- **[Security](./security.md)**: For securing database operations and preventing SQL injection / Cho bảo mật các thao tác database và ngăn chặn SQL injection
|
||||
- **[Observability](./observability-monitoring.md)**: For monitoring database performance / Cho giám sát hiệu năng database
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### External Documentation / Tài Liệu Bên Ngoài
|
||||
|
||||
- [Prisma Documentation](https://www.prisma.io/docs)
|
||||
- [Prisma Schema Reference](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference)
|
||||
- [Prisma Client API](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference)
|
||||
- [PostgreSQL Documentation](https://www.postgresql.org/docs/)
|
||||
- [Neon Documentation](https://neon.tech/docs)
|
||||
|
||||
### Internal Documentation / Tài Liệu Nội Bộ
|
||||
|
||||
- [Neon Database Guide](../guides/neon-database.md)
|
||||
- [Development Guide](../guides/development.md)
|
||||
468
docs/vi/skills/deployment-kubernetes.md
Normal file
468
docs/vi/skills/deployment-kubernetes.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# Kubernetes Deployment / Triển Khai Kubernetes
|
||||
|
||||
> **EN**: Kubernetes deployment patterns for GoodGo microservices. Use when deploying to staging/production, creating K8s manifests, configuring HPA, setting up ingress, or troubleshooting K8s deployments.
|
||||
> **VI**: Các pattern triển khai Kubernetes cho microservices GoodGo. Sử dụng khi triển khai lên staging/production, tạo K8s manifests, cấu hình HPA, thiết lập ingress, hoặc xử lý sự cố triển khai K8s.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: This skill covers Kubernetes deployment patterns and best practices for GoodGo microservices. It includes creating deployment manifests, configuring autoscaling, managing secrets and configmaps, setting up ingress, and implementing health checks.
|
||||
|
||||
**VI**: Skill này bao gồm các pattern triển khai Kubernetes và best practices cho microservices GoodGo. Nó bao gồm tạo deployment manifests, cấu hình autoscaling, quản lý secrets và configmaps, thiết lập ingress, và triển khai health checks.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Deploying services to staging/production environments
|
||||
- Creating or updating Kubernetes manifests
|
||||
- Configuring autoscaling (HPA/VPA)
|
||||
- Setting up ingress and load balancing
|
||||
- Managing secrets and configmaps
|
||||
- Troubleshooting deployment issues
|
||||
- Implementing health checks and probes
|
||||
- Setting up monitoring and logging
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Triển khai services lên môi trường staging/production
|
||||
- Tạo hoặc cập nhật Kubernetes manifests
|
||||
- Cấu hình autoscaling (HPA/VPA)
|
||||
- Thiết lập ingress và load balancing
|
||||
- Quản lý secrets và configmaps
|
||||
- Xử lý sự cố triển khai
|
||||
- Triển khai health checks và probes
|
||||
- Thiết lập monitoring và logging
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Deployment Strategy / Chiến Lược Triển Khai
|
||||
|
||||
**EN**:
|
||||
- Rolling updates for zero-downtime deployments
|
||||
- Resource limits and requests for stability
|
||||
- Health checks (liveness/readiness probes)
|
||||
- Horizontal Pod Autoscaler (HPA) for auto-scaling
|
||||
- ConfigMaps for configuration
|
||||
- Secrets for sensitive data
|
||||
|
||||
**VI**:
|
||||
- Rolling updates để triển khai không downtime
|
||||
- Resource limits và requests để đảm bảo ổn định
|
||||
- Health checks (liveness/readiness probes)
|
||||
- Horizontal Pod Autoscaler (HPA) để tự động scale
|
||||
- ConfigMaps cho cấu hình
|
||||
- Secrets cho dữ liệu nhạy cảm
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Service Deployment Manifest / Manifest Triển Khai Service
|
||||
|
||||
**EN**: Standard deployment manifest structure for GoodGo services.
|
||||
|
||||
**VI**: Cấu trúc deployment manifest chuẩn cho các services GoodGo.
|
||||
|
||||
**Ví dụ từ codebase**: [`deployments/production/kubernetes/iam-service.yaml`](../../../deployments/production/kubernetes/iam-service.yaml)
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: iam-service
|
||||
namespace: production
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: iam-service
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: iam-service
|
||||
spec:
|
||||
containers:
|
||||
- name: iam-service
|
||||
image: goodgo/iam-service:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 5001
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: iam-service-config
|
||||
- secretRef:
|
||||
name: iam-service-secrets
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "1000m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health/live
|
||||
port: 5001
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health/ready
|
||||
port: 5001
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: iam-service
|
||||
namespace: production
|
||||
spec:
|
||||
selector:
|
||||
app: iam-service
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5001
|
||||
targetPort: 5001
|
||||
type: ClusterIP
|
||||
```
|
||||
|
||||
### Horizontal Pod Autoscaler / Tự Động Scale Pod
|
||||
|
||||
**EN**: Configure HPA to automatically scale pods based on CPU and memory utilization.
|
||||
|
||||
**VI**: Cấu hình HPA để tự động scale pods dựa trên CPU và memory utilization.
|
||||
|
||||
**Ví dụ từ codebase**: [`deployments/production/kubernetes/iam-service.yaml`](../../../deployments/production/kubernetes/iam-service.yaml)
|
||||
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: iam-service-hpa
|
||||
namespace: production
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: iam-service
|
||||
minReplicas: 3
|
||||
maxReplicas: 10
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 70
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 80
|
||||
```
|
||||
|
||||
### ConfigMap & Secrets / ConfigMap và Secrets
|
||||
|
||||
**EN**: Use ConfigMaps for non-sensitive configuration and Secrets for sensitive data.
|
||||
|
||||
**VI**: Sử dụng ConfigMaps cho cấu hình không nhạy cảm và Secrets cho dữ liệu nhạy cảm.
|
||||
|
||||
**Ví dụ từ codebase**:
|
||||
- ConfigMap: [`deployments/production/kubernetes/iam-service-configmap.yaml`](../../../deployments/production/kubernetes/iam-service-configmap.yaml)
|
||||
- Secrets: [`deployments/production/kubernetes/secrets.yaml.example`](../../../deployments/production/kubernetes/secrets.yaml.example)
|
||||
|
||||
```yaml
|
||||
# ConfigMap
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: iam-service-config
|
||||
namespace: production
|
||||
data:
|
||||
NODE_ENV: "production"
|
||||
PORT: "5001"
|
||||
API_VERSION: "v1"
|
||||
CORS_ORIGIN: "https://goodgo.vn"
|
||||
LOG_LEVEL: "warn"
|
||||
SERVICE_NAME: "iam-service"
|
||||
TRACING_ENABLED: "true"
|
||||
|
||||
---
|
||||
# Secret (example - use sealed-secrets in production)
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: iam-service-secrets
|
||||
namespace: production
|
||||
type: Opaque
|
||||
stringData:
|
||||
database-url: "postgresql://user:password@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true"
|
||||
jwt-secret: "your-production-jwt-secret-min-32-chars"
|
||||
jwt-refresh-secret: "your-production-refresh-secret-min-32-chars"
|
||||
redis-password: ""
|
||||
```
|
||||
|
||||
### Ingress Configuration / Cấu Hình Ingress
|
||||
|
||||
**EN**: Configure ingress for external access with TLS and path-based routing.
|
||||
|
||||
**VI**: Cấu hình ingress để truy cập từ bên ngoài với TLS và path-based routing.
|
||||
|
||||
**Ví dụ từ codebase**: [`deployments/production/kubernetes/ingress.yaml`](../../../deployments/production/kubernetes/ingress.yaml)
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: api-ingress
|
||||
namespace: production
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/rule-type: PathPrefix
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- api.goodgo.vn
|
||||
secretName: api-tls-cert
|
||||
rules:
|
||||
- host: api.goodgo.vn
|
||||
http:
|
||||
paths:
|
||||
- path: /api/v1/auth
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: iam-service
|
||||
port:
|
||||
number: 5001
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Resource Management / Quản Lý Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- Always set resource requests and limits
|
||||
- Monitor actual usage and adjust accordingly
|
||||
- Use HPA for automatic scaling
|
||||
- Set appropriate CPU and memory based on service requirements
|
||||
|
||||
**VI**:
|
||||
- Luôn đặt resource requests và limits
|
||||
- Theo dõi sử dụng thực tế và điều chỉnh phù hợp
|
||||
- Sử dụng HPA để tự động scale
|
||||
- Đặt CPU và memory phù hợp dựa trên yêu cầu service
|
||||
|
||||
### Configuration / Cấu Hình
|
||||
|
||||
**EN**:
|
||||
- Use ConfigMaps for non-sensitive config
|
||||
- Use Secrets for sensitive data
|
||||
- Never hardcode configuration in images
|
||||
- Use `envFrom` to load entire ConfigMap/Secret
|
||||
|
||||
**VI**:
|
||||
- Sử dụng ConfigMaps cho cấu hình không nhạy cảm
|
||||
- Sử dụng Secrets cho dữ liệu nhạy cảm
|
||||
- Không bao giờ hardcode cấu hình trong images
|
||||
- Sử dụng `envFrom` để load toàn bộ ConfigMap/Secret
|
||||
|
||||
### Health Checks / Kiểm Tra Sức Khỏe
|
||||
|
||||
**EN**:
|
||||
- Implement both liveness and readiness probes
|
||||
- Set appropriate timeouts and thresholds
|
||||
- Include dependency checks in readiness probe
|
||||
- Use HTTP probes for web services
|
||||
|
||||
**VI**:
|
||||
- Triển khai cả liveness và readiness probes
|
||||
- Đặt timeouts và thresholds phù hợp
|
||||
- Bao gồm kiểm tra dependencies trong readiness probe
|
||||
- Sử dụng HTTP probes cho web services
|
||||
|
||||
**Ví dụ từ codebase**: [`services/iam-service/src/modules/health/health.controller.ts`](../../../services/iam-service/src/modules/health/health.controller.ts)
|
||||
|
||||
```typescript
|
||||
// Liveness probe - is the service alive?
|
||||
health = async (_req: Request, res: Response): Promise<void> => {
|
||||
res.json({
|
||||
success: true,
|
||||
data: { status: 'ok', timestamp: new Date().toISOString() },
|
||||
});
|
||||
};
|
||||
|
||||
// Readiness probe - is the service ready to accept traffic?
|
||||
ready = async (_req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
// Check database connection
|
||||
await prisma.$queryRaw`SELECT 1`;
|
||||
res.json({
|
||||
success: true,
|
||||
data: { status: 'ready' },
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(503).json({
|
||||
success: false,
|
||||
error: { code: 'HEALTH_001', message: 'Service not ready' },
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Deployment / Triển Khai
|
||||
|
||||
**EN**:
|
||||
- Use rolling updates for zero-downtime
|
||||
- Set maxSurge and maxUnavailable appropriately
|
||||
- Test deployments in staging first
|
||||
- Use image tags instead of `latest` in production
|
||||
|
||||
**VI**:
|
||||
- Sử dụng rolling updates để không downtime
|
||||
- Đặt maxSurge và maxUnavailable phù hợp
|
||||
- Test triển khai trong staging trước
|
||||
- Sử dụng image tags thay vì `latest` trong production
|
||||
|
||||
### Security / Bảo Mật
|
||||
|
||||
**EN**:
|
||||
- Run containers as non-root user
|
||||
- Use network policies to restrict traffic
|
||||
- Regularly update base images
|
||||
- Use sealed-secrets or external secret manager
|
||||
- Never commit secrets to Git
|
||||
|
||||
**VI**:
|
||||
- Chạy containers với user không phải root
|
||||
- Sử dụng network policies để hạn chế traffic
|
||||
- Cập nhật base images thường xuyên
|
||||
- Sử dụng sealed-secrets hoặc external secret manager
|
||||
- Không bao giờ commit secrets vào Git
|
||||
|
||||
### Monitoring / Giám Sát
|
||||
|
||||
**EN**:
|
||||
- Expose metrics endpoint (`/metrics`)
|
||||
- Set up alerts for critical issues
|
||||
- Monitor resource usage and performance
|
||||
- Use ServiceMonitor for Prometheus integration
|
||||
|
||||
**VI**:
|
||||
- Expose metrics endpoint (`/metrics`)
|
||||
- Thiết lập alerts cho các vấn đề quan trọng
|
||||
- Theo dõi sử dụng tài nguyên và hiệu suất
|
||||
- Sử dụng ServiceMonitor cho tích hợp Prometheus
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Production Deployment / Triển Khai Production
|
||||
|
||||
- **IAM Service**: [`deployments/production/kubernetes/iam-service.yaml`](../../../deployments/production/kubernetes/iam-service.yaml)
|
||||
- **ConfigMap**: [`deployments/production/kubernetes/iam-service-configmap.yaml`](../../../deployments/production/kubernetes/iam-service-configmap.yaml)
|
||||
- **Ingress**: [`deployments/production/kubernetes/ingress.yaml`](../../../deployments/production/kubernetes/ingress.yaml)
|
||||
|
||||
### Staging Deployment / Triển Khai Staging
|
||||
|
||||
- **IAM Service**: [`deployments/staging/kubernetes/iam-service.yaml`](../../../deployments/staging/kubernetes/iam-service.yaml)
|
||||
- **ConfigMap**: [`deployments/staging/kubernetes/iam-service-configmap.yaml`](../../../deployments/staging/kubernetes/iam-service-configmap.yaml)
|
||||
|
||||
### Health Check Implementation / Triển Khai Health Check
|
||||
|
||||
- **Health Controller**: [`services/iam-service/src/modules/health/health.controller.ts`](../../../services/iam-service/src/modules/health/health.controller.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Common Commands / Lệnh Thường Dùng
|
||||
|
||||
```bash
|
||||
# Deploy to production
|
||||
kubectl apply -f deployments/production/kubernetes/ -n production
|
||||
|
||||
# Check deployment status
|
||||
kubectl get deployments -n production
|
||||
kubectl get pods -n production
|
||||
kubectl get svc -n production
|
||||
|
||||
# View logs
|
||||
kubectl logs -f deployment/iam-service -n production
|
||||
kubectl logs -f pod-name -n production --tail=100
|
||||
|
||||
# Scale manually
|
||||
kubectl scale deployment iam-service --replicas=5 -n production
|
||||
|
||||
# Update image
|
||||
kubectl set image deployment/iam-service iam-service=goodgo/iam-service:v1.2.3 -n production
|
||||
|
||||
# Rollback
|
||||
kubectl rollout undo deployment/iam-service -n production
|
||||
|
||||
# Port forward for debugging
|
||||
kubectl port-forward service/iam-service 5001:5001 -n production
|
||||
|
||||
# Execute command in pod
|
||||
kubectl exec -it pod-name -n production -- /bin/sh
|
||||
|
||||
# View HPA status
|
||||
kubectl get hpa -n production
|
||||
kubectl describe hpa iam-service-hpa -n production
|
||||
|
||||
# View resource usage
|
||||
kubectl top nodes
|
||||
kubectl top pods -n production
|
||||
```
|
||||
|
||||
### Troubleshooting / Xử Lý Sự Cố
|
||||
|
||||
**Pod Not Starting / Pod Không Khởi Động**:
|
||||
```bash
|
||||
# Check pod status
|
||||
kubectl describe pod pod-name -n production
|
||||
|
||||
# Check events
|
||||
kubectl get events -n production --sort-by='.lastTimestamp'
|
||||
|
||||
# Check logs
|
||||
kubectl logs pod-name -n production --previous
|
||||
```
|
||||
|
||||
**ImagePullBackOff**:
|
||||
```bash
|
||||
# Check image name and tag
|
||||
kubectl describe pod pod-name -n production | grep -i image
|
||||
|
||||
# Check image pull secrets
|
||||
kubectl get secrets -n production
|
||||
```
|
||||
|
||||
**CrashLoopBackOff**:
|
||||
```bash
|
||||
# Check logs of crashed container
|
||||
kubectl logs pod-name -n production --previous
|
||||
|
||||
# Check resource limits
|
||||
kubectl describe pod pod-name -n production | grep -A 5 Limits
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- [Observability & Monitoring](./observability-monitoring.md) - Để giám sát các services đã triển khai
|
||||
- [Security](./security.md) - Để bảo mật các triển khai Kubernetes
|
||||
- [Project Rules](./project-rules.md) - Cho cấu trúc và tiêu chuẩn service
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### Official Documentation / Tài Liệu Chính Thức
|
||||
|
||||
- [Kubernetes Documentation](https://kubernetes.io/docs/)
|
||||
- [Kubernetes API Reference](https://kubernetes.io/docs/reference/kubernetes-api/)
|
||||
- [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)
|
||||
|
||||
### GoodGo Resources / Tài Nguyên GoodGo
|
||||
|
||||
- [Deployment Guide](../guides/deployment.md)
|
||||
- [Local Deployment Guide](../guides/local-deployment.md)
|
||||
- [Troubleshooting Guide](../guides/troubleshooting.md)
|
||||
535
docs/vi/skills/documentation.md
Normal file
535
docs/vi/skills/documentation.md
Normal file
@@ -0,0 +1,535 @@
|
||||
# Documentation / Tài Liệu
|
||||
|
||||
> **EN**: Guidelines for writing technical documentation in the GoodGo project. Use when creating or updating README files, guides, architecture docs, or API documentation. Ensures bilingual (EN/VI) consistency and proper structure.
|
||||
> **VI**: Hướng dẫn viết tài liệu kỹ thuật trong dự án GoodGo. Sử dụng khi tạo hoặc cập nhật file README, hướng dẫn, tài liệu kiến trúc hoặc tài liệu API. Đảm bảo tính nhất quán song ngữ (EN/VI) và cấu trúc phù hợp.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: The Documentation skill provides comprehensive guidelines for writing, structuring, and maintaining technical documentation in the GoodGo Microservices Platform. It covers documentation structure, bilingual formatting, templates, writing style, and best practices for maintaining documentation quality.
|
||||
|
||||
**VI**: Skill Documentation cung cấp hướng dẫn toàn diện để viết, cấu trúc và duy trì tài liệu kỹ thuật trong GoodGo Microservices Platform. Nó bao gồm cấu trúc tài liệu, định dạng song ngữ, template, phong cách viết và thực hành tốt nhất để duy trì chất lượng tài liệu.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Creating new documentation files
|
||||
- Updating existing documentation
|
||||
- Writing README files for services or packages
|
||||
- Creating guides or tutorials
|
||||
- Documenting API endpoints
|
||||
- Writing architecture documentation
|
||||
- Creating deployment documentation
|
||||
- Writing runbooks or operational guides
|
||||
- Ensuring bilingual consistency
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Tạo file tài liệu mới
|
||||
- Cập nhật tài liệu hiện có
|
||||
- Viết file README cho services hoặc packages
|
||||
- Tạo hướng dẫn hoặc tutorial
|
||||
- Tài liệu hóa API endpoints
|
||||
- Viết tài liệu kiến trúc
|
||||
- Tạo tài liệu triển khai
|
||||
- Viết runbook hoặc hướng dẫn vận hành
|
||||
- Đảm bảo tính nhất quán song ngữ
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Documentation Structure / Cấu Trúc Tài Liệu
|
||||
|
||||
**EN**: The project follows a structured documentation hierarchy:
|
||||
|
||||
```
|
||||
docs/
|
||||
├── en/ # English documentation
|
||||
│ ├── guides/ # How-to guides
|
||||
│ ├── architecture/ # System design docs
|
||||
│ ├── api/ # API documentation
|
||||
│ ├── onboarding/ # New developer guides
|
||||
│ ├── runbooks/ # Operational guides
|
||||
│ └── skills/ # Skill documentation
|
||||
├── vi/ # Vietnamese documentation (mirror structure)
|
||||
└── README.md # Documentation index
|
||||
```
|
||||
|
||||
**VI**: Dự án tuân theo hệ thống phân cấp tài liệu có cấu trúc:
|
||||
|
||||
```
|
||||
docs/
|
||||
├── en/ # Tài liệu tiếng Anh
|
||||
│ ├── guides/ # Hướng dẫn cách làm
|
||||
│ ├── architecture/ # Tài liệu thiết kế hệ thống
|
||||
│ ├── api/ # Tài liệu API
|
||||
│ ├── onboarding/ # Hướng dẫn cho developer mới
|
||||
│ ├── runbooks/ # Hướng dẫn vận hành
|
||||
│ └── skills/ # Tài liệu skills
|
||||
├── vi/ # Tài liệu tiếng Việt (cấu trúc tương tự)
|
||||
└── README.md # Mục lục tài liệu
|
||||
```
|
||||
|
||||
### Bilingual Documentation Rules / Quy Tắc Tài Liệu Song Ngữ
|
||||
|
||||
**EN**: The project maintains bilingual documentation (English and Vietnamese). Three formats are used:
|
||||
|
||||
1. **Side-by-side**: Short content with EN and VI on the same line
|
||||
2. **Separate files**: Long content in separate EN and VI files
|
||||
3. **Sections**: Mixed content with separate EN and VI sections
|
||||
|
||||
**VI**: Dự án duy trì tài liệu song ngữ (Tiếng Anh và Tiếng Việt). Ba định dạng được sử dụng:
|
||||
|
||||
1. **Side-by-side**: Nội dung ngắn với EN và VI trên cùng một dòng
|
||||
2. **Separate files**: Nội dung dài trong các file EN và VI riêng biệt
|
||||
3. **Sections**: Nội dung hỗn hợp với các phần EN và VI riêng biệt
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Service README Template / Template README Service
|
||||
|
||||
**EN**: Example structure from `services/iam-service/README.md`:
|
||||
|
||||
```markdown
|
||||
# Service Name / Tên Dịch Vụ
|
||||
|
||||
> **EN**: Brief description in English
|
||||
> **VI**: Mô tả ngắn gọn bằng tiếng Việt
|
||||
|
||||
## Features / Tính Năng
|
||||
|
||||
- Feature 1 / Tính năng 1
|
||||
- Feature 2 / Tính năng 2
|
||||
|
||||
## Prerequisites / Yêu Cầu
|
||||
|
||||
- Node.js 20+
|
||||
- PostgreSQL (Neon)
|
||||
- Redis
|
||||
|
||||
## Quick Start / Bắt Đầu Nhanh
|
||||
|
||||
```bash
|
||||
# Install dependencies / Cài đặt dependencies
|
||||
pnpm install
|
||||
|
||||
# Setup environment / Thiết lập môi trường
|
||||
cp .env.example .env
|
||||
|
||||
# Start service / Khởi động service
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Configuration / Cấu Hình
|
||||
|
||||
| Variable | Description / Mô Tả | Default | Required |
|
||||
|----------|---------------------|---------|----------|
|
||||
| PORT | Server port / Cổng server | 5000 | No |
|
||||
|
||||
## API Endpoints
|
||||
|
||||
See [API Documentation](../api/openapi/iam-service.yaml)
|
||||
```
|
||||
|
||||
**VI**: Ví dụ cấu trúc từ `services/iam-service/README.md`:
|
||||
|
||||
```markdown
|
||||
# Service Name / Tên Dịch Vụ
|
||||
|
||||
> **EN**: Brief description in English
|
||||
> **VI**: Mô tả ngắn gọn bằng tiếng Việt
|
||||
|
||||
## Features / Tính Năng
|
||||
|
||||
- Feature 1 / Tính năng 1
|
||||
- Feature 2 / Tính năng 2
|
||||
|
||||
## Prerequisites / Yêu Cầu
|
||||
|
||||
- Node.js 20+
|
||||
- PostgreSQL (Neon)
|
||||
- Redis
|
||||
|
||||
## Quick Start / Bắt Đầu Nhanh
|
||||
|
||||
```bash
|
||||
# Install dependencies / Cài đặt dependencies
|
||||
pnpm install
|
||||
|
||||
# Setup environment / Thiết lập môi trường
|
||||
cp .env.example .env
|
||||
|
||||
# Start service / Khởi động service
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Configuration / Cấu Hình
|
||||
|
||||
| Variable | Description / Mô Tả | Default | Required |
|
||||
|----------|---------------------|---------|----------|
|
||||
| PORT | Server port / Cổng server | 5000 | No |
|
||||
|
||||
## API Endpoints
|
||||
|
||||
See [API Documentation](../api/openapi/iam-service.yaml)
|
||||
```
|
||||
|
||||
### Guide Template / Template Hướng Dẫn
|
||||
|
||||
**EN**: Example from `docs/en/guides/getting-started.md`:
|
||||
|
||||
```markdown
|
||||
# Getting Started
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js >= 20.0.0
|
||||
- PNPM >= 8.0.0
|
||||
- Docker & Docker Compose
|
||||
- Git
|
||||
- Neon account (https://neon.tech) - for database
|
||||
|
||||
## Initial Setup
|
||||
|
||||
1. **Clone the repository**
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
```
|
||||
|
||||
2. **Setup Neon Database**
|
||||
```bash
|
||||
# Run setup script
|
||||
./scripts/db/setup-neon.sh
|
||||
```
|
||||
|
||||
See [Neon Setup Guide](../../../infra/databases/neon/README.md) for details.
|
||||
|
||||
3. **Initialize the project**
|
||||
```bash
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Read [Development Guide](../guides/development.md)
|
||||
- Check [API Documentation](../api/openapi/)
|
||||
- Review [Architecture Overview](../architecture/system-design.md)
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `docs/vi/guides/getting-started.md`:
|
||||
|
||||
```markdown
|
||||
# Bắt Đầu
|
||||
|
||||
## Yêu Cầu
|
||||
|
||||
- Node.js >= 20.0.0
|
||||
- PNPM >= 8.0.0
|
||||
- Docker & Docker Compose
|
||||
- Git
|
||||
- Tài khoản Neon (https://neon.tech) - cho database
|
||||
|
||||
## Thiết Lập Ban Đầu
|
||||
|
||||
1. **Clone repository**
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
```
|
||||
|
||||
2. **Thiết lập Neon Database**
|
||||
```bash
|
||||
# Chạy script setup
|
||||
./scripts/db/setup-neon.sh
|
||||
```
|
||||
|
||||
Xem [Hướng Dẫn Thiết Lập Neon](../../../infra/databases/neon/README.md) để biết chi tiết.
|
||||
|
||||
3. **Khởi tạo dự án**
|
||||
```bash
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
|
||||
## Bước Tiếp Theo
|
||||
|
||||
- Đọc [Hướng Dẫn Phát Triển](../guides/development.md)
|
||||
- Xem [Tài Liệu API](../api/openapi/)
|
||||
- Xem lại [Tổng Quan Kiến Trúc](../architecture/system-design.md)
|
||||
```
|
||||
|
||||
### Architecture Document Template / Template Tài Liệu Kiến Trúc
|
||||
|
||||
**EN**: Example from `docs/en/architecture/system-design.md`:
|
||||
|
||||
```markdown
|
||||
# System Design
|
||||
|
||||
## Overview
|
||||
|
||||
GoodGo Microservices Platform is built using a microservices architecture pattern with the following principles:
|
||||
|
||||
- **Service Independence**: Each service has its own database and can be deployed independently
|
||||
- **API Gateway**: Traefik handles routing, load balancing, and cross-cutting concerns
|
||||
- **Shared Libraries**: Common functionality is extracted into shared packages
|
||||
- **Infrastructure as Code**: All infrastructure configurations are versioned
|
||||
- **Observability**: Full monitoring, logging, and tracing capabilities
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Web App │ │ Mobile App │
|
||||
│ (Next.js) │ │ (React Native)
|
||||
└──────┬──────┘ └──────┬──────┘
|
||||
│ │
|
||||
└──────────┬────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ Traefik │
|
||||
│ (API Gateway) │
|
||||
└────────┬─────────┘
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### Frontend Layer
|
||||
- **Web App**: Next.js application with App Router
|
||||
- **Mobile App**: React Native application
|
||||
|
||||
### API Gateway
|
||||
- **Traefik**: Reverse proxy, load balancer, SSL termination
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `docs/vi/architecture/system-design.md`:
|
||||
|
||||
```markdown
|
||||
# Thiết Kế Hệ Thống
|
||||
|
||||
## Tổng Quan
|
||||
|
||||
GoodGo Microservices Platform được xây dựng bằng mẫu kiến trúc microservices với các nguyên tắc sau:
|
||||
|
||||
- **Độc Lập Dịch Vụ**: Mỗi service có database riêng và có thể triển khai độc lập
|
||||
- **API Gateway**: Traefik xử lý routing, load balancing và các mối quan tâm chéo
|
||||
- **Thư Viện Dùng Chung**: Chức năng chung được trích xuất thành packages dùng chung
|
||||
- **Infrastructure as Code**: Tất cả cấu hình infrastructure được version
|
||||
- **Observability**: Khả năng giám sát, logging và tracing đầy đủ
|
||||
|
||||
## Sơ Đồ Kiến Trúc
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Web App │ │ Mobile App │
|
||||
│ (Next.js) │ │ (React Native)
|
||||
└──────┬──────┘ └──────┬──────┘
|
||||
│ │
|
||||
└──────────┬────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ Traefik │
|
||||
│ (API Gateway) │
|
||||
└────────┬─────────┘
|
||||
```
|
||||
|
||||
## Thành Phần
|
||||
|
||||
### Lớp Frontend
|
||||
- **Web App**: Ứng dụng Next.js với App Router
|
||||
- **Mobile App**: Ứng dụng React Native
|
||||
|
||||
### API Gateway
|
||||
- **Traefik**: Reverse proxy, load balancer, SSL termination
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Writing Style / Phong Cách Viết
|
||||
|
||||
**EN**:
|
||||
1. **Clear and Concise**: Use simple language, avoid jargon
|
||||
2. **Action-Oriented**: Start with verbs (Install, Configure, Deploy)
|
||||
3. **Structured**: Use headings, lists, and tables
|
||||
4. **Examples**: Provide code examples and commands
|
||||
5. **Visual**: Use diagrams where helpful
|
||||
|
||||
**VI**:
|
||||
1. **Rõ Ràng và Súc Tích**: Sử dụng ngôn ngữ đơn giản, tránh thuật ngữ
|
||||
2. **Hướng Hành Động**: Bắt đầu bằng động từ (Cài đặt, Cấu hình, Triển khai)
|
||||
3. **Có Cấu Trúc**: Sử dụng tiêu đề, danh sách và bảng
|
||||
4. **Ví Dụ**: Cung cấp ví dụ code và lệnh
|
||||
5. **Trực Quan**: Sử dụng sơ đồ khi hữu ích
|
||||
|
||||
### Code Examples / Ví Dụ Code
|
||||
|
||||
**EN**: Always provide context and explanation:
|
||||
|
||||
```markdown
|
||||
# Good: With context and explanation
|
||||
Install dependencies using pnpm:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
# Bad: No context
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
```
|
||||
|
||||
**VI**: Luôn cung cấp ngữ cảnh và giải thích:
|
||||
|
||||
```markdown
|
||||
# Tốt: Có ngữ cảnh và giải thích
|
||||
Cài đặt dependencies sử dụng pnpm:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
# Không tốt: Không có ngữ cảnh
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
```
|
||||
|
||||
### Links / Liên Kết
|
||||
|
||||
**EN**:
|
||||
- Use relative links for internal docs
|
||||
- Use descriptive link text (not "click here")
|
||||
- Example: `See the [Deployment Guide](../guides/deployment.md) for details.`
|
||||
|
||||
**VI**:
|
||||
- Sử dụng liên kết tương đối cho tài liệu nội bộ
|
||||
- Sử dụng văn bản liên kết mô tả (không phải "click here")
|
||||
- Ví dụ: `Xem [Hướng Dẫn Triển Khai](../guides/deployment.md) để biết chi tiết.`
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Good Documentation Examples / Ví Dụ Tài Liệu Tốt
|
||||
|
||||
**EN**:
|
||||
- `docs/en/guides/getting-started.md` - Clear step-by-step guide
|
||||
- `services/iam-service/README.md` - Comprehensive service README
|
||||
- `docs/en/architecture/system-design.md` - Architecture documentation
|
||||
- `docs/README.md` - Documentation index
|
||||
|
||||
**VI**:
|
||||
- `docs/vi/guides/getting-started.md` - Hướng dẫn từng bước rõ ràng
|
||||
- `services/iam-service/README.md` - README service toàn diện
|
||||
- `docs/vi/architecture/system-design.md` - Tài liệu kiến trúc
|
||||
- `docs/README.md` - Mục lục tài liệu
|
||||
|
||||
### Documentation Locations Reference / Tham Chiếu Vị Trí Tài Liệu
|
||||
|
||||
**EN**:
|
||||
|
||||
| Content Type | Location | Format |
|
||||
|--------------|----------|--------|
|
||||
| Getting Started | `docs/en/guides/getting-started.md` | Separate files |
|
||||
| Service Setup | `services/[name]/README.md` | Side-by-side |
|
||||
| Deployment | `docs/en/guides/deployment.md` | Separate files |
|
||||
| Architecture | `docs/en/architecture/` | Separate files |
|
||||
| API Specs | `docs/en/api/openapi/` | OpenAPI YAML |
|
||||
| Runbooks | `docs/en/runbooks/` | Separate files |
|
||||
| Infrastructure | `infra/[component]/README.md` | Side-by-side |
|
||||
|
||||
**VI**:
|
||||
|
||||
| Loại Nội Dung | Vị Trí | Định Dạng |
|
||||
|--------------|--------|----------|
|
||||
| Bắt Đầu | `docs/vi/guides/getting-started.md` | File riêng biệt |
|
||||
| Thiết Lập Service | `services/[name]/README.md` | Side-by-side |
|
||||
| Triển Khai | `docs/vi/guides/deployment.md` | File riêng biệt |
|
||||
| Kiến Trúc | `docs/vi/architecture/` | File riêng biệt |
|
||||
| Spec API | `docs/vi/api/openapi/` | OpenAPI YAML |
|
||||
| Runbooks | `docs/vi/runbooks/` | File riêng biệt |
|
||||
| Infrastructure | `infra/[component]/README.md` | Side-by-side |
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### File Naming / Đặt Tên File
|
||||
|
||||
**EN**:
|
||||
- Use kebab-case: `getting-started.md`
|
||||
- Be descriptive: `local-development.md` not `dev.md`
|
||||
- Match EN and VI filenames
|
||||
|
||||
**VI**:
|
||||
- Sử dụng kebab-case: `getting-started.md`
|
||||
- Mô tả rõ ràng: `local-development.md` không phải `dev.md`
|
||||
- Khớp tên file EN và VI
|
||||
|
||||
### Heading Levels / Cấp Độ Tiêu Đề
|
||||
|
||||
```markdown
|
||||
# H1: Document Title (only one per file)
|
||||
## H2: Major Sections
|
||||
### H3: Subsections
|
||||
#### H4: Details (use sparingly)
|
||||
```
|
||||
|
||||
### Bilingual Patterns / Mẫu Song Ngữ
|
||||
|
||||
```markdown
|
||||
# Pattern 1: Inline
|
||||
Description / Mô tả
|
||||
|
||||
# Pattern 2: After slash
|
||||
PORT=5000 # Server port / Cổng server
|
||||
|
||||
# Pattern 3: Table
|
||||
| Variable | Description / Mô Tả |
|
||||
|
||||
# Pattern 4: Code comments
|
||||
# EN: Install dependencies
|
||||
# VI: Cài đặt dependencies
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Documentation Checklist / Danh Sách Kiểm Tra Tài Liệu
|
||||
|
||||
**EN**: Before publishing documentation:
|
||||
- [ ] Determine correct location (docs/ vs service README)
|
||||
- [ ] Choose bilingual format (side-by-side vs separate)
|
||||
- [ ] Review existing docs for consistency
|
||||
- [ ] Use clear, concise language
|
||||
- [ ] Include code examples
|
||||
- [ ] Add diagrams where helpful
|
||||
- [ ] Provide troubleshooting section
|
||||
- [ ] Link to related documentation
|
||||
- [ ] Test all commands and code examples
|
||||
- [ ] Check all links work
|
||||
- [ ] Ensure bilingual consistency
|
||||
- [ ] Update documentation index
|
||||
|
||||
**VI**: Trước khi xuất bản tài liệu:
|
||||
- [ ] Xác định vị trí đúng (docs/ vs service README)
|
||||
- [ ] Chọn định dạng song ngữ (side-by-side vs separate)
|
||||
- [ ] Xem lại tài liệu hiện có để đảm bảo tính nhất quán
|
||||
- [ ] Sử dụng ngôn ngữ rõ ràng, súc tích
|
||||
- [ ] Bao gồm ví dụ code
|
||||
- [ ] Thêm sơ đồ khi hữu ích
|
||||
- [ ] Cung cấp phần xử lý sự cố
|
||||
- [ ] Liên kết đến tài liệu liên quan
|
||||
- [ ] Kiểm tra tất cả lệnh và ví dụ code
|
||||
- [ ] Kiểm tra tất cả liên kết hoạt động
|
||||
- [ ] Đảm bảo tính nhất quán song ngữ
|
||||
- [ ] Cập nhật mục lục tài liệu
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Project Rules](./project-rules.md)** - Project structure and standards
|
||||
- **[API Design](./api-design.md)** - API documentation patterns
|
||||
- **[Comment Code](./comment-code.md)** - Code commenting guidelines
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- [Markdown Guide](https://www.markdownguide.org/)
|
||||
- [Mermaid Diagrams](https://mermaid.js.org/)
|
||||
- [Documentation Best Practices](https://www.writethedocs.org/guide/)
|
||||
|
||||
**VI**:
|
||||
- [Hướng Dẫn Markdown](https://www.markdownguide.org/)
|
||||
- [Sơ Đồ Mermaid](https://mermaid.js.org/)
|
||||
- [Thực Hành Tốt Nhất Tài Liệu](https://www.writethedocs.org/guide/)
|
||||
565
docs/vi/skills/observability-monitoring.md
Normal file
565
docs/vi/skills/observability-monitoring.md
Normal file
@@ -0,0 +1,565 @@
|
||||
# Observability & Monitoring / Khả Năng Quan Sát & Giám Sát
|
||||
|
||||
> **EN**: Observability and monitoring patterns for GoodGo microservices. Use when adding metrics, implementing logging, setting up tracing, creating health checks, or debugging production issues.
|
||||
> **VI**: Các pattern observability và monitoring cho microservices GoodGo. Sử dụng khi thêm metrics, triển khai logging, thiết lập tracing, tạo health checks, hoặc debug các vấn đề production.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: This skill covers the three pillars of observability (logs, metrics, traces) and how to implement them in GoodGo microservices. It includes structured logging, Prometheus metrics, distributed tracing with OpenTelemetry, health checks, and error tracking.
|
||||
|
||||
**VI**: Skill này bao gồm ba trụ cột của observability (logs, metrics, traces) và cách triển khai chúng trong microservices GoodGo. Nó bao gồm structured logging, Prometheus metrics, distributed tracing với OpenTelemetry, health checks, và error tracking.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Setting up logging infrastructure
|
||||
- Implementing metrics collection
|
||||
- Adding distributed tracing
|
||||
- Creating health check endpoints
|
||||
- Setting up monitoring dashboards
|
||||
- Debugging production issues
|
||||
- Implementing alerting rules
|
||||
- Analyzing performance bottlenecks
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Thiết lập hạ tầng logging
|
||||
- Triển khai thu thập metrics
|
||||
- Thêm distributed tracing
|
||||
- Tạo health check endpoints
|
||||
- Thiết lập monitoring dashboards
|
||||
- Debug các vấn đề production
|
||||
- Triển khai alerting rules
|
||||
- Phân tích performance bottlenecks
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Three Pillars of Observability / Ba Trụ Cột Của Observability
|
||||
|
||||
**EN**:
|
||||
1. **Logs**: Event records for debugging and auditing
|
||||
2. **Metrics**: Numerical measurements over time (counters, gauges, histograms)
|
||||
3. **Traces**: Request flow across services (distributed tracing)
|
||||
|
||||
**VI**:
|
||||
1. **Logs**: Bản ghi sự kiện để debug và audit
|
||||
2. **Metrics**: Đo lường số học theo thời gian (counters, gauges, histograms)
|
||||
3. **Traces**: Luồng request qua các services (distributed tracing)
|
||||
|
||||
### Tech Stack / Công Nghệ
|
||||
|
||||
**EN**:
|
||||
- **Logging**: `@goodgo/logger` (Pino-based structured logging)
|
||||
- **Metrics**: Prometheus + Grafana
|
||||
- **Tracing**: OpenTelemetry + Jaeger (`@goodgo/tracing`)
|
||||
- **Correlation IDs**: Request tracking across services
|
||||
|
||||
**VI**:
|
||||
- **Logging**: `@goodgo/logger` (structured logging dựa trên Pino)
|
||||
- **Metrics**: Prometheus + Grafana
|
||||
- **Tracing**: OpenTelemetry + Jaeger (`@goodgo/tracing`)
|
||||
- **Correlation IDs**: Theo dõi request qua các services
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Structured Logging / Logging Có Cấu Trúc
|
||||
|
||||
**EN**: Use structured logging with correlation IDs for request tracking.
|
||||
|
||||
**VI**: Sử dụng structured logging với correlation IDs để theo dõi request.
|
||||
|
||||
**Ví dụ từ codebase**: [`services/iam-service/src/middlewares/logger.middleware.ts`](../../../services/iam-service/src/middlewares/logger.middleware.ts)
|
||||
|
||||
```typescript
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { logger } from '@goodgo/logger';
|
||||
import { getCorrelationId, getRequestId } from './correlation.middleware';
|
||||
|
||||
export const requestLogger = (req: Request, res: Response, next: NextFunction): void => {
|
||||
// Bỏ qua logging chi tiết cho health checks và metrics
|
||||
if (req.path.startsWith('/health') || req.path.startsWith('/metrics')) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
res.on('finish', () => {
|
||||
const duration = Date.now() - start;
|
||||
const correlationId = getCorrelationId(req);
|
||||
const requestId = getRequestId(req);
|
||||
|
||||
logger.info('Request processed / Request đã xử lý', {
|
||||
correlationId,
|
||||
requestId,
|
||||
method: req.method,
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
statusCode: res.statusCode,
|
||||
duration: `${duration}ms`,
|
||||
contentLength: res.get('Content-Length') || 0,
|
||||
userAgent: req.get('User-Agent'),
|
||||
ip: req.ip,
|
||||
userId: (req as any).user?.userId,
|
||||
});
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
```
|
||||
|
||||
### Correlation IDs / Correlation IDs
|
||||
|
||||
**EN**: Use correlation IDs to track requests across services.
|
||||
|
||||
**VI**: Sử dụng correlation IDs để theo dõi request qua các services.
|
||||
|
||||
**Ví dụ từ codebase**: [`services/iam-service/src/middlewares/correlation.middleware.ts`](../../../services/iam-service/src/middlewares/correlation.middleware.ts)
|
||||
|
||||
```typescript
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
export const CORRELATION_ID_HEADER = 'x-correlation-id';
|
||||
export const REQUEST_ID_HEADER = 'x-request-id';
|
||||
|
||||
export const correlationMiddleware = (
|
||||
options: {
|
||||
headerName?: string;
|
||||
generateId?: () => string;
|
||||
skipPaths?: string[];
|
||||
} = {}
|
||||
) => {
|
||||
const {
|
||||
headerName = CORRELATION_ID_HEADER,
|
||||
generateId = randomUUID,
|
||||
skipPaths = ['/health', '/metrics', '/favicon.ico'],
|
||||
} = options;
|
||||
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
// Lấy correlation ID từ header hoặc tạo mới
|
||||
const correlationId = req.headers[headerName.toLowerCase()] as string || generateId();
|
||||
const requestId = generateId();
|
||||
|
||||
// Gắn vào request object
|
||||
req.correlationId = correlationId;
|
||||
req.requestId = requestId;
|
||||
|
||||
// Thêm vào response headers
|
||||
res.setHeader(headerName, correlationId);
|
||||
res.setHeader(REQUEST_ID_HEADER, requestId);
|
||||
|
||||
// Log request start
|
||||
logger.info('Request started / Request bắt đầu', {
|
||||
correlationId,
|
||||
requestId,
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
userAgent: req.get('User-Agent'),
|
||||
ip: req.ip,
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Metrics Collection / Thu Thập Metrics
|
||||
|
||||
**EN**: Expose Prometheus metrics for monitoring and alerting.
|
||||
|
||||
**VI**: Expose Prometheus metrics để monitoring và alerting.
|
||||
|
||||
**Ví dụ từ codebase**: [`services/iam-service/src/middlewares/metrics.middleware.ts`](../../../services/iam-service/src/middlewares/metrics.middleware.ts)
|
||||
|
||||
```typescript
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import client from 'prom-client';
|
||||
import { getCorrelationId } from './correlation.middleware';
|
||||
|
||||
// Tạo Registry để đăng ký các metrics
|
||||
const register = client.register;
|
||||
|
||||
// Thu thập các metrics mặc định
|
||||
client.collectDefaultMetrics({ register });
|
||||
|
||||
// Tạo histogram cho thời lượng request HTTP
|
||||
const httpRequestDurationSeconds = new client.Histogram({
|
||||
name: 'http_request_duration_seconds',
|
||||
help: 'Duration of HTTP requests in seconds',
|
||||
labelNames: ['method', 'route', 'status_code', 'correlation_id'],
|
||||
buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5, 10],
|
||||
});
|
||||
|
||||
// Tạo counter cho tổng số request HTTP
|
||||
const httpRequestsTotal = new client.Counter({
|
||||
name: 'http_requests_total',
|
||||
help: 'Total number of HTTP requests',
|
||||
labelNames: ['method', 'route', 'status_code'],
|
||||
});
|
||||
|
||||
// Tạo gauge cho active requests
|
||||
const activeRequests = new client.Gauge({
|
||||
name: 'http_active_requests',
|
||||
help: 'Number of active HTTP requests',
|
||||
});
|
||||
|
||||
// Tạo counter cho lỗi HTTP request
|
||||
const httpRequestErrors = new client.Counter({
|
||||
name: 'http_request_errors_total',
|
||||
help: 'Total number of HTTP request errors',
|
||||
labelNames: ['method', 'route', 'error_type'],
|
||||
});
|
||||
|
||||
export const metricsMiddleware = (req: Request, res: Response, next: NextFunction) => {
|
||||
// Tăng active requests
|
||||
activeRequests.inc();
|
||||
|
||||
// Bắt đầu bấm giờ
|
||||
const start = process.hrtime.bigint();
|
||||
|
||||
res.on('finish', () => {
|
||||
// Giảm active requests
|
||||
activeRequests.dec();
|
||||
|
||||
// Tính toán thời lượng
|
||||
const end = process.hrtime.bigint();
|
||||
const durationInSeconds = Number(end - start) / 1e9;
|
||||
|
||||
// Chuẩn hóa path để tránh high cardinality
|
||||
const route = normalizeRoutePath(req);
|
||||
const correlationId = getCorrelationId(req) || 'unknown';
|
||||
|
||||
// Ghi nhận thời lượng
|
||||
httpRequestDurationSeconds
|
||||
.labels(req.method, route, res.statusCode.toString(), correlationId)
|
||||
.observe(durationInSeconds);
|
||||
|
||||
// Tăng bộ đếm request
|
||||
httpRequestsTotal
|
||||
.labels(req.method, route, res.statusCode.toString())
|
||||
.inc();
|
||||
|
||||
// Theo dõi lỗi
|
||||
if (res.statusCode >= 400) {
|
||||
const errorType = res.statusCode >= 500 ? 'server_error' : 'client_error';
|
||||
httpRequestErrors
|
||||
.labels(req.method, route, errorType)
|
||||
.inc();
|
||||
}
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
// Chuẩn hóa route path để ngăn high cardinality metrics
|
||||
function normalizeRoutePath(req: Request): string {
|
||||
if (req.route && req.route.path) {
|
||||
return req.route.path;
|
||||
}
|
||||
|
||||
let path = req.path;
|
||||
// Thay thế UUIDs và numeric IDs bằng placeholders
|
||||
path = path.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ':uuid');
|
||||
path = path.replace(/\d+/g, ':id');
|
||||
|
||||
return path;
|
||||
}
|
||||
```
|
||||
|
||||
### Distributed Tracing / Distributed Tracing
|
||||
|
||||
**EN**: Use OpenTelemetry for distributed tracing across services.
|
||||
|
||||
**VI**: Sử dụng OpenTelemetry cho distributed tracing qua các services.
|
||||
|
||||
**Ví dụ từ codebase**: [`packages/tracing/src/index.ts`](../../../packages/tracing/src/index.ts)
|
||||
|
||||
```typescript
|
||||
import { NodeSDK } from '@opentelemetry/sdk-node';
|
||||
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
||||
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';
|
||||
import { Resource } from '@opentelemetry/resources';
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
||||
|
||||
export interface TracingConfig {
|
||||
serviceName: string;
|
||||
jaegerEndpoint?: string;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export const initTracing = (config: TracingConfig): NodeSDK | null => {
|
||||
if (config.enabled === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Tạo Jaeger exporter nếu endpoint được cung cấp
|
||||
const jaegerExporter = config.jaegerEndpoint
|
||||
? new JaegerExporter({
|
||||
endpoint: config.jaegerEndpoint,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
// Khởi tạo OpenTelemetry NodeSDK với auto-instrumentations
|
||||
const sdk = new NodeSDK({
|
||||
resource: new Resource({
|
||||
[SemanticResourceAttributes.SERVICE_NAME]: config.serviceName,
|
||||
}),
|
||||
traceExporter: jaegerExporter,
|
||||
instrumentations: [getNodeAutoInstrumentations()],
|
||||
});
|
||||
|
||||
// Khởi động tracing SDK
|
||||
sdk.start();
|
||||
|
||||
return sdk;
|
||||
};
|
||||
```
|
||||
|
||||
**Cách sử dụng trong service**:
|
||||
|
||||
```typescript
|
||||
// services/iam-service/src/main.ts
|
||||
import { initTracing } from '@goodgo/tracing';
|
||||
|
||||
// Khởi tạo tracing
|
||||
if (process.env.TRACING_ENABLED === 'true') {
|
||||
initTracing({
|
||||
serviceName: process.env.SERVICE_NAME || 'iam-service',
|
||||
jaegerEndpoint: process.env.JAEGER_ENDPOINT,
|
||||
enabled: true,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Health Checks / Kiểm Tra Sức Khỏe
|
||||
|
||||
**EN**: Implement liveness and readiness probes for Kubernetes.
|
||||
|
||||
**VI**: Triển khai liveness và readiness probes cho Kubernetes.
|
||||
|
||||
**Ví dụ từ codebase**: [`services/iam-service/src/modules/health/health.controller.ts`](../../../services/iam-service/src/modules/health/health.controller.ts)
|
||||
|
||||
```typescript
|
||||
import { Request, Response } from 'express';
|
||||
import { prisma } from '../../config/database.config';
|
||||
import { ApiResponse } from '@goodgo/types';
|
||||
|
||||
export class HealthController {
|
||||
/**
|
||||
* EN: Basic liveness probe
|
||||
* VI: Kiểm tra liveness cơ bản
|
||||
*/
|
||||
health = async (_req: Request, res: Response): Promise<void> => {
|
||||
const response: ApiResponse<{ status: string; timestamp: string }> = {
|
||||
success: true,
|
||||
data: {
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
res.json(response);
|
||||
};
|
||||
|
||||
/**
|
||||
* EN: Readiness probe (checks database connection)
|
||||
* VI: Kiểm tra readiness (kiểm tra kết nối database)
|
||||
*/
|
||||
ready = async (_req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
// Kiểm tra kết nối database
|
||||
await prisma.$queryRaw`SELECT 1`;
|
||||
res.json({
|
||||
success: true,
|
||||
data: { status: 'ready' },
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
} catch (error) {
|
||||
// Trả về 503 nếu database chưa sẵn sàng
|
||||
res.status(503).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'HEALTH_001',
|
||||
message: 'Service not ready',
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* EN: Alias for health check
|
||||
* VI: Alias cho kiểm tra sức khỏe
|
||||
*/
|
||||
live = async (_req: Request, res: Response): Promise<void> => {
|
||||
res.json({
|
||||
success: true,
|
||||
data: { status: 'live' },
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Logging / Logging
|
||||
|
||||
**EN**:
|
||||
- Use structured logging (JSON format)
|
||||
- Include correlation IDs for request tracing
|
||||
- Log at appropriate levels (ERROR, WARN, INFO, DEBUG)
|
||||
- Avoid logging sensitive data (passwords, tokens, PII)
|
||||
- Use consistent log format across services
|
||||
|
||||
**VI**:
|
||||
- Sử dụng structured logging (định dạng JSON)
|
||||
- Bao gồm correlation IDs để theo dõi request
|
||||
- Log ở mức độ phù hợp (ERROR, WARN, INFO, DEBUG)
|
||||
- Tránh log dữ liệu nhạy cảm (mật khẩu, tokens, PII)
|
||||
- Sử dụng format log nhất quán giữa các services
|
||||
|
||||
### Metrics / Metrics
|
||||
|
||||
**EN**:
|
||||
- Use standard metric types (Counter, Gauge, Histogram)
|
||||
- Keep cardinality low (avoid high-cardinality labels)
|
||||
- Define SLIs and SLOs for critical paths
|
||||
- Monitor business metrics, not just technical ones
|
||||
- Normalize route paths to prevent high cardinality
|
||||
|
||||
**VI**:
|
||||
- Sử dụng các loại metric chuẩn (Counter, Gauge, Histogram)
|
||||
- Giữ cardinality thấp (tránh high-cardinality labels)
|
||||
- Định nghĩa SLIs và SLOs cho các đường dẫn quan trọng
|
||||
- Giám sát business metrics, không chỉ technical metrics
|
||||
- Chuẩn hóa route paths để tránh high cardinality
|
||||
|
||||
### Tracing / Tracing
|
||||
|
||||
**EN**:
|
||||
- Add traces for critical operations
|
||||
- Include relevant context in spans
|
||||
- Sample appropriately to control costs
|
||||
- Use distributed tracing for microservices
|
||||
- Propagate correlation IDs across service boundaries
|
||||
|
||||
**VI**:
|
||||
- Thêm traces cho các thao tác quan trọng
|
||||
- Bao gồm context liên quan trong spans
|
||||
- Sample phù hợp để kiểm soát chi phí
|
||||
- Sử dụng distributed tracing cho microservices
|
||||
- Truyền correlation IDs qua ranh giới service
|
||||
|
||||
### Alerting / Cảnh Báo
|
||||
|
||||
**EN**:
|
||||
- Alert on symptoms, not causes
|
||||
- Include runbook links in alerts
|
||||
- Avoid alert fatigue with proper thresholds
|
||||
- Test alerting rules regularly
|
||||
- Use correlation IDs in alert context
|
||||
|
||||
**VI**:
|
||||
- Cảnh báo về triệu chứng, không phải nguyên nhân
|
||||
- Bao gồm links runbook trong alerts
|
||||
- Tránh alert fatigue với thresholds phù hợp
|
||||
- Test alerting rules thường xuyên
|
||||
- Sử dụng correlation IDs trong alert context
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Logging Implementation / Triển Khai Logging
|
||||
|
||||
- **Request Logger**: [`services/iam-service/src/middlewares/logger.middleware.ts`](../../../services/iam-service/src/middlewares/logger.middleware.ts)
|
||||
- **Correlation Middleware**: [`services/iam-service/src/middlewares/correlation.middleware.ts`](../../../services/iam-service/src/middlewares/correlation.middleware.ts)
|
||||
|
||||
### Metrics Implementation / Triển Khai Metrics
|
||||
|
||||
- **Metrics Middleware**: [`services/iam-service/src/middlewares/metrics.middleware.ts`](../../../services/iam-service/src/middlewares/metrics.middleware.ts)
|
||||
- **Metrics Endpoint**: Exposed at `/metrics` in all services
|
||||
|
||||
### Tracing Implementation / Triển Khai Tracing
|
||||
|
||||
- **Tracing Package**: [`packages/tracing/src/index.ts`](../../../packages/tracing/src/index.ts)
|
||||
- **Service Integration**: [`services/iam-service/src/main.ts`](../../../services/iam-service/src/main.ts)
|
||||
|
||||
### Health Checks / Health Checks
|
||||
|
||||
- **Health Controller**: [`services/iam-service/src/modules/health/health.controller.ts`](../../../services/iam-service/src/modules/health/health.controller.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Log Levels / Mức Độ Log
|
||||
|
||||
**EN**:
|
||||
- `ERROR`: Errors that require immediate attention
|
||||
- `WARN`: Warnings that may indicate issues
|
||||
- `INFO`: Informational messages (default)
|
||||
- `DEBUG`: Detailed debugging information
|
||||
|
||||
**VI**:
|
||||
- `ERROR`: Lỗi cần chú ý ngay lập tức
|
||||
- `WARN`: Cảnh báo có thể chỉ ra vấn đề
|
||||
- `INFO`: Thông điệp thông tin (mặc định)
|
||||
- `DEBUG`: Thông tin debug chi tiết
|
||||
|
||||
### Metric Types / Loại Metrics
|
||||
|
||||
**EN**:
|
||||
- **Counter**: Monotonically increasing value (e.g., request count)
|
||||
- **Gauge**: Value that can go up or down (e.g., active connections)
|
||||
- **Histogram**: Distribution of values (e.g., request duration)
|
||||
|
||||
**VI**:
|
||||
- **Counter**: Giá trị tăng đơn điệu (ví dụ: số lượng request)
|
||||
- **Gauge**: Giá trị có thể tăng hoặc giảm (ví dụ: kết nối đang hoạt động)
|
||||
- **Histogram**: Phân phối giá trị (ví dụ: thời lượng request)
|
||||
|
||||
### Health Check Endpoints / Endpoints Health Check
|
||||
|
||||
**EN**:
|
||||
- `/health` or `/health/live`: Liveness probe (service is running)
|
||||
- `/health/ready`: Readiness probe (service is ready to accept traffic)
|
||||
|
||||
**VI**:
|
||||
- `/health` hoặc `/health/live`: Liveness probe (service đang chạy)
|
||||
- `/health/ready`: Readiness probe (service sẵn sàng nhận traffic)
|
||||
|
||||
### Prometheus Queries / Truy Vấn Prometheus
|
||||
|
||||
```promql
|
||||
# Request rate
|
||||
rate(http_requests_total[5m])
|
||||
|
||||
# Error rate
|
||||
rate(http_requests_total{status_code=~"5.."}[5m])
|
||||
|
||||
# 95th percentile latency
|
||||
histogram_quantile(0.95, http_request_duration_seconds)
|
||||
|
||||
# Active requests
|
||||
http_active_requests
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- [Kubernetes Deployment](./deployment-kubernetes.md) - Để cấu hình health checks trong K8s
|
||||
- [Security](./security.md) - Để logging và monitoring an toàn
|
||||
- [Project Rules](./project-rules.md) - Cho cấu trúc và tiêu chuẩn service
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### Official Documentation / Tài Liệu Chính Thức
|
||||
|
||||
- [OpenTelemetry Documentation](https://opentelemetry.io/docs/)
|
||||
- [Prometheus Documentation](https://prometheus.io/docs/)
|
||||
- [Jaeger Documentation](https://www.jaegertracing.io/docs/)
|
||||
|
||||
### GoodGo Resources / Tài Nguyên GoodGo
|
||||
|
||||
- [Observability Guide](../guides/observability.md)
|
||||
- [Troubleshooting Guide](../guides/troubleshooting.md)
|
||||
- [Logger Package](../../../packages/logger/README.md)
|
||||
- [Tracing Package](../../../packages/tracing/README.md)
|
||||
425
docs/vi/skills/project-rules.md
Normal file
425
docs/vi/skills/project-rules.md
Normal file
@@ -0,0 +1,425 @@
|
||||
# Project Rules / Quy Tắc Dự Án
|
||||
|
||||
> **EN**: GoodGo Microservices Platform coding standards and architecture patterns. Use when working with services, apps, packages, or infrastructure.
|
||||
> **VI**: Tiêu chuẩn mã hóa và mẫu kiến trúc của GoodGo Microservices Platform. Sử dụng khi làm việc với services, apps, packages, hoặc infrastructure.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: The Project Rules skill provides comprehensive guidelines for the GoodGo Microservices Platform architecture, coding standards, naming conventions, workflows, and best practices. This skill ensures consistency across all services, packages, and applications in the monorepo.
|
||||
|
||||
**VI**: Skill Project Rules cung cấp hướng dẫn toàn diện về kiến trúc GoodGo Microservices Platform, tiêu chuẩn mã hóa, quy ước đặt tên, quy trình làm việc và thực hành tốt nhất. Skill này đảm bảo tính nhất quán trên tất cả services, packages và applications trong monorepo.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Creating a new service or package
|
||||
- Setting up project structure
|
||||
- Following naming conventions
|
||||
- Understanding deployment patterns
|
||||
- Working with dependencies
|
||||
- Configuring Docker containers
|
||||
- Setting up CI/CD workflows
|
||||
- Understanding the monorepo structure
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Tạo service hoặc package mới
|
||||
- Thiết lập cấu trúc dự án
|
||||
- Tuân theo quy ước đặt tên
|
||||
- Hiểu các mẫu triển khai
|
||||
- Làm việc với dependencies
|
||||
- Cấu hình Docker containers
|
||||
- Thiết lập CI/CD workflows
|
||||
- Hiểu cấu trúc monorepo
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Architecture / Kiến Trúc
|
||||
|
||||
**EN**: The platform follows a microservices architecture with:
|
||||
- **Apps**: Next.js (web) + Flutter (mobile)
|
||||
- **Services**: Node.js/TypeScript microservices (Express)
|
||||
- **Packages**: Shared libraries (logger, types, http-client, auth-sdk, tracing)
|
||||
- **Infrastructure**: Traefik (API Gateway), Redis, Neon PostgreSQL, Observability
|
||||
- **Deployments**: Local (Docker Compose), Staging/Production (Kubernetes)
|
||||
|
||||
**VI**: Nền tảng tuân theo kiến trúc microservices với:
|
||||
- **Apps**: Next.js (web) + Flutter (mobile)
|
||||
- **Services**: Node.js/TypeScript microservices (Express)
|
||||
- **Packages**: Thư viện dùng chung (logger, types, http-client, auth-sdk, tracing)
|
||||
- **Infrastructure**: Traefik (API Gateway), Redis, Neon PostgreSQL, Observability
|
||||
- **Deployments**: Local (Docker Compose), Staging/Production (Kubernetes)
|
||||
|
||||
### Tech Stack / Công Nghệ
|
||||
|
||||
**Frontend:**
|
||||
- Next.js 14+ (App Router), TypeScript, Tailwind CSS, Zustand
|
||||
- Flutter 3.x with Provider pattern
|
||||
- Use `@goodgo/types` and `@goodgo/http-client`
|
||||
|
||||
**Backend:**
|
||||
- Node.js 20+, TypeScript 5+, Express
|
||||
- Prisma ORM + Neon PostgreSQL
|
||||
- Zod validation, `@goodgo/logger`, `@goodgo/tracing`, `@goodgo/auth-sdk`
|
||||
|
||||
**Infrastructure:**
|
||||
- Traefik (path-based routing), Redis (cache), Prometheus + Grafana + Loki
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Service Structure / Cấu Trúc Service
|
||||
|
||||
**EN**: Standard service structure:
|
||||
```
|
||||
services/[service-name]/
|
||||
├── src/
|
||||
│ ├── config/ # Configuration files
|
||||
│ ├── modules/ # Feature modules
|
||||
│ ├── middlewares/ # Express middlewares
|
||||
│ ├── repositories/ # Data access layer
|
||||
│ ├── routes/ # Route definitions
|
||||
│ └── main.ts # Entry point
|
||||
├── prisma/ # Database schema
|
||||
├── Dockerfile # Container definition
|
||||
└── package.json # Dependencies
|
||||
```
|
||||
|
||||
**VI**: Cấu trúc service chuẩn:
|
||||
```
|
||||
services/[service-name]/
|
||||
├── src/
|
||||
│ ├── config/ # File cấu hình
|
||||
│ ├── modules/ # Module tính năng
|
||||
│ ├── middlewares/ # Express middlewares
|
||||
│ ├── repositories/ # Lớp truy cập dữ liệu
|
||||
│ ├── routes/ # Định nghĩa routes
|
||||
│ └── main.ts # Điểm vào
|
||||
├── prisma/ # Database schema
|
||||
├── Dockerfile # Định nghĩa container
|
||||
└── package.json # Dependencies
|
||||
```
|
||||
|
||||
### Module Pattern / Pattern Module
|
||||
|
||||
**EN**: Controller → Service → Repository pattern:
|
||||
|
||||
```typescript
|
||||
// DTO with Zod
|
||||
export const CreateFeatureDto = z.object({
|
||||
name: z.string().min(1),
|
||||
email: z.string().email()
|
||||
});
|
||||
export type CreateFeatureDto = z.infer<typeof CreateFeatureDto>;
|
||||
|
||||
// Controller
|
||||
export class FeatureController {
|
||||
constructor(private service: FeatureService) {}
|
||||
async create(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const dto = CreateFeatureDto.parse(req.body);
|
||||
const result = await this.service.create(dto);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (error) { next(error); }
|
||||
}
|
||||
}
|
||||
|
||||
// Service
|
||||
export class FeatureService {
|
||||
constructor(private repository: FeatureRepository) {}
|
||||
async create(dto: CreateFeatureDto) {
|
||||
return this.repository.create(dto);
|
||||
}
|
||||
}
|
||||
|
||||
// Repository
|
||||
export class FeatureRepository extends BaseRepository<Feature> {
|
||||
async create(data: CreateFeatureDto) {
|
||||
return this.prisma.feature.create({ data });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Pattern Controller → Service → Repository:
|
||||
|
||||
```typescript
|
||||
// DTO với Zod
|
||||
export const CreateFeatureDto = z.object({
|
||||
name: z.string().min(1),
|
||||
email: z.string().email()
|
||||
});
|
||||
export type CreateFeatureDto = z.infer<typeof CreateFeatureDto>;
|
||||
|
||||
// Controller
|
||||
export class FeatureController {
|
||||
constructor(private service: FeatureService) {}
|
||||
async create(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const dto = CreateFeatureDto.parse(req.body);
|
||||
const result = await this.service.create(dto);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (error) { next(error); }
|
||||
}
|
||||
}
|
||||
|
||||
// Service
|
||||
export class FeatureService {
|
||||
constructor(private repository: FeatureRepository) {}
|
||||
async create(dto: CreateFeatureDto) {
|
||||
return this.repository.create(dto);
|
||||
}
|
||||
}
|
||||
|
||||
// Repository
|
||||
export class FeatureRepository extends BaseRepository<Feature> {
|
||||
async create(data: CreateFeatureDto) {
|
||||
return this.prisma.feature.create({ data });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### API Response Pattern / Pattern Phản Hồi API
|
||||
|
||||
**EN**: Standardized API responses:
|
||||
|
||||
```typescript
|
||||
// Success response
|
||||
{
|
||||
success: true,
|
||||
data: any,
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
// Error response
|
||||
{
|
||||
success: false,
|
||||
error: {
|
||||
code: string,
|
||||
message: string,
|
||||
details?: any
|
||||
},
|
||||
timestamp: string
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Phản hồi API chuẩn hóa:
|
||||
|
||||
```typescript
|
||||
// Phản hồi thành công
|
||||
{
|
||||
success: true,
|
||||
data: any,
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
// Phản hồi lỗi
|
||||
{
|
||||
success: false,
|
||||
error: {
|
||||
code: string,
|
||||
message: string,
|
||||
details?: any
|
||||
},
|
||||
timestamp: string
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Naming Conventions / Quy Ước Đặt Tên
|
||||
|
||||
**EN**:
|
||||
- **Services/Packages**: `kebab-case` (e.g., `iam-service`, `http-client`)
|
||||
- **Files**: `kebab-case.type.ts` (e.g., `user.controller.ts`)
|
||||
- **Components**: `PascalCase.tsx` (React), `snake_case.dart` (Flutter)
|
||||
- **Classes**: `PascalCase`
|
||||
- **Functions**: `camelCase`
|
||||
- **Constants**: `UPPER_SNAKE_CASE`
|
||||
- **Package Names**: `@goodgo/package-name`
|
||||
|
||||
**VI**:
|
||||
- **Services/Packages**: `kebab-case` (ví dụ: `iam-service`, `http-client`)
|
||||
- **Files**: `kebab-case.type.ts` (ví dụ: `user.controller.ts`)
|
||||
- **Components**: `PascalCase.tsx` (React), `snake_case.dart` (Flutter)
|
||||
- **Classes**: `PascalCase`
|
||||
- **Functions**: `camelCase`
|
||||
- **Constants**: `UPPER_SNAKE_CASE`
|
||||
- **Package Names**: `@goodgo/package-name`
|
||||
|
||||
### TypeScript Standards / Tiêu Chuẩn TypeScript
|
||||
|
||||
**EN**:
|
||||
- Strict mode enabled
|
||||
- No `any` type (use `unknown` instead)
|
||||
- Zod for runtime validation
|
||||
- Export shared types from `@goodgo/types`
|
||||
|
||||
**VI**:
|
||||
- Bật strict mode
|
||||
- Không dùng type `any` (dùng `unknown` thay thế)
|
||||
- Zod cho runtime validation
|
||||
- Export shared types từ `@goodgo/types`
|
||||
|
||||
### Logging / Ghi Log
|
||||
|
||||
**EN**: Use `@goodgo/logger`:
|
||||
|
||||
```typescript
|
||||
import { logger } from '@goodgo/logger';
|
||||
logger.info('Message', { context });
|
||||
logger.error('Error', { error, context });
|
||||
```
|
||||
|
||||
**VI**: Sử dụng `@goodgo/logger`:
|
||||
|
||||
```typescript
|
||||
import { logger } from '@goodgo/logger';
|
||||
logger.info('Message', { context });
|
||||
logger.error('Error', { error, context });
|
||||
```
|
||||
|
||||
### Environment Variables / Biến Môi Trường
|
||||
|
||||
**EN**:
|
||||
- Use `.env.example` template
|
||||
- Never commit `.env` files
|
||||
- Validate with Zod at startup
|
||||
- Document all variables in README
|
||||
|
||||
**VI**:
|
||||
- Sử dụng template `.env.example`
|
||||
- Không bao giờ commit file `.env`
|
||||
- Validate với Zod khi khởi động
|
||||
- Tài liệu hóa tất cả biến trong README
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Service Template / Template Service
|
||||
|
||||
**EN**: See `services/_template/` for a complete service template with:
|
||||
- Standard structure
|
||||
- Middleware setup
|
||||
- Error handling
|
||||
- Health checks
|
||||
- Swagger documentation
|
||||
|
||||
**VI**: Xem `services/_template/` để có template service hoàn chỉnh với:
|
||||
- Cấu trúc chuẩn
|
||||
- Thiết lập middleware
|
||||
- Xử lý lỗi
|
||||
- Health checks
|
||||
- Tài liệu Swagger
|
||||
|
||||
### Traefik Configuration / Cấu Hình Traefik
|
||||
|
||||
**EN**: Services are registered in `deployments/local/docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-service:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/my-service/Dockerfile
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.my-service.rule=PathPrefix(`/api/v1/my-service`)"
|
||||
- "traefik.http.services.my-service.loadbalancer.server.port=5002"
|
||||
- "traefik.http.services.my-service.loadbalancer.healthcheck.path=/health/live"
|
||||
```
|
||||
|
||||
**VI**: Services được đăng ký trong `deployments/local/docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-service:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/my-service/Dockerfile
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.my-service.rule=PathPrefix(`/api/v1/my-service`)"
|
||||
- "traefik.http.services.my-service.loadbalancer.server.port=5002"
|
||||
- "traefik.http.services.my-service.loadbalancer.healthcheck.path=/health/live"
|
||||
```
|
||||
|
||||
### Real Service Examples / Ví Dụ Service Thực Tế
|
||||
|
||||
**EN**:
|
||||
- `services/iam-service/` - Identity and Access Management service (RBAC, OIDC, MFA, Identity, Access, Governance)
|
||||
- `packages/logger/` - Shared logging package
|
||||
- `packages/types/` - Shared TypeScript types
|
||||
|
||||
**VI**:
|
||||
- `services/iam-service/` - Service quản lý danh tính và quyền truy cập (RBAC, OIDC, MFA, Identity, Access, Governance)
|
||||
- `packages/logger/` - Package logging dùng chung
|
||||
- `packages/types/` - TypeScript types dùng chung
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Creating New Service / Tạo Service Mới
|
||||
|
||||
```bash
|
||||
# 1. Copy template
|
||||
cp -r services/_template services/my-service
|
||||
|
||||
# 2. Update package.json name
|
||||
# Change to: "@goodgo/my-service"
|
||||
|
||||
# 3. Add to docker-compose.yml
|
||||
# Add service configuration with Traefik labels
|
||||
|
||||
# 4. Configure Prisma schema
|
||||
cd services/my-service
|
||||
pnpm prisma migrate dev
|
||||
|
||||
# 5. Add health check endpoint
|
||||
# Already included in template
|
||||
```
|
||||
|
||||
### Working with Dependencies / Làm Việc Với Dependencies
|
||||
|
||||
```bash
|
||||
# Add external package
|
||||
pnpm --filter @goodgo/service-name add package-name
|
||||
|
||||
# Add workspace package
|
||||
pnpm --filter @goodgo/service-name add @goodgo/logger
|
||||
|
||||
# Add dev dependency
|
||||
pnpm --filter @goodgo/service-name add -D @types/pkg
|
||||
```
|
||||
|
||||
### Database Commands / Lệnh Database
|
||||
|
||||
```bash
|
||||
# Run migrations
|
||||
pnpm --filter @goodgo/service-name prisma migrate dev
|
||||
|
||||
# Generate Prisma client
|
||||
pnpm --filter @goodgo/service-name prisma generate
|
||||
|
||||
# Seed database
|
||||
pnpm --filter @goodgo/service-name prisma db seed
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[API Design](./api-design.md)** - RESTful API design standards
|
||||
- **[Database Prisma](./database-prisma.md)** - Prisma ORM patterns
|
||||
- **[Security](./security.md)** - Security best practices
|
||||
- **[Testing Patterns](./testing-patterns.md)** - Testing guidelines
|
||||
- **[Documentation](./documentation.md)** - Documentation writing guidelines
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- [Architecture Docs](../architecture/system-design.md)
|
||||
- [API Specs](../api/openapi/)
|
||||
- [Development Guide](../guides/development.md)
|
||||
- [Deployment Guide](../guides/deployment.md)
|
||||
- [Contributing Guide](../../../CONTRIBUTING.md)
|
||||
|
||||
**VI**:
|
||||
- [Tài Liệu Kiến Trúc](../architecture/system-design.md)
|
||||
- [Spec API](../api/openapi/)
|
||||
- [Hướng Dẫn Phát Triển](../guides/development.md)
|
||||
- [Hướng Dẫn Triển Khai](../guides/deployment.md)
|
||||
- [Hướng Dẫn Đóng Góp](../../../CONTRIBUTING.md)
|
||||
742
docs/vi/skills/security.md
Normal file
742
docs/vi/skills/security.md
Normal file
@@ -0,0 +1,742 @@
|
||||
# Security / Bảo Mật
|
||||
|
||||
> **EN**: Security best practices and patterns for GoodGo microservices platform. Use when implementing authentication, authorization, data protection, input validation, rate limiting, secrets management, or security testing across all services.
|
||||
> **VI**: Thực hành và mẫu bảo mật tốt nhất cho nền tảng microservices GoodGo. Sử dụng khi triển khai xác thực, phân quyền, bảo vệ dữ liệu, xác thực đầu vào, giới hạn tốc độ, quản lý bí mật hoặc kiểm tra bảo mật trên tất cả các dịch vụ.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: The Security skill provides comprehensive security patterns, best practices, and implementation examples for protecting GoodGo microservices. It covers authentication, authorization, data protection, input validation, rate limiting, secrets management, and security testing.
|
||||
|
||||
**VI**: Skill Security cung cấp các mẫu bảo mật toàn diện, thực hành tốt nhất và ví dụ triển khai để bảo vệ các microservices GoodGo. Nó bao gồm xác thực, phân quyền, bảo vệ dữ liệu, xác thực đầu vào, giới hạn tốc độ, quản lý bí mật và kiểm tra bảo mật.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Implementing authentication and authorization in any service
|
||||
- Protecting sensitive data (PII, credentials, tokens)
|
||||
- Validating user inputs and file uploads
|
||||
- Implementing rate limiting and DDoS protection
|
||||
- Setting up audit logging and security monitoring
|
||||
- Encrypting data at rest and in transit
|
||||
- Managing secrets and credentials
|
||||
- Implementing security testing
|
||||
- Handling security incidents
|
||||
- Designing secure API endpoints
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Triển khai xác thực và phân quyền trong bất kỳ service nào
|
||||
- Bảo vệ dữ liệu nhạy cảm (PII, thông tin đăng nhập, token)
|
||||
- Xác thực đầu vào người dùng và tải lên tệp
|
||||
- Triển khai giới hạn tốc độ và bảo vệ DDoS
|
||||
- Thiết lập ghi nhật ký kiểm toán và giám sát bảo mật
|
||||
- Mã hóa dữ liệu khi nghỉ và khi truyền
|
||||
- Quản lý bí mật và thông tin đăng nhập
|
||||
- Triển khai kiểm tra bảo mật
|
||||
- Xử lý sự cố bảo mật
|
||||
- Thiết kế các endpoint API an toàn
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Core Security Principles / Nguyên Tắc Bảo Mật Cốt Lõi
|
||||
|
||||
**EN**:
|
||||
1. **Defense in Depth**: Multiple layers of security controls
|
||||
2. **Least Privilege**: Grant minimum required permissions
|
||||
3. **Fail Secure**: Default to deny access
|
||||
4. **Separation of Duties**: Critical operations require multiple approvals
|
||||
5. **Audit Everything**: Log all security-relevant events
|
||||
6. **Encrypt Sensitive Data**: PII, tokens, credentials must be encrypted
|
||||
7. **Validate All Inputs**: Never trust user input
|
||||
8. **Principle of Least Exposure**: Minimize attack surface
|
||||
9. **Secure by Default**: Security built-in, not bolted on
|
||||
10. **Assume Breach**: Design for detection and response
|
||||
|
||||
**VI**:
|
||||
1. **Defense in Depth**: Nhiều lớp kiểm soát bảo mật
|
||||
2. **Least Privilege**: Cấp quyền tối thiểu cần thiết
|
||||
3. **Fail Secure**: Mặc định từ chối truy cập
|
||||
4. **Separation of Duties**: Các thao tác quan trọng yêu cầu nhiều phê duyệt
|
||||
5. **Audit Everything**: Ghi log tất cả sự kiện liên quan đến bảo mật
|
||||
6. **Encrypt Sensitive Data**: PII, token, thông tin đăng nhập phải được mã hóa
|
||||
7. **Validate All Inputs**: Không bao giờ tin tưởng đầu vào người dùng
|
||||
8. **Principle of Least Exposure**: Giảm thiểu bề mặt tấn công
|
||||
9. **Secure by Default**: Bảo mật được tích hợp sẵn, không phải thêm vào sau
|
||||
10. **Assume Breach**: Thiết kế để phát hiện và phản ứng
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Authentication & Authorization / Xác Thực & Phân Quyền
|
||||
|
||||
#### JWT Token Validation / Xác Thực Token JWT
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/auth.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { jwtService } from '../modules/token/jwt.service';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
export const authenticate = () => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Extract token from Authorization header or cookie
|
||||
let token: string | null = null;
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
if (authHeader?.startsWith('Bearer ')) {
|
||||
token = authHeader.substring(7);
|
||||
} else if (req.cookies?.access_token) {
|
||||
token = req.cookies.access_token;
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_001', message: 'Authentication required' }
|
||||
});
|
||||
}
|
||||
|
||||
// Verify token
|
||||
const payload = await jwtService.verifyAccessToken(token);
|
||||
|
||||
// Attach user to request
|
||||
req.user = {
|
||||
id: payload.sub,
|
||||
userId: payload.sub,
|
||||
email: payload.email,
|
||||
roles: payload.roles || [],
|
||||
permissions: payload.permissions || []
|
||||
};
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.warn('Authentication failed', { error: error.message });
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_002', message: 'Invalid or expired token' }
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/auth.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { jwtService } from '../modules/token/jwt.service';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
export const authenticate = () => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Trích xuất token từ header Authorization hoặc cookie
|
||||
let token: string | null = null;
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
if (authHeader?.startsWith('Bearer ')) {
|
||||
token = authHeader.substring(7);
|
||||
} else if (req.cookies?.access_token) {
|
||||
token = req.cookies.access_token;
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_001', message: 'Yêu cầu xác thực' }
|
||||
});
|
||||
}
|
||||
|
||||
// Xác minh token
|
||||
const payload = await jwtService.verifyAccessToken(token);
|
||||
|
||||
// Gắn user vào request
|
||||
req.user = {
|
||||
id: payload.sub,
|
||||
userId: payload.sub,
|
||||
email: payload.email,
|
||||
roles: payload.roles || [],
|
||||
permissions: payload.permissions || []
|
||||
};
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.warn('Xác thực thất bại', { error: error.message });
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_002', message: 'Token không hợp lệ hoặc hết hạn' }
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
#### Permission-Based Authorization / Phân Quyền Dựa Trên Quyền
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/rbac.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
export const requirePermission = (
|
||||
resource: string,
|
||||
action: string,
|
||||
scope?: string
|
||||
) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'UNAUTHORIZED', message: 'Authentication required' }
|
||||
});
|
||||
}
|
||||
|
||||
const hasPermission = await rbacService.hasPermission(
|
||||
userId,
|
||||
resource,
|
||||
action,
|
||||
scope
|
||||
);
|
||||
|
||||
if (!hasPermission) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INSUFFICIENT_PERMISSIONS',
|
||||
message: `Requires ${action} permission on ${resource}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/rbac.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
export const requirePermission = (
|
||||
resource: string,
|
||||
action: string,
|
||||
scope?: string
|
||||
) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'UNAUTHORIZED', message: 'Yêu cầu xác thực' }
|
||||
});
|
||||
}
|
||||
|
||||
const hasPermission = await rbacService.hasPermission(
|
||||
userId,
|
||||
resource,
|
||||
action,
|
||||
scope
|
||||
);
|
||||
|
||||
if (!hasPermission) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INSUFFICIENT_PERMISSIONS',
|
||||
message: `Yêu cầu quyền ${action} trên ${resource}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Input Validation / Xác Thực Đầu Vào
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/validation.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { AnyZodObject, ZodError } from 'zod';
|
||||
|
||||
export const validateDto = (
|
||||
schema: AnyZodObject,
|
||||
property: 'body' | 'query' | 'params' = 'body'
|
||||
) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Sanitize input by trimming strings
|
||||
const sanitizedData = sanitizeInput(req[property]);
|
||||
|
||||
// Validate the sanitized data
|
||||
const validatedData = schema.parse(sanitizedData);
|
||||
|
||||
// Replace original data with validated data
|
||||
(req as any)[property] = validatedData;
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Invalid request data',
|
||||
details: error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message,
|
||||
code: err.code
|
||||
}))
|
||||
}
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function sanitizeInput(data: any): any {
|
||||
if (typeof data === 'string') {
|
||||
return data.trim();
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(sanitizeInput);
|
||||
}
|
||||
if (data !== null && typeof data === 'object') {
|
||||
const sanitized: any = {};
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
sanitized[key] = sanitizeInput(value);
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/validation.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { AnyZodObject, ZodError } from 'zod';
|
||||
|
||||
export const validateDto = (
|
||||
schema: AnyZodObject,
|
||||
property: 'body' | 'query' | 'params' = 'body'
|
||||
) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Làm sạch đầu vào bằng cách cắt chuỗi
|
||||
const sanitizedData = sanitizeInput(req[property]);
|
||||
|
||||
// Xác thực dữ liệu đã được làm sạch
|
||||
const validatedData = schema.parse(sanitizedData);
|
||||
|
||||
// Thay thế dữ liệu gốc bằng dữ liệu đã xác thực
|
||||
(req as any)[property] = validatedData;
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Dữ liệu request không hợp lệ',
|
||||
details: error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message,
|
||||
code: err.code
|
||||
}))
|
||||
}
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function sanitizeInput(data: any): any {
|
||||
if (typeof data === 'string') {
|
||||
return data.trim();
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(sanitizeInput);
|
||||
}
|
||||
if (data !== null && typeof data === 'object') {
|
||||
const sanitized: any = {};
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
sanitized[key] = sanitizeInput(value);
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting / Giới Hạn Tốc Độ
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/rate-limit.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { RateLimiterRedis } from 'rate-limit-redis';
|
||||
import { getRedisClient } from '../config/redis.config';
|
||||
|
||||
export const dynamicRateLimit = async (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
// Default limits
|
||||
let windowMs = 15 * 60 * 1000; // 15 minutes
|
||||
let max = 100; // 100 requests
|
||||
|
||||
if (userId) {
|
||||
const roles = await rbacService.getUserRoles(userId);
|
||||
|
||||
// Set limits based on role
|
||||
if (roles.includes('SUPER_ADMIN')) {
|
||||
max = 1000;
|
||||
} else if (roles.includes('ADMIN')) {
|
||||
max = 500;
|
||||
} else if (roles.includes('MODERATOR')) {
|
||||
max = 300;
|
||||
}
|
||||
} else {
|
||||
// Unauthenticated users - stricter limits
|
||||
max = 50;
|
||||
}
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
store: new RateLimiterRedis({
|
||||
client: getRedisClient(),
|
||||
prefix: 'rl:'
|
||||
}),
|
||||
handler: (req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
limiter(req, res, next);
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/rate-limit.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { RateLimiterRedis } from 'rate-limit-redis';
|
||||
import { getRedisClient } from '../config/redis.config';
|
||||
|
||||
export const dynamicRateLimit = async (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
// Giới hạn mặc định
|
||||
let windowMs = 15 * 60 * 1000; // 15 phút
|
||||
let max = 100; // 100 requests
|
||||
|
||||
if (userId) {
|
||||
const roles = await rbacService.getUserRoles(userId);
|
||||
|
||||
// Đặt giới hạn dựa trên vai trò
|
||||
if (roles.includes('SUPER_ADMIN')) {
|
||||
max = 1000;
|
||||
} else if (roles.includes('ADMIN')) {
|
||||
max = 500;
|
||||
} else if (roles.includes('MODERATOR')) {
|
||||
max = 300;
|
||||
}
|
||||
} else {
|
||||
// Người dùng chưa xác thực - giới hạn nghiêm ngặt hơn
|
||||
max = 50;
|
||||
}
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
store: new RateLimiterRedis({
|
||||
client: getRedisClient(),
|
||||
prefix: 'rl:'
|
||||
}),
|
||||
handler: (req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Quá nhiều yêu cầu, vui lòng thử lại sau'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
limiter(req, res, next);
|
||||
};
|
||||
```
|
||||
|
||||
### Security Headers / Header Bảo Mật
|
||||
|
||||
**EN**: Example from `services/iam-service/src/main.ts`:
|
||||
|
||||
```typescript
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
|
||||
// Security middleware
|
||||
app.use(helmet());
|
||||
app.use(cors({
|
||||
origin: appConfig.corsOrigin,
|
||||
credentials: true
|
||||
}));
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/main.ts`:
|
||||
|
||||
```typescript
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
|
||||
// Middleware bảo mật
|
||||
app.use(helmet());
|
||||
app.use(cors({
|
||||
origin: appConfig.corsOrigin,
|
||||
credentials: true
|
||||
}));
|
||||
```
|
||||
|
||||
**EN**: Traefik security headers from `infra/traefik/dynamic/middlewares.yml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
middlewares:
|
||||
secure-headers:
|
||||
headers:
|
||||
sslRedirect: true
|
||||
stsSeconds: 31536000
|
||||
contentTypeNosniff: true
|
||||
browserXssFilter: true
|
||||
frameDeny: true
|
||||
customRequestHeaders:
|
||||
X-Forwarded-Proto: "https"
|
||||
```
|
||||
|
||||
**VI**: Header bảo mật Traefik từ `infra/traefik/dynamic/middlewares.yml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
middlewares:
|
||||
secure-headers:
|
||||
headers:
|
||||
sslRedirect: true
|
||||
stsSeconds: 31536000
|
||||
contentTypeNosniff: true
|
||||
browserXssFilter: true
|
||||
frameDeny: true
|
||||
customRequestHeaders:
|
||||
X-Forwarded-Proto: "https"
|
||||
```
|
||||
|
||||
### Audit Logging / Ghi Log Kiểm Toán
|
||||
|
||||
**EN**: Example from `services/iam-service/src/core/events/audit.service.ts`:
|
||||
|
||||
```typescript
|
||||
export class AuditService {
|
||||
async logAuthEvent(
|
||||
eventType: string,
|
||||
data: {
|
||||
userId?: string;
|
||||
success: boolean;
|
||||
errorMessage?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
metadata?: any;
|
||||
}
|
||||
): Promise<void> {
|
||||
await this.prisma.authEvent.create({
|
||||
data: {
|
||||
userId: data.userId || null,
|
||||
eventType,
|
||||
eventData: data.metadata || {},
|
||||
ipAddress: data.ipAddress,
|
||||
userAgent: data.userAgent,
|
||||
success: data.success,
|
||||
errorMessage: data.errorMessage
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/core/events/audit.service.ts`:
|
||||
|
||||
```typescript
|
||||
export class AuditService {
|
||||
async logAuthEvent(
|
||||
eventType: string,
|
||||
data: {
|
||||
userId?: string;
|
||||
success: boolean;
|
||||
errorMessage?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
metadata?: any;
|
||||
}
|
||||
): Promise<void> {
|
||||
await this.prisma.authEvent.create({
|
||||
data: {
|
||||
userId: data.userId || null,
|
||||
eventType,
|
||||
eventData: data.metadata || {},
|
||||
ipAddress: data.ipAddress,
|
||||
userAgent: data.userAgent,
|
||||
success: data.success,
|
||||
errorMessage: data.errorMessage
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Password Security / Bảo Mật Mật Khẩu
|
||||
|
||||
**EN**:
|
||||
- Always use bcrypt with cost factor 12+ in production
|
||||
- Never log passwords or password hashes
|
||||
- Use strong password requirements (min 8 chars, uppercase, lowercase, number, special char)
|
||||
- Implement password reset with secure tokens
|
||||
|
||||
**VI**:
|
||||
- Luôn sử dụng bcrypt với hệ số chi phí 12+ trong production
|
||||
- Không bao giờ ghi log mật khẩu hoặc hash mật khẩu
|
||||
- Sử dụng yêu cầu mật khẩu mạnh (tối thiểu 8 ký tự, chữ hoa, chữ thường, số, ký tự đặc biệt)
|
||||
- Triển khai đặt lại mật khẩu với token an toàn
|
||||
|
||||
### Token Security / Bảo Mật Token
|
||||
|
||||
**EN**:
|
||||
- Hash tokens before storing in database
|
||||
- Use short-lived access tokens (15 minutes)
|
||||
- Use longer-lived refresh tokens (7 days) with rotation
|
||||
- Store refresh tokens securely (httpOnly cookies)
|
||||
- Implement token revocation
|
||||
|
||||
**VI**:
|
||||
- Hash token trước khi lưu vào database
|
||||
- Sử dụng access token có thời gian sống ngắn (15 phút)
|
||||
- Sử dụng refresh token có thời gian sống dài hơn (7 ngày) với xoay vòng
|
||||
- Lưu trữ refresh token an toàn (httpOnly cookies)
|
||||
- Triển khai thu hồi token
|
||||
|
||||
### SQL Injection Prevention / Ngăn Chặn SQL Injection
|
||||
|
||||
**EN**:
|
||||
- Always use Prisma parameterized queries (automatic)
|
||||
- Never use string concatenation for queries
|
||||
- Validate and sanitize all inputs
|
||||
|
||||
**VI**:
|
||||
- Luôn sử dụng truy vấn tham số hóa của Prisma (tự động)
|
||||
- Không bao giờ sử dụng nối chuỗi cho truy vấn
|
||||
- Xác thực và làm sạch tất cả đầu vào
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Authentication Middleware / Middleware Xác Thực
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/auth.middleware.ts` for complete authentication implementation.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/auth.middleware.ts` để có implementation xác thực hoàn chỉnh.
|
||||
|
||||
### RBAC Middleware / Middleware RBAC
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/rbac.middleware.ts` for permission-based authorization.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/rbac.middleware.ts` để có phân quyền dựa trên quyền.
|
||||
|
||||
### Validation Middleware / Middleware Xác Thực
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/validation.middleware.ts` for input validation patterns.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/validation.middleware.ts` để có các mẫu xác thực đầu vào.
|
||||
|
||||
### Rate Limiting / Giới Hạn Tốc Độ
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/rate-limit.middleware.ts` for dynamic rate limiting.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/rate-limit.middleware.ts` để có giới hạn tốc độ động.
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Security Checklist / Danh Sách Kiểm Tra Bảo Mật
|
||||
|
||||
**EN**: Before deploying any service:
|
||||
- [ ] All endpoints require authentication (except public)
|
||||
- [ ] Authorization checks implemented (RBAC/ABAC)
|
||||
- [ ] Input validation with Zod schemas
|
||||
- [ ] Rate limiting configured
|
||||
- [ ] Error messages sanitized (no info disclosure)
|
||||
- [ ] PII encrypted at rest
|
||||
- [ ] Passwords hashed with bcrypt (cost 12+)
|
||||
- [ ] Tokens hashed before storing
|
||||
- [ ] Secrets in environment variables (never hardcoded)
|
||||
- [ ] HTTPS enforced (TLS 1.2+)
|
||||
- [ ] CORS configured correctly
|
||||
- [ ] Security headers set (helmet)
|
||||
- [ ] Audit logging enabled
|
||||
- [ ] SQL injection prevented (use Prisma)
|
||||
- [ ] XSS prevention (input sanitization)
|
||||
- [ ] File upload validation
|
||||
- [ ] Security tests passing
|
||||
|
||||
**VI**: Trước khi triển khai bất kỳ service nào:
|
||||
- [ ] Tất cả endpoint yêu cầu xác thực (trừ public)
|
||||
- [ ] Kiểm tra phân quyền đã triển khai (RBAC/ABAC)
|
||||
- [ ] Xác thực đầu vào với Zod schemas
|
||||
- [ ] Giới hạn tốc độ đã cấu hình
|
||||
- [ ] Thông báo lỗi đã được làm sạch (không tiết lộ thông tin)
|
||||
- [ ] PII được mã hóa khi nghỉ
|
||||
- [ ] Mật khẩu được hash với bcrypt (chi phí 12+)
|
||||
- [ ] Token được hash trước khi lưu
|
||||
- [ ] Bí mật trong biến môi trường (không bao giờ hardcode)
|
||||
- [ ] HTTPS được bắt buộc (TLS 1.2+)
|
||||
- [ ] CORS được cấu hình đúng
|
||||
- [ ] Header bảo mật được đặt (helmet)
|
||||
- [ ] Ghi log kiểm toán được bật
|
||||
- [ ] SQL injection được ngăn chặn (sử dụng Prisma)
|
||||
- [ ] Ngăn chặn XSS (làm sạch đầu vào)
|
||||
- [ ] Xác thực tải lên tệp
|
||||
- [ ] Kiểm tra bảo mật đã vượt qua
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Project Rules](./project-rules.md)** - Coding standards and architecture
|
||||
- **[API Design](./api-design.md)** - Secure API design patterns
|
||||
- **[Testing Patterns](./testing-patterns.md)** - Security testing
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
|
||||
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
|
||||
- [Express Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html)
|
||||
|
||||
**VI**:
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
|
||||
- [Thực Hành Bảo Mật Node.js](https://nodejs.org/en/docs/guides/security/)
|
||||
- [Thực Hành Bảo Mật Express](https://expressjs.com/en/advanced/best-practice-security.html)
|
||||
738
docs/vi/skills/testing-patterns.md
Normal file
738
docs/vi/skills/testing-patterns.md
Normal file
@@ -0,0 +1,738 @@
|
||||
# Testing Patterns / Các Pattern Testing
|
||||
|
||||
> **EN**: Comprehensive testing best practices for GoodGo microservices including unit tests, integration tests, E2E tests, Jest configuration, mocking strategies, and debugging techniques.
|
||||
> **VI**: Các thực hành tốt nhất về testing cho microservices GoodGo bao gồm unit tests, integration tests, E2E tests, cấu hình Jest, strategies mocking, và kỹ thuật debugging.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: Testing is a critical component of the GoodGo microservices platform. This guide provides comprehensive patterns and best practices for writing maintainable, reliable tests across all services. It covers test types, Jest configuration, mocking strategies, test utilities, and debugging techniques that ensure code quality and reliability.
|
||||
|
||||
**VI**: Testing là thành phần quan trọng của nền tảng microservices GoodGo. Hướng dẫn này cung cấp các patterns và best practices toàn diện để viết các test có thể bảo trì và đáng tin cậy trên tất cả các services. Nó bao gồm các loại test, cấu hình Jest, strategies mocking, test utilities, và kỹ thuật debugging để đảm bảo chất lượng và độ tin cậy của code.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use these testing patterns when:
|
||||
- Writing unit tests for services, controllers, or repositories
|
||||
- Creating integration tests for middleware chains
|
||||
- Building E2E tests for API endpoints
|
||||
- Setting up Jest configuration for a new service
|
||||
- Mocking external dependencies (Prisma, Redis, Auth SDK)
|
||||
- Debugging test failures
|
||||
- Improving test coverage
|
||||
- Creating test utilities and factories
|
||||
|
||||
**VI**: Sử dụng các testing patterns này khi:
|
||||
- Viết unit tests cho services, controllers, hoặc repositories
|
||||
- Tạo integration tests cho middleware chains
|
||||
- Xây dựng E2E tests cho API endpoints
|
||||
- Thiết lập cấu hình Jest cho service mới
|
||||
- Mocking các dependencies bên ngoài (Prisma, Redis, Auth SDK)
|
||||
- Debugging test failures
|
||||
- Cải thiện test coverage
|
||||
- Tạo test utilities và factories
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Test Types / Các Loại Test
|
||||
|
||||
#### 1. Unit Tests / Unit Tests
|
||||
|
||||
**EN**: Test individual functions or classes in isolation with all dependencies mocked.
|
||||
|
||||
**VI**: Test các functions hoặc classes riêng lẻ một cách cô lập với tất cả dependencies được mock.
|
||||
|
||||
**Characteristics / Đặc điểm**:
|
||||
- **Location / Vị trí**: Next to source files (`*.test.ts`) or in `__tests__/` directory
|
||||
- **Scope / Phạm vi**: Single function, method, or class
|
||||
- **Dependencies / Dependencies**: All external dependencies mocked
|
||||
- **Speed / Tốc độ**: Fast (<1s per test)
|
||||
- **Purpose / Mục đích**: Verify logic correctness
|
||||
|
||||
**Example / Ví dụ**: [`services/iam-service/src/modules/feature/__tests__/feature.service.test.ts`](../../../services/iam-service/src/modules/feature/__tests__/feature.service.test.ts)
|
||||
|
||||
#### 2. Integration Tests / Integration Tests
|
||||
|
||||
**EN**: Test multiple components working together with some real dependencies.
|
||||
|
||||
**VI**: Test nhiều components làm việc cùng nhau với một số dependencies thật.
|
||||
|
||||
**Characteristics / Đặc điểm**:
|
||||
- **Location / Vị trí**: `__tests__/` directory (`*.test.ts`)
|
||||
- **Scope / Phạm vi**: Multiple components interacting
|
||||
- **Dependencies / Dependencies**: Mix of real and mocked dependencies
|
||||
- **Speed / Tốc độ**: Medium (1-5s per test)
|
||||
- **Purpose / Mục đích**: Verify component integration
|
||||
|
||||
**Example / Ví dụ**: [`services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts`](../../../services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts)
|
||||
|
||||
#### 3. E2E Tests / E2E Tests
|
||||
|
||||
**EN**: Test complete request/response cycles through the entire application stack.
|
||||
|
||||
**VI**: Test các chu kỳ request/response hoàn chỉnh qua toàn bộ application stack.
|
||||
|
||||
**Characteristics / Đặc điểm**:
|
||||
- **Location / Vị trí**: `__tests__/*.e2e.ts`
|
||||
- **Scope / Phạm vi**: Full API workflow from HTTP request to response
|
||||
- **Dependencies / Dependencies**: Test database, mocked external services
|
||||
- **Speed / Tốc độ**: Slow (5-10s per test)
|
||||
- **Purpose / Mục đích**: Verify end-to-end functionality
|
||||
|
||||
**Example / Ví dụ**: [`services/iam-service/src/__tests__/feature.e2e.ts`](../../../services/iam-service/src/__tests__/feature.e2e.ts)
|
||||
|
||||
## Jest Configuration / Cấu Hình Jest
|
||||
|
||||
### Standard Configuration / Cấu Hình Chuẩn
|
||||
|
||||
The standard Jest configuration for GoodGo services includes TypeScript support, coverage thresholds, and proper test environment setup.
|
||||
|
||||
**Location / Vị trí**: [`services/iam-service/jest.config.ts`](../../../services/iam-service/jest.config.ts)
|
||||
|
||||
```typescript
|
||||
import type { Config } from 'jest';
|
||||
|
||||
const config: Config = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
roots: ['<rootDir>/src'],
|
||||
testMatch: [
|
||||
'**/__tests__/**/*.test.ts',
|
||||
'**/__tests__/**/*.spec.ts',
|
||||
'**/__tests__/**/*.e2e.ts',
|
||||
'**/?(*.)+(spec|test).ts'
|
||||
],
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.ts',
|
||||
'!src/**/*.d.ts',
|
||||
'!src/main.ts',
|
||||
'!src/config/**/*.ts',
|
||||
'!src/**/*.config.ts'
|
||||
],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['text', 'lcov', 'html'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 70,
|
||||
functions: 70,
|
||||
lines: 70,
|
||||
statements: 70
|
||||
}
|
||||
},
|
||||
setupFilesAfterEnv: ['<rootDir>/src/__tests__/setupTests.ts'],
|
||||
testTimeout: 10000,
|
||||
clearMocks: true,
|
||||
resetModules: true
|
||||
};
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
### Key Configuration Points / Điểm Cấu Hình Quan Trọng
|
||||
|
||||
- **preset: 'ts-jest'**: Enables TypeScript support / Bật hỗ trợ TypeScript
|
||||
- **testEnvironment: 'node'**: Sets Node.js environment (not browser) / Thiết lập môi trường Node.js (không phải browser)
|
||||
- **coverageThreshold**: Enforces minimum 70% coverage across all metrics / Yêu cầu tối thiểu 70% coverage trên tất cả các metrics
|
||||
- **setupFilesAfterEnv**: Loads test setup file before each test suite / Tải file setup test trước mỗi test suite
|
||||
- **clearMocks**: Automatically clears mock calls between tests / Tự động xóa mock calls giữa các test
|
||||
- **resetModules**: Resets module cache for test isolation / Reset module cache để cô lập test
|
||||
|
||||
## Setup Files / Files Thiết Lập
|
||||
|
||||
### Test Setup File / File Thiết Lập Test
|
||||
|
||||
The setup file (`setupTests.ts`) configures global mocks and test utilities that are available across all tests.
|
||||
|
||||
**Location / Vị trí**: [`services/iam-service/src/__tests__/setupTests.ts`](../../../services/iam-service/src/__tests__/setupTests.ts)
|
||||
|
||||
**Key Features / Tính Năng Chính**:
|
||||
- Mock external services (logger, tracing, database, Redis) / Mock các services bên ngoài
|
||||
- Configure test environment variables / Cấu hình biến môi trường test
|
||||
- Set up global test utilities / Thiết lập test utilities toàn cục
|
||||
- Initialize Prometheus mocks / Khởi tạo Prometheus mocks
|
||||
|
||||
**Example / Ví dụ**:
|
||||
```typescript
|
||||
import { jest } from '@jest/globals';
|
||||
|
||||
// EN: Mock environment variables for tests
|
||||
// VI: Mock biến môi trường cho tests
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.DATABASE_URL = 'postgresql://test:test@localhost:5432/test_db';
|
||||
process.env.REDIS_URL = 'redis://localhost:6379/1';
|
||||
|
||||
// EN: Mock external services to avoid real network calls
|
||||
// VI: Mock các service bên ngoài để tránh gọi mạng thật
|
||||
jest.mock('@goodgo/logger', () => ({
|
||||
logger: {
|
||||
info: jest.fn(),
|
||||
error: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
debug: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
// EN: Global test utilities
|
||||
// VI: Utilities test toàn cục
|
||||
global.testUtils = {
|
||||
createMockReq: (overrides = {}) => ({
|
||||
body: {},
|
||||
params: {},
|
||||
query: {},
|
||||
headers: {},
|
||||
...overrides,
|
||||
}),
|
||||
createMockRes: () => {
|
||||
const res: any = {};
|
||||
res.status = jest.fn().mockReturnValue(res);
|
||||
res.json = jest.fn().mockReturnValue(res);
|
||||
res.send = jest.fn().mockReturnValue(res);
|
||||
return res;
|
||||
},
|
||||
createMockNext: () => jest.fn(),
|
||||
};
|
||||
```
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Unit Test Pattern / Pattern Unit Test
|
||||
|
||||
**Structure / Cấu trúc**: Follow the AAA (Arrange-Act-Assert) pattern for clarity / Tuân theo pattern AAA để rõ ràng.
|
||||
|
||||
```typescript
|
||||
describe('FeatureService', () => {
|
||||
let service: FeatureService;
|
||||
let mockRepository: any;
|
||||
|
||||
beforeEach(() => {
|
||||
// EN: Clear all mocks before each test
|
||||
// VI: Xóa tất cả mocks trước mỗi test
|
||||
jest.clearAllMocks();
|
||||
|
||||
mockRepository = {
|
||||
findById: jest.fn(),
|
||||
create: jest.fn(),
|
||||
};
|
||||
service = new FeatureService(mockRepository);
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should create a feature successfully', async () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const testData = { name: 'test-feature', title: 'Test Feature' };
|
||||
const mockFeature = {
|
||||
id: 'test-id',
|
||||
name: testData.name,
|
||||
// ... other fields
|
||||
};
|
||||
mockRepository.create.mockResolvedValue(mockFeature);
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực hiện
|
||||
const result = await service.create(testData);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(mockRepository.create).toHaveBeenCalledWith(testData);
|
||||
expect(result).toEqual(mockFeature);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Real Example / Ví dụ Thực tế**: [`services/iam-service/src/modules/feature/__tests__/feature.service.test.ts`](../../../services/iam-service/src/modules/feature/__tests__/feature.service.test.ts)
|
||||
|
||||
### Integration Test Pattern / Pattern Integration Test
|
||||
|
||||
Integration tests verify that multiple components work together correctly / Integration tests xác minh nhiều components làm việc cùng nhau đúng cách.
|
||||
|
||||
```typescript
|
||||
describe('Auth Middleware', () => {
|
||||
const mockNext = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should authenticate valid token and attach user to request', () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const mockReq = createMockReq({
|
||||
headers: { authorization: 'Bearer valid-token' },
|
||||
});
|
||||
const mockRes = createMockRes();
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực hiện
|
||||
const middleware = authenticate({ secret: jwtSecret });
|
||||
middleware(mockReq as Request, mockRes as Response, mockNext);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(mockNext).toHaveBeenCalled();
|
||||
expect(mockReq.user).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Real Example / Ví dụ Thực tế**: [`services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts`](../../../services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts)
|
||||
|
||||
### E2E Test Pattern / Pattern E2E Test
|
||||
|
||||
E2E tests use supertest to test complete HTTP request/response cycles / E2E tests sử dụng supertest để test các chu kỳ HTTP request/response hoàn chỉnh.
|
||||
|
||||
```typescript
|
||||
import request from 'supertest';
|
||||
import express from 'express';
|
||||
import { createRouter } from '../routes';
|
||||
|
||||
describe('Feature Endpoints E2E', () => {
|
||||
let app: express.Application;
|
||||
|
||||
beforeAll(() => {
|
||||
// EN: Set up test environment
|
||||
// VI: Thiết lập môi trường test
|
||||
process.env.NODE_ENV = 'test';
|
||||
app = express();
|
||||
app.use(express.json());
|
||||
app.use(createRouter());
|
||||
});
|
||||
|
||||
describe('POST /api/v1/features', () => {
|
||||
it('should create a feature successfully', async () => {
|
||||
// EN: Arrange
|
||||
// VI: Chuẩn bị
|
||||
const featureData = {
|
||||
name: 'test-feature',
|
||||
title: 'Test Feature',
|
||||
description: 'A test feature for E2E testing'
|
||||
};
|
||||
|
||||
// EN: Act
|
||||
// VI: Thực hiện
|
||||
const response = await request(app)
|
||||
.post('/api/v1/features')
|
||||
.send(featureData)
|
||||
.expect(201);
|
||||
|
||||
// EN: Assert
|
||||
// VI: Kiểm tra
|
||||
expect(response.body).toMatchObject({
|
||||
success: true,
|
||||
message: 'Feature created successfully / Feature đã được tạo thành công',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Real Example / Ví dụ Thực tế**: [`services/iam-service/src/__tests__/feature.e2e.ts`](../../../services/iam-service/src/__tests__/feature.e2e.ts)
|
||||
|
||||
## Mocking Strategies / Chiến Lược Mocking
|
||||
|
||||
### Mock Prisma Database / Mock Database Prisma
|
||||
|
||||
Mock Prisma client to avoid real database connections in unit tests / Mock Prisma client để tránh kết nối database thật trong unit tests.
|
||||
|
||||
```typescript
|
||||
// In setupTests.ts or individual test files
|
||||
jest.mock('../config/database.config', () => ({
|
||||
connectDatabase: jest.fn(),
|
||||
prisma: {
|
||||
$queryRaw: jest.fn(),
|
||||
$disconnect: jest.fn(),
|
||||
feature: {
|
||||
create: jest.fn(),
|
||||
findMany: jest.fn(),
|
||||
findUnique: jest.fn(),
|
||||
update: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
// Usage in tests
|
||||
const { prisma } = require('../config/database.config');
|
||||
|
||||
test('should create user', async () => {
|
||||
prisma.feature.create.mockResolvedValue({
|
||||
id: 'test-id',
|
||||
name: 'test-feature',
|
||||
// ... other fields
|
||||
});
|
||||
|
||||
const result = await createFeature({ name: 'test-feature' });
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
```
|
||||
|
||||
### Mock Redis / Mock Redis
|
||||
|
||||
Mock Redis client for caching and session management tests / Mock Redis client cho các test caching và quản lý session.
|
||||
|
||||
```typescript
|
||||
jest.mock('../config/redis.config', () => ({
|
||||
getRedisClient: jest.fn().mockReturnValue({
|
||||
call: jest.fn(),
|
||||
connect: jest.fn(),
|
||||
disconnect: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
```
|
||||
|
||||
### Mock External APIs / Mock External APIs
|
||||
|
||||
Mock external HTTP calls using Jest mocks / Mock các HTTP calls bên ngoài sử dụng Jest mocks.
|
||||
|
||||
```typescript
|
||||
jest.mock('axios');
|
||||
import axios from 'axios';
|
||||
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
||||
|
||||
test('should fetch external data', async () => {
|
||||
mockedAxios.get.mockResolvedValue({
|
||||
data: { result: 'success' }
|
||||
});
|
||||
|
||||
const result = await fetchExternalData();
|
||||
expect(result).toEqual({ result: 'success' });
|
||||
});
|
||||
```
|
||||
|
||||
### Mock Auth SDK / Mock Auth SDK
|
||||
|
||||
Mock authentication SDK functions for middleware and service tests / Mock các functions của authentication SDK cho middleware và service tests.
|
||||
|
||||
```typescript
|
||||
jest.mock('@goodgo/auth-sdk', () => ({
|
||||
createToken: jest.fn(),
|
||||
verifyToken: jest.fn(),
|
||||
extractTokenFromHeader: jest.fn(),
|
||||
}));
|
||||
|
||||
// Setup mock implementations
|
||||
(verifyToken as jest.Mock).mockImplementation((token) => {
|
||||
if (token === 'valid-token') {
|
||||
return { userId: '123', role: 'user' };
|
||||
}
|
||||
throw new Error('Invalid token');
|
||||
});
|
||||
```
|
||||
|
||||
## Testing Utilities / Utilities Test
|
||||
|
||||
### Test Factory Pattern / Pattern Test Factory
|
||||
|
||||
Create reusable test data factories for consistent test data / Tạo các factories dữ liệu test có thể tái sử dụng để có dữ liệu test nhất quán.
|
||||
|
||||
```typescript
|
||||
export class TestFactory {
|
||||
static createUser(overrides = {}) {
|
||||
return {
|
||||
id: 'test-user-1',
|
||||
email: 'test@example.com',
|
||||
name: 'Test User',
|
||||
createdAt: new Date(),
|
||||
...overrides
|
||||
};
|
||||
}
|
||||
|
||||
static createAuthToken(userId: string) {
|
||||
return jwt.sign({ userId }, 'test-secret');
|
||||
}
|
||||
|
||||
static async cleanDatabase() {
|
||||
await prisma.user.deleteMany();
|
||||
await prisma.feature.deleteMany();
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
const user = TestFactory.createUser({ name: 'Custom Name' });
|
||||
const token = TestFactory.createAuthToken(user.id);
|
||||
```
|
||||
|
||||
### Mock Request/Response Helpers / Helpers Mock Request/Response
|
||||
|
||||
Use global test utilities for creating mock Express request/response objects / Sử dụng test utilities toàn cục để tạo các objects mock Express request/response.
|
||||
|
||||
```typescript
|
||||
// Available via global.testUtils (from setupTests.ts)
|
||||
const mockReq = global.testUtils.createMockReq({
|
||||
headers: { authorization: 'Bearer token' },
|
||||
params: { id: '123' },
|
||||
});
|
||||
|
||||
const mockRes = global.testUtils.createMockRes();
|
||||
const mockNext = global.testUtils.createMockNext();
|
||||
```
|
||||
|
||||
## Common Test Scenarios / Các Tình Huống Test Thường Gặp
|
||||
|
||||
### Testing Error Handling / Test Xử Lý Lỗi
|
||||
|
||||
```typescript
|
||||
it('should handle database errors gracefully', async () => {
|
||||
// EN: Arrange - Mock database error
|
||||
// VI: Chuẩn bị - Mock lỗi database
|
||||
prismaMock.user.findUnique.mockRejectedValue(
|
||||
new Error('Database connection failed')
|
||||
);
|
||||
|
||||
// EN: Act & Assert
|
||||
// VI: Thực hiện & Kiểm tra
|
||||
await expect(userService.findById('123')).rejects.toThrow();
|
||||
|
||||
// Or for HTTP endpoints
|
||||
const response = await request(app)
|
||||
.get('/api/users/123')
|
||||
.expect(500);
|
||||
|
||||
expect(response.body).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INTERNAL_ERROR',
|
||||
message: 'Internal server error / Lỗi máy chủ nội bộ',
|
||||
},
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Testing Validation / Test Validation
|
||||
|
||||
```typescript
|
||||
describe('Validation', () => {
|
||||
it('should reject invalid email', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/auth/register')
|
||||
.send({ email: 'invalid-email', password: '123456' })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.error.code).toBe('VALIDATION_ERROR');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Testing Authorization / Test Authorization
|
||||
|
||||
```typescript
|
||||
it('should deny access for user with incorrect role', () => {
|
||||
const mockReq = createMockReq({
|
||||
user: { userId: 'user-123', role: 'user' },
|
||||
});
|
||||
|
||||
const middleware = authorize('admin');
|
||||
middleware(mockReq as Request, mockRes as Response, mockNext);
|
||||
|
||||
expect(mockNext).not.toHaveBeenCalled();
|
||||
expect(mockStatus).toHaveBeenCalledWith(403);
|
||||
});
|
||||
```
|
||||
|
||||
## Test Commands / Lệnh Test
|
||||
|
||||
Add these scripts to `package.json` / Thêm các scripts này vào `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:unit": "jest --testPathPattern=\\.test\\.ts$",
|
||||
"test:e2e": "jest --testPathPattern=\\.e2e\\.ts$",
|
||||
"test:ci": "jest --coverage --silent --maxWorkers=2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Usage / Sử dụng**:
|
||||
- `pnpm test`: Run all tests / Chạy tất cả tests
|
||||
- `pnpm test:watch`: Run tests in watch mode / Chạy tests ở chế độ watch
|
||||
- `pnpm test:coverage`: Generate coverage report / Tạo báo cáo coverage
|
||||
- `pnpm test:unit`: Run only unit tests / Chỉ chạy unit tests
|
||||
- `pnpm test:e2e`: Run only E2E tests / Chỉ chạy E2E tests
|
||||
- `pnpm test:ci`: Run tests optimized for CI/CD / Chạy tests tối ưu cho CI/CD
|
||||
|
||||
## Debugging Tests / Debugging Tests
|
||||
|
||||
### VS Code Debug Configuration / Cấu Hình Debug VS Code
|
||||
|
||||
Create `.vscode/launch.json` for debugging tests / Tạo `.vscode/launch.json` để debug tests:
|
||||
|
||||
```json
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Debug Jest Tests",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["test", "--", "--runInBand"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Tips / Mẹo Debug
|
||||
|
||||
1. **Use `test.only()`** to run a single test / Sử dụng `test.only()` để chạy một test duy nhất:
|
||||
```typescript
|
||||
it.only('should test specific behavior', () => {
|
||||
// Only this test will run
|
||||
});
|
||||
```
|
||||
|
||||
2. **Use `--detectOpenHandles`** for async issues / Sử dụng `--detectOpenHandles` cho các vấn đề async:
|
||||
```bash
|
||||
pnpm test --detectOpenHandles
|
||||
```
|
||||
|
||||
3. **Use `--runInBand`** for sequential execution / Sử dụng `--runInBand` cho thực thi tuần tự:
|
||||
```bash
|
||||
pnpm test --runInBand
|
||||
```
|
||||
|
||||
4. **Add temporary console.log** / Thêm console.log tạm thời:
|
||||
```typescript
|
||||
console.log('Debug value:', someValue);
|
||||
```
|
||||
|
||||
5. **Use debugger breakpoints** in VS Code / Sử dụng breakpoints debugger trong VS Code
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Test Organization / Tổ Chức Test
|
||||
|
||||
- ✅ Each test is independent and isolated / Mỗi test độc lập và cô lập
|
||||
- ✅ Tests follow AAA pattern (Arrange-Act-Assert) / Tests tuân theo pattern AAA
|
||||
- ✅ Use descriptive test names that explain what is being tested / Sử dụng tên test mô tả giải thích điều đang được test
|
||||
- ✅ Group related tests using `describe` blocks / Nhóm các test liên quan sử dụng `describe` blocks
|
||||
- ✅ Use `beforeEach`/`afterEach` for setup/cleanup / Sử dụng `beforeEach`/`afterEach` cho setup/cleanup
|
||||
|
||||
### Mocking / Mocking
|
||||
|
||||
- ✅ Mock external dependencies (database, APIs, services) / Mock các dependencies bên ngoài
|
||||
- ✅ Use `jest.clearAllMocks()` in `beforeEach` to reset mocks / Sử dụng `jest.clearAllMocks()` trong `beforeEach` để reset mocks
|
||||
- ✅ Verify mock calls to ensure correct behavior / Xác minh mock calls để đảm bảo hành vi đúng
|
||||
- ✅ Keep mocks simple and focused / Giữ mocks đơn giản và tập trung
|
||||
|
||||
### Coverage / Coverage
|
||||
|
||||
- ✅ Maintain >70% code coverage (as per Jest config) / Duy trì >70% code coverage (theo cấu hình Jest)
|
||||
- ✅ Focus on covering critical business logic / Tập trung vào bao phủ logic nghiệp vụ quan trọng
|
||||
- ✅ Don't sacrifice test quality for coverage percentage / Không hy sinh chất lượng test cho phần trăm coverage
|
||||
- ✅ Review coverage reports regularly / Xem xét báo cáo coverage thường xuyên
|
||||
|
||||
### Test Data / Dữ Liệu Test
|
||||
|
||||
- ✅ Use factories for creating test data / Sử dụng factories để tạo dữ liệu test
|
||||
- ✅ Keep test data realistic and representative / Giữ dữ liệu test thực tế và đại diện
|
||||
- ✅ Clean up test data after tests (if using real database) / Dọn dẹp dữ liệu test sau tests (nếu dùng database thật)
|
||||
- ✅ Use meaningful test values, not just `'test'` or `123` / Sử dụng giá trị test có ý nghĩa, không chỉ `'test'` hoặc `123`
|
||||
|
||||
### Error Testing / Test Lỗi
|
||||
|
||||
- ✅ Test both success and error scenarios / Test cả kịch bản thành công và lỗi
|
||||
- ✅ Test edge cases and boundary conditions / Test edge cases và điều kiện biên
|
||||
- ✅ Test validation errors / Test lỗi validation
|
||||
- ✅ Test error messages and error codes / Test thông báo lỗi và mã lỗi
|
||||
|
||||
### Performance / Hiệu Suất
|
||||
|
||||
- ✅ Keep unit tests fast (<1s each) / Giữ unit tests nhanh (<1s mỗi test)
|
||||
- ✅ Avoid unnecessary async operations in unit tests / Tránh các thao tác async không cần thiết trong unit tests
|
||||
- ✅ Use `--maxWorkers` in CI for parallel execution / Sử dụng `--maxWorkers` trong CI cho thực thi song song
|
||||
- ✅ Don't test implementation details, test behavior / Không test chi tiết implementation, test hành vi
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Real Test Examples / Ví Dụ Test Thực Tế
|
||||
|
||||
1. **Unit Test**: [`services/iam-service/src/modules/feature/__tests__/feature.service.test.ts`](../../../services/iam-service/src/modules/feature/__tests__/feature.service.test.ts)
|
||||
2. **Integration Test**: [`services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts`](../../../services/iam-service/src/middlewares/__tests__/auth.middleware.test.ts)
|
||||
3. **E2E Test**: [`services/iam-service/src/__tests__/feature.e2e.ts`](../../../services/iam-service/src/__tests__/feature.e2e.ts)
|
||||
4. **Setup File**: [`services/iam-service/src/__tests__/setupTests.ts`](../../../services/iam-service/src/__tests__/setupTests.ts)
|
||||
5. **Jest Config**: [`services/iam-service/jest.config.ts`](../../../services/iam-service/jest.config.ts)
|
||||
|
||||
### Test Structure Examples / Ví Dụ Cấu Trúc Test
|
||||
|
||||
- **Repository Tests**: [`services/iam-service/src/modules/feature/__tests__/feature.repository.test.ts`](../../../services/iam-service/src/modules/feature/__tests__/feature.repository.test.ts)
|
||||
- **Controller Tests**: [`services/iam-service/src/modules/health/__tests__/health.controller.test.ts`](../../../services/iam-service/src/modules/health/__tests__/health.controller.test.ts)
|
||||
- **Middleware Tests**: [`services/iam-service/src/middlewares/__tests__/correlation.middleware.test.ts`](../../../services/iam-service/src/middlewares/__tests__/correlation.middleware.test.ts)
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Test Type Decision Tree / Cây Quyết Định Loại Test
|
||||
|
||||
```
|
||||
Need to test complete HTTP flow?
|
||||
├─ Yes → E2E Test (*.e2e.ts)
|
||||
└─ No → Multiple components interacting?
|
||||
├─ Yes → Integration Test (*.test.ts)
|
||||
└─ No → Unit Test (*.test.ts)
|
||||
```
|
||||
|
||||
### Common Jest Matchers / Các Matcher Jest Thường Dùng
|
||||
|
||||
| Matcher | Purpose / Mục đích | Example / Ví dụ |
|
||||
|---------|-------------------|-----------------|
|
||||
| `toBe()` | Exact equality / So sánh chính xác | `expect(value).toBe(5)` |
|
||||
| `toEqual()` | Deep equality / So sánh sâu | `expect(obj).toEqual({a: 1})` |
|
||||
| `toMatchObject()` | Partial match / So sánh một phần | `expect(obj).toMatchObject({a: 1})` |
|
||||
| `toHaveBeenCalled()` | Function called / Function đã được gọi | `expect(mockFn).toHaveBeenCalled()` |
|
||||
| `toHaveBeenCalledWith()` | Called with args / Gọi với args | `expect(mockFn).toHaveBeenCalledWith('arg')` |
|
||||
| `toThrow()` | Throws error / Ném lỗi | `expect(() => fn()).toThrow()` |
|
||||
| `toBeDefined()` | Not undefined / Không undefined | `expect(value).toBeDefined()` |
|
||||
| `toBeNull()` | Is null / Là null | `expect(value).toBeNull()` |
|
||||
| `toContain()` | Array/string contains / Chứa trong array/string | `expect(array).toContain('item')` |
|
||||
|
||||
### Mock Function Helpers / Helpers Mock Function
|
||||
|
||||
```typescript
|
||||
// Create mock
|
||||
const mockFn = jest.fn();
|
||||
|
||||
// Set return value
|
||||
mockFn.mockReturnValue('value');
|
||||
mockFn.mockResolvedValue('async value');
|
||||
mockFn.mockRejectedValue(new Error('error'));
|
||||
|
||||
// Set implementation
|
||||
mockFn.mockImplementation((arg) => arg * 2);
|
||||
|
||||
// Clear/reset
|
||||
mockFn.mockClear(); // Clear call history
|
||||
mockFn.mockReset(); // Reset to initial state
|
||||
jest.clearAllMocks(); // Clear all mocks
|
||||
```
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Comment Code](./comment-code.md)**: Writing bilingual comments in tests / Viết comments song ngữ trong tests
|
||||
- **[Security](./security.md)**: Testing security-critical code / Test code bảo mật quan trọng
|
||||
- **[API Design](./api-design.md)**: Testing API endpoints and responses / Test API endpoints và responses
|
||||
- **[Project Rules](./project-rules.md)**: Code organization for tests / Tổ chức code cho tests
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
### Official Documentation / Tài Liệu Chính Thức
|
||||
|
||||
- [Jest Documentation](https://jestjs.io/docs/getting-started)
|
||||
- [Supertest Documentation](https://github.com/visionmedia/supertest)
|
||||
- [jest-mock-extended](https://github.com/marchaos/jest-mock-extended)
|
||||
|
||||
### Internal Documentation / Tài Liệu Nội Bộ
|
||||
|
||||
- [Service Development Guide](../guides/development.md)
|
||||
- [Local Development Setup](../guides/local-development.md)
|
||||
- [Troubleshooting Guide](../guides/troubleshooting.md)
|
||||
|
||||
### Tools / Công Cụ
|
||||
|
||||
- **Jest**: JavaScript testing framework / Framework testing JavaScript
|
||||
- **Supertest**: HTTP assertion library / Thư viện assertion HTTP
|
||||
- **jest-mock-extended**: Enhanced mocking for TypeScript / Mock nâng cao cho TypeScript
|
||||
- **ioredis-mock**: Redis mock for testing / Mock Redis cho testing
|
||||
Reference in New Issue
Block a user