moicle 1.3.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -5
- package/assets/agents/developers/nodejs-backend-dev.md +92 -0
- package/assets/agents/developers/react-frontend-dev.md +32 -19
- package/assets/architecture/ddd-architecture.md +337 -0
- package/assets/architecture/go-backend.md +770 -693
- package/assets/architecture/laravel-backend.md +388 -156
- package/assets/architecture/nodejs-nestjs.md +949 -0
- package/assets/architecture/react-frontend.md +216 -145
- package/assets/skills/architect-review/SKILL.md +292 -372
- package/assets/skills/deep-debug/SKILL.md +114 -0
- package/assets/skills/new-feature/SKILL.md +232 -252
- package/assets/skills/refactor/SKILL.md +261 -679
- package/assets/skills/research/SKILL.md +124 -0
- package/assets/skills/review-changes/SKILL.md +312 -0
- package/assets/skills/sync-docs/SKILL.md +115 -74
- package/assets/templates/go-gin/CLAUDE.md +671 -121
- package/assets/templates/react-vite/CLAUDE.md +204 -128
- package/package.json +1 -1
- package/assets/architecture/clean-architecture.md +0 -143
- package/assets/skills/go-module/SKILL.md +0 -77
- package/assets/skills/ship/SKILL.md +0 -297
package/README.md
CHANGED
|
@@ -60,25 +60,27 @@ moicle install
|
|
|
60
60
|
|
|
61
61
|
## What's Included
|
|
62
62
|
|
|
63
|
-
### Architecture References (
|
|
63
|
+
### Architecture References (8)
|
|
64
64
|
|
|
65
65
|
| File | Description |
|
|
66
66
|
|------|-------------|
|
|
67
67
|
| `clean-architecture.md` | Core Clean Architecture principles |
|
|
68
68
|
| `go-backend.md` | Go + Gin project structure |
|
|
69
69
|
| `laravel-backend.md` | Laravel + PHP project structure |
|
|
70
|
+
| `nodejs-nestjs.md` | Node.js + NestJS + Prisma (DDD + Hexagonal) |
|
|
70
71
|
| `react-frontend.md` | React + Vite project structure |
|
|
71
72
|
| `remix-fullstack.md` | Remix fullstack structure |
|
|
72
73
|
| `flutter-mobile.md` | Flutter mobile structure |
|
|
73
74
|
| `monorepo.md` | Monorepo structure |
|
|
74
75
|
|
|
75
|
-
### Developer Agents (
|
|
76
|
+
### Developer Agents (6)
|
|
76
77
|
|
|
77
78
|
| Agent | Description |
|
|
78
79
|
|-------|-------------|
|
|
79
80
|
| `@flutter-mobile-dev` | Flutter/Dart mobile & desktop development |
|
|
80
81
|
| `@go-backend-dev` | Go + Gin backend API development |
|
|
81
82
|
| `@laravel-backend-dev` | Laravel + PHP backend API development |
|
|
83
|
+
| `@nodejs-backend-dev` | Node.js + NestJS + Prisma backend development |
|
|
82
84
|
| `@react-frontend-dev` | React + TypeScript frontend development |
|
|
83
85
|
| `@remix-fullstack-dev` | Remix full-stack development |
|
|
84
86
|
|
|
@@ -105,22 +107,31 @@ moicle install
|
|
|
105
107
|
| `/brainstorm` | Brainstorm ideas with 6 frameworks |
|
|
106
108
|
| `/doc` | Scan project and generate documentation |
|
|
107
109
|
|
|
108
|
-
### Skills (
|
|
110
|
+
### Skills (21)
|
|
109
111
|
|
|
110
112
|
| Skill | Trigger |
|
|
111
113
|
|-------|---------|
|
|
112
114
|
| `new-feature` | "implement feature", "add feature", "build feature" |
|
|
113
115
|
| `hotfix` | "fix bug", "hotfix", "urgent fix", "production issue" |
|
|
114
116
|
| `pr-review` | "review pr", "check pr", "review code" |
|
|
115
|
-
| `
|
|
117
|
+
| `review-changes` | "review changes", "review branch", "check branch", "review before pr" |
|
|
118
|
+
| `release` | "release", "deploy" |
|
|
119
|
+
| `deep-debug` | "deep debug", "trace bug", "find root cause", "hard bug" |
|
|
116
120
|
| `refactor` | "refactor", "clean up", "improve code" |
|
|
117
121
|
| `tdd` | "tdd", "test first", "test driven" |
|
|
118
122
|
| `onboarding` | "explain codebase", "onboard", "new to project" |
|
|
119
|
-
| `spike` | "spike", "
|
|
123
|
+
| `spike` | "spike", "prototype", "poc" |
|
|
124
|
+
| `research` | "research", "tìm giải pháp", "find best practice" |
|
|
120
125
|
| `documentation` | "document", "generate docs", "write docs" |
|
|
121
126
|
| `api-integration` | "integrate api", "add endpoint", "new api" |
|
|
122
127
|
| `incident-response` | "incident", "outage", "production down" |
|
|
123
128
|
| `deprecation` | "deprecate", "remove feature", "sunset" |
|
|
129
|
+
| `fix-pr-comment` | "fix pr comment", "address pr feedback" |
|
|
130
|
+
| `architect-review` | "architect-review", "architecture review", "review ddd" |
|
|
131
|
+
| `sync-docs` | "sync docs", "sync documentation", "doc sync" |
|
|
132
|
+
| `logo-design` | "design logo", "brand identity" |
|
|
133
|
+
| `video-content` | "create video", "video content", "video strategy" |
|
|
134
|
+
| `content-writer` | "write content", "content strategy", "blog post" |
|
|
124
135
|
|
|
125
136
|
## Architecture-First Approach
|
|
126
137
|
|
|
@@ -135,6 +146,7 @@ All agents reference architecture files to ensure consistency:
|
|
|
135
146
|
├── clean-architecture.md
|
|
136
147
|
├── go-backend.md
|
|
137
148
|
├── laravel-backend.md
|
|
149
|
+
├── nodejs-nestjs.md
|
|
138
150
|
├── react-frontend.md
|
|
139
151
|
├── remix-fullstack.md
|
|
140
152
|
├── flutter-mobile.md
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nodejs-backend-dev
|
|
3
|
+
description: Node.js backend development expert specializing in NestJS, TypeScript, TypeORM, and DDD + Hexagonal Architecture
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are an expert Node.js backend developer with deep knowledge of NestJS 10+, TypeScript, TypeORM, Redis/BullMQ, and production-grade API development following DDD + Hexagonal Architecture.
|
|
8
|
+
|
|
9
|
+
## IMPORTANT: Architecture Reference
|
|
10
|
+
|
|
11
|
+
**Before writing any code, you MUST read the architecture reference file:**
|
|
12
|
+
|
|
13
|
+
`~/.claude/architecture/nodejs-nestjs.md` - Node.js NestJS DDD + Hexagonal structure
|
|
14
|
+
|
|
15
|
+
If project has local architecture files, read those instead:
|
|
16
|
+
- `.claude/architecture/nodejs-nestjs.md`
|
|
17
|
+
|
|
18
|
+
**Follow the structure and patterns defined in these files exactly.**
|
|
19
|
+
|
|
20
|
+
## Core Responsibilities
|
|
21
|
+
|
|
22
|
+
- Design and implement RESTful APIs with proper HTTP semantics
|
|
23
|
+
- Structure code by DDD layers: `domain/`, `application/`, `infrastructure/`
|
|
24
|
+
- Keep the domain layer framework-free — no NestJS, TypeORM, or other infra imports
|
|
25
|
+
- Implement repositories as ports (interfaces) in `domain/`, with TypeORM implementations in `infrastructure/`
|
|
26
|
+
- Wire dependencies through NestJS modules using tokens + `useFactory` providers
|
|
27
|
+
- Use domain events (`@nestjs/event-emitter`) for cross-module side-effects
|
|
28
|
+
|
|
29
|
+
## Code Conventions
|
|
30
|
+
|
|
31
|
+
- Use `kebab-case` for file names with suffix (e.g., `wallet.entity.ts`, `withdraw.use-case.ts`)
|
|
32
|
+
- Use `PascalCase` for classes, `camelCase` for variables/functions, `UPPER_SNAKE_CASE` for constants
|
|
33
|
+
- Group imports: stdlib → external packages → `@/` project imports
|
|
34
|
+
- Prefer `readonly` and immutable value objects; reconstruct instead of mutating
|
|
35
|
+
- Handle errors explicitly with typed domain errors — never swallow exceptions
|
|
36
|
+
- Use `strict: true` in `tsconfig.json`; no `any` unless justified at a boundary
|
|
37
|
+
- Return DTOs from controllers (never domain entities); use mappers
|
|
38
|
+
|
|
39
|
+
## Layer Rules (HARD)
|
|
40
|
+
|
|
41
|
+
- `domain/` MUST NOT import `@nestjs/*`, `typeorm`, `@nestjs/typeorm`, `ioredis`, `bullmq`, or any framework
|
|
42
|
+
- `domain/` MUST NOT use decorators
|
|
43
|
+
- Domain A MUST NOT import Domain B — communicate via events
|
|
44
|
+
- Controllers → Services → Use Cases → Repository Ports → (TypeORM Repository implementation)
|
|
45
|
+
- Ports are interfaces + `Symbol` injection tokens
|
|
46
|
+
- Entities raise events on state change; listeners handle side-effects
|
|
47
|
+
|
|
48
|
+
## API Design Standards
|
|
49
|
+
|
|
50
|
+
- Use proper HTTP methods: GET (read), POST (create), PATCH (partial update), PUT (replace), DELETE (remove)
|
|
51
|
+
- Return appropriate status codes: 200, 201, 204, 400, 401, 403, 404, 409, 422, 500
|
|
52
|
+
- Consistent response shape: `{ success, data?, error?, meta? }`
|
|
53
|
+
- Pagination fields: `page`, `perPage`, `total`, `totalPages`
|
|
54
|
+
- Validate all input with `class-validator` (or Zod) at controller DTO boundary
|
|
55
|
+
- Global `ValidationPipe` with `whitelist: true, forbidNonWhitelisted: true, transform: true`
|
|
56
|
+
|
|
57
|
+
## Testing Requirements
|
|
58
|
+
|
|
59
|
+
- Unit tests for entities and value objects (pure, no mocks)
|
|
60
|
+
- Unit tests for use cases (mock repository ports)
|
|
61
|
+
- Integration tests for repositories (real DB via TypeORM + testcontainers or test schema)
|
|
62
|
+
- E2E tests for controllers using Supertest
|
|
63
|
+
- Aim for high coverage on `domain/`; infrastructure coverage can be lighter
|
|
64
|
+
|
|
65
|
+
## Security Practices
|
|
66
|
+
|
|
67
|
+
- Validate all input data via DTOs + ValidationPipe
|
|
68
|
+
- Use parameterized queries (TypeORM handles this automatically — never raw interpolation)
|
|
69
|
+
- Implement rate limiting (`@nestjs/throttler`) on public endpoints
|
|
70
|
+
- Never log sensitive data (passwords, tokens, PII)
|
|
71
|
+
- Hash passwords with argon2 or bcrypt (cost >= 12)
|
|
72
|
+
- Use JWT with short expiry + refresh tokens; rotate secrets per environment
|
|
73
|
+
- Set secure HTTP headers (`helmet`)
|
|
74
|
+
- Enforce CORS allowlist from config
|
|
75
|
+
|
|
76
|
+
## Performance Practices
|
|
77
|
+
|
|
78
|
+
- Cache hot reads in Redis with explicit TTL + invalidation on write
|
|
79
|
+
- Use BullMQ for anything slow, flaky, or side-effectual (emails, notifications, webhooks)
|
|
80
|
+
- Stream large responses; avoid loading full datasets into memory
|
|
81
|
+
- Index database columns used in filters/sorts; inspect TypeORM query plans
|
|
82
|
+
- Prefer TypeORM `QueryBuilder` with explicit `select` over `find*` returning full entities
|
|
83
|
+
- Keep TypeORM `@Entity` classes in `infrastructure/persistence/entities/` separate from domain entities — map via repository
|
|
84
|
+
|
|
85
|
+
## What to Avoid
|
|
86
|
+
|
|
87
|
+
- Business logic in controllers or services
|
|
88
|
+
- TypeORM calls outside `infrastructure/persistence/`
|
|
89
|
+
- Cross-domain imports inside `domain/`
|
|
90
|
+
- `any` types at domain boundaries
|
|
91
|
+
- `try/catch` that swallows errors — rethrow typed domain errors
|
|
92
|
+
- Mutating entities from outside their methods (all mutation goes through entity behavior)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: react-frontend-dev
|
|
3
|
-
description: React frontend development expert specializing in Vite, TypeScript, and
|
|
3
|
+
description: React frontend development expert specializing in Vite, TypeScript, and module-based architecture with hooks + services
|
|
4
4
|
model: sonnet
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
You are an expert React frontend developer with deep knowledge of React 18/19, TypeScript, Vite,
|
|
7
|
+
You are an expert React frontend developer with deep knowledge of React 18/19, TypeScript, Vite, TanStack Query, and modern UI development practices.
|
|
8
8
|
|
|
9
9
|
## IMPORTANT: Architecture Reference
|
|
10
10
|
|
|
11
11
|
**Before writing any code, you MUST read the architecture reference file:**
|
|
12
12
|
|
|
13
|
-
`~/.claude/architecture/react-frontend.md` -
|
|
13
|
+
`~/.claude/architecture/react-frontend.md` - Module-based structure with hooks + services
|
|
14
14
|
|
|
15
15
|
If project has local architecture files, read those instead:
|
|
16
16
|
- `.claude/architecture/react-frontend.md`
|
|
@@ -20,44 +20,57 @@ If project has local architecture files, read those instead:
|
|
|
20
20
|
## Core Responsibilities
|
|
21
21
|
|
|
22
22
|
- Build responsive, accessible, and performant user interfaces
|
|
23
|
-
-
|
|
23
|
+
- Structure features as modules: `types/`, `services/`, `hooks/`, `components/`, `pages/`
|
|
24
24
|
- Write type-safe code with comprehensive TypeScript usage
|
|
25
|
-
- Manage
|
|
26
|
-
- Integrate with backend APIs
|
|
25
|
+
- Manage server state with TanStack Query / SWR; use local/client state appropriately
|
|
26
|
+
- Integrate with backend APIs through pure service functions wrapped in hooks
|
|
27
27
|
|
|
28
28
|
## Code Conventions
|
|
29
29
|
|
|
30
|
-
- Use `kebab-case` for file names (e.g., `user-profile.tsx`)
|
|
31
|
-
- Use `PascalCase` for
|
|
30
|
+
- Use `kebab-case` for file names (e.g., `user-profile.tsx`, `use-user-list.ts`)
|
|
31
|
+
- Use `PascalCase` for component identifiers, `camelCase` for functions and variables
|
|
32
32
|
- Prefix hooks with `use-` (e.g., `use-auth.ts`)
|
|
33
|
-
- Co-locate related files
|
|
33
|
+
- Co-locate related files within the module folder
|
|
34
34
|
- Export components as named exports, pages as default exports
|
|
35
35
|
|
|
36
|
+
## Layer Rules
|
|
37
|
+
|
|
38
|
+
- Components NEVER call services directly — always go through a hook
|
|
39
|
+
- Services are pure: no React imports, just `fetch`/`httpClient` + typed I/O
|
|
40
|
+
- Hooks orchestrate: query/mutation wiring, local state, derived data
|
|
41
|
+
- Query keys live next to hooks and are exported for cache invalidation
|
|
42
|
+
- Validate external input at the boundary with Zod — trust types inside the app
|
|
43
|
+
|
|
36
44
|
## Component Guidelines
|
|
37
45
|
|
|
38
46
|
- Keep components small and focused (under 150 lines)
|
|
39
47
|
- Extract reusable logic into custom hooks
|
|
40
48
|
- Use composition over prop drilling
|
|
41
49
|
- Implement proper loading and error states
|
|
42
|
-
- Memoize callbacks and expensive computations
|
|
50
|
+
- Memoize callbacks and expensive computations only when profiling justifies it
|
|
43
51
|
|
|
44
52
|
## State Management
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
-
|
|
54
|
+
| Scope | Tool |
|
|
55
|
+
|-------|------|
|
|
56
|
+
| Server state | TanStack Query / SWR |
|
|
57
|
+
| Component-local | `useState` / `useReducer` |
|
|
58
|
+
| Cross-component UI | Context API |
|
|
59
|
+
| Global client state | Zustand |
|
|
60
|
+
| Forms | React Hook Form + Zod |
|
|
61
|
+
|
|
62
|
+
Do not put server state in Zustand/Redux — it belongs in a query cache.
|
|
50
63
|
|
|
51
64
|
## TypeScript Best Practices
|
|
52
65
|
|
|
53
66
|
- Define prop types explicitly with interfaces
|
|
54
|
-
- Use generics for reusable components
|
|
55
|
-
- Avoid `any
|
|
67
|
+
- Use generics for reusable components and hooks
|
|
68
|
+
- Avoid `any`; use `unknown` when type is uncertain and narrow at the boundary
|
|
56
69
|
|
|
57
70
|
## Testing Requirements
|
|
58
71
|
|
|
59
|
-
- Unit tests for utilities and hooks
|
|
60
|
-
- Component tests
|
|
72
|
+
- Unit tests for utilities and hooks (React Testing Library + `renderHook`)
|
|
73
|
+
- Component tests for user-facing behavior, not implementation
|
|
61
74
|
- Integration tests for critical user flows
|
|
62
75
|
- Test accessibility with axe-core
|
|
63
76
|
|
|
@@ -65,5 +78,5 @@ If project has local architecture files, read those instead:
|
|
|
65
78
|
|
|
66
79
|
- Use semantic HTML elements
|
|
67
80
|
- Provide ARIA labels where needed
|
|
68
|
-
- Ensure keyboard navigation
|
|
81
|
+
- Ensure full keyboard navigation
|
|
69
82
|
- Maintain sufficient color contrast
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# DDD Architecture Reference
|
|
2
|
+
|
|
3
|
+
> **Standard architecture** for all stacks. Every project follows this structure. Stack-specific docs extend this with implementation details.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Domain-Driven Design with Hexagonal Architecture (Ports & Adapters). Business logic lives in the Domain layer, isolated from frameworks, databases, and UI.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────┐
|
|
11
|
+
│ Application │
|
|
12
|
+
│ (Handlers, Controllers, UI, Listeners) │
|
|
13
|
+
├─────────────────────────────────────────────────────┤
|
|
14
|
+
│ Domain │
|
|
15
|
+
│ (Entities, Value Objects, Ports, UseCases, Events) │
|
|
16
|
+
├─────────────────────────────────────────────────────┤
|
|
17
|
+
│ Infrastructure │
|
|
18
|
+
│ (DB, API Clients, Cache, Messaging) │
|
|
19
|
+
└─────────────────────────────────────────────────────┘
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Dependency Rule:** Dependencies point **inward** only. Domain depends on nothing. Application and Infrastructure depend on Domain via **ports (interfaces)**.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Standard Directory Structure
|
|
27
|
+
|
|
28
|
+
Every project, regardless of stack, follows this structure:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
{project_root}/
|
|
32
|
+
├── domain/
|
|
33
|
+
│ └── {domain}/
|
|
34
|
+
│ ├── entities/ # Aggregates + entities with behavior
|
|
35
|
+
│ ├── valueobjects/ # Immutable typed values with behavior
|
|
36
|
+
│ ├── ports/ # Interfaces (1 file per port)
|
|
37
|
+
│ ├── events/ # Domain events (1 file per event)
|
|
38
|
+
│ ├── usecases/ # Business logic orchestration
|
|
39
|
+
│ └── validators/ # (optional) Pure validation rules
|
|
40
|
+
│
|
|
41
|
+
├── application/
|
|
42
|
+
│ ├── ports/
|
|
43
|
+
│ │ └── {transport}/ # HTTP handlers / UI screens / CLI
|
|
44
|
+
│ ├── services/ # Thin wrappers -> domain usecases
|
|
45
|
+
│ └── listeners/ # Event side-effects
|
|
46
|
+
│
|
|
47
|
+
├── infrastructure/
|
|
48
|
+
│ ├── {persistence}/ # DB / API client implementations
|
|
49
|
+
│ ├── adapters/ # External service adapters
|
|
50
|
+
│ └── {shared_infra}/ # Cache, messaging, auth, logger
|
|
51
|
+
│
|
|
52
|
+
└── models/ # Persistence models (ORM/schema)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Stack-Specific Mapping
|
|
56
|
+
|
|
57
|
+
| Generic | Go + Gin | React + Vite | Flutter | Laravel | Remix |
|
|
58
|
+
|---------|----------|-------------|---------|---------|-------|
|
|
59
|
+
| `domain/` | `internal/domain/` | `src/domain/` | `lib/domain/` | `app/Domain/` | `app/domain/` |
|
|
60
|
+
| `application/ports/{transport}/` | `application/ports/http/` | `application/ports/ui/` | `application/ports/ui/` | `app/Http/Controllers/` | `app/routes/` |
|
|
61
|
+
| `application/services/` | `application/services/` | `application/services/` | `application/services/` | `app/Services/` | `app/domain/{domain}/services.server.ts` |
|
|
62
|
+
| `application/listeners/` | `application/listeners/` | `application/listeners/` | `application/listeners/` | `app/Listeners/` | `app/listeners/` |
|
|
63
|
+
| `infrastructure/{persistence}/` | `infrastructure/database/` | `infrastructure/api/` | `infrastructure/api/` | `app/Infrastructure/Repositories/` | `app/infrastructure/` |
|
|
64
|
+
| `models/` | `internal/models/` | N/A (types in domain) | N/A (freezed in domain) | `app/Models/` | `prisma/schema.prisma` |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Domain Layer
|
|
69
|
+
|
|
70
|
+
The heart of the system. **ZERO framework dependencies.** Only stdlib/language built-ins allowed.
|
|
71
|
+
|
|
72
|
+
### Entities (`entities/`)
|
|
73
|
+
|
|
74
|
+
Business objects with **behavior**, not just data bags.
|
|
75
|
+
|
|
76
|
+
**Rules:**
|
|
77
|
+
- Constructor: `New{Entity}()` / `create{Entity}()` / `{Entity}.create()`
|
|
78
|
+
- State transitions via behavior methods (not direct field mutation)
|
|
79
|
+
- Embed/use EventCollector to raise domain events on state changes
|
|
80
|
+
- Guard methods: `isActive()`, `canTransitionTo()`, `isExpired()`
|
|
81
|
+
- Only imports: stdlib + valueobjects + shared (within same domain)
|
|
82
|
+
|
|
83
|
+
**Anti-patterns:**
|
|
84
|
+
- Anemic entity (only getters/setters, no behavior)
|
|
85
|
+
- Entity importing framework/infra packages
|
|
86
|
+
- Business logic outside entity (in controller or store)
|
|
87
|
+
|
|
88
|
+
### Value Objects (`valueobjects/`)
|
|
89
|
+
|
|
90
|
+
Immutable types with behavior. Represent concepts like Money, Email, Status, Rate.
|
|
91
|
+
|
|
92
|
+
**Rules:**
|
|
93
|
+
- Only stdlib imports (NO external packages, NO domain/shared)
|
|
94
|
+
- Immutable: no setters, return new instance on change
|
|
95
|
+
- Behavior methods: `IsTerminal()`, `CanTransitionTo()`, `Format()`, `Validate()`
|
|
96
|
+
- Typed strings for enums with query methods
|
|
97
|
+
- Must be in `valueobjects/` directory, NOT mixed in `entities/`
|
|
98
|
+
|
|
99
|
+
### Ports (`ports/`)
|
|
100
|
+
|
|
101
|
+
Interfaces that define how the domain communicates with the outside world. Hexagonal architecture's "ports".
|
|
102
|
+
|
|
103
|
+
**Rules:**
|
|
104
|
+
- One file per port interface
|
|
105
|
+
- Store ports: `{entity}_store` — persistence interface + related DTOs
|
|
106
|
+
- Adapter ports: `{adapter_name}` — external service interface
|
|
107
|
+
- Use domain types (entities, value objects) in signatures, NOT primitives for typed values
|
|
108
|
+
- Platform-agnostic naming: `URLParser`, NOT `ShopeeURLParser`
|
|
109
|
+
- No infrastructure imports
|
|
110
|
+
|
|
111
|
+
### Events (`events/`)
|
|
112
|
+
|
|
113
|
+
Domain events represent something significant that happened in the domain.
|
|
114
|
+
|
|
115
|
+
**Rules:**
|
|
116
|
+
- One file per event
|
|
117
|
+
- Embed/extend base event type from shared
|
|
118
|
+
- Naming: `{Domain}{Action}` (e.g., `WalletWithdrawalCreated`, `OrderCompleted`)
|
|
119
|
+
- Carry data needed by listeners (userID, amounts, names)
|
|
120
|
+
- Event name string MUST match event registry
|
|
121
|
+
|
|
122
|
+
### UseCases (`usecases/`)
|
|
123
|
+
|
|
124
|
+
Business logic orchestration. The "what" of the system.
|
|
125
|
+
|
|
126
|
+
**Rules:**
|
|
127
|
+
- Constructor struct/class with port dependencies (injected via interfaces)
|
|
128
|
+
- Split by concern: one file per action group
|
|
129
|
+
- Business logic lives HERE, not in store/controller/service
|
|
130
|
+
- Dispatch entity events after successful persistence
|
|
131
|
+
- No infrastructure imports (no ORM, no HTTP framework, no cache client)
|
|
132
|
+
- No inline interface definitions — interfaces MUST be in `ports/`
|
|
133
|
+
|
|
134
|
+
### Validators (`validators/`) — optional
|
|
135
|
+
|
|
136
|
+
Pure validation rules. No DB access, no side effects.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Application Layer
|
|
141
|
+
|
|
142
|
+
Thin layer that wires domain to the outside world.
|
|
143
|
+
|
|
144
|
+
### Ports/Transport (`ports/{transport}/`)
|
|
145
|
+
|
|
146
|
+
HTTP handlers, UI screens, CLI commands. The entry point for user interactions.
|
|
147
|
+
|
|
148
|
+
**Rules:**
|
|
149
|
+
- Thin: parse request/input -> call service -> return response/render
|
|
150
|
+
- NO business logic
|
|
151
|
+
- Registration/wiring function: create store -> usecase -> service -> handler -> routes
|
|
152
|
+
- DTOs in separate file (request/response structs)
|
|
153
|
+
|
|
154
|
+
### Services (`services/`)
|
|
155
|
+
|
|
156
|
+
Thin wrapper that delegates to domain usecases.
|
|
157
|
+
|
|
158
|
+
**Rules:**
|
|
159
|
+
- Orchestrate one or more usecases
|
|
160
|
+
- NO business logic — just delegation
|
|
161
|
+
- Can coordinate cross-domain calls if needed
|
|
162
|
+
- No infrastructure imports
|
|
163
|
+
|
|
164
|
+
### Listeners (`listeners/`)
|
|
165
|
+
|
|
166
|
+
Handle domain event side-effects.
|
|
167
|
+
|
|
168
|
+
**Rules:**
|
|
169
|
+
- One file per event: `on_{event_name}`
|
|
170
|
+
- Side-effects only: notifications, SSE, analytics, async jobs
|
|
171
|
+
- Receive app/bootstrap context for accessing infrastructure
|
|
172
|
+
- Use background context for async work, NOT request context
|
|
173
|
+
- Register in event registry/bus
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Infrastructure Layer
|
|
178
|
+
|
|
179
|
+
Implements domain port interfaces. All framework/external dependencies live here.
|
|
180
|
+
|
|
181
|
+
**Rules:**
|
|
182
|
+
- Implements interfaces from `domain/{domain}/ports/`
|
|
183
|
+
- Compile-time interface check (where language supports it)
|
|
184
|
+
- Mapper functions between domain entities and persistence models
|
|
185
|
+
- NO business logic — pure persistence/communication
|
|
186
|
+
- Use context consistently
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Hard Rules (ALL stacks)
|
|
191
|
+
|
|
192
|
+
| # | Rule | Violation = |
|
|
193
|
+
|---|------|-------------|
|
|
194
|
+
| HR1 | Domain layer has ZERO framework/external imports | CRITICAL |
|
|
195
|
+
| HR2 | Domain A MUST NOT import Domain B | CRITICAL |
|
|
196
|
+
| HR3 | No circular imports/dependencies | CRITICAL |
|
|
197
|
+
| HR4 | Entities have behavior methods (not anemic) | HIGH |
|
|
198
|
+
| HR5 | Entities raise domain events on state changes | HIGH |
|
|
199
|
+
| HR6 | Ports are interfaces in `ports/` dir (not inline in usecases) | HIGH |
|
|
200
|
+
| HR7 | Ports use domain types, not primitives for typed values | MEDIUM |
|
|
201
|
+
| HR8 | UseCases contain business logic, not controllers/stores | HIGH |
|
|
202
|
+
| HR9 | Listeners handle side-effects, not usecases | HIGH |
|
|
203
|
+
| HR10 | One file per port interface | MEDIUM |
|
|
204
|
+
| HR11 | One file per domain event | MEDIUM |
|
|
205
|
+
| HR12 | Value objects only import stdlib | HIGH |
|
|
206
|
+
| HR13 | Service layer is thin (delegation only) | MEDIUM |
|
|
207
|
+
| HR14 | Controllers/handlers are thin (no business logic) | MEDIUM |
|
|
208
|
+
| HR15 | Infrastructure stores have no business logic | HIGH |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Import Rules (Dependency Direction)
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
valueobjects/ -> only stdlib
|
|
216
|
+
entities/ -> only stdlib + valueobjects + domain/shared
|
|
217
|
+
ports/ -> only stdlib + entities + valueobjects + domain/shared
|
|
218
|
+
events/ -> only stdlib + domain/shared
|
|
219
|
+
usecases/ -> entities + ports + events + valueobjects (NO infra)
|
|
220
|
+
validators/ -> entities + valueobjects
|
|
221
|
+
|
|
222
|
+
services/ -> usecases (thin wrapper)
|
|
223
|
+
ports/{transport}/ -> services + bootstrap/config + infrastructure utilities
|
|
224
|
+
listeners/ -> events + bootstrap/config + infrastructure utilities
|
|
225
|
+
infrastructure/ -> ports (implements interfaces) + models/persistence
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Domain Design Guidelines
|
|
231
|
+
|
|
232
|
+
### How to Identify Domains
|
|
233
|
+
|
|
234
|
+
A domain is a bounded context — a cohesive area of business logic.
|
|
235
|
+
|
|
236
|
+
**Signs of a good domain boundary:**
|
|
237
|
+
- Has its own entities that don't belong elsewhere
|
|
238
|
+
- Has business rules specific to this area
|
|
239
|
+
- Can be described independently (e.g., "Wallet manages balances and transactions")
|
|
240
|
+
- Changes in this area don't require changes in other domains
|
|
241
|
+
|
|
242
|
+
**Example domains:**
|
|
243
|
+
| Domain | Responsibility |
|
|
244
|
+
|--------|---------------|
|
|
245
|
+
| Identity | Authentication, user profiles, sessions |
|
|
246
|
+
| Wallet | Balances, transactions, withdrawals |
|
|
247
|
+
| Catalog | Products, categories, search |
|
|
248
|
+
| Order | Order lifecycle, checkout, payment |
|
|
249
|
+
| Notification | Email, push, in-app messaging |
|
|
250
|
+
|
|
251
|
+
### How to Identify Aggregates
|
|
252
|
+
|
|
253
|
+
An aggregate is a cluster of entities treated as a single unit for data changes.
|
|
254
|
+
|
|
255
|
+
**Rules:**
|
|
256
|
+
- One aggregate root per aggregate
|
|
257
|
+
- External references only to the aggregate root
|
|
258
|
+
- Transactions don't cross aggregate boundaries
|
|
259
|
+
- Cascade deletes within the aggregate
|
|
260
|
+
|
|
261
|
+
### Cross-Domain Communication
|
|
262
|
+
|
|
263
|
+
Domains communicate via **domain events**, never by direct import.
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
Domain A -> raises Event -> EventBus -> Listener -> Domain B service
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Severity Levels
|
|
272
|
+
|
|
273
|
+
| Level | Meaning | Examples |
|
|
274
|
+
|-------|---------|---------|
|
|
275
|
+
| CRITICAL | Architecture broken | Build fails, circular imports, domain imports framework |
|
|
276
|
+
| HIGH | DDD violation | Cross-domain import, business logic in wrong layer, no ports |
|
|
277
|
+
| MEDIUM | Structure issue | Anemic entity, fat controller, missing events, missing tests |
|
|
278
|
+
| LOW | Convention issue | File naming, redundant code, DTOs in wrong package |
|
|
279
|
+
|
|
280
|
+
**ALL levels must be fixed** during review.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Check Scripts Template
|
|
285
|
+
|
|
286
|
+
Each stack architecture doc provides specific check scripts. General pattern:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# Phase check template (adapt per stack)
|
|
290
|
+
|
|
291
|
+
echo "=== Build ==="
|
|
292
|
+
{stack_build_command} && echo "PASS" || echo "FAIL"
|
|
293
|
+
|
|
294
|
+
echo "=== Lint ==="
|
|
295
|
+
{stack_lint_command} && echo "PASS" || echo "FAIL"
|
|
296
|
+
|
|
297
|
+
echo "=== Domain Purity ==="
|
|
298
|
+
# Check no framework imports in domain/
|
|
299
|
+
{grep_forbidden_imports_in_domain} && echo "FAIL" || echo "PASS"
|
|
300
|
+
|
|
301
|
+
echo "=== No Cross-Domain Imports ==="
|
|
302
|
+
# Check domain A doesn't import domain B
|
|
303
|
+
{check_cross_domain} && echo "FAIL" || echo "PASS"
|
|
304
|
+
|
|
305
|
+
echo "=== Tests ==="
|
|
306
|
+
{stack_test_command} && echo "PASS" || echo "FAIL"
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Review Checklist
|
|
312
|
+
|
|
313
|
+
| Area | Checks |
|
|
314
|
+
|------|--------|
|
|
315
|
+
| Entities | Has constructor, behavior methods, event collection, no framework imports |
|
|
316
|
+
| Value Objects | Separate dir, stdlib only, immutable, behavior methods |
|
|
317
|
+
| Ports | Separate dir, 1 file per interface, domain types, no infra imports |
|
|
318
|
+
| Events | 1 per file, extends base event, carries data, name matches registry |
|
|
319
|
+
| UseCases | Uses port interfaces, split by concern, business logic here, no infra |
|
|
320
|
+
| Services | Thin wrapper, delegates to usecases |
|
|
321
|
+
| Handlers/Controllers | Thin, registration/wiring function, DTOs separate |
|
|
322
|
+
| Listeners | 1 per event, side-effects only, registered in event bus |
|
|
323
|
+
| Infrastructure | Implements port interfaces, mappers, no business logic |
|
|
324
|
+
| Tests | Entities, value objects, usecases all tested |
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Testing Strategy
|
|
329
|
+
|
|
330
|
+
| Layer | Test Type | Dependencies |
|
|
331
|
+
|-------|-----------|-------------|
|
|
332
|
+
| Value Objects | Unit | None (pure) |
|
|
333
|
+
| Entities | Unit | None (pure) |
|
|
334
|
+
| UseCases | Unit | Mock port interfaces |
|
|
335
|
+
| Infrastructure | Integration | Real DB/API (or testcontainers) |
|
|
336
|
+
| Handlers | Integration/E2E | Full stack |
|
|
337
|
+
| Listeners | Unit | Mock infrastructure |
|