- Added request/response flow diagrams to api-design and api-gateway-advanced skills for better visualization of processes. - Introduced configuration loading flow in configuration-management skill to clarify the configuration process. - Included error propagation flow in error-handling-patterns skill to illustrate error handling across layers. - Enhanced various skills with additional diagrams to improve understanding of complex concepts. These updates aim to provide clearer guidance and improve the overall documentation experience for developers.
401 lines
13 KiB
Markdown
401 lines
13 KiB
Markdown
---
|
|
name: project-rules
|
|
description: GoodGo Microservices Platform coding standards and architecture patterns. Use when working with services, apps, packages, or infrastructure.
|
|
---
|
|
|
|
# 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
|
|
|
|
### Monorepo Architecture
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph apps[Apps Layer]
|
|
webAdmin[web-admin<br/>Next.js Admin]
|
|
webClient[web-client<br/>Next.js Client]
|
|
appAdmin[app-admin<br/>Flutter Admin]
|
|
appClient[app-client<br/>Flutter Client]
|
|
end
|
|
|
|
subgraph gateway[API Gateway]
|
|
traefik[Traefik<br/>Path-based Routing]
|
|
end
|
|
|
|
subgraph services[Services Layer]
|
|
iamService[iam-service<br/>IAM Service]
|
|
templateService[_template<br/>Service Template]
|
|
otherServices[Other Services<br/>Node.js/TypeScript]
|
|
end
|
|
|
|
subgraph packages[Shared Packages]
|
|
loggerPackage[@goodgo/logger<br/>Centralized Logging]
|
|
typesPackage[@goodgo/types<br/>TypeScript Types]
|
|
httpClientPackage[@goodgo/http-client<br/>API Client]
|
|
authSdkPackage[@goodgo/auth-sdk<br/>Auth Utilities]
|
|
tracingPackage[@goodgo/tracing<br/>OpenTelemetry]
|
|
configPackage[@goodgo/config<br/>Shared Configs]
|
|
end
|
|
|
|
subgraph infrastructure[Infrastructure]
|
|
postgres[Neon PostgreSQL<br/>Database]
|
|
redis[Redis<br/>Cache]
|
|
prometheus[Prometheus<br/>Metrics]
|
|
grafana[Grafana<br/>Dashboards]
|
|
loki[Loki<br/>Log Aggregation]
|
|
end
|
|
|
|
subgraph deployments[Deployments]
|
|
dockerCompose[Docker Compose<br/>Local Development]
|
|
kubernetes[Kubernetes<br/>Staging/Production]
|
|
end
|
|
|
|
webAdmin --> traefik
|
|
webClient --> traefik
|
|
appAdmin --> traefik
|
|
appClient --> traefik
|
|
traefik --> iamService
|
|
traefik --> otherServices
|
|
iamService --> packages
|
|
otherServices --> packages
|
|
iamService --> postgres
|
|
otherServices --> postgres
|
|
iamService --> redis
|
|
otherServices --> redis
|
|
services --> prometheus
|
|
services --> loki
|
|
prometheus --> grafana
|
|
loki --> grafana
|
|
services --> deployments
|
|
```
|
|
|
|
## Tech Stack
|
|
|
|
**Frontend:**
|
|
- Next.js 14+ (App Router), TypeScript, Tailwind CSS, Zustand
|
|
- Flutter 3.x with Provider pattern
|
|
- Use `@goodgo/types` and `@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`
|
|
|
|
### Detailed Structure Diagram
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph service[Service Structure]
|
|
serviceRoot[service-name/]
|
|
serviceSrc[src/]
|
|
serviceConfig[config/<br/>Configuration]
|
|
serviceModules[modules/<br/>Feature Modules]
|
|
serviceMiddlewares[middlewares/<br/>Express Middlewares]
|
|
serviceRoutes[routes/<br/>Route Definitions]
|
|
serviceMain[main.ts<br/>Entry Point]
|
|
servicePrisma[prisma/<br/>Schema & Migrations]
|
|
serviceDockerfile[Dockerfile<br/>Container Definition]
|
|
servicePackageJson[package.json<br/>Dependencies]
|
|
|
|
serviceRoot --> serviceSrc
|
|
serviceRoot --> servicePrisma
|
|
serviceRoot --> serviceDockerfile
|
|
serviceRoot --> servicePackageJson
|
|
serviceSrc --> serviceConfig
|
|
serviceSrc --> serviceModules
|
|
serviceSrc --> serviceMiddlewares
|
|
serviceSrc --> serviceRoutes
|
|
serviceSrc --> serviceMain
|
|
end
|
|
|
|
subgraph package[Package Structure]
|
|
packageRoot[package-name/]
|
|
packageSrc[src/]
|
|
packageIndex[index.ts<br/>Main Export]
|
|
packagePackageJson[package.json<br/>Package Metadata]
|
|
packageTsconfig[tsconfig.json<br/>TypeScript Config]
|
|
packageReadme[README.md<br/>Documentation]
|
|
|
|
packageRoot --> packageSrc
|
|
packageRoot --> packagePackageJson
|
|
packageRoot --> packageTsconfig
|
|
packageRoot --> packageReadme
|
|
packageSrc --> packageIndex
|
|
end
|
|
|
|
subgraph app[App Structure - Next.js]
|
|
appRoot[app-name/]
|
|
appSrc[src/]
|
|
appApp[app/<br/>Next.js App Router]
|
|
appServicesApi[services/api/<br/>API Clients]
|
|
appStores[stores/<br/>State Management]
|
|
appDockerfile[Dockerfile<br/>Container Definition]
|
|
appPackageJson[package.json<br/>Dependencies]
|
|
|
|
appRoot --> appSrc
|
|
appRoot --> appDockerfile
|
|
appRoot --> appPackageJson
|
|
appSrc --> appApp
|
|
appSrc --> appServicesApi
|
|
appSrc --> appStores
|
|
end
|
|
|
|
subgraph module[Module Structure inside modules/]
|
|
moduleRoot[modules/feature-name/]
|
|
moduleController[feature.controller.ts<br/>HTTP Handlers]
|
|
moduleService[feature.service.ts<br/>Business Logic]
|
|
moduleRepository[feature.repository.ts<br/>Data Access]
|
|
moduleDto[feature.dto.ts<br/>Zod Schemas]
|
|
moduleTypes[feature.types.ts<br/>TypeScript Types]
|
|
moduleTest[feature.controller.test.ts<br/>Unit Tests]
|
|
|
|
moduleRoot --> moduleController
|
|
moduleRoot --> moduleService
|
|
moduleRoot --> moduleRepository
|
|
moduleRoot --> moduleDto
|
|
moduleRoot --> moduleTypes
|
|
moduleRoot --> moduleTest
|
|
moduleController --> moduleService
|
|
moduleService --> moduleRepository
|
|
end
|
|
|
|
serviceModules --> moduleRoot
|
|
```
|
|
|
|
## 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:**
|
|
1. Copy `services/_template/`
|
|
2. Update `package.json` name to `@goodgo/service-name`
|
|
3. Add to `deployments/local/docker-compose.yml` with Traefik labels
|
|
4. Configure Prisma schema if needed
|
|
5. Add health check endpoint
|
|
|
|
**New Package:**
|
|
1. Create in `packages/`, export from `src/index.ts`
|
|
2. Add to `pnpm-workspace.yaml`
|
|
3. Use TypeScript strict mode
|
|
|
|
**Dependencies:**
|
|
```bash
|
|
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:**
|
|
```bash
|
|
pnpm --filter @goodgo/service-name prisma migrate dev
|
|
pnpm --filter @goodgo/service-name prisma generate
|
|
```
|
|
|
|
## Code Standards
|
|
|
|
**TypeScript:**
|
|
- Strict mode, no `any` (use `unknown`)
|
|
- Zod for runtime validation
|
|
- Export shared types from `@goodgo/types`
|
|
|
|
**API Responses:**
|
|
```typescript
|
|
// Success: { success: true, data: any }
|
|
// Error: { success: false, error: { code, message, details? } }
|
|
```
|
|
|
|
**Logging:**
|
|
```typescript
|
|
import { logger } from '@goodgo/logger';
|
|
logger.info('Message', { context });
|
|
logger.error('Error', { error, context });
|
|
```
|
|
|
|
**Environment:**
|
|
- Use `.env.example` template, 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:**
|
|
```dockerfile
|
|
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:**
|
|
```typescript
|
|
// 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:
|
|
|
|
```yaml
|
|
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_URL` in `.env.local`
|
|
- Module not found: Run `pnpm install`
|
|
- Type errors: Run `pnpm --filter @goodgo/service-name prisma generate`
|
|
|
|
**Debug:**
|
|
```bash
|
|
cd deployments/local
|
|
docker-compose logs -f service-name
|
|
docker-compose ps
|
|
docker-compose up -d --build
|
|
```
|
|
|
|
## Resources
|
|
|
|
- [Architecture Docs](../../docs/architecture/)
|
|
- [API Specs](../../docs/api/openapi/)
|
|
- [Development Guide](../../docs/guides/development.md)
|
|
- [Deployment Guide](../../docs/guides/deployment.md)
|
|
- [Neon Database Guide](../../docs/guides/neon-database.md)
|
|
- [Contributing Guide](../../CONTRIBUTING.md)
|