@aicgen/aicgen 1.0.0-beta.1
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/.claude/agents/architecture-reviewer.md +88 -0
- package/.claude/agents/guideline-checker.md +73 -0
- package/.claude/agents/security-auditor.md +108 -0
- package/.claude/guidelines/api-design.md +645 -0
- package/.claude/guidelines/architecture.md +2503 -0
- package/.claude/guidelines/best-practices.md +618 -0
- package/.claude/guidelines/code-style.md +304 -0
- package/.claude/guidelines/design-patterns.md +573 -0
- package/.claude/guidelines/devops.md +226 -0
- package/.claude/guidelines/error-handling.md +413 -0
- package/.claude/guidelines/language.md +782 -0
- package/.claude/guidelines/performance.md +706 -0
- package/.claude/guidelines/security.md +583 -0
- package/.claude/guidelines/testing.md +568 -0
- package/.claude/settings.json +98 -0
- package/.claude/settings.local.json +8 -0
- package/.env.example +23 -0
- package/.eslintrc.json +28 -0
- package/.github/workflows/release.yml +180 -0
- package/.github/workflows/test.yml +81 -0
- package/.gitmodules +3 -0
- package/.vs/ProjectSettings.json +3 -0
- package/.vs/VSWorkspaceState.json +16 -0
- package/.vs/aicgen.slnx/FileContentIndex/5f0ce2a3-fd68-4863-9e23-e428cf1794e3.vsidx +0 -0
- package/.vs/aicgen.slnx/v18/.wsuo +0 -0
- package/.vs/aicgen.slnx/v18/DocumentLayout.json +54 -0
- package/.vs/slnx.sqlite +0 -0
- package/AGENTS.md +121 -0
- package/CLAUDE.md +36 -0
- package/CONTRIBUTING.md +821 -0
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/assets/icon.svg +34 -0
- package/assets/logo.svg +41 -0
- package/bun.lock +848 -0
- package/data/LICENSE +21 -0
- package/data/README.md +203 -0
- package/data/api/basics.md +292 -0
- package/data/api/index.md +8 -0
- package/data/api/pagination.md +142 -0
- package/data/api/rest.md +137 -0
- package/data/api/versioning.md +60 -0
- package/data/architecture/clean-architecture/index.md +7 -0
- package/data/architecture/clean-architecture/layers.md +111 -0
- package/data/architecture/ddd/index.md +8 -0
- package/data/architecture/ddd/strategic.md +89 -0
- package/data/architecture/ddd/tactical.md +132 -0
- package/data/architecture/event-driven/index.md +7 -0
- package/data/architecture/event-driven/messaging.md +242 -0
- package/data/architecture/event-driven/patterns.md +129 -0
- package/data/architecture/feature-toggles/index.md +7 -0
- package/data/architecture/feature-toggles/patterns.md +73 -0
- package/data/architecture/gui/index.md +7 -0
- package/data/architecture/gui/patterns.md +132 -0
- package/data/architecture/hexagonal/ports-adapters.md +132 -0
- package/data/architecture/index.md +12 -0
- package/data/architecture/layered/index.md +7 -0
- package/data/architecture/layered/layers.md +100 -0
- package/data/architecture/microservices/api-gateway.md +56 -0
- package/data/architecture/microservices/boundaries.md +80 -0
- package/data/architecture/microservices/communication.md +97 -0
- package/data/architecture/microservices/data.md +92 -0
- package/data/architecture/microservices/index.md +11 -0
- package/data/architecture/microservices/resilience.md +111 -0
- package/data/architecture/modular-monolith/boundaries.md +133 -0
- package/data/architecture/modular-monolith/structure.md +131 -0
- package/data/architecture/serverless/best-practices.md +322 -0
- package/data/architecture/serverless/index.md +7 -0
- package/data/architecture/serverless/patterns.md +80 -0
- package/data/architecture/solid/index.md +7 -0
- package/data/architecture/solid/principles.md +187 -0
- package/data/database/basics.md +365 -0
- package/data/database/design-patterns.md +68 -0
- package/data/database/index.md +8 -0
- package/data/database/indexing.md +136 -0
- package/data/database/nosql.md +223 -0
- package/data/database/schema.md +137 -0
- package/data/devops/ci-cd.md +66 -0
- package/data/devops/index.md +8 -0
- package/data/devops/observability.md +73 -0
- package/data/devops/practices.md +77 -0
- package/data/error-handling/basics.md +222 -0
- package/data/error-handling/index.md +7 -0
- package/data/error-handling/strategy.md +185 -0
- package/data/guideline-mappings.yml +1077 -0
- package/data/index.md +3 -0
- package/data/language/csharp/basics.md +210 -0
- package/data/language/csharp/testing.md +252 -0
- package/data/language/go/basics.md +158 -0
- package/data/language/go/testing.md +192 -0
- package/data/language/index.md +14 -0
- package/data/language/java/basics.md +184 -0
- package/data/language/java/testing.md +273 -0
- package/data/language/javascript/basics.md +217 -0
- package/data/language/javascript/testing.md +269 -0
- package/data/language/python/async.md +100 -0
- package/data/language/python/basics.md +100 -0
- package/data/language/python/index.md +10 -0
- package/data/language/python/testing.md +125 -0
- package/data/language/python/types.md +99 -0
- package/data/language/ruby/basics.md +227 -0
- package/data/language/ruby/testing.md +267 -0
- package/data/language/rust/basics.md +175 -0
- package/data/language/rust/testing.md +219 -0
- package/data/language/typescript/async.md +103 -0
- package/data/language/typescript/basics.md +87 -0
- package/data/language/typescript/config.md +95 -0
- package/data/language/typescript/error-handling.md +98 -0
- package/data/language/typescript/generics.md +85 -0
- package/data/language/typescript/index.md +14 -0
- package/data/language/typescript/interfaces-types.md +83 -0
- package/data/language/typescript/performance.md +103 -0
- package/data/language/typescript/testing.md +98 -0
- package/data/patterns/base-patterns.md +105 -0
- package/data/patterns/concurrency.md +87 -0
- package/data/patterns/data-access.md +83 -0
- package/data/patterns/distribution.md +86 -0
- package/data/patterns/domain-logic.md +81 -0
- package/data/patterns/gof.md +109 -0
- package/data/patterns/index.md +12 -0
- package/data/performance/async.md +148 -0
- package/data/performance/basics.md +324 -0
- package/data/performance/caching-strategies.md +68 -0
- package/data/performance/caching.md +152 -0
- package/data/performance/index.md +8 -0
- package/data/practices/code-review.md +52 -0
- package/data/practices/documentation.md +260 -0
- package/data/practices/index.md +11 -0
- package/data/practices/planning.md +142 -0
- package/data/practices/refactoring.md +91 -0
- package/data/practices/version-control.md +55 -0
- package/data/security/auth-jwt.md +159 -0
- package/data/security/headers.md +143 -0
- package/data/security/index.md +10 -0
- package/data/security/injection.md +119 -0
- package/data/security/secrets.md +148 -0
- package/data/style/index.md +8 -0
- package/data/style/naming.md +136 -0
- package/data/style/organization.md +162 -0
- package/data/templates/agents/architecture-reviewer.md +88 -0
- package/data/templates/agents/guideline-checker.md +73 -0
- package/data/templates/agents/security-auditor.md +108 -0
- package/data/templates/antigravity/rules/architecture.md.hbs +5 -0
- package/data/templates/antigravity/rules/code-style.md.hbs +5 -0
- package/data/templates/antigravity/rules/language.md.hbs +5 -0
- package/data/templates/antigravity/rules/performance.md.hbs +5 -0
- package/data/templates/antigravity/rules/security.md.hbs +5 -0
- package/data/templates/antigravity/rules/testing.md.hbs +5 -0
- package/data/templates/antigravity/workflows/add-documentation.md.hbs +23 -0
- package/data/templates/antigravity/workflows/generate-integration-tests.md.hbs +17 -0
- package/data/templates/antigravity/workflows/generate-unit-tests.md.hbs +20 -0
- package/data/templates/antigravity/workflows/performance-audit.md.hbs +24 -0
- package/data/templates/antigravity/workflows/refactor-extract-module.md.hbs +17 -0
- package/data/templates/antigravity/workflows/security-audit.md.hbs +20 -0
- package/data/templates/hooks/formatting.json +26 -0
- package/data/templates/hooks/security.json +35 -0
- package/data/templates/hooks/testing.json +17 -0
- package/data/testing/basics.md +151 -0
- package/data/testing/index.md +9 -0
- package/data/testing/integration.md +159 -0
- package/data/testing/unit-fundamentals.md +128 -0
- package/data/testing/unit-mocking.md +116 -0
- package/data/version.json +49 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +46 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/config/profiles.d.ts +4 -0
- package/dist/config/profiles.d.ts.map +1 -0
- package/dist/config/profiles.js +30 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/settings.d.ts +7 -0
- package/dist/config/settings.d.ts.map +1 -0
- package/dist/config/settings.js +7 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58489 -0
- package/dist/index.js.map +1 -0
- package/dist/models/guideline.d.ts +15 -0
- package/dist/models/guideline.d.ts.map +1 -0
- package/dist/models/guideline.js +2 -0
- package/dist/models/guideline.js.map +1 -0
- package/dist/models/preference.d.ts +9 -0
- package/dist/models/preference.d.ts.map +1 -0
- package/dist/models/preference.js +2 -0
- package/dist/models/preference.js.map +1 -0
- package/dist/models/profile.d.ts +9 -0
- package/dist/models/profile.d.ts.map +1 -0
- package/dist/models/profile.js +2 -0
- package/dist/models/profile.js.map +1 -0
- package/dist/models/project.d.ts +13 -0
- package/dist/models/project.d.ts.map +1 -0
- package/dist/models/project.js +2 -0
- package/dist/models/project.js.map +1 -0
- package/dist/services/ai/anthropic.d.ts +7 -0
- package/dist/services/ai/anthropic.d.ts.map +1 -0
- package/dist/services/ai/anthropic.js +39 -0
- package/dist/services/ai/anthropic.js.map +1 -0
- package/dist/services/generator.d.ts +2 -0
- package/dist/services/generator.d.ts.map +1 -0
- package/dist/services/generator.js +4 -0
- package/dist/services/generator.js.map +1 -0
- package/dist/services/learner.d.ts +2 -0
- package/dist/services/learner.d.ts.map +1 -0
- package/dist/services/learner.js +4 -0
- package/dist/services/learner.js.map +1 -0
- package/dist/services/scanner.d.ts +3 -0
- package/dist/services/scanner.d.ts.map +1 -0
- package/dist/services/scanner.js +54 -0
- package/dist/services/scanner.js.map +1 -0
- package/dist/utils/errors.d.ts +15 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +27 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/file.d.ts +7 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +32 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +17 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/path.d.ts +6 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +14 -0
- package/dist/utils/path.js.map +1 -0
- package/docs/planning/memory-lane.md +83 -0
- package/package.json +64 -0
- package/packaging/linux/aicgen.spec +23 -0
- package/packaging/linux/control +9 -0
- package/packaging/macos/scripts/postinstall +12 -0
- package/packaging/windows/setup.nsi +92 -0
- package/planning/BRANDING-SUMMARY.md +194 -0
- package/planning/BRANDING.md +174 -0
- package/planning/BUILD.md +186 -0
- package/planning/CHUNK-IMPLEMENTATION-PLAN.md +87 -0
- package/planning/CHUNK-TAXONOMY.md +375 -0
- package/planning/CHUNKS-COMPLETE.md +382 -0
- package/planning/DESIGN.md +313 -0
- package/planning/DYNAMIC-GUIDELINES-DESIGN.md +265 -0
- package/planning/ENTERPRISE-UX-COMPLETE.md +281 -0
- package/planning/IMPLEMENTATION-PLAN.md +20 -0
- package/planning/PHASE1-COMPLETE.md +211 -0
- package/planning/PHASE2-COMPLETE.md +350 -0
- package/planning/PHASE3-COMPLETE.md +399 -0
- package/planning/PHASE4-COMPLETE.md +361 -0
- package/planning/PHASE4.5-CHUNKS.md +462 -0
- package/planning/STRUCTURE.md +170 -0
- package/scripts/add-categories.ts +87 -0
- package/scripts/build-binary.ts +46 -0
- package/scripts/embed-data.ts +105 -0
- package/scripts/generate-version.ts +150 -0
- package/scripts/test-decompress.ts +27 -0
- package/scripts/test-extract.ts +31 -0
- package/src/__tests__/services/assistant-file-writer.test.ts +400 -0
- package/src/__tests__/services/guideline-loader.test.ts +281 -0
- package/src/__tests__/services/tarball-extraction.test.ts +125 -0
- package/src/commands/add-guideline.ts +296 -0
- package/src/commands/clear.ts +61 -0
- package/src/commands/guideline-selector.ts +123 -0
- package/src/commands/init.ts +645 -0
- package/src/commands/quick-add.ts +586 -0
- package/src/commands/remove-guideline.ts +152 -0
- package/src/commands/stats.ts +49 -0
- package/src/commands/update.ts +240 -0
- package/src/config.ts +82 -0
- package/src/embedded-data.ts +1492 -0
- package/src/index.ts +67 -0
- package/src/models/profile.ts +24 -0
- package/src/models/project.ts +43 -0
- package/src/services/assistant-file-writer.ts +612 -0
- package/src/services/config-generator.ts +150 -0
- package/src/services/config-manager.ts +70 -0
- package/src/services/data-source.ts +248 -0
- package/src/services/first-run-init.ts +148 -0
- package/src/services/guideline-loader.ts +311 -0
- package/src/services/hook-generator.ts +178 -0
- package/src/services/subagent-generator.ts +310 -0
- package/src/utils/banner.ts +66 -0
- package/src/utils/errors.ts +27 -0
- package/src/utils/file.ts +67 -0
- package/src/utils/formatting.ts +172 -0
- package/src/utils/logger.ts +89 -0
- package/src/utils/path.ts +17 -0
- package/src/utils/wizard-state.ts +132 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Hexagonal Architecture (Ports & Adapters)
|
|
2
|
+
|
|
3
|
+
## Core Principle
|
|
4
|
+
|
|
5
|
+
The application core (domain logic) is isolated from external concerns through ports (interfaces) and adapters (implementations).
|
|
6
|
+
|
|
7
|
+
## Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/
|
|
11
|
+
├── domain/ # Pure business logic, no external dependencies
|
|
12
|
+
│ ├── models/ # Domain entities and value objects
|
|
13
|
+
│ ├── services/ # Domain services
|
|
14
|
+
│ └── ports/ # Interface definitions (driven & driving)
|
|
15
|
+
├── application/ # Use cases, orchestration
|
|
16
|
+
│ └── services/ # Application services
|
|
17
|
+
├── adapters/
|
|
18
|
+
│ ├── primary/ # Driving adapters (controllers, CLI, events)
|
|
19
|
+
│ │ ├── http/
|
|
20
|
+
│ │ ├── grpc/
|
|
21
|
+
│ │ └── cli/
|
|
22
|
+
│ └── secondary/ # Driven adapters (repositories, clients)
|
|
23
|
+
│ ├── persistence/
|
|
24
|
+
│ ├── messaging/
|
|
25
|
+
│ └── external-apis/
|
|
26
|
+
└── config/ # Dependency injection, configuration
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Port Types
|
|
30
|
+
|
|
31
|
+
### Driving Ports (Primary)
|
|
32
|
+
Interfaces that the application exposes to the outside world:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// domain/ports/driving/user-service.port.ts
|
|
36
|
+
export interface UserServicePort {
|
|
37
|
+
createUser(data: CreateUserDTO): Promise<User>;
|
|
38
|
+
getUser(id: string): Promise<User | null>;
|
|
39
|
+
updateUser(id: string, data: UpdateUserDTO): Promise<User>;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Driven Ports (Secondary)
|
|
44
|
+
Interfaces that the application needs from the outside world:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// domain/ports/driven/user-repository.port.ts
|
|
48
|
+
export interface UserRepositoryPort {
|
|
49
|
+
save(user: User): Promise<void>;
|
|
50
|
+
findById(id: string): Promise<User | null>;
|
|
51
|
+
findByEmail(email: string): Promise<User | null>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// domain/ports/driven/email-sender.port.ts
|
|
55
|
+
export interface EmailSenderPort {
|
|
56
|
+
send(to: string, subject: string, body: string): Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Adapter Implementation
|
|
61
|
+
|
|
62
|
+
### Primary Adapter (HTTP Controller)
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// adapters/primary/http/user.controller.ts
|
|
66
|
+
export class UserController {
|
|
67
|
+
constructor(private userService: UserServicePort) {}
|
|
68
|
+
|
|
69
|
+
async create(req: Request, res: Response) {
|
|
70
|
+
const user = await this.userService.createUser(req.body);
|
|
71
|
+
res.status(201).json(user);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Secondary Adapter (Repository)
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// adapters/secondary/persistence/postgres-user.repository.ts
|
|
80
|
+
export class PostgresUserRepository implements UserRepositoryPort {
|
|
81
|
+
constructor(private db: DatabaseConnection) {}
|
|
82
|
+
|
|
83
|
+
async save(user: User): Promise<void> {
|
|
84
|
+
await this.db.query('INSERT INTO users...', user);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async findById(id: string): Promise<User | null> {
|
|
88
|
+
const row = await this.db.query('SELECT * FROM users WHERE id = $1', [id]);
|
|
89
|
+
return row ? this.toDomain(row) : null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Dependency Rule
|
|
95
|
+
|
|
96
|
+
Dependencies always point inward:
|
|
97
|
+
- Adapters depend on Ports
|
|
98
|
+
- Application depends on Domain
|
|
99
|
+
- Domain has no external dependencies
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
[External World] → [Adapters] → [Ports] → [Domain]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Testing Benefits
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Test with mock adapters
|
|
109
|
+
class InMemoryUserRepository implements UserRepositoryPort {
|
|
110
|
+
private users = new Map<string, User>();
|
|
111
|
+
|
|
112
|
+
async save(user: User) { this.users.set(user.id, user); }
|
|
113
|
+
async findById(id: string) { return this.users.get(id) || null; }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Domain logic tested without infrastructure
|
|
117
|
+
describe('UserService', () => {
|
|
118
|
+
it('creates user', async () => {
|
|
119
|
+
const repo = new InMemoryUserRepository();
|
|
120
|
+
const service = new UserService(repo);
|
|
121
|
+
const user = await service.createUser({ name: 'Test' });
|
|
122
|
+
expect(user.name).toBe('Test');
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## When to Use
|
|
128
|
+
|
|
129
|
+
- Applications needing multiple entry points (HTTP, CLI, events)
|
|
130
|
+
- Systems requiring easy infrastructure swapping
|
|
131
|
+
- Projects prioritizing testability
|
|
132
|
+
- Long-lived applications expecting technology changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Architecture Patterns
|
|
2
|
+
|
|
3
|
+
Architecture-specific guidelines and best practices.
|
|
4
|
+
|
|
5
|
+
## Available Architectures
|
|
6
|
+
|
|
7
|
+
- `microservices/` - Microservices architecture
|
|
8
|
+
- `modular-monolith/` - Modular monolith patterns
|
|
9
|
+
- `event-driven/` - Event-driven architecture
|
|
10
|
+
- `layered/` - Layered architecture
|
|
11
|
+
- `hexagonal/` - Hexagonal (Ports & Adapters) architecture
|
|
12
|
+
- `refactor/` - Refactoring strategies
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Layered Architecture
|
|
2
|
+
|
|
3
|
+
## Layer Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
┌─────────────────────────────────────┐
|
|
7
|
+
│ Presentation Layer │
|
|
8
|
+
│ (Controllers, Views, APIs) │
|
|
9
|
+
└───────────────┬─────────────────────┘
|
|
10
|
+
│
|
|
11
|
+
┌───────────────▼─────────────────────┐
|
|
12
|
+
│ Domain Layer │
|
|
13
|
+
│ (Business Logic, Services) │
|
|
14
|
+
└───────────────┬─────────────────────┘
|
|
15
|
+
│
|
|
16
|
+
┌───────────────▼─────────────────────┐
|
|
17
|
+
│ Data Access Layer │
|
|
18
|
+
│ (Repositories, ORM, DAOs) │
|
|
19
|
+
└─────────────────────────────────────┘
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Presentation Layer
|
|
23
|
+
|
|
24
|
+
Handles user interaction and HTTP requests.
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
class OrderController {
|
|
28
|
+
constructor(private orderService: OrderService) {}
|
|
29
|
+
|
|
30
|
+
async createOrder(req: Request, res: Response): Promise<void> {
|
|
31
|
+
const dto = req.body as CreateOrderDTO;
|
|
32
|
+
const result = await this.orderService.createOrder(dto);
|
|
33
|
+
res.status(201).json(result);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Domain Layer
|
|
39
|
+
|
|
40
|
+
Contains business logic and rules.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
class OrderService {
|
|
44
|
+
constructor(
|
|
45
|
+
private orderRepository: OrderRepository,
|
|
46
|
+
private productRepository: ProductRepository
|
|
47
|
+
) {}
|
|
48
|
+
|
|
49
|
+
async createOrder(dto: CreateOrderDTO): Promise<Order> {
|
|
50
|
+
const products = await this.productRepository.findByIds(dto.productIds);
|
|
51
|
+
|
|
52
|
+
if (products.length !== dto.productIds.length) {
|
|
53
|
+
throw new ProductNotFoundError();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const order = new Order(dto.customerId, products);
|
|
57
|
+
order.calculateTotal();
|
|
58
|
+
|
|
59
|
+
await this.orderRepository.save(order);
|
|
60
|
+
return order;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Data Access Layer
|
|
66
|
+
|
|
67
|
+
Handles persistence operations.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
class OrderRepository {
|
|
71
|
+
constructor(private db: Database) {}
|
|
72
|
+
|
|
73
|
+
async save(order: Order): Promise<void> {
|
|
74
|
+
await this.db.query(
|
|
75
|
+
'INSERT INTO orders (id, customer_id, total) VALUES ($1, $2, $3)',
|
|
76
|
+
[order.id, order.customerId, order.total]
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async findById(id: string): Promise<Order | null> {
|
|
81
|
+
const row = await this.db.queryOne('SELECT * FROM orders WHERE id = $1', [id]);
|
|
82
|
+
return row ? this.mapToOrder(row) : null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Layer Rules
|
|
88
|
+
|
|
89
|
+
1. Upper layers depend on lower layers
|
|
90
|
+
2. Never skip layers
|
|
91
|
+
3. Each layer exposes interfaces to the layer above
|
|
92
|
+
4. Domain layer should not depend on data access implementation
|
|
93
|
+
|
|
94
|
+
## Best Practices
|
|
95
|
+
|
|
96
|
+
- Keep layers focused on their responsibility
|
|
97
|
+
- Use DTOs to transfer data between layers
|
|
98
|
+
- Define interfaces in domain layer, implement in data access
|
|
99
|
+
- Avoid business logic in presentation or data access layers
|
|
100
|
+
- Consider dependency inversion for testability
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# API Gateway
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
An API Gateway acts as a single entry point for a group of microservices. It handles cross-cutting concerns and routes requests to the appropriate backend services.
|
|
6
|
+
|
|
7
|
+
## Core Responsibilities
|
|
8
|
+
|
|
9
|
+
1. **Routing**: Forwarding requests to the correct service (e.g., `/api/users` -> User Service).
|
|
10
|
+
2. **Authentication & Authorization**: Verifying identity and permissions at the edge.
|
|
11
|
+
3. **Rate Limiting**: Protecting services from abuse.
|
|
12
|
+
4. **Protocol Translation**: Converting public HTTP/REST to internal gRPC or AMQP.
|
|
13
|
+
5. **Response Aggregation**: Combining data from multiple services into a single response.
|
|
14
|
+
|
|
15
|
+
## Patterns
|
|
16
|
+
|
|
17
|
+
### Backend for Frontend (BFF)
|
|
18
|
+
|
|
19
|
+
Create separate gateways for different client types (Mobile, Web, 3rd Party) to optimize the API for each consumer.
|
|
20
|
+
|
|
21
|
+
```mermaid
|
|
22
|
+
graph TD
|
|
23
|
+
Web[Web App] --> WebBFF[Web BFF]
|
|
24
|
+
Mobile[Mobile App] --> MobileBFF[Mobile BFF]
|
|
25
|
+
|
|
26
|
+
WebBFF --> SvcA[Service A]
|
|
27
|
+
WebBFF --> SvcB[Service B]
|
|
28
|
+
|
|
29
|
+
MobileBFF --> SvcA
|
|
30
|
+
MobileBFF --> SvcC[Service C]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Implementation
|
|
34
|
+
|
|
35
|
+
### Cross-Cutting Concerns
|
|
36
|
+
|
|
37
|
+
Handle these at the gateway to keep microservices focused on business logic:
|
|
38
|
+
|
|
39
|
+
- **SSL Termination**: Decrypt HTTPS at the gateway.
|
|
40
|
+
- **CORS**: Handle Cross-Origin Resource Sharing headers.
|
|
41
|
+
- **Request Validation**: Basic schema validation before hitting services.
|
|
42
|
+
- **Caching**: Cache common responses.
|
|
43
|
+
|
|
44
|
+
### When to Use
|
|
45
|
+
|
|
46
|
+
| Use API Gateway When... | Avoid API Gateway When... |
|
|
47
|
+
|-------------------------|---------------------------|
|
|
48
|
+
| You have multiple microservices | You have a monolithic application |
|
|
49
|
+
| You need centralized auth/security | You need ultra-low latency (extra hop) |
|
|
50
|
+
| You have diverse clients (Web, Mobile) | Your architecture is very simple |
|
|
51
|
+
|
|
52
|
+
## Best Practices
|
|
53
|
+
|
|
54
|
+
- **Keep it Logic-Free**: Don't put business logic in the gateway. It should be a router, not a processor.
|
|
55
|
+
- **High Availability**: The gateway is a single point of failure; deploy it in a cluster.
|
|
56
|
+
- **Observability**: Ensure the gateway generates trace IDs and logs all traffic.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Service Boundaries
|
|
2
|
+
|
|
3
|
+
## Defining Service Boundaries
|
|
4
|
+
|
|
5
|
+
Each service should own a specific business capability:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
✅ Good Boundaries:
|
|
9
|
+
- User Service: Authentication, profiles, preferences
|
|
10
|
+
- Order Service: Order processing, fulfillment
|
|
11
|
+
- Payment Service: Payment processing, billing
|
|
12
|
+
- Notification Service: Emails, SMS, push notifications
|
|
13
|
+
|
|
14
|
+
❌ Bad Boundaries:
|
|
15
|
+
- Data Access Service (technical, not business)
|
|
16
|
+
- Utility Service (too generic)
|
|
17
|
+
- God Service (does everything)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Bounded Contexts
|
|
21
|
+
|
|
22
|
+
Use Domain-Driven Design to identify boundaries:
|
|
23
|
+
|
|
24
|
+
- Each service represents a bounded context
|
|
25
|
+
- Services are organized around business domains
|
|
26
|
+
- Clear ownership of data and logic
|
|
27
|
+
- Services should be independently deployable
|
|
28
|
+
|
|
29
|
+
## Ownership Rules
|
|
30
|
+
|
|
31
|
+
**Each service:**
|
|
32
|
+
- Owns its own database (no shared databases)
|
|
33
|
+
- Owns its domain logic
|
|
34
|
+
- Exposes well-defined APIs
|
|
35
|
+
- Can be developed by autonomous teams
|
|
36
|
+
|
|
37
|
+
## Communication Rules
|
|
38
|
+
|
|
39
|
+
**Avoid:**
|
|
40
|
+
- Direct database access between services
|
|
41
|
+
- Chatty communication (N+1 service calls)
|
|
42
|
+
- Tight coupling through shared libraries
|
|
43
|
+
|
|
44
|
+
**Prefer:**
|
|
45
|
+
- API-based communication
|
|
46
|
+
- Event-driven for data synchronization
|
|
47
|
+
- Async messaging where possible
|
|
48
|
+
|
|
49
|
+
## Data Ownership
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
// ✅ Good - Service owns its data
|
|
53
|
+
Class OrderService:
|
|
54
|
+
Method CreateOrder(data):
|
|
55
|
+
# Order service owns order data
|
|
56
|
+
Order = OrderRepository.Save(data)
|
|
57
|
+
|
|
58
|
+
# Publish event for other services
|
|
59
|
+
EventBus.Publish("order.created", {
|
|
60
|
+
orderId: Order.id,
|
|
61
|
+
userId: Order.userId,
|
|
62
|
+
total: Order.total
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
Return Order
|
|
66
|
+
|
|
67
|
+
// ❌ Bad - Direct access to another service's database
|
|
68
|
+
Class OrderService:
|
|
69
|
+
Method CreateOrder(data):
|
|
70
|
+
# Don't do this!
|
|
71
|
+
User = UserDatabase.FindOne({ id: data.userId })
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Sizing Guidelines
|
|
75
|
+
|
|
76
|
+
Keep services:
|
|
77
|
+
- Small enough to be maintained by a small team (2-3 developers)
|
|
78
|
+
- Large enough to provide business value
|
|
79
|
+
- Focused on a single bounded context
|
|
80
|
+
- Independently deployable and scalable
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Microservices Communication
|
|
2
|
+
|
|
3
|
+
## Synchronous vs Asynchronous
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
# ⚠️ Synchronous creates coupling and multiplicative downtime
|
|
7
|
+
# If Service A calls B calls C, any failure breaks the chain
|
|
8
|
+
|
|
9
|
+
# ✅ Prefer asynchronous messaging for most inter-service communication
|
|
10
|
+
# Limit synchronous calls to one per user request
|
|
11
|
+
|
|
12
|
+
# Async Message Format Example
|
|
13
|
+
Event: "order.created"
|
|
14
|
+
Data: {
|
|
15
|
+
orderId: "ord_123",
|
|
16
|
+
userId: "user_456",
|
|
17
|
+
items: [...]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Subscribers process independently
|
|
21
|
+
Service Inventory -> ReserveItems(items)
|
|
22
|
+
Service Notification -> SendEmail(user)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## API-Based Communication
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
# ✅ Well-defined REST APIs between services
|
|
29
|
+
GET /users/{userId}
|
|
30
|
+
|
|
31
|
+
# ✅ Use circuit breaker for resilience
|
|
32
|
+
Function getUserSafe(userId):
|
|
33
|
+
Try:
|
|
34
|
+
return UserClient.getUser(userId)
|
|
35
|
+
Catch Error:
|
|
36
|
+
return getCachedUser(userId) # Fallback
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Event-Driven Integration
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
# ✅ Publish events for state changes
|
|
43
|
+
Function CreateOrder(data):
|
|
44
|
+
order = Repository.Save(data)
|
|
45
|
+
|
|
46
|
+
# Failures here don't block the user
|
|
47
|
+
EventBus.Publish("order.created", {
|
|
48
|
+
orderId: order.id,
|
|
49
|
+
userId: order.userId,
|
|
50
|
+
timestamp: Now()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
return order
|
|
54
|
+
|
|
55
|
+
# ✅ Consumers handle events independently (Decoupled)
|
|
56
|
+
Service Notification:
|
|
57
|
+
On("order.created"): SendConfirmation(event)
|
|
58
|
+
|
|
59
|
+
Service Inventory:
|
|
60
|
+
On("order.created"): ReserveInventory(event)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Tolerant Reader Pattern
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
# ✅ Don't fail on unknown fields - enables independent evolution
|
|
67
|
+
Structure UserResponse:
|
|
68
|
+
id: string
|
|
69
|
+
name: string
|
|
70
|
+
...ignore other fields...
|
|
71
|
+
|
|
72
|
+
# ✅ Use sensible defaults for missing optional fields
|
|
73
|
+
Function ParseUser(data):
|
|
74
|
+
return User {
|
|
75
|
+
id: data.id,
|
|
76
|
+
name: data.name,
|
|
77
|
+
role: data.role OR 'user', # Default
|
|
78
|
+
avatar: data.avatar OR null
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Anti-Patterns
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
# ❌ Chatty communication (N+1 service calls)
|
|
86
|
+
For each orderId in orderIds:
|
|
87
|
+
GetOrder(orderId) # N network calls!
|
|
88
|
+
|
|
89
|
+
# ✅ Batch requests
|
|
90
|
+
GetOrders(orderIds) # 1 network call
|
|
91
|
+
|
|
92
|
+
# ❌ Tight coupling via shared databases
|
|
93
|
+
# Service A directly queries Service B's tables
|
|
94
|
+
|
|
95
|
+
# ✅ API-based communication
|
|
96
|
+
UserClient.GetUsers(userIds)
|
|
97
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Microservices Data Management
|
|
2
|
+
|
|
3
|
+
## Database Per Service
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
Each service owns its database:
|
|
7
|
+
|
|
8
|
+
✅ Order Service → order_db (PostgreSQL)
|
|
9
|
+
✅ User Service → user_db (PostgreSQL)
|
|
10
|
+
✅ Catalog Service → catalog_db (MongoDB)
|
|
11
|
+
✅ Search Service → search_index (Elasticsearch)
|
|
12
|
+
|
|
13
|
+
❌ Never share databases between services
|
|
14
|
+
❌ Never query another service's tables directly
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Polyglot Persistence
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
# Each service uses the best database for its needs
|
|
21
|
+
|
|
22
|
+
# User Service -> Relational (ACID, relationships)
|
|
23
|
+
Repository UserRepository:
|
|
24
|
+
Method Create(user):
|
|
25
|
+
SQL "INSERT INTO users..."
|
|
26
|
+
|
|
27
|
+
# Catalog Service -> Document (Flexible schema)
|
|
28
|
+
Repository ProductRepository:
|
|
29
|
+
Method Create(product):
|
|
30
|
+
Collection("products").Insert(product)
|
|
31
|
+
|
|
32
|
+
# Analytics Service -> Time-Series (High write volume)
|
|
33
|
+
Repository MetricsRepository:
|
|
34
|
+
Method Record(metric):
|
|
35
|
+
InfluxDB.Write(metric)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Eventual Consistency
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
# ✅ Embrace eventual consistency for cross-service data
|
|
42
|
+
|
|
43
|
+
1. Order Service: Save Order -> Publish "order.created"
|
|
44
|
+
2. Inventory Service: Listen "order.created" -> Reserve Inventory
|
|
45
|
+
|
|
46
|
+
# Data may be temporarily inconsistent - that's OK
|
|
47
|
+
|
|
48
|
+
# ✅ Use compensating actions for failures
|
|
49
|
+
Function ProcessOrder(order):
|
|
50
|
+
Try:
|
|
51
|
+
InventoryService.Reserve(order.items)
|
|
52
|
+
PaymentService.Charge(order.total)
|
|
53
|
+
Catch Error:
|
|
54
|
+
# Compensate: undo previous actions
|
|
55
|
+
InventoryService.Release(order.items)
|
|
56
|
+
Throw Error
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Data Synchronization Patterns
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
# Pattern: Event Sourcing / CQRS
|
|
63
|
+
Service OrderQuery:
|
|
64
|
+
On("product.updated"):
|
|
65
|
+
# Update local read-optimized copy
|
|
66
|
+
Cache.Set(event.productId, { name: event.name, price: event.price })
|
|
67
|
+
|
|
68
|
+
# Pattern: Saga for distributed transactions
|
|
69
|
+
Saga CreateOrder:
|
|
70
|
+
Step 1:
|
|
71
|
+
Action: Inventory.Reserve()
|
|
72
|
+
Compensate: Inventory.Release()
|
|
73
|
+
Step 2:
|
|
74
|
+
Action: Payment.Charge()
|
|
75
|
+
Compensate: Payment.Refund()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Data Ownership
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
# ✅ Each service is the source of truth for its data
|
|
82
|
+
Service User:
|
|
83
|
+
Function UpdateEmail(userId, email):
|
|
84
|
+
Database.Update(userId, email)
|
|
85
|
+
EventBus.Publish("user.email.changed", { userId, email })
|
|
86
|
+
|
|
87
|
+
# Other services maintain their own copies (projections)
|
|
88
|
+
Service Order:
|
|
89
|
+
On("user.email.changed"):
|
|
90
|
+
# Update local cache, never query User DB directly
|
|
91
|
+
LocalUserCache.Update(event.userId, event.email)
|
|
92
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Microservices Architecture
|
|
2
|
+
|
|
3
|
+
Guidelines for building microservices.
|
|
4
|
+
|
|
5
|
+
## Chunks
|
|
6
|
+
|
|
7
|
+
- `boundaries.md` - Defining service boundaries
|
|
8
|
+
- `communication.md` - Inter-service communication
|
|
9
|
+
- `data.md` - Data management and consistency
|
|
10
|
+
- `deployment.md` - Deployment strategies
|
|
11
|
+
- `resilience.md` - Resilience patterns
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Microservices Resilience
|
|
2
|
+
|
|
3
|
+
## Circuit Breaker Pattern
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Class CircuitBreaker:
|
|
7
|
+
State: CLOSED | OPEN | HALF_OPEN
|
|
8
|
+
|
|
9
|
+
Method Execute(operation):
|
|
10
|
+
If State is OPEN:
|
|
11
|
+
If TimeoutExpired:
|
|
12
|
+
State = HALF_OPEN
|
|
13
|
+
Else:
|
|
14
|
+
Throw Error("Circuit Open")
|
|
15
|
+
|
|
16
|
+
Try:
|
|
17
|
+
Result = operation()
|
|
18
|
+
OnSuccess()
|
|
19
|
+
Return Result
|
|
20
|
+
Catch Error:
|
|
21
|
+
OnFailure()
|
|
22
|
+
Throw Error
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Retry with Exponential Backoff
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
Function Retry(operation, maxAttempts, baseDelay):
|
|
29
|
+
For attempt in 1..maxAttempts:
|
|
30
|
+
Try:
|
|
31
|
+
return operation()
|
|
32
|
+
Catch Error:
|
|
33
|
+
If attempt == maxAttempts: Throw Error
|
|
34
|
+
|
|
35
|
+
# Exponential Backoff + Jitter
|
|
36
|
+
delay = baseDelay * (2 ^ attempt) + RandomJitter()
|
|
37
|
+
Sleep(delay)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Bulkhead Pattern
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
# Isolate resources to prevent cascading failures
|
|
44
|
+
Class Bulkhead:
|
|
45
|
+
MaxConcurrent = 5
|
|
46
|
+
Active = 0
|
|
47
|
+
|
|
48
|
+
Method Execute(operation):
|
|
49
|
+
If Active >= MaxConcurrent:
|
|
50
|
+
Throw Error("Bulkhead Full")
|
|
51
|
+
|
|
52
|
+
Active++
|
|
53
|
+
Try:
|
|
54
|
+
return operation()
|
|
55
|
+
Finally:
|
|
56
|
+
Active--
|
|
57
|
+
|
|
58
|
+
# Usage: Separate bulkheads per dependency
|
|
59
|
+
PaymentBulkhead = New Bulkhead(5)
|
|
60
|
+
EmailBulkhead = New Bulkhead(10)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Timeouts
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
Function WithTimeout(operation, timeoutMs):
|
|
67
|
+
Race:
|
|
68
|
+
1. Result = operation()
|
|
69
|
+
2. Sleep(timeoutMs) -> Throw Error("Timeout")
|
|
70
|
+
|
|
71
|
+
# Always set timeouts for external calls
|
|
72
|
+
Result = WithTimeout(UserService.GetUser(id), 5000)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Graceful Degradation
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
Function GetProductRecommendations(userId):
|
|
79
|
+
Try:
|
|
80
|
+
return RecommendationService.GetPersonalized(userId)
|
|
81
|
+
Catch Error:
|
|
82
|
+
# Fallback to cached popular items
|
|
83
|
+
Log("Recommendation service unavailable")
|
|
84
|
+
return GetPopularProducts()
|
|
85
|
+
|
|
86
|
+
# Partial responses instead of complete failure
|
|
87
|
+
Function GetDashboard(userId):
|
|
88
|
+
User = GetUser(userId) OR null
|
|
89
|
+
Orders = GetOrders(userId) OR []
|
|
90
|
+
Stats = GetStats(userId) OR null
|
|
91
|
+
|
|
92
|
+
return { User, Orders, Stats }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Health Checks
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
Endpoint GET /health:
|
|
99
|
+
Checks = [
|
|
100
|
+
CheckDatabase(),
|
|
101
|
+
CheckRedis(),
|
|
102
|
+
CheckExternalAPI()
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
Healthy = All(Checks) passed
|
|
106
|
+
|
|
107
|
+
Return HTTP 200/503 {
|
|
108
|
+
status: Healthy ? "healthy" : "degraded",
|
|
109
|
+
checks: { ...details... }
|
|
110
|
+
}
|
|
111
|
+
```
|