9.8 KiB
trigger
| trigger |
|---|
| always_on |
GoodGo Project Rules
Architecture
Monorepo Structure:
- Apps: Next.js (web) + Flutter (mobile)
- Services: Node.js/TypeScript microservices (Express)
- Packages: Shared libraries (logger, types, http-client, auth-sdk, tracing)
- Infrastructure: Traefik (API Gateway), Redis, Neon PostgreSQL, Observability
- Deployments: Local (Docker Compose), Staging/Production (Kubernetes)
Template Location: services/_template/ - Use as starting point for new services
Tech Stack
Frontend:
- Next.js 14+ (App Router), TypeScript, Tailwind CSS, Zustand
- Flutter 3.x with Provider pattern
- Use
@goodgo/typesand@goodgo/http-client
Backend:
- Node.js 20+, TypeScript 5+, Express
- Prisma ORM + Neon PostgreSQL
- Zod validation,
@goodgo/logger,@goodgo/tracing,@goodgo/auth-sdk
Infrastructure:
- Traefik (path-based routing), Redis (cache), Prometheus + Grafana + Loki
Project Structure
Service: src/{config,modules,middlewares,routes,main.ts} + prisma/ + Dockerfile
Package: src/index.ts + package.json + tsconfig.json + README.md
App: src/{app,services/api,stores} + Dockerfile
Naming Conventions
- Services/Packages:
kebab-case(e.g.,auth-service,http-client) - Files:
kebab-case.type.ts(e.g.,user.controller.ts) - Components:
PascalCase.tsx(React),snake_case.dart(Flutter) - Classes:
PascalCase, Functions:camelCase, Constants:UPPER_SNAKE_CASE - Package Names:
@goodgo/package-name
Workflows
New Service:
- Copy
services/_template/ - Update
package.jsonname to@goodgo/service-name - Add to
deployments/local/docker-compose.ymlwith Traefik labels - Configure Prisma schema if needed
- Add health check endpoint
New Package:
- Create in
packages/, export fromsrc/index.ts - Add to
pnpm-workspace.yaml - Use TypeScript strict mode
Dependencies:
pnpm --filter @goodgo/service-name add package-name
pnpm --filter @goodgo/service-name add @goodgo/logger # workspace
pnpm --filter @goodgo/service-name add -D @types/pkg # dev
Database:
pnpm --filter @goodgo/service-name prisma migrate dev
pnpm --filter @goodgo/service-name prisma generate
Code Standards
TypeScript:
- Strict mode, no
any(useunknown) - Zod for runtime validation
- Export shared types from
@goodgo/types
API Responses:
// Success: { success: true, data: any }
// Error: { success: false, error: { code, message, details? } }
Logging:
import { logger } from '@goodgo/logger';
logger.info('Message', { context });
logger.error('Error', { error, context });
Environment:
- Use
.env.exampletemplate, never commit.env - Validate with Zod at startup
- Document all vars in README
Testing
- Unit: Place tests next to source (
*.test.ts), use Jest, mock dependencies, >80% coverage - Integration: Test API endpoints, use test database, cleanup after
- Commands:
pnpm test,pnpm --filter @goodgo/service-name test,pnpm test:coverage
Docker
Multi-stage Build Pattern:
FROM node:20-alpine AS builder
# ... build stage
FROM node:20-alpine
# ... production stage with non-root user
Image Naming: goodgo/service-name:version (semantic versioning)
Git Workflow
Branches: feature/, fix/, hotfix/, release/
Commits: Conventional Commits format
type(scope): subject
Types: feat, fix, docs, style, refactor, test, chore
PRs: Use template, link issues, ensure CI passes, squash merge to main
CI/CD
GitHub Actions: PR (lint, test, build) → develop (staging) → main (production)
Deployment Checklist: Tests pass, no lint errors, env vars set, migrations applied, docs updated, monitoring configured
Security
Auth: JWT (15min access, 7d refresh), httpOnly cookies, use @goodgo/auth-sdk
Authorization: RBAC, check permissions at service level, middleware for routes
Data: bcrypt (cost 12), HTTPS, sanitize inputs, Zod validation
Secrets: Environment variables, Kubernetes secrets, never hardcode, rotate regularly
Performance
Backend: Redis caching, connection pooling, pagination, database indexes, rate limiting Frontend: Next.js Image optimization, code splitting, lazy loading, React.memo, bundle optimization Database: Prisma optimization, indexes, transactions, soft deletes
Observability
Metrics: Prometheus (request count, duration, errors), set alerts
Logging: @goodgo/logger with trace IDs, levels (error, warn, info, debug), Loki aggregation
Tracing: OpenTelemetry via @goodgo/tracing, trace cross-service requests
Documentation
Code: JSDoc for public APIs, inline comments for complex logic, README per service/package
API: OpenAPI/Swagger specs in docs/api/openapi/, document endpoints with examples
Architecture: System design in docs/architecture/, service communication, data flows, ADRs
Architecture Patterns
Modular Structure: Controller → Service → Repository pattern DTO Validation: Zod schemas with type inference Error Handling: Custom error classes, global error middleware Dependency Injection: Constructor injection for testability
Example Module:
// DTO with Zod
export const CreateFeatureDto = z.object({
name: z.string().min(1),
email: z.string().email()
});
export type CreateFeatureDto = z.infer<typeof CreateFeatureDto>;
// Controller
export class FeatureController {
constructor(private service: FeatureService) {}
async create(req: Request, res: Response, next: NextFunction) {
try {
const dto = CreateFeatureDto.parse(req.body);
const result = await this.service.create(dto);
res.json({ success: true, data: result });
} catch (error) { next(error); }
}
}
// Service
export class FeatureService {
constructor(private repository: FeatureRepository) {}
async create(dto: CreateFeatureDto) {
return this.repository.create(dto);
}
}
// Repository
export class FeatureRepository extends BaseRepository<Feature> {
async create(data: CreateFeatureDto) {
return this.prisma.feature.create({ data });
}
}
Deployment & Traefik
Service Registration:
Services are deployed via deployments/local/docker-compose.yml and auto-discovered by Traefik:
services:
my-service:
build:
context: ../..
dockerfile: services/my-service/Dockerfile
labels:
- "traefik.enable=true"
- "traefik.http.routers.my-service.rule=PathPrefix(`/api/v1/my-service`)"
- "traefik.http.services.my-service.loadbalancer.server.port=5002"
- "traefik.http.services.my-service.loadbalancer.healthcheck.path=/health/live"
Traefik Configuration:
- Location:
infra/traefik/(platform-level, not per-service) - Static Config:
traefik.yml- Entry points, providers, dashboard - Dynamic Config:
dynamic/middlewares.yml,dynamic/routes.yml - Dashboard: http://localhost:8080
Access Points:
- API:
http://localhost/api/v1/service-name - Health:
http://localhost/api/v1/service-name/health - Docs:
http://localhost/api/v1/service-name/api-docs
Troubleshooting
Common Issues:
- Port conflicts: Check
deployments/local/docker-compose.yml - Database: Verify
DATABASE_URLin.env.local - Module not found: Run
pnpm install - Type errors: Run
pnpm --filter @goodgo/service-name prisma generate
Debug:
cd deployments/local
docker-compose logs -f service-name
docker-compose ps
docker-compose up -d --build
Common Mistakes
-
Wrong Directory Structure: Placing files in wrong locations
# ❌ BAD: Controllers outside modules src/controllers/user.controller.ts # ✅ GOOD: Controllers inside modules src/modules/user/user.controller.ts -
Inconsistent Naming: Mixing naming conventions
// ❌ BAD: Mixed naming UserService.ts user_repository.ts userController.ts // ✅ GOOD: Consistent kebab-case user.service.ts user.repository.ts user.controller.ts -
Wrong Response Format: Not following API response standard
// ❌ BAD: Inconsistent format res.json({ user: data }); res.json({ error: "Not found" }); // ✅ GOOD: Standard format res.json({ success: true, data: user }); res.json({ success: false, error: { code: 'NOT_FOUND', message: 'User not found' } }); -
Missing Bilingual Comments: Only one language
// ❌ BAD: English only // Initialize database // ✅ GOOD: Bilingual // EN: Initialize database connection // VI: Khởi tạo kết nối database
Quick Reference
| Category | Pattern/Standard |
|---|---|
| Service structure | src/{config,modules,middlewares,routes,main.ts} |
| File naming | kebab-case.type.ts (e.g., user.controller.ts) |
| Package naming | @goodgo/package-name |
| API response | { success: true, data } / { success: false, error: { code, message } } |
| Password hashing | bcrypt, cost 12 |
| JWT tokens | Access: 15min, Refresh: 7 days |
| Coverage target | >80% for unit tests |
| Commits | type(scope): subject (conventional commits) |
Common Commands:
# Add dependency
pnpm --filter @goodgo/service-name add package-name
# Run migrations
pnpm --filter @goodgo/service-name prisma migrate dev
# Run tests
pnpm --filter @goodgo/service-name test
# Start dev server
pnpm --filter @goodgo/service-name dev