- Updated the introductory notes in both Vietnamese and English development guides for improved clarity. - Reorganized the workflow steps in the Vietnamese documentation to align with the English version. - Added detailed Mermaid diagrams for better visualization of development processes and testing strategies. - Introduced new sections for color palette references and verification checklists to enhance documentation completeness. - Simplified headers and improved formatting for better readability across both language versions.
9.4 KiB
9.4 KiB
Development Guide
Comprehensive standards and workflows for contributing to the GoodGo Microservices Platform
Table of Contents
- Project Structure
- Code Standards
- Git Workflow
- Backend Development
- Testing Strategy
- Database Workflow
- 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.
/**
* 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. Noanyallowed (useunknownif 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 offdevelop).fix/xyz: Bug fixes (branch offdevelop).hotfix/xyz: Critical fixes (branch offmain).
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:
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
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:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style Done fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style DTO fill:#3498DB,color:#fff
style Repo fill:#2980B9,color:#fff
style Service fill:#8E44AD,color:#fff
style Controller fill:#E67E22, color:#fff
style Route fill:#2980B9,color:#fff
style Middleware fill:#3498DB,color:#fff
style Test fill:#27AE60,color:#fff
style ErrorCheck fill:#E67E22,color:#fff
style ThrowError fill:#C0392B,color:#fff
style ErrorHandler fill:#C0392B,color:#fff
style Response fill:#7F8C8D,color:#fff
style Success fill:#27AE60,color:#fff
Creating a New API Endpoint
-
Define DTO (
modules/user/user.dto.ts):export const CreateUserDto = z.object({ email: z.string().email(), name: z.string().min(2), }); export type CreateUserDto = z.infer<typeof CreateUserDto>; -
Create Service Method (
modules/user/user.service.ts):- Implement business logic.
- Use
BaseRepository. - Throw
HttpError(e.g.,NotFound,BadRequest).
-
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 }).
- Parse body with DTO:
-
Register Route (
modules/user/index.ts):- Add to Express router with middlewares.
Error Handling
Always use the custom error classes from core/errors:
import { NotFoundError, ConflictError } from '../../core/errors';
if (!user) {
throw new NotFoundError('User not found');
}
Testing Strategy
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:#27AE60,color:#fff
style Integration fill:#3498DB,color:#fff
style E2E fill:#8E44AD,color:#fff
style Code fill:#2980B9,color:#fff
style CheckLint fill:#E67E22,color:#fff
style UnitPass fill:#27AE60,color:#fff
style IntPass fill:#3498DB,color:#fff
style E2EPass fill:#8E44AD,color:#fff
style Coverage fill:#F39C12,color:#fff
style RunUnit fill:#27AE60,color:#fff
style RunIntegration fill:#3498DB,color:#fff
style RunE2E fill:#8E44AD,color:#fff
style ReadyMerge fill:#27AE60,color:#fff,stroke:#27AE60,stroke-width:2px
style FixLint fill:#C0392B,color:#fff
style FixUnit fill:#C0392B,color:#fff
style FixIntegration fill:#C0392B,color:#fff
style FixE2E fill:#C0392B,color:#fff
style AddTests fill:#F39C12,color:#fff
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
- Modify
prisma/schema.prisma. - Create migration (Dev):
./scripts/db/migrate.sh iam-service dev --name add_user_profile - Apply to Production (CI/CD):
./scripts/db/migrate.sh iam-service deploy
Seed Data
Populate database with initial data:
./scripts/db/seed.sh iam-service
Visualizing Data
Use Prisma Studio:
pnpm --filter @goodgo/iam-service prisma studio
Kubernetes Deployment
For local Kubernetes testing (Docker Desktop / Minikube):
# 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 for detailed setup.