Skip to content

Architecture

1. System Context (C4 L1)

2. Container View (C4 L2)

Không có Kafka consumer, không có BullMQ worker. Fan-out nền duy nhất là WebSocket emitter backed bởi Redis.

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

LayerTrách nhiệm
RoutesBề mặt HTTP; route tùy chỉnh khai báo trong RestPaths + definitions.ts của controller
ControllersAuth + cổng permission, map DTO, fire WS notify khi submit
ServicesLogic subscribe/unsubscribe/stats của SubscriberService
RepositoriesTruy vấn Drizzle, soft-delete, rollup getStatistics()
ComponentsApplicationWebSocketComponent — Redis emitter + socket event service

4. Chỉ mục State Machine

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

Cả hai dùng IGNIS Statuses. Chuyển trạng thái không được máy thực thi — admin di chuyển Inquiry tự do qua CRUD update; chuyển trạng thái Subscriber được điều khiển bởi SubscriberService (subscribe ↔ unsubscribe). Các sơ đồ dưới đây thể hiện vòng đời dự kiến.

Inquiry

TừSự kiệnĐếnGuards
[*]POST /inquiries/submitNEWstatus mặc định
NEWadmin updatePROCESSINGkhông (thủ công)
PROCESSINGadmin updateCOMPLETED / CLOSEDkhông (thủ công)
*admin updateCANCELLEDkhông (thủ công)

Subscriber

TừSự kiệnĐếnGuards
[*]subscribe (không có dòng)ACTIVATEDemail unique
ACTIVATEDsubscribe (active hiện có)ACTIVATEDidempotent — trả về dòng hiện có
DEACTIVATEDsubscribeACTIVATEDreactivate, clear unsubscribedAt
ACTIVATEDunsubscribe(token)DEACTIVATEDtoken phải resolve về một dòng

5. Kịch bản Runtime

5.1 Submit yêu cầu + notify real-time

BướcChi tiết
1-3Yêu cầu lưu với status=NEW, type=000_CONSULT mặc định trừ khi override
4-6WS notify là fire-and-forget (không await); skip nếu emitter chưa ready
6Broadcast tới outreach/inquiriesoutreach/inquiries/{id} qua Promise.allSettled
7Trả 201 bất kể kết quả 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ý
AuthNJWT (Issuer = identity), JWKS verify mỗi request; endpoint public skip auth
AuthZPermission Casbin seed qua migration; CRUD + stats có cổng, submit/subscribe/unsubscribe public mở
i18nSubscriber.locale (vi/en) chọn ngôn ngữ newsletter; nhãn permission mang { en, vi }
LoggingKey-value có cấu trúc (key: %s); WS notify log inquiry id + rooms
TracingNo-op (chưa nối tracer)
Idempotencysubscribe idempotent theo email; unsubscribe idempotent (áp lại DEACTIVATED là 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.