feat(docs): Enhance deployment and development guides with improved clarity and structure

- Updated Mermaid diagrams in the deployment and development guides for better visual representation and consistency.
- Improved formatting and clarity in the Kubernetes local deployment and IAM migration guides, including detailed workflows and troubleshooting sections.
- Enhanced the Vietnamese documentation to align with the English version, ensuring consistency across guides.
- Added quick tips and common issues sections to facilitate user navigation and understanding.
This commit is contained in:
Ho Ngoc Hai
2026-01-08 17:10:06 +07:00
parent 70d90d36e0
commit 9ba4a478ee
22 changed files with 3030 additions and 3030 deletions

View File

@@ -20,37 +20,37 @@
```mermaid
graph TD
subgraph "CI/CD Pipeline - GitHub Actions"
Code[Code Push] --> Test[Run Tests]
Test --> Build[Build Docker Image]
Build --> Registry[Push to Registry]
Registry --> Deploy[Deploy to K8s]
end
subgraph "Infrastructure - Kubernetes"
Ingress[Traefik Ingress] --> Service[K8s Service]
Service --> Pods[Application Pods]
Pods --> Secrets[K8s Secrets]
end
subgraph "External Services"
Pods --> Neon[(Neon PostgreSQL)]
Pods --> Redis[(Redis Cloud)]
end
Deploy --> Ingress
style Code fill:#1e3a5f,color:#e0e7ff
style Test fill:#065f46,color:#d1fae5
style Build fill:#1e40af,color:#dbeafe
style Registry fill:#581c87,color:#f3e8ff
style Deploy fill:#9a3412,color:#fed7aa
style Ingress fill:#312e81,color:#e0e7ff
style Service fill:#1e40af,color:#dbeafe
style Pods fill:#14532d,color:#d1fae5
style Secrets fill:#78350f,color:#fef3c7
style Neon fill:#4c1d95,color:#f3e8ff
style Redis fill:#854d0e,color:#fef3c7
subgraph "CI/CD Pipeline - GitHub Actions"
Code[Code Push] --> Test[Run Tests]
Test --> Build[Build Docker Image]
Build --> Registry[Push to Registry]
Registry --> Deploy[Deploy to K8s]
end
subgraph "Infrastructure - Kubernetes"
Ingress[Traefik Ingress] --> Service[K8s Service]
Service --> Pods[Application Pods]
Pods --> Secrets[K8s Secrets]
end
subgraph "External Services"
Pods --> Neon[(Neon PostgreSQL)]
Pods --> Redis[(Redis Cloud)]
end
Deploy --> Ingress
style Code fill:#1e3a5f,color:#e0e7ff
style Test fill:#065f46,color:#d1fae5
style Build fill:#1e40af,color:#dbeafe
style Registry fill:#581c87,color:#f3e8ff
style Deploy fill:#9a3412,color:#fed7aa
style Ingress fill:#312e81,color:#e0e7ff
style Service fill:#1e40af,color:#dbeafe
style Pods fill:#14532d,color:#d1fae5
style Secrets fill:#78350f,color:#fef3c7
style Neon fill:#4c1d95,color:#f3e8ff
style Redis fill:#854d0e,color:#fef3c7
```
---
@@ -59,14 +59,14 @@ graph TD
Before deploying, ensure you have:
* **Tools**: `kubectl`, `helm`, `docker` installed.
* **Access**:
* Kubernetes Cluster (EKS/GKE/DigitalOcean).
* Container Registry (GHCR/DockerHub).
* Neon Console Account.
* **Configuration**:
* `KUBECONFIG` file set up.
* GitHub Secrets configured for CI/CD.
* **Tools**: `kubectl`, `helm`, `docker` installed.
* **Access**:
* Kubernetes Cluster (EKS/GKE/DigitalOcean).
* Container Registry (GHCR/DockerHub).
* Neon Console Account.
* **Configuration**:
* `KUBECONFIG` file set up.
* GitHub Secrets configured for CI/CD.
---
@@ -74,13 +74,13 @@ Before deploying, ensure you have:
We use **Neon Serverless PostgreSQL** for all environments to leverage branching and auto-scaling.
1. **Create Project**: Log in to [neon.tech](https://neon.tech) and create a project `goodgo-platform`.
2. **Create Branches**:
* `main` -> For Development/Local.
* `staging` -> For Staging environment.
* `production` -> For Production environment (Protected).
3. **Get Connection Strings**:
* Note the connection string for each branch (Pooler mode recommended).
1. **Create Project**: Log in to [neon.tech](https://neon.tech) and create a project `goodgo-platform`.
2. **Create Branches**:
* `main` -> For Development/Local.
* `staging` -> For Staging environment.
* `production` -> For Production environment (Protected).
3. **Get Connection Strings**:
* Note the connection string for each branch (Pooler mode recommended).
---
@@ -117,11 +117,11 @@ We use GitHub Actions for automated deployments.
Set these secrets in your repository settings:
* `NEON_DATABASE_URL_STAGING`: Connection string for staging branch.
* `NEON_DATABASE_URL_PRODUCTION`: Connection string for production branch.
* `KUBECONFIG_STAGING`: Base64 encoded kubeconfig for staging.
* `KUBECONFIG_PRODUCTION`: Base64 encoded kubeconfig for production.
* `DOCKER_REGISTRY_TOKEN`: For pushing images.
* `NEON_DATABASE_URL_STAGING`: Connection string for staging branch.
* `NEON_DATABASE_URL_PRODUCTION`: Connection string for production branch.
* `KUBECONFIG_STAGING`: Base64 encoded kubeconfig for staging.
* `KUBECONFIG_PRODUCTION`: Base64 encoded kubeconfig for production.
* `DOCKER_REGISTRY_TOKEN`: For pushing images.
---
@@ -134,9 +134,9 @@ Staging mirrors production but uses cost-effective resources.
```bash
# 1. Create Secrets
kubectl create secret generic iam-service-secrets \
--from-literal=database-url='<STAGING_NEON_URL>' \
--from-literal=jwt-secret='<RANDOM_SECRET>' \
-n staging
--from-literal=database-url='<STAGING_NEON_URL>' \
--from-literal=jwt-secret='<RANDOM_SECRET>' \
-n staging
# 2. Apply Manifests
kubectl apply -f deployments/staging/kubernetes/ -n staging
@@ -148,9 +148,9 @@ kubectl get pods -n staging
### via CI/CD
Push code to `develop` branch. The action will:
1. Run tests.
2. Run `prisma migrate deploy` against Staging DB.
3. Update Kubernetes deployment image.
1. Run tests.
2. Run `prisma migrate deploy` against Staging DB.
3. Update Kubernetes deployment image.
---
@@ -160,8 +160,8 @@ Production uses high-availability configurations.
### 1. Database Preparation
* Ensure Production branch in Neon is **protected**.
* Configure **Point-in-Time Recovery (PITR)** window (e.g., 7 days).
* Ensure Production branch in Neon is **protected**.
* Configure **Point-in-Time Recovery (PITR)** window (e.g., 7 days).
### 2. Manual Deployment Steps
@@ -171,10 +171,10 @@ kubectl create namespace production
# 2. Create Sealed Secrets (Recommended) or Standard Secrets
kubectl create secret generic iam-service-secrets \
--from-literal=database-url='<PROD_NEON_URL>' \
--from-literal=jwt-secret='<SECURE_RANDOM_SECRET>' \
--from-literal=jwt-refresh-secret='<SECURE_RANDOM_SECRET>' \
-n production
--from-literal=database-url='<PROD_NEON_URL>' \
--from-literal=jwt-secret='<SECURE_RANDOM_SECRET>' \
--from-literal=jwt-refresh-secret='<SECURE_RANDOM_SECRET>' \
-n production
# 3. Deploy
kubectl apply -f deployments/production/kubernetes/ -n production
@@ -203,24 +203,24 @@ We use HPA to automatically scale pods based on CPU/Memory.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: iam-service-hpa
name: iam-service-hpa
spec:
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
```
### Zero-Downtime Deployment
Kubernetes handles this via Rolling Updates.
* **MaxSurge**: 25% (Add new pods before removing old ones).
* **MaxUnavailable**: 0 (Ensure no downtime during update).
* **MaxSurge**: 25% (Add new pods before removing old ones).
* **MaxUnavailable**: 0 (Ensure no downtime during update).
---
@@ -241,6 +241,6 @@ kubectl rollout undo deployment/iam-service -n production --to-revision=2
### Database Rollback
Since Neon supports branching and PITR:
1. Go to Neon Console.
2. Restore the `production` branch to a timestamp before the bad migration.
3. **Warning**: This may result in data loss for new transactions. Use with caution.
1. Go to Neon Console.
2. Restore the `production` branch to a timestamp before the bad migration.
3. **Warning**: This may result in data loss for new transactions. Use with caution.

View File

@@ -20,22 +20,22 @@ We follow a strict monorepo structure managed by PNPM Workspaces.
```
Base/
├── apps/ # Frontend applications
│ ├── web-client/ # Next.js 14+ (App Router)
│ └── mobile-client/ # Flutter
├── services/ # Backend microservices
│ ├── _template/ # Template for new services
│ ├── iam-service/ # Identity & Access Management
│ └── ...
├── packages/ # Shared libraries
│ ├── logger/ # Structured logging (Winston)
│ ├── types/ # Shared DTOs & Interfaces
│ ├── http-client/ # Internal Service Client
│ └── tracing/ # OpenTelemetry configuration
├── infra/ # Infrastructure-as-Code
│ ├── traefik/ # API Gateway
│ └── databases/ # Database setup scripts
└── docs/ # Documentation (EN & VI)
apps/ # Frontend applications
web-client/ # Next.js 14+ (App Router)
mobile-client/ # Flutter
services/ # Backend microservices
_template/ # Template for new services
iam-service/ # Identity & Access Management
...
packages/ # Shared libraries
logger/ # Structured logging (Winston)
types/ # Shared DTOs & Interfaces
http-client/ # Internal Service Client
tracing/ # OpenTelemetry configuration
infra/ # Infrastructure-as-Code
traefik/ # API Gateway
databases/ # Database setup scripts
docs/ # Documentation (EN & VI)
```
---
@@ -44,11 +44,11 @@ Base/
### Naming Conventions
* **Files**: `kebab-case.ts` (e.g., `user.controller.ts`, `app.config.ts`)
* **Classes**: `PascalCase` (e.g., `UserController`, `AuthService`)
* **Functions/Variables**: `camelCase` (e.g., `getUserById`, `isValid`)
* **Constants**: `UPPER_SNAKE_CASE` (e.g., `MAX_RETRIES`, `DEFAULT_TIMEOUT`)
* **Interfaces**: `PascalCase` (e.g., `User`, `CreateUserDto`) - *No 'I' prefix*
* **Files**: `kebab-case.ts` (e.g., `user.controller.ts`, `app.config.ts`)
* **Classes**: `PascalCase` (e.g., `UserController`, `AuthService`)
* **Functions/Variables**: `camelCase` (e.g., `getUserById`, `isValid`)
* **Constants**: `UPPER_SNAKE_CASE` (e.g., `MAX_RETRIES`, `DEFAULT_TIMEOUT`)
* **Interfaces**: `PascalCase` (e.g., `User`, `CreateUserDto`) - *No 'I' prefix*
### Bilingual Comments
@@ -64,9 +64,9 @@ async login(dto: LoginDto): Promise<TokenResponse> { ... }
### TypeScript Usage
* **Strict Mode**: Enabled in `tsconfig.json`. No `any` allowed (use `unknown` if needed).
* **DTOs**: Use Zod for runtime validation and type inference.
* **Return Types**: Explicitly declare return types for all public methods.
* **Strict Mode**: Enabled in `tsconfig.json`. No `any` allowed (use `unknown` if needed).
* **DTOs**: Use Zod for runtime validation and type inference.
* **Return Types**: Explicitly declare return types for all public methods.
---
@@ -74,44 +74,44 @@ async login(dto: LoginDto): Promise<TokenResponse> { ... }
### Branching Strategy
* `main`: Production-ready code.
* `develop`: Integration branch for next release.
* `feature/xyz`: New features (branch off `develop`).
* `fix/xyz`: Bug fixes (branch off `develop`).
* `hotfix/xyz`: Critical fixes (branch off `main`).
* `main`: Production-ready code.
* `develop`: Integration branch for next release.
* `feature/xyz`: New features (branch off `develop`).
* `fix/xyz`: Bug fixes (branch off `develop`).
* `hotfix/xyz`: Critical fixes (branch off `main`).
```mermaid
gitGraph
commit id: "Initial"
branch develop
checkout develop
commit id: "Setup"
branch feature/login
checkout feature/login
commit id: "Add login form"
commit id: "Add validation"
checkout develop
merge feature/login
branch feature/dashboard
checkout feature/dashboard
commit id: "Create dashboard"
checkout develop
checkout main
merge develop tag: "v1.0.0"
checkout develop
merge feature/dashboard
checkout main
branch hotfix/security
commit id: "Fix security issue"
checkout main
merge hotfix/security tag: "v1.0.1"
checkout develop
merge hotfix/security
commit id: "Initial"
branch develop
checkout develop
commit id: "Setup"
branch feature/login
checkout feature/login
commit id: "Add login form"
commit id: "Add validation"
checkout develop
merge feature/login
branch feature/dashboard
checkout feature/dashboard
commit id: "Create dashboard"
checkout develop
checkout main
merge develop tag: "v1.0.0"
checkout develop
merge feature/dashboard
checkout main
branch hotfix/security
commit id: "Fix security issue"
checkout main
merge hotfix/security tag: "v1.0.1"
checkout develop
merge hotfix/security
```
### Commit Messages
@@ -134,60 +134,60 @@ chore: update dependencies
```mermaid
graph TD
Start([Start Creating New API]) --> DTO[1. Define DTO - Zod Schema]
DTO --> Repo[2. Create Repository Method]
Repo --> Service[3. Create Service Method - Business Logic]
Service --> Controller[4. Create Controller - HTTP Handler]
Controller --> Route[5. Register Route - Express Router]
Route --> Middleware[6. Add Middlewares]
Middleware --> Test[7. Write Tests]
Test --> Done([API Complete])
Service --> ErrorCheck{Has Error?}
ErrorCheck -->|Yes| ThrowError[Throw HttpError]
ThrowError --> ErrorHandler[Global Error Handler]
ErrorHandler --> Response[Error Response]
ErrorCheck -->|No| Success[Success Response]
style Start fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style Done fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style DTO fill:#1e293b,color:#60a5fa
style Repo fill:#1e293b,color:#3b82f6
style Service fill:#2e1a47,color:#a78bfa
style Controller fill:#2d1b0e,color:#fb923c
style Route fill:#1e293b,color:#3b82f6
style Middleware fill:#1e293b,color:#60a5fa
style Test fill:#1e3a2e,color:#4ade80
style ErrorCheck fill:#2d1b0e,color:#fb923c
style ThrowError fill:#3f1a1a,color:#f87171
style ErrorHandler fill:#3f1a1a,color:#f87171
style Response fill:#27272a,color:#a1a1aa
style Success fill:#1e3a2e,color:#4ade80
Start([Start Creating New API]) --> DTO[1. Define DTO - Zod Schema]
DTO --> Repo[2. Create Repository Method]
Repo --> Service[3. Create Service Method - Business Logic]
Service --> Controller[4. Create Controller - HTTP Handler]
Controller --> Route[5. Register Route - Express Router]
Route --> Middleware[6. Add Middlewares]
Middleware --> Test[7. Write Tests]
Test --> Done([API Complete])
Service --> ErrorCheck{Has Error?}
ErrorCheck -->|Yes| ThrowError[Throw HttpError]
ThrowError --> ErrorHandler[Global Error Handler]
ErrorHandler --> Response[Error Response]
ErrorCheck -->|No| Success[Success Response]
style Start fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style Done fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style DTO fill:#1e293b,color:#60a5fa
style Repo fill:#1e293b,color:#3b82f6
style Service fill:#2e1a47,color:#a78bfa
style Controller fill:#2d1b0e,color:#fb923c
style Route fill:#1e293b,color:#3b82f6
style Middleware fill:#1e293b,color:#60a5fa
style Test fill:#1e3a2e,color:#4ade80
style ErrorCheck fill:#2d1b0e,color:#fb923c
style ThrowError fill:#3f1a1a,color:#f87171
style ErrorHandler fill:#3f1a1a,color:#f87171
style Response fill:#27272a,color:#a1a1aa
style Success fill:#1e3a2e,color:#4ade80
```
### Creating a New API Endpoint
1. **Define DTO** (`modules/user/user.dto.ts`):
```typescript
export const CreateUserDto = z.object({
email: z.string().email(),
name: z.string().min(2),
});
export type CreateUserDto = z.infer<typeof CreateUserDto>;
```
1. **Define DTO** (`modules/user/user.dto.ts`):
```typescript
export const CreateUserDto = z.object({
email: z.string().email(),
name: z.string().min(2),
});
export type CreateUserDto = z.infer<typeof CreateUserDto>;
```
2. **Create Service Method** (`modules/user/user.service.ts`):
* Implement business logic.
* Use `BaseRepository`.
* Throw `HttpError` (e.g., `NotFound`, `BadRequest`).
2. **Create Service Method** (`modules/user/user.service.ts`):
* Implement business logic.
* Use `BaseRepository`.
* Throw `HttpError` (e.g., `NotFound`, `BadRequest`).
3. **Create Controller** (`modules/user/user.controller.ts`):
* Parse body with DTO: `const dto = CreateUserDto.parse(req.body)`.
* Call service.
* Return success response: `res.json({ success: true, data: result })`.
3. **Create Controller** (`modules/user/user.controller.ts`):
* Parse body with DTO: `const dto = CreateUserDto.parse(req.body)`.
* Call service.
* Return success response: `res.json({ success: true, data: result })`.
4. **Register Route** (`modules/user/index.ts`):
* Add to Express router with middlewares.
4. **Register Route** (`modules/user/index.ts`):
* Add to Express router with middlewares.
### Error Handling
@@ -197,7 +197,7 @@ Always use the custom error classes from `core/errors`:
import { NotFoundError, ConflictError } from '../../core/errors';
if (!user) {
throw new NotFoundError('User not found');
throw new NotFoundError('User not found');
}
```
@@ -207,74 +207,74 @@ if (!user) {
```mermaid
graph TB
subgraph "Testing Pyramid - Bottom to Top"
Unit[Unit Tests - Most, Fastest]
Integration[Integration Tests - Medium]
E2E[E2E Tests - Least, Slowest]
end
Code[Code Changes] --> CheckLint{Lint Pass?}
CheckLint -->|No| FixLint[Fix Linting Errors]
FixLint --> CheckLint
CheckLint -->|Yes| RunUnit[Run Unit Tests]
RunUnit --> UnitPass{Unit Tests Pass?}
UnitPass -->|No| FixUnit[Fix Unit Tests]
FixUnit --> RunUnit
UnitPass -->|Yes| RunIntegration[Run Integration Tests]
RunIntegration --> IntPass{Integration Pass?}
IntPass -->|No| FixIntegration[Fix Integration]
FixIntegration --> RunIntegration
IntPass -->|Yes| RunE2E[Run E2E Tests]
RunE2E --> E2EPass{E2E Pass?}
E2EPass -->|No| FixE2E[Fix E2E]
FixE2E --> RunE2E
E2EPass -->|Yes| Coverage{Coverage > 70%?}
Coverage -->|No| AddTests[Add More Tests]
AddTests --> RunUnit
Coverage -->|Yes| ReadyMerge[Ready to Merge]
style Unit fill:#1e3a2e,color:#4ade80
style Integration fill:#1e293b,color:#60a5fa
style E2E fill:#2e1a47,color:#a78bfa
style Code fill:#1e293b,color:#3b82f6
style CheckLint fill:#2d1b0e,color:#fb923c
style UnitPass fill:#1e3a2e,color:#4ade80
style IntPass fill:#1e293b,color:#60a5fa
style E2EPass fill:#2e1a47,color:#a78bfa
style Coverage fill:#2d1b0e,color:#fbbf24
style RunUnit fill:#1e3a2e,color:#4ade80
style RunIntegration fill:#1e293b,color:#60a5fa
style RunE2E fill:#2e1a47,color:#a78bfa
style ReadyMerge fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style FixLint fill:#3f1a1a,color:#f87171
style FixUnit fill:#3f1a1a,color:#f87171
style FixIntegration fill:#3f1a1a,color:#f87171
style FixE2E fill:#3f1a1a,color:#f87171
style AddTests fill:#2d1b0e,color:#fbbf24
subgraph "Testing Pyramid - Bottom to Top"
Unit[Unit Tests - Most, Fastest]
Integration[Integration Tests - Medium]
E2E[E2E Tests - Least, Slowest]
end
Code[Code Changes] --> CheckLint{Lint Pass?}
CheckLint -->|No| FixLint[Fix Linting Errors]
FixLint --> CheckLint
CheckLint -->|Yes| RunUnit[Run Unit Tests]
RunUnit --> UnitPass{Unit Tests Pass?}
UnitPass -->|No| FixUnit[Fix Unit Tests]
FixUnit --> RunUnit
UnitPass -->|Yes| RunIntegration[Run Integration Tests]
RunIntegration --> IntPass{Integration Pass?}
IntPass -->|No| FixIntegration[Fix Integration]
FixIntegration --> RunIntegration
IntPass -->|Yes| RunE2E[Run E2E Tests]
RunE2E --> E2EPass{E2E Pass?}
E2EPass -->|No| FixE2E[Fix E2E]
FixE2E --> RunE2E
E2EPass -->|Yes| Coverage{Coverage > 70%?}
Coverage -->|No| AddTests[Add More Tests]
AddTests --> RunUnit
Coverage -->|Yes| ReadyMerge[Ready to Merge]
style Unit fill:#1e3a2e,color:#4ade80
style Integration fill:#1e293b,color:#60a5fa
style E2E fill:#2e1a47,color:#a78bfa
style Code fill:#1e293b,color:#3b82f6
style CheckLint fill:#2d1b0e,color:#fb923c
style UnitPass fill:#1e3a2e,color:#4ade80
style IntPass fill:#1e293b,color:#60a5fa
style E2EPass fill:#2e1a47,color:#a78bfa
style Coverage fill:#2d1b0e,color:#fbbf24
style RunUnit fill:#1e3a2e,color:#4ade80
style RunIntegration fill:#1e293b,color:#60a5fa
style RunE2E fill:#2e1a47,color:#a78bfa
style ReadyMerge fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style FixLint fill:#3f1a1a,color:#f87171
style FixUnit fill:#3f1a1a,color:#f87171
style FixIntegration fill:#3f1a1a,color:#f87171
style FixE2E fill:#3f1a1a,color:#f87171
style AddTests fill:#2d1b0e,color:#fbbf24
```
### Unit Tests (`*.test.ts`)
* **Scope**: Individual classes/functions.
* **Mocking**: Mock all external dependencies (DB, other services) using `jest-mock-extended`.
* **Location**: Co-located with source files.
* **Run**: `pnpm test`
* **Scope**: Individual classes/functions.
* **Mocking**: Mock all external dependencies (DB, other services) using `jest-mock-extended`.
* **Location**: Co-located with source files.
* **Run**: `pnpm test`
### E2E Tests (`tests/**/*.e2e.ts`)
* **Scope**: Full API flows (Controller -> Service -> DB).
* **Database**: Use a separate test database (Dockerized).
* **Run**: `pnpm test:e2e`
* **Scope**: Full API flows (Controller -> Service -> DB).
* **Database**: Use a separate test database (Dockerized).
* **Run**: `pnpm test:e2e`
### Linting & Formatting
* **Lint**: `pnpm lint` (ESLint)
* **Format**: `pnpm format` (Prettier)
* **Typecheck**: `pnpm typecheck` (TSC)
* **Lint**: `pnpm lint` (ESLint)
* **Format**: `pnpm format` (Prettier)
* **Typecheck**: `pnpm typecheck` (TSC)
---
@@ -284,15 +284,15 @@ We use **Prisma** with **Neon PostgreSQL**.
### Migrations
1. Modify `prisma/schema.prisma`.
2. Create migration (Dev):
```bash
./scripts/db/migrate.sh iam-service dev --name add_user_profile
```
3. Apply to Production (CI/CD):
```bash
./scripts/db/migrate.sh iam-service deploy
```
1. Modify `prisma/schema.prisma`.
2. Create migration (Dev):
```bash
./scripts/db/migrate.sh iam-service dev --name add_user_profile
```
3. Apply to Production (CI/CD):
```bash
./scripts/db/migrate.sh iam-service deploy
```
### Seed Data

View File

@@ -16,23 +16,23 @@
Before starting, ensure you have the following installed:
* **Node.js**: v20.0.0 or higher (recommended v22+ or v25+)
```bash
node -v
# v25.2.1
```
* **PNPM**: v8.15.0 or higher (we use pnpm workspaces)
```bash
pnpm -v
# 8.15.0
```
* **Docker & Docker Compose**: v24.0.0 or higher for local infrastructure
```bash
docker -v
# Docker version 29.1.3, build f52814d
```
* **Git**: For version control
* **Neon Account**: Serverless PostgreSQL (https://neon.tech)
* **Node.js**: v20.0.0 or higher (recommended v22+ or v25+)
```bash
node -v
# v25.2.1
```
* **PNPM**: v8.15.0 or higher (we use pnpm workspaces)
```bash
pnpm -v
# 8.15.0
```
* **Docker & Docker Compose**: v24.0.0 or higher for local infrastructure
```bash
docker -v
# Docker version 29.1.3, build f52814d
```
* **Git**: For version control
* **Neon Account**: Serverless PostgreSQL (https://neon.tech)
## Architecture Overview
@@ -40,44 +40,44 @@ GoodGo Platform uses a microservices architecture with a shared infrastructure l
```mermaid
graph TD
Client[Client Apps] --> Traefik[Traefik Gateway]
Traefik --> IAM[IAM Service]
Traefik --> Template[Template Service]
IAM --> DB[(Neon PostgreSQL)]
IAM --> Redis[(Redis Cache)]
IAM --> Kafka[Kafka Events]
style Client fill:#34495E,stroke:#2C3E50,color:#ECF0F1
style Traefik fill:#1A5490,stroke:#154360,color:#ECF0F1
style IAM fill:#1E8449,stroke:#186A3B,color:#ECF0F1
style Template fill:#BA6610,stroke:#935116,color:#ECF0F1
style DB fill:#6C3483,stroke:#512E5F,color:#ECF0F1
style Redis fill:#CA6F1E,stroke:#A04000,color:#ECF0F1
style Kafka fill:#21618C,stroke:#1B4F72,color:#ECF0F1
Client[Client Apps] --> Traefik[Traefik Gateway]
Traefik --> IAM[IAM Service]
Traefik --> Template[Template Service]
IAM --> DB[(Neon PostgreSQL)]
IAM --> Redis[(Redis Cache)]
IAM --> Kafka[Kafka Events]
style Client fill:#34495E,stroke:#2C3E50,color:#ECF0F1
style Traefik fill:#1A5490,stroke:#154360,color:#ECF0F1
style IAM fill:#1E8449,stroke:#186A3B,color:#ECF0F1
style Template fill:#BA6610,stroke:#935116,color:#ECF0F1
style DB fill:#6C3483,stroke:#512E5F,color:#ECF0F1
style Redis fill:#CA6F1E,stroke:#A04000,color:#ECF0F1
style Kafka fill:#21618C,stroke:#1B4F72,color:#ECF0F1
```
### Color Palette
```mermaid
graph LR
A["🔵 Primary<br/>#1A5490"] --> B["🟠 Data/Cache<br/>#CA6F1E"]
B --> C["🟢 Success<br/>#1E8449"]
C --> D["🟡 Warning<br/>#BA6610"]
D --> E["🔴 Error<br/>#922B21"]
E --> F["🟣 Processing<br/>#6C3483"]
F --> G["🔷 Info<br/>#21618C"]
G --> H[" Neutral<br/>#34495E"]
style A fill:#1A5490,stroke:#154360,color:#ECF0F1
style B fill:#CA6F1E,stroke:#A04000,color:#ECF0F1
style C fill:#1E8449,stroke:#186A3B,color:#ECF0F1
style D fill:#BA6610,stroke:#935116,color:#ECF0F1
style E fill:#922B21,stroke:#78281F,color:#ECF0F1
style F fill:#6C3483,stroke:#512E5F,color:#ECF0F1
style G fill:#21618C,stroke:#1B4F72,color:#ECF0F1
style H fill:#34495E,stroke:#2C3E50,color:#ECF0F1
A[" Primary<br/>#1A5490"] --> B[" Data/Cache<br/>#CA6F1E"]
B --> C[" Success<br/>#1E8449"]
C --> D[" Warning<br/>#BA6610"]
D --> E[" Error<br/>#922B21"]
E --> F[" Processing<br/>#6C3483"]
F --> G[" Info<br/>#21618C"]
G --> H[" Neutral<br/>#34495E"]
style A fill:#1A5490,stroke:#154360,color:#ECF0F1
style B fill:#CA6F1E,stroke:#A04000,color:#ECF0F1
style C fill:#1E8449,stroke:#186A3B,color:#ECF0F1
style D fill:#BA6610,stroke:#935116,color:#ECF0F1
style E fill:#922B21,stroke:#78281F,color:#ECF0F1
style F fill:#6C3483,stroke:#512E5F,color:#ECF0F1
style G fill:#21618C,stroke:#1B4F72,color:#ECF0F1
style H fill:#34495E,stroke:#2C3E50,color:#ECF0F1
```
## Project Structure
@@ -86,42 +86,42 @@ The repository follows a monorepo structure:
```
Base/
├── apps/ # Frontend applications
│ ├── app-admin/ # Admin dashboard application
│ ├── app-client/ # Client mobile application (Flutter)
│ ├── web-client/ # Next.js web application
│ └── web-docs/ # Documentation website (Next.js)
├── services/ # Backend microservices
│ ├── iam-service/ # Authentication & Authorization service
│ └── _template/ # Template for new services
├── packages/ # Shared libraries
│ ├── auth-sdk/ # Authentication SDK
│ ├── config/ # Shared configuration utilities
│ ├── http-client/ # Internal HTTP client
│ ├── logger/ # Structured logging (@goodgo/logger)
│ ├── tracing/ # OpenTelemetry tracing
│ └── types/ # Shared TypeScript types
├── infra/ # Infrastructure configuration
│ ├── databases/ # Database setup scripts
│ ├── docker/ # Docker configurations
│ ├── observability/ # Prometheus, Grafana, Loki configs
│ ├── secrets/ # Secrets management templates
│ └── traefik/ # API Gateway configuration
├── deployments/ # Deployment configurations
│ ├── local/ # Docker Compose for development
│ ├── staging/ # Staging environment configs
│ └── production/ # Production Kubernetes manifests
├── scripts/ # Automation scripts
│ ├── build/ # Build scripts
│ ├── db/ # Database utilities
│ ├── deploy/ # Deployment scripts
│ ├── dev/ # Development helpers
│ ├── observability/ # Monitoring setup scripts
│ ├── setup/ # Initial setup scripts
│ └── utils/ # Utility scripts
└── docs/ # Documentation
├── en/ # English documentation
└── vi/ # Vietnamese documentation
apps/ # Frontend applications
app-admin/ # Admin dashboard application
app-client/ # Client mobile application (Flutter)
web-client/ # Next.js web application
web-docs/ # Documentation website (Next.js)
services/ # Backend microservices
iam-service/ # Authentication & Authorization service
_template/ # Template for new services
packages/ # Shared libraries
auth-sdk/ # Authentication SDK
config/ # Shared configuration utilities
http-client/ # Internal HTTP client
logger/ # Structured logging (@goodgo/logger)
tracing/ # OpenTelemetry tracing
types/ # Shared TypeScript types
infra/ # Infrastructure configuration
databases/ # Database setup scripts
docker/ # Docker configurations
observability/ # Prometheus, Grafana, Loki configs
secrets/ # Secrets management templates
traefik/ # API Gateway configuration
deployments/ # Deployment configurations
local/ # Docker Compose for development
staging/ # Staging environment configs
production/ # Production Kubernetes manifests
scripts/ # Automation scripts
build/ # Build scripts
db/ # Database utilities
deploy/ # Deployment scripts
dev/ # Development helpers
observability/ # Monitoring setup scripts
setup/ # Initial setup scripts
utils/ # Utility scripts
docs/ # Documentation
en/ # English documentation
vi/ # Vietnamese documentation
```
## Installation & Setup
@@ -146,10 +146,10 @@ Each service and the local infrastructure needs environment variables. We provid
We use Neon (Serverless PostgreSQL) for all environments (Dev, Staging, Prod).
1. Create a project at [neon.tech](https://neon.tech).
2. Create a branch named `dev` (or use `main`).
3. Get the Connection String from the Neon dashboard.
4. Update `deployments/local/.env.local`:
1. Create a project at [neon.tech](https://neon.tech).
2. Create a branch named `dev` (or use `main`).
3. Get the Connection String from the Neon dashboard.
4. Update `deployments/local/.env.local`:
```env
DATABASE_URL="postgres://user:pass@ep-xyz.region.neon.tech/neondb"
@@ -194,20 +194,20 @@ pnpm --filter @goodgo/iam-service dev
### Creating a New Service
1. Copy the template:
```bash
cp -r services/_template services/my-new-service
```
2. Update `package.json` name.
3. Add logic in `src/modules/`.
4. Register in `deployments/local/docker-compose.yml`.
1. Copy the template:
```bash
cp -r services/_template services/my-new-service
```
2. Update `package.json` name.
3. Add logic in `src/modules/`.
4. Register in `deployments/local/docker-compose.yml`.
### Making Changes
1. Create a new branch: `feature/my-feature`.
2. Implement changes.
3. Run tests: `pnpm test`.
4. Commit with conventional commits: `feat(iam): add login endpoint`.
1. Create a new branch: `feature/my-feature`.
2. Implement changes.
3. Run tests: `pnpm test`.
4. Commit with conventional commits: `feat(iam): add login endpoint`.
## Common Commands
@@ -239,21 +239,21 @@ kill -9 <PID>
**Error**: `P1001: Can't reach database server`
**Solution**:
1. Check your internet connection (Neon is cloud-based).
2. Verify `DATABASE_URL` in `deployments/local/.env.local`.
3. Ensure your IP is allowed in Neon dashboard settings.
1. Check your internet connection (Neon is cloud-based).
2. Verify `DATABASE_URL` in `deployments/local/.env.local`.
3. Ensure your IP is allowed in Neon dashboard settings.
### Service Not Found in Gateway
**Error**: `404 Not Found` from api.localhost
**Solution**:
1. Check if service is running.
2. Check Traefik dashboard at http://localhost:8080.
3. Verify `PathPrefix` labels in `docker-compose.yml`.
1. Check if service is running.
2. Check Traefik dashboard at http://localhost:8080.
3. Verify `PathPrefix` labels in `docker-compose.yml`.
## Next Steps
* [Development Guide](development.md) - Deep dive into coding standards
* [API Documentation](../api/openapi/) - Explore the APIs
* [Architecture](../architecture/system-design.md) - Understand the system design
* [Development Guide](development.md) - Deep dive into coding standards
* [API Documentation](../api/openapi/) - Explore the APIs
* [Architecture](../architecture/system-design.md) - Understand the system design

View File

@@ -10,39 +10,39 @@ IAM Service is an extended version of Auth Service with additional features for
```mermaid
graph LR
Start([Start Migration]) --> Backup[📦 Backup]
Backup --> DBMigrate[🗄️ Database Migration]
DBMigrate --> UpdateDeps[📚 Update Dependencies]
UpdateDeps --> Deploy[🚀 Deploy]
Deploy --> Verify[ Verify]
Verify --> Decision{All Tests Pass?}
Decision -->|Yes| Rollout[📊 Gradual Rollout]
Decision -->|No| Rollback[⏮ Rollback]
Rollback --> Debug[🔍 Debug Issues]
Debug --> DBMigrate
Rollout --> Monitor[📈 Monitor]
Monitor --> Complete([ Complete])
style Start fill:#2d4263,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style Backup fill:#191e29,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style DBMigrate fill:#191e29,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style UpdateDeps fill:#191e29,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style Deploy fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Verify fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Decision fill:#4a5568,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style Rollout fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
style Rollback fill:#742a2a,stroke:#f56565,stroke-width:2px,color:#f5f5f5
style Debug fill:#742a2a,stroke:#f56565,stroke-width:2px,color:#f5f5f5
style Monitor fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Complete fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
Start([Start Migration]) --> Backup[ Backup]
Backup --> DBMigrate[ Database Migration]
DBMigrate --> UpdateDeps[ Update Dependencies]
UpdateDeps --> Deploy[ Deploy]
Deploy --> Verify[ Verify]
Verify --> Decision{All Tests Pass?}
Decision -->|Yes| Rollout[ Gradual Rollout]
Decision -->|No| Rollback[⏮ Rollback]
Rollback --> Debug[ Debug Issues]
Debug --> DBMigrate
Rollout --> Monitor[ Monitor]
Monitor --> Complete([ Complete])
style Start fill:#2d4263,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style Backup fill:#191e29,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style DBMigrate fill:#191e29,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style UpdateDeps fill:#191e29,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style Deploy fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Verify fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Decision fill:#4a5568,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style Rollout fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
style Rollback fill:#742a2a,stroke:#f56565,stroke-width:2px,color:#f5f5f5
style Debug fill:#742a2a,stroke:#f56565,stroke-width:2px,color:#f5f5f5
style Monitor fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Complete fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
```
## Backward Compatibility
**All existing endpoints continue to work normally:**
**All existing endpoints continue to work normally:**
- `/api/v1/auth/*` - Authentication endpoints
- `/api/v1/rbac/*` - RBAC endpoints
- `/api/v1/rbac/*` - RBAC endpoints
- `/api/v1/mfa/*` - MFA endpoints
- `/api/v1/sessions/*` - Session management endpoints
- `/api/v1/oidc/*` - OIDC endpoints
@@ -53,45 +53,45 @@ No breaking changes. Existing clients can continue using these endpoints without
```mermaid
graph TB
subgraph "Auth Service (Old)"
A1[Authentication]
A2[RBAC]
A3[MFA]
A4[Sessions]
A5[OIDC]
end
subgraph "IAM Service (New)"
B1[Authentication]
B2[RBAC]
B3[MFA]
B4[Sessions]
B5[OIDC]
B6[Identity Management]
B7[Access Management]
B8[Governance]
end
A1 -.->|Unchanged| B1
A2 -.->|Unchanged| B2
A3 -.->|Unchanged| B3
A4 -.->|Unchanged| B4
A5 -.->|Unchanged| B5
style A1 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style A2 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style A3 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style A4 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style A5 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B1 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B2 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B3 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B4 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B5 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B6 fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
style B7 fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
style B8 fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
subgraph "Auth Service (Old)"
A1[Authentication]
A2[RBAC]
A3[MFA]
A4[Sessions]
A5[OIDC]
end
subgraph "IAM Service (New)"
B1[Authentication]
B2[RBAC]
B3[MFA]
B4[Sessions]
B5[OIDC]
B6[Identity Management]
B7[Access Management]
B8[Governance]
end
A1 -.->|Unchanged| B1
A2 -.->|Unchanged| B2
A3 -.->|Unchanged| B3
A4 -.->|Unchanged| B4
A5 -.->|Unchanged| B5
style A1 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style A2 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style A3 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style A4 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style A5 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B1 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B2 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B3 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B4 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B5 fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style B6 fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
style B7 fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
style B8 fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
```
## Changes
@@ -129,43 +129,43 @@ Database schema is extended with new models but **does not delete or modify** ex
```mermaid
erDiagram
User ||--o{ UserProfile : has
User ||--o{ AccessRequest : creates
User }o--|| Organization : "belongs to"
User ||--o{ GroupMember : "member of"
Organization ||--o{ Group : contains
Group ||--o{ GroupMember : has
Group ||--o{ GroupPermission : has
AccessRequest ||--|| AccessReview : "reviewed by"
Organization ||--o{ ComplianceReport : generates
User {
string id PK
string email
string organizationId FK
}
Organization {
string id PK
string name
}
Group {
string id PK
string organizationId FK
}
UserProfile {
string userId FK
json metadata
}
AccessRequest {
string id PK
string userId FK
}
User ||--o{ UserProfile : has
User ||--o{ AccessRequest : creates
User }o--|| Organization : "belongs to"
User ||--o{ GroupMember : "member of"
Organization ||--o{ Group : contains
Group ||--o{ GroupMember : has
Group ||--o{ GroupPermission : has
AccessRequest ||--|| AccessReview : "reviewed by"
Organization ||--o{ ComplianceReport : generates
User {
string id PK
string email
string organizationId FK
}
Organization {
string id PK
string name
}
Group {
string id PK
string organizationId FK
}
UserProfile {
string userId FK
json metadata
}
AccessRequest {
string id PK
string userId FK
}
```
### 4. New API Endpoints
@@ -229,7 +229,7 @@ pnpm prisma generate
pnpm prisma migrate dev --name add_iam_models
# Verify migration
pnpm prisma studio # Check database structure
pnpm prisma studio # Check database structure
```
### Step 3: Update Dependencies
@@ -264,7 +264,7 @@ Test that all old endpoints still work:
# Test auth endpoints
curl http://localhost/api/v1/auth/me
# Test RBAC endpoints
# Test RBAC endpoints
curl http://localhost/api/v1/rbac/permissions
# Test MFA endpoints
@@ -274,55 +274,55 @@ curl http://localhost/api/v1/mfa/devices
### Step 6: Gradual Rollout
1. **Dual Deployment** (Optional):
- Deploy both `auth-service` and `iam-service` simultaneously
- Gradually route traffic to `iam-service`
- Monitor errors and performance
- Deploy both `auth-service` and `iam-service` simultaneously
- Gradually route traffic to `iam-service`
- Monitor errors and performance
2. **Update Clients**:
- Update clients to use new endpoints if needed
- Clients don't need updates if only using old endpoints
- Update clients to use new endpoints if needed
- Clients don't need updates if only using old endpoints
3. **Deprecate Old Service**:
- After verifying everything works well, deprecate `auth-service`
- Ensure all clients have migrated to `iam-service`
- After verifying everything works well, deprecate `auth-service`
- Ensure all clients have migrated to `iam-service`
## Deployment Strategy
```mermaid
graph TB
Current[Current: auth-service] --> Phase1[Phase 1: Dual Deploy]
Phase1 --> Split{Traffic Split}
Split -->|10%| IAM1[iam-service]
Split -->|90%| Auth1[auth-service]
Split --> Phase2[Phase 2: Increase]
Phase2 --> Split2{Traffic Split}
Split2 -->|50%| IAM2[iam-service]
Split2 -->|50%| Auth2[auth-service]
Split2 --> Phase3[Phase 3: Majority]
Phase3 --> Split3{Traffic Split}
Split3 -->|90%| IAM3[iam-service]
Split3 -->|10%| Auth3[auth-service]
Split3 --> Phase4[Phase 4: Complete]
Phase4 --> Final[iam-service only]
style Current fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style Phase1 fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Phase2 fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Phase3 fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Phase4 fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Final fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
style Split fill:#4a5568,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style Split2 fill:#4a5568,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style Split3 fill:#4a5568,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style IAM1 fill:#1a472a,stroke:#48bb78,stroke-width:1px,color:#f5f5f5
style IAM2 fill:#1a472a,stroke:#48bb78,stroke-width:1px,color:#f5f5f5
style IAM3 fill:#1a472a,stroke:#48bb78,stroke-width:1px,color:#f5f5f5
style Auth1 fill:#742a2a,stroke:#f56565,stroke-width:1px,color:#f5f5f5
style Auth2 fill:#742a2a,stroke:#f56565,stroke-width:1px,color:#f5f5f5
style Auth3 fill:#742a2a,stroke:#f56565,stroke-width:1px,color:#f5f5f5
Current[Current: auth-service] --> Phase1[Phase 1: Dual Deploy]
Phase1 --> Split{Traffic Split}
Split -->|10%| IAM1[iam-service]
Split -->|90%| Auth1[auth-service]
Split --> Phase2[Phase 2: Increase]
Phase2 --> Split2{Traffic Split}
Split2 -->|50%| IAM2[iam-service]
Split2 -->|50%| Auth2[auth-service]
Split2 --> Phase3[Phase 3: Majority]
Phase3 --> Split3{Traffic Split}
Split3 -->|90%| IAM3[iam-service]
Split3 -->|10%| Auth3[auth-service]
Split3 --> Phase4[Phase 4: Complete]
Phase4 --> Final[iam-service only]
style Current fill:#2d4263,stroke:#76b6c4,stroke-width:2px,color:#f5f5f5
style Phase1 fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Phase2 fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Phase3 fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Phase4 fill:#2d4263,stroke:#87a2a7,stroke-width:2px,color:#f5f5f5
style Final fill:#1a472a,stroke:#48bb78,stroke-width:2px,color:#f5f5f5
style Split fill:#4a5568,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style Split2 fill:#4a5568,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style Split3 fill:#4a5568,stroke:#c69b7b,stroke-width:2px,color:#f5f5f5
style IAM1 fill:#1a472a,stroke:#48bb78,stroke-width:1px,color:#f5f5f5
style IAM2 fill:#1a472a,stroke:#48bb78,stroke-width:1px,color:#f5f5f5
style IAM3 fill:#1a472a,stroke:#48bb78,stroke-width:1px,color:#f5f5f5
style Auth1 fill:#742a2a,stroke:#f56565,stroke-width:1px,color:#f5f5f5
style Auth2 fill:#742a2a,stroke:#f56565,stroke-width:1px,color:#f5f5f5
style Auth3 fill:#742a2a,stroke:#f56565,stroke-width:1px,color:#f5f5f5
```
## Rollback Plan
@@ -330,21 +330,21 @@ graph TB
If rollback is needed:
1. **Database Rollback**:
```bash
# Revert Prisma migration
cd services/iam-service
pnpm prisma migrate resolve --rolled-back <migration_name>
# Or restore from backup
psql $DATABASE_URL < auth-service-backup.sql
```
```bash
# Revert Prisma migration
cd services/iam-service
pnpm prisma migrate resolve --rolled-back <migration_name>
# Or restore from backup
psql $DATABASE_URL < auth-service-backup.sql
```
2. **Service Rollback**:
```bash
# Switch back to auth-service in docker-compose
# Or revert Kubernetes deployment
kubectl rollout undo deployment/auth-service
```
```bash
# Switch back to auth-service in docker-compose
# Or revert Kubernetes deployment
kubectl rollout undo deployment/auth-service
```
## Breaking Changes
@@ -367,25 +367,25 @@ If you encounter issues during migration:
## Quick Tips
**Migration Checklist:**
- Backup database and code
- Run database migrations
- Update deployment configuration
- Test backward compatibility
- Monitor gradual rollout
- Prepare rollback plan
- Backup database and code
- Run database migrations
- Update deployment configuration
- Test backward compatibility
- Monitor gradual rollout
- Prepare rollback plan
### Common Issues & Solutions
| Issue | Cause | Solution |
|-------|-------|----------|
| 🔴 Migration failed | Database connection | Check `DATABASE_URL` in `.env` |
| 🔴 Service won't start | Missing env vars | Verify all env vars are set |
| 🟡 Slow performance | Database indexes | Run Prisma migrations completely |
| 🟡 Connection timeout | Network issues | Check firewall & security groups |
| 🔵 New endpoints 404 | Routing config | Update Traefik/Ingress config |
| Migration failed | Database connection | Check `DATABASE_URL` in `.env` |
| Service won't start | Missing env vars | Verify all env vars are set |
| Slow performance | Database indexes | Run Prisma migrations completely |
| Connection timeout | Network issues | Check firewall & security groups |
| New endpoints 404 | Routing config | Update Traefik/Ingress config |
**Visual Indicators:**
- 🔵 Old Components (Unchanged)
- 🟢 New Components (Added)
- 🔴 Components to Deprecate
- ⚠️ Requires Attention
- Old Components (Unchanged)
- New Components (Added)
- Components to Deprecate
- Requires Attention

View File

@@ -10,39 +10,39 @@
```mermaid
graph TD
Start([🚀 Start]) --> EnvPrep[1⃣ Environment Prep<br/>Enable K8s in Docker Desktop]
EnvPrep --> BuildImg[2⃣ Build Docker Image<br/>docker build -t service:local]
BuildImg --> LoadImg[3⃣ Load Image to Cluster<br/>kind load docker-image]
LoadImg --> Secrets[4⃣ Configure Secrets<br/>kubectl create secret]
Secrets --> Deploy[5⃣ Deploy Service<br/>kubectl apply -f manifests]
Deploy --> Verify[6⃣ Verify Deployment<br/>kubectl get pods]
Verify --> Test[7⃣ Test Service<br/>Port Forward & Curl]
Test --> End([ Complete])
Start([ Start]) --> EnvPrep[1⃣ Environment Prep<br/>Enable K8s in Docker Desktop]
EnvPrep --> BuildImg[2⃣ Build Docker Image<br/>docker build -t service:local]
BuildImg --> LoadImg[3⃣ Load Image to Cluster<br/>kind load docker-image]
LoadImg --> Secrets[4⃣ Configure Secrets<br/>kubectl create secret]
Secrets --> Deploy[5⃣ Deploy Service<br/>kubectl apply -f manifests]
Deploy --> Verify[6⃣ Verify Deployment<br/>kubectl get pods]
Verify --> Test[7⃣ Test Service<br/>Port Forward & Curl]
Test --> End([ Complete])
subgraph Deployment["📦 Deployment Resources"]
Deploy --> |Apply| ConfigMap[ConfigMap<br/>Environment Config]
Deploy --> |Apply| K8sDeployment[Deployment<br/>Pod Template]
Deploy --> |Apply| Service[Service<br/>LoadBalancer/NodePort]
end
%% Start/End nodes - Success Green
style Start fill:#004d40,stroke:#00bfa5,stroke-width:3px,color:#e0f2f1
style End fill:#1b5e20,stroke:#66bb6a,stroke-width:3px,color:#e8f5e9
%% Workflow steps - Dark theme with distinct colors
style EnvPrep fill:#263238,stroke:#546e7a,stroke-width:2px,color:#eceff1
style BuildImg fill:#3e2723,stroke:#8d6e63,stroke-width:2px,color:#efebe9
style LoadImg fill:#1a237e,stroke:#5c6bc0,stroke-width:2px,color:#e8eaf6
style Secrets fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#ffebee
style Deploy fill:#004d40,stroke:#26a69a,stroke-width:2px,color:#e0f2f1
style Verify fill:#1565c0,stroke:#42a5f5,stroke-width:2px,color:#e3f2fd
style Test fill:#4a148c,stroke:#ab47bc,stroke-width:2px,color:#f3e5f5
%% Deployment resources subgraph
style Deployment fill:#1a1a1a,stroke:#424242,stroke-width:2px,color:#e0e0e0
style ConfigMap fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
style K8sDeployment fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
style Service fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
subgraph Deployment[" Deployment Resources"]
Deploy --> |Apply| ConfigMap[ConfigMap<br/>Environment Config]
Deploy --> |Apply| K8sDeployment[Deployment<br/>Pod Template]
Deploy --> |Apply| Service[Service<br/>LoadBalancer/NodePort]
end
%% Start/End nodes - Success Green
style Start fill:#004d40,stroke:#00bfa5,stroke-width:3px,color:#e0f2f1
style End fill:#1b5e20,stroke:#66bb6a,stroke-width:3px,color:#e8f5e9
%% Workflow steps - Dark theme with distinct colors
style EnvPrep fill:#263238,stroke:#546e7a,stroke-width:2px,color:#eceff1
style BuildImg fill:#3e2723,stroke:#8d6e63,stroke-width:2px,color:#efebe9
style LoadImg fill:#1a237e,stroke:#5c6bc0,stroke-width:2px,color:#e8eaf6
style Secrets fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#ffebee
style Deploy fill:#004d40,stroke:#26a69a,stroke-width:2px,color:#e0f2f1
style Verify fill:#1565c0,stroke:#42a5f5,stroke-width:2px,color:#e3f2fd
style Test fill:#4a148c,stroke:#ab47bc,stroke-width:2px,color:#f3e5f5
%% Deployment resources subgraph
style Deployment fill:#1a1a1a,stroke:#424242,stroke-width:2px,color:#e0e0e0
style ConfigMap fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
style K8sDeployment fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
style Service fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
```
## Overview
@@ -55,19 +55,19 @@ This guide details how to deploy the IAM Service (or any microservice in the Goo
### Software
- **Docker Desktop 4.0+**: [Download Link](https://www.docker.com/products/docker-desktop/)
- Kubernetes must be enabled in settings.
- Kubernetes must be enabled in settings.
- **kubectl CLI**: Command-line tool for interacting with K8s.
```bash
brew install kubectl
```
```bash
brew install kubectl
```
- **kind CLI**: Required to load images into the cluster if using Kind backend explicitely.
```bash
brew install kind
```
```bash
brew install kind
```
- **pnpm 8+**: Project package manager.
```bash
npm install -g pnpm
```
```bash
npm install -g pnpm
```
### Knowledge
- Basic understanding of Kubernetes concepts: **Pod**, **Deployment**, **Service**, **Secret**, **ConfigMap**.
@@ -79,7 +79,7 @@ This guide details how to deploy the IAM Service (or any microservice in the Goo
### 2.1 Enable Kubernetes in Docker Desktop
1. Open **Docker Desktop**.
2. Click the **Settings (⚙️)** icon.
2. Click the **Settings ()** icon.
3. Select the **Kubernetes** tab.
4. Check **Enable Kubernetes**.
5. Select **Show system containers (advanced)** for easier debugging (optional).
@@ -98,8 +98,8 @@ kubectl config current-context
# List all nodes in the cluster
kubectl get nodes
# Expected Output:
# NAME STATUS ROLES AGE VERSION
# docker-desktop Ready control-plane 10m v1.29.1
# NAME STATUS ROLES AGE VERSION
# docker-desktop Ready control-plane 10m v1.29.1
```
## 3. Build Docker Image
@@ -117,12 +117,12 @@ docker build -t iam-service:local -f ../../../services/iam-service/Dockerfile ..
# Verify the image was built successfully
docker images | grep iam-service
# Expected Output:
# iam-service local [IMAGE_ID] [SIZE] [CREATED]
# iam-service local [IMAGE_ID] [SIZE] [CREATED]
```
## 4. Load Image into Cluster
**⚠️ IMPORTANT**: Docker Desktop can use different backends. If you are running Kubernetes inside Docker Desktop, sometimes it doesn't immediately see local images if using a `kind` node underneath.
** IMPORTANT**: Docker Desktop can use different backends. If you are running Kubernetes inside Docker Desktop, sometimes it doesn't immediately see local images if using a `kind` node underneath.
If you are using **Kind** (Kubernetes in Docker) separately or a specific Docker Desktop config, you need to load the image:
@@ -149,11 +149,11 @@ kubectl create namespace iam-local
# Generate random secrets and store in Kubernetes
kubectl create secret generic iam-service-secrets \
--from-literal=DATABASE_URL="postgresql://user:password@host.docker.internal:5432/iam_db?schema=public" \
--from-literal=JWT_SECRET="$(openssl rand -base64 32)" \
--from-literal=JWT_REFRESH_SECRET="$(openssl rand -base64 32)" \
--from-literal=ENCRYPTION_KEY="$(openssl rand -base64 32)" \
-n iam-local
--from-literal=DATABASE_URL="postgresql://user:password@host.docker.internal:5432/iam_db?schema=public" \
--from-literal=JWT_SECRET="$(openssl rand -base64 32)" \
--from-literal=JWT_REFRESH_SECRET="$(openssl rand -base64 32)" \
--from-literal=ENCRYPTION_KEY="$(openssl rand -base64 32)" \
-n iam-local
# Verify secrets creation
kubectl get secrets -n iam-local
@@ -193,8 +193,8 @@ After deployment, ensure the Pod is stable (Running).
kubectl get pods -n iam-local
# Expected Output:
# NAME READY STATUS RESTARTS AGE
# iam-service-68994fdc79-gh2mj 1/1 Running 0 30s
# NAME READY STATUS RESTARTS AGE
# iam-service-68994fdc79-gh2mj 1/1 Running 0 30s
```
### 7.2 View Detailed Logs
@@ -211,17 +211,17 @@ kubectl describe pod -n iam-local -l app=iam-service
### 7.3 Common Errors
1. **ImagePullBackOff**:
- **Reason**: K8s cannot find `iam-service:local` image.
- **Fix**: Ensure `imagePullPolicy: IfNotPresent` or `Never` in local deployment yaml. If using Kind, remember to run `kind load`.
1. **ImagePullBackOff**:
- **Reason**: K8s cannot find `iam-service:local` image.
- **Fix**: Ensure `imagePullPolicy: IfNotPresent` or `Never` in local deployment yaml. If using Kind, remember to run `kind load`.
2. **CrashLoopBackOff**:
- **Reason**: Runtime error, usually unable to connect to Database.
- **Fix**: Check `DATABASE_URL` in Secret. Ensure Postgres is running and accessible from K8s (use `host.docker.internal`).
2. **CrashLoopBackOff**:
- **Reason**: Runtime error, usually unable to connect to Database.
- **Fix**: Check `DATABASE_URL` in Secret. Ensure Postgres is running and accessible from K8s (use `host.docker.internal`).
3. **Pending Service**:
- **Reason**: `LoadBalancer` type on local sometimes hangs pending IP.
- **Fix**: Not a problem, we can use `port-forward` or access via `localhost`.
3. **Pending Service**:
- **Reason**: `LoadBalancer` type on local sometimes hangs pending IP.
- **Fix**: Not a problem, we can use `port-forward` or access via `localhost`.
## 8. Test Service Access
@@ -254,55 +254,55 @@ When done, delete resources to free up capacity.
kubectl delete namespace iam-local
```
## 📚 Quick Tips
## Quick Tips
### Common Issues & Solutions
| Issue | Symptoms | Solution |
|-------|----------|----------|
| 🔴 **ImagePullBackOff** | Pod stuck in `ImagePullBackOff` | Set `imagePullPolicy: Never` in deployment YAML<br/>Run `kind load docker-image` if using Kind |
| 🔴 **CrashLoopBackOff** | Pod keeps restarting | Check logs with `kubectl logs`<br/>Verify `DATABASE_URL` in secrets<br/>Ensure DB is accessible via `host.docker.internal` |
| 🟡 **Pending LoadBalancer** | Service External-IP shows `<pending>` | Normal on local—use `kubectl port-forward` instead |
| 🟡 **Connection Refused** | Can't connect after port-forward | Check pod is `Running` (not `CrashLoopBackOff`)<br/>Verify correct port mapping |
| **ImagePullBackOff** | Pod stuck in `ImagePullBackOff` | Set `imagePullPolicy: Never` in deployment YAML<br/>Run `kind load docker-image` if using Kind |
| **CrashLoopBackOff** | Pod keeps restarting | Check logs with `kubectl logs`<br/>Verify `DATABASE_URL` in secrets<br/>Ensure DB is accessible via `host.docker.internal` |
| **Pending LoadBalancer** | Service External-IP shows `<pending>` | Normal on local—use `kubectl port-forward` instead |
| **Connection Refused** | Can't connect after port-forward | Check pod is `Running` (not `CrashLoopBackOff`)<br/>Verify correct port mapping |
### Essential Commands Reference
```bash
# 🔍 Debugging
kubectl get pods -n iam-local -w # Watch pods in real-time
kubectl describe pod <POD_NAME> -n iam-local # Detailed pod info + events
kubectl logs -f <POD_NAME> -n iam-local # Stream logs
kubectl exec -it <POD_NAME> -n iam-local -- /bin/sh # Shell into container
# Debugging
kubectl get pods -n iam-local -w # Watch pods in real-time
kubectl describe pod <POD_NAME> -n iam-local # Detailed pod info + events
kubectl logs -f <POD_NAME> -n iam-local # Stream logs
kubectl exec -it <POD_NAME> -n iam-local -- /bin/sh # Shell into container
# 🔄 Image Management
docker build -t service:local -f Dockerfile . # Build image
kind load docker-image service:local --name desktop # Load to Kind cluster
docker images | grep service # List local images
# Image Management
docker build -t service:local -f Dockerfile . # Build image
kind load docker-image service:local --name desktop # Load to Kind cluster
docker images | grep service # List local images
# 🚀 Quick Deployment
kubectl apply -f deployment.yaml -n iam-local # Deploy single manifest
kubectl apply -f . -n iam-local # Deploy all files in directory
kubectl rollout restart deployment/iam-service -n iam-local # Force pod restart
# Quick Deployment
kubectl apply -f deployment.yaml -n iam-local # Deploy single manifest
kubectl apply -f . -n iam-local # Deploy all files in directory
kubectl rollout restart deployment/iam-service -n iam-local # Force pod restart
# 🧹 Cleanup
kubectl delete pod <POD_NAME> -n iam-local --force # Force delete stuck pod
kubectl delete namespace iam-local --force --grace-period=0 # Force delete namespace
# Cleanup
kubectl delete pod <POD_NAME> -n iam-local --force # Force delete stuck pod
kubectl delete namespace iam-local --force --grace-period=0 # Force delete namespace
```
### Visual Status Indicators
- 🟢 **Running** - Service is healthy
- 🟡 **Pending** - Waiting for resources
- 🔴 **CrashLoopBackOff** - Service keeps failing (check logs!)
- 🔵 **ContainerCreating** - Pod starting up
- **Terminating** - Pod shutting down
- **Running** - Service is healthy
- **Pending** - Waiting for resources
- **CrashLoopBackOff** - Service keeps failing (check logs!)
- **ContainerCreating** - Pod starting up
- **Terminating** - Pod shutting down
### Pro Tips
1. ** Fast Rebuild**: For quick iteration, use `kubectl rollout restart deployment/iam-service -n iam-local` after rebuilding image
2. **🔍 Watch Mode**: Use `-w` flag to watch resources update in real-time
3. **📝 YAML Validation**: Run `kubectl apply --dry-run=client -f file.yaml` to validate before applying
4. **🎯 Label Filtering**: Use `-l app=iam-service` to filter resources by label instead of typing pod names
1. ** Fast Rebuild**: For quick iteration, use `kubectl rollout restart deployment/iam-service -n iam-local` after rebuilding image
2. ** Watch Mode**: Use `-w` flag to watch resources update in real-time
3. ** YAML Validation**: Run `kubectl apply --dry-run=client -f file.yaml` to validate before applying
4. ** Label Filtering**: Use `-l app=iam-service` to filter resources by label instead of typing pod names
## References

View File

@@ -39,8 +39,8 @@ docker-compose logs -f
### Backend Services
- **iam-service** (Port 5001): Authentication and user management
- Routes: `/api/v1/auth`, `/api/v1/users`
- Health: http://localhost/api/v1/auth/health
- Routes: `/api/v1/auth`, `/api/v1/users`
- Health: http://localhost/api/v1/auth/health
### Frontend Applications
@@ -117,33 +117,33 @@ docker-compose exec iam-service sh
```yaml
services:
my-new-service:
build:
context: ../..
dockerfile: services/my-new-service/Dockerfile
container_name: my-new-service-local
env_file:
- .env.local
environment:
- PORT=5002
- SERVICE_NAME=my-new-service
- DATABASE_URL=${DATABASE_URL}
- REDIS_HOST=${REDIS_HOST}
- JWT_SECRET=${JWT_SECRET}
ports:
- "5002:5002"
depends_on:
redis:
condition: service_healthy
traefik:
condition: service_started
networks:
- microservices-network
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.my-new-service.rule=PathPrefix(`/api/v1/my-new-service`)"
- "traefik.http.services.my-new-service.loadbalancer.server.port=5002"
my-new-service:
build:
context: ../..
dockerfile: services/my-new-service/Dockerfile
container_name: my-new-service-local
env_file:
- .env.local
environment:
- PORT=5002
- SERVICE_NAME=my-new-service
- DATABASE_URL=${DATABASE_URL}
- REDIS_HOST=${REDIS_HOST}
- JWT_SECRET=${JWT_SECRET}
ports:
- "5002:5002"
depends_on:
redis:
condition: service_healthy
traefik:
condition: service_started
networks:
- microservices-network
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.my-new-service.rule=PathPrefix(`/api/v1/my-new-service`)"
- "traefik.http.services.my-new-service.loadbalancer.server.port=5002"
```
2. **Start the service**:
@@ -153,8 +153,8 @@ docker-compose up -d my-new-service
```
3. **Access the service**:
- Via Traefik: http://localhost/api/v1/my-new-service
- Direct: http://localhost:5002
- Via Traefik: http://localhost/api/v1/my-new-service
- Direct: http://localhost:5002
## Traefik Configuration
@@ -229,40 +229,40 @@ docker-compose logs traefik
```mermaid
graph TB
Client[👤 Client<br/>Browser] --> Traefik
Traefik[🌐 Traefik<br/>API Gateway<br/>:80, :8080]
Traefik --> IAM[🔐 IAM Service<br/>Authentication<br/>:5001]
Traefik --> Admin[⚙️ Web Admin<br/>Dashboard<br/>:3000]
Traefik --> WebClient[🌍 Web Client<br/>Application<br/>:3001]
IAM --> Redis[(💾 Redis<br/>Cache<br/>:6379)]
IAM --> DB[(🗄️ PostgreSQL<br/>Neon Database)]
classDef client fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#eee
classDef gateway fill:#0f3460,stroke:#16213e,stroke-width:3px,color:#eee
classDef service fill:#16213e,stroke:#533483,stroke-width:2px,color:#eee
classDef frontend fill:#1a1a40,stroke:#6c5ce7,stroke-width:2px,color:#eee
classDef data fill:#2d132c,stroke:#801336,stroke-width:2px,color:#eee
class Client client
class Traefik gateway
class IAM service
class Admin,WebClient frontend
class Redis,DB data
Client[ Client<br/>Browser] --> Traefik
Traefik[ Traefik<br/>API Gateway<br/>:80, :8080]
Traefik --> IAM[ IAM Service<br/>Authentication<br/>:5001]
Traefik --> Admin[ Web Admin<br/>Dashboard<br/>:3000]
Traefik --> WebClient[ Web Client<br/>Application<br/>:3001]
IAM --> Redis[( Redis<br/>Cache<br/>:6379)]
IAM --> DB[( PostgreSQL<br/>Neon Database)]
classDef client fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#eee
classDef gateway fill:#0f3460,stroke:#16213e,stroke-width:3px,color:#eee
classDef service fill:#16213e,stroke:#533483,stroke-width:2px,color:#eee
classDef frontend fill:#1a1a40,stroke:#6c5ce7,stroke-width:2px,color:#eee
classDef data fill:#2d132c,stroke:#801336,stroke-width:2px,color:#eee
class Client client
class Traefik gateway
class IAM service
class Admin,WebClient frontend
class Redis,DB data
```
**Legend:**
- 👤 **Client**: External users via browser
- 🌐 **Gateway**: Traefik API Gateway (auto-routing)
- 🔐 **Backend**: IAM Service (authentication)
- ⚙️ **Frontend**: Web Admin & Client applications
- 💾 **Storage**: Redis cache & PostgreSQL database
- **Client**: External users via browser
- **Gateway**: Traefik API Gateway (auto-routing)
- **Backend**: IAM Service (authentication)
- **Frontend**: Web Admin & Client applications
- **Storage**: Redis cache & PostgreSQL database
## Quick Tips
### 🚨 Common Issues
### Common Issues
| Problem | Solution |
|---------|----------|
@@ -272,7 +272,7 @@ graph TB
| **Redis connection** | Ensure Redis is healthy: `docker-compose exec redis redis-cli ping` |
| **Traefik routing** | Check dashboard at http://localhost:8080 for route status |
### 🎯 Development Workflow
### Development Workflow
```bash
# Quick restart (code changes)
@@ -285,14 +285,14 @@ docker-compose up -d --build iam-service
docker-compose down -v && docker-compose up -d
```
### 🔐 Security Checklist
### Security Checklist
- Change default `JWT_SECRET` (min 32 characters)
- Use environment-specific `.env.local` (never commit)
- Verify CORS origins match your frontend URLs
- Enable HTTPS in production (not needed for local)
- Change default `JWT_SECRET` (min 32 characters)
- Use environment-specific `.env.local` (never commit)
- Verify CORS origins match your frontend URLs
- Enable HTTPS in production (not needed for local)
### 📊 Monitoring
### Monitoring
- **Traefik Dashboard**: http://localhost:8080 - View all routes and services
- **Service Health**: http://localhost/api/v1/auth/health - Check service status

View File

@@ -12,33 +12,33 @@
```mermaid
graph TD
Start([Start]) --> Prerequisites[1. System Prerequisites]
Prerequisites --> Clone["2. Clone and Install"]
Clone --> Env["3. Configure Environment - Shared and Service-Specific"]
Env --> DB["4. Setup Database - Migrate and Seed"]
DB --> Run["5. Run Project - Native/Docker/Hybrid"]
Run --> Dev["6. Development Loop - Watch Mode"]
Dev --> Test["7. Testing and Verify"]
Test --> End([Complete])
Start([Start]) --> Prerequisites[1. System Prerequisites]
Prerequisites --> Clone["2. Clone and Install"]
Clone --> Env["3. Configure Environment - Shared and Service-Specific"]
Env --> DB["4. Setup Database - Migrate and Seed"]
DB --> Run["5. Run Project - Native/Docker/Hybrid"]
Run --> Dev["6. Development Loop - Watch Mode"]
Dev --> Test["7. Testing and Verify"]
Test --> End([Complete])
subgraph "Run Modes"
Run --> Mode1[Mode 1: Native - Fastest]
Run --> Mode2[Mode 2: Hybrid - Flexible]
Run --> Mode3[Mode 3: Full Docker - Production-like]
end
subgraph "Run Modes"
Run --> Mode1[Mode 1: Native - Fastest]
Run --> Mode2[Mode 2: Hybrid - Flexible]
Run --> Mode3[Mode 3: Full Docker - Production-like]
end
style Start fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style End fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style Prerequisites fill:#7F8C8D,color:#fff
style Clone fill:#7F8C8D,color:#fff
style Env fill:#E67E22,color:#fff
style DB fill:#E67E22,color:#fff
style Run fill:#2980B9,color:#fff
style Dev fill:#2980B9,color:#fff
style Test fill:#3498DB,color:#fff
style Mode1 fill:#8E44AD,color:#fff
style Mode2 fill:#8E44AD,color:#fff
style Mode3 fill:#8E44AD,color:#fff
style Start fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style End fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style Prerequisites fill:#7F8C8D,color:#fff
style Clone fill:#7F8C8D,color:#fff
style Env fill:#E67E22,color:#fff
style DB fill:#E67E22,color:#fff
style Run fill:#2980B9,color:#fff
style Dev fill:#2980B9,color:#fff
style Test fill:#3498DB,color:#fff
style Mode1 fill:#8E44AD,color:#fff
style Mode2 fill:#8E44AD,color:#fff
style Mode3 fill:#8E44AD,color:#fff
```
## Overview
@@ -148,21 +148,21 @@ You can run the project in 3 ways depending on your needs:
Run directly on the host machine. Fastest speed, fastest hot-reload.
1. **Start Infrastructure**:
```bash
# EN: Start Redis and Traefik in Docker background
# VI: Khởi động Redis và Traefik chạy ngầm bằng Docker
cd deployments/local
docker-compose up -d redis traefik
cd ../..
```
1. **Start Infrastructure**:
```bash
# EN: Start Redis and Traefik in Docker background
# VI: Khởi động Redis và Traefik chạy ngầm bằng Docker
cd deployments/local
docker-compose up -d redis traefik
cd ../..
```
2. **Run Service**:
```bash
# EN: Start iam-service in watch mode
# VI: Chạy iam-service ở chế độ watch
pnpm --filter @goodgo/iam-service dev
```
2. **Run Service**:
```bash
# EN: Start iam-service in watch mode
# VI: Chạy iam-service ở chế độ watch
pnpm --filter @goodgo/iam-service dev
```
### Mode 2: Hybrid Development (Flexible)

View File

@@ -8,13 +8,13 @@ This guide helps you choose the right Mermaid diagram type for your documentatio
| Diagram Type | Use For | Complexity |
|----------------------|------------------------|---------------------------|
| **Flowchart** | Workflows, decision trees | ⭐⭐ |
| **Sequence Diagram** | API interactions, request flows | ⭐⭐⭐ |
| **Class Diagram** | Code structure, patterns | ⭐⭐⭐ |
| **Graph** | System architecture, dependencies | ⭐⭐ |
| **ER Diagram** | Database schema | ⭐⭐⭐ |
| **Gantt** | Timeline, project schedule | ⭐⭐ |
| **C4 Diagram** | System context, containers | ⭐⭐⭐⭐ |
| **Flowchart** | Workflows, decision trees | |
| **Sequence Diagram** | API interactions, request flows | |
| **Class Diagram** | Code structure, patterns | |
| **Graph** | System architecture, dependencies | |
| **ER Diagram** | Database schema | |
| **Gantt** | Timeline, project schedule | |
| **C4 Diagram** | System context, containers | |
---
@@ -32,21 +32,21 @@ Use flowcharts for:
```mermaid
flowchart TD
Start([Start]) --> Input[Get Input]
Input --> Check{Valid?}
Check -->|Yes| Process[Process Data]
Check -->|No| Error[Show Error]
Process --> Output[Return Result]
Output --> End([End])
Error --> End
style Start fill:#2C3E50,stroke:#34495E,stroke-width:2px,color:#ECF0F1
style End fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style Check fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Error fill:#C0392B,stroke:#A93226,stroke-width:2px,color:#ECF0F1
style Process fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Input fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style Output fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
Start([Start]) --> Input[Get Input]
Input --> Check{Valid?}
Check -->|Yes| Process[Process Data]
Check -->|No| Error[Show Error]
Process --> Output[Return Result]
Output --> End([End])
Error --> End
style Start fill:#2C3E50,stroke:#34495E,stroke-width:2px,color:#ECF0F1
style End fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style Check fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Error fill:#C0392B,stroke:#A93226,stroke-width:2px,color:#ECF0F1
style Process fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Input fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style Output fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
```
**Explanation**: A basic flowchart starting with an input, followed by a validation check. If valid, it proceeds to processing and returns a result; otherwise, it shows an error and ends.
@@ -55,18 +55,18 @@ flowchart TD
````markdown
```mermaid
flowchart TD
Start([Start]) --> Input[Get Input]
Input --> Check{Valid?}
Check -->|Yes| Process[Process Data]
Check -->|No| Error[Show Error]
Process --> Output[Return Result]
Output --> End([End])
Error --> End
style Start fill:#2C3E50,stroke:#34495E,stroke-width:2px,color:#ECF0F1
style End fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style Check fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Error fill:#C0392B,stroke:#A93226,stroke-width:2px,color:#ECF0F1
Start([Start]) --> Input[Get Input]
Input --> Check{Valid?}
Check -->|Yes| Process[Process Data]
Check -->|No| Error[Show Error]
Process --> Output[Return Result]
Output --> End([End])
Error --> End
style Start fill:#2C3E50,stroke:#34495E,stroke-width:2px,color:#ECF0F1
style End fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style Check fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Error fill:#C0392B,stroke:#A93226,stroke-width:2px,color:#ECF0F1
```
````
@@ -74,30 +74,30 @@ flowchart TD
```mermaid
flowchart LR
A[Client Request] --> B{Auth?}
B -->|No| C[401 Unauthorized]
B -->|Yes| D[Process]
subgraph Processing["Request Processing"]
D --> E[Validate Input]
E --> F[Execute Logic]
F --> G[Format Response]
end
G --> H[Return 200 OK]
C --> I[End]
H --> I
style Processing fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style A fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style B fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style C fill:#C0392B,stroke:#A93226,stroke-width:2px,color:#ECF0F1
style D fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style E fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style F fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style G fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style H fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style I fill:#2C3E50,stroke:#34495E,stroke-width:2px,color:#ECF0F1
A[Client Request] --> B{Auth?}
B -->|No| C[401 Unauthorized]
B -->|Yes| D[Process]
subgraph Processing["Request Processing"]
D --> E[Validate Input]
E --> F[Execute Logic]
F --> G[Format Response]
end
G --> H[Return 200 OK]
C --> I[End]
H --> I
style Processing fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style A fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style B fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style C fill:#C0392B,stroke:#A93226,stroke-width:2px,color:#ECF0F1
style D fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style E fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style F fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style G fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style H fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style I fill:#2C3E50,stroke:#34495E,stroke-width:2px,color:#ECF0F1
```
**Explanation**: A flowchart featuring an authorization check and a dedicated **Subgraph** for detailed request processing steps.
@@ -118,18 +118,18 @@ Use sequence diagrams for:
```mermaid
sequenceDiagram
participant Client
participant API
participant Service
participant DB
Client->>API: POST /login
API->>Service: authenticate(credentials)
Service->>DB: findUser(email)
DB-->>Service: user
Service->>Service: verifyPassword()
Service-->>API: JWT token
API-->>Client: 200 OK {token}
participant Client
participant API
participant Service
participant DB
Client->>API: POST /login
API->>Service: authenticate(credentials)
Service->>DB: findUser(email)
DB-->>Service: user
Service->>Service: verifyPassword()
Service-->>API: JWT token
API-->>Client: 200 OK {token}
```
**Explanation**: A login sequence illustrating the interaction between the Client, API, Service Layer, and Database, including password verification.
@@ -138,18 +138,18 @@ sequenceDiagram
````markdown
```mermaid
sequenceDiagram
participant Client
participant API
participant Service
participant DB
Client->>API: POST /login
API->>Service: authenticate(credentials)
Service->>DB: findUser(email)
DB-->>Service: user
Service->>Service: verifyPassword()
Service-->>API: JWT token
API-->>Client: 200 OK {token}
participant Client
participant API
participant Service
participant DB
Client->>API: POST /login
API->>Service: authenticate(credentials)
Service->>DB: findUser(email)
DB-->>Service: user
Service->>Service: verifyPassword()
Service-->>API: JWT token
API-->>Client: 200 OK {token}
```
````
@@ -157,24 +157,24 @@ sequenceDiagram
```mermaid
sequenceDiagram
participant Client
participant API
participant Cache
participant DB
Client->>API: GET /users/:id
API->>Cache: get(key)
alt Cache Hit
Cache-->>API: cached data
API-->>Client: 200 OK (from cache)
else Cache Miss
Cache-->>API: null
API->>DB: SELECT * FROM users
DB-->>API: user data
API->>Cache: set(key, data, ttl)
API-->>Client: 200 OK (from DB)
end
participant Client
participant API
participant Cache
participant DB
Client->>API: GET /users/:id
API->>Cache: get(key)
alt Cache Hit
Cache-->>API: cached data
API-->>Client: 200 OK (from cache)
else Cache Miss
Cache-->>API: null
API->>DB: SELECT * FROM users
DB-->>API: user data
API->>Cache: set(key, data, ttl)
API-->>Client: 200 OK (from DB)
end
```
**Explanation**: A data retrieval sequence using **Alt/Else** blocks to handle both Cache Hit and Cache Miss scenarios.
@@ -195,28 +195,28 @@ Use class diagrams for:
```mermaid
classDiagram
class BaseRepository {
#prisma: PrismaClient
#modelName: string
+findById(id: string) T
+findAll(options: QueryOptions) T[]
+create(data: CreateDto) T
+update(id: string, data: UpdateDto) T
+delete(id: string) void
}
class UserRepository {
+findByEmail(email: string) User
+findByUsername(username: string) User
}
class FeatureRepository {
+findByName(name: string) Feature
+toggleStatus(id: string) Feature
}
BaseRepository <|-- UserRepository
BaseRepository <|-- FeatureRepository
class BaseRepository {
#prisma: PrismaClient
#modelName: string
+findById(id: string) T
+findAll(options: QueryOptions) T[]
+create(data: CreateDto) T
+update(id: string, data: UpdateDto) T
+delete(id: string) void
}
class UserRepository {
+findByEmail(email: string) User
+findByUsername(username: string) User
}
class FeatureRepository {
+findByName(name: string) Feature
+toggleStatus(id: string) Feature
}
BaseRepository <|-- UserRepository
BaseRepository <|-- FeatureRepository
```
**Explanation**: A class diagram showing inheritance relationships between a generic `BaseRepository` and specific repository implementations.
@@ -237,24 +237,24 @@ Use graph diagrams for:
```mermaid
graph TD
Client[Web Client] --> Gateway[Traefik Gateway]
Gateway --> Auth[Auth Service]
Gateway --> IAM[IAM Service]
Gateway --> User[User Service]
Auth --> DB[(PostgreSQL)]
IAM --> DB
User --> DB
User --> Cache[(Redis Cache)]
style Client fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style Gateway fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Auth fill:#8E44AD,stroke:#7D3C98,stroke-width:2px,color:#ECF0F1
style IAM fill:#8E44AD,stroke:#7D3C98,stroke-width:2px,color:#ECF0F1
style User fill:#8E44AD,stroke:#7D3C98,stroke-width:2px,color:#ECF0F1
style DB fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Cache fill:#E67E22,stroke:#CA6F1E,stroke-width:2px,color:#ECF0F1
Client[Web Client] --> Gateway[Traefik Gateway]
Gateway --> Auth[Auth Service]
Gateway --> IAM[IAM Service]
Gateway --> User[User Service]
Auth --> DB[(PostgreSQL)]
IAM --> DB
User --> DB
User --> Cache[(Redis Cache)]
style Client fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style Gateway fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Auth fill:#8E44AD,stroke:#7D3C98,stroke-width:2px,color:#ECF0F1
style IAM fill:#8E44AD,stroke:#7D3C98,stroke-width:2px,color:#ECF0F1
style User fill:#8E44AD,stroke:#7D3C98,stroke-width:2px,color:#ECF0F1
style DB fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Cache fill:#E67E22,stroke:#CA6F1E,stroke-width:2px,color:#ECF0F1
```
**Explanation**: A high-level view of the system architecture showing how the Gateway routes requests to different services, all connected to a shared Database and Cache.
@@ -263,23 +263,23 @@ graph TD
```mermaid
graph LR
Input[User Input] --> Validation[Zod Validation]
Validation --> Controller[Controller]
Controller --> Service[Service Layer]
Service --> Repository[Repository]
Repository --> Prisma[Prisma ORM]
Prisma --> DB[(Database)]
Service --> Cache[(Redis Cache)]
style Input fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style Validation fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style Controller fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Service fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Repository fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Prisma fill:#8E44AD,stroke:#7D3C98,stroke-width:2px,color:#ECF0F1
style DB fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Cache fill:#E67E22,stroke:#CA6F1E,stroke-width:2px,color:#ECF0F1
Input[User Input] --> Validation[Zod Validation]
Validation --> Controller[Controller]
Controller --> Service[Service Layer]
Service --> Repository[Repository]
Repository --> Prisma[Prisma ORM]
Prisma --> DB[(Database)]
Service --> Cache[(Redis Cache)]
style Input fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style Validation fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style Controller fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Service fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Repository fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style Prisma fill:#8E44AD,stroke:#7D3C98,stroke-width:2px,color:#ECF0F1
style DB fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Cache fill:#E67E22,stroke:#CA6F1E,stroke-width:2px,color:#ECF0F1
```
**Explanation**: A detailed data flow showing Input going through Validation -> Controller -> Service -> Repository -> ORM -> DB, while also interacting with the Cache.
@@ -300,45 +300,45 @@ Use ER diagrams for:
```mermaid
erDiagram
User ||--o{ Session : has
User ||--o{ RefreshToken : has
User ||--o{ UserRole : has
Role ||--o{ UserRole : has
Role ||--o{ RolePermission : has
Permission ||--o{ RolePermission : has
User {
string id PK
string email UK
string passwordHash
boolean mfaEnabled
datetime createdAt
datetime updatedAt
}
Session {
string id PK
string userId FK
string token UK
string deviceId
string ipAddress
datetime expiresAt
}
Role {
string id PK
string name UK
string description
datetime createdAt
}
Permission {
string id PK
string code UK
string resource
string action
string scope
}
User ||--o{ Session : has
User ||--o{ RefreshToken : has
User ||--o{ UserRole : has
Role ||--o{ UserRole : has
Role ||--o{ RolePermission : has
Permission ||--o{ RolePermission : has
User {
string id PK
string email UK
string passwordHash
boolean mfaEnabled
datetime createdAt
datetime updatedAt
}
Session {
string id PK
string userId FK
string token UK
string deviceId
string ipAddress
datetime expiresAt
}
Role {
string id PK
string name UK
string description
datetime createdAt
}
Permission {
string id PK
string code UK
string resource
string action
string scope
}
```
**Explanation**: An Entity-Relationship diagram illustrating a typical IAM schema with Users, Sessions, Roles, and Permissions.
@@ -359,18 +359,18 @@ Use Gantt charts for:
```mermaid
gantt
title Documentation Update Project Timeline
dateFormat YYYY-MM-DD
section Phase 1
Analysis & Research :done, p1, 2024-01-01, 1d
section Phase 2
Templates & Strategy :active, p2, 2024-01-02, 0.5d
section Phase 3
High Priority Docs :p3, 2024-01-03, 2d
section Phase 4
Remaining Docs :p4, 2024-01-05, 3d
section Phase 5
QA & Verification :p5, 2024-01-08, 1d
title Documentation Update Project Timeline
dateFormat YYYY-MM-DD
section Phase 1
Analysis & Research :done, p1, 2024-01-01, 1d
section Phase 2
Templates & Strategy :active, p2, 2024-01-02, 0.5d
section Phase 3
High Priority Docs :p3, 2024-01-03, 2d
section Phase 4
Remaining Docs :p4, 2024-01-05, 3d
section Phase 5
QA & Verification :p5, 2024-01-08, 1d
```
---
@@ -389,20 +389,20 @@ Use C4 diagrams for:
```mermaid
C4Context
title System Context Diagram for IAM System
Person(user, "User", "System user needing authentication")
Person(admin, "Admin", "System administrator")
System(iam, "IAM System", "Identity and Access Management")
System_Ext(email, "Email Service", "SendGrid/AWS SES")
System_Ext(oauth, "OAuth Providers", "Google, Facebook, GitHub")
Rel(user, iam, "Authenticates with", "HTTPS")
Rel(admin, iam, "Manages users and permissions", "HTTPS")
Rel(iam, email, "Sends emails", "SMTP/API")
Rel(iam, oauth, "OAuth login", "OAuth 2.0")
title System Context Diagram for IAM System
Person(user, "User", "System user needing authentication")
Person(admin, "Admin", "System administrator")
System(iam, "IAM System", "Identity and Access Management")
System_Ext(email, "Email Service", "SendGrid/AWS SES")
System_Ext(oauth, "OAuth Providers", "Google, Facebook, GitHub")
Rel(user, iam, "Authenticates with", "HTTPS")
Rel(admin, iam, "Manages users and permissions", "HTTPS")
Rel(iam, email, "Sends emails", "SMTP/API")
Rel(iam, oauth, "OAuth login", "OAuth 2.0")
```
---
@@ -415,50 +415,50 @@ Our diagrams use a consistent dark color palette based on professional design pr
```mermaid
graph LR
subgraph Primary["🎨 Primary Colors"]
A1["Dark Blue<br/>#2980B9"]
A2["Purple<br/>#8E44AD"]
A3["Green<br/>#27AE60"]
end
subgraph Secondary["🎨 Secondary Colors"]
B1["Orange<br/>#E67E22"]
B2["Yellow<br/>#F39C12"]
B3["Red<br/>#C0392B"]
end
subgraph Neutrals["🎨 Neutral Colors"]
C1["Dark Gray<br/>#2C3E50"]
C2["Medium Gray<br/>#34495E"]
C3["Light Text<br/>#ECF0F1"]
end
style A1 fill:#2980B9,stroke:#1F618D,stroke-width:3px,color:#ECF0F1
style A2 fill:#8E44AD,stroke:#7D3C98,stroke-width:3px,color:#ECF0F1
style A3 fill:#27AE60,stroke:#229954,stroke-width:3px,color:#ECF0F1
style B1 fill:#E67E22,stroke:#CA6F1E,stroke-width:3px,color:#ECF0F1
style B2 fill:#F39C12,stroke:#D68910,stroke-width:3px,color:#ECF0F1
style B3 fill:#C0392B,stroke:#A93226,stroke-width:3px,color:#ECF0F1
style C1 fill:#2C3E50,stroke:#1C2833,stroke-width:3px,color:#ECF0F1
style C2 fill:#34495E,stroke:#2C3E50,stroke-width:3px,color:#ECF0F1
style C3 fill:#ECF0F1,stroke:#BDC3C7,stroke-width:3px,color:#2C3E50
subgraph Primary[" Primary Colors"]
A1["Dark Blue<br/>#2980B9"]
A2["Purple<br/>#8E44AD"]
A3["Green<br/>#27AE60"]
end
subgraph Secondary[" Secondary Colors"]
B1["Orange<br/>#E67E22"]
B2["Yellow<br/>#F39C12"]
B3["Red<br/>#C0392B"]
end
subgraph Neutrals[" Neutral Colors"]
C1["Dark Gray<br/>#2C3E50"]
C2["Medium Gray<br/>#34495E"]
C3["Light Text<br/>#ECF0F1"]
end
style A1 fill:#2980B9,stroke:#1F618D,stroke-width:3px,color:#ECF0F1
style A2 fill:#8E44AD,stroke:#7D3C98,stroke-width:3px,color:#ECF0F1
style A3 fill:#27AE60,stroke:#229954,stroke-width:3px,color:#ECF0F1
style B1 fill:#E67E22,stroke:#CA6F1E,stroke-width:3px,color:#ECF0F1
style B2 fill:#F39C12,stroke:#D68910,stroke-width:3px,color:#ECF0F1
style B3 fill:#C0392B,stroke:#A93226,stroke-width:3px,color:#ECF0F1
style C1 fill:#2C3E50,stroke:#1C2833,stroke-width:3px,color:#ECF0F1
style C2 fill:#34495E,stroke:#2C3E50,stroke-width:3px,color:#ECF0F1
style C3 fill:#ECF0F1,stroke:#BDC3C7,stroke-width:3px,color:#2C3E50
```
### Color Usage Guidelines
| Color | Hex Code | Use For | Example |
|-------|----------|---------|---------|
| **Dark Blue** | `#2980B9` | Services, Processing, APIs | User Service, API Gateway |
| **Purple** | `#8E44AD` | Core Components, ORM | Prisma, IAM Service |
| **Green** | `#27AE60` | Success, Validation, End States | Success Flow, Validated Data |
| **Orange** | `#E67E22` | ⚠️ Cache, Warning States | Redis Cache, Warnings |
| **Yellow** | `#F39C12` | ⚠️ Database, Important Decisions | PostgreSQL, Decision Nodes |
| **Red** | `#C0392B` | Errors, Failures, Alerts | Error States, Failed Operations |
| **Dark Gray** | `#2C3E50` | 🔘 Start/End, Neutral Elements | Start Node, End Node |
| **Medium Gray** | `#34495E` | 🔘 Subgraphs, Background | Processing Groups, Containers |
| **Light Text** | `#ECF0F1` | 📝 Text Color (always use) | All node text |
| **Dark Blue** | `#2980B9` | Services, Processing, APIs | User Service, API Gateway |
| **Purple** | `#8E44AD` | Core Components, ORM | Prisma, IAM Service |
| **Green** | `#27AE60` | Success, Validation, End States | Success Flow, Validated Data |
| **Orange** | `#E67E22` | Cache, Warning States | Redis Cache, Warnings |
| **Yellow** | `#F39C12` | Database, Important Decisions | PostgreSQL, Decision Nodes |
| **Red** | `#C0392B` | Errors, Failures, Alerts | Error States, Failed Operations |
| **Dark Gray** | `#2C3E50` | Start/End, Neutral Elements | Start Node, End Node |
| **Medium Gray** | `#34495E` | Subgraphs, Background | Processing Groups, Containers |
| **Light Text** | `#ECF0F1` | Text Color (always use) | All node text |
### Standard Style Pattern
@@ -493,14 +493,14 @@ style NodeName fill:#HexColor,stroke:#DarkerShade,stroke-width:2px,color:#ECF0F1
**Choose colors based on node function:**
🔵 **Blue (`#2980B9`)** → Services, APIs, Controllers
🟣 **Purple (`#8E44AD`)** → Core Systems, ORM, Frameworks
🟢 **Green (`#27AE60`)** → Success, Validation, Completion
🟠 **Orange (`#E67E22`)** → Cache, Memory, Storage
🟡 **Yellow (`#F39C12`)** → Databases, Decisions, Important Actions
🔴 **Red (`#C0392B`)** → Errors, Failures, Critical Issues
**Dark Gray (`#2C3E50`)** → Start/End, Neutral States
**Medium Gray (`#34495E`)** → Containers, Subgraphs, Groups
**Blue (`#2980B9`)** → Services, APIs, Controllers
**Purple (`#8E44AD`)** → Core Systems, ORM, Frameworks
**Green (`#27AE60`)** → Success, Validation, Completion
**Orange (`#E67E22`)** → Cache, Memory, Storage
**Yellow (`#F39C12`)** → Databases, Decisions, Important Actions
**Red (`#C0392B`)** → Errors, Failures, Critical Issues
**Dark Gray (`#2C3E50`)** → Start/End, Neutral States
**Medium Gray (`#34495E`)** → Containers, Subgraphs, Groups
---
@@ -520,45 +520,45 @@ style NodeName fill:#HexColor,stroke:#DarkerShade,stroke-width:2px,color:#ECF0F1
## Common Pitfalls
### Too Complex
### Too Complex
```mermaid
graph TD
A --> B
A --> C
B --> D
B --> E
C --> F
C --> G
D --> H
E --> H
F --> I
G --> I
H --> J
I --> J
A --> B
A --> C
B --> D
B --> E
C --> F
C --> G
D --> H
E --> H
F --> I
G --> I
H --> J
I --> J
```
### Simplified with Subgraphs
### Simplified with Subgraphs
```mermaid
graph TD
A[Start] --> B[Process A]
B --> C[Process B]
subgraph Detailed["Detailed Processing"]
C --> D[Step 1]
D --> E[Step 2]
end
E --> F[End]
style Detailed fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style A fill:#2C3E50,stroke:#1C2833,stroke-width:2px,color:#ECF0F1
style F fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style B fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style C fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style D fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style E fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
A[Start] --> B[Process A]
B --> C[Process B]
subgraph Detailed["Detailed Processing"]
C --> D[Step 1]
D --> E[Step 2]
end
E --> F[End]
style Detailed fill:#34495E,stroke:#2C3E50,stroke-width:2px,color:#ECF0F1
style A fill:#2C3E50,stroke:#1C2833,stroke-width:2px,color:#ECF0F1
style F fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
style B fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style C fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style D fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
style E fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
```
---
@@ -592,24 +592,24 @@ mmdc -i your-doc.md
## Quick Tips
### 🔧 Mermaid Common Issues
### Mermaid Common Issues
**Issue**: Diagram not rendering
- Check for syntax errors (missing arrows, brackets)
- Ensure proper indentation in subgraphs
- Validate special characters are escaped
- Check for syntax errors (missing arrows, brackets)
- Ensure proper indentation in subgraphs
- Validate special characters are escaped
**Issue**: Colors not applying
- Place style commands after all node definitions
- Use exact node IDs in style statements
- Ensure hex colors include `#` prefix
- Place style commands after all node definitions
- Use exact node IDs in style statements
- Ensure hex colors include `#` prefix
**Issue**: Text overlapping
- Use shorter labels or `<br/>` for line breaks
- Adjust diagram direction (TD, LR, RL, BT)
- Increase spacing between nodes
- Use shorter labels or `<br/>` for line breaks
- Adjust diagram direction (TD, LR, RL, BT)
- Increase spacing between nodes
### 🎨 Color Pattern Quick Reference
### Color Pattern Quick Reference
```markdown
// Services & APIs
@@ -634,19 +634,19 @@ style Node fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
style Node fill:#2C3E50,stroke:#1C2833,stroke-width:2px,color:#ECF0F1
```
### 📊 Visual Indicators
### Visual Indicators
Use emojis to enhance diagram readability:
- 🔵 Services & APIs
- 🟣 Core Systems
- 🟢 Success Paths
- 🟡 Databases
- 🟠 Cache/Storage
- 🔴 Errors
- Neutral/Start/End
- ⚠️ Warnings
- Validated
- Failed
- Services & APIs
- Core Systems
- Success Paths
- Databases
- Cache/Storage
- Errors
- Neutral/Start/End
- Warnings
- Validated
- Failed
---

View File

@@ -4,42 +4,42 @@ This project uses [Neon PostgreSQL](https://neon.tech) for all environments.
## Why Neon?
- **Serverless**: No infrastructure management
- **Branching**: Separate databases for dev/staging/prod
- **Auto-scaling**: Handles traffic spikes automatically
- **Point-in-time restore**: Easy recovery from mistakes
- **Free tier**: Perfect for development
- **Connection pooling**: Built-in PgBouncer support
- **Serverless**: No infrastructure management
- **Branching**: Separate databases for dev/staging/prod
- **Auto-scaling**: Handles traffic spikes automatically
- **Point-in-time restore**: Easy recovery from mistakes
- **Free tier**: Perfect for development
- **Connection pooling**: Built-in PgBouncer support
## Architecture Overview
```mermaid
graph TD
Project["📦 Neon Project<br/>goodgo-platform"]
Dev["🔧 Development Branch<br/>main"]
Staging["🧪 Staging Branch<br/>staging"]
Prod["🚀 Production Branch<br/>production"]
LocalDev["💻 Local Dev<br/>.env.local"]
K8sStaging["☸️ Kubernetes<br/>staging namespace"]
K8sProd["☸️ Kubernetes<br/>production namespace"]
Project --> Dev
Project --> Staging
Project --> Prod
Dev -.->|DATABASE_URL| LocalDev
Staging -.->|Secret| K8sStaging
Prod -.->|Secret| K8sProd
style Project fill:#1e293b,stroke:#3b82f6,stroke-width:3px,color:#fff
style Dev fill:#0f172a,stroke:#10b981,stroke-width:2px,color:#fff
style Staging fill:#0f172a,stroke:#f59e0b,stroke-width:2px,color:#fff
style Prod fill:#0f172a,stroke:#ef4444,stroke-width:2px,color:#fff
style LocalDev fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
style K8sStaging fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
style K8sProd fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
Project[" Neon Project<br/>goodgo-platform"]
Dev[" Development Branch<br/>main"]
Staging[" Staging Branch<br/>staging"]
Prod[" Production Branch<br/>production"]
LocalDev[" Local Dev<br/>.env.local"]
K8sStaging[" Kubernetes<br/>staging namespace"]
K8sProd[" Kubernetes<br/>production namespace"]
Project --> Dev
Project --> Staging
Project --> Prod
Dev -.->|DATABASE_URL| LocalDev
Staging -.->|Secret| K8sStaging
Prod -.->|Secret| K8sProd
style Project fill:#1e293b,stroke:#3b82f6,stroke-width:3px,color:#fff
style Dev fill:#0f172a,stroke:#10b981,stroke-width:2px,color:#fff
style Staging fill:#0f172a,stroke:#f59e0b,stroke-width:2px,color:#fff
style Prod fill:#0f172a,stroke:#ef4444,stroke-width:2px,color:#fff
style LocalDev fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
style K8sStaging fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
style K8sProd fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
```
## Quick Start
@@ -105,8 +105,8 @@ Store in GitHub Secrets: `NEON_DATABASE_URL_STAGING`
Or in Kubernetes:
```bash
kubectl create secret generic iam-service-secrets \
--from-literal=database-url='postgresql://...' \
-n staging
--from-literal=database-url='postgresql://...' \
-n staging
```
### Production
@@ -116,8 +116,8 @@ Store in GitHub Secrets: `NEON_DATABASE_URL_PRODUCTION`
Or in Kubernetes:
```bash
kubectl create secret generic iam-service-secrets \
--from-literal=database-url='postgresql://...' \
-n production
--from-literal=database-url='postgresql://...' \
-n production
```
## Migrations
@@ -126,59 +126,59 @@ kubectl create secret generic iam-service-secrets \
```mermaid
graph LR
subgraph Local["💻 Local Development"]
Schema["📝 Update Schema<br/>prisma/schema.prisma"]
CreateMig["🔧 Create Migration<br/>migrate dev"]
TestLocal[" Test Locally"]
end
subgraph CI["⚙️ CI/CD Pipeline"]
Push["📤 Git Push"]
Build["🔨 Build"]
TestCI["🧪 Run Tests"]
end
subgraph Staging["🧪 Staging"]
MigStaging["📊 Run Migrations<br/>migrate deploy"]
TestStaging[" Verify Schema"]
end
subgraph Prod["🚀 Production"]
Approval["👤 Manual Approval"]
MigProd["📊 Run Migrations<br/>migrate deploy"]
Rollback["🔄 Rollback Plan"]
end
Schema --> CreateMig
CreateMig --> TestLocal
TestLocal --> Push
Push --> Build
Build --> TestCI
TestCI --> MigStaging
MigStaging --> TestStaging
TestStaging --> Approval
Approval --> MigProd
MigProd -.->|If Failed| Rollback
style Local fill:#1e293b,stroke:#3b82f6,stroke-width:2px,color:#fff
style CI fill:#1e293b,stroke:#8b5cf6,stroke-width:2px,color:#fff
style Staging fill:#1e293b,stroke:#f59e0b,stroke-width:2px,color:#fff
style Prod fill:#1e293b,stroke:#ef4444,stroke-width:2px,color:#fff
style Schema fill:#0f172a,stroke:#10b981,color:#fff
style CreateMig fill:#0f172a,stroke:#10b981,color:#fff
style TestLocal fill:#0f172a,stroke:#10b981,color:#fff
style Push fill:#475569,stroke:#94a3b8,color:#fff
style Build fill:#475569,stroke:#94a3b8,color:#fff
style TestCI fill:#475569,stroke:#94a3b8,color:#fff
style MigStaging fill:#0f172a,stroke:#f59e0b,color:#fff
style TestStaging fill:#0f172a,stroke:#f59e0b,color:#fff
style Approval fill:#475569,stroke:#94a3b8,color:#fff
style MigProd fill:#0f172a,stroke:#ef4444,color:#fff
style Rollback fill:#7f1d1d,stroke:#ef4444,color:#fff
subgraph Local[" Local Development"]
Schema[" Update Schema<br/>prisma/schema.prisma"]
CreateMig[" Create Migration<br/>migrate dev"]
TestLocal[" Test Locally"]
end
subgraph CI[" CI/CD Pipeline"]
Push[" Git Push"]
Build[" Build"]
TestCI[" Run Tests"]
end
subgraph Staging[" Staging"]
MigStaging[" Run Migrations<br/>migrate deploy"]
TestStaging[" Verify Schema"]
end
subgraph Prod[" Production"]
Approval[" Manual Approval"]
MigProd[" Run Migrations<br/>migrate deploy"]
Rollback[" Rollback Plan"]
end
Schema --> CreateMig
CreateMig --> TestLocal
TestLocal --> Push
Push --> Build
Build --> TestCI
TestCI --> MigStaging
MigStaging --> TestStaging
TestStaging --> Approval
Approval --> MigProd
MigProd -.->|If Failed| Rollback
style Local fill:#1e293b,stroke:#3b82f6,stroke-width:2px,color:#fff
style CI fill:#1e293b,stroke:#8b5cf6,stroke-width:2px,color:#fff
style Staging fill:#1e293b,stroke:#f59e0b,stroke-width:2px,color:#fff
style Prod fill:#1e293b,stroke:#ef4444,stroke-width:2px,color:#fff
style Schema fill:#0f172a,stroke:#10b981,color:#fff
style CreateMig fill:#0f172a,stroke:#10b981,color:#fff
style TestLocal fill:#0f172a,stroke:#10b981,color:#fff
style Push fill:#475569,stroke:#94a3b8,color:#fff
style Build fill:#475569,stroke:#94a3b8,color:#fff
style TestCI fill:#475569,stroke:#94a3b8,color:#fff
style MigStaging fill:#0f172a,stroke:#f59e0b,color:#fff
style TestStaging fill:#0f172a,stroke:#f59e0b,color:#fff
style Approval fill:#475569,stroke:#94a3b8,color:#fff
style MigProd fill:#0f172a,stroke:#ef4444,color:#fff
style Rollback fill:#7f1d1d,stroke:#ef4444,color:#fff
```
### Development
@@ -242,46 +242,46 @@ Monitor your databases via Neon Console:
### Connection Issues
1. **Check connection string format**
- Must include `?sslmode=require`
- Verify credentials
- Must include `?sslmode=require`
- Verify credentials
2. **Check IP allowlist**
- Neon may restrict IPs
- Add your IP in Neon Console
- Neon may restrict IPs
- Add your IP in Neon Console
3. **Check branch status**
- Ensure branch is active
- Check for maintenance
- Ensure branch is active
- Check for maintenance
### Migration Issues
1. **DATABASE_URL not set**
```bash
export DATABASE_URL="your-neon-url"
```
```bash
export DATABASE_URL="your-neon-url"
```
2. **Schema mismatch**
```bash
# Reset and re-migrate (dev only!)
pnpm prisma migrate reset
```
```bash
# Reset and re-migrate (dev only!)
pnpm prisma migrate reset
```
3. **Connection timeout**
- Add `?pgbouncer=true` for pooling
- Check Neon console for limits
- Add `?pgbouncer=true` for pooling
- Check Neon console for limits
### Performance Issues
1. **Enable connection pooling**
- Add `?pgbouncer=true` to connection string
- Add `?pgbouncer=true` to connection string
2. **Check query performance**
- Use Neon Console query analyzer
- Review slow queries
- Use Neon Console query analyzer
- Review slow queries
3. **Optimize indexes**
- Review Prisma schema
- Add indexes for frequent queries
- Review Prisma schema
- Add indexes for frequent queries
## Cost Optimization
@@ -300,7 +300,7 @@ Monitor your databases via Neon Console:
## Quick Tips
### 🎨 Mermaid Diagram Color Palette
### Mermaid Diagram Color Palette
| Element | Color | Usage |
|---------|-------|-------|
@@ -311,38 +311,38 @@ Monitor your databases via Neon Console:
| **Infrastructure** | `#475569` + `#94a3b8` | K8s, CI/CD (gray) |
| **Error/Rollback** | `#7f1d1d` + `#ef4444` | Critical actions (dark red) |
### 🚨 Common Mermaid Issues
### Common Mermaid Issues
**Syntax Errors:**
- Use quotes for labels with special chars: `["Label<br/>text"]`
- Escape HTML entities: `&amp;` not `&`
- Use `<br/>` for line breaks inside labels
- Avoid `<br>` without closing slash
- Use quotes for labels with special chars: `["Label<br/>text"]`
- Escape HTML entities: `&amp;` not `&`
- Use `<br/>` for line breaks inside labels
- Avoid `<br>` without closing slash
**Rendering Issues:**
- If diagram doesn't render, check for matching brackets `[]` or `{}`
- Verify all style declarations use valid CSS colors
- Ensure subgraph names are unique
### 📊 Visual Indicators
### Visual Indicators
| Icon | Meaning |
|------|---------|
| 📦 | Project/Package |
| 🔧 | Development/Tools |
| 🧪 | Testing/Staging |
| 🚀 | Production/Deploy |
| 💻 | Local Environment |
| ☸️ | Kubernetes |
| ⚙️ | CI/CD Pipeline |
| 📝 | Configuration/Schema |
| 📊 | Database/Data |
| | Success/Validation |
| | Error/Failed |
| 🔄 | Rollback/Retry |
| 👤 | Manual Action |
| 📤 | Push/Upload |
| 🔨 | Build Process |
| | Project/Package |
| | Development/Tools |
| | Testing/Staging |
| | Production/Deploy |
| | Local Environment |
| | Kubernetes |
| | CI/CD Pipeline |
| | Configuration/Schema |
| | Database/Data |
| | Success/Validation |
| | Error/Failed |
| | Rollback/Retry |
| | Manual Action |
| | Push/Upload |
| | Build Process |
## Resources

View File

@@ -8,93 +8,93 @@ This guide explains how to use the observability stack (Grafana, Prometheus, Lok
The stack consists of the following components:
- **Prometheus**: Metrics collection and storage
- **Loki**: Log aggregation system
- **Promtail**: Log collector agent
- **Grafana**: Unified visualization dashboard
- **Prometheus**: Metrics collection and storage
- **Loki**: Log aggregation system
- **Promtail**: Log collector agent
- **Grafana**: Unified visualization dashboard
### Architecture Diagram
```mermaid
flowchart LR
subgraph Services["Microservices"]
IAM[IAM Service]
USER[User Service]
TRAEFIK[Traefik Gateway]
end
subgraph Collection["Data Collection"]
PROM[Prometheus]
PROMTAIL[Promtail]
end
subgraph Storage["Data Storage"]
PROM_DB[(Prometheus DB)]
LOKI_DB[(Loki DB)]
end
subgraph Visualization["Visualization"]
GRAFANA[Grafana Dashboard]
end
IAM -->|Metrics| PROM
USER -->|Metrics| PROM
TRAEFIK -->|Metrics| PROM
IAM -.->|Logs| PROMTAIL
USER -.->|Logs| PROMTAIL
TRAEFIK -.->|Logs| PROMTAIL
PROM -->|Store| PROM_DB
PROMTAIL -->|Push| LOKI_DB
PROM_DB -->|Query| GRAFANA
LOKI_DB -->|Query| GRAFANA
style Services fill:#2d3748
style Collection fill:#2c5282
style Storage fill:#2f855a
style Visualization fill:#744210
style IAM fill:#4a5568
style USER fill:#4a5568
style TRAEFIK fill:#4a5568
style PROM fill:#3182ce
style PROMTAIL fill:#3182ce
style PROM_DB fill:#38a169
style LOKI_DB fill:#38a169
style GRAFANA fill:#d69e2e
subgraph Services["Microservices"]
IAM[IAM Service]
USER[User Service]
TRAEFIK[Traefik Gateway]
end
subgraph Collection["Data Collection"]
PROM[Prometheus]
PROMTAIL[Promtail]
end
subgraph Storage["Data Storage"]
PROM_DB[(Prometheus DB)]
LOKI_DB[(Loki DB)]
end
subgraph Visualization["Visualization"]
GRAFANA[Grafana Dashboard]
end
IAM -->|Metrics| PROM
USER -->|Metrics| PROM
TRAEFIK -->|Metrics| PROM
IAM -.->|Logs| PROMTAIL
USER -.->|Logs| PROMTAIL
TRAEFIK -.->|Logs| PROMTAIL
PROM -->|Store| PROM_DB
PROMTAIL -->|Push| LOKI_DB
PROM_DB -->|Query| GRAFANA
LOKI_DB -->|Query| GRAFANA
style Services fill:#2d3748
style Collection fill:#2c5282
style Storage fill:#2f855a
style Visualization fill:#744210
style IAM fill:#4a5568
style USER fill:#4a5568
style TRAEFIK fill:#4a5568
style PROM fill:#3182ce
style PROMTAIL fill:#3182ce
style PROM_DB fill:#38a169
style LOKI_DB fill:#38a169
style GRAFANA fill:#d69e2e
```
### Data Flow
```mermaid
sequenceDiagram
participant S as Service
participant PT as Promtail
participant P as Prometheus
participant L as Loki
participant G as Grafana
Note over S,G: Metrics Flow
S->>P: Expose /metrics endpoint
P->>P: Scrape metrics (15s interval)
G->>P: Query PromQL
P-->>G: Return metrics data
Note over S,G: Logs Flow
S->>PT: Write logs to stdout
PT->>PT: Parse & Label logs
PT->>L: Push logs via HTTP
G->>L: Query LogQL
L-->>G: Return log data
participant S as Service
participant PT as Promtail
participant P as Prometheus
participant L as Loki
participant G as Grafana
Note over S,G: Metrics Flow
S->>P: Expose /metrics endpoint
P->>P: Scrape metrics (15s interval)
G->>P: Query PromQL
P-->>G: Return metrics data
Note over S,G: Logs Flow
S->>PT: Write logs to stdout
PT->>PT: Parse & Label logs
PT->>L: Push logs via HTTP
G->>L: Query LogQL
L-->>G: Return log data
```
## Getting Started
### Prerequisites
- Docker and Docker Compose installed
- Existing `microservices-network` (created by the main application stack or manually)
- Docker and Docker Compose installed
- Existing `microservices-network` (created by the main application stack or manually)
### Starting the Stack
@@ -133,26 +133,26 @@ You should see `grafana`, `prometheus`, `loki`, and `promtail`.
### Initial Setup
1. **Login**: Access [http://localhost:3001](http://localhost:3001) and login with `admin`/`admin`
2. **Change Password**: You'll be prompted to change the default password (recommended)
3. **Verify Datasources**:
- Navigate to **Configuration****Data Sources**
- Ensure both **Prometheus** and **Loki** are connected
1. **Login**: Access [http://localhost:3001](http://localhost:3001) and login with `admin`/`admin`
2. **Change Password**: You'll be prompted to change the default password (recommended)
3. **Verify Datasources**:
- Navigate to **Configuration****Data Sources**
- Ensure both **Prometheus** and **Loki** are connected
### Exploring Data
Go to **Explore** (compass icon) in the sidebar:
- Select **Loki** from the datasource dropdown to search logs
- Select **Prometheus** from the datasource dropdown to query metrics
- Select **Loki** from the datasource dropdown to search logs
- Select **Prometheus** from the datasource dropdown to query metrics
### Viewing Logs (Loki)
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., `iam-service` or `traefik`)
4. Click **Show logs**
1. Click **Label browser**
2. Select a label, e.g., `container`
3. Choose a specific container (e.g., `iam-service` or `traefik`)
4. Click **Show logs**
**LogQL Query Examples:**
@@ -166,8 +166,8 @@ In the **Explore** view with **Loki** selected:
In the **Explore** view with **Prometheus** selected:
1. Type a metric name in the query field (e.g., `up`, `container_memory_usage_bytes`)
2. Click **Run query**
1. Type a metric name in the query field (e.g., `up`, `container_memory_usage_bytes`)
2. Click **Run query**
**PromQL Query Examples:**
@@ -183,9 +183,9 @@ container_memory_usage_bytes{container="iam-service"}
### File Locations
- **Prometheus**: `infra/observability/prometheus/prometheus.yml`
- **Promtail**: `infra/observability/promtail/promtail-config.yml`
- **Grafana**: `infra/observability/grafana/`
- **Prometheus**: `infra/observability/prometheus/prometheus.yml`
- **Promtail**: `infra/observability/promtail/promtail-config.yml`
- **Grafana**: `infra/observability/grafana/`
### Custom Metrics
@@ -195,15 +195,15 @@ To expose custom metrics from your service:
import { Counter, Histogram } from 'prom-client';
const requestCounter = new Counter({
name: 'http_requests_total',
help: 'Total HTTP requests',
labelNames: ['method', 'route', 'status']
name: 'http_requests_total',
help: 'Total HTTP requests',
labelNames: ['method', 'route', 'status']
});
const requestDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP request duration',
labelNames: ['method', 'route']
name: 'http_request_duration_seconds',
help: 'HTTP request duration',
labelNames: ['method', 'route']
});
```
@@ -211,10 +211,10 @@ const requestDuration = new Histogram({
Create custom dashboards in Grafana:
1. Click **+** → **Dashboard**
2. Add **Panel**
3. Configure query (Prometheus or Loki)
4. Save dashboard
1. Click **+** → **Dashboard**
2. Add **Panel**
3. Configure query (Prometheus or Loki)
4. Save dashboard
## Color Palette Reference
@@ -222,11 +222,11 @@ Diagrams use a dark color palette for better readability:
| Component Type | Fill Color | Stroke Color | Purpose |
|----------------|------------|--------------|----------|
| 🚀 Services | `#e94560` | `#c81e3b` | Microservices (red) |
| 📊 Collectors | `#f39c12` | `#d68910` | Data collection (orange) |
| 💾 Storage | `#3498db` | `#2874a6` | Storage (blue) |
| 📊 Visualization | `#9b59b6` | `#7d3c98` | Visualization (purple) |
| 📦 Subgraphs | `#1a1a2e` - `#533483` | `#16213e` - `#0f3460` | Logical groups |
| Services | `#e94560` | `#c81e3b` | Microservices (red) |
| Collectors | `#f39c12` | `#d68910` | Data collection (orange) |
| Storage | `#3498db` | `#2874a6` | Storage (blue) |
| Visualization | `#9b59b6` | `#7d3c98` | Visualization (purple) |
| Subgraphs | `#1a1a2e` - `#533483` | `#16213e` - `#0f3460` | Logical groups |
**All text uses `color:#ffffff` (white) for readability on dark backgrounds**
@@ -234,13 +234,13 @@ Diagrams use a dark color palette for better readability:
### Mermaid Common Issues
**DO:**
**DO:**
- Use `flowchart LR` for left-to-right flow
- Use `sequenceDiagram` for time-based interactions
- Apply dark colors for better contrast
- Use descriptive node IDs
**DON'T:**
**DON'T:**
- Mix `graph` and `flowchart` syntax
- Use special characters in node IDs without quotes
- Forget closing brackets for subgraphs
@@ -265,11 +265,11 @@ sum(metric_name) by (label)
### Visual Indicators
- 📊 **Metrics**: Numerical time-series data
- 📝 **Logs**: Text-based event records
- 🎯 **Query**: Search/filter operations
- 🔍 **Explore**: Investigation interface
- 📈 **Dashboard**: Pre-configured visualizations
- **Metrics**: Numerical time-series data
- **Logs**: Text-based event records
- **Query**: Search/filter operations
- **Explore**: Investigation interface
- **Dashboard**: Pre-configured visualizations
## Troubleshooting
@@ -277,25 +277,25 @@ sum(metric_name) by (label)
| Issue | Symptoms | Solution |
|-------|----------|----------|
| ⚠️ No logs visible | Grafana Explore shows no logs | Check Promtail is running: `docker ps \| grep promtail` |
| 📊 Missing metrics | Services don't appear in Prometheus targets | Check service `/metrics` endpoint |
| 🔴 Container won't start | `docker ps` doesn't show container | View logs: `docker-compose logs <service-name>` |
| 🌐 Network issue | Services can't connect | Create network: `docker network create microservices-network` |
| No logs visible | Grafana Explore shows no logs | Check Promtail is running: `docker ps \| grep promtail` |
| Missing metrics | Services don't appear in Prometheus targets | Check service `/metrics` endpoint |
| Container won't start | `docker ps` doesn't show container | View logs: `docker-compose logs <service-name>` |
| Network issue | Services can't connect | Create network: `docker network create microservices-network` |
### Logs Not Appearing in Loki
1. Check Promtail logs: `docker logs promtail`
2. Verify container labels are correct
3. Ensure services are on `microservices-network`
1. Check Promtail logs: `docker logs promtail`
2. Verify container labels are correct
3. Ensure services are on `microservices-network`
### Metrics Not Appearing in Prometheus
1. Check Prometheus targets: [http://localhost:9090/targets](http://localhost:9090/targets)
2. Verify service exposes `/metrics` endpoint
3. Check Prometheus scrape config
1. Check Prometheus targets: [http://localhost:9090/targets](http://localhost:9090/targets)
2. Verify service exposes `/metrics` endpoint
3. Check Prometheus scrape config
### Grafana Shows "No Data"
1. Verify datasource connection (Configuration → Data Sources)
2. Check time range in query
3. Ensure data exists in Prometheus/Loki
1. Verify datasource connection (Configuration → Data Sources)
2. Check time range in query
3. Ensure data exists in Prometheus/Loki

View File

@@ -6,13 +6,13 @@
1. [General Diagnosis](#general-diagnosis)
2. [Infrastructure Issues](#infrastructure-issues)
- [Database (Neon/PostgreSQL)](#database-neonpostgresql)
- [Redis](#redis)
- [Traefik Gateway](#traefik-gateway)
- [Database (Neon/PostgreSQL)](#database-neonpostgresql)
- [Redis](#redis)
- [Traefik Gateway](#traefik-gateway)
3. [Service Issues](#service-issues)
- [Service Fails to Start](#service-fails-to-start)
- [Prisma/Database Errors](#prismadatabase-errors)
- [Authentication Errors](#authentication-errors)
- [Service Fails to Start](#service-fails-to-start)
- [Prisma/Database Errors](#prismadatabase-errors)
- [Authentication Errors](#authentication-errors)
4. [Debugging Tools](#debugging-tools)
5. [FAQ](#faq)
@@ -22,110 +22,110 @@
When something goes wrong, follow this checklist:
1. **Check Service Status**:
```bash
cd deployments/local
docker-compose ps
```
*All services should be `Up` or `Running`.*
1. **Check Service Status**:
```bash
cd deployments/local
docker-compose ps
```
*All services should be `Up` or `Running`.*
2. **Check Logs**:
```bash
# View logs for a specific service
docker-compose logs -f <service-name>
# View last 100 lines for all
docker-compose logs --tail=100
```
2. **Check Logs**:
```bash
# View logs for a specific service
docker-compose logs -f <service-name>
3. **Check Connectivity**:
* Can you reach the Gateway? `curl http://localhost/health`
* Can you reach the Dashboard? http://localhost:8080
# View last 100 lines for all
docker-compose logs --tail=100
```
3. **Check Connectivity**:
* Can you reach the Gateway? `curl http://localhost/health`
* Can you reach the Dashboard? http://localhost:8080
### Troubleshooting Flowchart
```mermaid
flowchart TD
Start([🔍 Issue Detected]) --> CheckStatus{Check Service<br/>Status}
CheckStatus -->|All Running| CheckLogs[📋 Check Logs]
CheckStatus -->|Some Down| IdentifyService[🎯 Identify Failed<br/>Service]
IdentifyService --> ServiceType{Service Type?}
ServiceType -->|Infrastructure| InfraCheck[🔧 Infrastructure<br/>Check]
ServiceType -->|Application| AppCheck[⚙️ Application<br/>Check]
InfraCheck --> DBCheck{Database?}
InfraCheck --> RedisCheck{Redis?}
InfraCheck --> TraefikCheck{Traefik?}
DBCheck -->|Yes| DBSolution[ Check DATABASE_URL<br/> Verify Neon connection<br/> Check IP whitelist]
RedisCheck -->|Yes| RedisSolution[ Restart Redis<br/> Check port mapping<br/> Verify connection string]
TraefikCheck -->|Yes| TraefikSolution[ Check labels<br/> Verify PathPrefix<br/> Check health status]
AppCheck --> ErrorType{Error Type?}
ErrorType -->|Config| ConfigFix[ Check .env variables<br/> Run init-project.sh]
ErrorType -->|Prisma| PrismaFix[ Check migrations<br/> Regenerate client<br/> Reset database]
ErrorType -->|Auth| AuthFix[ Check token expiry<br/> Verify keys<br/> Sync Docker time]
CheckLogs --> LogAnalysis{Log Shows<br/>Error?}
LogAnalysis -->|Yes| ErrorType
LogAnalysis -->|No| ConnCheck[🌐 Check Connectivity]
ConnCheck --> GatewayTest{Gateway<br/>Reachable?}
GatewayTest -->|No| TraefikCheck
GatewayTest -->|Yes| ServiceTest{Service<br/>Reachable?}
ServiceTest -->|No| AppCheck
ServiceTest -->|Yes| Resolved([ Issue Resolved])
DBSolution --> Restart[🔄 Restart Services]
RedisSolution --> Restart
TraefikSolution --> Restart
ConfigFix --> Restart
PrismaFix --> Restart
AuthFix --> Restart
Restart --> Verify{Issue<br/>Fixed?}
Verify -->|Yes| Resolved
Verify -->|No| DeepDebug[🛠️ Deep Debugging<br/>Required]
DeepDebug --> ContainerShell[Access Container Shell]
DeepDebug --> PrismaStudio[Use Prisma Studio]
DeepDebug --> RedisInspect[Inspect Redis]
DeepDebug --> APITest[Direct API Testing]
style Start fill:#1a1a2e,color:#fff
style Resolved fill:#0f3460,color:#fff
style CheckStatus fill:#16213e,color:#fff
style ServiceType fill:#16213e,color:#fff
style ErrorType fill:#16213e,color:#fff
style DBCheck fill:#16213e,color:#fff
style RedisCheck fill:#16213e,color:#fff
style TraefikCheck fill:#16213e,color:#fff
style GatewayTest fill:#16213e,color:#fff
style ServiceTest fill:#16213e,color:#fff
style Verify fill:#16213e,color:#fff
style LogAnalysis fill:#16213e,color:#fff
style InfraCheck fill:#1a1a40,color:#fff
style AppCheck fill:#1a1a40,color:#fff
style DBSolution fill:#0f4c75,color:#fff
style RedisSolution fill:#0f4c75,color:#fff
style TraefikSolution fill:#0f4c75,color:#fff
style ConfigFix fill:#0f4c75,color:#fff
style PrismaFix fill:#0f4c75,color:#fff
style AuthFix fill:#0f4c75,color:#fff
style Restart fill:#3282b8,color:#fff
style DeepDebug fill:#1b262c,color:#fff
style IdentifyService fill:#1a1a40,color:#fff
style CheckLogs fill:#1a1a40,color:#fff
style ConnCheck fill:#1a1a40,color:#fff
style ContainerShell fill:#0f3460,color:#fff
style PrismaStudio fill:#0f3460,color:#fff
style RedisInspect fill:#0f3460,color:#fff
style APITest fill:#0f3460,color:#fff
Start([ Issue Detected]) --> CheckStatus{Check Service<br/>Status}
CheckStatus -->|All Running| CheckLogs[ Check Logs]
CheckStatus -->|Some Down| IdentifyService[ Identify Failed<br/>Service]
IdentifyService --> ServiceType{Service Type?}
ServiceType -->|Infrastructure| InfraCheck[ Infrastructure<br/>Check]
ServiceType -->|Application| AppCheck[ Application<br/>Check]
InfraCheck --> DBCheck{Database?}
InfraCheck --> RedisCheck{Redis?}
InfraCheck --> TraefikCheck{Traefik?}
DBCheck -->|Yes| DBSolution[ Check DATABASE_URL<br/> Verify Neon connection<br/> Check IP whitelist]
RedisCheck -->|Yes| RedisSolution[ Restart Redis<br/> Check port mapping<br/> Verify connection string]
TraefikCheck -->|Yes| TraefikSolution[ Check labels<br/> Verify PathPrefix<br/> Check health status]
AppCheck --> ErrorType{Error Type?}
ErrorType -->|Config| ConfigFix[ Check .env variables<br/> Run init-project.sh]
ErrorType -->|Prisma| PrismaFix[ Check migrations<br/> Regenerate client<br/> Reset database]
ErrorType -->|Auth| AuthFix[ Check token expiry<br/> Verify keys<br/> Sync Docker time]
CheckLogs --> LogAnalysis{Log Shows<br/>Error?}
LogAnalysis -->|Yes| ErrorType
LogAnalysis -->|No| ConnCheck[ Check Connectivity]
ConnCheck --> GatewayTest{Gateway<br/>Reachable?}
GatewayTest -->|No| TraefikCheck
GatewayTest -->|Yes| ServiceTest{Service<br/>Reachable?}
ServiceTest -->|No| AppCheck
ServiceTest -->|Yes| Resolved([ Issue Resolved])
DBSolution --> Restart[ Restart Services]
RedisSolution --> Restart
TraefikSolution --> Restart
ConfigFix --> Restart
PrismaFix --> Restart
AuthFix --> Restart
Restart --> Verify{Issue<br/>Fixed?}
Verify -->|Yes| Resolved
Verify -->|No| DeepDebug[ Deep Debugging<br/>Required]
DeepDebug --> ContainerShell[Access Container Shell]
DeepDebug --> PrismaStudio[Use Prisma Studio]
DeepDebug --> RedisInspect[Inspect Redis]
DeepDebug --> APITest[Direct API Testing]
style Start fill:#1a1a2e,color:#fff
style Resolved fill:#0f3460,color:#fff
style CheckStatus fill:#16213e,color:#fff
style ServiceType fill:#16213e,color:#fff
style ErrorType fill:#16213e,color:#fff
style DBCheck fill:#16213e,color:#fff
style RedisCheck fill:#16213e,color:#fff
style TraefikCheck fill:#16213e,color:#fff
style GatewayTest fill:#16213e,color:#fff
style ServiceTest fill:#16213e,color:#fff
style Verify fill:#16213e,color:#fff
style LogAnalysis fill:#16213e,color:#fff
style InfraCheck fill:#1a1a40,color:#fff
style AppCheck fill:#1a1a40,color:#fff
style DBSolution fill:#0f4c75,color:#fff
style RedisSolution fill:#0f4c75,color:#fff
style TraefikSolution fill:#0f4c75,color:#fff
style ConfigFix fill:#0f4c75,color:#fff
style PrismaFix fill:#0f4c75,color:#fff
style AuthFix fill:#0f4c75,color:#fff
style Restart fill:#3282b8,color:#fff
style DeepDebug fill:#1b262c,color:#fff
style IdentifyService fill:#1a1a40,color:#fff
style CheckLogs fill:#1a1a40,color:#fff
style ConnCheck fill:#1a1a40,color:#fff
style ContainerShell fill:#0f3460,color:#fff
style PrismaStudio fill:#0f3460,color:#fff
style RedisInspect fill:#0f3460,color:#fff
style APITest fill:#0f3460,color:#fff
```
---
@@ -136,55 +136,55 @@ flowchart TD
**Problem**: `P1001: Can't reach database server` or `Connection timed out`
* **Cause 1**: Internet connectivity issues (Neon is cloud-based).
* **Cause 2**: Incorrect `DATABASE_URL` in `.env`.
* **Cause 3**: IP address blocked by Neon.
* **Cause 1**: Internet connectivity issues (Neon is cloud-based).
* **Cause 2**: Incorrect `DATABASE_URL` in `.env`.
* **Cause 3**: IP address blocked by Neon.
**Solution**:
1. Verify internet connection: `ping neon.tech`.
2. Check `deployments/local/.env.local`. The URL should look like:
`postgres://user:pass@ep-xyz.aws.neon.tech/neondb`
3. Go to Neon Dashboard -> Settings, ensure "Allow all IPs" or add your current IP.
1. Verify internet connection: `ping neon.tech`.
2. Check `deployments/local/.env.local`. The URL should look like:
`postgres://user:pass@ep-xyz.aws.neon.tech/neondb`
3. Go to Neon Dashboard -> Settings, ensure "Allow all IPs" or add your current IP.
**Problem**: `P1003: Database does not exist`
* **Reason**: You are connecting to the wrong database name.
* **Fix**: Check the end of your connection string (e.g., `/neondb` usually). If you are using a custom DB name, ensure it exists in Neon.
* **Reason**: You are connecting to the wrong database name.
* **Fix**: Check the end of your connection string (e.g., `/neondb` usually). If you are using a custom DB name, ensure it exists in Neon.
### Redis
**Problem**: `Redis connection refused` or `ECONNREFUSED`
* **Cause**: Redis container is not running or port mapping is wrong.
* **Cause**: Redis container is not running or port mapping is wrong.
**Solution**:
1. Check Redis status: `docker-compose ps redis`.
2. Restart Redis: `docker-compose restart redis`.
3. Check logs: `docker-compose logs redis`.
4. Connection string from services:
* **Inside Docker**: `redis:6379`
* **From Host**: `localhost:6379`
1. Check Redis status: `docker-compose ps redis`.
2. Restart Redis: `docker-compose restart redis`.
3. Check logs: `docker-compose logs redis`.
4. Connection string from services:
* **Inside Docker**: `redis:6379`
* **From Host**: `localhost:6379`
### Traefik Gateway
**Problem**: `404 Not Found` when accessing APIs (e.g., `http://localhost/api/v1/auth`)
* **Cause**: Service is down or Labels are misconfigured.
* **Cause**: Service is down or Labels are misconfigured.
**Solution**:
1. Check Traefik Dashboard at http://localhost:8080.
* Look for "HTTP Routers" and "Services".
* If your service is missing, check `docker-compose.yml` labels.
2. Verify `PathPrefix` in labels matches your request.
```yaml
- "traefik.http.routers.iam.rule=PathPrefix(`/api/v1/auth`)"
```
3. Check if the service passed health checks (Health status in dashboard).
1. Check Traefik Dashboard at http://localhost:8080.
* Look for "HTTP Routers" and "Services".
* If your service is missing, check `docker-compose.yml` labels.
2. Verify `PathPrefix` in labels matches your request.
```yaml
- "traefik.http.routers.iam.rule=PathPrefix(`/api/v1/auth`)"
```
3. Check if the service passed health checks (Health status in dashboard).
**Problem**: `Bad Gateway` or `Gateway Timeout`
* **Cause**: Service is crashing or taking too long to respond.
* **Fix**: Check the specific service logs (`docker-compose logs iam-service`).
* **Cause**: Service is crashing or taking too long to respond.
* **Fix**: Check the specific service logs (`docker-compose logs iam-service`).
---
@@ -195,44 +195,44 @@ flowchart TD
**Symptom**: Container status is `Exited (1)` or `Restarting`.
**Debugging**:
1. Check logs immediately:
```bash
docker-compose logs iam-service
```
2. **Common Error**: `Config validation error`
* **Fix**: Check environment variables. Using `./scripts/setup/init-project.sh` ensures `.env` exists.
3. **Common Error**: `PrismaClientInitializationError`
* **Fix**: Database connectivity issue (see Infrastructure section).
1. Check logs immediately:
```bash
docker-compose logs iam-service
```
2. **Common Error**: `Config validation error`
* **Fix**: Check environment variables. Using `./scripts/setup/init-project.sh` ensures `.env` exists.
3. **Common Error**: `PrismaClientInitializationError`
* **Fix**: Database connectivity issue (see Infrastructure section).
### Prisma/Database Errors
**Error**: `P2025: Record to update not found`
* **Fix**: Logic error. Ensure the ID exists before updating.
* **Fix**: Logic error. Ensure the ID exists before updating.
**Error**: `P2002: Unique constraint failed`
* **Fix**: You are trying to insert duplicate data (e.g., same email).
* **Fix**: You are trying to insert duplicate data (e.g., same email).
**Error**: `Migration failed`
* **Fix**:
1. Delete `prisma/migrations` folder (only in dev!).
2. Reset database: `pnpm prisma migrate reset`.
3. Regenerate client: `pnpm prisma generate`.
* **Fix**:
1. Delete `prisma/migrations` folder (only in dev!).
2. Reset database: `pnpm prisma migrate reset`.
3. Regenerate client: `pnpm prisma generate`.
### Authentication Errors
**Problem**: `401 Unauthorized` despite valid token
* **Cause 1**: Token expired.
* **Cause 2**: Public key mismatch (Service can't verify token signed by IAM).
* **Cause 3**: Clock skew (Docker time vs Host time).
* **Cause 1**: Token expired.
* **Cause 2**: Public key mismatch (Service can't verify token signed by IAM).
* **Cause 3**: Clock skew (Docker time vs Host time).
**Solution**:
1. Check server logs for JWT verification errors.
2. Restart services to refresh keys.
3. Sync Docker time: restart Docker Desktop.
1. Check server logs for JWT verification errors.
2. Restart services to refresh keys.
3. Sync Docker time: restart Docker Desktop.
---
@@ -276,8 +276,8 @@ curl -v http://localhost/api/v1/auth/health/live
# Login (example)
curl -X POST http://localhost/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com", "password":"password"}'
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com", "password":"password"}'
```
---
@@ -300,14 +300,14 @@ docker-compose down -v
**Q: My computer is slow when running everything.**
A: Docker consumes RAM.
1. Stop unused services (e.g., `future-service`).
2. Increase Docker resource limits in Docker Desktop settings.
1. Stop unused services (e.g., `future-service`).
2. Increase Docker resource limits in Docker Desktop settings.
---
## Quick Tips
### 🎯 Debugging Shortcuts
### Debugging Shortcuts
```bash
# Quick health check all services
@@ -329,7 +329,7 @@ docker stats --no-stream
docker system prune -a --volumes
```
### 🔍 Common Error Patterns
### Common Error Patterns
| Error Pattern | Likely Cause | Quick Fix |
|--------------|--------------|-----------|
@@ -341,13 +341,13 @@ docker system prune -a --volumes
| `502 Bad Gateway` | Service crashed | Check service logs |
| `Config validation error` | Missing env vars | Run `init-project.sh` |
### 📋 Log Analysis Tips
### Log Analysis Tips
**What to look for in logs:**
- `Server listening on port XXXX` = Service started successfully
- ⚠️ `Warning:` = Non-critical issues
- `Error:` = Critical issues requiring attention
- 🔍 `Trace:` = Detailed execution flow
- `Server listening on port XXXX` = Service started successfully
- `Warning:` = Non-critical issues
- `Error:` = Critical issues requiring attention
- `Trace:` = Detailed execution flow
**Useful grep patterns:**
```bash
@@ -364,7 +364,7 @@ docker-compose logs | grep -i "prisma\|database\|p1001\|p1003"
docker-compose logs | grep -i "unauthorized\|401\|jwt\|token"
```
### 💾 Resource Management
### Resource Management
**Recommended Docker Resources:**
- **RAM**: Minimum 4GB, Recommended 8GB
@@ -388,14 +388,14 @@ docker container prune
# Remove unused images
docker image prune -a
# Remove unused volumes (⚠️ deletes data!)
# Remove unused volumes ( deletes data!)
docker volume prune
# Nuclear option (⚠️ removes everything!)
# Nuclear option ( removes everything!)
docker system prune -a --volumes
```
### 🛡️ Best Practices
### Best Practices
1. **Always check logs first** before making changes
2. **Use Traefik Dashboard** (http://localhost:8080) to verify routing
@@ -406,16 +406,16 @@ docker system prune -a --volumes
7. **Keep services running** you're actively developing
8. **Stop services** you're not using to save resources
### 🎨 Visual Indicators
### Visual Indicators
When reading logs, look for these patterns:
- 🟢 `[INFO]` = Normal operation
- 🟡 `[WARN]` = Something to watch
- 🔴 `[ERROR]` = Needs immediate attention
- 🔵 `[DEBUG]` = Detailed information
- `[TRACE]` = Very detailed execution flow
- `[INFO]` = Normal operation
- `[WARN]` = Something to watch
- `[ERROR]` = Needs immediate attention
- `[DEBUG]` = Detailed information
- `[TRACE]` = Very detailed execution flow
### 🔗 Related Resources
### Related Resources
- [Local Deployment Guide](./local-deployment.md) - Setup instructions
- [Development Guide](./development.md) - Development workflow

View File

@@ -20,37 +20,37 @@
```mermaid
graph TD
subgraph "CI/CD Pipeline - GitHub Actions"
Code[Code Push] --> Test[Run Tests]
Test --> Build[Build Docker Image]
Build --> Registry[Push to Registry]
Registry --> Deploy[Deploy to K8s]
end
subgraph "Infrastructure - Kubernetes"
Ingress[Traefik Ingress] --> Service[K8s Service]
Service --> Pods[Application Pods]
Pods --> Secrets[K8s Secrets]
end
subgraph "External Services"
Pods --> Neon[(Neon PostgreSQL)]
Pods --> Redis[(Redis Cloud)]
end
Deploy --> Ingress
style Code fill:#1e3a5f,color:#e0e7ff
style Test fill:#065f46,color:#d1fae5
style Build fill:#1e40af,color:#dbeafe
style Registry fill:#581c87,color:#f3e8ff
style Deploy fill:#9a3412,color:#fed7aa
style Ingress fill:#312e81,color:#e0e7ff
style Service fill:#1e40af,color:#dbeafe
style Pods fill:#14532d,color:#d1fae5
style Secrets fill:#78350f,color:#fef3c7
style Neon fill:#4c1d95,color:#f3e8ff
style Redis fill:#854d0e,color:#fef3c7
subgraph "CI/CD Pipeline - GitHub Actions"
Code[Code Push] --> Test[Run Tests]
Test --> Build[Build Docker Image]
Build --> Registry[Push to Registry]
Registry --> Deploy[Deploy to K8s]
end
subgraph "Infrastructure - Kubernetes"
Ingress[Traefik Ingress] --> Service[K8s Service]
Service --> Pods[Application Pods]
Pods --> Secrets[K8s Secrets]
end
subgraph "External Services"
Pods --> Neon[(Neon PostgreSQL)]
Pods --> Redis[(Redis Cloud)]
end
Deploy --> Ingress
style Code fill:#1e3a5f,color:#e0e7ff
style Test fill:#065f46,color:#d1fae5
style Build fill:#1e40af,color:#dbeafe
style Registry fill:#581c87,color:#f3e8ff
style Deploy fill:#9a3412,color:#fed7aa
style Ingress fill:#312e81,color:#e0e7ff
style Service fill:#1e40af,color:#dbeafe
style Pods fill:#14532d,color:#d1fae5
style Secrets fill:#78350f,color:#fef3c7
style Neon fill:#4c1d95,color:#f3e8ff
style Redis fill:#854d0e,color:#fef3c7
```
---
@@ -59,14 +59,14 @@ graph TD
Trước khi deploy, đảm bảo bạn có:
* **Công cụ**: Cài đặt `kubectl`, `helm`, `docker`.
* **Quyền truy cập**:
* Kubernetes Cluster (EKS/GKE/DigitalOcean).
* Container Registry (GHCR/DockerHub).
* Tài khoản Neon Console.
* **Cấu hình**:
* File `KUBECONFIG` đã được setup.
* GitHub Secrets đã cấu hình cho CI/CD.
* **Công cụ**: Cài đặt `kubectl`, `helm`, `docker`.
* **Quyền truy cập**:
* Kubernetes Cluster (EKS/GKE/DigitalOcean).
* Container Registry (GHCR/DockerHub).
* Tài khoản Neon Console.
* **Cấu hình**:
* File `KUBECONFIG` đã được setup.
* GitHub Secrets đã cấu hình cho CI/CD.
---
@@ -74,13 +74,13 @@ Trước khi deploy, đảm bảo bạn có:
Chúng tôi sử dụng **Neon Serverless PostgreSQL** cho tất cả môi trường để tận dụng tính năng branching và auto-scaling.
1. **Tạo Project**: Đăng nhập [neon.tech](https://neon.tech) và tạo project `goodgo-platform`.
2. **Tạo Branches**:
* `main` -> Cho Development/Local.
* `staging` -> Cho môi trường Staging.
* `production` -> Cho môi trường Production (Protected).
3. **Lấy Connection Strings**:
* Lưu lại connection string cho từng branch (Khuyến nghị dùng Pooler mode).
1. **Tạo Project**: Đăng nhập [neon.tech](https://neon.tech) và tạo project `goodgo-platform`.
2. **Tạo Branches**:
* `main` -> Cho Development/Local.
* `staging` -> Cho môi trường Staging.
* `production` -> Cho môi trường Production (Protected).
3. **Lấy Connection Strings**:
* Lưu lại connection string cho từng branch (Khuyến nghị dùng Pooler mode).
---
@@ -117,11 +117,11 @@ Chúng tôi sử dụng GitHub Actions để tự động hóa deployment.
Cài đặt các secrets này trong phần settings của repository:
* `NEON_DATABASE_URL_STAGING`: Connection string cho branch staging.
* `NEON_DATABASE_URL_PRODUCTION`: Connection string cho branch production.
* `KUBECONFIG_STAGING`: Base64 encoded kubeconfig cho staging.
* `KUBECONFIG_PRODUCTION`: Base64 encoded kubeconfig cho production.
* `DOCKER_REGISTRY_TOKEN`: Dùng để push images.
* `NEON_DATABASE_URL_STAGING`: Connection string cho branch staging.
* `NEON_DATABASE_URL_PRODUCTION`: Connection string cho branch production.
* `KUBECONFIG_STAGING`: Base64 encoded kubeconfig cho staging.
* `KUBECONFIG_PRODUCTION`: Base64 encoded kubeconfig cho production.
* `DOCKER_REGISTRY_TOKEN`: Dùng để push images.
---
@@ -134,9 +134,9 @@ Staging phản chiếu production nhưng sử dụng tài nguyên tiết kiệm
```bash
# 1. Tạo Secrets
kubectl create secret generic iam-service-secrets \
--from-literal=database-url='<STAGING_NEON_URL>' \
--from-literal=jwt-secret='<RANDOM_SECRET>' \
-n staging
--from-literal=database-url='<STAGING_NEON_URL>' \
--from-literal=jwt-secret='<RANDOM_SECRET>' \
-n staging
# 2. Apply Manifests
kubectl apply -f deployments/staging/kubernetes/ -n staging
@@ -148,9 +148,9 @@ kubectl get pods -n staging
### Qua CI/CD
Push code vào branch `develop`. Action sẽ:
1. Chạy tests.
2. Chạy `prisma migrate deploy` vào Database Staging.
3. Cập nhật Kubernetes deployment image.
1. Chạy tests.
2. Chạy `prisma migrate deploy` vào Database Staging.
3. Cập nhật Kubernetes deployment image.
---
@@ -160,8 +160,8 @@ Production sử dụng cấu hình high-availability (HA).
### 1. Chuẩn bị Database
* Đảm bảo branch Production trên Neon được set **protected**.
* Cấu hình **Point-in-Time Recovery (PITR)** window (ví dụ: 7 ngày).
* Đảm bảo branch Production trên Neon được set **protected**.
* Cấu hình **Point-in-Time Recovery (PITR)** window (ví dụ: 7 ngày).
### 2. Các bước Deployment Thủ công
@@ -171,10 +171,10 @@ kubectl create namespace production
# 2. Tạo Secrets (Khuyến nghị Sealed Secrets) hoặc Standard Secrets
kubectl create secret generic iam-service-secrets \
--from-literal=database-url='<PROD_NEON_URL>' \
--from-literal=jwt-secret='<SECURE_RANDOM_SECRET>' \
--from-literal=jwt-refresh-secret='<SECURE_RANDOM_SECRET>' \
-n production
--from-literal=database-url='<PROD_NEON_URL>' \
--from-literal=jwt-secret='<SECURE_RANDOM_SECRET>' \
--from-literal=jwt-refresh-secret='<SECURE_RANDOM_SECRET>' \
-n production
# 3. Deploy
kubectl apply -f deployments/production/kubernetes/ -n production
@@ -203,24 +203,24 @@ Chúng tôi sử dụng HPA để tự động scale số lượng pods dựa tr
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: iam-service-hpa
name: iam-service-hpa
spec:
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
```
### Zero-Downtime Deployment
Kubernetes xử lý việc này thông qua Rolling Updates.
* **MaxSurge**: 25% (Thêm pods mới trước khi xóa pods cũ).
* **MaxUnavailable**: 0 (Đảm bảo không có downtime trong quá trình update).
* **MaxSurge**: 25% (Thêm pods mới trước khi xóa pods cũ).
* **MaxUnavailable**: 0 (Đảm bảo không có downtime trong quá trình update).
---
@@ -241,6 +241,6 @@ kubectl rollout undo deployment/iam-service -n production --to-revision=2
### Database Rollback
Vì Neon hỗ trợ branching và PITR:
1. Vào Neon Console.
2. Restore branch `production` về timestamp trước khi migration bị lỗi.
3. **Cảnh báo**: Việc này có thể gây mất dữ liệu giao dịch mới. Hãy cẩn trọng.
1. Vào Neon Console.
2. Restore branch `production` về timestamp trước khi migration bị lỗi.
3. **Cảnh báo**: Việc này có thể gây mất dữ liệu giao dịch mới. Hãy cẩn trọng.

View File

@@ -20,22 +20,22 @@ Chúng tôi tuân theo cấu trúc monorepo quản lý bởi PNPM Workspaces.
```
Base/
├── apps/ # Ứng dụng Frontend
│ ├── web-client/ # Next.js 14+ (App Router)
│ └── mobile-client/ # Flutter
├── services/ # Backend microservices
│ ├── _template/ # Template cho service mới
│ ├── iam-service/ # Identity & Access Management
│ └── ...
├── packages/ # Thư viện chia sẻ
│ ├── logger/ # Structured logging (Winston)
│ ├── types/ # DTOs & Interfaces chia sẻ
│ ├── http-client/ # Internal Service Client
│ └── tracing/ # Cấu hình OpenTelemetry
├── infra/ # Infrastructure-as-Code
│ ├── traefik/ # API Gateway
│ └── databases/ # Scripts thiết lập Database
└── docs/ # Tài liệu (EN & VI)
apps/ # Ứng dụng Frontend
web-client/ # Next.js 14+ (App Router)
mobile-client/ # Flutter
services/ # Backend microservices
_template/ # Template cho service mới
iam-service/ # Identity & Access Management
...
packages/ # Thư viện chia sẻ
logger/ # Structured logging (Winston)
types/ # DTOs & Interfaces chia sẻ
http-client/ # Internal Service Client
tracing/ # Cấu hình OpenTelemetry
infra/ # Infrastructure-as-Code
traefik/ # API Gateway
databases/ # Scripts thiết lập Database
docs/ # Tài liệu (EN & VI)
```
---
@@ -44,11 +44,11 @@ Base/
### Quy ước Đặt tên
* **Files**: `kebab-case.ts` (ví dụ: `user.controller.ts`, `app.config.ts`)
* **Classes**: `PascalCase` (ví dụ: `UserController`, `AuthService`)
* **Functions/Variables**: `camelCase` (ví dụ: `getUserById`, `isValid`)
* **Constants**: `UPPER_SNAKE_CASE` (ví dụ: `MAX_RETRIES`, `DEFAULT_TIMEOUT`)
* **Interfaces**: `PascalCase` (ví dụ: `User`, `CreateUserDto`) - *Không dùng tiền tố 'I'*
* **Files**: `kebab-case.ts` (ví dụ: `user.controller.ts`, `app.config.ts`)
* **Classes**: `PascalCase` (ví dụ: `UserController`, `AuthService`)
* **Functions/Variables**: `camelCase` (ví dụ: `getUserById`, `isValid`)
* **Constants**: `UPPER_SNAKE_CASE` (ví dụ: `MAX_RETRIES`, `DEFAULT_TIMEOUT`)
* **Interfaces**: `PascalCase` (ví dụ: `User`, `CreateUserDto`) - *Không dùng tiền tố 'I'*
### Bilingual Comments (Bình luận Song ngữ)
@@ -64,9 +64,9 @@ async login(dto: LoginDto): Promise<TokenResponse> { ... }
### TypeScript Usage
* **Strict Mode**: Được bật trong `tsconfig.json`. Không cho phép `any` (dùng `unknown` nếu cần).
* **DTOs**: Sử dụng Zod để runtime validation và type inference.
* **Return Types**: Khai báo rõ ràng kiểu trả về cho tất cả public methods.
* **Strict Mode**: Được bật trong `tsconfig.json`. Không cho phép `any` (dùng `unknown` nếu cần).
* **DTOs**: Sử dụng Zod để runtime validation và type inference.
* **Return Types**: Khai báo rõ ràng kiểu trả về cho tất cả public methods.
---
@@ -74,44 +74,44 @@ async login(dto: LoginDto): Promise<TokenResponse> { ... }
### Chiến lược Nhánh (Branching Strategy)
* `main`: Code production-ready.
* `develop`: Nhánh integration cho release tiếp theo.
* `feature/xyz`: Tính năng mới (tách từ `develop`).
* `fix/xyz`: Sửa lỗi (tách từ `develop`).
* `hotfix/xyz`: Sửa lỗi nghiêm trọng (tách từ `main`).
* `main`: Code production-ready.
* `develop`: Nhánh integration cho release tiếp theo.
* `feature/xyz`: Tính năng mới (tách từ `develop`).
* `fix/xyz`: Sửa lỗi (tách từ `develop`).
* `hotfix/xyz`: Sửa lỗi nghiêm trọng (tách từ `main`).
```mermaid
gitGraph
commit id: "Initial"
branch develop
checkout develop
commit id: "Setup"
branch feature/login
checkout feature/login
commit id: "Add login form"
commit id: "Add validation"
checkout develop
merge feature/login
branch feature/dashboard
checkout feature/dashboard
commit id: "Create dashboard"
checkout develop
checkout main
merge develop tag: "v1.0.0"
checkout develop
merge feature/dashboard
checkout main
branch hotfix/security
commit id: "Fix security issue"
checkout main
merge hotfix/security tag: "v1.0.1"
checkout develop
merge hotfix/security
commit id: "Initial"
branch develop
checkout develop
commit id: "Setup"
branch feature/login
checkout feature/login
commit id: "Add login form"
commit id: "Add validation"
checkout develop
merge feature/login
branch feature/dashboard
checkout feature/dashboard
commit id: "Create dashboard"
checkout develop
checkout main
merge develop tag: "v1.0.0"
checkout develop
merge feature/dashboard
checkout main
branch hotfix/security
commit id: "Fix security issue"
checkout main
merge hotfix/security tag: "v1.0.1"
checkout develop
merge hotfix/security
```
### Commit Messages
@@ -134,60 +134,60 @@ chore: update dependencies
```mermaid
graph TD
Start([Bắt đầu tạo API mới]) --> DTO[1. Định nghĩa DTO - Zod Schema]
DTO --> Repo[2. Tạo Repository Method]
Repo --> Service[3. Tạo Service Method - Business Logic]
Service --> Controller[4. Tạo Controller - HTTP Handler]
Controller --> Route[5. Đăng ký Route - Express Router]
Route --> Middleware[6. Thêm Middlewares]
Middleware --> Test[7. Viết Tests]
Test --> Done([API hoàn thành])
Service --> ErrorCheck{Có lỗi?}
ErrorCheck -->|Có| ThrowError[Throw HttpError]
ThrowError --> ErrorHandler[Global Error Handler]
ErrorHandler --> Response[Error Response]
ErrorCheck -->|Không| Success[Success Response]
style Start fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style Done fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style DTO fill:#1e293b,color:#60a5fa
style Repo fill:#1e293b,color:#3b82f6
style Service fill:#2e1a47,color:#a78bfa
style Controller fill:#2d1b0e,color:#fb923c
style Route fill:#1e293b,color:#3b82f6
style Middleware fill:#1e293b,color:#60a5fa
style Test fill:#1e3a2e,color:#4ade80
style ErrorCheck fill:#2d1b0e,color:#fb923c
style ThrowError fill:#3f1a1a,color:#f87171
style ErrorHandler fill:#3f1a1a,color:#f87171
style Response fill:#27272a,color:#a1a1aa
style Success fill:#1e3a2e,color:#4ade80
Start([Bắt đầu tạo API mới]) --> DTO[1. Định nghĩa DTO - Zod Schema]
DTO --> Repo[2. Tạo Repository Method]
Repo --> Service[3. Tạo Service Method - Business Logic]
Service --> Controller[4. Tạo Controller - HTTP Handler]
Controller --> Route[5. Đăng ký Route - Express Router]
Route --> Middleware[6. Thêm Middlewares]
Middleware --> Test[7. Viết Tests]
Test --> Done([API hoàn thành])
Service --> ErrorCheck{Có lỗi?}
ErrorCheck -->|Có| ThrowError[Throw HttpError]
ThrowError --> ErrorHandler[Global Error Handler]
ErrorHandler --> Response[Error Response]
ErrorCheck -->|Không| Success[Success Response]
style Start fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style Done fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style DTO fill:#1e293b,color:#60a5fa
style Repo fill:#1e293b,color:#3b82f6
style Service fill:#2e1a47,color:#a78bfa
style Controller fill:#2d1b0e,color:#fb923c
style Route fill:#1e293b,color:#3b82f6
style Middleware fill:#1e293b,color:#60a5fa
style Test fill:#1e3a2e,color:#4ade80
style ErrorCheck fill:#2d1b0e,color:#fb923c
style ThrowError fill:#3f1a1a,color:#f87171
style ErrorHandler fill:#3f1a1a,color:#f87171
style Response fill:#27272a,color:#a1a1aa
style Success fill:#1e3a2e,color:#4ade80
```
### Tạo API Endpoint Mới
1. **Định nghĩa DTO** (`modules/user/user.dto.ts`):
```typescript
export const CreateUserDto = z.object({
email: z.string().email(),
name: z.string().min(2),
});
export type CreateUserDto = z.infer<typeof CreateUserDto>;
```
1. **Định nghĩa DTO** (`modules/user/user.dto.ts`):
```typescript
export const CreateUserDto = z.object({
email: z.string().email(),
name: z.string().min(2),
});
export type CreateUserDto = z.infer<typeof CreateUserDto>;
```
2. **Tạo Service Method** (`modules/user/user.service.ts`):
* Implement business logic.
* Sử dụng `BaseRepository`.
* Throw `HttpError` (ví dụ: `NotFound`, `BadRequest`).
2. **Tạo Service Method** (`modules/user/user.service.ts`):
* Implement business logic.
* Sử dụng `BaseRepository`.
* Throw `HttpError` (ví dụ: `NotFound`, `BadRequest`).
3. **Tạo Controller** (`modules/user/user.controller.ts`):
* Parse body với DTO: `const dto = CreateUserDto.parse(req.body)`.
* Gọi service.
* Trả về success response: `res.json({ success: true, data: result })`.
3. **Tạo Controller** (`modules/user/user.controller.ts`):
* Parse body với DTO: `const dto = CreateUserDto.parse(req.body)`.
* Gọi service.
* Trả về success response: `res.json({ success: true, data: result })`.
4. **Đăng ký Route** (`modules/user/index.ts`):
* Thêm vào Express router cùng middlewares.
4. **Đăng ký Route** (`modules/user/index.ts`):
* Thêm vào Express router cùng middlewares.
### Xử lý Lỗi (Error Handling)
@@ -197,7 +197,7 @@ Luôn sử dụng các class lỗi tùy chỉnh từ `core/errors`:
import { NotFoundError, ConflictError } from '../../core/errors';
if (!user) {
throw new NotFoundError('User not found');
throw new NotFoundError('User not found');
}
```
@@ -207,74 +207,74 @@ if (!user) {
```mermaid
graph TB
subgraph "Testing Pyramid - Từ dưới lên"
Unit[Unit Tests - Nhiều nhất, Nhanh nhất]
Integration[Integration Tests - Trung bình]
E2E[E2E Tests - Ít nhất, Chậm nhất]
end
Code[Code Changes] --> CheckLint{Lint Pass?}
CheckLint -->|Không| FixLint[Fix Linting Errors]
FixLint --> CheckLint
CheckLint -->|Có| RunUnit[Run Unit Tests]
RunUnit --> UnitPass{Unit Tests Pass?}
UnitPass -->|Không| FixUnit[Fix Unit Tests]
FixUnit --> RunUnit
UnitPass -->|Có| RunIntegration[Run Integration Tests]
RunIntegration --> IntPass{Integration Pass?}
IntPass -->|Không| FixIntegration[Fix Integration]
FixIntegration --> RunIntegration
IntPass -->|Có| RunE2E[Run E2E Tests]
RunE2E --> E2EPass{E2E Pass?}
E2EPass -->|Không| FixE2E[Fix E2E]
FixE2E --> RunE2E
E2EPass -->|Có| Coverage{Coverage > 70%?}
Coverage -->|Không| AddTests[Add More Tests]
AddTests --> RunUnit
Coverage -->|Có| ReadyMerge[Ready to Merge]
style Unit fill:#1e3a2e,color:#4ade80
style Integration fill:#1e293b,color:#60a5fa
style E2E fill:#2e1a47,color:#a78bfa
style Code fill:#1e293b,color:#3b82f6
style CheckLint fill:#2d1b0e,color:#fb923c
style UnitPass fill:#1e3a2e,color:#4ade80
style IntPass fill:#1e293b,color:#60a5fa
style E2EPass fill:#2e1a47,color:#a78bfa
style Coverage fill:#2d1b0e,color:#fbbf24
style RunUnit fill:#1e3a2e,color:#4ade80
style RunIntegration fill:#1e293b,color:#60a5fa
style RunE2E fill:#2e1a47,color:#a78bfa
style ReadyMerge fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style FixLint fill:#3f1a1a,color:#f87171
style FixUnit fill:#3f1a1a,color:#f87171
style FixIntegration fill:#3f1a1a,color:#f87171
style FixE2E fill:#3f1a1a,color:#f87171
style AddTests fill:#2d1b0e,color:#fbbf24
subgraph "Testing Pyramid - Từ dưới lên"
Unit[Unit Tests - Nhiều nhất, Nhanh nhất]
Integration[Integration Tests - Trung bình]
E2E[E2E Tests - Ít nhất, Chậm nhất]
end
Code[Code Changes] --> CheckLint{Lint Pass?}
CheckLint -->|Không| FixLint[Fix Linting Errors]
FixLint --> CheckLint
CheckLint -->|Có| RunUnit[Run Unit Tests]
RunUnit --> UnitPass{Unit Tests Pass?}
UnitPass -->|Không| FixUnit[Fix Unit Tests]
FixUnit --> RunUnit
UnitPass -->|Có| RunIntegration[Run Integration Tests]
RunIntegration --> IntPass{Integration Pass?}
IntPass -->|Không| FixIntegration[Fix Integration]
FixIntegration --> RunIntegration
IntPass -->|Có| RunE2E[Run E2E Tests]
RunE2E --> E2EPass{E2E Pass?}
E2EPass -->|Không| FixE2E[Fix E2E]
FixE2E --> RunE2E
E2EPass -->|Có| Coverage{Coverage > 70%?}
Coverage -->|Không| AddTests[Add More Tests]
AddTests --> RunUnit
Coverage -->|Có| ReadyMerge[Ready to Merge]
style Unit fill:#1e3a2e,color:#4ade80
style Integration fill:#1e293b,color:#60a5fa
style E2E fill:#2e1a47,color:#a78bfa
style Code fill:#1e293b,color:#3b82f6
style CheckLint fill:#2d1b0e,color:#fb923c
style UnitPass fill:#1e3a2e,color:#4ade80
style IntPass fill:#1e293b,color:#60a5fa
style E2EPass fill:#2e1a47,color:#a78bfa
style Coverage fill:#2d1b0e,color:#fbbf24
style RunUnit fill:#1e3a2e,color:#4ade80
style RunIntegration fill:#1e293b,color:#60a5fa
style RunE2E fill:#2e1a47,color:#a78bfa
style ReadyMerge fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
style FixLint fill:#3f1a1a,color:#f87171
style FixUnit fill:#3f1a1a,color:#f87171
style FixIntegration fill:#3f1a1a,color:#f87171
style FixE2E fill:#3f1a1a,color:#f87171
style AddTests fill:#2d1b0e,color:#fbbf24
```
### Unit Tests (`*.test.ts`)
* **Phạm vi**: Các class/function đơn lẻ.
* **Mocking**: Mock tất cả dependencies bên ngoài (DB, services khác) dùng `jest-mock-extended`.
* **Vị trí**: Đặt cùng thư mục với file source.
* **Chạy**: `pnpm test`
* **Phạm vi**: Các class/function đơn lẻ.
* **Mocking**: Mock tất cả dependencies bên ngoài (DB, services khác) dùng `jest-mock-extended`.
* **Vị trí**: Đặt cùng thư mục với file source.
* **Chạy**: `pnpm test`
### E2E Tests (`tests/**/*.e2e.ts`)
* **Phạm vi**: Full API flows (Controller -> Service -> DB).
* **Database**: Sử dụng test database riêng biệt (Dockerized).
* **Chạy**: `pnpm test:e2e`
* **Phạm vi**: Full API flows (Controller -> Service -> DB).
* **Database**: Sử dụng test database riêng biệt (Dockerized).
* **Chạy**: `pnpm test:e2e`
### Linting & Formatting
* **Lint**: `pnpm lint` (ESLint)
* **Format**: `pnpm format` (Prettier)
* **Typecheck**: `pnpm typecheck` (TSC)
* **Lint**: `pnpm lint` (ESLint)
* **Format**: `pnpm format` (Prettier)
* **Typecheck**: `pnpm typecheck` (TSC)
---
@@ -284,15 +284,15 @@ Chúng tôi sử dụng **Prisma** với **Neon PostgreSQL**.
### Migrations
1. Sửa `prisma/schema.prisma`.
2. Tạo migration (Dev):
```bash
./scripts/db/migrate.sh iam-service dev --name add_user_profile
```
3. Áp dụng cho Production (CI/CD):
```bash
./scripts/db/migrate.sh iam-service deploy
```
1. Sửa `prisma/schema.prisma`.
2. Tạo migration (Dev):
```bash
./scripts/db/migrate.sh iam-service dev --name add_user_profile
```
3. Áp dụng cho Production (CI/CD):
```bash
./scripts/db/migrate.sh iam-service deploy
```
### Seed Data

View File

@@ -16,23 +16,23 @@
Trước khi bắt đầu, đảm bảo bạn đã cài đặt:
* **Node.js**: v20.0.0 trở lên (khuyến nghị v22+ hoặc v25+)
```bash
node -v
# v25.2.1
```
* **PNPM**: v8.15.0 trở lên (sử dụng pnpm workspaces)
```bash
pnpm -v
# 8.15.0
```
* **Docker & Docker Compose**: v24.0.0 trở lên cho infrastructure cục bộ
```bash
docker -v
# Docker version 29.1.3, build f52814d
```
* **Git**: Để quản lý version
* **Tài khoản Neon**: Serverless PostgreSQL (https://neon.tech)
* **Node.js**: v20.0.0 trở lên (khuyến nghị v22+ hoặc v25+)
```bash
node -v
# v25.2.1
```
* **PNPM**: v8.15.0 trở lên (sử dụng pnpm workspaces)
```bash
pnpm -v
# 8.15.0
```
* **Docker & Docker Compose**: v24.0.0 trở lên cho infrastructure cục bộ
```bash
docker -v
# Docker version 29.1.3, build f52814d
```
* **Git**: Để quản lý version
* **Tài khoản Neon**: Serverless PostgreSQL (https://neon.tech)
## Tổng quan Kiến trúc
@@ -40,44 +40,44 @@ GoodGo Platform sử dụng kiến trúc microservices với layer infrastructur
```mermaid
graph TD
Client[Client Apps] --> Traefik[Traefik Gateway]
Traefik --> IAM[IAM Service]
Traefik --> Template[Template Service]
IAM --> DB[(Neon PostgreSQL)]
IAM --> Redis[(Redis Cache)]
IAM --> Kafka[Kafka Events]
style Client fill:#7F8C8D,color:#fff
style Traefik fill:#2980B9,color:#fff
style IAM fill:#27AE60,color:#fff
style Template fill:#E67E22,color:#fff
style DB fill:#8E44AD,color:#fff
style Redis fill:#F39C12,color:#fff
style Kafka fill:#3498DB,color:#fff
Client[Client Apps] --> Traefik[Traefik Gateway]
Traefik --> IAM[IAM Service]
Traefik --> Template[Template Service]
IAM --> DB[(Neon PostgreSQL)]
IAM --> Redis[(Redis Cache)]
IAM --> Kafka[Kafka Events]
style Client fill:#7F8C8D,color:#fff
style Traefik fill:#2980B9,color:#fff
style IAM fill:#27AE60,color:#fff
style Template fill:#E67E22,color:#fff
style DB fill:#8E44AD,color:#fff
style Redis fill:#F39C12,color:#fff
style Kafka fill:#3498DB,color:#fff
```
### Color Palette / Bảng màu
```mermaid
graph LR
A["Primary #2980B9"] --> B["Data/Cache #F39C12"]
B --> C["Success #27AE60"]
C --> D["Warning #E67E22"]
D --> E["Error #C0392B"]
E --> F["Processing #8E44AD"]
F --> G["Info #3498DB"]
G --> H["Neutral #7F8C8D"]
style A fill:#2980B9,color:#fff
style B fill:#F39C12,color:#fff
style C fill:#27AE60,color:#fff
style D fill:#E67E22,color:#fff
style E fill:#C0392B,color:#fff
style F fill:#8E44AD,color:#fff
style G fill:#3498DB,color:#fff
style H fill:#7F8C8D,color:#fff
A["Primary #2980B9"] --> B["Data/Cache #F39C12"]
B --> C["Success #27AE60"]
C --> D["Warning #E67E22"]
D --> E["Error #C0392B"]
E --> F["Processing #8E44AD"]
F --> G["Info #3498DB"]
G --> H["Neutral #7F8C8D"]
style A fill:#2980B9,color:#fff
style B fill:#F39C12,color:#fff
style C fill:#27AE60,color:#fff
style D fill:#E67E22,color:#fff
style E fill:#C0392B,color:#fff
style F fill:#8E44AD,color:#fff
style G fill:#3498DB,color:#fff
style H fill:#7F8C8D,color:#fff
```
## Cấu trúc Dự án
@@ -86,42 +86,42 @@ Repository tuân theo cấu trúc monorepo:
```
Base/
├── apps/ # Ứng dụng Frontend
│ ├── app-admin/ # Admin dashboard application
│ ├── app-client/ # Client mobile application (Flutter)
│ ├── web-client/ # Next.js web application
│ └── web-docs/ # Documentation website (Next.js)
├── services/ # Backend microservices
│ ├── iam-service/ # Service xác thực & phân quyền
│ └── _template/ # Template cho service mới
├── packages/ # Thư viện chia sẻ (Shared libraries)
│ ├── auth-sdk/ # Authentication SDK
│ ├── config/ # Shared configuration utilities
│ ├── http-client/ # Client HTTP nội bộ
│ ├── logger/ # Structured logging (@goodgo/logger)
│ ├── tracing/ # OpenTelemetry tracing
│ └── types/ # TypeScript types chia sẻ
├── infra/ # Cấu hình Infrastructure
│ ├── databases/ # Scripts thiết lập Database
│ ├── docker/ # Docker configurations
│ ├── observability/ # Prometheus, Grafana, Loki configs
│ ├── secrets/ # Secrets management templates
│ └── traefik/ # Cấu hình API Gateway
├── deployments/ # Cấu hình Deploy
│ ├── local/ # Docker Compose cho dev
│ ├── staging/ # Staging environment configs
│ └── production/ # Production Kubernetes manifests
├── scripts/ # Automation scripts
│ ├── build/ # Build scripts
│ ├── db/ # Database utilities
│ ├── deploy/ # Deployment scripts
│ ├── dev/ # Development helpers
│ ├── observability/ # Monitoring setup scripts
│ ├── setup/ # Initial setup scripts
│ └── utils/ # Utility scripts
└── docs/ # Tài liệu
├── en/ # English documentation
└── vi/ # Vietnamese documentation
apps/ # Ứng dụng Frontend
app-admin/ # Admin dashboard application
app-client/ # Client mobile application (Flutter)
web-client/ # Next.js web application
web-docs/ # Documentation website (Next.js)
services/ # Backend microservices
iam-service/ # Service xác thực & phân quyền
_template/ # Template cho service mới
packages/ # Thư viện chia sẻ (Shared libraries)
auth-sdk/ # Authentication SDK
config/ # Shared configuration utilities
http-client/ # Client HTTP nội bộ
logger/ # Structured logging (@goodgo/logger)
tracing/ # OpenTelemetry tracing
types/ # TypeScript types chia sẻ
infra/ # Cấu hình Infrastructure
databases/ # Scripts thiết lập Database
docker/ # Docker configurations
observability/ # Prometheus, Grafana, Loki configs
secrets/ # Secrets management templates
traefik/ # Cấu hình API Gateway
deployments/ # Cấu hình Deploy
local/ # Docker Compose cho dev
staging/ # Staging environment configs
production/ # Production Kubernetes manifests
scripts/ # Automation scripts
build/ # Build scripts
db/ # Database utilities
deploy/ # Deployment scripts
dev/ # Development helpers
observability/ # Monitoring setup scripts
setup/ # Initial setup scripts
utils/ # Utility scripts
docs/ # Tài liệu
en/ # English documentation
vi/ # Vietnamese documentation
```
## Cài đặt & Thiết lập
@@ -146,10 +146,10 @@ Mỗi service và infrastructure cục bộ cần biến môi trường. Chúng
Dự án sử dụng Neon (Serverless PostgreSQL) cho mọi môi trường.
1. Tạo project tại [neon.tech](https://neon.tech).
2. Tạo branch tên `dev` (hoặc `main`).
3. Lấy Connection String từ dashboard.
4. Cập nhật file `deployments/local/.env.local`:
1. Tạo project tại [neon.tech](https://neon.tech).
2. Tạo branch tên `dev` (hoặc `main`).
3. Lấy Connection String từ dashboard.
4. Cập nhật file `deployments/local/.env.local`:
```env
DATABASE_URL="postgres://user:pass@ep-xyz.region.neon.tech/neondb"
@@ -194,20 +194,20 @@ pnpm --filter @goodgo/iam-service dev
### Tạo Service Mới
1. Copy từ template:
```bash
cp -r services/_template services/my-new-service
```
2. Cập nhật tên trong `package.json`.
3. Thêm logic trong `src/modules/`.
4. Đăng ký trong `deployments/local/docker-compose.yml`.
1. Copy từ template:
```bash
cp -r services/_template services/my-new-service
```
2. Cập nhật tên trong `package.json`.
3. Thêm logic trong `src/modules/`.
4. Đăng ký trong `deployments/local/docker-compose.yml`.
### Thực hiện Thay đổi
1. Tạo branch mới: `feature/my-feature`.
2. Implement thay đổi.
3. Chạy tests: `pnpm test`.
4. Commit với conventional commits: `feat(iam): add login endpoint`.
1. Tạo branch mới: `feature/my-feature`.
2. Implement thay đổi.
3. Chạy tests: `pnpm test`.
4. Commit với conventional commits: `feat(iam): add login endpoint`.
## Các Lệnh Thường dùng
@@ -239,21 +239,21 @@ kill -9 <PID>
**Lỗi**: `P1001: Can't reach database server`
**Giải pháp**:
1. Kiểm tra kết nối internet (Neon là cloud DB).
2. Kiểm tra `DATABASE_URL` trong `deployments/local/.env.local`.
3. Đảm bảo IP của bạn được allow trong Neon dashboard.
1. Kiểm tra kết nối internet (Neon là cloud DB).
2. Kiểm tra `DATABASE_URL` trong `deployments/local/.env.local`.
3. Đảm bảo IP của bạn được allow trong Neon dashboard.
### Gateway Không Tìm Thấy Service
**Lỗi**: `404 Not Found` từ api.localhost
**Giải pháp**:
1. Kiểm tra service có đang chạy không.
2. Kiểm tra Traefik dashboard tại http://localhost:8080.
3. Kiểm tra labels `PathPrefix` trong `docker-compose.yml`.
1. Kiểm tra service có đang chạy không.
2. Kiểm tra Traefik dashboard tại http://localhost:8080.
3. Kiểm tra labels `PathPrefix` trong `docker-compose.yml`.
## Bước Tiếp Theo
* [Hướng dẫn Development](development.md) - Chi tiết chuẩn code và quy trình
* [Tài liệu API](../api/openapi/) - Khám phá các API endpoints
* [Kiến trúc Hệ thống](../architecture/system-design.md) - Hiểu về thiết kế hệ thống
* [Hướng dẫn Development](development.md) - Chi tiết chuẩn code và quy trình
* [Tài liệu API](../api/openapi/) - Khám phá các API endpoints
* [Kiến trúc Hệ thống](../architecture/system-design.md) - Hiểu về thiết kế hệ thống

View File

@@ -6,105 +6,105 @@ Tài liệu này hướng dẫn cách migrate từ `auth-service` sang `iam-serv
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.
### 🔄 Migration Process Flow
### Migration Process Flow
```mermaid
graph TD
Start([🚀 Bắt đầu Migration]) --> Backup[📦 Step 1: Backup<br/>Database & Code]
Backup --> Update[🔧 Step 2: Update Codebase<br/>Package refs, Env vars]
Update --> Migrate[🗄️ Step 3: Run Prisma Migration<br/>Add IAM models]
Migrate --> Deploy{🚀 Deployment Strategy}
Deploy -->|Khuyến nghị| BlueGreen[💚 Blue-Green Deployment]
Deploy -->|Dễ dàng hơn| InPlace[ In-Place Migration]
BlueGreen --> DeployNew[Deploy IAM Service mới]
DeployNew --> Verify1[ Verify hoạt động]
Verify1 --> Switch[🔀 Switch traffic]
Switch --> Monitor1[📊 Monitor]
Monitor1 --> Success{Thành công?}
InPlace --> DeployBoth[Deploy cả 2 service]
DeployBoth --> GradualRoute[🔀 Gradually route traffic]
GradualRoute --> Monitor2[📊 Monitor]
Monitor2 --> Success
Success -->|Yes| Cleanup[🧹 Decommission Auth Service]
Success -->|No| Rollback[⏮ Rollback]
Cleanup --> Complete([ Migration Hoàn Thành])
Rollback --> End([ Migration Failed])
style Start fill:#1a472a,stroke:#2d8659,stroke-width:3px,color:#fff
style Complete fill:#1a472a,stroke:#2d8659,stroke-width:3px,color:#fff
style End fill:#4a1a1a,stroke:#8b2e2e,stroke-width:3px,color:#fff
style Backup fill:#1e3a5f,stroke:#2e5984,color:#fff
style Update fill:#1e3a5f,stroke:#2e5984,color:#fff
style Migrate fill:#1e3a5f,stroke:#2e5984,color:#fff
style Deploy fill:#4a2c5f,stroke:#6b4391,color:#fff
style BlueGreen fill:#2d5016,stroke:#4a7c2c,color:#fff
style InPlace fill:#5f4a1e,stroke:#8b7030,color:#fff
style DeployNew fill:#1e3a5f,stroke:#2e5984,color:#fff
style Verify1 fill:#1e3a5f,stroke:#2e5984,color:#fff
style Switch fill:#1e3a5f,stroke:#2e5984,color:#fff
style Monitor1 fill:#1e3a5f,stroke:#2e5984,color:#fff
style DeployBoth fill:#1e3a5f,stroke:#2e5984,color:#fff
style GradualRoute fill:#1e3a5f,stroke:#2e5984,color:#fff
style Monitor2 fill:#1e3a5f,stroke:#2e5984,color:#fff
style Success fill:#4a2c5f,stroke:#6b4391,color:#fff
style Cleanup fill:#1e3a5f,stroke:#2e5984,color:#fff
style Rollback fill:#4a1a1a,stroke:#8b2e2e,color:#fff
Start([ Bắt đầu Migration]) --> Backup[ Step 1: Backup<br/>Database & Code]
Backup --> Update[ Step 2: Update Codebase<br/>Package refs, Env vars]
Update --> Migrate[ Step 3: Run Prisma Migration<br/>Add IAM models]
Migrate --> Deploy{ Deployment Strategy}
Deploy -->|Khuyến nghị| BlueGreen[ Blue-Green Deployment]
Deploy -->|Dễ dàng hơn| InPlace[ In-Place Migration]
BlueGreen --> DeployNew[Deploy IAM Service mới]
DeployNew --> Verify1[ Verify hoạt động]
Verify1 --> Switch[ Switch traffic]
Switch --> Monitor1[ Monitor]
Monitor1 --> Success{Thành công?}
InPlace --> DeployBoth[Deploy cả 2 service]
DeployBoth --> GradualRoute[ Gradually route traffic]
GradualRoute --> Monitor2[ Monitor]
Monitor2 --> Success
Success -->|Yes| Cleanup[ Decommission Auth Service]
Success -->|No| Rollback[⏮ Rollback]
Cleanup --> Complete([ Migration Hoàn Thành])
Rollback --> End([ Migration Failed])
style Start fill:#1a472a,stroke:#2d8659,stroke-width:3px,color:#fff
style Complete fill:#1a472a,stroke:#2d8659,stroke-width:3px,color:#fff
style End fill:#4a1a1a,stroke:#8b2e2e,stroke-width:3px,color:#fff
style Backup fill:#1e3a5f,stroke:#2e5984,color:#fff
style Update fill:#1e3a5f,stroke:#2e5984,color:#fff
style Migrate fill:#1e3a5f,stroke:#2e5984,color:#fff
style Deploy fill:#4a2c5f,stroke:#6b4391,color:#fff
style BlueGreen fill:#2d5016,stroke:#4a7c2c,color:#fff
style InPlace fill:#5f4a1e,stroke:#8b7030,color:#fff
style DeployNew fill:#1e3a5f,stroke:#2e5984,color:#fff
style Verify1 fill:#1e3a5f,stroke:#2e5984,color:#fff
style Switch fill:#1e3a5f,stroke:#2e5984,color:#fff
style Monitor1 fill:#1e3a5f,stroke:#2e5984,color:#fff
style DeployBoth fill:#1e3a5f,stroke:#2e5984,color:#fff
style GradualRoute fill:#1e3a5f,stroke:#2e5984,color:#fff
style Monitor2 fill:#1e3a5f,stroke:#2e5984,color:#fff
style Success fill:#4a2c5f,stroke:#6b4391,color:#fff
style Cleanup fill:#1e3a5f,stroke:#2e5984,color:#fff
style Rollback fill:#4a1a1a,stroke:#8b2e2e,color:#fff
```
### 🏗️ Architecture Evolution
### Architecture Evolution
```mermaid
graph TB
subgraph Before["Auth Service (Trước)"]
AuthAPI[🔐 Authentication APIs<br/>/api/v1/auth/*]
RBACAPI[👥 RBAC APIs<br/>/api/v1/rbac/*]
MFAAPI[🔒 MFA APIs<br/>/api/v1/mfa/*]
SessionAPI[🎫 Session APIs<br/>/api/v1/sessions/*]
OIDCAPI[🆔 OIDC APIs<br/>/api/v1/oidc/*]
end
subgraph After["IAM Service (Sau)"]
AuthAPI2[🔐 Authentication APIs<br/>/api/v1/auth/*<br/> Giữ nguyên]
RBACAPI2[👥 RBAC APIs<br/>/api/v1/rbac/*<br/> Giữ nguyên]
MFAAPI2[🔒 MFA APIs<br/>/api/v1/mfa/*<br/> Giữ nguyên]
SessionAPI2[🎫 Session APIs<br/>/api/v1/sessions/*<br/> Giữ nguyên]
OIDCAPI2[🆔 OIDC APIs<br/>/api/v1/oidc/*<br/> Giữ nguyên]
IdentityAPI[🆔 Identity Management<br/>/api/v1/identity/*<br/> MỚI]
AccessAPI[🔑 Access Management<br/>/api/v1/access/*<br/> MỚI]
GovernanceAPI[📋 Governance<br/>/api/v1/governance/*<br/> MỚI]
end
Before -.->|Backward Compatible<br/>Migration| After
style Before fill:#2d2d2d,stroke:#4a4a4a,color:#fff
style After fill:#1a472a,stroke:#2d8659,color:#fff
style AuthAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style RBACAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style MFAAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style SessionAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style OIDCAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style AuthAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style RBACAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style MFAAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style SessionAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style OIDCAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style IdentityAPI fill:#4a2c5f,stroke:#6b4391,color:#fff
style AccessAPI fill:#4a2c5f,stroke:#6b4391,color:#fff
style GovernanceAPI fill:#4a2c5f,stroke:#6b4391,color:#fff
subgraph Before["Auth Service (Trước)"]
AuthAPI[ Authentication APIs<br/>/api/v1/auth/*]
RBACAPI[ RBAC APIs<br/>/api/v1/rbac/*]
MFAAPI[ MFA APIs<br/>/api/v1/mfa/*]
SessionAPI[ Session APIs<br/>/api/v1/sessions/*]
OIDCAPI[ OIDC APIs<br/>/api/v1/oidc/*]
end
subgraph After["IAM Service (Sau)"]
AuthAPI2[ Authentication APIs<br/>/api/v1/auth/*<br/> Giữ nguyên]
RBACAPI2[ RBAC APIs<br/>/api/v1/rbac/*<br/> Giữ nguyên]
MFAAPI2[ MFA APIs<br/>/api/v1/mfa/*<br/> Giữ nguyên]
SessionAPI2[ Session APIs<br/>/api/v1/sessions/*<br/> Giữ nguyên]
OIDCAPI2[ OIDC APIs<br/>/api/v1/oidc/*<br/> Giữ nguyên]
IdentityAPI[ Identity Management<br/>/api/v1/identity/*<br/> MỚI]
AccessAPI[ Access Management<br/>/api/v1/access/*<br/> MỚI]
GovernanceAPI[ Governance<br/>/api/v1/governance/*<br/> MỚI]
end
Before -.->|Backward Compatible<br/>Migration| After
style Before fill:#2d2d2d,stroke:#4a4a4a,color:#fff
style After fill:#1a472a,stroke:#2d8659,color:#fff
style AuthAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style RBACAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style MFAAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style SessionAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style OIDCAPI fill:#1e3a5f,stroke:#2e5984,color:#fff
style AuthAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style RBACAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style MFAAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style SessionAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style OIDCAPI2 fill:#2d5016,stroke:#4a7c2c,color:#fff
style IdentityAPI fill:#4a2c5f,stroke:#6b4391,color:#fff
style AccessAPI fill:#4a2c5f,stroke:#6b4391,color:#fff
style GovernanceAPI fill:#4a2c5f,stroke:#6b4391,color:#fff
```
## Backward Compatibility
**Tất cả các endpoints hiện tại vẫn hoạt động bình thường:**
**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/rbac/*` - RBAC endpoints
- `/api/v1/mfa/*` - MFA endpoints
- `/api/v1/sessions/*` - Session management endpoints
- `/api/v1/oidc/*` - OIDC endpoints
@@ -195,62 +195,62 @@ 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'
```
```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
- 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
```
```bash
cd services/iam-service
pnpm prisma generate
pnpm prisma migrate dev --name add_iam_models
```
### Step 3: Deployment
#### 🎯 Deployment Strategy Comparison
#### Deployment Strategy Comparison
```mermaid
graph LR
subgraph BlueGreen["💚 Blue-Green Deployment (Khuyến nghị)"]
BG1[Ưu điểm:<br/> Zero downtime<br/> Easy rollback<br/> Safe testing]
BG2[Nhược điểm:<br/>⚠️ Cần thêm resources<br/>⚠️ Phức tạp hơn]
end
subgraph InPlace[" In-Place Migration"]
IP1[Ưu điểm:<br/> Simple setup<br/> Less resources<br/> Gradual migration]
IP2[Nhược điểm:<br/>⚠️ Potential downtime<br/>⚠️ Harder rollback<br/>⚠️ Higher risk]
end
Decision{Chọn Strategy} -->|Production| BlueGreen
Decision -->|Staging/Dev| InPlace
style BlueGreen fill:#1a472a,stroke:#2d8659,color:#fff
style InPlace fill:#5f4a1e,stroke:#8b7030,color:#fff
style BG1 fill:#2d5016,stroke:#4a7c2c,color:#fff
style BG2 fill:#4a1a1a,stroke:#8b2e2e,color:#fff
style IP1 fill:#2d5016,stroke:#4a7c2c,color:#fff
style IP2 fill:#4a1a1a,stroke:#8b2e2e,color:#fff
style Decision fill:#4a2c5f,stroke:#6b4391,color:#fff
subgraph BlueGreen[" Blue-Green Deployment (Khuyến nghị)"]
BG1[Ưu điểm:<br/> Zero downtime<br/> Easy rollback<br/> Safe testing]
BG2[Nhược điểm:<br/> Cần thêm resources<br/> Phức tạp hơn]
end
subgraph InPlace[" In-Place Migration"]
IP1[Ưu điểm:<br/> Simple setup<br/> Less resources<br/> Gradual migration]
IP2[Nhược điểm:<br/> Potential downtime<br/> Harder rollback<br/> Higher risk]
end
Decision{Chọn Strategy} -->|Production| BlueGreen
Decision -->|Staging/Dev| InPlace
style BlueGreen fill:#1a472a,stroke:#2d8659,color:#fff
style InPlace fill:#5f4a1e,stroke:#8b7030,color:#fff
style BG1 fill:#2d5016,stroke:#4a7c2c,color:#fff
style BG2 fill:#4a1a1a,stroke:#8b2e2e,color:#fff
style IP1 fill:#2d5016,stroke:#4a7c2c,color:#fff
style IP2 fill:#4a1a1a,stroke:#8b2e2e,color:#fff
style Decision fill:#4a2c5f,stroke:#6b4391,color:#fff
```
#### Option A: Blue-Green Deployment (Khuyến Nghị)
1. **Deploy iam-service mới:**
```bash
kubectl apply -f deployments/staging/kubernetes/iam-service.yaml
```
```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
- Update Ingress để point đến `iam-service`
- Hoặc dùng weighted routing để gradually migrate
4. **Monitor và verify**
@@ -318,11 +318,11 @@ Nếu gặp vấn đề trong quá trình migration, vui lòng:
2. Review migration guide này
3. Contact team lead hoặc DevOps team
## 💡 Quick Tips
## Quick Tips
### Migration Best Practices
**DO:**
**DO:**
- Backup database trước khi migrate
- Test migration trên staging trước
- Monitor metrics trong quá trình migration
@@ -330,7 +330,7 @@ Nếu gặp vấn đề trong quá trình migration, vui lòng:
- Prepare rollback plan trước khi deploy
- Document tất cả các thay đổi
**DON'T:**
**DON'T:**
- Skip backup step
- Migrate trực tiếp trên production
- Ignore error logs
@@ -342,11 +342,11 @@ Nếu gặp vấn đề trong quá trình migration, vui lòng:
| Vấn đề | Nguyên nhân | Giải pháp |
|--------|-------------|-----------|
| 🔴 Migration failed | Database connection | Check `DATABASE_URL` trong `.env` |
| 🔴 Service won't start | Missing env vars | Verify tất cả env vars được set |
| 🟡 Slow performance | Database indexes | Run Prisma migrations đầy đủ |
| 🟡 Connection timeout | Network issues | Check firewall & security groups |
| 🔵 New endpoints 404 | Routing config | Update Traefik/Ingress config |
| Migration failed | Database connection | Check `DATABASE_URL` trong `.env` |
| Service won't start | Missing env vars | Verify tất cả env vars được set |
| Slow performance | Database indexes | Run Prisma migrations đầy đủ |
| Connection timeout | Network issues | Check firewall & security groups |
| New endpoints 404 | Routing config | Update Traefik/Ingress config |
### Troubleshooting Quick Reference
@@ -366,28 +366,28 @@ curl http://localhost:5001/health/ready
psql $DATABASE_URL -c "SELECT 1"
# Rollback migration (CAREFUL!)
pnpm prisma migrate reset # DEV ONLY
pnpm prisma migrate reset # DEV ONLY
kubectl rollout undo deployment/iam-service
```
### 📊 Color Palette Reference
### Color Palette Reference
**Diagram Colors:**
- 🟢 **Success/Recommended**: `#1a472a` (Dark green)
- 🔵 **Process/Info**: `#1e3a5f` (Dark blue)
- 🟣 **Decision/Important**: `#4a2c5f` (Dark purple)
- 🟡 **Warning/Alternative**: `#5f4a1e` (Dark yellow)
- 🔴 **Error/Rollback**: `#4a1a1a` (Dark red)
- **Success/Recommended**: `#1a472a` (Dark green)
- **Process/Info**: `#1e3a5f` (Dark blue)
- **Decision/Important**: `#4a2c5f` (Dark purple)
- **Warning/Alternative**: `#5f4a1e` (Dark yellow)
- **Error/Rollback**: `#4a1a1a` (Dark red)
### ⚠️ Important Reminders
### Important Reminders
- 📦 **Always backup** trước khi migrate
- 🧪 **Test thoroughly** trên staging
- 📊 **Monitor closely** sau khi deploy
- 🔄 **Prepare rollback** plan
- 📝 **Document changes** cho team
- **Always backup** trước khi migrate
- **Test thoroughly** trên staging
- **Monitor closely** sau khi deploy
- **Prepare rollback** plan
- **Document changes** cho team
-**Schedule wisely** - tránh giờ peak
- 🤝 **Communicate** với team và stakeholders
- **Communicate** với team và stakeholders
---

View File

@@ -6,33 +6,33 @@
```mermaid
graph TD
Start([🚀 Bắt đầu]) --> EnvPrep[1. Chuẩn bị Môi trường]
EnvPrep --> BuildImg[2. Build Docker Image]
BuildImg --> LoadImg[3. Load Image vào Cluster]
LoadImg --> Secrets[4. Cấu hình Secrets & Environment]
Secrets --> Deploy[5. Deploy Service]
Deploy --> Verify[6. Kiểm tra & Verify]
Verify --> Test[7. Test Service]
Test --> End([ Hoàn tất])
Start([ Bắt đầu]) --> EnvPrep[1. Chuẩn bị Môi trường]
EnvPrep --> BuildImg[2. Build Docker Image]
BuildImg --> LoadImg[3. Load Image vào Cluster]
LoadImg --> Secrets[4. Cấu hình Secrets & Environment]
Secrets --> Deploy[5. Deploy Service]
Deploy --> Verify[6. Kiểm tra & Verify]
Verify --> Test[7. Test Service]
Test --> End([ Hoàn tất])
subgraph "Chi tiết Deploy"
Deploy --> |Apply| ConfigMap[ConfigMap]
Deploy --> |Apply| Deployment[Deployment]
Deploy --> |Apply| Service[Service]
end
style Start fill:#1a1a2e,color:#fff
style End fill:#0f3460,color:#fff
style EnvPrep fill:#16213e,color:#fff
style BuildImg fill:#1a1a40,color:#fff
style LoadImg fill:#1a1a40,color:#fff
style Secrets fill:#0f4c75,color:#fff
style Deploy fill:#3282b8,color:#fff
style Verify fill:#3282b8,color:#fff
style Test fill:#3282b8,color:#fff
style ConfigMap fill:#16213e,color:#fff
style Deployment fill:#16213e,color:#fff
style Service fill:#16213e,color:#fff
subgraph "Chi tiết Deploy"
Deploy --> |Apply| ConfigMap[ConfigMap]
Deploy --> |Apply| Deployment[Deployment]
Deploy --> |Apply| Service[Service]
end
style Start fill:#1a1a2e,color:#fff
style End fill:#0f3460,color:#fff
style EnvPrep fill:#16213e,color:#fff
style BuildImg fill:#1a1a40,color:#fff
style LoadImg fill:#1a1a40,color:#fff
style Secrets fill:#0f4c75,color:#fff
style Deploy fill:#3282b8,color:#fff
style Verify fill:#3282b8,color:#fff
style Test fill:#3282b8,color:#fff
style ConfigMap fill:#16213e,color:#fff
style Deployment fill:#16213e,color:#fff
style Service fill:#16213e,color:#fff
```
## Tổng Quan
@@ -45,19 +45,19 @@ Hướng dẫn này mô tả chi tiết cách deploy IAM Service (hoặc bất k
### Phần Mềm
- **Docker Desktop 4.0+**: [Download Link](https://www.docker.com/products/docker-desktop/)
- Kubernetes phải được enable trong settings.
- Kubernetes phải được enable trong settings.
- **kubectl CLI**: Công cụ dòng lệnh để tương tác với K8s.
```bash
brew install kubectl
```
```bash
brew install kubectl
```
- **kind CLI**: Cần thiết để load images vào cluster nếu dùng Kind backend (mặc định cho dev).
```bash
brew install kind
```
```bash
brew install kind
```
- **pnpm 8+**: Package manager của dự án.
```bash
npm install -g pnpm
```
```bash
npm install -g pnpm
```
### Kiến Thức
- Hiểu cơ bản về các khái niệm Kubernetes: **Pod**, **Deployment**, **Service**, **Secret**, **ConfigMap**.
@@ -69,7 +69,7 @@ Hướng dẫn này mô tả chi tiết cách deploy IAM Service (hoặc bất k
### 2.1 Enable Kubernetes trong Docker Desktop
1. Mở **Docker Desktop**.
2. Nhấn vào biểu tượng **Settings (⚙️)**.
2. Nhấn vào biểu tượng **Settings ()**.
3. Chọn tab **Kubernetes**.
4. Check vào ô **Enable Kubernetes**.
5. Chọn **Show system containers (advanced)** để dễ debug (tùy chọn).
@@ -88,8 +88,8 @@ kubectl config current-context
# Liệt kê các node trong cluster
kubectl get nodes
# Output mong đợi:
# NAME STATUS ROLES AGE VERSION
# docker-desktop Ready control-plane 10m v1.29.1
# NAME STATUS ROLES AGE VERSION
# docker-desktop Ready control-plane 10m v1.29.1
```
## 3. Build Docker Image
@@ -107,12 +107,12 @@ docker build -t iam-service:local -f ../../../services/iam-service/Dockerfile ..
# Kiểm tra image đã build thành công chưa
docker images | grep iam-service
# Output mong đợi:
# iam-service local [IMAGE_ID] [SIZE] [CREATED]
# iam-service local [IMAGE_ID] [SIZE] [CREATED]
```
## 4. Load Image vào Cluster
**⚠️ QUAN TRỌNG**: Docker Desktop có thể sử dụng các backend khác nhau. Nếu bạn đang chạy Kubernetes trong Docker Desktop, đôi khi nó không nhìn thấy image local ngay lập tức nếu sử dụng `kind` node dưới nền.
** QUAN TRỌNG**: Docker Desktop có thể sử dụng các backend khác nhau. Nếu bạn đang chạy Kubernetes trong Docker Desktop, đôi khi nó không nhìn thấy image local ngay lập tức nếu sử dụng `kind` node dưới nền.
Nếu bạn dùng **Kind** (Kubernetes in Docker) riêng biệt hoặc cấu hình Docker Desktop đặc biệt, bạn cần load image:
@@ -139,11 +139,11 @@ kubectl create namespace iam-local
# Tạo secrets ngẫu nhiên và lưu vào Kubernetes
kubectl create secret generic iam-service-secrets \
--from-literal=DATABASE_URL="postgresql://user:password@host.docker.internal:5432/iam_db?schema=public" \
--from-literal=JWT_SECRET="$(openssl rand -base64 32)" \
--from-literal=JWT_REFRESH_SECRET="$(openssl rand -base64 32)" \
--from-literal=ENCRYPTION_KEY="$(openssl rand -base64 32)" \
-n iam-local
--from-literal=DATABASE_URL="postgresql://user:password@host.docker.internal:5432/iam_db?schema=public" \
--from-literal=JWT_SECRET="$(openssl rand -base64 32)" \
--from-literal=JWT_REFRESH_SECRET="$(openssl rand -base64 32)" \
--from-literal=ENCRYPTION_KEY="$(openssl rand -base64 32)" \
-n iam-local
# Kiểm tra secrets đã tạo
kubectl get secrets -n iam-local
@@ -183,8 +183,8 @@ Sau khi deploy, cần đảm bảo Pod đang chạy ổn định (Running).
kubectl get pods -n iam-local
# Output mong đợi:
# NAME READY STATUS RESTARTS AGE
# iam-service-68994fdc79-gh2mj 1/1 Running 0 30s
# NAME READY STATUS RESTARTS AGE
# iam-service-68994fdc79-gh2mj 1/1 Running 0 30s
```
### 7.2 Xem Logs Chi Tiết
@@ -201,17 +201,17 @@ kubectl describe pod -n iam-local -l app=iam-service
### 7.3 Lỗi Thường Gặp
1. **ImagePullBackOff**:
- **Lý do**: K8s không tìm thấy image `iam-service:local`.
- **Fix**: Đảm bảo `imagePullPolicy: IfNotPresent` hoặc `Never` trong file yaml deployment local. Nếu dùng Kind, nhớ chạy lệnh `kind load`.
1. **ImagePullBackOff**:
- **Lý do**: K8s không tìm thấy image `iam-service:local`.
- **Fix**: Đảm bảo `imagePullPolicy: IfNotPresent` hoặc `Never` trong file yaml deployment local. Nếu dùng Kind, nhớ chạy lệnh `kind load`.
2. **CrashLoopBackOff**:
- **Lý do**: Lỗi runtime, thường là không kết nối được Database.
- **Fix**: Check biến `DATABASE_URL` trong Secret. Đảm bảo Postgres đang chạy và accessible từ K8s (dùng `host.docker.internal`).
2. **CrashLoopBackOff**:
- **Lý do**: Lỗi runtime, thường là không kết nối được Database.
- **Fix**: Check biến `DATABASE_URL` trong Secret. Đảm bảo Postgres đang chạy và accessible từ K8s (dùng `host.docker.internal`).
3. **Pending Service**:
- **Lý do**: Type `LoadBalancer` trên local đôi khi mãi pending IP.
- **Fix**: Không sao cả, chúng ta có thể dùng `port-forward` hoặc truy cập qua `localhost`.
3. **Pending Service**:
- **Lý do**: Type `LoadBalancer` trên local đôi khi mãi pending IP.
- **Fix**: Không sao cả, chúng ta có thể dùng `port-forward` hoặc truy cập qua `localhost`.
## 8. Test Service Access
@@ -249,64 +249,64 @@ kubectl delete namespace iam-local
## Quick Tips
### 🔍 Các Vấn Đề Thường Gặp & Giải Pháp
### Các Vấn Đề Thường Gặp & Giải Pháp
| Vấn đề | Triệu chứng | Giải pháp |
|--------|-------------|-----------|
| 🔴 **ImagePullBackOff** | Pod bị kẹt ở trạng thái `ImagePullBackOff` | Đặt `imagePullPolicy: Never` trong deployment YAML<br/>Chạy `kind load docker-image` nếu dùng Kind |
| 🔴 **CrashLoopBackOff** | Pod liên tục restart | Kiểm tra logs với `kubectl logs`<br/>Verify `DATABASE_URL` trong secrets<br/>Đảm bảo DB accessible qua `host.docker.internal` |
| 🟡 **Pending LoadBalancer** | Service External-IP hiển thị `<pending>` | Bình thường trên local—dùng `kubectl port-forward` thay thế |
| 🟡 **Connection Refused** | Không kết nối được sau port-forward | Kiểm tra pod đang `Running` (không phải `CrashLoopBackOff`)<br/>Verify port mapping chính xác |
| **ImagePullBackOff** | Pod bị kẹt ở trạng thái `ImagePullBackOff` | Đặt `imagePullPolicy: Never` trong deployment YAML<br/>Chạy `kind load docker-image` nếu dùng Kind |
| **CrashLoopBackOff** | Pod liên tục restart | Kiểm tra logs với `kubectl logs`<br/>Verify `DATABASE_URL` trong secrets<br/>Đảm bảo DB accessible qua `host.docker.internal` |
| **Pending LoadBalancer** | Service External-IP hiển thị `<pending>` | Bình thường trên local—dùng `kubectl port-forward` thay thế |
| **Connection Refused** | Không kết nối được sau port-forward | Kiểm tra pod đang `Running` (không phải `CrashLoopBackOff`)<br/>Verify port mapping chính xác |
### 📖 Tham Chiếu Lệnh Thiết Yếu
### Tham Chiếu Lệnh Thiết Yếu
```bash
# 🔍 Debugging
kubectl get pods -n iam-local -w # Theo dõi pods real-time
kubectl describe pod <POD_NAME> -n iam-local # Thông tin chi tiết pod + events
kubectl logs -f <POD_NAME> -n iam-local # Stream logs
kubectl exec -it <POD_NAME> -n iam-local -- /bin/sh # Shell vào container
# Debugging
kubectl get pods -n iam-local -w # Theo dõi pods real-time
kubectl describe pod <POD_NAME> -n iam-local # Thông tin chi tiết pod + events
kubectl logs -f <POD_NAME> -n iam-local # Stream logs
kubectl exec -it <POD_NAME> -n iam-local -- /bin/sh # Shell vào container
# 🔄 Quản Lý Image
docker build -t service:local -f Dockerfile . # Build image
kind load docker-image service:local --name desktop # Load vào Kind cluster
docker images | grep service # Liệt kê local images
# Quản Lý Image
docker build -t service:local -f Dockerfile . # Build image
kind load docker-image service:local --name desktop # Load vào Kind cluster
docker images | grep service # Liệt kê local images
# 🚀 Deploy Nhanh
kubectl apply -f deployment.yaml -n iam-local # Deploy single manifest
kubectl apply -f . -n iam-local # Deploy tất cả files trong thư mục
kubectl rollout restart deployment/iam-service -n iam-local # Force restart pods
# Deploy Nhanh
kubectl apply -f deployment.yaml -n iam-local # Deploy single manifest
kubectl apply -f . -n iam-local # Deploy tất cả files trong thư mục
kubectl rollout restart deployment/iam-service -n iam-local # Force restart pods
# 🧹 Cleanup
kubectl delete pod <POD_NAME> -n iam-local --force # Force delete pod bị kẹt
kubectl delete namespace iam-local --force --grace-period=0 # Force delete namespace
# Cleanup
kubectl delete pod <POD_NAME> -n iam-local --force # Force delete pod bị kẹt
kubectl delete namespace iam-local --force --grace-period=0 # Force delete namespace
```
### 📋 Deployment Checklist
### Deployment Checklist
- [ ] Docker Desktop Kubernetes enabled
- [ ] kubectl context = `docker-desktop`
- [ ] Image built locally: `docker images | grep iam-service`
- [ ] Namespace created: `kubectl get ns iam-local`
- [ ] Secrets created: `kubectl get secrets -n iam-local`
- [ ] ConfigMap applied: `kubectl get cm -n iam-local`
- [ ] Deployment applied: `kubectl get deploy -n iam-local`
- [ ] Service created: `kubectl get svc -n iam-local`
- [ ] Pods running: `kubectl get pods -n iam-local`
- [ ] Port-forward works: `kubectl port-forward ...`
- [ ] Health check passes: `curl http://localhost:5002/health/live`
- [ ] Docker Desktop Kubernetes enabled
- [ ] kubectl context = `docker-desktop`
- [ ] Image built locally: `docker images | grep iam-service`
- [ ] Namespace created: `kubectl get ns iam-local`
- [ ] Secrets created: `kubectl get secrets -n iam-local`
- [ ] ConfigMap applied: `kubectl get cm -n iam-local`
- [ ] Deployment applied: `kubectl get deploy -n iam-local`
- [ ] Service created: `kubectl get svc -n iam-local`
- [ ] Pods running: `kubectl get pods -n iam-local`
- [ ] Port-forward works: `kubectl port-forward ...`
- [ ] Health check passes: `curl http://localhost:5002/health/live`
### 💾 Resource Management
### Resource Management
**Recommended Resources per Pod:**
```yaml
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
```
**Check Resource Usage:**
@@ -321,7 +321,7 @@ kubectl top pods -n iam-local
kubectl describe node docker-desktop
```
### 🛡️ Best Practices
### Best Practices
1. **Sử dụng namespaces** để tách biệt môi trường
2. **Set resource limits** cho mọi pod
@@ -332,22 +332,22 @@ kubectl describe node docker-desktop
7. **Enable logging** để dễ debug
8. **Regular cleanup** các resources không dùng
### 🎨 Trạng Thái Visual
### Trạng Thái Visual
- 🟢 **Running** - Service hoạt động bình thường
- 🟡 **Pending** - Đang chờ resources
- 🔴 **CrashLoopBackOff** - Service liên tục fail (kiểm tra logs!)
- 🔵 **ContainerCreating** - Pod đang khởi động
- **Terminating** - Pod đang tắt
- **Running** - Service hoạt động bình thường
- **Pending** - Đang chờ resources
- **CrashLoopBackOff** - Service liên tục fail (kiểm tra logs!)
- **ContainerCreating** - Pod đang khởi động
- **Terminating** - Pod đang tắt
### 💡 Pro Tips
### Pro Tips
1. ** Fast Rebuild**: Để iterate nhanh, dùng `kubectl rollout restart deployment/iam-service -n iam-local` sau khi rebuild image
2. **🔍 Watch Mode**: Dùng flag `-w` để theo dõi resources update real-time
3. **📝 YAML Validation**: Chạy `kubectl apply --dry-run=client -f file.yaml` để validate trước khi apply
4. **🎯 Label Filtering**: Dùng `-l app=iam-service` để filter resources theo label thay vì gõ pod names
1. ** Fast Rebuild**: Để iterate nhanh, dùng `kubectl rollout restart deployment/iam-service -n iam-local` sau khi rebuild image
2. ** Watch Mode**: Dùng flag `-w` để theo dõi resources update real-time
3. ** YAML Validation**: Chạy `kubectl apply --dry-run=client -f file.yaml` để validate trước khi apply
4. ** Label Filtering**: Dùng `-l app=iam-service` để filter resources theo label thay vì gõ pod names
### 🔗 Tài Liệu Tham Khảo
### Tài Liệu Tham Khảo
- [Kubernetes Documentation](https://kubernetes.io/docs/)
- [Docker Desktop for Mac](https://docs.docker.com/desktop/mac/networking/)

View File

@@ -39,8 +39,8 @@ docker-compose logs -f
### Backend Services
- **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
- Routes: `/api/v1/auth`, `/api/v1/users`
- Health: http://localhost/api/v1/auth/health
### Frontend Applications
@@ -117,33 +117,33 @@ docker-compose exec iam-service sh
```yaml
services:
my-new-service:
build:
context: ../..
dockerfile: services/my-new-service/Dockerfile
container_name: my-new-service-local
env_file:
- .env.local
environment:
- PORT=5002
- SERVICE_NAME=my-new-service
- DATABASE_URL=${DATABASE_URL}
- REDIS_HOST=${REDIS_HOST}
- JWT_SECRET=${JWT_SECRET}
ports:
- "5002:5002"
depends_on:
redis:
condition: service_healthy
traefik:
condition: service_started
networks:
- microservices-network
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.my-new-service.rule=PathPrefix(`/api/v1/my-new-service`)"
- "traefik.http.services.my-new-service.loadbalancer.server.port=5002"
my-new-service:
build:
context: ../..
dockerfile: services/my-new-service/Dockerfile
container_name: my-new-service-local
env_file:
- .env.local
environment:
- PORT=5002
- SERVICE_NAME=my-new-service
- DATABASE_URL=${DATABASE_URL}
- REDIS_HOST=${REDIS_HOST}
- JWT_SECRET=${JWT_SECRET}
ports:
- "5002:5002"
depends_on:
redis:
condition: service_healthy
traefik:
condition: service_started
networks:
- microservices-network
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.my-new-service.rule=PathPrefix(`/api/v1/my-new-service`)"
- "traefik.http.services.my-new-service.loadbalancer.server.port=5002"
```
2. **Khởi động service**:
@@ -153,8 +153,8 @@ docker-compose up -d my-new-service
```
3. **Truy cập service**:
- Qua Traefik: http://localhost/api/v1/my-new-service
- Trực tiếp: http://localhost:5002
- Qua Traefik: http://localhost/api/v1/my-new-service
- Trực tiếp: http://localhost:5002
## Cấu Hình Traefik
@@ -227,40 +227,40 @@ docker-compose logs traefik
```mermaid
graph TB
Client[👤 Client<br/>Browser] --> Traefik
Traefik[🌐 Traefik<br/>API Gateway<br/>:80, :8080]
Traefik --> IAM[🔐 IAM Service<br/>Authentication<br/>:5001]
Traefik --> Admin[⚙️ Web Admin<br/>Dashboard<br/>:3000]
Traefik --> WebClient[🌍 Web Client<br/>Application<br/>:3001]
IAM --> Redis[(💾 Redis<br/>Cache<br/>:6379)]
IAM --> DB[(🗄️ PostgreSQL<br/>Neon Database)]
classDef client fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#eee
classDef gateway fill:#0f3460,stroke:#16213e,stroke-width:3px,color:#eee
classDef service fill:#16213e,stroke:#533483,stroke-width:2px,color:#eee
classDef frontend fill:#1a1a40,stroke:#6c5ce7,stroke-width:2px,color:#eee
classDef data fill:#2d132c,stroke:#801336,stroke-width:2px,color:#eee
class Client client
class Traefik gateway
class IAM service
class Admin,WebClient frontend
class Redis,DB data
Client[ Client<br/>Browser] --> Traefik
Traefik[ Traefik<br/>API Gateway<br/>:80, :8080]
Traefik --> IAM[ IAM Service<br/>Authentication<br/>:5001]
Traefik --> Admin[ Web Admin<br/>Dashboard<br/>:3000]
Traefik --> WebClient[ Web Client<br/>Application<br/>:3001]
IAM --> Redis[( Redis<br/>Cache<br/>:6379)]
IAM --> DB[( PostgreSQL<br/>Neon Database)]
classDef client fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#eee
classDef gateway fill:#0f3460,stroke:#16213e,stroke-width:3px,color:#eee
classDef service fill:#16213e,stroke:#533483,stroke-width:2px,color:#eee
classDef frontend fill:#1a1a40,stroke:#6c5ce7,stroke-width:2px,color:#eee
classDef data fill:#2d132c,stroke:#801336,stroke-width:2px,color:#eee
class Client client
class Traefik gateway
class IAM service
class Admin,WebClient frontend
class Redis,DB data
```
**Chú Giải:**
- 👤 **Client**: Người dùng truy cập qua trình duyệt
- 🌐 **Gateway**: Traefik API Gateway (định tuyến tự động)
- 🔐 **Backend**: IAM Service (xác thực)
- ⚙️ **Frontend**: Ứng dụng Web Admin & Client
- 💾 **Storage**: Redis cache & PostgreSQL database
- **Client**: Người dùng truy cập qua trình duyệt
- **Gateway**: Traefik API Gateway (định tuyến tự động)
- **Backend**: IAM Service (xác thực)
- **Frontend**: Ứng dụng Web Admin & Client
- **Storage**: Redis cache & PostgreSQL database
## Quick Tips
### 🚨 Các Vấn Đề Thường Gặp
### Các Vấn Đề Thường Gặp
| Vấn Đề | Giải Pháp |
|--------|-----------|
@@ -270,7 +270,7 @@ graph TB
| **Kết nối Redis** | Đảm bảo Redis healthy: `docker-compose exec redis redis-cli ping` |
| **Traefik routing** | Kiểm tra dashboard tại http://localhost:8080 để xem trạng thái routes |
### 🎯 Development Workflow
### Development Workflow
```bash
# Restart nhanh (thay đổi code)
@@ -283,14 +283,14 @@ docker-compose up -d --build iam-service
docker-compose down -v && docker-compose up -d
```
### 🔐 Security Checklist
### Security Checklist
- Thay đổi `JWT_SECRET` mặc định (tối thiểu 32 ký tự)
- Sử dụng `.env.local` riêng cho từng môi trường (không commit)
- Xác minh CORS origins khớp với frontend URLs
- Bật HTTPS trong production (không cần cho local)
- Thay đổi `JWT_SECRET` mặc định (tối thiểu 32 ký tự)
- Sử dụng `.env.local` riêng cho từng môi trường (không commit)
- Xác minh CORS origins khớp với frontend URLs
- Bật HTTPS trong production (không cần cho local)
### 📊 Monitoring
### Monitoring
- **Traefik Dashboard**: http://localhost:8080 - Xem tất cả routes và services
- **Service Health**: http://localhost/api/v1/auth/health - Kiểm tra trạng thái service

View File

@@ -6,33 +6,33 @@
```mermaid
graph TD
Start([Bắt đầu / Start]) --> Prerequisites["1. Yêu cầu Hệ thống - Prerequisites"]
Prerequisites --> Clone["2. Clone và Install"]
Clone --> Env["3. Cấu hình Environment - Shared và Service-Specific"]
Env --> DB["4. Setup Database - Migrate và Seed"]
DB --> Run["5. Chạy Dự án - Native/Docker/Hybrid"]
Run --> Dev["6. Development Loop - Watch Mode"]
Dev --> Test["7. Testing và Verify"]
Test --> End([Hoàn tất / Complete])
Start([Bắt đầu / Start]) --> Prerequisites["1. Yêu cầu Hệ thống - Prerequisites"]
Prerequisites --> Clone["2. Clone và Install"]
Clone --> Env["3. Cấu hình Environment - Shared và Service-Specific"]
Env --> DB["4. Setup Database - Migrate và Seed"]
DB --> Run["5. Chạy Dự án - Native/Docker/Hybrid"]
Run --> Dev["6. Development Loop - Watch Mode"]
Dev --> Test["7. Testing và Verify"]
Test --> End([Hoàn tất / Complete])
subgraph "Các Chế độ Chạy / Run Modes"
Run --> Mode1["Cách 1: Native - Nhanh nhất"]
Run --> Mode2["Cách 2: Hybrid - Linh hoạt"]
Run --> Mode3["Cách 3: Full Docker - Production-like"]
end
subgraph "Các Chế độ Chạy / Run Modes"
Run --> Mode1["Cách 1: Native - Nhanh nhất"]
Run --> Mode2["Cách 2: Hybrid - Linh hoạt"]
Run --> Mode3["Cách 3: Full Docker - Production-like"]
end
style Start fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style End fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style Prerequisites fill:#7F8C8D,color:#fff
style Clone fill:#7F8C8D,color:#fff
style Env fill:#E67E22,color:#fff
style DB fill:#E67E22,color:#fff
style Run fill:#2980B9,color:#fff
style Dev fill:#2980B9,color:#fff
style Test fill:#3498DB,color:#fff
style Mode1 fill:#8E44AD,color:#fff
style Mode2 fill:#8E44AD,color:#fff
style Mode3 fill:#8E44AD,color:#fff
style Start fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style End fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style Prerequisites fill:#7F8C8D,color:#fff
style Clone fill:#7F8C8D,color:#fff
style Env fill:#E67E22,color:#fff
style DB fill:#E67E22,color:#fff
style Run fill:#2980B9,color:#fff
style Dev fill:#2980B9,color:#fff
style Test fill:#3498DB,color:#fff
style Mode1 fill:#8E44AD,color:#fff
style Mode2 fill:#8E44AD,color:#fff
style Mode3 fill:#8E44AD,color:#fff
```
## Tổng Quan / Overview
@@ -135,19 +135,19 @@ Bạn có thể chạy dự án theo 3 cách tùy thuộc vào nhu cầu:
Chạy trực tiếp trên máy host. Tốc độ cao nhất, hot-reload nhanh nhất.
1. **Khởi động Hạ tầng (Infrastructure)**:
```bash
# VI: Khởi động Redis và Traefik chạy ngầm bằng Docker
cd deployments/local
docker-compose up -d redis traefik
cd ../..
```
1. **Khởi động Hạ tầng (Infrastructure)**:
```bash
# VI: Khởi động Redis và Traefik chạy ngầm bằng Docker
cd deployments/local
docker-compose up -d redis traefik
cd ../..
```
2. **Chạy Service**:
```bash
# VI: Chạy iam-service ở chế độ watch
pnpm --filter @goodgo/iam-service dev
```
2. **Chạy Service**:
```bash
# VI: Chạy iam-service ở chế độ watch
pnpm --filter @goodgo/iam-service dev
```
### Cách 2: Hybrid Development (Linh hoạt)

View File

@@ -8,13 +8,13 @@ Hướng dẫn này giúp bạn chọn loại sơ đồ Mermaid phù hợp cho t
| Loại Sơ đồ | Sử dụng cho | Độ phức tạp |
|-------------|-------------|-------------|
| **Flowchart** | Quy trình, cây quyết định | ⭐⭐ |
| **Sequence Diagram** | Tương tác API, luồng request | ⭐⭐⭐ |
| **Class Diagram** | Cấu trúc code, patterns | ⭐⭐⭐ |
| **Graph** | Kiến trúc hệ thống, dependencies | ⭐⭐ |
| **ER Diagram** | Schema database | ⭐⭐⭐ |
| **Gantt** | Timeline, lịch trình dự án | ⭐⭐ |
| **C4 Diagram** | Bối cảnh hệ thống, containers | ⭐⭐⭐⭐ |
| **Flowchart** | Quy trình, cây quyết định | |
| **Sequence Diagram** | Tương tác API, luồng request | |
| **Class Diagram** | Cấu trúc code, patterns | |
| **Graph** | Kiến trúc hệ thống, dependencies | |
| **ER Diagram** | Schema database | |
| **Gantt** | Timeline, lịch trình dự án | |
| **C4 Diagram** | Bối cảnh hệ thống, containers | |
---
@@ -32,23 +32,23 @@ Sử dụng flowcharts cho:
```mermaid
flowchart TD
Start([Start]) --> Input[Get Input]
Input --> Check{Valid?}
Check -->|Yes| Process[Process Data]
Check -->|No| Error[Show Error]
Process --> Output[Return Result]
Output --> End([End])
Error --> End
style Start fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style End fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:3px
style Check fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Error fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style Input fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Output fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
Start([Start]) --> Input[Get Input]
Input --> Check{Valid?}
Check -->|Yes| Process[Process Data]
Check -->|No| Error[Show Error]
Process --> Output[Return Result]
Output --> End([End])
Error --> End
style Start fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style End fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:3px
style Check fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Error fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style Input fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Output fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
```
**Giải thích**: Sơ đồ này minh họa quy trình từ lúc Bắt đầu -> Nhận đầu vào -> Kiểm tra tính hợp lệ -> Xử lý (nếu hợp lệ) hoặc Báo lỗi (nếu không) -> Kết thúc.
@@ -56,21 +56,21 @@ flowchart TD
````markdown
```mermaid
flowchart TD
Start([Start]) --> Input[Get Input]
Input --> Check{Valid?}
Check -->|Yes| Process[Process Data]
Check -->|No| Error[Show Error]
Process --> Output[Return Result]
Output --> End([End])
Error --> End
style Start fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style End fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:3px
style Check fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Error fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style Input fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Output fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
Start([Start]) --> Input[Get Input]
Input --> Check{Valid?}
Check -->|Yes| Process[Process Data]
Check -->|No| Error[Show Error]
Process --> Output[Return Result]
Output --> End([End])
Error --> End
style Start fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style End fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:3px
style Check fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Error fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style Input fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Output fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
```
````
@@ -78,30 +78,30 @@ flowchart TD
```mermaid
flowchart LR
A[Client Request] --> B{Auth?}
B -->|No| C[401 Unauthorized]
B -->|Yes| D[Process]
subgraph Processing["Request Processing"]
D --> E[Validate Input]
E --> F[Execute Logic]
F --> G[Format Response]
end
G --> H[Return 200 OK]
C --> I[End]
H --> I
style A fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style B fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style C fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style D fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style E fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style F fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style G fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style H fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style I fill:#7F8C8D,color:#ECF0F1,stroke:#5D6D7E,stroke-width:2px
style Processing fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:2px
A[Client Request] --> B{Auth?}
B -->|No| C[401 Unauthorized]
B -->|Yes| D[Process]
subgraph Processing["Request Processing"]
D --> E[Validate Input]
E --> F[Execute Logic]
F --> G[Format Response]
end
G --> H[Return 200 OK]
C --> I[End]
H --> I
style A fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style B fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style C fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style D fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style E fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style F fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style G fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style H fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style I fill:#7F8C8D,color:#ECF0F1,stroke:#5D6D7E,stroke-width:2px
style Processing fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:2px
```
**Giải thích**: Sơ đồ này cho thấy quy trình xử lý request phức tạp hơn với các logic nhóm trong `subgraph`. Nếu Auth thất bại, trả về 401. Nếu thành công, tiếp tục xử lý, validate, chạy logic, format và trả về 200 OK.
@@ -123,18 +123,18 @@ Sử dụng sequence diagrams cho:
```mermaid
sequenceDiagram
participant Client
participant API
participant Service
participant DB
Client->>API: POST /login
API->>Service: authenticate(credentials)
Service->>DB: findUser(email)
DB-->>Service: user
Service->>Service: verifyPassword()
Service-->>API: JWT token
API-->>Client: 200 OK {token}
participant Client
participant API
participant Service
participant DB
Client->>API: POST /login
API->>Service: authenticate(credentials)
Service->>DB: findUser(email)
DB-->>Service: user
Service->>Service: verifyPassword()
Service-->>API: JWT token
API-->>Client: 200 OK {token}
```
**Giải thích**: Sơ đồ tuần tự mô tả luồng đăng nhập: Client gửi thông tin -> API gọi Service -> Service kiểm tra DB -> DB trả về User -> Service xác thực pass -> Service trả Token -> API trả về cho Client.
@@ -144,18 +144,18 @@ sequenceDiagram
````markdown
```mermaid
sequenceDiagram
participant Client
participant API
participant Service
participant DB
Client->>API: POST /login
API->>Service: authenticate(credentials)
Service->>DB: findUser(email)
DB-->>Service: user
Service->>Service: verifyPassword()
Service-->>API: JWT token
API-->>Client: 200 OK {token}
participant Client
participant API
participant Service
participant DB
Client->>API: POST /login
API->>Service: authenticate(credentials)
Service->>DB: findUser(email)
DB-->>Service: user
Service->>Service: verifyPassword()
Service-->>API: JWT token
API-->>Client: 200 OK {token}
```
````
@@ -163,24 +163,24 @@ sequenceDiagram
```mermaid
sequenceDiagram
participant Client
participant API
participant Cache
participant DB
Client->>API: GET /users/:id
API->>Cache: get(key)
alt Cache Hit
Cache-->>API: cached data
API-->>Client: 200 OK (from cache)
else Cache Miss
Cache-->>API: null
API->>DB: SELECT * FROM users
DB-->>API: user data
API->>Cache: set(key, data, ttl)
API-->>Client: 200 OK (from DB)
end
participant Client
participant API
participant Cache
participant DB
Client->>API: GET /users/:id
API->>Cache: get(key)
alt Cache Hit
Cache-->>API: cached data
API-->>Client: 200 OK (from cache)
else Cache Miss
Cache-->>API: null
API->>DB: SELECT * FROM users
DB-->>API: user data
API->>Cache: set(key, data, ttl)
API-->>Client: 200 OK (from DB)
end
```
**Giải thích**: Sơ đồ này sử dụng khối `alt` để mô tả logic rẽ nhánh: Nếu có Cache (Cache Hit) thì trả về ngay. Nếu không (Cache Miss) thì query DB, lưu vào Cache rồi mới trả về.
@@ -203,28 +203,28 @@ Sử dụng class diagrams cho:
```mermaid
%%{init: {'theme':'dark'}}%%
classDiagram
class BaseRepository {
#prisma: PrismaClient
#modelName: string
+findById(id: string) T
+findAll(options: QueryOptions) T[]
+create(data: CreateDto) T
+update(id: string, data: UpdateDto) T
+delete(id: string) void
}
class UserRepository {
+findByEmail(email: string) User
+findByUsername(username: string) User
}
class FeatureRepository {
+findByName(name: string) Feature
+toggleStatus(id: string) Feature
}
BaseRepository <|-- UserRepository
BaseRepository <|-- FeatureRepository
class BaseRepository {
#prisma: PrismaClient
#modelName: string
+findById(id: string) T
+findAll(options: QueryOptions) T[]
+create(data: CreateDto) T
+update(id: string, data: UpdateDto) T
+delete(id: string) void
}
class UserRepository {
+findByEmail(email: string) User
+findByUsername(username: string) User
}
class FeatureRepository {
+findByName(name: string) Feature
+toggleStatus(id: string) Feature
}
BaseRepository <|-- UserRepository
BaseRepository <|-- FeatureRepository
```
**Giải thích**: Sơ đồ Class thể hiện mối quan hệ kế thừa (`<|--`): `UserRepository` và `FeatureRepository` đều kế thừa từ `BaseRepository`, tận dụng các phương thức chung như `findById`, `create`.
@@ -246,26 +246,26 @@ Sử dụng graph diagrams cho:
```mermaid
graph TD
Client[Web Client] --> Gateway[Traefik Gateway]
Gateway --> Auth[Auth Service]
Gateway --> IAM[IAM Service]
Gateway --> User[User Service]
Auth --> DB[(PostgreSQL)]
IAM --> DB
User --> DB
Auth --> Cache[(Redis)]
IAM --> Cache
User --> Cache
style Client fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Gateway fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:3px
style Auth fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style IAM fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style User fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style Cache fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
Client[Web Client] --> Gateway[Traefik Gateway]
Gateway --> Auth[Auth Service]
Gateway --> IAM[IAM Service]
Gateway --> User[User Service]
Auth --> DB[(PostgreSQL)]
IAM --> DB
User --> DB
Auth --> Cache[(Redis)]
IAM --> Cache
User --> Cache
style Client fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Gateway fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:3px
style Auth fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style IAM fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style User fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style Cache fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
```
**Giải thích**: Sơ đồ kiến trúc tổng quan: `Web Client` đi qua `Traefik Gateway`, sau đó được điều hướng đến các microservices (`Auth`, `IAM`, `User`). Các service này đều kết nối đến Database chung và Redis Cache.
@@ -275,25 +275,25 @@ graph TD
```mermaid
graph LR
Input[User Input] --> Validation[Zod Validation]
Validation --> Controller[Controller]
Controller --> Service[Service Layer]
Service --> Repository[Repository]
Repository --> Prisma[Prisma ORM]
Prisma --> DB[(Database)]
Service --> Cache[Cache Service]
Cache --> Redis[(Redis)]
style Input fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Validation fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style Controller fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Service fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Repository fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Prisma fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style Cache fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Redis fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
Input[User Input] --> Validation[Zod Validation]
Validation --> Controller[Controller]
Controller --> Service[Service Layer]
Service --> Repository[Repository]
Repository --> Prisma[Prisma ORM]
Prisma --> DB[(Database)]
Service --> Cache[Cache Service]
Cache --> Redis[(Redis)]
style Input fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Validation fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style Controller fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Service fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Repository fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Prisma fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style Cache fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Redis fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
```
**Giải thích**: Sơ đồ luồng dữ liệu chi tiết: Input đi qua lớp Validation -> Controller -> Service -> Repository -> ORM -> DB. Đồng thời Service cũng tương tác với Cache.
@@ -316,45 +316,45 @@ Sử dụng ER diagrams cho:
```mermaid
%%{init: {'theme':'dark'}}%%
erDiagram
User ||--o{ Session : has
User ||--o{ RefreshToken : has
User ||--o{ UserRole : has
Role ||--o{ UserRole : has
Role ||--o{ RolePermission : has
Permission ||--o{ RolePermission : has
User {
string id PK
string email UK
string passwordHash
boolean mfaEnabled
datetime createdAt
datetime updatedAt
}
Session {
string id PK
string userId FK
string token UK
string deviceId
string ipAddress
datetime expiresAt
}
Role {
string id PK
string name UK
string description
datetime createdAt
}
Permission {
string id PK
string code UK
string resource
string action
string scope
}
User ||--o{ Session : has
User ||--o{ RefreshToken : has
User ||--o{ UserRole : has
Role ||--o{ UserRole : has
Role ||--o{ RolePermission : has
Permission ||--o{ RolePermission : has
User {
string id PK
string email UK
string passwordHash
boolean mfaEnabled
datetime createdAt
datetime updatedAt
}
Session {
string id PK
string userId FK
string token UK
string deviceId
string ipAddress
datetime expiresAt
}
Role {
string id PK
string name UK
string description
datetime createdAt
}
Permission {
string id PK
string code UK
string resource
string action
string scope
}
```
**Giải thích**: Sơ đồ ER mô tả quan hệ thực thể: Một `User` có nhiều `Session`, `RefreshToken` và `UserRole`. Quan hệ `||--o{` nghĩa là "một-nhiều".
@@ -376,18 +376,18 @@ Sử dụng Gantt charts cho:
```mermaid
gantt
title Documentation Update Project Timeline
dateFormat YYYY-MM-DD
section Phase 1
Analysis & Research :done, p1, 2024-01-01, 1d
section Phase 2
Templates & Strategy :active, p2, 2024-01-02, 0.5d
section Phase 3
High Priority Docs :p3, 2024-01-03, 2d
section Phase 4
Remaining Docs :p4, 2024-01-05, 3d
section Phase 5
QA & Verification :p5, 2024-01-08, 1d
title Documentation Update Project Timeline
dateFormat YYYY-MM-DD
section Phase 1
Analysis & Research :done, p1, 2024-01-01, 1d
section Phase 2
Templates & Strategy :active, p2, 2024-01-02, 0.5d
section Phase 3
High Priority Docs :p3, 2024-01-03, 2d
section Phase 4
Remaining Docs :p4, 2024-01-05, 3d
section Phase 5
QA & Verification :p5, 2024-01-08, 1d
```
**Giải thích**: Biểu đồ Gantt giúp theo dõi tiến độ dự án theo thời gian. Các thanh màu thể hiện trạng thái: `done` (đã xong), `active` (đang làm), hoặc chưa làm.
@@ -410,20 +410,20 @@ Sử dụng C4 diagrams cho:
```mermaid
%%{init: {'theme':'dark'}}%%
C4Context
title System Context Diagram for IAM System
Person(user, "User", "System user needing authentication")
Person(admin, "Admin", "System administrator")
System(iam, "IAM System", "Identity and Access Management")
System_Ext(email, "Email Service", "SendGrid/AWS SES")
System_Ext(oauth, "OAuth Providers", "Google, Facebook, GitHub")
Rel(user, iam, "Authenticates with", "HTTPS")
Rel(admin, iam, "Manages users and permissions", "HTTPS")
Rel(iam, email, "Sends emails", "SMTP/API")
Rel(iam, oauth, "OAuth login", "OAuth 2.0")
title System Context Diagram for IAM System
Person(user, "User", "System user needing authentication")
Person(admin, "Admin", "System administrator")
System(iam, "IAM System", "Identity and Access Management")
System_Ext(email, "Email Service", "SendGrid/AWS SES")
System_Ext(oauth, "OAuth Providers", "Google, Facebook, GitHub")
Rel(user, iam, "Authenticates with", "HTTPS")
Rel(admin, iam, "Manages users and permissions", "HTTPS")
Rel(iam, email, "Sends emails", "SMTP/API")
Rel(iam, oauth, "OAuth login", "OAuth 2.0")
```
**Giải thích**: Sơ đồ C4 Context cho thấy bối cảnh hệ thống ở mức cao nhất: Người dùng và Admin tương tác với `IAM System`. Hệ thống này lại tương tác với các hệ thống bên ngoài như `Email Service` và `OAuth Providers`.
@@ -439,46 +439,46 @@ Sử dụng bảng màu tối để tạo sơ đồ có độ tương phản cao
```mermaid
graph LR
A["🔵 Primary<br/>#2C3E50"] --> B["💾 Data/Cache<br/>#34495E"]
B --> C[" Success<br/>#27AE60"]
C --> D["⚠️ Warning<br/>#E67E22"]
D --> E[" Error<br/>#C0392B"]
E --> F["⚙️ Processing<br/>#8E44AD"]
F --> G[" Info<br/>#3498DB"]
G --> H[" Neutral<br/>#7F8C8D"]
style A fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:2px
style B fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style C fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style D fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style E fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style F fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style G fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style H fill:#7F8C8D,color:#ECF0F1,stroke:#5D6D7E,stroke-width:2px
A[" Primary<br/>#2C3E50"] --> B[" Data/Cache<br/>#34495E"]
B --> C[" Success<br/>#27AE60"]
C --> D[" Warning<br/>#E67E22"]
D --> E[" Error<br/>#C0392B"]
E --> F[" Processing<br/>#8E44AD"]
F --> G[" Info<br/>#3498DB"]
G --> H[" Neutral<br/>#7F8C8D"]
style A fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:2px
style B fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style C fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style D fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style E fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style F fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style G fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style H fill:#7F8C8D,color:#ECF0F1,stroke:#5D6D7E,stroke-width:2px
```
### Bảng Màu Chi tiết
| Màu | Mã Hex | Sử dụng cho | Màu Viền | Màu Chữ |
|-----|--------|-------------|----------|---------|
| 🔵 **Primary** | `#2C3E50` | Node chính, bắt đầu, khối chính | `#34495E` | `#ECF0F1` |
| 💾 **Data/Cache** | `#34495E` | Database, Cache, Storage | `#2C3E50` | `#ECF0F1` |
| **Success** | `#27AE60` | Kết thúc thành công, xác nhận | `#229954` | `#ECF0F1` |
| ⚠️ **Warning** | `#E67E22` | Cảnh báo, điều kiện quan trọng | `#D35400` | `#ECF0F1` |
| **Error** | `#C0392B` | Lỗi, thất bại, hủy bỏ | `#A93226` | `#ECF0F1` |
| ⚙️ **Processing** | `#8E44AD` | Xử lý, quá trình chạy | `#7D3C98` | `#ECF0F1` |
| **Info** | `#3498DB` | Thông tin, ghi chú | `#2980B9` | `#ECF0F1` |
| **Neutral** | `#7F8C8D` | Trung lập, không ưu tiên | `#5D6D7E` | `#ECF0F1` |
| **Primary** | `#2C3E50` | Node chính, bắt đầu, khối chính | `#34495E` | `#ECF0F1` |
| **Data/Cache** | `#34495E` | Database, Cache, Storage | `#2C3E50` | `#ECF0F1` |
| **Success** | `#27AE60` | Kết thúc thành công, xác nhận | `#229954` | `#ECF0F1` |
| **Warning** | `#E67E22` | Cảnh báo, điều kiện quan trọng | `#D35400` | `#ECF0F1` |
| **Error** | `#C0392B` | Lỗi, thất bại, hủy bỏ | `#A93226` | `#ECF0F1` |
| **Processing** | `#8E44AD` | Xử lý, quá trình chạy | `#7D3C98` | `#ECF0F1` |
| **Info** | `#3498DB` | Thông tin, ghi chú | `#2980B9` | `#ECF0F1` |
| **Neutral** | `#7F8C8D` | Trung lập, không ưu tiên | `#5D6D7E` | `#ECF0F1` |
### Checklist Áp dụng Màu
**Nguyên tắc Cơ bản:**
**Nguyên tắc Cơ bản:**
- [ ] Sử dụng màu tối cho nền (dark background)
- [ ] Màu chữ sáng (`#ECF0F1` hoặc `#fff`) để tạo tương phản
- [ ] Viền tối hơn nền một chút để tạo chiều sâu
- [ ] Độ dày viền: `2px` hoặc `3px`
**Pattern theo Loại Node:**
**Pattern theo Loại Node:**
**Start/End Nodes (Bắt đầu/Kết thúc):**
```markdown
@@ -516,23 +516,23 @@ style Gateway fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:3px
```mermaid
flowchart TD
Start([Bắt đầu]) --> Auth{Xác thực?}
Auth -->|Không| Error[Lỗi 401]
Auth -->|Có| Process[Xử lý Request]
Process --> DB[(Database)]
DB --> Cache[(Redis Cache)]
Cache --> Success[Thành công]
Error --> End([Kết thúc])
Success --> End
style Start fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style Auth fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Error fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style Cache fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style Success fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style End fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:3px
Start([Bắt đầu]) --> Auth{Xác thực?}
Auth -->|Không| Error[Lỗi 401]
Auth -->|Có| Process[Xử lý Request]
Process --> DB[(Database)]
DB --> Cache[(Redis Cache)]
Cache --> Success[Thành công]
Error --> End([Kết thúc])
Success --> End
style Start fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style Auth fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Error fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style Cache fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
style Success fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style End fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:3px
```
### Cú pháp Style
@@ -560,56 +560,56 @@ style NodeName fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:2px
## Cạm bẫy Thường gặp
### Too Complex
### Too Complex
```mermaid
graph TD
A --> B
A --> C
B --> D
B --> E
C --> F
C --> G
D --> H
E --> H
F --> I
G --> I
H --> J
I --> J
style A fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style B fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style C fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style D fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style E fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style F fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style G fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style H fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style I fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style J fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
A --> B
A --> C
B --> D
B --> E
C --> F
C --> G
D --> H
E --> H
F --> I
G --> I
H --> J
I --> J
style A fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style B fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style C fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style D fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style E fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style F fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style G fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style H fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style I fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style J fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
```
### Simplified with Subgraphs
### Simplified with Subgraphs
```mermaid
graph TD
A[Start] --> B[Process A]
B --> C[Process B]
subgraph DetailedProcessing["Detailed Processing"]
C --> D[Step 1]
D --> E[Step 2]
end
E --> F[End]
style A fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style B fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style C fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style D fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style E fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style F fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:3px
style DetailedProcessing fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:2px
A[Start] --> B[Process A]
B --> C[Process B]
subgraph DetailedProcessing["Detailed Processing"]
C --> D[Step 1]
D --> E[Step 2]
end
E --> F[End]
style A fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style B fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style C fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style D fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style E fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style F fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:3px
style DetailedProcessing fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:2px
```
---
@@ -641,17 +641,17 @@ mmdc -i your-doc.md
---
## 💡 Quick Tips
## Quick Tips
### ⚠️ Lỗi Mermaid Thường gặp
### Lỗi Mermaid Thường gặp
#### 1. Lỗi Cú pháp
**Vấn đề:** Sơ đồ không render
```markdown
SAI: flowchart TD A -> B
ĐÚNG: flowchart TD
A --> B
SAI: flowchart TD A -> B
ĐÚNG: flowchart TD
A --> B
```
**Nguyên nhân:**
@@ -663,42 +663,42 @@ mmdc -i your-doc.md
**Vấn đề:** Node ID trùng lặp
```markdown
SAI:
SAI:
graph TD
A[Start]
A[Process] <!-- Trùng ID -->
A[Start]
A[Process] <!-- Trùng ID -->
ĐÚNG:
ĐÚNG:
graph TD
A[Start]
B[Process]
A[Start]
B[Process]
```
#### 3. Lỗi Style
**Vấn đề:** Style không áp dụng
```markdown
SAI: style Node fill:#2C3E50 <!-- Thiếu dấu phẩy -->
SAI: style Node fill:#2C3E50 <!-- Thiếu dấu phẩy -->
ĐÚNG: style Node fill:#2C3E50,color:#ECF0F1
ĐÚNG: style Node fill:#2C3E50,color:#ECF0F1
```
#### 4. Lỗi Subgraph
**Vấn đề:** Subgraph không hiển thị đúng
```markdown
SAI:
SAI:
subgraph "My Group"
A --> B
end
ĐÚNG:
ĐÚNG:
subgraph MyGroup["My Group"]
A --> B
A --> B
end
```
### 🎨 Quick Color Pattern Reference
### Quick Color Pattern Reference
**Copy-paste Templates:**
@@ -725,42 +725,42 @@ style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style Info fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
```
### 🔍 Visual Indicators Guide
### Visual Indicators Guide
Sử dụng emoji để tăng khả năng đọc:
| Emoji | Ý nghĩa | Sử dụng trong |
|-------|---------|---------------|
| 🚀 | Start/Launch | Node bắt đầu |
| | Success | Node thành công |
| | Error/Failed | Node lỗi |
| ⚠️ | Warning | Decision nodes quan trọng |
| 🔐 | Security/Auth | Authentication steps |
| 💾 | Database/Storage | Data nodes |
| ⚙️ | Processing | Processing nodes |
| | Information | Info nodes |
| 🔄 | Sync/Update | Sync operations |
| 📡 | API/Network | External calls |
| | Start/Launch | Node bắt đầu |
| | Success | Node thành công |
| | Error/Failed | Node lỗi |
| | Warning | Decision nodes quan trọng |
| | Security/Auth | Authentication steps |
| | Database/Storage | Data nodes |
| | Processing | Processing nodes |
| | Information | Info nodes |
| | Sync/Update | Sync operations |
| | API/Network | External calls |
**Ví dụ sử dụng:**
```mermaid
flowchart TD
Start([🚀 Bắt đầu]) --> Auth{🔐 Xác thực?}
Auth -->|| Error[Lỗi]
Auth -->|| Process[⚙️ Xử lý]
Process --> DB[(💾 Database)]
DB --> Success[ Thành công]
style Start fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style Success fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style Error fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style Auth fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
Start([ Bắt đầu]) --> Auth{ Xác thực?}
Auth -->|| Error[Lỗi]
Auth -->|| Process[ Xử lý]
Process --> DB[( Database)]
DB --> Success[ Thành công]
style Start fill:#2C3E50,color:#ECF0F1,stroke:#34495E,stroke-width:3px
style Success fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
style Error fill:#C0392B,color:#ECF0F1,stroke:#A93226,stroke-width:2px
style Auth fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Process fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px
```
### 🛠️ Troubleshooting Checklist
### Troubleshooting Checklist
Khi sơ đồ không render:
@@ -772,30 +772,30 @@ Khi sơ đồ không render:
- [ ] **Kiểm tra Color**: Hex code có dấu `#` phía trước?
- [ ] **Kiểm tra Special Characters**: Tránh ký tự đặc biệt trong label
### 📊 Diagram Selection Matrix
### Diagram Selection Matrix
**Chọn loại sơ đồ dựa trên mục đích:**
```mermaid
flowchart TD
Start{Bạn cần<br/>visualize gì?}
Start -->|Quy trình| Flow[Flowchart ⭐⭐]
Start -->|API/Giao tiếp| Seq[Sequence ⭐⭐⭐]
Start -->|Code Structure| Class[Class Diagram ⭐⭐⭐]
Start -->|Kiến trúc| Graph[Graph ⭐⭐]
Start -->|Database| ER[ER Diagram ⭐⭐⭐]
Start -->|Timeline| Gantt[Gantt Chart ⭐⭐]
Start -->|System Context| C4[C4 Diagram ⭐⭐⭐⭐]
style Start fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Flow fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Seq fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Class fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Graph fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style ER fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Gantt fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style C4 fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
Start{Bạn cần<br/>visualize gì?}
Start -->|Quy trình| Flow[Flowchart ]
Start -->|API/Giao tiếp| Seq[Sequence ]
Start -->|Code Structure| Class[Class Diagram ]
Start -->|Kiến trúc| Graph[Graph ]
Start -->|Database| ER[ER Diagram ]
Start -->|Timeline| Gantt[Gantt Chart ]
Start -->|System Context| C4[C4 Diagram ]
style Start fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
style Flow fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Seq fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Class fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Graph fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style ER fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style Gantt fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
style C4 fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
```
---

View File

@@ -4,46 +4,46 @@ Project này sử dụng [Neon PostgreSQL](https://neon.tech) cho tất cả mô
## Tại Sao Chọn Neon?
- **Serverless**: Không cần quản lý infrastructure
- **Branching**: Database riêng cho dev/staging/prod
- **Auto-scaling**: Tự động xử lý traffic spikes
- **Point-in-time restore**: Dễ dàng khôi phục từ lỗi
- **Free tier**: Hoàn hảo cho development
- **Connection pooling**: Hỗ trợ PgBouncer tích hợp
- **Serverless**: Không cần quản lý infrastructure
- **Branching**: Database riêng cho dev/staging/prod
- **Auto-scaling**: Tự động xử lý traffic spikes
- **Point-in-time restore**: Dễ dàng khôi phục từ lỗi
- **Free tier**: Hoàn hảo cho development
- **Connection pooling**: Hỗ trợ PgBouncer tích hợp
## Kiến Trúc Neon
```mermaid
graph TB
subgraph NeonProject["🌐 Neon Project: goodgo-platform"]
Main["<b>Branch: main</b><br/>🔧 Development<br/>Auto-scaling<br/>Point-in-time restore"]
Staging["<b>Branch: staging</b><br/>🧪 Staging<br/>Created from main<br/>Pre-production testing"]
Production["<b>Branch: production</b><br/>🚀 Production<br/>Created from main<br/>Live environment"]
end
subgraph Features[" Tính Năng Chính"]
F1[" Serverless<br/>No infrastructure"]
F2["🔄 Auto-scaling<br/>Handle spikes"]
F3["💾 Backups<br/>Point-in-time"]
F4["🔌 Pooling<br/>PgBouncer"]
end
Main -->|Branch từ| Staging
Main -->|Branch từ| Production
Features -.->|Áp dụng cho| Main
Features -.->|Áp dụng cho| Staging
Features -.->|Áp dụng cho| Production
style NeonProject fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#fff
style Main fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style Staging fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style Production fill:#c72c41,stroke:#16213e,stroke-width:2px,color:#fff
style Features fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#fff
style F1 fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style F2 fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style F3 fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style F4 fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
subgraph NeonProject[" Neon Project: goodgo-platform"]
Main["<b>Branch: main</b><br/> Development<br/>Auto-scaling<br/>Point-in-time restore"]
Staging["<b>Branch: staging</b><br/> Staging<br/>Created from main<br/>Pre-production testing"]
Production["<b>Branch: production</b><br/> Production<br/>Created from main<br/>Live environment"]
end
subgraph Features[" Tính Năng Chính"]
F1[" Serverless<br/>No infrastructure"]
F2[" Auto-scaling<br/>Handle spikes"]
F3[" Backups<br/>Point-in-time"]
F4[" Pooling<br/>PgBouncer"]
end
Main -->|Branch từ| Staging
Main -->|Branch từ| Production
Features -.->|Áp dụng cho| Main
Features -.->|Áp dụng cho| Staging
Features -.->|Áp dụng cho| Production
style NeonProject fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#fff
style Main fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style Staging fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style Production fill:#c72c41,stroke:#16213e,stroke-width:2px,color:#fff
style Features fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#fff
style F1 fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style F2 fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style F3 fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style F4 fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
```
## Bắt Đầu Nhanh
@@ -109,8 +109,8 @@ Lưu trong GitHub Secrets: `NEON_DATABASE_URL_STAGING`
Hoặc trong Kubernetes:
```bash
kubectl create secret generic iam-service-secrets \
--from-literal=database-url='postgresql://...' \
-n staging
--from-literal=database-url='postgresql://...' \
-n staging
```
### Production
@@ -120,8 +120,8 @@ Lưu trong GitHub Secrets: `NEON_DATABASE_URL_PRODUCTION`
Hoặc trong Kubernetes:
```bash
kubectl create secret generic iam-service-secrets \
--from-literal=database-url='postgresql://...' \
-n production
--from-literal=database-url='postgresql://...' \
-n production
```
## Migrations
@@ -153,44 +153,44 @@ Migration thủ công:
```mermaid
flowchart TD
Start([👨‍💻 Bắt đầu<br/>Schema thay đổi]) --> Dev[📝 Development<br/>Tạo migration mới<br/>migrate.sh dev]
Dev --> Test{ Test<br/>Migration<br/>OK?}
Test -->| Không| Fix[🔧 Sửa lỗi<br/>Cập nhật schema]
Fix --> Dev
Test -->| Có| Commit[📦 Commit<br/>Migration files<br/>+ schema.prisma]
Commit --> PR[🔀 Pull Request<br/>Code review]
PR --> CICD[⚙️ CI/CD Pipeline<br/>Kiểm tra migration]
CICD --> Staging[🧪 Staging Branch<br/>Auto-apply migration]
Staging --> StagingTest{ Staging<br/>Test OK?}
StagingTest -->| Không| Rollback1[↩ Rollback staging]
Rollback1 --> Fix
StagingTest -->| Có| Approval[👥 Approval<br/>Production deploy]
Approval --> Prod[🚀 Production Branch<br/>Apply migration]
Prod --> ProdTest{ Production<br/>OK?}
ProdTest -->| Không| Rollback2[🚨 Emergency Rollback<br/>Restore point-in-time]
ProdTest -->| Có| Complete([ Hoàn thành<br/>Migration thành công])
style Start fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#fff
style Dev fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style Test fill:#16213e,stroke:#0f3460,stroke-width:2px,color:#fff
style Fix fill:#c72c41,stroke:#16213e,stroke-width:2px,color:#fff
style Commit fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style PR fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style CICD fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style Staging fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style StagingTest fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style Rollback1 fill:#c72c41,stroke:#16213e,stroke-width:2px,color:#fff
style Approval fill:#16213e,stroke:#0f3460,stroke-width:2px,color:#fff
style Prod fill:#c72c41,stroke:#16213e,stroke-width:2px,color:#fff
style ProdTest fill:#16213e,stroke:#c72c41,stroke-width:2px,color:#fff
style Rollback2 fill:#c72c41,stroke:#16213e,stroke-width:3px,color:#fff
style Complete fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
Start([ Bắt đầu<br/>Schema thay đổi]) --> Dev[ Development<br/>Tạo migration mới<br/>migrate.sh dev]
Dev --> Test{ Test<br/>Migration<br/>OK?}
Test -->| Không| Fix[ Sửa lỗi<br/>Cập nhật schema]
Fix --> Dev
Test -->| Có| Commit[ Commit<br/>Migration files<br/>+ schema.prisma]
Commit --> PR[ Pull Request<br/>Code review]
PR --> CICD[ CI/CD Pipeline<br/>Kiểm tra migration]
CICD --> Staging[ Staging Branch<br/>Auto-apply migration]
Staging --> StagingTest{ Staging<br/>Test OK?}
StagingTest -->| Không| Rollback1[↩ Rollback staging]
Rollback1 --> Fix
StagingTest -->| Có| Approval[ Approval<br/>Production deploy]
Approval --> Prod[ Production Branch<br/>Apply migration]
Prod --> ProdTest{ Production<br/>OK?}
ProdTest -->| Không| Rollback2[ Emergency Rollback<br/>Restore point-in-time]
ProdTest -->| Có| Complete([ Hoàn thành<br/>Migration thành công])
style Start fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#fff
style Dev fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style Test fill:#16213e,stroke:#0f3460,stroke-width:2px,color:#fff
style Fix fill:#c72c41,stroke:#16213e,stroke-width:2px,color:#fff
style Commit fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style PR fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style CICD fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style Staging fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style StagingTest fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style Rollback1 fill:#c72c41,stroke:#16213e,stroke-width:2px,color:#fff
style Approval fill:#16213e,stroke:#0f3460,stroke-width:2px,color:#fff
style Prod fill:#c72c41,stroke:#16213e,stroke-width:2px,color:#fff
style ProdTest fill:#16213e,stroke:#c72c41,stroke-width:2px,color:#fff
style Rollback2 fill:#c72c41,stroke:#16213e,stroke-width:3px,color:#fff
style Complete fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
```
## Backup & Restore
@@ -232,125 +232,125 @@ Theo dõi databases qua Neon Console:
```mermaid
flowchart TD
Problem([🚨 Vấn Đề Neon<br/>Không kết nối được?]) --> Type{Loại<br/>Vấn Đề?}
Type -->|🔌 Kết nối| ConnIssue[Vấn Đề Kết Nối]
Type -->|📊 Migration| MigIssue[Vấn Đề Migration]
Type -->| Hiệu suất| PerfIssue[Vấn Đề Hiệu Suất]
ConnIssue --> CheckURL{Connection<br/>String OK?}
CheckURL -->| Không| FixURL[ Kiểm tra:<br/>• sslmode=require<br/>• Credentials đúng<br/>• Endpoint active]
CheckURL -->| Có| CheckIP{IP trong<br/>allowlist?}
CheckIP -->| Không| AddIP[ Thêm IP vào<br/>Neon Console]
CheckIP -->| Có| CheckBranch{Branch<br/>active?}
CheckBranch -->| Không| ActivateBranch[ Kích hoạt branch<br/>hoặc tạo mới]
CheckBranch -->| Có| ContactSupport[📞 Liên hệ<br/>Neon Support]
MigIssue --> CheckEnv{DATABASE_URL<br/>đã set?}
CheckEnv -->| Không| SetEnv[ Export<br/>DATABASE_URL]
CheckEnv -->| Có| CheckSchema{Schema<br/>đồng bộ?}
CheckSchema -->| Không| ResetMig[ DEV ONLY:<br/>prisma migrate reset]
CheckSchema -->| Có| CheckTimeout{Connection<br/>timeout?}
CheckTimeout -->| Có| AddPooling[ Thêm<br/>?pgbouncer=true]
CheckTimeout -->| Không| CheckLimits[ Kiểm tra<br/>Neon Console limits]
PerfIssue --> HasPooling{Connection<br/>Pooling ON?}
HasPooling -->| Không| EnablePooling[ Thêm<br/>?pgbouncer=true]
HasPooling -->| Có| CheckQueries{Slow<br/>queries?}
CheckQueries -->| Có| AnalyzeQueries[ Neon Console<br/>Query Analyzer]
CheckQueries -->| Không| CheckIndexes{Indexes<br/>tối ưu?}
CheckIndexes -->| Không| AddIndexes[ Thêm indexes<br/>vào Prisma schema]
CheckIndexes -->| Có| ScalePlan[ Nâng cấp<br/>Neon plan]
FixURL --> Solved([ Đã giải quyết])
AddIP --> Solved
ActivateBranch --> Solved
ContactSupport --> Solved
SetEnv --> Solved
ResetMig --> Solved
AddPooling --> Solved
CheckLimits --> Solved
EnablePooling --> Solved
AnalyzeQueries --> Solved
AddIndexes --> Solved
ScalePlan --> Solved
style Problem fill:#c72c41,stroke:#16213e,stroke-width:3px,color:#fff
style Type fill:#16213e,stroke:#0f3460,stroke-width:2px,color:#fff
style ConnIssue fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style MigIssue fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style PerfIssue fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style CheckURL fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckIP fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckBranch fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckEnv fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckSchema fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckTimeout fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style HasPooling fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckQueries fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckIndexes fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style FixURL fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style AddIP fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style ActivateBranch fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style ContactSupport fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style SetEnv fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style ResetMig fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style AddPooling fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style CheckLimits fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style EnablePooling fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style AnalyzeQueries fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style AddIndexes fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style ScalePlan fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style Solved fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
Problem([ Vấn Đề Neon<br/>Không kết nối được?]) --> Type{Loại<br/>Vấn Đề?}
Type -->| Kết nối| ConnIssue[Vấn Đề Kết Nối]
Type -->| Migration| MigIssue[Vấn Đề Migration]
Type -->| Hiệu suất| PerfIssue[Vấn Đề Hiệu Suất]
ConnIssue --> CheckURL{Connection<br/>String OK?}
CheckURL -->| Không| FixURL[ Kiểm tra:<br/>• sslmode=require<br/>• Credentials đúng<br/>• Endpoint active]
CheckURL -->| Có| CheckIP{IP trong<br/>allowlist?}
CheckIP -->| Không| AddIP[ Thêm IP vào<br/>Neon Console]
CheckIP -->| Có| CheckBranch{Branch<br/>active?}
CheckBranch -->| Không| ActivateBranch[ Kích hoạt branch<br/>hoặc tạo mới]
CheckBranch -->| Có| ContactSupport[ Liên hệ<br/>Neon Support]
MigIssue --> CheckEnv{DATABASE_URL<br/>đã set?}
CheckEnv -->| Không| SetEnv[ Export<br/>DATABASE_URL]
CheckEnv -->| Có| CheckSchema{Schema<br/>đồng bộ?}
CheckSchema -->| Không| ResetMig[ DEV ONLY:<br/>prisma migrate reset]
CheckSchema -->| Có| CheckTimeout{Connection<br/>timeout?}
CheckTimeout -->| Có| AddPooling[ Thêm<br/>?pgbouncer=true]
CheckTimeout -->| Không| CheckLimits[ Kiểm tra<br/>Neon Console limits]
PerfIssue --> HasPooling{Connection<br/>Pooling ON?}
HasPooling -->| Không| EnablePooling[ Thêm<br/>?pgbouncer=true]
HasPooling -->| Có| CheckQueries{Slow<br/>queries?}
CheckQueries -->| Có| AnalyzeQueries[ Neon Console<br/>Query Analyzer]
CheckQueries -->| Không| CheckIndexes{Indexes<br/>tối ưu?}
CheckIndexes -->| Không| AddIndexes[ Thêm indexes<br/>vào Prisma schema]
CheckIndexes -->| Có| ScalePlan[ Nâng cấp<br/>Neon plan]
FixURL --> Solved([ Đã giải quyết])
AddIP --> Solved
ActivateBranch --> Solved
ContactSupport --> Solved
SetEnv --> Solved
ResetMig --> Solved
AddPooling --> Solved
CheckLimits --> Solved
EnablePooling --> Solved
AnalyzeQueries --> Solved
AddIndexes --> Solved
ScalePlan --> Solved
style Problem fill:#c72c41,stroke:#16213e,stroke-width:3px,color:#fff
style Type fill:#16213e,stroke:#0f3460,stroke-width:2px,color:#fff
style ConnIssue fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style MigIssue fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style PerfIssue fill:#533483,stroke:#16213e,stroke-width:2px,color:#fff
style CheckURL fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckIP fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckBranch fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckEnv fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckSchema fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckTimeout fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style HasPooling fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckQueries fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style CheckIndexes fill:#16213e,stroke:#533483,stroke-width:2px,color:#fff
style FixURL fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style AddIP fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style ActivateBranch fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style ContactSupport fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style SetEnv fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style ResetMig fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style AddPooling fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style CheckLimits fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style EnablePooling fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style AnalyzeQueries fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style AddIndexes fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style ScalePlan fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
style Solved fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
```
### Vấn Đề Kết Nối
1. **Kiểm tra định dạng connection string**
- Phải bao gồm `?sslmode=require`
- Xác minh credentials
- Phải bao gồm `?sslmode=require`
- Xác minh credentials
2. **Kiểm tra IP allowlist**
- Neon có thể giới hạn IPs
- Thêm IP của bạn trong Neon Console
- Neon có thể giới hạn IPs
- Thêm IP của bạn trong Neon Console
3. **Kiểm tra branch status**
- Đảm bảo branch đang active
- Kiểm tra maintenance
- Đảm bảo branch đang active
- Kiểm tra maintenance
### Vấn Đề Migration
1. **DATABASE_URL chưa set**
```bash
export DATABASE_URL="your-neon-url"
```
```bash
export DATABASE_URL="your-neon-url"
```
2. **Schema không khớp**
```bash
# Reset và migrate lại (chỉ dev!)
pnpm prisma migrate reset
```
```bash
# Reset và migrate lại (chỉ dev!)
pnpm prisma migrate reset
```
3. **Connection timeout**
- Thêm `?pgbouncer=true` cho pooling
- Kiểm tra Neon console cho limits
- Thêm `?pgbouncer=true` cho pooling
- Kiểm tra Neon console cho limits
### Vấn Đề Hiệu Suất
1. **Bật connection pooling**
- Thêm `?pgbouncer=true` vào connection string
- Thêm `?pgbouncer=true` vào connection string
2. **Kiểm tra query performance**
- Sử dụng Neon Console query analyzer
- Xem lại slow queries
- Sử dụng Neon Console query analyzer
- Xem lại slow queries
3. **Tối ưu indexes**
- Xem lại Prisma schema
- Thêm indexes cho các query thường dùng
- Xem lại Prisma schema
- Thêm indexes cho các query thường dùng
## Tối Ưu Chi Phí
@@ -367,7 +367,7 @@ flowchart TD
4. **Backup thường xuyên**: Sử dụng automatic backups của Neon
5. **Theo dõi usage**: Kiểm tra Neon Console thường xuyên
## 💡 Quick Tips
## Quick Tips
### Mermaid Diagram Colors
@@ -375,11 +375,11 @@ Tất cả Mermaid diagrams sử dụng **bảng màu tối (dark palette)** v
| Loại Node | Màu | Mục Đích |
|-----------|-----|----------|
| 🔵 **Primary** | `#0f3460` | Actions, Steps, Solutions |
| 🟣 **Purple** | `#533483` | Staging, Categories, Warnings |
| 🔴 **Red** | `#c72c41` | Production, Errors, Critical |
| 🔘 **Dark** | `#1a1a2e` | Backgrounds, Containers |
| **Darker** | `#16213e` | Decision Points, Questions |
| **Primary** | `#0f3460` | Actions, Steps, Solutions |
| **Purple** | `#533483` | Staging, Categories, Warnings |
| **Red** | `#c72c41` | Production, Errors, Critical |
| **Dark** | `#1a1a2e` | Backgrounds, Containers |
| **Darker** | `#16213e` | Decision Points, Questions |
**Pattern:**
```css
@@ -390,28 +390,28 @@ style NodeName fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#fff
| Vấn đề | Giải pháp nhanh | Emoji |
|--------|----------------|-------|
| Connection timeout | Thêm `?pgbouncer=true` | |
| SSL error | Thêm `?sslmode=require` | 🔒 |
| IP bị chặn | Thêm IP vào Neon Console allowlist | 🚫 |
| Branch inactive | Kích hoạt lại trong Console | 💤 |
| Migration lỗi | Reset dev: `prisma migrate reset` | 🔄 |
| Slow queries | Bật Query Analyzer trong Console | 🐌 |
| Storage đầy | Nâng cấp plan hoặc cleanup data | 💾 |
| Connection timeout | Thêm `?pgbouncer=true` | |
| SSL error | Thêm `?sslmode=require` | |
| IP bị chặn | Thêm IP vào Neon Console allowlist | |
| Branch inactive | Kích hoạt lại trong Console | |
| Migration lỗi | Reset dev: `prisma migrate reset` | |
| Slow queries | Bật Query Analyzer trong Console | |
| Storage đầy | Nâng cấp plan hoặc cleanup data | |
### Visual Indicators
- 🌐 = Neon Project
- 🔧 = Development
- 🧪 = Staging
- 🚀 = Production
- = Performance/Speed
- 🔌 = Connection
- 💾 = Storage/Backup
- 🔄 = Retry/Rollback
- = Success/OK
- = Error/Failed
- 🚨 = Critical/Emergency
- 📊 = Metrics/Analytics
- = Neon Project
- = Development
- = Staging
- = Production
- = Performance/Speed
- = Connection
- = Storage/Backup
- = Retry/Rollback
- = Success/OK
- = Error/Failed
- = Critical/Emergency
- = Metrics/Analytics
## Tài Nguyên

View File

@@ -6,71 +6,71 @@ Tài liệu này hướng dẫn cách sử dụng stack observability (Grafana,
```mermaid
graph TB
subgraph Services["🚀 Microservices"]
IAM["IAM Service"]
User["User Service"]
Order["Order Service"]
end
subgraph Collectors["📊 Data Collectors"]
Prometheus["Prometheus<br/>📈 Metrics Collector"]
Promtail["Promtail<br/>📝 Log Collector"]
end
subgraph Storage["💾 Storage"]
PrometheusDB["Prometheus TSDB<br/>Metrics Storage"]
Loki["Loki<br/>Log Aggregation"]
end
subgraph Visualization["📊 Visualization"]
Grafana["Grafana<br/>Dashboard & Analytics"]
end
IAM -->|"metrics /metrics"| Prometheus
User -->|"metrics /metrics"| Prometheus
Order -->|"metrics /metrics"| Prometheus
IAM -->|"logs (stdout)"| Promtail
User -->|"logs (stdout)"| Promtail
Order -->|"logs (stdout)"| Promtail
Prometheus -->|"store"| PrometheusDB
Promtail -->|"push logs"| Loki
PrometheusDB -->|"query PromQL"| Grafana
Loki -->|"query LogQL"| Grafana
style Services fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#ffffff
style Collectors fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#ffffff
style Storage fill:#16213e,stroke:#0f3460,stroke-width:2px,color:#ffffff
style Visualization fill:#533483,stroke:#16213e,stroke-width:2px,color:#ffffff
style IAM fill:#e94560,stroke:#c81e3b,stroke-width:2px,color:#ffffff
style User fill:#e94560,stroke:#c81e3b,stroke-width:2px,color:#ffffff
style Order fill:#e94560,stroke:#c81e3b,stroke-width:2px,color:#ffffff
style Prometheus fill:#f39c12,stroke:#d68910,stroke-width:2px,color:#ffffff
style Promtail fill:#f39c12,stroke:#d68910,stroke-width:2px,color:#ffffff
style PrometheusDB fill:#3498db,stroke:#2874a6,stroke-width:2px,color:#ffffff
style Loki fill:#3498db,stroke:#2874a6,stroke-width:2px,color:#ffffff
style Grafana fill:#9b59b6,stroke:#7d3c98,stroke-width:2px,color:#ffffff
subgraph Services[" Microservices"]
IAM["IAM Service"]
User["User Service"]
Order["Order Service"]
end
subgraph Collectors[" Data Collectors"]
Prometheus["Prometheus<br/> Metrics Collector"]
Promtail["Promtail<br/> Log Collector"]
end
subgraph Storage[" Storage"]
PrometheusDB["Prometheus TSDB<br/>Metrics Storage"]
Loki["Loki<br/>Log Aggregation"]
end
subgraph Visualization[" Visualization"]
Grafana["Grafana<br/>Dashboard & Analytics"]
end
IAM -->|"metrics /metrics"| Prometheus
User -->|"metrics /metrics"| Prometheus
Order -->|"metrics /metrics"| Prometheus
IAM -->|"logs (stdout)"| Promtail
User -->|"logs (stdout)"| Promtail
Order -->|"logs (stdout)"| Promtail
Prometheus -->|"store"| PrometheusDB
Promtail -->|"push logs"| Loki
PrometheusDB -->|"query PromQL"| Grafana
Loki -->|"query LogQL"| Grafana
style Services fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#ffffff
style Collectors fill:#0f3460,stroke:#16213e,stroke-width:2px,color:#ffffff
style Storage fill:#16213e,stroke:#0f3460,stroke-width:2px,color:#ffffff
style Visualization fill:#533483,stroke:#16213e,stroke-width:2px,color:#ffffff
style IAM fill:#e94560,stroke:#c81e3b,stroke-width:2px,color:#ffffff
style User fill:#e94560,stroke:#c81e3b,stroke-width:2px,color:#ffffff
style Order fill:#e94560,stroke:#c81e3b,stroke-width:2px,color:#ffffff
style Prometheus fill:#f39c12,stroke:#d68910,stroke-width:2px,color:#ffffff
style Promtail fill:#f39c12,stroke:#d68910,stroke-width:2px,color:#ffffff
style PrometheusDB fill:#3498db,stroke:#2874a6,stroke-width:2px,color:#ffffff
style Loki fill:#3498db,stroke:#2874a6,stroke-width:2px,color:#ffffff
style Grafana fill:#9b59b6,stroke:#7d3c98,stroke-width:2px,color:#ffffff
```
### Các thành phần chính
- **Prometheus**: Thu thập metrics từ các services qua endpoint `/metrics`
- **Loki**: Thu thập và tổng hợp logs từ các container
- **Promtail**: Agent quét logs từ Docker containers và đẩy đến Loki
- **Grafana**: Dashboard trực quan hóa metrics (Prometheus) và logs (Loki)
- **Prometheus**: Thu thập metrics từ các services qua endpoint `/metrics`
- **Loki**: Thu thập và tổng hợp logs từ các container
- **Promtail**: Agent quét logs từ Docker containers và đẩy đến Loki
- **Grafana**: Dashboard trực quan hóa metrics (Prometheus) và logs (Loki)
## Bắt đầu
### Yêu cầu tiên quyết
- Đã cài đặt Docker và Docker Compose.
- Đã có network `microservices-network` (thường được tạo bởi stack chính của ứng dụng hoặc tạo thủ công).
- Đã cài đặt Docker và Docker Compose.
- Đã có network `microservices-network` (thường được tạo bởi stack chính của ứng dụng hoặc tạo thủ công).
### Khởi chạy Stack
@@ -108,20 +108,20 @@ Bạn sẽ thấy các container `grafana`, `prometheus`, `loki`, và `promtail`
## Sử dụng Grafana
1. **Đăng nhập**: Truy cập [http://localhost:3001](http://localhost:3001) và đăng nhập với `admin`/`admin`.
2. **Khám phá dữ liệu (Explore)**:
- Chọn biểu tượng **Explore** (hình la bàn) ở thanh bên trái.
- Chọn **Loki** từ menu datasource để tìm kiếm logs.
- Chọn **Prometheus** từ menu datasource để truy vấn metrics.
1. **Đăng nhập**: Truy cập [http://localhost:3001](http://localhost:3001) và đăng nhập với `admin`/`admin`.
2. **Khám phá dữ liệu (Explore)**:
- Chọn biểu tượng **Explore** (hình la bàn) ở thanh bên trái.
- Chọn **Loki** từ menu datasource để tìm kiếm logs.
- Chọn **Prometheus** từ menu datasource để truy vấn metrics.
### Xem Logs (Loki)
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ụ: `iam-service` hoặc `traefik`).
4. Nhấn **Show logs**.
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ụ: `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ụ:
@@ -133,50 +133,50 @@ Bạn cũng có thể viết truy vấn LogQL thủ công, ví dụ:
Trong giao diện **Explore** với **Prometheus** đã chọn:
1. Nhập tên metric vào ô truy vấn (ví dụ: `up`, `container_memory_usage_bytes`).
2. Nhấn **Run query**.
1. Nhập tên metric vào ô truy vấn (ví dụ: `up`, `container_memory_usage_bytes`).
2. Nhấn **Run query**.
## Cấu hình
- **Prometheus**: Các rules và targets được cấu hình tại `infra/observability/prometheus/prometheus.yml`.
- **Promtail**: Rules để quét log được cấu hình tại `infra/observability/promtail/promtail-config.yml`.
- **Grafana**: Cấu hình datasources và dashboards provisioning nằm trong `infra/observability/grafana/`.
- **Prometheus**: Các rules và targets được cấu hình tại `infra/observability/prometheus/prometheus.yml`.
- **Promtail**: Rules để quét log được cấu hình tại `infra/observability/promtail/promtail-config.yml`.
- **Grafana**: Cấu hình datasources và dashboards provisioning nằm trong `infra/observability/grafana/`.
## 💡 Quick Tips
## Quick Tips
### Troubleshooting chung
| Vấn đề | Triệu chứng | Giải pháp |
|--------|-------------|-----------|
| ⚠️ Không thấy logs | Grafana Explore không hiển thị logs | Kiểm tra Promtail đang chạy: `docker ps \| grep promtail` |
| 📊 Metrics bị thiếu | Services không xuất hiện trong Prometheus targets | Kiểm tra `/metrics` endpoint của service |
| 🔴 Container không khởi động | `docker ps` không show container | Xem logs: `docker-compose logs <service-name>` |
| 🌐 Network issue | Services không kết nối được | Tạo network: `docker network create microservices-network` |
| Không thấy logs | Grafana Explore không hiển thị logs | Kiểm tra Promtail đang chạy: `docker ps \| grep promtail` |
| Metrics bị thiếu | Services không xuất hiện trong Prometheus targets | Kiểm tra `/metrics` endpoint của service |
| Container không khởi động | `docker ps` không show container | Xem logs: `docker-compose logs <service-name>` |
| Network issue | Services không kết nối được | Tạo network: `docker network create microservices-network` |
### LogQL Quick Reference
```logql
{container="iam-service"} # Logs từ IAM service
{container="iam-service"} |= "error" # Chỉ logs có chứa "error"
{container="iam-service"} | json # Parse JSON logs
{container="iam-service"} | json | level="error" # Filter by log level
{container="iam-service"} # Logs từ IAM service
{container="iam-service"} |= "error" # Chỉ logs có chứa "error"
{container="iam-service"} | json # Parse JSON logs
{container="iam-service"} | json | level="error" # Filter by log level
```
### PromQL Quick Reference
```promql
up # Status của tất cả targets (1 = up, 0 = down)
rate(http_requests_total[5m]) # Request rate trong 5 phút
container_memory_usage_bytes{container="iam-service"} # Memory usage của IAM service
up # Status của tất cả targets (1 = up, 0 = down)
rate(http_requests_total[5m]) # Request rate trong 5 phút
container_memory_usage_bytes{container="iam-service"} # Memory usage của IAM service
```
### Best Practices
- **Naming Convention**: Đặt tên metrics theo pattern `<namespace>_<subsystem>_<name>_<unit>`
- **Labels**: Sử dụng labels để phân loại dữ liệu (environment, service, instance)
- **Retention**: Cấu hình retention phù hợp cho Prometheus và Loki
- **Alerting**: Thiết lập alerts cho các metrics quan trọng
- ⚠️ **Cardinality**: Tránh sử dụng quá nhiều unique labels (gây tăng cardinality)
- **Naming Convention**: Đặt tên metrics theo pattern `<namespace>_<subsystem>_<name>_<unit>`
- **Labels**: Sử dụng labels để phân loại dữ liệu (environment, service, instance)
- **Retention**: Cấu hình retention phù hợp cho Prometheus và Loki
- **Alerting**: Thiết lập alerts cho các metrics quan trọng
- **Cardinality**: Tránh sử dụng quá nhiều unique labels (gây tăng cardinality)
### Color Palette Reference
@@ -184,11 +184,11 @@ Diagram sử dụng bảng màu tối để dễ nhìn:
| Loại Component | Fill Color | Stroke Color | Mục đích |
|----------------|------------|--------------|----------|
| 🚀 Services | `#e94560` | `#c81e3b` | Microservices (đỏ) |
| 📊 Collectors | `#f39c12` | `#d68910` | Thu thập dữ liệu (cam) |
| 💾 Storage | `#3498db` | `#2874a6` | Lưu trữ (xanh dương) |
| 📊 Visualization | `#9b59b6` | `#7d3c98` | Trực quan hóa (tím) |
| 📦 Subgraphs | `#1a1a2e` - `#533483` | `#16213e` - `#0f3460` | Nhóm logic |
| Services | `#e94560` | `#c81e3b` | Microservices (đỏ) |
| Collectors | `#f39c12` | `#d68910` | Thu thập dữ liệu (cam) |
| Storage | `#3498db` | `#2874a6` | Lưu trữ (xanh dương) |
| Visualization | `#9b59b6` | `#7d3c98` | Trực quan hóa (tím) |
| Subgraphs | `#1a1a2e` - `#533483` | `#16213e` - `#0f3460` | Nhóm logic |
**Tất cả text sử dụng `color:#ffffff` (trắng) để dễ đọc trên nền tối**

View File

@@ -6,13 +6,13 @@
1. [Chẩn đoán Chung](#chẩn-đoán-chung)
2. [Vấn đề Infrastructure](#vấn-đề-infrastructure)
- [Database (Neon/PostgreSQL)](#database-neonpostgresql)
- [Redis](#redis)
- [Traefik Gateway](#traefik-gateway)
- [Database (Neon/PostgreSQL)](#database-neonpostgresql)
- [Redis](#redis)
- [Traefik Gateway](#traefik-gateway)
3. [Vấn đề Service](#vấn-đề-service)
- [Service Không Khởi Động](#service-không-khởi-động)
- [Lỗi Prisma/Database](#lỗi-prismadatabase)
- [Lỗi Authentication](#lỗi-authentication)
- [Service Không Khởi Động](#service-không-khởi-động)
- [Lỗi Prisma/Database](#lỗi-prismadatabase)
- [Lỗi Authentication](#lỗi-authentication)
4. [Công cụ Debug](#công-cụ-debug)
5. [Câu hỏi Thường Gặp (FAQ)](#câu-hỏi-thường-gặp-faq)
@@ -22,110 +22,110 @@
Khi có sự cố, hãy làm theo danh sách kiểm tra sau:
1. **Kiểm tra Trạng thái Service**:
```bash
cd deployments/local
docker-compose ps
```
*Tất cả services nên ở trạng thái `Up` hoặc `Running`.*
1. **Kiểm tra Trạng thái Service**:
```bash
cd deployments/local
docker-compose ps
```
*Tất cả services nên ở trạng thái `Up` hoặc `Running`.*
2. **Xem Logs**:
```bash
# Xem logs của service cụ thể
docker-compose logs -f <service-name>
# Xem 100 dòng cuối của tất cả
docker-compose logs --tail=100
```
2. **Xem Logs**:
```bash
# Xem logs của service cụ thể
docker-compose logs -f <service-name>
3. **Kiểm tra Kết nối**:
* Có thể truy cập Gateway không? `curl http://localhost/health`
* Có thể truy cập Dashboard không? http://localhost:8080
# Xem 100 dòng cuối của tất cả
docker-compose logs --tail=100
```
3. **Kiểm tra Kết nối**:
* Có thể truy cập Gateway không? `curl http://localhost/health`
* Có thể truy cập Dashboard không? http://localhost:8080
### Sơ Đồ Xử Lý Sự Cố
```mermaid
flowchart TD
Start([🔍 Phát Hiện Sự Cố]) --> CheckStatus{Kiểm tra<br/>Trạng thái Service}
CheckStatus -->|Tất cả Running| CheckLogs[📋 Xem Logs]
CheckStatus -->|Một số Down| IdentifyService[🎯 Xác định Service<br/>Bị Lỗi]
IdentifyService --> ServiceType{Loại Service?}
ServiceType -->|Infrastructure| InfraCheck[🔧 Kiểm tra<br/>Infrastructure]
ServiceType -->|Application| AppCheck[⚙️ Kiểm tra<br/>Application]
InfraCheck --> DBCheck{Database?}
InfraCheck --> RedisCheck{Redis?}
InfraCheck --> TraefikCheck{Traefik?}
DBCheck -->|Có| DBSolution[ Kiểm tra DATABASE_URL<br/> Verify kết nối Neon<br/> Kiểm tra IP whitelist]
RedisCheck -->|Có| RedisSolution[ Restart Redis<br/> Kiểm tra port mapping<br/> Verify connection string]
TraefikCheck -->|Có| TraefikSolution[ Kiểm tra labels<br/> Verify PathPrefix<br/> Kiểm tra health status]
AppCheck --> ErrorType{Loại Lỗi?}
ErrorType -->|Config| ConfigFix[ Kiểm tra .env variables<br/> Chạy init-project.sh]
ErrorType -->|Prisma| PrismaFix[ Kiểm tra migrations<br/> Regenerate client<br/> Reset database]
ErrorType -->|Auth| AuthFix[ Kiểm tra token expiry<br/> Verify keys<br/> Sync thời gian Docker]
CheckLogs --> LogAnalysis{Log Hiện<br/>Lỗi?}
LogAnalysis -->|Có| ErrorType
LogAnalysis -->|Không| ConnCheck[🌐 Kiểm tra Kết nối]
ConnCheck --> GatewayTest{Gateway<br/>Truy Cập Được?}
GatewayTest -->|Không| TraefikCheck
GatewayTest -->|Có| ServiceTest{Service<br/>Truy Cập Được?}
ServiceTest -->|Không| AppCheck
ServiceTest -->|Có| Resolved([ Đã Giải Quyết])
DBSolution --> Restart[🔄 Restart Services]
RedisSolution --> Restart
TraefikSolution --> Restart
ConfigFix --> Restart
PrismaFix --> Restart
AuthFix --> Restart
Restart --> Verify{Đã Sửa<br/>Xong?}
Verify -->|Có| Resolved
Verify -->|Không| DeepDebug[🛠️ Debug Sâu<br/>Hơn]
DeepDebug --> ContainerShell[Truy cập Container Shell]
DeepDebug --> PrismaStudio[Dùng Prisma Studio]
DeepDebug --> RedisInspect[Kiểm tra Redis]
DeepDebug --> APITest[Test API Trực tiếp]
style Start fill:#1a1a2e,color:#fff
style Resolved fill:#0f3460,color:#fff
style CheckStatus fill:#16213e,color:#fff
style ServiceType fill:#16213e,color:#fff
style ErrorType fill:#16213e,color:#fff
style DBCheck fill:#16213e,color:#fff
style RedisCheck fill:#16213e,color:#fff
style TraefikCheck fill:#16213e,color:#fff
style GatewayTest fill:#16213e,color:#fff
style ServiceTest fill:#16213e,color:#fff
style Verify fill:#16213e,color:#fff
style LogAnalysis fill:#16213e,color:#fff
style InfraCheck fill:#1a1a40,color:#fff
style AppCheck fill:#1a1a40,color:#fff
style DBSolution fill:#0f4c75,color:#fff
style RedisSolution fill:#0f4c75,color:#fff
style TraefikSolution fill:#0f4c75,color:#fff
style ConfigFix fill:#0f4c75,color:#fff
style PrismaFix fill:#0f4c75,color:#fff
style AuthFix fill:#0f4c75,color:#fff
style Restart fill:#3282b8,color:#fff
style DeepDebug fill:#1b262c,color:#fff
style IdentifyService fill:#1a1a40,color:#fff
style CheckLogs fill:#1a1a40,color:#fff
style ConnCheck fill:#1a1a40,color:#fff
style ContainerShell fill:#0f3460,color:#fff
style PrismaStudio fill:#0f3460,color:#fff
style RedisInspect fill:#0f3460,color:#fff
style APITest fill:#0f3460,color:#fff
Start([ Phát Hiện Sự Cố]) --> CheckStatus{Kiểm tra<br/>Trạng thái Service}
CheckStatus -->|Tất cả Running| CheckLogs[ Xem Logs]
CheckStatus -->|Một số Down| IdentifyService[ Xác định Service<br/>Bị Lỗi]
IdentifyService --> ServiceType{Loại Service?}
ServiceType -->|Infrastructure| InfraCheck[ Kiểm tra<br/>Infrastructure]
ServiceType -->|Application| AppCheck[ Kiểm tra<br/>Application]
InfraCheck --> DBCheck{Database?}
InfraCheck --> RedisCheck{Redis?}
InfraCheck --> TraefikCheck{Traefik?}
DBCheck -->|Có| DBSolution[ Kiểm tra DATABASE_URL<br/> Verify kết nối Neon<br/> Kiểm tra IP whitelist]
RedisCheck -->|Có| RedisSolution[ Restart Redis<br/> Kiểm tra port mapping<br/> Verify connection string]
TraefikCheck -->|Có| TraefikSolution[ Kiểm tra labels<br/> Verify PathPrefix<br/> Kiểm tra health status]
AppCheck --> ErrorType{Loại Lỗi?}
ErrorType -->|Config| ConfigFix[ Kiểm tra .env variables<br/> Chạy init-project.sh]
ErrorType -->|Prisma| PrismaFix[ Kiểm tra migrations<br/> Regenerate client<br/> Reset database]
ErrorType -->|Auth| AuthFix[ Kiểm tra token expiry<br/> Verify keys<br/> Sync thời gian Docker]
CheckLogs --> LogAnalysis{Log Hiện<br/>Lỗi?}
LogAnalysis -->|Có| ErrorType
LogAnalysis -->|Không| ConnCheck[ Kiểm tra Kết nối]
ConnCheck --> GatewayTest{Gateway<br/>Truy Cập Được?}
GatewayTest -->|Không| TraefikCheck
GatewayTest -->|Có| ServiceTest{Service<br/>Truy Cập Được?}
ServiceTest -->|Không| AppCheck
ServiceTest -->|Có| Resolved([ Đã Giải Quyết])
DBSolution --> Restart[ Restart Services]
RedisSolution --> Restart
TraefikSolution --> Restart
ConfigFix --> Restart
PrismaFix --> Restart
AuthFix --> Restart
Restart --> Verify{Đã Sửa<br/>Xong?}
Verify -->|Có| Resolved
Verify -->|Không| DeepDebug[ Debug Sâu<br/>Hơn]
DeepDebug --> ContainerShell[Truy cập Container Shell]
DeepDebug --> PrismaStudio[Dùng Prisma Studio]
DeepDebug --> RedisInspect[Kiểm tra Redis]
DeepDebug --> APITest[Test API Trực tiếp]
style Start fill:#1a1a2e,color:#fff
style Resolved fill:#0f3460,color:#fff
style CheckStatus fill:#16213e,color:#fff
style ServiceType fill:#16213e,color:#fff
style ErrorType fill:#16213e,color:#fff
style DBCheck fill:#16213e,color:#fff
style RedisCheck fill:#16213e,color:#fff
style TraefikCheck fill:#16213e,color:#fff
style GatewayTest fill:#16213e,color:#fff
style ServiceTest fill:#16213e,color:#fff
style Verify fill:#16213e,color:#fff
style LogAnalysis fill:#16213e,color:#fff
style InfraCheck fill:#1a1a40,color:#fff
style AppCheck fill:#1a1a40,color:#fff
style DBSolution fill:#0f4c75,color:#fff
style RedisSolution fill:#0f4c75,color:#fff
style TraefikSolution fill:#0f4c75,color:#fff
style ConfigFix fill:#0f4c75,color:#fff
style PrismaFix fill:#0f4c75,color:#fff
style AuthFix fill:#0f4c75,color:#fff
style Restart fill:#3282b8,color:#fff
style DeepDebug fill:#1b262c,color:#fff
style IdentifyService fill:#1a1a40,color:#fff
style CheckLogs fill:#1a1a40,color:#fff
style ConnCheck fill:#1a1a40,color:#fff
style ContainerShell fill:#0f3460,color:#fff
style PrismaStudio fill:#0f3460,color:#fff
style RedisInspect fill:#0f3460,color:#fff
style APITest fill:#0f3460,color:#fff
```
---
@@ -136,55 +136,55 @@ flowchart TD
**Vấn đề**: `P1001: Can't reach database server` hoặc `Connection timed out`
* **Nguyên nhân 1**: Lỗi kết nối Internet (Neon là cloud DB).
* **Nguyên nhân 2**: Sai `DATABASE_URL` trong `.env`.
* **Nguyên nhân 3**: Địa chỉ IP bị chặn bởi Neon.
* **Nguyên nhân 1**: Lỗi kết nối Internet (Neon là cloud DB).
* **Nguyên nhân 2**: Sai `DATABASE_URL` trong `.env`.
* **Nguyên nhân 3**: Địa chỉ IP bị chặn bởi Neon.
**Giải pháp**:
1. Ping thử: `ping neon.tech`.
2. Kiểm tra file `deployments/local/.env.local`. URL nên có dạng:
`postgres://user:pass@ep-xyz.aws.neon.tech/neondb`
3. Vào Neon Dashboard -> Settings, đảm bảo đã chọn "Allow all IPs" hoặc thêm IP hiện tại của bạn.
1. Ping thử: `ping neon.tech`.
2. Kiểm tra file `deployments/local/.env.local`. URL nên có dạng:
`postgres://user:pass@ep-xyz.aws.neon.tech/neondb`
3. Vào Neon Dashboard -> Settings, đảm bảo đã chọn "Allow all IPs" hoặc thêm IP hiện tại của bạn.
**Vấn đề**: `P1003: Database does not exist`
* **Nguyên nhân**: Bạn kết nối sai tên database.
* **Sửa**: Kiểm tra cuối chuỗi kết nối (thường là `/neondb`). Nếu dùng tên DB tùy chỉnh, đảm bảo nó đã được tạo trên Neon.
* **Nguyên nhân**: Bạn kết nối sai tên database.
* **Sửa**: Kiểm tra cuối chuỗi kết nối (thường là `/neondb`). Nếu dùng tên DB tùy chỉnh, đảm bảo nó đã được tạo trên Neon.
### Redis
**Vấn đề**: `Redis connection refused` hoặc `ECONNREFUSED`
* **Nguyên nhân**: Container Redis chưa chạy hoặc sai port mapping.
* **Nguyên nhân**: Container Redis chưa chạy hoặc sai port mapping.
**Giải pháp**:
1. Kiểm tra trạng thái: `docker-compose ps redis`.
2. Khởi động lại: `docker-compose restart redis`.
3. Xem logs: `docker-compose logs redis`.
4. Chuỗi kết nối từ services:
* **Bên trong Docker**: `redis:6379`
* **Từ Host**: `localhost:6379`
1. Kiểm tra trạng thái: `docker-compose ps redis`.
2. Khởi động lại: `docker-compose restart redis`.
3. Xem logs: `docker-compose logs redis`.
4. Chuỗi kết nối từ services:
* **Bên trong Docker**: `redis:6379`
* **Từ Host**: `localhost:6379`
### Traefik Gateway
**Vấn đề**: `404 Not Found` khi gọi API (ví dụ: `http://localhost/api/v1/auth`)
* **Nguyên nhân**: Service bị down hoặc Labels cấu hình sai.
* **Nguyên nhân**: Service bị down hoặc Labels cấu hình sai.
**Giải pháp**:
1. Kiểm tra Traefik Dashboard tại http://localhost:8080.
* Tìm trong "HTTP Routers" và "Services".
* Nếu service không hiện, kiểm tra labels trong `docker-compose.yml`.
2. Đảm bảo `PathPrefix` trùng khớp với request:
```yaml
- "traefik.http.routers.iam.rule=PathPrefix(`/api/v1/auth`)"
```
3. Kiểm tra health checks xem service có healthy không.
1. Kiểm tra Traefik Dashboard tại http://localhost:8080.
* Tìm trong "HTTP Routers" và "Services".
* Nếu service không hiện, kiểm tra labels trong `docker-compose.yml`.
2. Đảm bảo `PathPrefix` trùng khớp với request:
```yaml
- "traefik.http.routers.iam.rule=PathPrefix(`/api/v1/auth`)"
```
3. Kiểm tra health checks xem service có healthy không.
**Vấn đề**: `Bad Gateway` hoặc `Gateway Timeout`
* **Nguyên nhân**: Service bị crash hoặc phản hồi quá lâu.
* **Sửa**: Xem logs cụ thể của service (`docker-compose logs iam-service`).
* **Nguyên nhân**: Service bị crash hoặc phản hồi quá lâu.
* **Sửa**: Xem logs cụ thể của service (`docker-compose logs iam-service`).
---
@@ -195,44 +195,44 @@ flowchart TD
**Triệu chứng**: Trạng thái container là `Exited (1)` hoặc `Restarting`.
**Debug**:
1. Xem logs ngay lập tức:
```bash
docker-compose logs iam-service
```
2. **Lỗi thường gặp**: `Config validation error`
* **Sửa**: Kiểm tra biến môi trường. Chạy `./scripts/setup/init-project.sh` để copy `.env`.
3. **Lỗi thường gặp**: `PrismaClientInitializationError`
* **Sửa**: Lỗi kết nối database (xem phần Infrastructure).
1. Xem logs ngay lập tức:
```bash
docker-compose logs iam-service
```
2. **Lỗi thường gặp**: `Config validation error`
* **Sửa**: Kiểm tra biến môi trường. Chạy `./scripts/setup/init-project.sh` để copy `.env`.
3. **Lỗi thường gặp**: `PrismaClientInitializationError`
* **Sửa**: Lỗi kết nối database (xem phần Infrastructure).
### Lỗi Prisma/Database
**Lỗi**: `P2025: Record to update not found`
* **Sửa**: Lỗi logic. Đảm bảo ID tồn tại trước khi update.
* **Sửa**: Lỗi logic. Đảm bảo ID tồn tại trước khi update.
**Lỗi**: `P2002: Unique constraint failed`
* **Sửa**: Bạn đang cố insert dữ liệu trùng lặp (ví dụ: trùng email).
* **Sửa**: Bạn đang cố insert dữ liệu trùng lặp (ví dụ: trùng email).
**Lỗi**: `Migration failed`
* **Sửa**:
1. Xóa thư mục `prisma/migrations` (chỉ làm ở dev!).
2. Reset DB: `pnpm prisma migrate reset`.
3. Regenerate client: `pnpm prisma generate`.
* **Sửa**:
1. Xóa thư mục `prisma/migrations` (chỉ làm ở dev!).
2. Reset DB: `pnpm prisma migrate reset`.
3. Regenerate client: `pnpm prisma generate`.
### Lỗi Authentication
**Vấn đề**: `401 Unauthorized` dù token hợp lệ
* **Nguyên nhân 1**: Token hết hạn.
* **Nguyên nhân 2**: Public key mismatch (Service không verify được token do IAM ký).
* **Nguyên nhân 3**: Lệch giờ (Thời gian Docker khác Host).
* **Nguyên nhân 1**: Token hết hạn.
* **Nguyên nhân 2**: Public key mismatch (Service không verify được token do IAM ký).
* **Nguyên nhân 3**: Lệch giờ (Thời gian Docker khác Host).
**Giải pháp**:
1. Kiểm tra logs xem lỗi verify JWT cụ thể.
2. Restart services để refresh keys.
3. Sync thời gian Docker: restart Docker Desktop.
1. Kiểm tra logs xem lỗi verify JWT cụ thể.
2. Restart services để refresh keys.
3. Sync thời gian Docker: restart Docker Desktop.
---
@@ -276,8 +276,8 @@ curl -v http://localhost/api/v1/auth/health/live
# Login (ví dụ)
curl -X POST http://localhost/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com", "password":"password"}'
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com", "password":"password"}'
```
---
@@ -300,14 +300,14 @@ docker-compose down -v
**H: Máy tính chạy rất chậm khi bật dự án.**
Đ: Docker tốn nhiều RAM.
1. Tắt các service không dùng (ví dụ `future-service`).
2. Tăng giới hạn resource trong cài đặt Docker Desktop.
1. Tắt các service không dùng (ví dụ `future-service`).
2. Tăng giới hạn resource trong cài đặt Docker Desktop.
---
## Mẹo Nhanh (Quick Tips)
### 🎯 Lệnh Debug Nhanh
### Lệnh Debug Nhanh
```bash
# Kiểm tra nhanh các service bị lỗi
@@ -329,7 +329,7 @@ docker stats --no-stream
docker system prune -a --volumes
```
### 🔍 Các Pattern Lỗi Thường Gặp
### Các Pattern Lỗi Thường Gặp
| Pattern Lỗi | Nguyên nhân Có thể | Cách Sửa Nhanh |
|-------------|-------------------|----------------|
@@ -341,13 +341,13 @@ docker system prune -a --volumes
| `502 Bad Gateway` | Service bị crash | Xem logs service |
| `Config validation error` | Thiếu biến môi trường | Chạy `init-project.sh` |
### 📋 Mẹo Phân Tích Logs
### Mẹo Phân Tích Logs
**Những gì cần tìm trong logs:**
- `Server listening on port XXXX` = Service khởi động thành công
- ⚠️ `Warning:` = Vấn đề không nghiêm trọng
- `Error:` = Vấn đề nghiêm trọng cần xử lý
- 🔍 `Trace:` = Chi tiết luồng thực thi
- `Server listening on port XXXX` = Service khởi động thành công
- `Warning:` = Vấn đề không nghiêm trọng
- `Error:` = Vấn đề nghiêm trọng cần xử lý
- `Trace:` = Chi tiết luồng thực thi
**Các pattern grep hữu ích:**
```bash
@@ -364,7 +364,7 @@ docker-compose logs | grep -i "prisma\|database\|p1001\|p1003"
docker-compose logs | grep -i "unauthorized\|401\|jwt\|token"
```
### 💾 Quản Lý Tài Nguyên
### Quản Lý Tài Nguyên
**Docker Resources Khuyến nghị:**
- **RAM**: Tối thiểu 4GB, Khuyến nghị 8GB
@@ -388,14 +388,14 @@ docker container prune
# Xóa images không dùng
docker image prune -a
# Xóa volumes không dùng (⚠️ mất dữ liệu!)
# Xóa volumes không dùng ( mất dữ liệu!)
docker volume prune
# Tùy chọn hạt nhân (⚠️ xóa mọi thứ!)
# Tùy chọn hạt nhân ( xóa mọi thứ!)
docker system prune -a --volumes
```
### 🛡️ Best Practices
### Best Practices
1. **Luôn kiểm tra logs trước** khi thay đổi gì
2. **Dùng Traefik Dashboard** (http://localhost:8080) để verify routing
@@ -406,16 +406,16 @@ docker system prune -a --volumes
7. **Giữ services đang chạy** mà bạn đang develop
8. **Tắt services** không dùng để tiết kiệm tài nguyên
### 🎨 Visual Indicators
### Visual Indicators
Khi đọc logs, chú ý các pattern sau:
- 🟢 `[INFO]` = Hoạt động bình thường
- 🟡 `[WARN]` = Cần theo dõi
- 🔴 `[ERROR]` = Cần xử lý ngay
- 🔵 `[DEBUG]` = Thông tin chi tiết
- `[TRACE]` = Luồng thực thi rất chi tiết
- `[INFO]` = Hoạt động bình thường
- `[WARN]` = Cần theo dõi
- `[ERROR]` = Cần xử lý ngay
- `[DEBUG]` = Thông tin chi tiết
- `[TRACE]` = Luồng thực thi rất chi tiết
### 🔗 Tài Liệu Liên Quan
### Tài Liệu Liên Quan
- [Hướng dẫn Local Deployment](./local-deployment.md) - Hướng dẫn setup
- [Hướng dẫn Development](./development.md) - Workflow phát triển