Migrate
This commit is contained in:
246
microservices/docs/en/guides/deployment.md
Normal file
246
microservices/docs/en/guides/deployment.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# Deployment Guide
|
||||
|
||||
>Deployment strategies for GoodGo Microservices Platform across Local, Staging, and Production environments using Kubernetes and Neon PostgreSQL
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Deployment Architecture](#deployment-architecture)
|
||||
2. [Prerequisites](#prerequisites)
|
||||
3. [Database Setup (Neon)](#database-setup-neon)
|
||||
4. [Local Deployment](#local-deployment)
|
||||
5. [CI/CD Pipeline](#cicd-pipeline)
|
||||
6. [Staging Deployment](#staging-deployment)
|
||||
7. [Production Deployment](#production-deployment)
|
||||
8. [Scaling & Resilience](#scaling--resilience)
|
||||
9. [Rollback Procedures](#rollback-procedures)
|
||||
|
||||
---
|
||||
|
||||
## Deployment Architecture
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## Database Setup (Neon)
|
||||
|
||||
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).
|
||||
|
||||
---
|
||||
|
||||
## Local Deployment
|
||||
|
||||
For local development, we use Docker Compose.
|
||||
|
||||
```bash
|
||||
# 1. Setup Environment
|
||||
cp deployments/local/env.local.example deployments/local/.env.local
|
||||
# Edit .env.local with Neon `main` branch connection string
|
||||
|
||||
# 2. Start Infrastructure (Redis, Traefik, etc.)
|
||||
cd deployments/local
|
||||
docker-compose up -d
|
||||
|
||||
# 3. Start Services (Hot-reload)
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD Pipeline
|
||||
|
||||
We use GitHub Actions for automated deployments.
|
||||
|
||||
| Workflow | Trigger | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `ci-check.yml` | Pull Request | Runs unit tests, linting, and build check. |
|
||||
| `deploy-staging.yml` | Push to `develop` | Build image -> Deploy to Staging Namespace. |
|
||||
| `deploy-prod.yml` | Release / Tag | Build image -> Deploy to Production Namespace. |
|
||||
|
||||
### Secrets Configuration (GitHub)
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## Staging Deployment
|
||||
|
||||
Staging mirrors production but uses cost-effective resources.
|
||||
|
||||
### Manual Deployment
|
||||
|
||||
```bash
|
||||
# 1. Create Secrets
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='<STAGING_NEON_URL>' \
|
||||
--from-literal=jwt-secret='<RANDOM_SECRET>' \
|
||||
-n staging
|
||||
|
||||
# 2. Apply Manifests
|
||||
kubectl apply -f deployments/staging/kubernetes/ -n staging
|
||||
|
||||
# 3. Verify
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## Production Deployment
|
||||
|
||||
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).
|
||||
|
||||
### 2. Manual Deployment Steps
|
||||
|
||||
```bash
|
||||
# 1. Create Namespace
|
||||
kubectl create namespace production
|
||||
|
||||
# 2. Create Sealed Secrets (Recommended) or Standard Secrets
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=database-url='<PROD_NEON_URL>' \
|
||||
--from-literal=jwt-secret='<SECURE_RANDOM_SECRET>' \
|
||||
--from-literal=jwt-refresh-secret='<SECURE_RANDOM_SECRET>' \
|
||||
-n production
|
||||
|
||||
# 3. Deploy
|
||||
kubectl apply -f deployments/production/kubernetes/ -n production
|
||||
```
|
||||
|
||||
### 3. Verification
|
||||
|
||||
```bash
|
||||
# Check Rollout Status
|
||||
kubectl rollout status deployment/iam-service -n production
|
||||
|
||||
# Check Logs
|
||||
kubectl logs -l app=iam-service -n production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scaling & Resilience
|
||||
|
||||
### Horizontal Pod Autoscaler (HPA)
|
||||
|
||||
We use HPA to automatically scale pods based on CPU/Memory.
|
||||
|
||||
```yaml
|
||||
# Example HPA Config
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: iam-service-hpa
|
||||
spec:
|
||||
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).
|
||||
|
||||
---
|
||||
|
||||
## Rollback Procedures
|
||||
|
||||
If a deployment fails or introduces a critical bug:
|
||||
|
||||
### Kubernetes Rollback
|
||||
|
||||
```bash
|
||||
# Undo last deployment
|
||||
kubectl rollout undo deployment/iam-service -n production
|
||||
|
||||
# Undo to specific revision
|
||||
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.
|
||||
330
microservices/docs/en/guides/development.md
Normal file
330
microservices/docs/en/guides/development.md
Normal file
@@ -0,0 +1,330 @@
|
||||
# Development Guide
|
||||
|
||||
Comprehensive standards and workflows for contributing to the GoodGo Microservices Platform.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Project Structure](#project-structure)
|
||||
2. [Code Standards](#code-standards)
|
||||
3. [Git Workflow](#git-workflow)
|
||||
4. [Backend Development](#backend-development)
|
||||
5. [Testing Strategy](#testing-strategy)
|
||||
6. [Database Workflow](#database-workflow)
|
||||
7. [Kubernetes Deployment](#kubernetes-deployment)
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
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)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Standards
|
||||
|
||||
### 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*
|
||||
|
||||
### Bilingual Comments
|
||||
|
||||
For core logic and public APIs, assume both international and Vietnamese developers reading the code.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* EN: Validates user credentials and returns a token
|
||||
* VI: Xác thực thông tin người dùng và trả về token
|
||||
*/
|
||||
async login(dto: LoginDto): Promise<TokenResponse> { ... }
|
||||
```
|
||||
|
||||
### TypeScript Usage
|
||||
|
||||
* **Strict Mode**: Enabled in `tsconfig.json`. No `any` allowed (use `unknown` if needed).
|
||||
* **DTOs**: Use Zod for runtime validation and type inference.
|
||||
* **Return Types**: Explicitly declare return types for all public methods.
|
||||
|
||||
---
|
||||
|
||||
## Git Workflow
|
||||
|
||||
### 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`).
|
||||
|
||||
```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 Messages
|
||||
|
||||
We follow [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
feat(iam): add multi-factor authentication
|
||||
fix(db): correct unique constraint on email
|
||||
docs(guide): update development setup
|
||||
style: format code with prettier
|
||||
refactor: simplify auth middleware
|
||||
test: add unit tests for user service
|
||||
chore: update dependencies
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backend Development
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### Creating a New API Endpoint
|
||||
|
||||
1. **Define DTO** (`modules/user/user.dto.ts`):
|
||||
```typescript
|
||||
export const CreateUserDto = z.object({
|
||||
email: z.string().email(),
|
||||
name: z.string().min(2),
|
||||
});
|
||||
export type CreateUserDto = z.infer<typeof CreateUserDto>;
|
||||
```
|
||||
|
||||
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 })`.
|
||||
|
||||
4. **Register Route** (`modules/user/index.ts`):
|
||||
* Add to Express router with middlewares.
|
||||
|
||||
### Error Handling
|
||||
|
||||
Always use the custom error classes from `core/errors`:
|
||||
|
||||
```typescript
|
||||
import { NotFoundError, ConflictError } from '../../core/errors';
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundError('User not found');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### 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`
|
||||
|
||||
### E2E Tests (`tests/**/*.e2e.ts`)
|
||||
|
||||
* **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)
|
||||
|
||||
---
|
||||
|
||||
## Database Workflow
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### Seed Data
|
||||
|
||||
Populate database with initial data:
|
||||
```bash
|
||||
./scripts/db/seed.sh iam-service
|
||||
```
|
||||
|
||||
### Visualizing Data
|
||||
|
||||
Use Prisma Studio:
|
||||
```bash
|
||||
pnpm --filter @goodgo/iam-service prisma studio
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Kubernetes Deployment
|
||||
|
||||
For local Kubernetes testing (Docker Desktop / Minikube):
|
||||
|
||||
```bash
|
||||
# 1. Build images
|
||||
docker build -t goodgo/iam-service:latest -f services/iam-service/Dockerfile .
|
||||
|
||||
# 2. Deploy
|
||||
cd deployments/local/kubernetes
|
||||
./deploy.sh
|
||||
|
||||
# 3. Verify
|
||||
kubectl get pods -n iam-local
|
||||
kubectl logs -f -l app=iam-service -n iam-local
|
||||
```
|
||||
|
||||
See [Kubernetes Guide](./kubernetes-local.md) for detailed setup.
|
||||
259
microservices/docs/en/guides/getting-started.md
Normal file
259
microservices/docs/en/guides/getting-started.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# Getting Started
|
||||
|
||||
> **Note**: This guide assumes you are setting up the project on macOS or Linux. Windows users should use WSL2.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Prerequisites](#prerequisites)
|
||||
2. [Architecture Overview](#architecture-overview)
|
||||
3. [Project Structure](#project-structure)
|
||||
4. [Installation & Setup](#installation--setup)
|
||||
5. [Development Workflow](#development-workflow)
|
||||
6. [Common Commands](#common-commands)
|
||||
7. [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
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)
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
GoodGo Platform uses a microservices architecture with a shared infrastructure layer.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### Color Palette
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[" Primary<br/>#1A5490"] --> B[" Data/Cache<br/>#CA6F1E"]
|
||||
B --> C[" Success<br/>#1E8449"]
|
||||
C --> D[" Warning<br/>#BA6610"]
|
||||
D --> E[" Error<br/>#922B21"]
|
||||
E --> F[" Processing<br/>#6C3483"]
|
||||
F --> G[" Info<br/>#21618C"]
|
||||
G --> H[" Neutral<br/>#34495E"]
|
||||
|
||||
style A fill:#1A5490,stroke:#154360,color:#ECF0F1
|
||||
style B fill:#CA6F1E,stroke:#A04000,color:#ECF0F1
|
||||
style C fill:#1E8449,stroke:#186A3B,color:#ECF0F1
|
||||
style D fill:#BA6610,stroke:#935116,color:#ECF0F1
|
||||
style E fill:#922B21,stroke:#78281F,color:#ECF0F1
|
||||
style F fill:#6C3483,stroke:#512E5F,color:#ECF0F1
|
||||
style G fill:#21618C,stroke:#1B4F72,color:#ECF0F1
|
||||
style H fill:#34495E,stroke:#2C3E50,color:#ECF0F1
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
## Installation & Setup
|
||||
|
||||
### 1. Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
```
|
||||
|
||||
### 2. Configure Environment
|
||||
|
||||
Each service and the local infrastructure needs environment variables. We provide templates for these.
|
||||
|
||||
```bash
|
||||
# Initialize project setup (copies .env.example to .env)
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
|
||||
### 3. Setup Neon Database
|
||||
|
||||
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`:
|
||||
|
||||
```env
|
||||
DATABASE_URL="postgres://user:pass@ep-xyz.region.neon.tech/neondb"
|
||||
```
|
||||
|
||||
### 4. Start Infrastructure
|
||||
|
||||
Start the supporting infrastructure (Redis, Traefik, Observability) using Docker Compose.
|
||||
|
||||
```bash
|
||||
cd deployments/local
|
||||
docker-compose up -d
|
||||
# Expected output: Containers for traefik, redis, kafka created
|
||||
```
|
||||
|
||||
### 5. Install Dependencies
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 6. Setup Database Schema
|
||||
|
||||
Push the Prisma schema to your Neon database.
|
||||
|
||||
```bash
|
||||
# Run migrations for IAM service
|
||||
pnpm --filter @goodgo/iam-service prisma migrate dev
|
||||
```
|
||||
|
||||
### 7. Start Services
|
||||
|
||||
Start all backend services in development mode.
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
# or start specific service
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### 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`.
|
||||
|
||||
### 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`.
|
||||
|
||||
## Common Commands
|
||||
|
||||
| Command | Description |
|
||||
| :--- | :--- |
|
||||
| `pnpm install` | Install all dependencies |
|
||||
| `pnpm dev` | Start all services in dev mode |
|
||||
| `pnpm build` | Build all packages and services |
|
||||
| `pnpm test` | Run unit tests |
|
||||
| `pnpm lint` | Lint code |
|
||||
| `docker-compose up -d` | Start local infra |
|
||||
| `docker-compose down` | Stop local infra |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Conflicts
|
||||
|
||||
**Error**: `Bind for 0.0.0.0:80 failed: port is already allocated`
|
||||
|
||||
**Solution**: Check what's using port 80 (likely another web server) and stop it, or change Traefik ports in `docker-compose.yml`.
|
||||
|
||||
```bash
|
||||
lsof -i :80
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
### Database Connection Failed
|
||||
|
||||
**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.
|
||||
|
||||
### 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`.
|
||||
|
||||
## 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
|
||||
351
microservices/docs/en/guides/iam-authentication.md
Normal file
351
microservices/docs/en/guides/iam-authentication.md
Normal file
@@ -0,0 +1,351 @@
|
||||
# IAM Service Authentication Guide
|
||||
|
||||
> Complete guide for authentication using GoodGo IAM Service with OAuth2/OpenID Connect.
|
||||
|
||||
## Overview
|
||||
|
||||
The IAM Service provides OAuth2/OIDC authentication using Duende IdentityServer:
|
||||
- **Password Grant** - User login with email/password
|
||||
- **Refresh Token** - Token renewal without re-authentication
|
||||
- **Client Credentials** - Service-to-service authentication
|
||||
- **Email Verification** - SMTP-based email confirmation
|
||||
- **Two-Factor Authentication (2FA)** - TOTP with QR code and recovery codes
|
||||
- **Social Login** - Google and Facebook OAuth integration
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Register a User
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/api/v1/auth/register \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "user@example.com",
|
||||
"password": "Password123!",
|
||||
"firstName": "John",
|
||||
"lastName": "Doe"
|
||||
}'
|
||||
```
|
||||
|
||||
### 2. Login (Get Tokens)
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/connect/token \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=password" \
|
||||
-d "username=user@example.com" \
|
||||
-d "password=Password123!" \
|
||||
-d "scope=openid profile email offline_access"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"access_token": "eyJhbGciOiJSUzI1NiIs...",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 900,
|
||||
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
|
||||
"scope": "openid profile email offline_access"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Use Access Token
|
||||
|
||||
```bash
|
||||
curl http://localhost:5001/api/v1/users/me \
|
||||
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
|
||||
```
|
||||
|
||||
## OAuth2 Grant Types
|
||||
|
||||
### Password Grant (User Login)
|
||||
|
||||
For trusted first-party applications where users enter credentials directly.
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/connect/token \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=password" \
|
||||
-d "username=user@example.com" \
|
||||
-d "password=Password123!" \
|
||||
-d "scope=openid profile email offline_access"
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `grant_type` | Yes | Must be `password` |
|
||||
| `username` | Yes | User's email |
|
||||
| `password` | Yes | User's password |
|
||||
| `scope` | No | Space-separated scopes |
|
||||
|
||||
### Refresh Token
|
||||
|
||||
Renew access token without re-entering credentials.
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/connect/token \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=refresh_token" \
|
||||
-d "refresh_token=eyJhbGciOiJSUzI1NiIs..."
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `grant_type` | Yes | Must be `refresh_token` |
|
||||
| `refresh_token` | Yes | Valid refresh token |
|
||||
|
||||
### Client Credentials (Service-to-Service)
|
||||
|
||||
For backend services authenticating without user context.
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/connect/token \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=client_credentials" \
|
||||
-d "client_id=goodgo-service" \
|
||||
-d "client_secret=service-secret" \
|
||||
-d "scope=api"
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `grant_type` | Yes | Must be `client_credentials` |
|
||||
| `client_id` | Yes | Registered client ID |
|
||||
| `client_secret` | Yes | Client secret |
|
||||
| `scope` | No | Requested scopes |
|
||||
|
||||
> **Note:** Client applications must be registered in the database before use.
|
||||
|
||||
## Token Lifetimes
|
||||
|
||||
| Token Type | Lifetime | Use |
|
||||
|------------|----------|-----|
|
||||
| Access Token | 15 minutes | API authorization |
|
||||
| Refresh Token | 7 days | Token renewal |
|
||||
|
||||
## Available Scopes
|
||||
|
||||
| Scope | Description |
|
||||
|-------|-------------|
|
||||
| `openid` | Required for OIDC |
|
||||
| `profile` | User profile (name) |
|
||||
| `email` | User email |
|
||||
| `roles` | User roles |
|
||||
| `offline_access` | Get refresh token |
|
||||
| `api` | API access |
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Authentication
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | `/api/v1/auth/register` | Register new user |
|
||||
| `POST` | `/connect/token` | OAuth2 token endpoint |
|
||||
| `POST` | `/api/v1/auth/change-password` | Change password (auth required) |
|
||||
| `POST` | `/api/v1/auth/logout` | Revoke tokens (auth required) |
|
||||
|
||||
### Email Verification
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | `/api/v1/auth/send-verification-email` | Send email verification link (auth required) |
|
||||
| `POST` | `/api/v1/auth/confirm-email` | Confirm email with token |
|
||||
|
||||
### Two-Factor Authentication (2FA)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | `/api/v1/auth/2fa/enable` | Enable 2FA (get QR code) (auth required) |
|
||||
| `POST` | `/api/v1/auth/2fa/verify` | Verify TOTP code & activate (auth required) |
|
||||
| `POST` | `/api/v1/auth/2fa/disable` | Disable 2FA (auth required) |
|
||||
|
||||
### Social Login
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/v1/auth/external-login/{provider}` | Initiate OAuth flow (Google/Facebook) |
|
||||
| `GET` | `/api/v1/auth/external-callback` | Handle OAuth callback |
|
||||
| `GET` | `/api/v1/auth/linked-accounts` | Get linked OAuth providers (auth required) |
|
||||
|
||||
### User Management
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/v1/users` | List users (paginated) |
|
||||
| `GET` | `/api/v1/users/me` | Current user info |
|
||||
| `GET` | `/api/v1/users/{id}` | Get user by ID |
|
||||
| `PUT` | `/api/v1/users/{id}` | Update user |
|
||||
| `DELETE` | `/api/v1/users/{id}` | Delete user (soft) |
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### JavaScript/TypeScript
|
||||
|
||||
```typescript
|
||||
// Login
|
||||
const response = await fetch('http://localhost:5001/connect/token', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({
|
||||
grant_type: 'password',
|
||||
username: 'user@example.com',
|
||||
password: 'Password123!',
|
||||
scope: 'openid profile email offline_access'
|
||||
})
|
||||
});
|
||||
const { access_token, refresh_token } = await response.json();
|
||||
|
||||
// Use token
|
||||
const user = await fetch('http://localhost:5001/api/v1/users/me', {
|
||||
headers: { 'Authorization': `Bearer ${access_token}` }
|
||||
}).then(r => r.json());
|
||||
```
|
||||
|
||||
### C# / .NET
|
||||
|
||||
```csharp
|
||||
// Login
|
||||
var client = new HttpClient();
|
||||
var content = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
["grant_type"] = "password",
|
||||
["username"] = "user@example.com",
|
||||
["password"] = "Password123!",
|
||||
["scope"] = "openid profile email offline_access"
|
||||
});
|
||||
var response = await client.PostAsync("http://localhost:5001/connect/token", content);
|
||||
var tokens = await response.Content.ReadFromJsonAsync<TokenResponse>();
|
||||
|
||||
// Use token
|
||||
client.DefaultRequestHeaders.Authorization =
|
||||
new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
|
||||
var user = await client.GetFromJsonAsync<UserDto>("/api/v1/users/me");
|
||||
```
|
||||
|
||||
## Email Verification
|
||||
|
||||
### Send Verification Email
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/api/v1/auth/send-verification-email \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email": "user@example.com"}'
|
||||
```
|
||||
|
||||
### Confirm Email
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/api/v1/auth/confirm-email \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"userId": "user-guid", "token": "confirmation-token"}'
|
||||
```
|
||||
|
||||
## Two-Factor Authentication (2FA)
|
||||
|
||||
### Enable 2FA
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/api/v1/auth/2fa/enable \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"secretKey": "JBSWY3DPEHPK3PXP",
|
||||
"qrCodeBase64": "data:image/png;base64,...",
|
||||
"recoveryCodes": ["code1", "code2", "code3"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Verify 2FA Code
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/api/v1/auth/2fa/verify \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"code": "123456"}'
|
||||
```
|
||||
|
||||
### Disable 2FA
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5001/api/v1/auth/2fa/disable \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"code": "123456"}'
|
||||
```
|
||||
|
||||
## Social Login
|
||||
|
||||
### Initiate OAuth Flow
|
||||
|
||||
Redirect user to:
|
||||
```
|
||||
GET http://localhost:5001/api/v1/auth/external-login/Google?returnUrl=http://your-app/callback
|
||||
GET http://localhost:5001/api/v1/auth/external-login/Facebook?returnUrl=http://your-app/callback
|
||||
```
|
||||
|
||||
### Get Linked Accounts
|
||||
|
||||
```bash
|
||||
curl http://localhost:5001/api/v1/auth/linked-accounts \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"linkedProviders": [
|
||||
{"provider": "Google", "providerDisplayName": "Google"},
|
||||
{"provider": "Facebook", "providerDisplayName": "Facebook"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
### Common Errors
|
||||
|
||||
| Error | HTTP Code | Description |
|
||||
|-------|-----------|-------------|
|
||||
| `invalid_grant` | 400 | Invalid credentials |
|
||||
| `invalid_client` | 400 | Unknown client_id |
|
||||
| `invalid_scope` | 400 | Invalid scope requested |
|
||||
| `unauthorized` | 401 | Invalid/expired token |
|
||||
|
||||
### Error Response Format
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "invalid_grant",
|
||||
"error_description": "The username or password is incorrect."
|
||||
}
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Store tokens securely** - Use httpOnly cookies or secure storage
|
||||
2. **Refresh tokens proactively** - Before access token expires
|
||||
3. **Use HTTPS in production** - Never send credentials over HTTP
|
||||
4. **Logout properly** - Call logout endpoint to revoke tokens
|
||||
5. **Validate tokens server-side** - Don't trust client-side validation
|
||||
|
||||
## Swagger UI
|
||||
|
||||
Access interactive API documentation:
|
||||
- **Local**: http://localhost:5001/swagger
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [IAM Migration Guide](./iam-migration.md)
|
||||
- [Local Development](./local-development.md)
|
||||
- [Security Architecture](../architecture/security-architecture.md)
|
||||
391
microservices/docs/en/guides/iam-migration.md
Normal file
391
microservices/docs/en/guides/iam-migration.md
Normal file
@@ -0,0 +1,391 @@
|
||||
# Migration Guide: Auth Service → IAM Service
|
||||
|
||||
This document guides you through migrating from `auth-service` to `iam-service`.
|
||||
|
||||
## Overview
|
||||
|
||||
IAM Service is an extended version of Auth Service with additional features for Identity Management, Access Management, and Governance & Compliance. All Auth Service API endpoints remain unchanged to ensure backward compatibility.
|
||||
|
||||
## Migration Workflow
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
**All existing endpoints continue to work normally:**
|
||||
|
||||
- `/api/v1/auth/*` - Authentication endpoints
|
||||
- `/api/v1/rbac/*` - RBAC endpoints
|
||||
- `/api/v1/mfa/*` - MFA endpoints
|
||||
- `/api/v1/sessions/*` - Session management endpoints
|
||||
- `/api/v1/oidc/*` - OIDC endpoints
|
||||
|
||||
No breaking changes. Existing clients can continue using these endpoints without any modifications.
|
||||
|
||||
## Architecture Comparison
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. Service Name
|
||||
|
||||
- **Old**: `auth-service`
|
||||
- **New**: `iam-service`
|
||||
|
||||
### 2. Package Name
|
||||
|
||||
- **Old**: `@goodgo/auth-service`
|
||||
- **New**: `@goodgo/iam-service`
|
||||
|
||||
### 3. Database Schema
|
||||
|
||||
Database schema is extended with new models but **does not delete or modify** existing models:
|
||||
|
||||
**New models added:**
|
||||
- `Organization` - Organization management
|
||||
- `Group` - Group management
|
||||
- `GroupMember` - Group members
|
||||
- `GroupPermission` - Group permissions
|
||||
- `UserProfile` - Extended profile
|
||||
- `IdentityVerification` - Identity verification
|
||||
- `AccessRequest` - Access requests
|
||||
- `AccessReview` - Access reviews
|
||||
- `ComplianceReport` - Compliance reports
|
||||
- `PolicyTemplate` - Policy templates
|
||||
- `RiskScore` - Risk scores
|
||||
|
||||
**User model extended:**
|
||||
- Added `organizationId` field (optional)
|
||||
- Added new relations (optional)
|
||||
|
||||
```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
|
||||
}
|
||||
```
|
||||
|
||||
### 4. New API Endpoints
|
||||
|
||||
#### Identity Management
|
||||
- `/api/v1/identity/users/*` - User lifecycle management
|
||||
- `/api/v1/identity/users/:id/profile` - Profile management
|
||||
- `/api/v1/identity/verification/*` - Identity verification
|
||||
- `/api/v1/identity/organizations/*` - Organization management
|
||||
- `/api/v1/identity/groups/*` - Group management
|
||||
|
||||
#### Access Management
|
||||
- `/api/v1/access/requests/*` - Access requests
|
||||
- `/api/v1/access/reviews/*` - Access reviews
|
||||
- `/api/v1/access/analytics/*` - Access analytics
|
||||
|
||||
#### Governance
|
||||
- `/api/v1/governance/compliance/*` - Compliance reports
|
||||
- `/api/v1/governance/policies/*` - Policy governance
|
||||
- `/api/v1/governance/risk/*` - Risk management
|
||||
- `/api/v1/governance/reports/*` - Reporting dashboard
|
||||
|
||||
### 5. Environment Variables
|
||||
|
||||
Some new environment variables may be added in the future for advanced IAM features (email service, SMS service, file storage), but they will not affect existing variables.
|
||||
|
||||
### 6. Deployment Configuration
|
||||
|
||||
**Docker Compose:**
|
||||
- Service name: `auth-service` → `iam-service`
|
||||
- Container name: `auth-service-local` → `iam-service-local`
|
||||
- Traefik labels: Add new routes for `/api/v1/identity/*`, `/api/v1/access/*`, `/api/v1/governance/*`
|
||||
|
||||
**Kubernetes:**
|
||||
- Deployment name: `auth-service` → `iam-service`
|
||||
- Service name: `auth-service` → `iam-service`
|
||||
- ConfigMap: `auth-service-config` → `iam-service-config`
|
||||
- Secrets: `auth-service-secrets` → `iam-service-secrets`
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Step 1: Backup
|
||||
|
||||
```bash
|
||||
# Backup database
|
||||
pg_dump $DATABASE_URL > auth-service-backup.sql
|
||||
|
||||
# Backup code
|
||||
cp -r services/auth-service services/auth-service.backup
|
||||
```
|
||||
|
||||
### Step 2: Database Migration
|
||||
|
||||
```bash
|
||||
cd services/iam-service
|
||||
|
||||
# Generate Prisma client with new schema
|
||||
pnpm prisma generate
|
||||
|
||||
# Create migration
|
||||
pnpm prisma migrate dev --name add_iam_models
|
||||
|
||||
# Verify migration
|
||||
pnpm prisma studio # Check database structure
|
||||
```
|
||||
|
||||
### Step 3: Update Dependencies
|
||||
|
||||
```bash
|
||||
# Install dependencies (if new packages exist)
|
||||
pnpm install
|
||||
|
||||
# Verify types compile
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
### Step 4: Update Deployment
|
||||
|
||||
**Local Development:**
|
||||
```bash
|
||||
cd deployments/local
|
||||
# Update docker-compose.yml (already updated)
|
||||
docker-compose up -d iam-service
|
||||
```
|
||||
|
||||
**Staging/Production:**
|
||||
- Update Kubernetes manifests
|
||||
- Update ingress routes
|
||||
- Update ConfigMaps and Secrets
|
||||
|
||||
### Step 5: Verify Backward Compatibility
|
||||
|
||||
Test that all old endpoints still work:
|
||||
|
||||
```bash
|
||||
# Test auth endpoints
|
||||
curl http://localhost/api/v1/auth/me
|
||||
|
||||
# Test RBAC endpoints
|
||||
curl http://localhost/api/v1/rbac/permissions
|
||||
|
||||
# Test MFA endpoints
|
||||
curl http://localhost/api/v1/mfa/devices
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
2. **Update Clients**:
|
||||
- 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`
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If rollback is needed:
|
||||
|
||||
1. **Database Rollback**:
|
||||
```bash
|
||||
# Revert Prisma migration
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate resolve --rolled-back <migration_name>
|
||||
|
||||
# Or restore from backup
|
||||
psql $DATABASE_URL < auth-service-backup.sql
|
||||
```
|
||||
|
||||
2. **Service Rollback**:
|
||||
```bash
|
||||
# Switch back to auth-service in docker-compose
|
||||
# Or revert Kubernetes deployment
|
||||
kubectl rollout undo deployment/auth-service
|
||||
```
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
**No breaking changes** in this migration. All existing API endpoints and database models are preserved.
|
||||
|
||||
## Notes
|
||||
|
||||
- This migration is **additive** - only adds new features, does not remove or change existing ones
|
||||
- Database migrations are **non-destructive** - do not delete or modify existing data
|
||||
- Clients can continue using old endpoints without any changes
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues during migration:
|
||||
1. Check logs: `docker-compose logs iam-service`
|
||||
2. Verify database connection
|
||||
3. Check environment variables
|
||||
4. Review error messages and stack traces
|
||||
|
||||
## Quick Tips
|
||||
|
||||
**Migration Checklist:**
|
||||
- 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 |
|
||||
|
||||
**Visual Indicators:**
|
||||
- Old Components (Unchanged)
|
||||
- New Components (Added)
|
||||
- Components to Deprecate
|
||||
- Requires Attention
|
||||
312
microservices/docs/en/guides/kubernetes-local.md
Normal file
312
microservices/docs/en/guides/kubernetes-local.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# Local Kubernetes Deployment Guide
|
||||
|
||||
|
||||
|
||||
**Last Updated**: 2026-01-05
|
||||
**Difficulty**: Intermediate
|
||||
**Duration**: 30-45 minutes
|
||||
|
||||
## Workflow
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Start([ Start]) --> EnvPrep[1⃣ Environment Prep<br/>Enable K8s in Docker Desktop]
|
||||
EnvPrep --> BuildImg[2⃣ Build Docker Image<br/>docker build -t service:local]
|
||||
BuildImg --> LoadImg[3⃣ Load Image to Cluster<br/>kind load docker-image]
|
||||
LoadImg --> Secrets[4⃣ Configure Secrets<br/>kubectl create secret]
|
||||
Secrets --> Deploy[5⃣ Deploy Service<br/>kubectl apply -f manifests]
|
||||
Deploy --> Verify[6⃣ Verify Deployment<br/>kubectl get pods]
|
||||
Verify --> Test[7⃣ Test Service<br/>Port Forward & Curl]
|
||||
Test --> End([ Complete])
|
||||
|
||||
subgraph Deployment[" Deployment Resources"]
|
||||
Deploy --> |Apply| ConfigMap[ConfigMap<br/>Environment Config]
|
||||
Deploy --> |Apply| K8sDeployment[Deployment<br/>Pod Template]
|
||||
Deploy --> |Apply| Service[Service<br/>LoadBalancer/NodePort]
|
||||
end
|
||||
|
||||
%% Start/End nodes - Success Green
|
||||
style Start fill:#004d40,stroke:#00bfa5,stroke-width:3px,color:#e0f2f1
|
||||
style End fill:#1b5e20,stroke:#66bb6a,stroke-width:3px,color:#e8f5e9
|
||||
|
||||
%% Workflow steps - Dark theme with distinct colors
|
||||
style EnvPrep fill:#263238,stroke:#546e7a,stroke-width:2px,color:#eceff1
|
||||
style BuildImg fill:#3e2723,stroke:#8d6e63,stroke-width:2px,color:#efebe9
|
||||
style LoadImg fill:#1a237e,stroke:#5c6bc0,stroke-width:2px,color:#e8eaf6
|
||||
style Secrets fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#ffebee
|
||||
style Deploy fill:#004d40,stroke:#26a69a,stroke-width:2px,color:#e0f2f1
|
||||
style Verify fill:#1565c0,stroke:#42a5f5,stroke-width:2px,color:#e3f2fd
|
||||
style Test fill:#4a148c,stroke:#ab47bc,stroke-width:2px,color:#f3e5f5
|
||||
|
||||
%% Deployment resources subgraph
|
||||
style Deployment fill:#1a1a1a,stroke:#424242,stroke-width:2px,color:#e0e0e0
|
||||
style ConfigMap fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
|
||||
style K8sDeployment fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
|
||||
style Service fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
This guide details how to deploy the IAM Service (or any microservice in the GoodGo ecosystem) to a local Kubernetes cluster using Docker Desktop on macOS.
|
||||
|
||||
**Important:** This guide assumes you are using **Docker Desktop** with **Kubernetes enabled**. If you are using Minikube or plain Kind, the steps might differ slightly (especially the image loading part).
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
### Software
|
||||
- **Docker Desktop 4.0+**: [Download Link](https://www.docker.com/products/docker-desktop/)
|
||||
- Kubernetes must be enabled in settings.
|
||||
- **kubectl CLI**: Command-line tool for interacting with K8s.
|
||||
```bash
|
||||
brew install kubectl
|
||||
```
|
||||
- **kind CLI**: Required to load images into the cluster if using Kind backend explicitely.
|
||||
```bash
|
||||
brew install kind
|
||||
```
|
||||
- **pnpm 8+**: Project package manager.
|
||||
```bash
|
||||
npm install -g pnpm
|
||||
```
|
||||
|
||||
### Knowledge
|
||||
- Basic understanding of Kubernetes concepts: **Pod**, **Deployment**, **Service**, **Secret**, **ConfigMap**.
|
||||
- Familiarity with basic Docker commands (`docker build`, `docker images`).
|
||||
- Ability to navigate and run commands in the Terminal.
|
||||
|
||||
## 2. Environment Preparation
|
||||
|
||||
### 2.1 Enable Kubernetes in Docker Desktop
|
||||
|
||||
1. Open **Docker Desktop**.
|
||||
2. Click the **Settings ()** icon.
|
||||
3. Select the **Kubernetes** tab.
|
||||
4. Check **Enable Kubernetes**.
|
||||
5. Select **Show system containers (advanced)** for easier debugging (optional).
|
||||
6. Click **Apply & Restart**.
|
||||
7. Wait 2-3 minutes until the Kubernetes icon in the bottom corner turns green.
|
||||
|
||||
### 2.2 Verify Kubernetes Connection
|
||||
|
||||
Check if `kubectl` is connected to the correct context:
|
||||
|
||||
```bash
|
||||
# Check current context
|
||||
kubectl config current-context
|
||||
# Expected Output: docker-desktop
|
||||
|
||||
# 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
|
||||
```
|
||||
|
||||
## 3. Build Docker Image
|
||||
|
||||
We need to build the service image before deploying. Taking `iam-service` as an example.
|
||||
|
||||
```bash
|
||||
# Navigate to the kubernetes deployment directory
|
||||
cd deployments/local/kubernetes
|
||||
|
||||
# Build the Docker image from the root context
|
||||
# Note: -f points to service Dockerfile, context is root (../../..)
|
||||
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]
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
If you are using **Kind** (Kubernetes in Docker) separately or a specific Docker Desktop config, you need to load the image:
|
||||
|
||||
```bash
|
||||
# Load image into kind cluster (if using kind explicitly)
|
||||
kind load docker-image iam-service:local --name desktop
|
||||
|
||||
# Validating image presence (optional, hard with Docker Desktop K8s directly)
|
||||
```
|
||||
|
||||
**Tip:** With default Docker Desktop, building the local image (`docker build ...`) is usually automatically available to Docker Desktop's K8s cluster. This loading step is mainly for those using `kind` CLI to create separate clusters.
|
||||
|
||||
## 5. Configure Secrets & ConfigMap
|
||||
|
||||
Kubernetes environments need sensitive environment variables (Secrets) and general configuration (ConfigMap).
|
||||
|
||||
### 5.1 Create Secrets (Manually)
|
||||
|
||||
You can run a script or the following commands to create secrets securely.
|
||||
|
||||
```bash
|
||||
# Create a dedicated namespace for local testing
|
||||
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
|
||||
|
||||
# Verify secrets creation
|
||||
kubectl get secrets -n iam-local
|
||||
```
|
||||
|
||||
**Note on `host.docker.internal`:** On macOS, for a K8s pod to connect to PostgreSQL running on the host machine (or another container via port mapping), we use `host.docker.internal`.
|
||||
|
||||
### 5.2 ConfigMap
|
||||
|
||||
The `iam-service-configmap.yaml` file typically contains non-sensitive variables like `NODE_ENV`, `LOG_LEVEL`.
|
||||
|
||||
```bash
|
||||
# Apply ConfigMap
|
||||
kubectl apply -f iam-service-configmap.yaml -n iam-local
|
||||
```
|
||||
|
||||
## 6. Deploy Service
|
||||
|
||||
Now we will deploy the main resources.
|
||||
|
||||
```bash
|
||||
# Apply Deployment manifest
|
||||
kubectl apply -f iam-service-deployment.yaml -n iam-local
|
||||
|
||||
# Apply Service manifest (LoadBalancer/NodePort)
|
||||
kubectl apply -f iam-service-service.yaml -n iam-local
|
||||
```
|
||||
|
||||
## 7. Verify & Debug
|
||||
|
||||
After deployment, ensure the Pod is stable (Running).
|
||||
|
||||
### 7.1 Check Pods
|
||||
|
||||
```bash
|
||||
# Get all pods in the namespace
|
||||
kubectl get pods -n iam-local
|
||||
|
||||
# Expected Output:
|
||||
# NAME READY STATUS RESTARTS AGE
|
||||
# iam-service-68994fdc79-gh2mj 1/1 Running 0 30s
|
||||
```
|
||||
|
||||
### 7.2 View Detailed Logs
|
||||
|
||||
If Status is not `Running` (e.g., `CrashLoopBackOff` or `ImagePullBackOff`), check logs:
|
||||
|
||||
```bash
|
||||
# Stream logs from the pod
|
||||
kubectl logs -f -n iam-local -l app=iam-service
|
||||
|
||||
# Describe pod to see events (pull error, mounts, scheduling)
|
||||
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`.
|
||||
|
||||
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`.
|
||||
|
||||
## 8. Test Service Access
|
||||
|
||||
To access the service from your local machine, the safest way is `port-forward`.
|
||||
|
||||
```bash
|
||||
# Port forward from local port 5002 to service port 80
|
||||
kubectl port-forward svc/iam-service 5002:80 -n iam-local
|
||||
|
||||
# Terminal will hang and show: Forwarding from 127.0.0.1:5002 -> 8000
|
||||
```
|
||||
|
||||
Open another terminal and test:
|
||||
|
||||
```bash
|
||||
# Test Health Check
|
||||
curl http://localhost:5002/health/live
|
||||
# Response: {"status":"ok", ...}
|
||||
|
||||
# View Swagger/OpenAPI docs (if enabled)
|
||||
open http://localhost:5002/api-docs
|
||||
```
|
||||
|
||||
## 9. Cleanup
|
||||
|
||||
When done, delete resources to free up capacity.
|
||||
|
||||
```bash
|
||||
# Delete the namespace (removes all resources within)
|
||||
kubectl delete namespace iam-local
|
||||
```
|
||||
|
||||
## Quick Tips
|
||||
|
||||
### Common Issues & Solutions
|
||||
|
||||
| Issue | Symptoms | Solution |
|
||||
|-------|----------|----------|
|
||||
| **ImagePullBackOff** | Pod stuck in `ImagePullBackOff` | Set `imagePullPolicy: Never` in deployment YAML<br/>Run `kind load docker-image` if using Kind |
|
||||
| **CrashLoopBackOff** | Pod keeps restarting | Check logs with `kubectl logs`<br/>Verify `DATABASE_URL` in secrets<br/>Ensure DB is accessible via `host.docker.internal` |
|
||||
| **Pending LoadBalancer** | Service External-IP shows `<pending>` | Normal on local—use `kubectl port-forward` instead |
|
||||
| **Connection Refused** | Can't connect after port-forward | Check pod is `Running` (not `CrashLoopBackOff`)<br/>Verify correct port mapping |
|
||||
|
||||
### Essential Commands Reference
|
||||
|
||||
```bash
|
||||
# Debugging
|
||||
kubectl get pods -n iam-local -w # Watch pods in real-time
|
||||
kubectl describe pod <POD_NAME> -n iam-local # Detailed pod info + events
|
||||
kubectl logs -f <POD_NAME> -n iam-local # Stream logs
|
||||
kubectl exec -it <POD_NAME> -n iam-local -- /bin/sh # Shell into container
|
||||
|
||||
# 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
|
||||
|
||||
# Cleanup
|
||||
kubectl delete pod <POD_NAME> -n iam-local --force # Force delete stuck pod
|
||||
kubectl delete namespace iam-local --force --grace-period=0 # Force delete namespace
|
||||
```
|
||||
|
||||
### Visual Status Indicators
|
||||
|
||||
- **Running** - Service is healthy
|
||||
- **Pending** - Waiting for resources
|
||||
- **CrashLoopBackOff** - Service keeps failing (check logs!)
|
||||
- **ContainerCreating** - Pod starting up
|
||||
- **Terminating** - Pod shutting down
|
||||
|
||||
### 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
|
||||
|
||||
|
||||
## References
|
||||
|
||||
- [Kubernetes Documentation](https://kubernetes.io/docs/)
|
||||
- [Docker Desktop for Mac](https://docs.docker.com/desktop/mac/networking/)
|
||||
- [Prisma Deployment Guide](https://www.prisma.io/docs/guides/deployment/deployment-guides/deploying-to-kubernetes)
|
||||
317
microservices/docs/en/guides/local-deployment.md
Normal file
317
microservices/docs/en/guides/local-deployment.md
Normal file
@@ -0,0 +1,317 @@
|
||||
# Local Development Deployment
|
||||
|
||||
This directory contains Docker Compose configuration for running the entire GoodGo platform locally.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Setup environment variables
|
||||
cp env.local.example .env
|
||||
cp env.local.example .env.local
|
||||
# Edit both files with your values (JWT_SECRET, service DB URLs, Redis, etc.)
|
||||
|
||||
# 2. Start all services
|
||||
docker-compose up -d
|
||||
|
||||
# 3. Check service status
|
||||
docker-compose ps
|
||||
|
||||
# 4. View logs
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
## Access Points
|
||||
|
||||
| Service | URL | Description |
|
||||
|---------|-----|-------------|
|
||||
| **Traefik Dashboard** | http://localhost:8080 | API Gateway dashboard |
|
||||
| **Auth Service** | http://localhost/api/v1/auth | Authentication API |
|
||||
| **Web Admin** | http://admin.localhost | Admin dashboard |
|
||||
| **Web Client** | http://localhost | Client application |
|
||||
| **Redis** | localhost:6379 | Cache (direct access) |
|
||||
|
||||
## Services
|
||||
|
||||
### Infrastructure
|
||||
|
||||
- **Traefik** (Port 80, 8080): API Gateway with automatic service discovery
|
||||
- **Redis** (Port 6379): Shared cache and session store
|
||||
|
||||
### Backend Services
|
||||
|
||||
- **iam-service** (Port 5001): Authentication and user management
|
||||
- Routes: `/api/v1/auth`, `/api/v1/users`
|
||||
- Health: http://localhost/api/v1/auth/health
|
||||
|
||||
### Frontend Applications
|
||||
|
||||
- **web-admin** (Port 3000): Admin dashboard (Next.js)
|
||||
- **web-client** (Port 3001): Client application (Next.js)
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
Environment variables are managed in `.env` and `.env.local`:
|
||||
|
||||
### Required Variables
|
||||
|
||||
```bash
|
||||
# Authentication (MUST be same across all services)
|
||||
JWT_SECRET=your-super-secret-jwt-key-min-32-characters
|
||||
JWT_REFRESH_SECRET=your-super-secret-refresh-key-min-32-characters
|
||||
JWT_ID_SECRET=your-super-secret-id-key-min-32-characters
|
||||
|
||||
# IAM + service databases (Neon PostgreSQL)
|
||||
IAM_DATABASE_URL=Host=...;Port=5432;Database=iam_service;Username=...;Password=...;SSL Mode=Require
|
||||
STORAGE_DATABASE_URL=Host=...;Port=5432;Database=storage_service;Username=...;Password=...;SSL Mode=Require
|
||||
ORDER_DATABASE_URL=Host=...;Port=5432;Database=order_service;Username=...;Password=...;SSL Mode=Require
|
||||
```
|
||||
|
||||
### Optional Variables
|
||||
|
||||
```bash
|
||||
# Redis
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=replace-with-redis-password
|
||||
|
||||
# Observability
|
||||
TRACING_ENABLED=false
|
||||
JAEGER_ENDPOINT=http://jaeger:14268/api/traces
|
||||
|
||||
# CORS
|
||||
CORS_ORIGIN=http://localhost:3000,http://localhost:3001
|
||||
|
||||
# Object storage and messaging
|
||||
MINIO_ENDPOINT=minio:9000
|
||||
MINIO_ACCESS_KEY=...
|
||||
MINIO_SECRET_KEY=...
|
||||
RABBITMQ_PASSWORD=...
|
||||
```
|
||||
|
||||
## Common Commands
|
||||
|
||||
```bash
|
||||
# Start all services
|
||||
docker-compose up -d
|
||||
|
||||
# Start specific service
|
||||
docker-compose up -d iam-service
|
||||
|
||||
# Stop all services
|
||||
docker-compose down
|
||||
|
||||
# Stop and remove volumes
|
||||
docker-compose down -v
|
||||
|
||||
# View logs (all services)
|
||||
docker-compose logs -f
|
||||
|
||||
# View logs (specific service)
|
||||
docker-compose logs -f iam-service
|
||||
|
||||
# Restart service
|
||||
docker-compose restart iam-service
|
||||
|
||||
# Rebuild service
|
||||
docker-compose up -d --build iam-service
|
||||
|
||||
# Check service status
|
||||
docker-compose ps
|
||||
|
||||
# Execute command in container
|
||||
docker-compose exec iam-service sh
|
||||
```
|
||||
|
||||
## Adding New Service
|
||||
|
||||
1. **Add service to docker-compose.yml**:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
2. **Start the service**:
|
||||
|
||||
```bash
|
||||
docker-compose up -d my-new-service
|
||||
```
|
||||
|
||||
3. **Access the service**:
|
||||
- Via Traefik: http://localhost/api/v1/my-new-service
|
||||
- Direct: http://localhost:5002
|
||||
|
||||
## Traefik Configuration
|
||||
|
||||
Traefik is configured via:
|
||||
- **Static config**: `infra/traefik/traefik.yml`
|
||||
- **Dynamic config**: `infra/traefik/dynamic/`
|
||||
- **Service discovery**: Docker labels in this file
|
||||
|
||||
Services are automatically discovered by Traefik using Docker labels. No manual route configuration needed.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Already in Use
|
||||
|
||||
```bash
|
||||
# Find process using port
|
||||
lsof -i :80
|
||||
lsof -i :5001
|
||||
|
||||
# Kill process
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
### Service Won't Start
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs service-name
|
||||
|
||||
# Rebuild without cache
|
||||
docker-compose build --no-cache service-name
|
||||
docker-compose up -d service-name
|
||||
```
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
```bash
|
||||
# Verify IAM_DATABASE_URL in .env/.env.local
|
||||
cat .env | grep IAM_DATABASE_URL
|
||||
|
||||
# Test connection from service
|
||||
docker-compose exec iam-service sh
|
||||
# Inside container:
|
||||
# curl $DATABASE_URL (won't work, but shows if var is set)
|
||||
```
|
||||
|
||||
### Redis Connection Issues
|
||||
|
||||
```bash
|
||||
# Check Redis is running
|
||||
docker-compose ps redis
|
||||
|
||||
# Test Redis connection
|
||||
docker-compose exec redis redis-cli ping
|
||||
# Should return: PONG
|
||||
```
|
||||
|
||||
### Traefik Not Routing
|
||||
|
||||
```bash
|
||||
# Check Traefik dashboard
|
||||
open http://localhost:8080
|
||||
|
||||
# Verify service has correct labels
|
||||
docker-compose config | grep -A 5 "labels:"
|
||||
|
||||
# Check Traefik logs
|
||||
docker-compose logs traefik
|
||||
```
|
||||
|
||||
## Network Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Client[ Client<br/>Browser] --> Traefik
|
||||
|
||||
Traefik[ Traefik<br/>API Gateway<br/>:80, :8080]
|
||||
|
||||
Traefik --> IAM[ IAM Service<br/>Authentication<br/>:5001]
|
||||
Traefik --> Admin[ Web Admin<br/>Dashboard<br/>:3000]
|
||||
Traefik --> WebClient[ Web Client<br/>Application<br/>:3001]
|
||||
|
||||
IAM --> Redis[( Redis<br/>Cache<br/>:6379)]
|
||||
IAM --> DB[( PostgreSQL<br/>Neon Database)]
|
||||
|
||||
classDef client fill:#1a1a2e,stroke:#16213e,stroke-width:2px,color:#eee
|
||||
classDef gateway fill:#0f3460,stroke:#16213e,stroke-width:3px,color:#eee
|
||||
classDef service fill:#16213e,stroke:#533483,stroke-width:2px,color:#eee
|
||||
classDef frontend fill:#1a1a40,stroke:#6c5ce7,stroke-width:2px,color:#eee
|
||||
classDef data fill:#2d132c,stroke:#801336,stroke-width:2px,color:#eee
|
||||
|
||||
class Client client
|
||||
class Traefik gateway
|
||||
class IAM service
|
||||
class Admin,WebClient frontend
|
||||
class Redis,DB data
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
## Quick Tips
|
||||
|
||||
### Common Issues
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| **Port conflict** | Check if port 80/5001/6379 is already in use: `lsof -i :<port>` |
|
||||
| **Service won't start** | Check logs: `docker-compose logs <service-name>` |
|
||||
| **Database connection** | Verify `DATABASE_URL` in `.env.local` is correct |
|
||||
| **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
|
||||
|
||||
```bash
|
||||
# Quick restart (code changes)
|
||||
docker-compose restart iam-service
|
||||
|
||||
# Full rebuild (dependency changes)
|
||||
docker-compose up -d --build iam-service
|
||||
|
||||
# Clean restart (database issues)
|
||||
docker-compose down -v && docker-compose up -d
|
||||
```
|
||||
|
||||
### Security Checklist
|
||||
|
||||
- Change default `JWT_SECRET` (min 32 characters)
|
||||
- Use environment-specific `.env` / `.env.local` with real secrets (never commit real values)
|
||||
- Verify CORS origins match your frontend URLs
|
||||
- Enable HTTPS in production (not needed for local)
|
||||
|
||||
### Monitoring
|
||||
|
||||
- **Traefik Dashboard**: http://localhost:8080 - View all routes and services
|
||||
- **Service Health**: http://localhost/api/v1/auth/health - Check service status
|
||||
- **Redis CLI**: `docker-compose exec redis redis-cli` - Query cache directly
|
||||
|
||||
## Resources
|
||||
|
||||
- [Traefik Configuration](../../infra/traefik/)
|
||||
- [Service Template](../../services/_template/)
|
||||
- [Development Guide](../../docs/en/guides/development.md)
|
||||
- [Neon Database Guide](../../docs/en/guides/neon-database.md)
|
||||
257
microservices/docs/en/guides/local-development.md
Normal file
257
microservices/docs/en/guides/local-development.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# Local Development Guide
|
||||
|
||||
> **EN**: Local Development Guide
|
||||
>
|
||||
> **VI**: Hướng dẫn phát triển cục bộ
|
||||
|
||||
**Last Updated**: 2026-01-05
|
||||
**Difficulty**: Intermediate
|
||||
**Setup Time**: 15-30 minutes
|
||||
|
||||
## Workflow
|
||||
|
||||
```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])
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
This guide provides a detailed process for setting up a development environment for the GoodGo Microservices ecosystem. You will learn how to run services, set up databases, and establish an efficient workflow with hot-reload.
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
Before starting, ensure your machine has the following tools installed:
|
||||
|
||||
- **Node.js**: Latest LTS version (v20+).
|
||||
- **PNPM**: Main project package manager (`npm install -g pnpm`).
|
||||
- **Docker Desktop**: Required for running infrastructure services (Redis, Local Database).
|
||||
- **Git**: For source code management.
|
||||
- **Neon Account** (Optional): If using Neon Database on cloud (recommended for dev).
|
||||
|
||||
## 2. Initial Setup
|
||||
|
||||
### 2.1 Clone and Install Dependencies
|
||||
|
||||
```bash
|
||||
# EN: Clone the repository
|
||||
# VI: Clone repository về máy
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
|
||||
# EN: Install dependencies using pnpm
|
||||
# VI: Cài đặt các thư viện phụ thuộc bằng pnpm
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 2.2 Quick Init Script (Recommended)
|
||||
|
||||
The project includes an automation script for basic initialization:
|
||||
|
||||
```bash
|
||||
# EN: Run initialization script
|
||||
# VI: Chạy script khởi tạo
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
|
||||
> This script will:
|
||||
> - Install dependencies.
|
||||
> - Copy example environment files (`.env.example` -> `.env`).
|
||||
> - Generate Prisma client.
|
||||
|
||||
## 3. Environment Configuration
|
||||
|
||||
The project uses a **Hybrid Environment** strategy to optimize configuration management:
|
||||
|
||||
### 3.1 Shared Configuration
|
||||
|
||||
File: `deployments/local/.env.local`
|
||||
Contains variables shared across the entire system (JWT, Redis, Logging).
|
||||
|
||||
```bash
|
||||
# EN: Create shared env file from example
|
||||
# VI: Tạo file môi trường chung từ file mẫu
|
||||
cp deployments/local/env.local.example deployments/local/.env.local
|
||||
```
|
||||
|
||||
### 3.2 Service-Specific Configuration
|
||||
|
||||
Each service (e.g., `iam-service`) needs its own `.env.local` file containing specific details like Database URL and Port.
|
||||
|
||||
```bash
|
||||
# EN: Create service-specific env file
|
||||
# VI: Tạo file môi trường riêng cho service
|
||||
cp services/iam-service/env.local.example services/iam-service/.env.local
|
||||
```
|
||||
|
||||
**Key contents to check in `services/iam-service/.env.local`**:
|
||||
|
||||
```properties
|
||||
# Database URL (Use Neon Tech or Local Postgres)
|
||||
DATABASE_URL=postgresql://user:password@host:5432/db_name?sslmode=require
|
||||
|
||||
# Service Port (Must be unique per service)
|
||||
PORT=5001
|
||||
|
||||
# Service Name
|
||||
SERVICE_NAME=iam-service
|
||||
|
||||
# Redis Host (localhost for Native Dev, redis for Docker Dev)
|
||||
REDIS_HOST=localhost
|
||||
```
|
||||
|
||||
## 4. Setup Database
|
||||
|
||||
After configuring `DATABASE_URL`, you need to sync the schema and seed initial data.
|
||||
|
||||
```bash
|
||||
# EN: Run migrations for iam-service
|
||||
# VI: Chạy migration cho iam-service
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# EN: Seed initial data (optional)
|
||||
# VI: Tạo dữ liệu mẫu (tùy chọn)
|
||||
./scripts/db/seed.sh iam-service
|
||||
```
|
||||
|
||||
## 5. Run Modes
|
||||
|
||||
You can run the project in 3 ways depending on your needs:
|
||||
|
||||
### Mode 1: Native Development (Recommended for Backend Dev)
|
||||
|
||||
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 ../..
|
||||
```
|
||||
|
||||
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)
|
||||
|
||||
Use when you need to run multiple auxiliary services in Docker but want to dev the main service directly.
|
||||
|
||||
```bash
|
||||
# EN: Start dependent services in Docker
|
||||
# VI: Chạy các service phụ thuộc trong Docker
|
||||
docker-compose -f deployments/local/docker-compose.yml up -d user-service payment-service
|
||||
|
||||
# EN: Run the service you are working on natively
|
||||
# VI: Chạy service bạn đang làm việc trực tiếp trên máy
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
```
|
||||
|
||||
### Mode 3: Full Docker (Production Simulation)
|
||||
|
||||
Run the entire system in Docker. Good for Integration Testing but no hot-reload.
|
||||
|
||||
```bash
|
||||
# EN: Start everything with Docker Compose
|
||||
# VI: Chạy tất cả bằng Docker Compose
|
||||
cd deployments/local
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## 6. Access & Verification
|
||||
|
||||
After startup, you can access the following endpoints:
|
||||
|
||||
| Service | URL | Description |
|
||||
|---------|-----|-------------|
|
||||
| **API Gateway** | `http://localhost/api/v1` | Main entry point via Traefik |
|
||||
| **IAM Service** | `http://localhost:5001` | Direct service access |
|
||||
| **Health Check** | `http://localhost:5001/health` | Service status check |
|
||||
| **Metrics** | `http://localhost:5001/metrics` | Prometheus metrics |
|
||||
| **API Docs** | `http://localhost:5001/api-docs` | Swagger UI |
|
||||
|
||||
### Health Check Validation
|
||||
|
||||
```bash
|
||||
# EN: Check liveness
|
||||
# VI: Kiểm tra liveness
|
||||
curl http://localhost:5001/health/live
|
||||
|
||||
# EN: Check readiness
|
||||
# VI: Kiểm tra readiness
|
||||
curl http://localhost:5001/health/ready
|
||||
```
|
||||
|
||||
## 7. Troubleshooting
|
||||
|
||||
### Port Already In Use
|
||||
|
||||
**Error**: `Error: listen EADDRINUSE: address already in use :::5001`
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# EN: Find process using port 5001
|
||||
# VI: Tìm process đang chiếm port 5001
|
||||
lsof -i :5001
|
||||
|
||||
# EN: Kill the process
|
||||
# VI: Tắt process đó
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
### Database Connection Error
|
||||
|
||||
**Error**: `P1001: Can't reach database server`
|
||||
|
||||
**Solution**:
|
||||
- Re-check `DATABASE_URL` variable.
|
||||
- If using local Postgres Docker, ensure container is running (`docker ps`).
|
||||
- If using Neon, check internet connection.
|
||||
|
||||
### Module Not Found
|
||||
|
||||
**Error**: Cannot find internal packages (e.g., `@goodgo/logger`).
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# EN: Re-install dependencies and build packages
|
||||
# VI: Cài lại dependencies và build lại packages
|
||||
pnpm install
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Kubernetes Guide](kubernetes-local.md) - Deploy to Local K8s.
|
||||
- [Project Architecture](../../docs/en/ARCHITECTURE.en.md) - System architecture overview.
|
||||
661
microservices/docs/en/guides/mermaid.md
Normal file
661
microservices/docs/en/guides/mermaid.md
Normal file
@@ -0,0 +1,661 @@
|
||||
# Mermaid Diagram Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide helps you choose the right Mermaid diagram type for your documentation and provides examples for common use cases.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| 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 | |
|
||||
|
||||
---
|
||||
|
||||
## 1. Flowcharts
|
||||
|
||||
### When to Use
|
||||
|
||||
Use flowcharts for:
|
||||
- Step-by-step guides and workflows (e.g., **"Onboarding process"**)
|
||||
- Decision trees and conditional logic (e.g., **"Discount calculation"**)
|
||||
- Process flows with multiple branches (e.g., **"Order fulfillment"**)
|
||||
- Troubleshooting procedures (e.g., **"Login issue diagnosis"**)
|
||||
|
||||
### Basic Flowchart
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
**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.
|
||||
|
||||
**Code**:
|
||||
````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
|
||||
```
|
||||
````
|
||||
|
||||
### Advanced Flowchart with Subgraphs
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
**Explanation**: A flowchart featuring an authorization check and a dedicated **Subgraph** for detailed request processing steps.
|
||||
|
||||
---
|
||||
|
||||
## 2. Sequence Diagrams
|
||||
|
||||
### When to Use
|
||||
|
||||
Use sequence diagrams for:
|
||||
- API communication flows (e.g., **"New order creation API"**)
|
||||
- Authentication/authorization flows (e.g., **"OAuth2 login flow"**)
|
||||
- Service-to-service interactions (e.g., **"Microservices sync/async calls"**)
|
||||
- Request/response cycles (e.g., **"Checkout process"**)
|
||||
|
||||
### Basic Sequence Diagram
|
||||
|
||||
```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}
|
||||
```
|
||||
|
||||
**Explanation**: A login sequence illustrating the interaction between the Client, API, Service Layer, and Database, including password verification.
|
||||
|
||||
**Code**:
|
||||
````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}
|
||||
```
|
||||
````
|
||||
|
||||
### Advanced with Alt/Opt/Loop
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
**Explanation**: A data retrieval sequence using **Alt/Else** blocks to handle both Cache Hit and Cache Miss scenarios.
|
||||
|
||||
---
|
||||
|
||||
## 3. Class Diagrams
|
||||
|
||||
### When to Use
|
||||
|
||||
Use class diagrams for:
|
||||
- Design patterns and code structure (e.g., **"Singleton Pattern for Logger"**)
|
||||
- Object-oriented architecture (e.g., **"Domain-Driven Design (DDD) models"**)
|
||||
- Inheritance and relationships (e.g., **"Repository base and concrete classes"**)
|
||||
- Module dependencies (e.g., **"Service layer dependencies"**)
|
||||
|
||||
### Basic Class Diagram
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
**Explanation**: A class diagram showing inheritance relationships between a generic `BaseRepository` and specific repository implementations.
|
||||
|
||||
---
|
||||
|
||||
## 4. Graph Diagrams
|
||||
|
||||
### When to Use
|
||||
|
||||
Use graph diagrams for:
|
||||
- System architecture overview (e.g., **"Microservices Architecture"**)
|
||||
- Component relationships (e.g., **"Service-to-database mapping"**)
|
||||
- Data flow diagrams (e.g., **"Request processing pipeline"**)
|
||||
- Dependency graphs (e.g., **"Package to package dependencies"**)
|
||||
|
||||
### System Architecture
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
**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.
|
||||
|
||||
### Data Flow
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
**Explanation**: A detailed data flow showing Input going through Validation -> Controller -> Service -> Repository -> ORM -> DB, while also interacting with the Cache.
|
||||
|
||||
---
|
||||
|
||||
## 5. ER Diagrams
|
||||
|
||||
### When to Use
|
||||
|
||||
Use ER diagrams for:
|
||||
- Database schema documentation (e.g., **"User and IAM tables"**)
|
||||
- Entity relationships (e.g., **"One-to-many between User and Sessions"**)
|
||||
- Data modeling (e.g., **"Designing new feature entities"**)
|
||||
- Prisma schema visualization (e.g., **"Mapping code entities to DB tables"**)
|
||||
|
||||
### Database Schema
|
||||
|
||||
```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
|
||||
}
|
||||
```
|
||||
|
||||
**Explanation**: An Entity-Relationship diagram illustrating a typical IAM schema with Users, Sessions, Roles, and Permissions.
|
||||
|
||||
---
|
||||
|
||||
## 6. Gantt Charts
|
||||
|
||||
### When to Use
|
||||
|
||||
Use Gantt charts for:
|
||||
- Project timelines
|
||||
- Implementation phases
|
||||
- Migration schedules
|
||||
- Deployment plans
|
||||
|
||||
### Project Timeline
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. C4 Diagrams
|
||||
|
||||
### When to Use
|
||||
|
||||
Use C4 diagrams for:
|
||||
- System context (highest level)
|
||||
- Container diagrams (services, databases)
|
||||
- Component diagrams (modules within services)
|
||||
- Code diagrams (classes, functions)
|
||||
|
||||
### System Context
|
||||
|
||||
```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")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Color Palette Reference
|
||||
|
||||
### Dark Theme Color System
|
||||
|
||||
Our diagrams use a consistent dark color palette based on professional design principles:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph Primary[" Primary Colors"]
|
||||
A1["Dark Blue<br/>#2980B9"]
|
||||
A2["Purple<br/>#8E44AD"]
|
||||
A3["Green<br/>#27AE60"]
|
||||
end
|
||||
|
||||
subgraph Secondary[" Secondary Colors"]
|
||||
B1["Orange<br/>#E67E22"]
|
||||
B2["Yellow<br/>#F39C12"]
|
||||
B3["Red<br/>#C0392B"]
|
||||
end
|
||||
|
||||
subgraph Neutrals[" Neutral Colors"]
|
||||
C1["Dark Gray<br/>#2C3E50"]
|
||||
C2["Medium Gray<br/>#34495E"]
|
||||
C3["Light Text<br/>#ECF0F1"]
|
||||
end
|
||||
|
||||
style A1 fill:#2980B9,stroke:#1F618D,stroke-width:3px,color:#ECF0F1
|
||||
style A2 fill:#8E44AD,stroke:#7D3C98,stroke-width:3px,color:#ECF0F1
|
||||
style A3 fill:#27AE60,stroke:#229954,stroke-width:3px,color:#ECF0F1
|
||||
|
||||
style B1 fill:#E67E22,stroke:#CA6F1E,stroke-width:3px,color:#ECF0F1
|
||||
style B2 fill:#F39C12,stroke:#D68910,stroke-width:3px,color:#ECF0F1
|
||||
style B3 fill:#C0392B,stroke:#A93226,stroke-width:3px,color:#ECF0F1
|
||||
|
||||
style C1 fill:#2C3E50,stroke:#1C2833,stroke-width:3px,color:#ECF0F1
|
||||
style C2 fill:#34495E,stroke:#2C3E50,stroke-width:3px,color:#ECF0F1
|
||||
style C3 fill:#ECF0F1,stroke:#BDC3C7,stroke-width:3px,color:#2C3E50
|
||||
```
|
||||
|
||||
### 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 |
|
||||
|
||||
### Standard Style Pattern
|
||||
|
||||
Always include these three properties for professional appearance:
|
||||
|
||||
```markdown
|
||||
style NodeName fill:#HexColor,stroke:#DarkerShade,stroke-width:2px,color:#ECF0F1
|
||||
```
|
||||
|
||||
**Components:**
|
||||
- `fill`: Main background color
|
||||
- `stroke`: Border color (typically darker shade of fill)
|
||||
- `stroke-width`: Border thickness (use `2px` for standard, `3px` for emphasis)
|
||||
- `color`: Text color (always use `#ECF0F1` for dark backgrounds)
|
||||
|
||||
### Node Type Color Patterns
|
||||
|
||||
| Node Type | Fill Color | Stroke Color | Use Case |
|
||||
|-----------|------------|--------------|----------|
|
||||
| **Services** | `#2980B9` | `#1F618D` | Auth Service, User Service |
|
||||
| **API/Gateway** | `#2980B9` | `#1F618D` | Traefik, API Gateway |
|
||||
| **Database** | `#F39C12` | `#D68910` | PostgreSQL, MySQL |
|
||||
| **Cache** | `#E67E22` | `#CA6F1E` | Redis, Memcached |
|
||||
| **ORM/Framework** | `#8E44AD` | `#7D3C98` | Prisma, TypeORM |
|
||||
| **Success/End** | `#27AE60` | `#229954` | Success Flow, Completion |
|
||||
| **Error/Failure** | `#C0392B` | `#A93226` | Error States, Failures |
|
||||
| **Decision** | `#F39C12` | `#D68910` | Validation, Conditionals |
|
||||
| **Start** | `#2C3E50` | `#1C2833` | Entry Point |
|
||||
| **Process** | `#34495E` | `#2C3E50` | General Processing |
|
||||
|
||||
### Quick Color Selection Guide
|
||||
|
||||
**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
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Guidelines
|
||||
|
||||
1. **Keep it Simple**: Don't overcomplicate diagrams
|
||||
2. **Use Consistent Styling**: Apply color scheme consistently
|
||||
3. **Add Legends**: Explain symbols and colors when needed
|
||||
4. **Limit Complexity**: Break into multiple diagrams if too complex
|
||||
5. **Test Rendering**: Always test diagrams render correctly
|
||||
6. **Dark Theme**: Always use dark color palette for professional appearance
|
||||
7. **Text Contrast**: Always use `color:#ECF0F1` for text on dark backgrounds
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Diagrams
|
||||
|
||||
Always test your diagrams before committing:
|
||||
|
||||
```bash
|
||||
# Install mermaid-cli
|
||||
npm install -g @mermaid-js/mermaid-cli
|
||||
|
||||
# Test render (SVG)
|
||||
mmdc -i your-doc.md -o test-output.svg
|
||||
|
||||
# Render high-quality PNG with dark theme
|
||||
mmdc -i your-doc.md -o test-output.png -b black -t dark -s 3
|
||||
|
||||
# Render ALL diagrams in a markdown file
|
||||
mmdc -i your-doc.md
|
||||
|
||||
# Parameter Explanations:
|
||||
# -i: Input file (.md or .mmd)
|
||||
# -o: Output file (format based on extension .svg, .png, .pdf)
|
||||
# -b: Background color (hex code or color names like black, white, transparent)
|
||||
# -t: Theme (default, forest, dark, neutral)
|
||||
# -s: Scale (increase resolution, e.g., 3 for sharper images)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Tips
|
||||
|
||||
### Mermaid Common Issues
|
||||
|
||||
**Issue**: Diagram not rendering
|
||||
- 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
|
||||
|
||||
**Issue**: Text overlapping
|
||||
- Use shorter labels or `<br/>` for line breaks
|
||||
- Adjust diagram direction (TD, LR, RL, BT)
|
||||
- Increase spacing between nodes
|
||||
|
||||
### Color Pattern Quick Reference
|
||||
|
||||
```markdown
|
||||
// Services & APIs
|
||||
style Node fill:#2980B9,stroke:#1F618D,stroke-width:2px,color:#ECF0F1
|
||||
|
||||
// Database
|
||||
style Node fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
|
||||
|
||||
// Cache
|
||||
style Node fill:#E67E22,stroke:#CA6F1E,stroke-width:2px,color:#ECF0F1
|
||||
|
||||
// Success/End
|
||||
style Node fill:#27AE60,stroke:#229954,stroke-width:2px,color:#ECF0F1
|
||||
|
||||
// Error/Failure
|
||||
style Node fill:#C0392B,stroke:#A93226,stroke-width:2px,color:#ECF0F1
|
||||
|
||||
// Decision Points
|
||||
style Node fill:#F39C12,stroke:#D68910,stroke-width:2px,color:#ECF0F1
|
||||
|
||||
// Start/Neutral
|
||||
style Node fill:#2C3E50,stroke:#1C2833,stroke-width:2px,color:#ECF0F1
|
||||
```
|
||||
|
||||
### Visual Indicators
|
||||
|
||||
Use emojis to enhance diagram readability:
|
||||
- Services & APIs
|
||||
- Core Systems
|
||||
- Success Paths
|
||||
- Databases
|
||||
- Cache/Storage
|
||||
- Errors
|
||||
- Neutral/Start/End
|
||||
- Warnings
|
||||
- Validated
|
||||
- Failed
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [Mermaid Official Documentation](https://mermaid.js.org/) - Complete reference
|
||||
- [Mermaid Live Editor](https://mermaid.live/) - Test diagrams online
|
||||
- [Mermaid CheatSheet](https://jojozhuang.github.io/tutorial/mermaid-cheat-sheet/) - Quick reference
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-01-08
|
||||
351
microservices/docs/en/guides/neon-database.md
Normal file
351
microservices/docs/en/guides/neon-database.md
Normal file
@@ -0,0 +1,351 @@
|
||||
# Neon Database Guide
|
||||
|
||||
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
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Project[" Neon Project<br/>goodgo-platform"]
|
||||
|
||||
Dev[" Development Branch<br/>main"]
|
||||
Staging[" Staging Branch<br/>staging"]
|
||||
Prod[" Production Branch<br/>production"]
|
||||
|
||||
LocalDev[" Local Dev<br/>.env.local"]
|
||||
K8sStaging[" Kubernetes<br/>staging namespace"]
|
||||
K8sProd[" Kubernetes<br/>production namespace"]
|
||||
|
||||
Project --> Dev
|
||||
Project --> Staging
|
||||
Project --> Prod
|
||||
|
||||
Dev -.->|DATABASE_URL| LocalDev
|
||||
Staging -.->|Secret| K8sStaging
|
||||
Prod -.->|Secret| K8sProd
|
||||
|
||||
style Project fill:#1e293b,stroke:#3b82f6,stroke-width:3px,color:#fff
|
||||
style Dev fill:#0f172a,stroke:#10b981,stroke-width:2px,color:#fff
|
||||
style Staging fill:#0f172a,stroke:#f59e0b,stroke-width:2px,color:#fff
|
||||
style Prod fill:#0f172a,stroke:#ef4444,stroke-width:2px,color:#fff
|
||||
style LocalDev fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
|
||||
style K8sStaging fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
|
||||
style K8sProd fill:#475569,stroke:#94a3b8,stroke-width:2px,color:#fff
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create Neon Account
|
||||
|
||||
1. Sign up at https://neon.tech
|
||||
2. Create a new project: `goodgo-platform`
|
||||
|
||||
### 2. Create Branches
|
||||
|
||||
In Neon Console, create branches:
|
||||
- `main` (development) - already exists
|
||||
- `staging` - create from main
|
||||
- `production` - create from main
|
||||
|
||||
### 3. Get Connection Strings
|
||||
|
||||
For each branch, copy the connection string:
|
||||
- Format: `postgresql://user:password@ep-xxx.region.neon.tech/dbname?sslmode=require`
|
||||
- Add `?pgbouncer=true` for connection pooling (recommended)
|
||||
|
||||
### 4. Configure Local Development
|
||||
|
||||
```bash
|
||||
# Create .env.local
|
||||
cp deployments/local/env.local.example deployments/local/.env.local
|
||||
|
||||
# Edit .env.local and add:
|
||||
DATABASE_URL=postgresql://user:pass@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true
|
||||
```
|
||||
|
||||
### 5. Run Migrations
|
||||
|
||||
```bash
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
## Connection String Format
|
||||
|
||||
```
|
||||
postgresql://[user]:[password]@[endpoint]/[dbname]?sslmode=require&pgbouncer=true
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `sslmode=require` - Required for Neon
|
||||
- `pgbouncer=true` - Enable connection pooling (recommended)
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
### Local Development
|
||||
|
||||
File: `deployments/local/.env.local`
|
||||
|
||||
```bash
|
||||
DATABASE_URL=postgresql://user:pass@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true
|
||||
```
|
||||
|
||||
### Staging
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
## Migrations
|
||||
|
||||
### Migration Workflow
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph Local[" Local Development"]
|
||||
Schema[" Update Schema<br/>prisma/schema.prisma"]
|
||||
CreateMig[" Create Migration<br/>migrate dev"]
|
||||
TestLocal[" Test Locally"]
|
||||
end
|
||||
|
||||
subgraph CI[" CI/CD Pipeline"]
|
||||
Push[" Git Push"]
|
||||
Build[" Build"]
|
||||
TestCI[" Run Tests"]
|
||||
end
|
||||
|
||||
subgraph Staging[" Staging"]
|
||||
MigStaging[" Run Migrations<br/>migrate deploy"]
|
||||
TestStaging[" Verify Schema"]
|
||||
end
|
||||
|
||||
subgraph Prod[" Production"]
|
||||
Approval[" Manual Approval"]
|
||||
MigProd[" Run Migrations<br/>migrate deploy"]
|
||||
Rollback[" Rollback Plan"]
|
||||
end
|
||||
|
||||
Schema --> CreateMig
|
||||
CreateMig --> TestLocal
|
||||
TestLocal --> Push
|
||||
|
||||
Push --> Build
|
||||
Build --> TestCI
|
||||
TestCI --> MigStaging
|
||||
|
||||
MigStaging --> TestStaging
|
||||
TestStaging --> Approval
|
||||
|
||||
Approval --> MigProd
|
||||
MigProd -.->|If Failed| Rollback
|
||||
|
||||
style Local fill:#1e293b,stroke:#3b82f6,stroke-width:2px,color:#fff
|
||||
style CI fill:#1e293b,stroke:#8b5cf6,stroke-width:2px,color:#fff
|
||||
style Staging fill:#1e293b,stroke:#f59e0b,stroke-width:2px,color:#fff
|
||||
style Prod fill:#1e293b,stroke:#ef4444,stroke-width:2px,color:#fff
|
||||
|
||||
style Schema fill:#0f172a,stroke:#10b981,color:#fff
|
||||
style CreateMig fill:#0f172a,stroke:#10b981,color:#fff
|
||||
style TestLocal fill:#0f172a,stroke:#10b981,color:#fff
|
||||
style Push fill:#475569,stroke:#94a3b8,color:#fff
|
||||
style Build fill:#475569,stroke:#94a3b8,color:#fff
|
||||
style TestCI fill:#475569,stroke:#94a3b8,color:#fff
|
||||
style MigStaging fill:#0f172a,stroke:#f59e0b,color:#fff
|
||||
style TestStaging fill:#0f172a,stroke:#f59e0b,color:#fff
|
||||
style Approval fill:#475569,stroke:#94a3b8,color:#fff
|
||||
style MigProd fill:#0f172a,stroke:#ef4444,color:#fff
|
||||
style Rollback fill:#7f1d1d,stroke:#ef4444,color:#fff
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Create new migration
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# This will:
|
||||
# 1. Create migration file
|
||||
# 2. Apply to database
|
||||
# 3. Update Prisma Client
|
||||
```
|
||||
|
||||
### Staging/Production
|
||||
|
||||
Migrations run automatically in CI/CD:
|
||||
- Before deployment to staging
|
||||
- Before deployment to production (with approval)
|
||||
|
||||
Manual migration:
|
||||
```bash
|
||||
./scripts/db/migrate.sh iam-service deploy
|
||||
```
|
||||
|
||||
## Backup & Restore
|
||||
|
||||
### Automatic Backups
|
||||
|
||||
Neon provides automatic backups. Access via Neon Console:
|
||||
- Point-in-time restore
|
||||
- Branch restore
|
||||
- Export data
|
||||
|
||||
### Manual Backup
|
||||
|
||||
```bash
|
||||
./scripts/db/backup.sh iam-service
|
||||
```
|
||||
|
||||
This creates a SQL dump file in `backups/` directory.
|
||||
|
||||
### Restore
|
||||
|
||||
```bash
|
||||
# From Neon Console (recommended)
|
||||
# Or using psql:
|
||||
psql $DATABASE_URL < backup.sql
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
Monitor your databases via Neon Console:
|
||||
- Connection metrics
|
||||
- Query performance
|
||||
- Storage usage
|
||||
- Branch status
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Issues
|
||||
|
||||
1. **Check connection string format**
|
||||
- Must include `?sslmode=require`
|
||||
- Verify credentials
|
||||
|
||||
2. **Check IP allowlist**
|
||||
- Neon may restrict IPs
|
||||
- Add your IP in Neon Console
|
||||
|
||||
3. **Check branch status**
|
||||
- Ensure branch is active
|
||||
- Check for maintenance
|
||||
|
||||
### Migration Issues
|
||||
|
||||
1. **DATABASE_URL not set**
|
||||
```bash
|
||||
export DATABASE_URL="your-neon-url"
|
||||
```
|
||||
|
||||
2. **Schema mismatch**
|
||||
```bash
|
||||
# Reset and re-migrate (dev only!)
|
||||
pnpm prisma migrate reset
|
||||
```
|
||||
|
||||
3. **Connection timeout**
|
||||
- Add `?pgbouncer=true` for pooling
|
||||
- Check Neon console for limits
|
||||
|
||||
### Performance Issues
|
||||
|
||||
1. **Enable connection pooling**
|
||||
- Add `?pgbouncer=true` to connection string
|
||||
|
||||
2. **Check query performance**
|
||||
- Use Neon Console query analyzer
|
||||
- Review slow queries
|
||||
|
||||
3. **Optimize indexes**
|
||||
- Review Prisma schema
|
||||
- Add indexes for frequent queries
|
||||
|
||||
## Cost Optimization
|
||||
|
||||
- **Free tier**: 0.5 GB storage, sufficient for dev
|
||||
- **Staging**: Use free tier or minimal paid plan
|
||||
- **Production**: Scale based on usage
|
||||
- **Branching**: Free branches for testing
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use connection pooling**: `?pgbouncer=true`
|
||||
2. **Use SSL**: `?sslmode=require`
|
||||
3. **Separate branches**: One per environment
|
||||
4. **Regular backups**: Use Neon's automatic backups
|
||||
5. **Monitor usage**: Check Neon Console regularly
|
||||
|
||||
## Quick Tips
|
||||
|
||||
### Mermaid Diagram Color Palette
|
||||
|
||||
| Element | Color | Usage |
|
||||
|---------|-------|-------|
|
||||
| **Project/Main** | `#1e293b` + `#3b82f6` | Primary containers |
|
||||
| **Development** | `#0f172a` + `#10b981` | Dev environment (green) |
|
||||
| **Staging** | `#0f172a` + `#f59e0b` | Staging environment (orange) |
|
||||
| **Production** | `#0f172a` + `#ef4444` | Prod environment (red) |
|
||||
| **Infrastructure** | `#475569` + `#94a3b8` | K8s, CI/CD (gray) |
|
||||
| **Error/Rollback** | `#7f1d1d` + `#ef4444` | Critical actions (dark red) |
|
||||
|
||||
### Common Mermaid Issues
|
||||
|
||||
**Syntax Errors:**
|
||||
- Use quotes for labels with special chars: `["Label<br/>text"]`
|
||||
- Escape HTML entities: `&` not `&`
|
||||
- Use `<br/>` for line breaks inside labels
|
||||
- Avoid `<br>` without closing slash
|
||||
|
||||
**Rendering Issues:**
|
||||
- If diagram doesn't render, check for matching brackets `[]` or `{}`
|
||||
- Verify all style declarations use valid CSS colors
|
||||
- Ensure subgraph names are unique
|
||||
|
||||
### Visual Indicators
|
||||
|
||||
| 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 |
|
||||
|
||||
## Resources
|
||||
|
||||
- [Neon Documentation](https://neon.tech/docs)
|
||||
- [Neon Console](https://console.neon.tech)
|
||||
- [Prisma + Neon Guide](https://neon.tech/docs/guides/prisma)
|
||||
301
microservices/docs/en/guides/observability.md
Normal file
301
microservices/docs/en/guides/observability.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# Observability Stack Guide
|
||||
|
||||
This guide explains how to use the observability stack (Grafana, Prometheus, Loki, Promtail) included in the infrastructure.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Components
|
||||
|
||||
The stack consists of the following components:
|
||||
|
||||
- **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
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- Existing `microservices-network` (created by the main application stack or manually)
|
||||
|
||||
### Starting the Stack
|
||||
|
||||
You can easily start the stack using the provided script:
|
||||
|
||||
```bash
|
||||
./scripts/observability/start.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
docker network create microservices-network || true
|
||||
|
||||
cd infra/observability
|
||||
docker-compose -f docker-compose.observability.yml up -d
|
||||
```
|
||||
|
||||
Check if all containers are running:
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
```
|
||||
|
||||
You should see `grafana`, `prometheus`, `loki`, and `promtail`.
|
||||
|
||||
## Accessing Services
|
||||
|
||||
| Service | URL | Credentials | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Grafana** | [http://localhost:3001](http://localhost:3001) | `admin` / `admin` | Main dashboard for visualization |
|
||||
| **Prometheus** | [http://localhost:9090](http://localhost:9090) | N/A | Raw metrics and target status |
|
||||
| **Loki** | [http://localhost:3100](http://localhost:3100) | N/A | Log aggregation API (no UI) |
|
||||
|
||||
## Using Grafana
|
||||
|
||||
### 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
|
||||
|
||||
### 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
|
||||
|
||||
### 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**
|
||||
|
||||
**LogQL Query Examples:**
|
||||
|
||||
```logql
|
||||
{container="iam-service"}
|
||||
{container="iam-service"} |= "error"
|
||||
{container="iam-service"} |= "error" | json
|
||||
```
|
||||
|
||||
### Viewing Metrics (Prometheus)
|
||||
|
||||
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**
|
||||
|
||||
**PromQL Query Examples:**
|
||||
|
||||
```promql
|
||||
up
|
||||
|
||||
rate(http_requests_total[5m])
|
||||
|
||||
container_memory_usage_bytes{container="iam-service"}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### File Locations
|
||||
|
||||
- **Prometheus**: `infra/observability/prometheus/prometheus.yml`
|
||||
- **Promtail**: `infra/observability/promtail/promtail-config.yml`
|
||||
- **Grafana**: `infra/observability/grafana/`
|
||||
|
||||
### Custom Metrics
|
||||
|
||||
To expose custom metrics from your service:
|
||||
|
||||
```typescript
|
||||
import { Counter, Histogram } from 'prom-client';
|
||||
|
||||
const requestCounter = new Counter({
|
||||
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']
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Dashboards
|
||||
|
||||
Create custom dashboards in Grafana:
|
||||
|
||||
1. Click **+** → **Dashboard**
|
||||
2. Add **Panel**
|
||||
3. Configure query (Prometheus or Loki)
|
||||
4. Save dashboard
|
||||
|
||||
## Color Palette Reference
|
||||
|
||||
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 |
|
||||
|
||||
**All text uses `color:#ffffff` (white) for readability on dark backgrounds**
|
||||
|
||||
## Quick Tips
|
||||
|
||||
### Mermaid Common Issues
|
||||
|
||||
**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:**
|
||||
- Mix `graph` and `flowchart` syntax
|
||||
- Use special characters in node IDs without quotes
|
||||
- Forget closing brackets for subgraphs
|
||||
|
||||
### LogQL Quick Reference
|
||||
|
||||
```logql
|
||||
{label="value"}
|
||||
{label="value"} |= "search"
|
||||
{label="value"} |= "error" | json
|
||||
{label="value"} | logfmt
|
||||
```
|
||||
|
||||
### PromQL Quick Reference
|
||||
|
||||
```promql
|
||||
metric_name
|
||||
metric_name{label="value"}
|
||||
rate(metric_name[5m])
|
||||
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
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
| Issue | Symptoms | Solution |
|
||||
|-------|----------|----------|
|
||||
| No logs visible | Grafana Explore shows no logs | Check Promtail is running: `docker ps \| grep promtail` |
|
||||
| Missing metrics | Services don't appear in Prometheus targets | Check service `/metrics` endpoint |
|
||||
| Container won't start | `docker ps` doesn't show container | View logs: `docker-compose logs <service-name>` |
|
||||
| Network issue | Services can't connect | Create network: `docker network create microservices-network` |
|
||||
|
||||
### 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`
|
||||
|
||||
### 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
|
||||
|
||||
### Grafana Shows "No Data"
|
||||
|
||||
1. Verify datasource connection (Configuration → Data Sources)
|
||||
2. Check time range in query
|
||||
3. Ensure data exists in Prometheus/Loki
|
||||
423
microservices/docs/en/guides/troubleshooting.md
Normal file
423
microservices/docs/en/guides/troubleshooting.md
Normal file
@@ -0,0 +1,423 @@
|
||||
# Troubleshooting Guide
|
||||
|
||||
> **Note**: This guide focuses on debugging the GoodGo Microservices Platform in a local development environment (Docker Compose).
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [General Diagnosis](#general-diagnosis)
|
||||
2. [Infrastructure Issues](#infrastructure-issues)
|
||||
- [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)
|
||||
4. [Debugging Tools](#debugging-tools)
|
||||
5. [FAQ](#faq)
|
||||
|
||||
---
|
||||
|
||||
## General Diagnosis
|
||||
|
||||
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`.*
|
||||
|
||||
2. **Check Logs**:
|
||||
```bash
|
||||
# View logs for a specific service
|
||||
docker-compose logs -f <service-name>
|
||||
|
||||
# View last 100 lines for all
|
||||
docker-compose logs --tail=100
|
||||
```
|
||||
|
||||
3. **Check Connectivity**:
|
||||
* Can you reach the Gateway? `curl http://localhost/health`
|
||||
* Can you reach the Dashboard? http://localhost:8080
|
||||
|
||||
### Troubleshooting Flowchart
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([ Issue Detected]) --> CheckStatus{Check Service<br/>Status}
|
||||
|
||||
CheckStatus -->|All Running| CheckLogs[ Check Logs]
|
||||
CheckStatus -->|Some Down| IdentifyService[ Identify Failed<br/>Service]
|
||||
|
||||
IdentifyService --> ServiceType{Service Type?}
|
||||
|
||||
ServiceType -->|Infrastructure| InfraCheck[ Infrastructure<br/>Check]
|
||||
ServiceType -->|Application| AppCheck[ Application<br/>Check]
|
||||
|
||||
InfraCheck --> DBCheck{Database?}
|
||||
InfraCheck --> RedisCheck{Redis?}
|
||||
InfraCheck --> TraefikCheck{Traefik?}
|
||||
|
||||
DBCheck -->|Yes| DBSolution[ Check DATABASE_URL<br/> Verify Neon connection<br/> Check IP whitelist]
|
||||
RedisCheck -->|Yes| RedisSolution[ Restart Redis<br/> Check port mapping<br/> Verify connection string]
|
||||
TraefikCheck -->|Yes| TraefikSolution[ Check labels<br/> Verify PathPrefix<br/> Check health status]
|
||||
|
||||
AppCheck --> ErrorType{Error Type?}
|
||||
|
||||
ErrorType -->|Config| ConfigFix[ Check .env variables<br/> Run init-project.sh]
|
||||
ErrorType -->|Prisma| PrismaFix[ Check migrations<br/> Regenerate client<br/> Reset database]
|
||||
ErrorType -->|Auth| AuthFix[ Check token expiry<br/> Verify keys<br/> Sync Docker time]
|
||||
|
||||
CheckLogs --> LogAnalysis{Log Shows<br/>Error?}
|
||||
LogAnalysis -->|Yes| ErrorType
|
||||
LogAnalysis -->|No| ConnCheck[ Check Connectivity]
|
||||
|
||||
ConnCheck --> GatewayTest{Gateway<br/>Reachable?}
|
||||
GatewayTest -->|No| TraefikCheck
|
||||
GatewayTest -->|Yes| ServiceTest{Service<br/>Reachable?}
|
||||
|
||||
ServiceTest -->|No| AppCheck
|
||||
ServiceTest -->|Yes| Resolved([ Issue Resolved])
|
||||
|
||||
DBSolution --> Restart[ Restart Services]
|
||||
RedisSolution --> Restart
|
||||
TraefikSolution --> Restart
|
||||
ConfigFix --> Restart
|
||||
PrismaFix --> Restart
|
||||
AuthFix --> Restart
|
||||
|
||||
Restart --> Verify{Issue<br/>Fixed?}
|
||||
Verify -->|Yes| Resolved
|
||||
Verify -->|No| DeepDebug[ Deep Debugging<br/>Required]
|
||||
|
||||
DeepDebug --> ContainerShell[Access Container Shell]
|
||||
DeepDebug --> PrismaStudio[Use Prisma Studio]
|
||||
DeepDebug --> RedisInspect[Inspect Redis]
|
||||
DeepDebug --> APITest[Direct API Testing]
|
||||
|
||||
style Start fill:#1a1a2e,color:#fff
|
||||
style Resolved fill:#0f3460,color:#fff
|
||||
style CheckStatus fill:#16213e,color:#fff
|
||||
style ServiceType fill:#16213e,color:#fff
|
||||
style ErrorType fill:#16213e,color:#fff
|
||||
style DBCheck fill:#16213e,color:#fff
|
||||
style RedisCheck fill:#16213e,color:#fff
|
||||
style TraefikCheck fill:#16213e,color:#fff
|
||||
style GatewayTest fill:#16213e,color:#fff
|
||||
style ServiceTest fill:#16213e,color:#fff
|
||||
style Verify fill:#16213e,color:#fff
|
||||
style LogAnalysis fill:#16213e,color:#fff
|
||||
style InfraCheck fill:#1a1a40,color:#fff
|
||||
style AppCheck fill:#1a1a40,color:#fff
|
||||
style DBSolution fill:#0f4c75,color:#fff
|
||||
style RedisSolution fill:#0f4c75,color:#fff
|
||||
style TraefikSolution fill:#0f4c75,color:#fff
|
||||
style ConfigFix fill:#0f4c75,color:#fff
|
||||
style PrismaFix fill:#0f4c75,color:#fff
|
||||
style AuthFix fill:#0f4c75,color:#fff
|
||||
style Restart fill:#3282b8,color:#fff
|
||||
style DeepDebug fill:#1b262c,color:#fff
|
||||
style IdentifyService fill:#1a1a40,color:#fff
|
||||
style CheckLogs fill:#1a1a40,color:#fff
|
||||
style ConnCheck fill:#1a1a40,color:#fff
|
||||
style ContainerShell fill:#0f3460,color:#fff
|
||||
style PrismaStudio fill:#0f3460,color:#fff
|
||||
style RedisInspect fill:#0f3460,color:#fff
|
||||
style APITest fill:#0f3460,color:#fff
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Infrastructure Issues
|
||||
|
||||
### Database (Neon/PostgreSQL)
|
||||
|
||||
**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.
|
||||
|
||||
**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.
|
||||
|
||||
**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.
|
||||
|
||||
### Redis
|
||||
|
||||
**Problem**: `Redis connection refused` or `ECONNREFUSED`
|
||||
|
||||
* **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`
|
||||
|
||||
### Traefik Gateway
|
||||
|
||||
**Problem**: `404 Not Found` when accessing APIs (e.g., `http://localhost/api/v1/auth`)
|
||||
|
||||
* **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).
|
||||
|
||||
**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`).
|
||||
|
||||
---
|
||||
|
||||
## Service Issues
|
||||
|
||||
### Service Fails to Start
|
||||
|
||||
**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).
|
||||
|
||||
### Prisma/Database Errors
|
||||
|
||||
**Error**: `P2025: Record to update not found`
|
||||
|
||||
* **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).
|
||||
|
||||
**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`.
|
||||
|
||||
### 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).
|
||||
|
||||
**Solution**:
|
||||
1. Check server logs for JWT verification errors.
|
||||
2. Restart services to refresh keys.
|
||||
3. Sync Docker time: restart Docker Desktop.
|
||||
|
||||
---
|
||||
|
||||
## Debugging Tools
|
||||
|
||||
### 1. Accessing Container Shell
|
||||
|
||||
To inspect files or run commands inside a running container:
|
||||
|
||||
```bash
|
||||
docker-compose exec iam-service sh
|
||||
# or /bin/bash
|
||||
```
|
||||
|
||||
### 2. Inspecting Database (via Prisma Studio)
|
||||
|
||||
Use Prisma Studio to view/edit data visually:
|
||||
|
||||
```bash
|
||||
pnpm --filter @goodgo/iam-service prisma studio
|
||||
# Opens http://localhost:5555
|
||||
```
|
||||
|
||||
### 3. Inspecting Redis
|
||||
|
||||
```bash
|
||||
docker-compose exec redis redis-cli
|
||||
> PING
|
||||
PONG
|
||||
> KEYS *
|
||||
1) "user:123:session"
|
||||
```
|
||||
|
||||
### 4. Direct API Testing
|
||||
|
||||
Use `curl` or Postman.
|
||||
|
||||
```bash
|
||||
# Health Check
|
||||
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"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Why is my change not reflecting?**
|
||||
A: If you changed `.env` or `docker-compose.yml`, you must restart:
|
||||
```bash
|
||||
docker-compose down && docker-compose up -d
|
||||
```
|
||||
If you changed code, hot-reloading (nodemon) should pick it up. If not, restart container.
|
||||
|
||||
**Q: How do I reset everything?**
|
||||
A: Be careful, this deletes all data!
|
||||
```bash
|
||||
docker-compose down -v
|
||||
# -v removes volumes (Redis data, etc.)
|
||||
```
|
||||
|
||||
**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.
|
||||
|
||||
---
|
||||
|
||||
## Quick Tips
|
||||
|
||||
### Debugging Shortcuts
|
||||
|
||||
```bash
|
||||
# Quick health check all services
|
||||
docker-compose ps | grep -v "Up"
|
||||
|
||||
# Tail logs for all services
|
||||
docker-compose logs -f --tail=50
|
||||
|
||||
# Restart specific service without rebuilding
|
||||
docker-compose restart iam-service
|
||||
|
||||
# Rebuild and restart service
|
||||
docker-compose up -d --build iam-service
|
||||
|
||||
# Check resource usage
|
||||
docker stats --no-stream
|
||||
|
||||
# Clean up unused resources
|
||||
docker system prune -a --volumes
|
||||
```
|
||||
|
||||
### Common Error Patterns
|
||||
|
||||
| Error Pattern | Likely Cause | Quick Fix |
|
||||
|--------------|--------------|-----------|
|
||||
| `ECONNREFUSED` | Service not running | `docker-compose restart <service>` |
|
||||
| `P1001` | Database unreachable | Check `DATABASE_URL` and internet |
|
||||
| `P2002` | Duplicate entry | Check unique constraints |
|
||||
| `401 Unauthorized` | Token expired/invalid | Refresh token or re-login |
|
||||
| `404 Not Found` | Wrong route/service down | Check Traefik dashboard |
|
||||
| `502 Bad Gateway` | Service crashed | Check service logs |
|
||||
| `Config validation error` | Missing env vars | Run `init-project.sh` |
|
||||
|
||||
### 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
|
||||
|
||||
**Useful grep patterns:**
|
||||
```bash
|
||||
# Find all errors
|
||||
docker-compose logs | grep -i error
|
||||
|
||||
# Find specific service errors
|
||||
docker-compose logs iam-service | grep -i "error\|failed"
|
||||
|
||||
# Find database connection issues
|
||||
docker-compose logs | grep -i "prisma\|database\|p1001\|p1003"
|
||||
|
||||
# Find auth issues
|
||||
docker-compose logs | grep -i "unauthorized\|401\|jwt\|token"
|
||||
```
|
||||
|
||||
### Resource Management
|
||||
|
||||
**Recommended Docker Resources:**
|
||||
- **RAM**: Minimum 4GB, Recommended 8GB
|
||||
- **CPU**: Minimum 2 cores, Recommended 4 cores
|
||||
- **Disk**: Minimum 10GB free space
|
||||
|
||||
**Check resource usage:**
|
||||
```bash
|
||||
# Overall system
|
||||
docker system df
|
||||
|
||||
# Per container
|
||||
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
|
||||
```
|
||||
|
||||
**Cleanup commands:**
|
||||
```bash
|
||||
# Remove stopped containers
|
||||
docker container prune
|
||||
|
||||
# Remove unused images
|
||||
docker image prune -a
|
||||
|
||||
# Remove unused volumes ( deletes data!)
|
||||
docker volume prune
|
||||
|
||||
# Nuclear option ( removes everything!)
|
||||
docker system prune -a --volumes
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Always check logs first** before making changes
|
||||
2. **Use Traefik Dashboard** (http://localhost:8080) to verify routing
|
||||
3. **Keep `.env.local` updated** with correct credentials
|
||||
4. **Don't delete volumes** unless you want to lose data
|
||||
5. **Restart Docker Desktop** if experiencing weird networking issues
|
||||
6. **Use `docker-compose down && up`** after `.env` changes
|
||||
7. **Keep services running** you're actively developing
|
||||
8. **Stop services** you're not using to save resources
|
||||
|
||||
### 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
|
||||
|
||||
### Related Resources
|
||||
|
||||
- [Local Deployment Guide](./local-deployment.md) - Setup instructions
|
||||
- [Development Guide](./development.md) - Development workflow
|
||||
- [Kubernetes Local Guide](./kubernetes-local.md) - K8s troubleshooting
|
||||
- [Neon Database Guide](./neon-database.md) - Database management
|
||||
Reference in New Issue
Block a user