@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,83 @@
|
|
|
1
|
+
# Data Access Patterns
|
|
2
|
+
|
|
3
|
+
## Repository
|
|
4
|
+
|
|
5
|
+
Collection-like interface for domain objects.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface UserRepository {
|
|
9
|
+
findById(id: string): Promise<User | null>;
|
|
10
|
+
findByEmail(email: string): Promise<User | null>;
|
|
11
|
+
save(user: User): Promise<void>;
|
|
12
|
+
delete(user: User): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class PostgreSQLUserRepository implements UserRepository {
|
|
16
|
+
async findById(id: string): Promise<User | null> {
|
|
17
|
+
const row = await this.db.queryOne('SELECT * FROM users WHERE id = $1', [id]);
|
|
18
|
+
return row ? this.mapToUser(row) : null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Data Mapper
|
|
24
|
+
|
|
25
|
+
Complete separation between domain and persistence.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
class UserMapper {
|
|
29
|
+
toDomain(row: DbRow): User {
|
|
30
|
+
return new User(row.id, row.name, new Email(row.email));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
toDatabase(user: User): DbRow {
|
|
34
|
+
return { id: user.id, name: user.name, email: user.email.toString() };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Unit of Work
|
|
40
|
+
|
|
41
|
+
Track changes and commit together.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
class UnitOfWork {
|
|
45
|
+
private newObjects = new Set<any>();
|
|
46
|
+
private dirtyObjects = new Set<any>();
|
|
47
|
+
|
|
48
|
+
registerNew(obj: any): void { this.newObjects.add(obj); }
|
|
49
|
+
registerDirty(obj: any): void { this.dirtyObjects.add(obj); }
|
|
50
|
+
|
|
51
|
+
async commit(): Promise<void> {
|
|
52
|
+
await this.db.beginTransaction();
|
|
53
|
+
try {
|
|
54
|
+
for (const obj of this.newObjects) await this.insert(obj);
|
|
55
|
+
for (const obj of this.dirtyObjects) await this.update(obj);
|
|
56
|
+
await this.db.commit();
|
|
57
|
+
} catch (e) {
|
|
58
|
+
await this.db.rollback();
|
|
59
|
+
throw e;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Identity Map
|
|
66
|
+
|
|
67
|
+
Ensure each object loaded only once per session.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
class IdentityMap {
|
|
71
|
+
private map = new Map<string, any>();
|
|
72
|
+
|
|
73
|
+
get(id: string): any | null { return this.map.get(id) || null; }
|
|
74
|
+
put(id: string, obj: any): void { this.map.set(id, obj); }
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Best Practices
|
|
79
|
+
|
|
80
|
+
- Return domain objects from repositories
|
|
81
|
+
- Use one repository per aggregate root
|
|
82
|
+
- Keep repositories focused on persistence
|
|
83
|
+
- Don't leak database details into domain
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Distribution Patterns
|
|
2
|
+
|
|
3
|
+
## Remote Facade
|
|
4
|
+
|
|
5
|
+
Coarse-grained interface to reduce network calls.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Bad: Multiple network calls
|
|
9
|
+
const customer = await api.getCustomer(id);
|
|
10
|
+
const orders = await api.getOrders(id);
|
|
11
|
+
const addresses = await api.getAddresses(id);
|
|
12
|
+
|
|
13
|
+
// Good: Single call via facade
|
|
14
|
+
const details = await api.getCustomerDetails(id);
|
|
15
|
+
// Returns { customer, orders, addresses }
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Data Transfer Object (DTO)
|
|
19
|
+
|
|
20
|
+
Bundle data for transfer across boundaries.
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
interface OrderDTO {
|
|
24
|
+
id: string;
|
|
25
|
+
customerId: string;
|
|
26
|
+
items: OrderItemDTO[];
|
|
27
|
+
total: number;
|
|
28
|
+
status: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class OrderDTOMapper {
|
|
32
|
+
static toDTO(order: Order): OrderDTO {
|
|
33
|
+
return {
|
|
34
|
+
id: order.id,
|
|
35
|
+
customerId: order.customer.id,
|
|
36
|
+
items: order.items.map(i => this.itemToDTO(i)),
|
|
37
|
+
total: order.total.amount,
|
|
38
|
+
status: order.status.toString()
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Gateway
|
|
45
|
+
|
|
46
|
+
Abstract external system access.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
interface PaymentGateway {
|
|
50
|
+
charge(amount: Money, method: PaymentMethod): Promise<PaymentResult>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class StripeGateway implements PaymentGateway {
|
|
54
|
+
async charge(amount: Money, method: PaymentMethod): Promise<PaymentResult> {
|
|
55
|
+
const result = await this.stripe.paymentIntents.create({
|
|
56
|
+
amount: amount.cents,
|
|
57
|
+
currency: amount.currency
|
|
58
|
+
});
|
|
59
|
+
return this.mapToResult(result);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Service Stub
|
|
65
|
+
|
|
66
|
+
Test double for external services.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
class StubPaymentGateway implements PaymentGateway {
|
|
70
|
+
private shouldSucceed = true;
|
|
71
|
+
|
|
72
|
+
async charge(amount: Money): Promise<PaymentResult> {
|
|
73
|
+
if (!this.shouldSucceed) throw new PaymentDeclinedError();
|
|
74
|
+
return { success: true, transactionId: 'stub-123' };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
configureFail(): void { this.shouldSucceed = false; }
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Best Practices
|
|
82
|
+
|
|
83
|
+
- Design facades around client use cases
|
|
84
|
+
- Keep DTOs simple and serializable
|
|
85
|
+
- Isolate vendor code in gateways
|
|
86
|
+
- Use stubs for testing, not production
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Domain Logic Patterns
|
|
2
|
+
|
|
3
|
+
## Transaction Script
|
|
4
|
+
|
|
5
|
+
Procedural approach - one procedure per operation.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
async function transferMoney(fromId: string, toId: string, amount: number) {
|
|
9
|
+
const db = await Database.connect();
|
|
10
|
+
await db.beginTransaction();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const from = await db.query('SELECT * FROM accounts WHERE id = $1', [fromId]);
|
|
14
|
+
if (from.balance < amount) throw new Error('Insufficient funds');
|
|
15
|
+
|
|
16
|
+
await db.execute('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [amount, fromId]);
|
|
17
|
+
await db.execute('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [amount, toId]);
|
|
18
|
+
await db.commit();
|
|
19
|
+
} catch (e) {
|
|
20
|
+
await db.rollback();
|
|
21
|
+
throw e;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Use for:** Simple apps, CRUD, reports.
|
|
27
|
+
|
|
28
|
+
## Domain Model
|
|
29
|
+
|
|
30
|
+
Rich objects with behavior.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
class Account {
|
|
34
|
+
constructor(private balance: Money, private overdraftLimit: Money) {}
|
|
35
|
+
|
|
36
|
+
withdraw(amount: Money): void {
|
|
37
|
+
if (!this.canWithdraw(amount)) throw new InsufficientFundsError();
|
|
38
|
+
this.balance = this.balance.subtract(amount);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
transfer(amount: Money, recipient: Account): void {
|
|
42
|
+
this.withdraw(amount);
|
|
43
|
+
recipient.deposit(amount);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Use for:** Complex business rules, rich domains.
|
|
49
|
+
|
|
50
|
+
## Service Layer
|
|
51
|
+
|
|
52
|
+
Application boundary coordinating domain objects.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
class AccountService {
|
|
56
|
+
constructor(
|
|
57
|
+
private accountRepo: AccountRepository,
|
|
58
|
+
private unitOfWork: UnitOfWork
|
|
59
|
+
) {}
|
|
60
|
+
|
|
61
|
+
async transfer(fromId: string, toId: string, amount: Money): Promise<void> {
|
|
62
|
+
const from = await this.accountRepo.findById(fromId);
|
|
63
|
+
const to = await this.accountRepo.findById(toId);
|
|
64
|
+
|
|
65
|
+
from.transfer(amount, to); // Domain logic
|
|
66
|
+
|
|
67
|
+
await this.accountRepo.save(from);
|
|
68
|
+
await this.accountRepo.save(to);
|
|
69
|
+
await this.unitOfWork.commit();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Use for:** API boundaries, multiple clients, transaction coordination.
|
|
75
|
+
|
|
76
|
+
## Best Practices
|
|
77
|
+
|
|
78
|
+
- Choose pattern based on complexity
|
|
79
|
+
- Service layer orchestrates, domain model contains logic
|
|
80
|
+
- Keep services thin, domain objects rich
|
|
81
|
+
- Combine Domain Model + Service Layer for complex apps
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Gang of Four Patterns
|
|
2
|
+
|
|
3
|
+
## Creational
|
|
4
|
+
|
|
5
|
+
### Factory Method
|
|
6
|
+
```typescript
|
|
7
|
+
interface Logger { log(msg: string): void; }
|
|
8
|
+
|
|
9
|
+
abstract class Application {
|
|
10
|
+
abstract createLogger(): Logger;
|
|
11
|
+
run(): void { this.createLogger().log('Started'); }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class DevApp extends Application {
|
|
15
|
+
createLogger(): Logger { return new ConsoleLogger(); }
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Builder
|
|
20
|
+
```typescript
|
|
21
|
+
const query = new QueryBuilder()
|
|
22
|
+
.from('users')
|
|
23
|
+
.select('id', 'name')
|
|
24
|
+
.where('active = true')
|
|
25
|
+
.limit(10)
|
|
26
|
+
.build();
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Structural
|
|
30
|
+
|
|
31
|
+
### Adapter
|
|
32
|
+
```typescript
|
|
33
|
+
class PaymentAdapter implements PaymentProcessor {
|
|
34
|
+
constructor(private legacy: OldPaymentSystem) {}
|
|
35
|
+
|
|
36
|
+
async process(amount: number): Promise<boolean> {
|
|
37
|
+
return this.legacy.makePayment(amount);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Decorator
|
|
43
|
+
```typescript
|
|
44
|
+
interface Coffee { cost(): number; }
|
|
45
|
+
|
|
46
|
+
class MilkDecorator implements Coffee {
|
|
47
|
+
constructor(private coffee: Coffee) {}
|
|
48
|
+
cost(): number { return this.coffee.cost() + 2; }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let coffee: Coffee = new SimpleCoffee();
|
|
52
|
+
coffee = new MilkDecorator(coffee);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Facade
|
|
56
|
+
```typescript
|
|
57
|
+
class ComputerFacade {
|
|
58
|
+
start(): void {
|
|
59
|
+
this.cpu.freeze();
|
|
60
|
+
this.memory.load(0, this.hdd.read(0, 1024));
|
|
61
|
+
this.cpu.execute();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Behavioral
|
|
67
|
+
|
|
68
|
+
### Strategy
|
|
69
|
+
```typescript
|
|
70
|
+
interface SortStrategy { sort(data: number[]): number[]; }
|
|
71
|
+
|
|
72
|
+
class Sorter {
|
|
73
|
+
constructor(private strategy: SortStrategy) {}
|
|
74
|
+
sort(data: number[]): number[] { return this.strategy.sort(data); }
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Observer
|
|
79
|
+
```typescript
|
|
80
|
+
class Stock {
|
|
81
|
+
private observers: Observer[] = [];
|
|
82
|
+
|
|
83
|
+
attach(o: Observer): void { this.observers.push(o); }
|
|
84
|
+
notify(): void { this.observers.forEach(o => o.update(this)); }
|
|
85
|
+
|
|
86
|
+
setPrice(price: number): void {
|
|
87
|
+
this.price = price;
|
|
88
|
+
this.notify();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Command
|
|
94
|
+
```typescript
|
|
95
|
+
interface Command { execute(): void; undo(): void; }
|
|
96
|
+
|
|
97
|
+
class AppendCommand implements Command {
|
|
98
|
+
constructor(private editor: Editor, private text: string) {}
|
|
99
|
+
execute(): void { this.editor.append(this.text); }
|
|
100
|
+
undo(): void { this.editor.delete(this.text.length); }
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Best Practices
|
|
105
|
+
|
|
106
|
+
- Use patterns to solve specific problems, not everywhere
|
|
107
|
+
- Combine patterns when appropriate
|
|
108
|
+
- Favor composition over inheritance
|
|
109
|
+
- Keep implementations simple
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Enterprise Patterns
|
|
2
|
+
|
|
3
|
+
This directory contains enterprise application patterns.
|
|
4
|
+
|
|
5
|
+
## Available Chunks
|
|
6
|
+
|
|
7
|
+
- **base-patterns.md** - Value Objects, Money, Special Case, Registry, Plugin
|
|
8
|
+
- **concurrency.md** - Optimistic/Pessimistic locking, Coarse-Grained Lock
|
|
9
|
+
- **data-access.md** - Repository, Data Mapper, Active Record, Unit of Work
|
|
10
|
+
- **distribution.md** - Remote Facade, DTO, Gateway, Service Stub
|
|
11
|
+
- **domain-logic.md** - Transaction Script, Domain Model, Service Layer
|
|
12
|
+
- **gof.md** - Gang of Four: Creational, Structural, Behavioral patterns
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Async Performance Patterns
|
|
2
|
+
|
|
3
|
+
## Parallel Execution
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// ❌ Sequential - slow
|
|
7
|
+
async function getUserData(userId: string) {
|
|
8
|
+
const user = await fetchUser(userId); // 100ms
|
|
9
|
+
const posts = await fetchPosts(userId); // 150ms
|
|
10
|
+
const comments = await fetchComments(userId); // 120ms
|
|
11
|
+
return { user, posts, comments }; // Total: 370ms
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// ✅ Parallel - fast
|
|
15
|
+
async function getUserData(userId: string) {
|
|
16
|
+
const [user, posts, comments] = await Promise.all([
|
|
17
|
+
fetchUser(userId),
|
|
18
|
+
fetchPosts(userId),
|
|
19
|
+
fetchComments(userId)
|
|
20
|
+
]);
|
|
21
|
+
return { user, posts, comments }; // Total: 150ms
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ✅ Partial parallel with dependencies
|
|
25
|
+
async function getOrderDetails(orderId: string) {
|
|
26
|
+
const order = await fetchOrder(orderId); // Must fetch first
|
|
27
|
+
|
|
28
|
+
const [customer, items, shipping] = await Promise.all([
|
|
29
|
+
fetchCustomer(order.customerId),
|
|
30
|
+
fetchOrderItems(orderId),
|
|
31
|
+
fetchShippingInfo(orderId)
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
return { order, customer, items, shipping };
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Promise.allSettled for Partial Failures
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// Return partial data instead of complete failure
|
|
42
|
+
async function getDashboard(userId: string) {
|
|
43
|
+
const [user, orders, stats] = await Promise.allSettled([
|
|
44
|
+
getUser(userId),
|
|
45
|
+
getOrders(userId),
|
|
46
|
+
getStats(userId)
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
user: user.status === 'fulfilled' ? user.value : null,
|
|
51
|
+
orders: orders.status === 'fulfilled' ? orders.value : [],
|
|
52
|
+
stats: stats.status === 'fulfilled' ? stats.value : null,
|
|
53
|
+
errors: {
|
|
54
|
+
user: user.status === 'rejected' ? user.reason.message : null,
|
|
55
|
+
orders: orders.status === 'rejected' ? orders.reason.message : null,
|
|
56
|
+
stats: stats.status === 'rejected' ? stats.reason.message : null
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Batch Processing
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// ❌ One at a time - slow
|
|
66
|
+
async function processUsers(userIds: string[]) {
|
|
67
|
+
for (const id of userIds) {
|
|
68
|
+
await updateUser(id);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ✅ Batch processing
|
|
73
|
+
async function processUsers(userIds: string[]) {
|
|
74
|
+
const BATCH_SIZE = 50;
|
|
75
|
+
|
|
76
|
+
for (let i = 0; i < userIds.length; i += BATCH_SIZE) {
|
|
77
|
+
const batch = userIds.slice(i, i + BATCH_SIZE);
|
|
78
|
+
await Promise.all(batch.map(id => updateUser(id)));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ✅ Bulk database operations
|
|
83
|
+
async function createUsers(users: User[]) {
|
|
84
|
+
await db.query(`
|
|
85
|
+
INSERT INTO users (name, email)
|
|
86
|
+
VALUES ${users.map(() => '(?, ?)').join(', ')}
|
|
87
|
+
`, users.flatMap(u => [u.name, u.email]));
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Debouncing and Throttling
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// Debounce: Wait until user stops typing
|
|
95
|
+
const debounce = <T extends (...args: any[]) => any>(
|
|
96
|
+
fn: T,
|
|
97
|
+
delay: number
|
|
98
|
+
): ((...args: Parameters<T>) => void) => {
|
|
99
|
+
let timeoutId: NodeJS.Timeout;
|
|
100
|
+
|
|
101
|
+
return (...args: Parameters<T>) => {
|
|
102
|
+
clearTimeout(timeoutId);
|
|
103
|
+
timeoutId = setTimeout(() => fn(...args), delay);
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Throttle: Execute at most once per interval
|
|
108
|
+
const throttle = <T extends (...args: any[]) => any>(
|
|
109
|
+
fn: T,
|
|
110
|
+
limit: number
|
|
111
|
+
): ((...args: Parameters<T>) => void) => {
|
|
112
|
+
let inThrottle: boolean;
|
|
113
|
+
|
|
114
|
+
return (...args: Parameters<T>) => {
|
|
115
|
+
if (!inThrottle) {
|
|
116
|
+
fn(...args);
|
|
117
|
+
inThrottle = true;
|
|
118
|
+
setTimeout(() => (inThrottle = false), limit);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Usage
|
|
124
|
+
const searchUsers = debounce(query => api.search(query), 300);
|
|
125
|
+
const handleScroll = throttle(() => console.log('scroll'), 100);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Rate Limiting Concurrent Operations
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
async function processWithLimit<T>(
|
|
132
|
+
items: T[],
|
|
133
|
+
fn: (item: T) => Promise<void>,
|
|
134
|
+
concurrency: number
|
|
135
|
+
): Promise<void> {
|
|
136
|
+
const chunks = [];
|
|
137
|
+
for (let i = 0; i < items.length; i += concurrency) {
|
|
138
|
+
chunks.push(items.slice(i, i + concurrency));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for (const chunk of chunks) {
|
|
142
|
+
await Promise.all(chunk.map(fn));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Usage: Process 100 items, max 10 at a time
|
|
147
|
+
await processWithLimit(users, updateUser, 10);
|
|
148
|
+
```
|