diff --git a/docs/en/guides/deployment.md b/docs/en/guides/deployment.md index 069e3d33..7b17c398 100644 --- a/docs/en/guides/deployment.md +++ b/docs/en/guides/deployment.md @@ -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='' \ - --from-literal=jwt-secret='' \ - -n staging + --from-literal=database-url='' \ + --from-literal=jwt-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='' \ - --from-literal=jwt-secret='' \ - --from-literal=jwt-refresh-secret='' \ - -n production + --from-literal=database-url='' \ + --from-literal=jwt-secret='' \ + --from-literal=jwt-refresh-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. diff --git a/docs/en/guides/development.md b/docs/en/guides/development.md index 26658299..4497261f 100644 --- a/docs/en/guides/development.md +++ b/docs/en/guides/development.md @@ -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 { ... } ### 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 { ... } ### 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; - ``` +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; + ``` -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 diff --git a/docs/en/guides/getting-started.md b/docs/en/guides/getting-started.md index 483494b0..8a739d8e 100644 --- a/docs/en/guides/getting-started.md +++ b/docs/en/guides/getting-started.md @@ -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
#1A5490"] --> B["🟠 Data/Cache
#CA6F1E"] - B --> C["🟢 Success
#1E8449"] - C --> D["🟡 Warning
#BA6610"] - D --> E["🔴 Error
#922B21"] - E --> F["🟣 Processing
#6C3483"] - F --> G["🔷 Info
#21618C"] - G --> H["⚫ Neutral
#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
#1A5490"] --> B[" Data/Cache
#CA6F1E"] + B --> C[" Success
#1E8449"] + C --> D[" Warning
#BA6610"] + D --> E[" Error
#922B21"] + E --> F[" Processing
#6C3483"] + F --> G[" Info
#21618C"] + G --> H[" Neutral
#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 **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 diff --git a/docs/en/guides/iam-migration.md b/docs/en/guides/iam-migration.md index 3c540554..12ec552f 100644 --- a/docs/en/guides/iam-migration.md +++ b/docs/en/guides/iam-migration.md @@ -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 - - # 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 + + # 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 diff --git a/docs/en/guides/kubernetes-local.md b/docs/en/guides/kubernetes-local.md index 028bbb3d..3c6b6872 100644 --- a/docs/en/guides/kubernetes-local.md +++ b/docs/en/guides/kubernetes-local.md @@ -10,39 +10,39 @@ ```mermaid graph TD - Start([🚀 Start]) --> EnvPrep[1️⃣ Environment Prep
Enable K8s in Docker Desktop] - EnvPrep --> BuildImg[2️⃣ Build Docker Image
docker build -t service:local] - BuildImg --> LoadImg[3️⃣ Load Image to Cluster
kind load docker-image] - LoadImg --> Secrets[4️⃣ Configure Secrets
kubectl create secret] - Secrets --> Deploy[5️⃣ Deploy Service
kubectl apply -f manifests] - Deploy --> Verify[6️⃣ Verify Deployment
kubectl get pods] - Verify --> Test[7️⃣ Test Service
Port Forward & Curl] - Test --> End([✅ Complete]) + Start([ Start]) --> EnvPrep[1⃣ Environment Prep
Enable K8s in Docker Desktop] + EnvPrep --> BuildImg[2⃣ Build Docker Image
docker build -t service:local] + BuildImg --> LoadImg[3⃣ Load Image to Cluster
kind load docker-image] + LoadImg --> Secrets[4⃣ Configure Secrets
kubectl create secret] + Secrets --> Deploy[5⃣ Deploy Service
kubectl apply -f manifests] + Deploy --> Verify[6⃣ Verify Deployment
kubectl get pods] + Verify --> Test[7⃣ Test Service
Port Forward & Curl] + Test --> End([ Complete]) - subgraph Deployment["📦 Deployment Resources"] - Deploy --> |Apply| ConfigMap[ConfigMap
Environment Config] - Deploy --> |Apply| K8sDeployment[Deployment
Pod Template] - Deploy --> |Apply| Service[Service
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
Environment Config] + Deploy --> |Apply| K8sDeployment[Deployment
Pod Template] + Deploy --> |Apply| Service[Service
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
Run `kind load docker-image` if using Kind | -| 🔴 **CrashLoopBackOff** | Pod keeps restarting | Check logs with `kubectl logs`
Verify `DATABASE_URL` in secrets
Ensure DB is accessible via `host.docker.internal` | -| 🟡 **Pending LoadBalancer** | Service External-IP shows `` | Normal on local—use `kubectl port-forward` instead | -| 🟡 **Connection Refused** | Can't connect after port-forward | Check pod is `Running` (not `CrashLoopBackOff`)
Verify correct port mapping | +| **ImagePullBackOff** | Pod stuck in `ImagePullBackOff` | Set `imagePullPolicy: Never` in deployment YAML
Run `kind load docker-image` if using Kind | +| **CrashLoopBackOff** | Pod keeps restarting | Check logs with `kubectl logs`
Verify `DATABASE_URL` in secrets
Ensure DB is accessible via `host.docker.internal` | +| **Pending LoadBalancer** | Service External-IP shows `` | Normal on local—use `kubectl port-forward` instead | +| **Connection Refused** | Can't connect after port-forward | Check pod is `Running` (not `CrashLoopBackOff`)
Verify correct port mapping | ### Essential Commands Reference ```bash -# 🔍 Debugging -kubectl get pods -n iam-local -w # Watch pods in real-time -kubectl describe pod -n iam-local # Detailed pod info + events -kubectl logs -f -n iam-local # Stream logs -kubectl exec -it -n iam-local -- /bin/sh # Shell into container +# Debugging +kubectl get pods -n iam-local -w # Watch pods in real-time +kubectl describe pod -n iam-local # Detailed pod info + events +kubectl logs -f -n iam-local # Stream logs +kubectl exec -it -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 -n iam-local --force # Force delete stuck pod -kubectl delete namespace iam-local --force --grace-period=0 # Force delete namespace +# Cleanup +kubectl delete pod -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 diff --git a/docs/en/guides/local-deployment.md b/docs/en/guides/local-deployment.md index c811e806..69081d09 100644 --- a/docs/en/guides/local-deployment.md +++ b/docs/en/guides/local-deployment.md @@ -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
Browser] --> Traefik - - Traefik[🌐 Traefik
API Gateway
:80, :8080] - - Traefik --> IAM[🔐 IAM Service
Authentication
:5001] - Traefik --> Admin[⚙️ Web Admin
Dashboard
:3000] - Traefik --> WebClient[🌍 Web Client
Application
:3001] - - IAM --> Redis[(💾 Redis
Cache
:6379)] - IAM --> DB[(🗄️ PostgreSQL
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
Browser] --> Traefik + + Traefik[ Traefik
API Gateway
:80, :8080] + + Traefik --> IAM[ IAM Service
Authentication
:5001] + Traefik --> Admin[ Web Admin
Dashboard
:3000] + Traefik --> WebClient[ Web Client
Application
:3001] + + IAM --> Redis[( Redis
Cache
:6379)] + IAM --> DB[( PostgreSQL
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 diff --git a/docs/en/guides/local-development.md b/docs/en/guides/local-development.md index 87321c0d..6e376640 100644 --- a/docs/en/guides/local-development.md +++ b/docs/en/guides/local-development.md @@ -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) diff --git a/docs/en/guides/mermaid.md b/docs/en/guides/mermaid.md index 26002e12..8bccc18e 100644 --- a/docs/en/guides/mermaid.md +++ b/docs/en/guides/mermaid.md @@ -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
#2980B9"] - A2["Purple
#8E44AD"] - A3["Green
#27AE60"] - end - - subgraph Secondary["🎨 Secondary Colors"] - B1["Orange
#E67E22"] - B2["Yellow
#F39C12"] - B3["Red
#C0392B"] - end - - subgraph Neutrals["🎨 Neutral Colors"] - C1["Dark Gray
#2C3E50"] - C2["Medium Gray
#34495E"] - C3["Light Text
#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
#2980B9"] + A2["Purple
#8E44AD"] + A3["Green
#27AE60"] + end + + subgraph Secondary[" Secondary Colors"] + B1["Orange
#E67E22"] + B2["Yellow
#F39C12"] + B3["Red
#C0392B"] + end + + subgraph Neutrals[" Neutral Colors"] + C1["Dark Gray
#2C3E50"] + C2["Medium Gray
#34495E"] + C3["Light Text
#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 `
` for line breaks -- ✅ Adjust diagram direction (TD, LR, RL, BT) -- ✅ Increase spacing between nodes +- Use shorter labels or `
` 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 --- diff --git a/docs/en/guides/neon-database.md b/docs/en/guides/neon-database.md index 2fed1a36..393e2778 100644 --- a/docs/en/guides/neon-database.md +++ b/docs/en/guides/neon-database.md @@ -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
goodgo-platform"] - - Dev["🔧 Development Branch
main"] - Staging["🧪 Staging Branch
staging"] - Prod["🚀 Production Branch
production"] - - LocalDev["💻 Local Dev
.env.local"] - K8sStaging["☸️ Kubernetes
staging namespace"] - K8sProd["☸️ Kubernetes
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
goodgo-platform"] + + Dev[" Development Branch
main"] + Staging[" Staging Branch
staging"] + Prod[" Production Branch
production"] + + LocalDev[" Local Dev
.env.local"] + K8sStaging[" Kubernetes
staging namespace"] + K8sProd[" Kubernetes
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
prisma/schema.prisma"] - CreateMig["🔧 Create Migration
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
migrate deploy"] - TestStaging["✅ Verify Schema"] - end - - subgraph Prod["🚀 Production"] - Approval["👤 Manual Approval"] - MigProd["📊 Run Migrations
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
prisma/schema.prisma"] + CreateMig[" Create Migration
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
migrate deploy"] + TestStaging[" Verify Schema"] + end + + subgraph Prod[" Production"] + Approval[" Manual Approval"] + MigProd[" Run Migrations
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
text"]` -- ✅ Escape HTML entities: `&` not `&` -- ✅ Use `
` for line breaks inside labels -- ❌ Avoid `
` without closing slash +- Use quotes for labels with special chars: `["Label
text"]` +- Escape HTML entities: `&` not `&` +- Use `
` for line breaks inside labels +- Avoid `
` 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 diff --git a/docs/en/guides/observability.md b/docs/en/guides/observability.md index c424f7b5..60ee9c03 100644 --- a/docs/en/guides/observability.md +++ b/docs/en/guides/observability.md @@ -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 ` | -| 🌐 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 ` | +| 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 diff --git a/docs/en/guides/troubleshooting.md b/docs/en/guides/troubleshooting.md index 6494efb6..26049a1b 100644 --- a/docs/en/guides/troubleshooting.md +++ b/docs/en/guides/troubleshooting.md @@ -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 - - # 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 -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
Status} - - CheckStatus -->|All Running| CheckLogs[📋 Check Logs] - CheckStatus -->|Some Down| IdentifyService[🎯 Identify Failed
Service] - - IdentifyService --> ServiceType{Service Type?} - - ServiceType -->|Infrastructure| InfraCheck[🔧 Infrastructure
Check] - ServiceType -->|Application| AppCheck[⚙️ Application
Check] - - InfraCheck --> DBCheck{Database?} - InfraCheck --> RedisCheck{Redis?} - InfraCheck --> TraefikCheck{Traefik?} - - DBCheck -->|Yes| DBSolution[✅ Check DATABASE_URL
✅ Verify Neon connection
✅ Check IP whitelist] - RedisCheck -->|Yes| RedisSolution[✅ Restart Redis
✅ Check port mapping
✅ Verify connection string] - TraefikCheck -->|Yes| TraefikSolution[✅ Check labels
✅ Verify PathPrefix
✅ Check health status] - - AppCheck --> ErrorType{Error Type?} - - ErrorType -->|Config| ConfigFix[✅ Check .env variables
✅ Run init-project.sh] - ErrorType -->|Prisma| PrismaFix[✅ Check migrations
✅ Regenerate client
✅ Reset database] - ErrorType -->|Auth| AuthFix[✅ Check token expiry
✅ Verify keys
✅ Sync Docker time] - - CheckLogs --> LogAnalysis{Log Shows
Error?} - LogAnalysis -->|Yes| ErrorType - LogAnalysis -->|No| ConnCheck[🌐 Check Connectivity] - - ConnCheck --> GatewayTest{Gateway
Reachable?} - GatewayTest -->|No| TraefikCheck - GatewayTest -->|Yes| ServiceTest{Service
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
Fixed?} - Verify -->|Yes| Resolved - Verify -->|No| DeepDebug[🛠️ Deep Debugging
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
Status} + + CheckStatus -->|All Running| CheckLogs[ Check Logs] + CheckStatus -->|Some Down| IdentifyService[ Identify Failed
Service] + + IdentifyService --> ServiceType{Service Type?} + + ServiceType -->|Infrastructure| InfraCheck[ Infrastructure
Check] + ServiceType -->|Application| AppCheck[ Application
Check] + + InfraCheck --> DBCheck{Database?} + InfraCheck --> RedisCheck{Redis?} + InfraCheck --> TraefikCheck{Traefik?} + + DBCheck -->|Yes| DBSolution[ Check DATABASE_URL
Verify Neon connection
Check IP whitelist] + RedisCheck -->|Yes| RedisSolution[ Restart Redis
Check port mapping
Verify connection string] + TraefikCheck -->|Yes| TraefikSolution[ Check labels
Verify PathPrefix
Check health status] + + AppCheck --> ErrorType{Error Type?} + + ErrorType -->|Config| ConfigFix[ Check .env variables
Run init-project.sh] + ErrorType -->|Prisma| PrismaFix[ Check migrations
Regenerate client
Reset database] + ErrorType -->|Auth| AuthFix[ Check token expiry
Verify keys
Sync Docker time] + + CheckLogs --> LogAnalysis{Log Shows
Error?} + LogAnalysis -->|Yes| ErrorType + LogAnalysis -->|No| ConnCheck[ Check Connectivity] + + ConnCheck --> GatewayTest{Gateway
Reachable?} + GatewayTest -->|No| TraefikCheck + GatewayTest -->|Yes| ServiceTest{Service
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
Fixed?} + Verify -->|Yes| Resolved + Verify -->|No| DeepDebug[ Deep Debugging
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 diff --git a/docs/vi/guides/deployment.md b/docs/vi/guides/deployment.md index b59eacdf..5dbe6b50 100644 --- a/docs/vi/guides/deployment.md +++ b/docs/vi/guides/deployment.md @@ -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='' \ - --from-literal=jwt-secret='' \ - -n staging + --from-literal=database-url='' \ + --from-literal=jwt-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='' \ - --from-literal=jwt-secret='' \ - --from-literal=jwt-refresh-secret='' \ - -n production + --from-literal=database-url='' \ + --from-literal=jwt-secret='' \ + --from-literal=jwt-refresh-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. diff --git a/docs/vi/guides/development.md b/docs/vi/guides/development.md index f4dd9df6..456ad497 100644 --- a/docs/vi/guides/development.md +++ b/docs/vi/guides/development.md @@ -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 { ... } ### 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 { ... } ### 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; - ``` +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; + ``` -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 diff --git a/docs/vi/guides/getting-started.md b/docs/vi/guides/getting-started.md index 4a877529..ff014ed4 100644 --- a/docs/vi/guides/getting-started.md +++ b/docs/vi/guides/getting-started.md @@ -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 **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 diff --git a/docs/vi/guides/iam-migration.md b/docs/vi/guides/iam-migration.md index cdee5ab8..6ee6ada6 100644 --- a/docs/vi/guides/iam-migration.md +++ b/docs/vi/guides/iam-migration.md @@ -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
Database & Code] - Backup --> Update[🔧 Step 2: Update Codebase
Package refs, Env vars] - Update --> Migrate[🗄️ Step 3: Run Prisma Migration
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
Database & Code] + Backup --> Update[ Step 2: Update Codebase
Package refs, Env vars] + Update --> Migrate[ Step 3: Run Prisma Migration
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
/api/v1/auth/*] - RBACAPI[👥 RBAC APIs
/api/v1/rbac/*] - MFAAPI[🔒 MFA APIs
/api/v1/mfa/*] - SessionAPI[🎫 Session APIs
/api/v1/sessions/*] - OIDCAPI[🆔 OIDC APIs
/api/v1/oidc/*] - end - - subgraph After["IAM Service (Sau)"] - AuthAPI2[🔐 Authentication APIs
/api/v1/auth/*
✅ Giữ nguyên] - RBACAPI2[👥 RBAC APIs
/api/v1/rbac/*
✅ Giữ nguyên] - MFAAPI2[🔒 MFA APIs
/api/v1/mfa/*
✅ Giữ nguyên] - SessionAPI2[🎫 Session APIs
/api/v1/sessions/*
✅ Giữ nguyên] - OIDCAPI2[🆔 OIDC APIs
/api/v1/oidc/*
✅ Giữ nguyên] - - IdentityAPI[🆔 Identity Management
/api/v1/identity/*
⭐ MỚI] - AccessAPI[🔑 Access Management
/api/v1/access/*
⭐ MỚI] - GovernanceAPI[📋 Governance
/api/v1/governance/*
⭐ MỚI] - end - - Before -.->|Backward Compatible
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
/api/v1/auth/*] + RBACAPI[ RBAC APIs
/api/v1/rbac/*] + MFAAPI[ MFA APIs
/api/v1/mfa/*] + SessionAPI[ Session APIs
/api/v1/sessions/*] + OIDCAPI[ OIDC APIs
/api/v1/oidc/*] + end + + subgraph After["IAM Service (Sau)"] + AuthAPI2[ Authentication APIs
/api/v1/auth/*
Giữ nguyên] + RBACAPI2[ RBAC APIs
/api/v1/rbac/*
Giữ nguyên] + MFAAPI2[ MFA APIs
/api/v1/mfa/*
Giữ nguyên] + SessionAPI2[ Session APIs
/api/v1/sessions/*
Giữ nguyên] + OIDCAPI2[ OIDC APIs
/api/v1/oidc/*
Giữ nguyên] + + IdentityAPI[ Identity Management
/api/v1/identity/*
MỚI] + AccessAPI[ Access Management
/api/v1/access/*
MỚI] + GovernanceAPI[ Governance
/api/v1/governance/*
MỚI] + end + + Before -.->|Backward Compatible
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:
✅ Zero downtime
✅ Easy rollback
✅ Safe testing] - BG2[Nhược điểm:
⚠️ Cần thêm resources
⚠️ Phức tạp hơn] - end - - subgraph InPlace["⚡ In-Place Migration"] - IP1[Ưu điểm:
✅ Simple setup
✅ Less resources
✅ Gradual migration] - IP2[Nhược điểm:
⚠️ Potential downtime
⚠️ Harder rollback
⚠️ 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:
Zero downtime
Easy rollback
Safe testing] + BG2[Nhược điểm:
Cần thêm resources
Phức tạp hơn] + end + + subgraph InPlace[" In-Place Migration"] + IP1[Ưu điểm:
Simple setup
Less resources
Gradual migration] + IP2[Nhược điểm:
Potential downtime
Harder rollback
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 --- diff --git a/docs/vi/guides/kubernetes-local.md b/docs/vi/guides/kubernetes-local.md index 3e6cf538..a531c572 100644 --- a/docs/vi/guides/kubernetes-local.md +++ b/docs/vi/guides/kubernetes-local.md @@ -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
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`
Verify `DATABASE_URL` trong secrets
Đảm bảo DB accessible qua `host.docker.internal` | -| 🟡 **Pending LoadBalancer** | Service External-IP hiển thị `` | 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`)
Verify port mapping chính xác | +| **ImagePullBackOff** | Pod bị kẹt ở trạng thái `ImagePullBackOff` | Đặt `imagePullPolicy: Never` trong deployment YAML
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`
Verify `DATABASE_URL` trong secrets
Đảm bảo DB accessible qua `host.docker.internal` | +| **Pending LoadBalancer** | Service External-IP hiển thị `` | 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`)
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 -n iam-local # Thông tin chi tiết pod + events -kubectl logs -f -n iam-local # Stream logs -kubectl exec -it -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 -n iam-local # Thông tin chi tiết pod + events +kubectl logs -f -n iam-local # Stream logs +kubectl exec -it -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 -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 -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/) diff --git a/docs/vi/guides/local-deployment.md b/docs/vi/guides/local-deployment.md index a2c7ea00..32d110a6 100644 --- a/docs/vi/guides/local-deployment.md +++ b/docs/vi/guides/local-deployment.md @@ -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
Browser] --> Traefik - - Traefik[🌐 Traefik
API Gateway
:80, :8080] - - Traefik --> IAM[🔐 IAM Service
Authentication
:5001] - Traefik --> Admin[⚙️ Web Admin
Dashboard
:3000] - Traefik --> WebClient[🌍 Web Client
Application
:3001] - - IAM --> Redis[(💾 Redis
Cache
:6379)] - IAM --> DB[(🗄️ PostgreSQL
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
Browser] --> Traefik + + Traefik[ Traefik
API Gateway
:80, :8080] + + Traefik --> IAM[ IAM Service
Authentication
:5001] + Traefik --> Admin[ Web Admin
Dashboard
:3000] + Traefik --> WebClient[ Web Client
Application
:3001] + + IAM --> Redis[( Redis
Cache
:6379)] + IAM --> DB[( PostgreSQL
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 diff --git a/docs/vi/guides/local-development.md b/docs/vi/guides/local-development.md index fc226d4c..b77843d5 100644 --- a/docs/vi/guides/local-development.md +++ b/docs/vi/guides/local-development.md @@ -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) diff --git a/docs/vi/guides/mermaid.md b/docs/vi/guides/mermaid.md index 7da3fe5d..d65bff68 100644 --- a/docs/vi/guides/mermaid.md +++ b/docs/vi/guides/mermaid.md @@ -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
#2C3E50"] --> B["💾 Data/Cache
#34495E"] - 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:#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
#2C3E50"] --> B[" Data/Cache
#34495E"] + 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:#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] + A[Start] + A[Process] -✅ ĐÚ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 + SAI: style Node fill:#2C3E50 -✅ ĐÚ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
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
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 ``` --- diff --git a/docs/vi/guides/neon-database.md b/docs/vi/guides/neon-database.md index c8cfed82..0f4fb13b 100644 --- a/docs/vi/guides/neon-database.md +++ b/docs/vi/guides/neon-database.md @@ -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["Branch: main
🔧 Development
Auto-scaling
Point-in-time restore"] - Staging["Branch: staging
🧪 Staging
Created from main
Pre-production testing"] - Production["Branch: production
🚀 Production
Created from main
Live environment"] - end - - subgraph Features["✨ Tính Năng Chính"] - F1["⚡ Serverless
No infrastructure"] - F2["🔄 Auto-scaling
Handle spikes"] - F3["💾 Backups
Point-in-time"] - F4["🔌 Pooling
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["Branch: main
Development
Auto-scaling
Point-in-time restore"] + Staging["Branch: staging
Staging
Created from main
Pre-production testing"] + Production["Branch: production
Production
Created from main
Live environment"] + end + + subgraph Features[" Tính Năng Chính"] + F1[" Serverless
No infrastructure"] + F2[" Auto-scaling
Handle spikes"] + F3[" Backups
Point-in-time"] + F4[" Pooling
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
Schema thay đổi]) --> Dev[📝 Development
Tạo migration mới
migrate.sh dev] - Dev --> Test{✅ Test
Migration
OK?} - - Test -->|❌ Không| Fix[🔧 Sửa lỗi
Cập nhật schema] - Fix --> Dev - - Test -->|✅ Có| Commit[📦 Commit
Migration files
+ schema.prisma] - Commit --> PR[🔀 Pull Request
Code review] - - PR --> CICD[⚙️ CI/CD Pipeline
Kiểm tra migration] - CICD --> Staging[🧪 Staging Branch
Auto-apply migration] - - Staging --> StagingTest{✅ Staging
Test OK?} - StagingTest -->|❌ Không| Rollback1[↩️ Rollback staging] - Rollback1 --> Fix - - StagingTest -->|✅ Có| Approval[👥 Approval
Production deploy] - Approval --> Prod[🚀 Production Branch
Apply migration] - - Prod --> ProdTest{✅ Production
OK?} - ProdTest -->|❌ Không| Rollback2[🚨 Emergency Rollback
Restore point-in-time] - ProdTest -->|✅ Có| Complete([✨ Hoàn thành
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
Schema thay đổi]) --> Dev[ Development
Tạo migration mới
migrate.sh dev] + Dev --> Test{ Test
Migration
OK?} + + Test -->| Không| Fix[ Sửa lỗi
Cập nhật schema] + Fix --> Dev + + Test -->| Có| Commit[ Commit
Migration files
+ schema.prisma] + Commit --> PR[ Pull Request
Code review] + + PR --> CICD[ CI/CD Pipeline
Kiểm tra migration] + CICD --> Staging[ Staging Branch
Auto-apply migration] + + Staging --> StagingTest{ Staging
Test OK?} + StagingTest -->| Không| Rollback1[↩ Rollback staging] + Rollback1 --> Fix + + StagingTest -->| Có| Approval[ Approval
Production deploy] + Approval --> Prod[ Production Branch
Apply migration] + + Prod --> ProdTest{ Production
OK?} + ProdTest -->| Không| Rollback2[ Emergency Rollback
Restore point-in-time] + ProdTest -->| Có| Complete([ Hoàn thành
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
Không kết nối được?]) --> Type{Loại
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
String OK?} - CheckURL -->|❌ Không| FixURL[✅ Kiểm tra:
• sslmode=require
• Credentials đúng
• Endpoint active] - CheckURL -->|✅ Có| CheckIP{IP trong
allowlist?} - CheckIP -->|❌ Không| AddIP[✅ Thêm IP vào
Neon Console] - CheckIP -->|✅ Có| CheckBranch{Branch
active?} - CheckBranch -->|❌ Không| ActivateBranch[✅ Kích hoạt branch
hoặc tạo mới] - CheckBranch -->|✅ Có| ContactSupport[📞 Liên hệ
Neon Support] - - MigIssue --> CheckEnv{DATABASE_URL
đã set?} - CheckEnv -->|❌ Không| SetEnv[✅ Export
DATABASE_URL] - CheckEnv -->|✅ Có| CheckSchema{Schema
đồng bộ?} - CheckSchema -->|❌ Không| ResetMig[✅ DEV ONLY:
prisma migrate reset] - CheckSchema -->|✅ Có| CheckTimeout{Connection
timeout?} - CheckTimeout -->|✅ Có| AddPooling[✅ Thêm
?pgbouncer=true] - CheckTimeout -->|❌ Không| CheckLimits[✅ Kiểm tra
Neon Console limits] - - PerfIssue --> HasPooling{Connection
Pooling ON?} - HasPooling -->|❌ Không| EnablePooling[✅ Thêm
?pgbouncer=true] - HasPooling -->|✅ Có| CheckQueries{Slow
queries?} - CheckQueries -->|✅ Có| AnalyzeQueries[✅ Neon Console
Query Analyzer] - CheckQueries -->|❌ Không| CheckIndexes{Indexes
tối ưu?} - CheckIndexes -->|❌ Không| AddIndexes[✅ Thêm indexes
vào Prisma schema] - CheckIndexes -->|✅ Có| ScalePlan[✅ Nâng cấp
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
Không kết nối được?]) --> Type{Loại
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
String OK?} + CheckURL -->| Không| FixURL[ Kiểm tra:
• sslmode=require
• Credentials đúng
• Endpoint active] + CheckURL -->| Có| CheckIP{IP trong
allowlist?} + CheckIP -->| Không| AddIP[ Thêm IP vào
Neon Console] + CheckIP -->| Có| CheckBranch{Branch
active?} + CheckBranch -->| Không| ActivateBranch[ Kích hoạt branch
hoặc tạo mới] + CheckBranch -->| Có| ContactSupport[ Liên hệ
Neon Support] + + MigIssue --> CheckEnv{DATABASE_URL
đã set?} + CheckEnv -->| Không| SetEnv[ Export
DATABASE_URL] + CheckEnv -->| Có| CheckSchema{Schema
đồng bộ?} + CheckSchema -->| Không| ResetMig[ DEV ONLY:
prisma migrate reset] + CheckSchema -->| Có| CheckTimeout{Connection
timeout?} + CheckTimeout -->| Có| AddPooling[ Thêm
?pgbouncer=true] + CheckTimeout -->| Không| CheckLimits[ Kiểm tra
Neon Console limits] + + PerfIssue --> HasPooling{Connection
Pooling ON?} + HasPooling -->| Không| EnablePooling[ Thêm
?pgbouncer=true] + HasPooling -->| Có| CheckQueries{Slow
queries?} + CheckQueries -->| Có| AnalyzeQueries[ Neon Console
Query Analyzer] + CheckQueries -->| Không| CheckIndexes{Indexes
tối ưu?} + CheckIndexes -->| Không| AddIndexes[ Thêm indexes
vào Prisma schema] + CheckIndexes -->| Có| ScalePlan[ Nâng cấp
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 diff --git a/docs/vi/guides/observability.md b/docs/vi/guides/observability.md index 625e05cc..c8d693f8 100644 --- a/docs/vi/guides/observability.md +++ b/docs/vi/guides/observability.md @@ -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
📈 Metrics Collector"] - Promtail["Promtail
📝 Log Collector"] - end - - subgraph Storage["💾 Storage"] - PrometheusDB["Prometheus TSDB
Metrics Storage"] - Loki["Loki
Log Aggregation"] - end - - subgraph Visualization["📊 Visualization"] - Grafana["Grafana
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
Metrics Collector"] + Promtail["Promtail
Log Collector"] + end + + subgraph Storage[" Storage"] + PrometheusDB["Prometheus TSDB
Metrics Storage"] + Loki["Loki
Log Aggregation"] + end + + subgraph Visualization[" Visualization"] + Grafana["Grafana
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 ` | -| 🌐 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 ` | +| 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 `___` -- ✅ **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 `___` +- **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** diff --git a/docs/vi/guides/troubleshooting.md b/docs/vi/guides/troubleshooting.md index 0d3d1884..e2b1ff13 100644 --- a/docs/vi/guides/troubleshooting.md +++ b/docs/vi/guides/troubleshooting.md @@ -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 - - # 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 -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
Trạng thái Service} - - CheckStatus -->|Tất cả Running| CheckLogs[📋 Xem Logs] - CheckStatus -->|Một số Down| IdentifyService[🎯 Xác định Service
Bị Lỗi] - - IdentifyService --> ServiceType{Loại Service?} - - ServiceType -->|Infrastructure| InfraCheck[🔧 Kiểm tra
Infrastructure] - ServiceType -->|Application| AppCheck[⚙️ Kiểm tra
Application] - - InfraCheck --> DBCheck{Database?} - InfraCheck --> RedisCheck{Redis?} - InfraCheck --> TraefikCheck{Traefik?} - - DBCheck -->|Có| DBSolution[✅ Kiểm tra DATABASE_URL
✅ Verify kết nối Neon
✅ Kiểm tra IP whitelist] - RedisCheck -->|Có| RedisSolution[✅ Restart Redis
✅ Kiểm tra port mapping
✅ Verify connection string] - TraefikCheck -->|Có| TraefikSolution[✅ Kiểm tra labels
✅ Verify PathPrefix
✅ Kiểm tra health status] - - AppCheck --> ErrorType{Loại Lỗi?} - - ErrorType -->|Config| ConfigFix[✅ Kiểm tra .env variables
✅ Chạy init-project.sh] - ErrorType -->|Prisma| PrismaFix[✅ Kiểm tra migrations
✅ Regenerate client
✅ Reset database] - ErrorType -->|Auth| AuthFix[✅ Kiểm tra token expiry
✅ Verify keys
✅ Sync thời gian Docker] - - CheckLogs --> LogAnalysis{Log Hiện
Lỗi?} - LogAnalysis -->|Có| ErrorType - LogAnalysis -->|Không| ConnCheck[🌐 Kiểm tra Kết nối] - - ConnCheck --> GatewayTest{Gateway
Truy Cập Được?} - GatewayTest -->|Không| TraefikCheck - GatewayTest -->|Có| ServiceTest{Service
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
Xong?} - Verify -->|Có| Resolved - Verify -->|Không| DeepDebug[🛠️ Debug Sâu
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
Trạng thái Service} + + CheckStatus -->|Tất cả Running| CheckLogs[ Xem Logs] + CheckStatus -->|Một số Down| IdentifyService[ Xác định Service
Bị Lỗi] + + IdentifyService --> ServiceType{Loại Service?} + + ServiceType -->|Infrastructure| InfraCheck[ Kiểm tra
Infrastructure] + ServiceType -->|Application| AppCheck[ Kiểm tra
Application] + + InfraCheck --> DBCheck{Database?} + InfraCheck --> RedisCheck{Redis?} + InfraCheck --> TraefikCheck{Traefik?} + + DBCheck -->|Có| DBSolution[ Kiểm tra DATABASE_URL
Verify kết nối Neon
Kiểm tra IP whitelist] + RedisCheck -->|Có| RedisSolution[ Restart Redis
Kiểm tra port mapping
Verify connection string] + TraefikCheck -->|Có| TraefikSolution[ Kiểm tra labels
Verify PathPrefix
Kiểm tra health status] + + AppCheck --> ErrorType{Loại Lỗi?} + + ErrorType -->|Config| ConfigFix[ Kiểm tra .env variables
Chạy init-project.sh] + ErrorType -->|Prisma| PrismaFix[ Kiểm tra migrations
Regenerate client
Reset database] + ErrorType -->|Auth| AuthFix[ Kiểm tra token expiry
Verify keys
Sync thời gian Docker] + + CheckLogs --> LogAnalysis{Log Hiện
Lỗi?} + LogAnalysis -->|Có| ErrorType + LogAnalysis -->|Không| ConnCheck[ Kiểm tra Kết nối] + + ConnCheck --> GatewayTest{Gateway
Truy Cập Được?} + GatewayTest -->|Không| TraefikCheck + GatewayTest -->|Có| ServiceTest{Service
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
Xong?} + Verify -->|Có| Resolved + Verify -->|Không| DeepDebug[ Debug Sâu
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