Skip to content

ADR-0002. Kiến trúc phân lớp use-case (controller giữ mỏng)

TrườngGiá trị
StatusAccepted
Ngày2026-04-05
Người quyết địnhsupport-team
Thay thế

Bối cảnh

  • Helpdesk có bề mặt lớn: 11 controller và hàng chục thao tác trải dài tickets, agents, SLA, articles, surveys, feature requests, và notifications.
  • Đặt business logic trong controller (mẫu IGNIS phổ biến của fat service) sẽ tạo ra controller lan man và làm cùng một thao tác khó gọi từ cả handler HTTP worker BullMQ (ví dụ AutoAssignTicketUseCase chạy từ assignment worker, RunSlaMonitorUseCase từ SLA worker).

Quyết định

Áp dụng một lớp use-case: mỗi thao tác nghiệp vụ là một lớp single-responsibility trong src/application/use-cases/<domain>/<verb>.use-case.ts, đăng ký làm service DI trong configureServices(). Cả controller và worker đều phụ thuộc vào use-case qua injection.

  • Controller mỏng: thực thi truy cập theo merchant (assertMerchantAccess() + useRequestContext()), ánh xạ DTO, gọi một use-case. Không có decorator @authenticate; truy cập được thực thi trong handler.
  • Service thuần (PermissionService, CompensationCalculatorService, ProcessNotificationService, v.v.) giữ logic xuyên suốt dùng chung mà nhiều use-case tái dùng.
  • Repository chỉ giữ truy cập dữ liệu; schema tập trung trong @nx/core.

Hệ quả

ƯuNhược
Cùng thao tác tái dùng từ HTTP và worker (một đường code)Nhiều file nhỏ — số lượng lớp cao để điều hướng
Single responsibility làm mỗi thao tác kiểm thử được độc lậpDanh sách đăng ký DI trong application.ts dài và phải giữ đồng bộ
Controller mỏng; ranh giới rõ giữa transport và logicRủi ro use-case mồ côi (một cuộc gọi bị comment out để assignTicketUseCase chết — xem Vận hành Vấn đề đã biết)

Phương án đã cân nhắc

Tùy chọnVì sao bị từ chối
Fat service (một service mỗi controller)Khó chia sẻ một thao tác giữa điểm vào HTTP và worker; service phình to
Logic trong controllerKhông tái dùng được từ worker; vi phạm hướng dẫn dự án về giữ logic ngoài controller

Tham khảo

  • src/application/use-cases/** (lớp use-case)
  • src/application.ts configureServices() (đăng ký DI)
  • src/controllers/ticket/ticket.controller.ts (controller mỏng ủy thác cho use-case)
  • AGENTS.md — "Keep business logic in use-cases, not controllers"

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.