Skip to content

Architecture

1. System Context (C4 L1)

2. Container View (C4 L2)

Không có Kafka consumer, không có BullMQ worker. Cơ chế fan-out nền duy nhất là WebSocket emitter dựa trên Redis.

3. Component View (C4 L3) - Phân lớp nội bộ

LớpTrách nhiệm
RoutesGiao diện HTTP; các route tuỳ chỉnh khai báo trong RestPaths + definitions.ts của controller
ControllersXác thực + chốt kiểm tra permission, ánh xạ DTO, kích hoạt thông báo WS khi gửi
ServicesLogic đăng ký/huỷ đăng ký/thống kê của SubscriberService
RepositoriesTruy vấn Drizzle, soft-delete, tổng hợp getStatistics()
ComponentsApplicationWebSocketComponent - Redis emitter + socket event service

4. Chỉ mục máy trạng thái

EntityTrạng tháiSơ đồ
InquiryNEW, PROCESSING, COMPLETED, CLOSED, CANCELLED→ jump
SubscriberACTIVATED, DEACTIVATED, ARCHIVED→ jump

Cả hai dùng IGNIS Statuses. Việc chuyển trạng thái không được máy ép buộc - admin chuyển Inquiry tự do qua CRUD update; còn các chuyển trạng thái của Subscriber được điều khiển bởi SubscriberService (đăng ký ↔ huỷ đăng ký). Các sơ đồ dưới đây thể hiện vòng đời dự kiến.

Inquiry

TừSự kiệnĐếnĐiều kiện
[*]POST /inquiries/submitNEWstatus mặc định
NEWadmin cập nhậtPROCESSINGkhông (thủ công)
PROCESSINGadmin cập nhậtCOMPLETED / CLOSEDkhông (thủ công)
*admin cập nhậtCANCELLEDkhông (thủ công)

Subscriber

TừSự kiệnĐếnĐiều kiện
[*]subscribe (chưa có dòng)ACTIVATEDemail duy nhất
ACTIVATEDsubscribe (đang hoạt động)ACTIVATEDidempotent - trả về dòng hiện có
DEACTIVATEDsubscribeACTIVATEDkích hoạt lại, xoá unsubscribedAt
ACTIVATEDunsubscribe(token)DEACTIVATEDtoken phải trỏ về một dòng

5. Kịch bản Runtime

5.1 Gửi yêu cầu + thông báo theo thời gian thực

BướcChi tiết
1-3Yêu cầu được lưu với status=NEW, type=000_CONSULT mặc định trừ khi ghi đè
4-6Thông báo WS theo kiểu fire-and-forget (không await); bỏ qua nếu emitter chưa sẵn sàng
6Phát tới outreach/inquiriesoutreach/inquiries/{id} qua Promise.allSettled
7Trả 201 bất kể kết quả của WS

5.2 Subscribe (idempotent)

5.3 Unsubscribe (token)

6. Mối quan tâm xuyên suốt

Mối quan tâmCách service này xử lý
Xác thực (AuthN)JWT (Issuer = identity), JWKS được xác thực ở mỗi request; các endpoint công khai bỏ qua xác thực
Phân quyền (AuthZ)Permission của Casbin được seed qua migration; CRUD + thống kê có kiểm tra quyền, còn submit/subscribe/unsubscribe công khai để mở
i18nSubscriber.locale (vi/en) chọn ngôn ngữ newsletter; nhãn permission mang { en, vi }
LoggingDạng key-value có cấu trúc (key: %s); thông báo WS ghi log inquiry id + danh sách phòng
TracingKhông hoạt động (chưa nối tracer)
Idempotencysubscribe idempotent theo email; unsubscribe idempotent (áp lại DEACTIVATED vẫn an toàn)
Soft-deleteSoftDeletableRepository (deletedAt); filter mặc định deletedAt IS NULL
IDsSnowflake qua IdGenerator, worker 10; unsubscribeToken cũng là một Snowflake

7. Trang liên quan

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