@mytechtoday/augment-extensions 1.2.1 → 1.3.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/AGENTS.md +33 -1
- package/README.md +3 -3
- package/augment-extensions/domain-rules/software-architecture/README.md +143 -0
- package/augment-extensions/domain-rules/software-architecture/examples/banking-layered.md +961 -0
- package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md +990 -0
- package/augment-extensions/domain-rules/software-architecture/examples/iot-eventdriven.md +882 -0
- package/augment-extensions/domain-rules/software-architecture/examples/monolith-to-microservices-migration.md +703 -0
- package/augment-extensions/domain-rules/software-architecture/examples/serverless-imageprocessing.md +957 -0
- package/augment-extensions/domain-rules/software-architecture/examples/trading-eventdriven.md +747 -0
- package/augment-extensions/domain-rules/software-architecture/module.json +119 -0
- package/augment-extensions/domain-rules/software-architecture/rules/challenges-solutions.md +763 -0
- package/augment-extensions/domain-rules/software-architecture/rules/definitions-terminology.md +409 -0
- package/augment-extensions/domain-rules/software-architecture/rules/design-principles.md +684 -0
- package/augment-extensions/domain-rules/software-architecture/rules/evaluation-testing.md +1381 -0
- package/augment-extensions/domain-rules/software-architecture/rules/event-driven-architecture.md +616 -0
- package/augment-extensions/domain-rules/software-architecture/rules/fundamentals.md +306 -0
- package/augment-extensions/domain-rules/software-architecture/rules/industry-architectures.md +554 -0
- package/augment-extensions/domain-rules/software-architecture/rules/layered-architecture.md +776 -0
- package/augment-extensions/domain-rules/software-architecture/rules/microservices-architecture.md +503 -0
- package/augment-extensions/domain-rules/software-architecture/rules/modeling-documentation.md +1199 -0
- package/augment-extensions/domain-rules/software-architecture/rules/monolithic-architecture.md +351 -0
- package/augment-extensions/domain-rules/software-architecture/rules/principles.md +556 -0
- package/augment-extensions/domain-rules/software-architecture/rules/quality-attributes.md +797 -0
- package/augment-extensions/domain-rules/software-architecture/rules/scalability-performance.md +1345 -0
- package/augment-extensions/domain-rules/software-architecture/rules/security-architecture.md +1039 -0
- package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md +711 -0
- package/augment-extensions/domain-rules/software-architecture/rules/skills-development.md +568 -0
- package/augment-extensions/domain-rules/software-architecture/rules/tools-methodologies.md +961 -0
- package/augment-extensions/visual-design/CHANGELOG.md +132 -0
- package/augment-extensions/visual-design/README.md +255 -0
- package/augment-extensions/visual-design/__tests__/README.md +119 -0
- package/augment-extensions/visual-design/__tests__/style-selector.test.ts +172 -0
- package/augment-extensions/visual-design/__tests__/vendor-styles.test.ts +214 -0
- package/augment-extensions/visual-design/domains/other/ai-prompt-helper.ts +157 -0
- package/augment-extensions/visual-design/domains/other/dotnet-application.ts +156 -0
- package/augment-extensions/visual-design/domains/other/linux-platform.ts +156 -0
- package/augment-extensions/visual-design/domains/other/mobile-application.ts +157 -0
- package/augment-extensions/visual-design/domains/other/motion-picture.ts +156 -0
- package/augment-extensions/visual-design/domains/other/os-application.ts +156 -0
- package/augment-extensions/visual-design/domains/other/print-campaigns.ts +158 -0
- package/augment-extensions/visual-design/domains/other/web-app.ts +157 -0
- package/augment-extensions/visual-design/domains/other/website.ts +161 -0
- package/augment-extensions/visual-design/domains/other/windows-platform.ts +156 -0
- package/augment-extensions/visual-design/domains/web-page-styles/amazon-cloudscape.ts +506 -0
- package/augment-extensions/visual-design/domains/web-page-styles/google-modern.ts +615 -0
- package/augment-extensions/visual-design/domains/web-page-styles/microsoft-fluent.ts +531 -0
- package/augment-extensions/visual-design/examples/README.md +97 -0
- package/augment-extensions/visual-design/examples/ai-prompt-generation.md +233 -0
- package/augment-extensions/visual-design/examples/basic-usage.md +216 -0
- package/augment-extensions/visual-design/examples/domain-workflows.md +257 -0
- package/augment-extensions/visual-design/examples/vendor-comparison.md +247 -0
- package/augment-extensions/visual-design/module.json +78 -0
- package/augment-extensions/visual-design/style-selector.ts +177 -0
- package/augment-extensions/visual-design/types.ts +302 -0
- package/augment-extensions/visual-design/visual-design-core.ts +469 -0
- package/augment-extensions/workflows/adr-support/README.md +227 -0
- package/augment-extensions/workflows/adr-support/__tests__/adr-validator.test.ts +203 -0
- package/augment-extensions/workflows/adr-support/adr-validator.ts +162 -0
- package/augment-extensions/workflows/adr-support/examples/complete-lifecycle-example.md +449 -0
- package/augment-extensions/workflows/adr-support/examples/integration-example.md +580 -0
- package/augment-extensions/workflows/adr-support/examples/superseding-example.md +436 -0
- package/augment-extensions/workflows/adr-support/module.json +112 -0
- package/augment-extensions/workflows/adr-support/rules/adr-creation.md +372 -0
- package/augment-extensions/workflows/adr-support/rules/beads-integration.md +443 -0
- package/augment-extensions/workflows/adr-support/rules/conflict-detection.md +486 -0
- package/augment-extensions/workflows/adr-support/rules/decision-detection.md +362 -0
- package/augment-extensions/workflows/adr-support/rules/lifecycle-management.md +427 -0
- package/augment-extensions/workflows/adr-support/rules/openspec-integration.md +465 -0
- package/augment-extensions/workflows/adr-support/rules/template-selection.md +405 -0
- package/augment-extensions/workflows/adr-support/rules/validation-rules.md +543 -0
- package/augment-extensions/workflows/adr-support/schemas/adr-config.json +191 -0
- package/augment-extensions/workflows/adr-support/schemas/adr-metadata.json +172 -0
- package/augment-extensions/workflows/adr-support/templates/business-case.md +235 -0
- package/augment-extensions/workflows/adr-support/templates/madr-elaborate.md +197 -0
- package/augment-extensions/workflows/adr-support/templates/madr-simple.md +68 -0
- package/augment-extensions/workflows/adr-support/templates/nygard.md +84 -0
- package/augment-extensions/workflows/beads/rules/workflow.md +1 -1
- package/cli/dist/utils/__tests__/adr-validator.example.d.ts +6 -0
- package/cli/dist/utils/__tests__/adr-validator.example.d.ts.map +1 -0
- package/cli/dist/utils/__tests__/adr-validator.example.js +148 -0
- package/cli/dist/utils/__tests__/adr-validator.example.js.map +1 -0
- package/cli/dist/utils/adr-validator.d.ts +65 -0
- package/cli/dist/utils/adr-validator.d.ts.map +1 -0
- package/cli/dist/utils/adr-validator.js +203 -0
- package/cli/dist/utils/adr-validator.js.map +1 -0
- package/modules.md +40 -3
- package/package.json +1 -1
package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md
ADDED
|
@@ -0,0 +1,990 @@
|
|
|
1
|
+
# E-Commerce Platform Architecture Example
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document provides a comprehensive example of an e-commerce platform built with microservices architecture, focusing on high availability, scalability, and resilience.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## System Context
|
|
10
|
+
|
|
11
|
+
### Business Requirements
|
|
12
|
+
|
|
13
|
+
**Functional Requirements**
|
|
14
|
+
- Product catalog with search and filtering
|
|
15
|
+
- Shopping cart and checkout
|
|
16
|
+
- Order processing and tracking
|
|
17
|
+
- Payment processing
|
|
18
|
+
- User authentication and profiles
|
|
19
|
+
- Inventory management
|
|
20
|
+
- Shipping and fulfillment
|
|
21
|
+
- Customer reviews and ratings
|
|
22
|
+
|
|
23
|
+
**Non-Functional Requirements**
|
|
24
|
+
- **Availability**: 99.99% uptime (52 minutes downtime/year)
|
|
25
|
+
- **Scalability**: Handle 10,000 concurrent users, 1M products
|
|
26
|
+
- **Performance**: Page load < 2s, API response < 200ms
|
|
27
|
+
- **Security**: PCI DSS compliance for payments
|
|
28
|
+
- **Reliability**: Zero data loss, eventual consistency acceptable
|
|
29
|
+
|
|
30
|
+
### Scale Metrics
|
|
31
|
+
- 1 million registered users
|
|
32
|
+
- 100,000 daily active users
|
|
33
|
+
- 10,000 orders per day
|
|
34
|
+
- 1 million products in catalog
|
|
35
|
+
- Peak traffic: Black Friday (10x normal load)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Architecture Overview
|
|
40
|
+
|
|
41
|
+
### Microservices Decomposition
|
|
42
|
+
|
|
43
|
+
**Service Boundaries (Domain-Driven Design)**
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
47
|
+
│ API Gateway (Kong) │
|
|
48
|
+
│ Authentication, Rate Limiting, Routing │
|
|
49
|
+
└─────────────────────────────────────────────────────────────┘
|
|
50
|
+
│
|
|
51
|
+
┌─────────────────────┼─────────────────────┐
|
|
52
|
+
│ │ │
|
|
53
|
+
┌───────▼────────┐ ┌────────▼────────┐ ┌───────▼────────┐
|
|
54
|
+
│ User Service │ │ Product Service │ │ Order Service │
|
|
55
|
+
│ (Auth, Profile)│ │ (Catalog, Search│ │ (Checkout, │
|
|
56
|
+
│ │ │ Inventory) │ │ Fulfillment) │
|
|
57
|
+
└────────────────┘ └─────────────────┘ └────────────────┘
|
|
58
|
+
│ │ │
|
|
59
|
+
│ ┌────────▼────────┐ │
|
|
60
|
+
│ │ Search Service │ │
|
|
61
|
+
│ │ (Elasticsearch) │ │
|
|
62
|
+
│ └─────────────────┘ │
|
|
63
|
+
│ │
|
|
64
|
+
┌───────▼────────┐ ┌─────────────────┐ ┌───────▼────────┐
|
|
65
|
+
│ Payment Service│ │ Review Service │ │ Shipping Svc │
|
|
66
|
+
│ (Stripe, PayPal│ │ (Ratings, UGC) │ │ (Tracking, │
|
|
67
|
+
│ PCI Compliant)│ │ │ │ Carriers) │
|
|
68
|
+
└────────────────┘ └─────────────────┘ └────────────────┘
|
|
69
|
+
│ │ │
|
|
70
|
+
└─────────────────────┼─────────────────────┘
|
|
71
|
+
│
|
|
72
|
+
┌─────────▼─────────┐
|
|
73
|
+
│ Event Bus (Kafka) │
|
|
74
|
+
│ (Event Sourcing) │
|
|
75
|
+
└────────────────────┘
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Service Responsibilities
|
|
79
|
+
|
|
80
|
+
**1. User Service**
|
|
81
|
+
- User registration and authentication (JWT)
|
|
82
|
+
- Profile management
|
|
83
|
+
- Address book
|
|
84
|
+
- Preferences and settings
|
|
85
|
+
- OAuth integration (Google, Facebook)
|
|
86
|
+
|
|
87
|
+
**2. Product Service**
|
|
88
|
+
- Product catalog CRUD
|
|
89
|
+
- Category management
|
|
90
|
+
- Product attributes and variants
|
|
91
|
+
- Inventory tracking
|
|
92
|
+
- Price management
|
|
93
|
+
|
|
94
|
+
**3. Search Service**
|
|
95
|
+
- Full-text search (Elasticsearch)
|
|
96
|
+
- Faceted search and filtering
|
|
97
|
+
- Search suggestions and autocomplete
|
|
98
|
+
- Personalized search results
|
|
99
|
+
- Search analytics
|
|
100
|
+
|
|
101
|
+
**4. Order Service**
|
|
102
|
+
- Shopping cart management
|
|
103
|
+
- Order creation and processing
|
|
104
|
+
- Order history and tracking
|
|
105
|
+
- Order status updates
|
|
106
|
+
- Saga orchestration for distributed transactions
|
|
107
|
+
|
|
108
|
+
**5. Payment Service**
|
|
109
|
+
- Payment processing (Stripe, PayPal)
|
|
110
|
+
- PCI DSS compliance
|
|
111
|
+
- Payment method management
|
|
112
|
+
- Refund processing
|
|
113
|
+
- Fraud detection integration
|
|
114
|
+
|
|
115
|
+
**6. Review Service**
|
|
116
|
+
- Product reviews and ratings
|
|
117
|
+
- Review moderation
|
|
118
|
+
- Helpful votes
|
|
119
|
+
- Review analytics
|
|
120
|
+
|
|
121
|
+
**7. Shipping Service**
|
|
122
|
+
- Shipping rate calculation
|
|
123
|
+
- Carrier integration (FedEx, UPS, USPS)
|
|
124
|
+
- Shipment tracking
|
|
125
|
+
- Delivery notifications
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Technology Stack
|
|
130
|
+
|
|
131
|
+
### Services
|
|
132
|
+
- **Language**: Node.js (TypeScript) for most services
|
|
133
|
+
- **Framework**: Express.js, NestJS
|
|
134
|
+
- **API**: REST + GraphQL (BFF pattern)
|
|
135
|
+
|
|
136
|
+
### Data Storage
|
|
137
|
+
- **User Service**: PostgreSQL (relational, ACID)
|
|
138
|
+
- **Product Service**: PostgreSQL + Redis (caching)
|
|
139
|
+
- **Search Service**: Elasticsearch
|
|
140
|
+
- **Order Service**: PostgreSQL + Event Store
|
|
141
|
+
- **Review Service**: MongoDB (document-based)
|
|
142
|
+
- **Session Store**: Redis
|
|
143
|
+
|
|
144
|
+
### Infrastructure
|
|
145
|
+
- **Container Orchestration**: Kubernetes (EKS)
|
|
146
|
+
- **Service Mesh**: Istio (traffic management, security)
|
|
147
|
+
- **API Gateway**: Kong
|
|
148
|
+
- **Message Broker**: Apache Kafka
|
|
149
|
+
- **Cache**: Redis Cluster
|
|
150
|
+
- **CDN**: CloudFront
|
|
151
|
+
- **Load Balancer**: AWS ALB
|
|
152
|
+
|
|
153
|
+
### Observability
|
|
154
|
+
- **Monitoring**: Prometheus + Grafana
|
|
155
|
+
- **Logging**: ELK Stack (Elasticsearch, Logstash, Kibana)
|
|
156
|
+
- **Tracing**: Jaeger (distributed tracing)
|
|
157
|
+
- **Alerting**: PagerDuty
|
|
158
|
+
|
|
159
|
+
### CI/CD
|
|
160
|
+
- **Version Control**: GitHub
|
|
161
|
+
- **CI/CD**: GitHub Actions + ArgoCD
|
|
162
|
+
- **Container Registry**: ECR
|
|
163
|
+
- **Infrastructure as Code**: Terraform
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Implementation Details
|
|
168
|
+
|
|
169
|
+
### 1. Product Service Implementation
|
|
170
|
+
|
|
171
|
+
**Service Structure**
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// src/product-service/domain/product.entity.ts
|
|
175
|
+
export class Product {
|
|
176
|
+
id: string;
|
|
177
|
+
name: string;
|
|
178
|
+
description: string;
|
|
179
|
+
price: number;
|
|
180
|
+
categoryId: string;
|
|
181
|
+
inventory: number;
|
|
182
|
+
images: string[];
|
|
183
|
+
attributes: Record<string, any>;
|
|
184
|
+
createdAt: Date;
|
|
185
|
+
updatedAt: Date;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/product-service/application/product.service.ts
|
|
189
|
+
export class ProductService {
|
|
190
|
+
constructor(
|
|
191
|
+
private readonly productRepo: ProductRepository,
|
|
192
|
+
private readonly cache: CacheService,
|
|
193
|
+
private readonly eventBus: EventBus
|
|
194
|
+
) {}
|
|
195
|
+
|
|
196
|
+
async getProduct(productId: string): Promise<Product> {
|
|
197
|
+
// Check cache first
|
|
198
|
+
const cached = await this.cache.get(`product:${productId}`);
|
|
199
|
+
if (cached) return cached;
|
|
200
|
+
|
|
201
|
+
// Fetch from database
|
|
202
|
+
const product = await this.productRepo.findById(productId);
|
|
203
|
+
if (!product) throw new NotFoundException('Product not found');
|
|
204
|
+
|
|
205
|
+
// Cache for 1 hour
|
|
206
|
+
await this.cache.set(`product:${productId}`, product, 3600);
|
|
207
|
+
return product;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async updateInventory(productId: string, quantity: number): Promise<void> {
|
|
211
|
+
await this.productRepo.updateInventory(productId, quantity);
|
|
212
|
+
|
|
213
|
+
// Invalidate cache
|
|
214
|
+
await this.cache.delete(`product:${productId}`);
|
|
215
|
+
|
|
216
|
+
// Publish event
|
|
217
|
+
await this.eventBus.publish('product.inventory.updated', {
|
|
218
|
+
productId,
|
|
219
|
+
quantity,
|
|
220
|
+
timestamp: new Date()
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// src/product-service/infrastructure/product.controller.ts
|
|
226
|
+
@Controller('products')
|
|
227
|
+
export class ProductController {
|
|
228
|
+
constructor(private readonly productService: ProductService) {}
|
|
229
|
+
|
|
230
|
+
@Get(':id')
|
|
231
|
+
@UseInterceptors(CacheInterceptor)
|
|
232
|
+
async getProduct(@Param('id') id: string): Promise<Product> {
|
|
233
|
+
return await this.productService.getProduct(id);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
@Post()
|
|
237
|
+
@UseGuards(AuthGuard)
|
|
238
|
+
async createProduct(@Body() dto: CreateProductDto): Promise<Product> {
|
|
239
|
+
return await this.productService.createProduct(dto);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 2. Order Service with Saga Pattern
|
|
245
|
+
|
|
246
|
+
**Distributed Transaction Handling**
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// src/order-service/sagas/order-saga.ts
|
|
250
|
+
export class OrderSaga {
|
|
251
|
+
constructor(
|
|
252
|
+
private readonly orderRepo: OrderRepository,
|
|
253
|
+
private readonly eventBus: EventBus
|
|
254
|
+
) {}
|
|
255
|
+
|
|
256
|
+
async createOrder(orderData: CreateOrderDto): Promise<Order> {
|
|
257
|
+
const sagaId = uuidv4();
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
// Step 1: Create order (pending)
|
|
261
|
+
const order = await this.orderRepo.create({
|
|
262
|
+
...orderData,
|
|
263
|
+
status: 'PENDING',
|
|
264
|
+
sagaId
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Step 2: Reserve inventory
|
|
268
|
+
await this.eventBus.publish('inventory.reserve', {
|
|
269
|
+
sagaId,
|
|
270
|
+
orderId: order.id,
|
|
271
|
+
items: order.items
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Step 3: Process payment
|
|
275
|
+
await this.eventBus.publish('payment.process', {
|
|
276
|
+
sagaId,
|
|
277
|
+
orderId: order.id,
|
|
278
|
+
amount: order.total,
|
|
279
|
+
paymentMethod: orderData.paymentMethod
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Step 4: Create shipment
|
|
283
|
+
await this.eventBus.publish('shipment.create', {
|
|
284
|
+
sagaId,
|
|
285
|
+
orderId: order.id,
|
|
286
|
+
address: orderData.shippingAddress
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
return order;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
// Compensating transactions
|
|
292
|
+
await this.compensate(sagaId);
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private async compensate(sagaId: string): Promise<void> {
|
|
298
|
+
// Rollback in reverse order
|
|
299
|
+
await this.eventBus.publish('shipment.cancel', { sagaId });
|
|
300
|
+
await this.eventBus.publish('payment.refund', { sagaId });
|
|
301
|
+
await this.eventBus.publish('inventory.release', { sagaId });
|
|
302
|
+
await this.orderRepo.updateStatus(sagaId, 'CANCELLED');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Event handlers
|
|
306
|
+
@EventHandler('payment.completed')
|
|
307
|
+
async onPaymentCompleted(event: PaymentCompletedEvent): Promise<void> {
|
|
308
|
+
await this.orderRepo.updateStatus(event.orderId, 'PAID');
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
@EventHandler('payment.failed')
|
|
312
|
+
async onPaymentFailed(event: PaymentFailedEvent): Promise<void> {
|
|
313
|
+
await this.compensate(event.sagaId);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### 3. API Gateway Configuration
|
|
319
|
+
|
|
320
|
+
**Kong Gateway Setup**
|
|
321
|
+
|
|
322
|
+
```yaml
|
|
323
|
+
# kong.yml
|
|
324
|
+
_format_version: "2.1"
|
|
325
|
+
|
|
326
|
+
services:
|
|
327
|
+
- name: product-service
|
|
328
|
+
url: http://product-service:3000
|
|
329
|
+
routes:
|
|
330
|
+
- name: products-route
|
|
331
|
+
paths:
|
|
332
|
+
- /api/products
|
|
333
|
+
methods:
|
|
334
|
+
- GET
|
|
335
|
+
- POST
|
|
336
|
+
- PUT
|
|
337
|
+
- DELETE
|
|
338
|
+
plugins:
|
|
339
|
+
- name: rate-limiting
|
|
340
|
+
config:
|
|
341
|
+
minute: 100
|
|
342
|
+
policy: local
|
|
343
|
+
- name: cors
|
|
344
|
+
config:
|
|
345
|
+
origins:
|
|
346
|
+
- https://example.com
|
|
347
|
+
- name: jwt
|
|
348
|
+
config:
|
|
349
|
+
secret_is_base64: false
|
|
350
|
+
|
|
351
|
+
- name: order-service
|
|
352
|
+
url: http://order-service:3000
|
|
353
|
+
routes:
|
|
354
|
+
- name: orders-route
|
|
355
|
+
paths:
|
|
356
|
+
- /api/orders
|
|
357
|
+
plugins:
|
|
358
|
+
- name: rate-limiting
|
|
359
|
+
config:
|
|
360
|
+
minute: 50
|
|
361
|
+
- name: jwt
|
|
362
|
+
config:
|
|
363
|
+
secret_is_base64: false
|
|
364
|
+
- name: request-transformer
|
|
365
|
+
config:
|
|
366
|
+
add:
|
|
367
|
+
headers:
|
|
368
|
+
- X-User-Id:$(jwt.claims.sub)
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
### 4. High Availability Setup
|
|
374
|
+
|
|
375
|
+
**Kubernetes Deployment**
|
|
376
|
+
|
|
377
|
+
```yaml
|
|
378
|
+
# k8s/product-service-deployment.yml
|
|
379
|
+
apiVersion: apps/v1
|
|
380
|
+
kind: Deployment
|
|
381
|
+
metadata:
|
|
382
|
+
name: product-service
|
|
383
|
+
labels:
|
|
384
|
+
app: product-service
|
|
385
|
+
spec:
|
|
386
|
+
replicas: 3
|
|
387
|
+
strategy:
|
|
388
|
+
type: RollingUpdate
|
|
389
|
+
rollingUpdate:
|
|
390
|
+
maxSurge: 1
|
|
391
|
+
maxUnavailable: 0
|
|
392
|
+
selector:
|
|
393
|
+
matchLabels:
|
|
394
|
+
app: product-service
|
|
395
|
+
template:
|
|
396
|
+
metadata:
|
|
397
|
+
labels:
|
|
398
|
+
app: product-service
|
|
399
|
+
spec:
|
|
400
|
+
containers:
|
|
401
|
+
- name: product-service
|
|
402
|
+
image: product-service:1.0.0
|
|
403
|
+
ports:
|
|
404
|
+
- containerPort: 3000
|
|
405
|
+
env:
|
|
406
|
+
- name: DATABASE_URL
|
|
407
|
+
valueFrom:
|
|
408
|
+
secretKeyRef:
|
|
409
|
+
name: db-credentials
|
|
410
|
+
key: url
|
|
411
|
+
- name: REDIS_URL
|
|
412
|
+
valueFrom:
|
|
413
|
+
configMapKeyRef:
|
|
414
|
+
name: redis-config
|
|
415
|
+
key: url
|
|
416
|
+
resources:
|
|
417
|
+
requests:
|
|
418
|
+
memory: "256Mi"
|
|
419
|
+
cpu: "250m"
|
|
420
|
+
limits:
|
|
421
|
+
memory: "512Mi"
|
|
422
|
+
cpu: "500m"
|
|
423
|
+
livenessProbe:
|
|
424
|
+
httpGet:
|
|
425
|
+
path: /health
|
|
426
|
+
port: 3000
|
|
427
|
+
initialDelaySeconds: 30
|
|
428
|
+
periodSeconds: 10
|
|
429
|
+
readinessProbe:
|
|
430
|
+
httpGet:
|
|
431
|
+
path: /ready
|
|
432
|
+
port: 3000
|
|
433
|
+
initialDelaySeconds: 5
|
|
434
|
+
periodSeconds: 5
|
|
435
|
+
---
|
|
436
|
+
apiVersion: v1
|
|
437
|
+
kind: Service
|
|
438
|
+
metadata:
|
|
439
|
+
name: product-service
|
|
440
|
+
spec:
|
|
441
|
+
selector:
|
|
442
|
+
app: product-service
|
|
443
|
+
ports:
|
|
444
|
+
- protocol: TCP
|
|
445
|
+
port: 80
|
|
446
|
+
targetPort: 3000
|
|
447
|
+
type: ClusterIP
|
|
448
|
+
---
|
|
449
|
+
apiVersion: autoscaling/v2
|
|
450
|
+
kind: HorizontalPodAutoscaler
|
|
451
|
+
metadata:
|
|
452
|
+
name: product-service-hpa
|
|
453
|
+
spec:
|
|
454
|
+
scaleTargetRef:
|
|
455
|
+
apiVersion: apps/v1
|
|
456
|
+
kind: Deployment
|
|
457
|
+
name: product-service
|
|
458
|
+
minReplicas: 3
|
|
459
|
+
maxReplicas: 10
|
|
460
|
+
metrics:
|
|
461
|
+
- type: Resource
|
|
462
|
+
resource:
|
|
463
|
+
name: cpu
|
|
464
|
+
target:
|
|
465
|
+
type: Utilization
|
|
466
|
+
averageUtilization: 70
|
|
467
|
+
- type: Resource
|
|
468
|
+
resource:
|
|
469
|
+
name: memory
|
|
470
|
+
target:
|
|
471
|
+
type: Utilization
|
|
472
|
+
averageUtilization: 80
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### 5. Monitoring and Observability
|
|
476
|
+
|
|
477
|
+
**Prometheus Metrics**
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
// src/common/metrics/metrics.service.ts
|
|
481
|
+
import { Counter, Histogram, Registry } from 'prom-client';
|
|
482
|
+
|
|
483
|
+
export class MetricsService {
|
|
484
|
+
private readonly registry: Registry;
|
|
485
|
+
private readonly httpRequestDuration: Histogram;
|
|
486
|
+
private readonly httpRequestTotal: Counter;
|
|
487
|
+
private readonly orderTotal: Counter;
|
|
488
|
+
|
|
489
|
+
constructor() {
|
|
490
|
+
this.registry = new Registry();
|
|
491
|
+
|
|
492
|
+
this.httpRequestDuration = new Histogram({
|
|
493
|
+
name: 'http_request_duration_seconds',
|
|
494
|
+
help: 'Duration of HTTP requests in seconds',
|
|
495
|
+
labelNames: ['method', 'route', 'status_code'],
|
|
496
|
+
buckets: [0.1, 0.5, 1, 2, 5]
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
this.httpRequestTotal = new Counter({
|
|
500
|
+
name: 'http_requests_total',
|
|
501
|
+
help: 'Total number of HTTP requests',
|
|
502
|
+
labelNames: ['method', 'route', 'status_code']
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
this.orderTotal = new Counter({
|
|
506
|
+
name: 'orders_total',
|
|
507
|
+
help: 'Total number of orders',
|
|
508
|
+
labelNames: ['status']
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
this.registry.registerMetric(this.httpRequestDuration);
|
|
512
|
+
this.registry.registerMetric(this.httpRequestTotal);
|
|
513
|
+
this.registry.registerMetric(this.orderTotal);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
recordHttpRequest(method: string, route: string, statusCode: number, duration: number): void {
|
|
517
|
+
this.httpRequestDuration.observe({ method, route, status_code: statusCode }, duration);
|
|
518
|
+
this.httpRequestTotal.inc({ method, route, status_code: statusCode });
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
recordOrder(status: string): void {
|
|
522
|
+
this.orderTotal.inc({ status });
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
getMetrics(): Promise<string> {
|
|
526
|
+
return this.registry.metrics();
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**Distributed Tracing**
|
|
532
|
+
|
|
533
|
+
```typescript
|
|
534
|
+
// src/common/tracing/tracing.interceptor.ts
|
|
535
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
536
|
+
import { Observable } from 'rxjs';
|
|
537
|
+
import { tap } from 'rxjs/operators';
|
|
538
|
+
import * as opentracing from 'opentracing';
|
|
539
|
+
|
|
540
|
+
@Injectable()
|
|
541
|
+
export class TracingInterceptor implements NestInterceptor {
|
|
542
|
+
constructor(private readonly tracer: opentracing.Tracer) {}
|
|
543
|
+
|
|
544
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
545
|
+
const request = context.switchToHttp().getRequest();
|
|
546
|
+
const parentSpanContext = this.tracer.extract(
|
|
547
|
+
opentracing.FORMAT_HTTP_HEADERS,
|
|
548
|
+
request.headers
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
const span = this.tracer.startSpan(
|
|
552
|
+
`${request.method} ${request.route.path}`,
|
|
553
|
+
{ childOf: parentSpanContext }
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
span.setTag('http.method', request.method);
|
|
557
|
+
span.setTag('http.url', request.url);
|
|
558
|
+
span.setTag('service.name', 'product-service');
|
|
559
|
+
|
|
560
|
+
return next.handle().pipe(
|
|
561
|
+
tap({
|
|
562
|
+
next: () => {
|
|
563
|
+
span.setTag('http.status_code', 200);
|
|
564
|
+
span.finish();
|
|
565
|
+
},
|
|
566
|
+
error: (error) => {
|
|
567
|
+
span.setTag('http.status_code', error.status || 500);
|
|
568
|
+
span.setTag('error', true);
|
|
569
|
+
span.log({ event: 'error', message: error.message });
|
|
570
|
+
span.finish();
|
|
571
|
+
}
|
|
572
|
+
})
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## Scalability Patterns
|
|
581
|
+
|
|
582
|
+
### 1. Database Sharding (Product Service)
|
|
583
|
+
|
|
584
|
+
**Shard by Product Category**
|
|
585
|
+
|
|
586
|
+
```typescript
|
|
587
|
+
// src/product-service/infrastructure/sharding.service.ts
|
|
588
|
+
export class ShardingService {
|
|
589
|
+
private readonly shards = [
|
|
590
|
+
{ id: 'shard-1', categories: ['electronics', 'computers'] },
|
|
591
|
+
{ id: 'shard-2', categories: ['clothing', 'shoes'] },
|
|
592
|
+
{ id: 'shard-3', categories: ['home', 'garden'] }
|
|
593
|
+
];
|
|
594
|
+
|
|
595
|
+
getShardForCategory(category: string): string {
|
|
596
|
+
const shard = this.shards.find(s => s.categories.includes(category));
|
|
597
|
+
return shard?.id || 'shard-1'; // Default shard
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
async getProduct(productId: string, category: string): Promise<Product> {
|
|
601
|
+
const shardId = this.getShardForCategory(category);
|
|
602
|
+
const connection = await this.getConnection(shardId);
|
|
603
|
+
return await connection.query('SELECT * FROM products WHERE id = ?', [productId]);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### 2. Caching Strategy
|
|
609
|
+
|
|
610
|
+
**Multi-Level Caching**
|
|
611
|
+
|
|
612
|
+
```typescript
|
|
613
|
+
// src/common/cache/cache.service.ts
|
|
614
|
+
export class CacheService {
|
|
615
|
+
constructor(
|
|
616
|
+
private readonly redis: Redis,
|
|
617
|
+
private readonly cdn: CloudFront
|
|
618
|
+
) {}
|
|
619
|
+
|
|
620
|
+
async get(key: string): Promise<any> {
|
|
621
|
+
// Level 1: Application cache (in-memory)
|
|
622
|
+
const memCached = this.memCache.get(key);
|
|
623
|
+
if (memCached) return memCached;
|
|
624
|
+
|
|
625
|
+
// Level 2: Redis cache
|
|
626
|
+
const redisCached = await this.redis.get(key);
|
|
627
|
+
if (redisCached) {
|
|
628
|
+
this.memCache.set(key, redisCached, 60); // 1 minute
|
|
629
|
+
return JSON.parse(redisCached);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
async set(key: string, value: any, ttl: number): Promise<void> {
|
|
636
|
+
// Set in both caches
|
|
637
|
+
this.memCache.set(key, value, Math.min(ttl, 60));
|
|
638
|
+
await this.redis.setex(key, ttl, JSON.stringify(value));
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
async invalidate(pattern: string): Promise<void> {
|
|
642
|
+
// Invalidate in Redis
|
|
643
|
+
const keys = await this.redis.keys(pattern);
|
|
644
|
+
if (keys.length > 0) {
|
|
645
|
+
await this.redis.del(...keys);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Invalidate in CDN
|
|
649
|
+
await this.cdn.createInvalidation({
|
|
650
|
+
DistributionId: process.env.CDN_DISTRIBUTION_ID,
|
|
651
|
+
InvalidationBatch: {
|
|
652
|
+
Paths: { Quantity: 1, Items: [`/${pattern}*`] },
|
|
653
|
+
CallerReference: Date.now().toString()
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
### 3. Circuit Breaker Pattern
|
|
662
|
+
|
|
663
|
+
**Resilience Against Service Failures**
|
|
664
|
+
|
|
665
|
+
```typescript
|
|
666
|
+
// src/common/resilience/circuit-breaker.ts
|
|
667
|
+
import CircuitBreaker from 'opossum';
|
|
668
|
+
|
|
669
|
+
export class ResilientHttpClient {
|
|
670
|
+
private breakers: Map<string, CircuitBreaker> = new Map();
|
|
671
|
+
|
|
672
|
+
async call(serviceName: string, fn: () => Promise<any>): Promise<any> {
|
|
673
|
+
let breaker = this.breakers.get(serviceName);
|
|
674
|
+
|
|
675
|
+
if (!breaker) {
|
|
676
|
+
breaker = new CircuitBreaker(fn, {
|
|
677
|
+
timeout: 3000, // 3 seconds
|
|
678
|
+
errorThresholdPercentage: 50,
|
|
679
|
+
resetTimeout: 30000, // 30 seconds
|
|
680
|
+
rollingCountTimeout: 10000,
|
|
681
|
+
rollingCountBuckets: 10
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
breaker.on('open', () => {
|
|
685
|
+
console.error(`Circuit breaker opened for ${serviceName}`);
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
breaker.on('halfOpen', () => {
|
|
689
|
+
console.log(`Circuit breaker half-open for ${serviceName}`);
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
this.breakers.set(serviceName, breaker);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return await breaker.fire();
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Usage in Order Service
|
|
700
|
+
export class OrderService {
|
|
701
|
+
constructor(private readonly httpClient: ResilientHttpClient) {}
|
|
702
|
+
|
|
703
|
+
async createOrder(orderData: CreateOrderDto): Promise<Order> {
|
|
704
|
+
// Call payment service with circuit breaker
|
|
705
|
+
const payment = await this.httpClient.call(
|
|
706
|
+
'payment-service',
|
|
707
|
+
() => this.paymentClient.processPayment(orderData.payment)
|
|
708
|
+
);
|
|
709
|
+
|
|
710
|
+
return await this.orderRepo.create({ ...orderData, paymentId: payment.id });
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
## Security Implementation
|
|
718
|
+
|
|
719
|
+
### 1. Authentication & Authorization
|
|
720
|
+
|
|
721
|
+
**JWT-Based Authentication**
|
|
722
|
+
|
|
723
|
+
```typescript
|
|
724
|
+
// src/user-service/auth/auth.service.ts
|
|
725
|
+
import * as jwt from 'jsonwebtoken';
|
|
726
|
+
import * as bcrypt from 'bcrypt';
|
|
727
|
+
|
|
728
|
+
export class AuthService {
|
|
729
|
+
async login(email: string, password: string): Promise<{ accessToken: string; refreshToken: string }> {
|
|
730
|
+
const user = await this.userRepo.findByEmail(email);
|
|
731
|
+
if (!user) throw new UnauthorizedException('Invalid credentials');
|
|
732
|
+
|
|
733
|
+
const isValid = await bcrypt.compare(password, user.passwordHash);
|
|
734
|
+
if (!isValid) throw new UnauthorizedException('Invalid credentials');
|
|
735
|
+
|
|
736
|
+
const accessToken = jwt.sign(
|
|
737
|
+
{ sub: user.id, email: user.email, roles: user.roles },
|
|
738
|
+
process.env.JWT_SECRET,
|
|
739
|
+
{ expiresIn: '15m' }
|
|
740
|
+
);
|
|
741
|
+
|
|
742
|
+
const refreshToken = jwt.sign(
|
|
743
|
+
{ sub: user.id },
|
|
744
|
+
process.env.JWT_REFRESH_SECRET,
|
|
745
|
+
{ expiresIn: '7d' }
|
|
746
|
+
);
|
|
747
|
+
|
|
748
|
+
await this.tokenRepo.saveRefreshToken(user.id, refreshToken);
|
|
749
|
+
|
|
750
|
+
return { accessToken, refreshToken };
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
async refreshAccessToken(refreshToken: string): Promise<string> {
|
|
754
|
+
const payload = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
|
|
755
|
+
const isValid = await this.tokenRepo.validateRefreshToken(payload.sub, refreshToken);
|
|
756
|
+
|
|
757
|
+
if (!isValid) throw new UnauthorizedException('Invalid refresh token');
|
|
758
|
+
|
|
759
|
+
const user = await this.userRepo.findById(payload.sub);
|
|
760
|
+
return jwt.sign(
|
|
761
|
+
{ sub: user.id, email: user.email, roles: user.roles },
|
|
762
|
+
process.env.JWT_SECRET,
|
|
763
|
+
{ expiresIn: '15m' }
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### 2. PCI DSS Compliance (Payment Service)
|
|
770
|
+
|
|
771
|
+
**Secure Payment Processing**
|
|
772
|
+
|
|
773
|
+
```typescript
|
|
774
|
+
// src/payment-service/payment.service.ts
|
|
775
|
+
export class PaymentService {
|
|
776
|
+
constructor(
|
|
777
|
+
private readonly stripe: Stripe,
|
|
778
|
+
private readonly encryptionService: EncryptionService,
|
|
779
|
+
private readonly auditLog: AuditLogService
|
|
780
|
+
) {}
|
|
781
|
+
|
|
782
|
+
async processPayment(paymentData: PaymentDto): Promise<Payment> {
|
|
783
|
+
// Never store raw card data
|
|
784
|
+
// Use Stripe tokenization
|
|
785
|
+
const paymentIntent = await this.stripe.paymentIntents.create({
|
|
786
|
+
amount: paymentData.amount * 100, // Convert to cents
|
|
787
|
+
currency: 'usd',
|
|
788
|
+
payment_method: paymentData.stripeToken,
|
|
789
|
+
confirm: true,
|
|
790
|
+
metadata: {
|
|
791
|
+
orderId: paymentData.orderId,
|
|
792
|
+
customerId: paymentData.customerId
|
|
793
|
+
}
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
// Store only encrypted, tokenized reference
|
|
797
|
+
const payment = await this.paymentRepo.create({
|
|
798
|
+
orderId: paymentData.orderId,
|
|
799
|
+
amount: paymentData.amount,
|
|
800
|
+
status: paymentIntent.status,
|
|
801
|
+
stripePaymentIntentId: paymentIntent.id,
|
|
802
|
+
last4: paymentData.last4, // Only last 4 digits
|
|
803
|
+
cardBrand: paymentData.cardBrand
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
// Audit log for compliance
|
|
807
|
+
await this.auditLog.log({
|
|
808
|
+
action: 'PAYMENT_PROCESSED',
|
|
809
|
+
userId: paymentData.customerId,
|
|
810
|
+
orderId: paymentData.orderId,
|
|
811
|
+
amount: paymentData.amount,
|
|
812
|
+
timestamp: new Date(),
|
|
813
|
+
ipAddress: paymentData.ipAddress
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
return payment;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
---
|
|
822
|
+
|
|
823
|
+
## Deployment Strategy
|
|
824
|
+
|
|
825
|
+
### 1. Blue-Green Deployment
|
|
826
|
+
|
|
827
|
+
**Zero-Downtime Deployments**
|
|
828
|
+
|
|
829
|
+
```yaml
|
|
830
|
+
# k8s/blue-green-deployment.yml
|
|
831
|
+
apiVersion: v1
|
|
832
|
+
kind: Service
|
|
833
|
+
metadata:
|
|
834
|
+
name: product-service
|
|
835
|
+
spec:
|
|
836
|
+
selector:
|
|
837
|
+
app: product-service
|
|
838
|
+
version: blue # Switch to 'green' for deployment
|
|
839
|
+
ports:
|
|
840
|
+
- protocol: TCP
|
|
841
|
+
port: 80
|
|
842
|
+
targetPort: 3000
|
|
843
|
+
---
|
|
844
|
+
apiVersion: apps/v1
|
|
845
|
+
kind: Deployment
|
|
846
|
+
metadata:
|
|
847
|
+
name: product-service-blue
|
|
848
|
+
spec:
|
|
849
|
+
replicas: 3
|
|
850
|
+
selector:
|
|
851
|
+
matchLabels:
|
|
852
|
+
app: product-service
|
|
853
|
+
version: blue
|
|
854
|
+
template:
|
|
855
|
+
metadata:
|
|
856
|
+
labels:
|
|
857
|
+
app: product-service
|
|
858
|
+
version: blue
|
|
859
|
+
spec:
|
|
860
|
+
containers:
|
|
861
|
+
- name: product-service
|
|
862
|
+
image: product-service:1.0.0
|
|
863
|
+
---
|
|
864
|
+
apiVersion: apps/v1
|
|
865
|
+
kind: Deployment
|
|
866
|
+
metadata:
|
|
867
|
+
name: product-service-green
|
|
868
|
+
spec:
|
|
869
|
+
replicas: 3
|
|
870
|
+
selector:
|
|
871
|
+
matchLabels:
|
|
872
|
+
app: product-service
|
|
873
|
+
version: green
|
|
874
|
+
template:
|
|
875
|
+
metadata:
|
|
876
|
+
labels:
|
|
877
|
+
app: product-service
|
|
878
|
+
version: green
|
|
879
|
+
spec:
|
|
880
|
+
containers:
|
|
881
|
+
- name: product-service
|
|
882
|
+
image: product-service:1.1.0 # New version
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
### 2. CI/CD Pipeline
|
|
886
|
+
|
|
887
|
+
**GitHub Actions Workflow**
|
|
888
|
+
|
|
889
|
+
```yaml
|
|
890
|
+
# .github/workflows/deploy.yml
|
|
891
|
+
name: Deploy Product Service
|
|
892
|
+
|
|
893
|
+
on:
|
|
894
|
+
push:
|
|
895
|
+
branches: [main]
|
|
896
|
+
paths:
|
|
897
|
+
- 'services/product-service/**'
|
|
898
|
+
|
|
899
|
+
jobs:
|
|
900
|
+
test:
|
|
901
|
+
runs-on: ubuntu-latest
|
|
902
|
+
steps:
|
|
903
|
+
- uses: actions/checkout@v3
|
|
904
|
+
- uses: actions/setup-node@v3
|
|
905
|
+
with:
|
|
906
|
+
node-version: '18'
|
|
907
|
+
- run: npm ci
|
|
908
|
+
- run: npm test
|
|
909
|
+
- run: npm run test:e2e
|
|
910
|
+
|
|
911
|
+
build:
|
|
912
|
+
needs: test
|
|
913
|
+
runs-on: ubuntu-latest
|
|
914
|
+
steps:
|
|
915
|
+
- uses: actions/checkout@v3
|
|
916
|
+
- uses: docker/build-push-action@v4
|
|
917
|
+
with:
|
|
918
|
+
context: ./services/product-service
|
|
919
|
+
push: true
|
|
920
|
+
tags: |
|
|
921
|
+
${{ secrets.ECR_REGISTRY }}/product-service:${{ github.sha }}
|
|
922
|
+
${{ secrets.ECR_REGISTRY }}/product-service:latest
|
|
923
|
+
|
|
924
|
+
deploy:
|
|
925
|
+
needs: build
|
|
926
|
+
runs-on: ubuntu-latest
|
|
927
|
+
steps:
|
|
928
|
+
- uses: actions/checkout@v3
|
|
929
|
+
- uses: aws-actions/configure-aws-credentials@v2
|
|
930
|
+
with:
|
|
931
|
+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
932
|
+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
933
|
+
aws-region: us-east-1
|
|
934
|
+
- run: |
|
|
935
|
+
kubectl set image deployment/product-service-green \
|
|
936
|
+
product-service=${{ secrets.ECR_REGISTRY }}/product-service:${{ github.sha }}
|
|
937
|
+
kubectl rollout status deployment/product-service-green
|
|
938
|
+
kubectl patch service product-service -p '{"spec":{"selector":{"version":"green"}}}'
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
---
|
|
942
|
+
|
|
943
|
+
## Key Takeaways
|
|
944
|
+
|
|
945
|
+
### Architecture Decisions
|
|
946
|
+
|
|
947
|
+
1. **Microservices over Monolith**: Enables independent scaling and deployment
|
|
948
|
+
2. **Event-Driven Communication**: Decouples services, improves resilience
|
|
949
|
+
3. **API Gateway**: Single entry point, centralized security and routing
|
|
950
|
+
4. **Saga Pattern**: Manages distributed transactions without 2PC
|
|
951
|
+
5. **Circuit Breaker**: Prevents cascade failures
|
|
952
|
+
6. **Multi-Level Caching**: Reduces database load, improves performance
|
|
953
|
+
7. **Database per Service**: Data ownership, independent scaling
|
|
954
|
+
|
|
955
|
+
### Trade-offs
|
|
956
|
+
|
|
957
|
+
**Benefits**
|
|
958
|
+
- ✅ Independent scaling of services
|
|
959
|
+
- ✅ Technology diversity
|
|
960
|
+
- ✅ Fault isolation
|
|
961
|
+
- ✅ Faster deployments
|
|
962
|
+
- ✅ Team autonomy
|
|
963
|
+
|
|
964
|
+
**Challenges**
|
|
965
|
+
- ❌ Increased operational complexity
|
|
966
|
+
- ❌ Distributed transaction management
|
|
967
|
+
- ❌ Network latency
|
|
968
|
+
- ❌ Data consistency challenges
|
|
969
|
+
- ❌ Testing complexity
|
|
970
|
+
|
|
971
|
+
### Performance Metrics
|
|
972
|
+
|
|
973
|
+
- **Availability**: 99.99% (4 nines)
|
|
974
|
+
- **API Response Time**: P95 < 200ms
|
|
975
|
+
- **Order Processing**: 10,000 orders/day
|
|
976
|
+
- **Concurrent Users**: 10,000
|
|
977
|
+
- **Database Queries**: < 50ms (P95)
|
|
978
|
+
- **Cache Hit Rate**: > 80%
|
|
979
|
+
|
|
980
|
+
---
|
|
981
|
+
|
|
982
|
+
## References
|
|
983
|
+
|
|
984
|
+
- [Microservices Architecture](../rules/microservices-architecture.md)
|
|
985
|
+
- [Scalability Patterns](../rules/scalability.md)
|
|
986
|
+
- [Security Architecture](../rules/security.md)
|
|
987
|
+
- [Event-Driven Architecture](../rules/event-driven-architecture.md)
|
|
988
|
+
- [Saga Pattern](https://microservices.io/patterns/data/saga.html)
|
|
989
|
+
- [Circuit Breaker Pattern](https://martinfowler.com/bliki/CircuitBreaker.html)
|
|
990
|
+
|