feat(deploy): production deployment setup and fixes
- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma binaryTargets for openssl 3.0 - nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal cron, http->https redirect - prisma: add origin_goods.delisted migration, sync missing schema (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz - api: CORS wildcard reflection, helmet CORP cross-origin, price backfill in persistProductDetail, categoryIcon ancestor fallback, mediaByColor per-color gallery in public goods detail - admin: /admin base path (vite + router) - import-data.mjs: udt_name casting, serial sequence advance fix
This commit is contained in:
@@ -1,106 +0,0 @@
|
||||
---
|
||||
title: Single Responsibility for Services
|
||||
impact: CRITICAL
|
||||
impactDescription: "40%+ improvement in testability"
|
||||
tags: architecture, services, single-responsibility
|
||||
---
|
||||
|
||||
## Single Responsibility for Services
|
||||
|
||||
Each service should have a single, well-defined responsibility. Avoid "god services" that handle multiple unrelated concerns. If a service name includes "And" or handles more than one domain concept, it likely violates single responsibility. This reduces complexity and improves testability by 40%+.
|
||||
|
||||
**Incorrect (god service anti-pattern):**
|
||||
|
||||
```typescript
|
||||
// God service anti-pattern
|
||||
@Injectable()
|
||||
export class UserAndOrderService {
|
||||
constructor(
|
||||
private userRepo: UserRepository,
|
||||
private orderRepo: OrderRepository,
|
||||
private mailer: MailService,
|
||||
private payment: PaymentService,
|
||||
) {}
|
||||
|
||||
async createUser(dto: CreateUserDto) {
|
||||
const user = await this.userRepo.save(dto);
|
||||
await this.mailer.sendWelcome(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
async createOrder(userId: string, dto: CreateOrderDto) {
|
||||
const order = await this.orderRepo.save({ userId, ...dto });
|
||||
await this.payment.charge(order);
|
||||
await this.mailer.sendOrderConfirmation(order);
|
||||
return order;
|
||||
}
|
||||
|
||||
async calculateOrderStats(userId: string) {
|
||||
// Stats logic mixed in
|
||||
}
|
||||
|
||||
async validatePayment(orderId: string) {
|
||||
// Payment logic mixed in
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Correct (focused services with single responsibility):**
|
||||
|
||||
```typescript
|
||||
// Focused services with single responsibility
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(private userRepo: UserRepository) {}
|
||||
|
||||
async create(dto: CreateUserDto): Promise<User> {
|
||||
return this.userRepo.save(dto);
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<User> {
|
||||
return this.userRepo.findOneOrFail({ where: { id } });
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class OrdersService {
|
||||
constructor(private orderRepo: OrderRepository) {}
|
||||
|
||||
async create(userId: string, dto: CreateOrderDto): Promise<Order> {
|
||||
return this.orderRepo.save({ userId, ...dto });
|
||||
}
|
||||
|
||||
async findByUser(userId: string): Promise<Order[]> {
|
||||
return this.orderRepo.find({ where: { userId } });
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class OrderStatsService {
|
||||
constructor(private orderRepo: OrderRepository) {}
|
||||
|
||||
async calculateForUser(userId: string): Promise<OrderStats> {
|
||||
// Focused stats calculation
|
||||
}
|
||||
}
|
||||
|
||||
// Orchestration in controller or dedicated orchestrator
|
||||
@Controller('orders')
|
||||
export class OrdersController {
|
||||
constructor(
|
||||
private orders: OrdersService,
|
||||
private payment: PaymentService,
|
||||
private notifications: NotificationService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
async create(@CurrentUser() user: User, @Body() dto: CreateOrderDto) {
|
||||
const order = await this.orders.create(user.id, dto);
|
||||
await this.payment.charge(order);
|
||||
await this.notifications.sendOrderConfirmation(order);
|
||||
return order;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference: [NestJS Providers](https://docs.nestjs.com/providers)
|
||||
Reference in New Issue
Block a user