把 9 份需求單拆出的 35 條流程,往上抽象成 TFF 建系統時真正要關心的領域模型: 前中後台各自的 Bounded Context、每個脈絡的 Aggregate Root 與其 Aggregate/Value Object/Domain Event,以及脈絡之間的關係(上下游、防腐層 ACL、共享核心 SK)。
本圖的真正價值在最後一段「尚未找出的概念」——用 DDD 的蒸餾(distillation)反推:現有 9 條 workflow 只覆蓋了學員「說得出口」的痛,還有一整排領域概念沒被任何人提出,卻是系統跑得起來的前提。
⚠ 這是待驗證的策略草模(strawman),不是定案。DDD 第一原則:模型必須由領域專家點頭。每張卡片、每個缺口都是下一輪訪談的題目。
flowchart LR
classDef core fill:#f6d0c4,stroke:#cf5f3a,stroke-width:3px,color:#172033,font-weight:bold;
classDef sup fill:#d7e6f5,stroke:#3f6bad,stroke-width:2px,color:#172033;
classDef gen fill:#e7e1d3,stroke:#8f846d,stroke-width:2px,color:#172033;
classDef gap fill:#ffe6ac,stroke:#c58a1f,stroke-width:2px,stroke-dasharray:5 4,color:#172033,font-weight:bold;
classDef ext fill:#eeeae0,stroke:#999,stroke-width:1px,color:#555;
subgraph FRONT["🟩 前台 · 業務行銷"]
direction TB
CRM["客戶關係"]:::sup
PM["教育訓練專案"]:::sup
MKT["行銷推廣"]:::sup
end
subgraph MID["🟨 中台 · 企劃知識工廠"]
direction TB
KB["★ 課程知識庫"]:::core
CW["教材製作"]:::sup
end
subgraph BACK["🟦 後台 · 行政"]
direction TB
ENR["報名與異動"]:::sup
OPS["開課營運"]:::sup
ATT["出席與結案"]:::sup
FIN["金流財務"]:::sup
end
subgraph CROSS["⬜ 跨切 · 基礎通用"]
direction TB
NOTI["通知引擎"]:::gen
PII["資料治理/個資"]:::sup
IAM["身分與權限"]:::gen
DOC["文件槽"]:::gen
end
subgraph GAPS["🟧 缺口 · 尚未找出"]
direction TB
MEM["會員與續約"]:::gap
INS["講師管理"]:::gap
CERT["證照學分"]:::gap
PRICE["定價/退費"]:::gap
EFF["學習成效"]:::gap
ANA["營運分析"]:::gap
end
EXT["外部系統
官網·CRM·Webex/Teams·SurveyCake·LINE"]:::ext
CRM -->|成交建案 C/S| PM
MKT -->|招生| ENR
KB ==>|議題 OHS/PL| MKT
KB -.->|解析 SK| CW
INS -.->|供給講義| CW
INS -.->|供給師資| OPS
MEM -.->|續約訊號| KB
EFF -.->|課後成效| MEM
PM --> FIN
PM --> OPS
OPS --> ATT
OPS -.->|會議 ACL| EXT
ATT -.->|時數| CERT
ATT -.->|問卷| EFF
PRICE -.->|定價/退費規則| FIN
PRICE -.->|退費 gate| ENR
NOTI -.->|通知| OPS
PII -.->|掃描| KB
ENR <-->|ACL 寫回| EXT
FIN <-->|訂單/合約 ACL| EXT
style FRONT fill:#e4f2d8,stroke:#5f9b75,stroke-width:3px
style MID fill:#fdeec2,stroke:#c99a2a,stroke-width:3px
style BACK fill:#dff0f5,stroke:#3f6bad,stroke-width:3px
style CROSS fill:#ece4d6,stroke:#8f846d,stroke-width:3px
style GAPS fill:#ffe9c9,stroke:#c58a1f,stroke-width:3px,stroke-dasharray:7 4
| Entities | 窗口 Contact[] |
| Value Objects | 統編 TaxID · 產業別 · 規模 |
| Invariant | 每個窗口只隸屬一個機構;機構識別 = 統編 |
| Commands | registerContact() merge() |
| Events | InstitutionMerged |
| Repository | findByTaxId() · search(產業/規模) |
| Value Objects | 預估金額 Money · 課程偏好 · 階段 Stage(潛在→報價→成交/流失) |
| Invariant | 成交必連結一機構;一階段只能前進不可跳級 |
| Commands | qualify() quote() win() lose() |
| Events | OpportunityIdentified · OpportunityWon |
| Repository | findOpenByOwner() · findDormant(days) |
OpportunityWon 觸發「教育訓練專案」建立(Customer/Supplier)|⇄ ACL 讀 CRM(通用數碼)| Entities | 里程碑 Milestone[] |
| Value Objects | 型態 · 狀態 State(報價→簽約→招生→開課→收款→結案) · 到期日 |
| Invariant | 未簽約不得進招生;未收款不得結案(可設定) |
| Commands | quote() sign() openEnrollment() close() |
| Events | ProjectCreated · MilestoneOverdue · ProjectClosed |
| Repository | findActiveByStage() · findOverdue() |
OpportunityWon,串 金流/開課營運/出席結案;發提醒走 通知引擎| Value Objects | 通路(EDM/官網/LINE/社群) · SEO 關鍵字 · 版本 |
| Invariant | 一律經人審後才可發布(品牌 + 法遵) |
| Commands | generate(course,style) approve() publish() |
| Events | ContentPublished · EnrollmentSignalCollected |
| Repository | findHighPerforming() |
| Entities | 三元組 Triple · 證據 Evidence[] |
| Value Objects | 來源 Source · 來源權威 A/B/C · piiFlag · 審核狀態 |
| Invariant | 未核可卡不可被問答引用(D2 閘);未過驗證的髒三元組不進圖 |
| Commands | grade() approve() attachEvidence() |
| Events | KnowledgeExtracted · CardApproved |
| Repository | findApprovedByTopic() · findByAuthority(A/B/C) |
| Value Objects | 命名建議 · 市場依據 · 相近歷史成效 |
| Invariant | 只從核可卡集生成;產出必附引用來源 |
| Commands | recommend(季度) · Hybrid RAG(BM25+向量+圖→rerank) |
| Events | TopicRecommended |
| Value Objects | 命名風格 · 術語表(per-tenant few-shot 偏好集) |
| Commands | learnFromSamples() tune() |
| Value Objects | 版面結構 · 品牌合規狀態 |
| Invariant | 不動講師內容,只動版面;定稿前須過錯字+個資檢核 |
| Commands | parse() applyTemplate() checkQuality() archive() |
| Events | CoursewareStandardized · QualityIssueFlagged |
| Repository | findByCourse() |
| Value Objects | 版型 · 字體 · 色彩 · 重點框 |
| Invariant | 視覺規格須經高層核定(呼應董事長品牌訴求) |
| Value Objects | 學員快照 · 狀態(報名→異動→取消) |
| Commands | register() change() cancel() |
| Events | Enrolled · ChangeApplied |
| Value Objects | 異動類型 · 附件(退費同意書) |
| Invariant | 退費類異動需同意書齊全才可執行(人工 gate) |
| Commands | validate() chase()(缺件追件) apply() |
| Events | ChangeRequested · ChangeApplied |
| Repository | findPending() |
| Value Objects | 上課方式 · 會議連結 · 助教 |
| Commands | schedule() bindMeeting() |
| Entities | 檢核項 CheckItem[] |
| Value Objects | 燈號 紅黃綠 · 時點 T-7/T-3/T-1 |
| Invariant | 所有必要項全綠才判定 ready |
| Commands | inspect() remind() escalate() |
| Events | PrepItemMissing · OfferingReady |
| Repository | findByDate(未來7天) |
| Value Objects | 簽到退 · 上線時長 |
| Invariant | 出席時數達標才可發證 |
| Commands | reconcile()(Webex/Teams/LINE 三源合併) |
| Events | AttendanceConfirmed |
| Value Objects | 證號 · 學分/時數|結案包(簽到表/證書/送審/問卷) |
| Invariant | 結案包檢核齊全才可送出;主管覆核為最後閘 |
| Commands | issue() assemble() submit() |
| Events | CertificateIssued · CourseClosed |
| Value Objects | 課程 · 金額 Money · 方案 |
| Invariant | 訂單金額須與課程價目一致(不一致落人工) |
| Commands | place() reconcile() |
| Events | OrderPlaced |
| Value Objects | 合約編號 · 用印 · 附件|付款狀態 · 匯款日 |
| Commands | draft() assignNumber() fileSigned()(OCR) settle() |
| Events | ContractSigned · PaymentReceived |
| Repository | findByNumber() · findOverdueReceivable() |
| Value Objects | 收件人 · 通路(LINE/Email/簡訊) · 模板 · 狀態 |
| Commands | send() retry() |
| Events | NotificationSent · NotificationFailed |
| Value Objects | piiFlag · 位置 · 動作(遮罩/hash/加密) · 來源分級 |
| Invariant | 受監管租戶:未過 PII 掃描不得入庫/簽約(合約門檻) |
| Commands | scan()(Presidio+NER) redact() |
| Events | PIIFlagged |
| Value Objects | 會籍狀態 · 續約日 · 參與度(出席/影片觀看) |
| Invariant | 續約決策應綁定 學習成效 + 參與度(與缺口 G6 連動) |
| Events | MembershipRenewed · MemberChurned |
| Value Objects | 專長 · 鐘點費 · 檔期 · 評鑑分 |
| Events | InstructorEngaged · SessionRated |
| Value Objects | 證照別 · 換證時數 · 主管機關(金研院/證基會/信託公會) |
| Invariant | 時數認列須對應核准課程;申報錯誤可追溯責任 |
| Events | CreditAccredited · HoursFiled |
| Value Objects | 公開班/專班價 · 會員價 · 團報折扣 · 退費級距(開課前天數) |
| Invariant | 訂單金額與退費比例皆須由規則導出,不靠人腦 |
| Value Objects | 滿意度 · 學習成果 · 課後追蹤指標 |
| Events | EffectivenessScored |
| Value Objects | 週報 · 開班率 · 營收|資源 · 檔期 · 衝突 |
| Invariant | 同一資源(室/助教)同時段不可重複預約 |
| 缺口 | DDD 型別 | 為什麼是缺口(線索) | 建議分類 | 訪談要問 |
|---|---|---|---|---|
| G2 會員與續約 Membership | Bounded Context | 「續約」在多份需求單被當成價值驅動,18 支會員影片 9 支零觀看也點名會員經營,但沒有任一 workflow 擁有會員生命週期。聯誼會、會員影片、續約全散落。 | 核心 | 會員分級?續約決策看什麼?誰負責會員經營? |
| G3 證照與學分 CE Credits | Bounded Context / Aggregate | 金融從業的在職訓練換證時數是金融研訓院的招牌價值,但只在「結案」以「證號」露一角,缺時數認列、主管機關(金研院/證基會/信託公會)送審。 | 核心? | 哪些課給時數?如何報主管機關?時數錯了誰扛? |
| G1 講師管理 Instructor | Bounded Context | 講師散見 課程/教材/巡檢/結案,卻無脈絡擁有講師本身:師資庫、鐘點費、檔期、評鑑、助教(G8)。教材/開課都上游依賴它。 | 支援 | 講師怎麼找/評/排?鐘點費規則?助教誰管? |
| G4/G5 定價與退費 Pricing / Refund | Aggregate / Specification | PM 有「報價試算」,但定價規則(公開班/專班/會員價/團報)與退費比例(開課前天數)是規則型知識,被藏在人腦與 Excel,沒被模型化。 | 支援 | 價目怎麼定?折扣誰能給?退費比例級距? |
| G6 學習成效 Effectiveness | Subdomain | 問卷資料在結案已收,但「課程好不好 → 要不要續約 / 改哪門課」的成效評估閉環沒人建。它正是 G2 續約 與 KB 成效回饋 的中間環節。 | 支援 | 怎麼定義「課成功」?滿意度以外還看什麼? |
| G7/G9 營運分析與排程 Analytics / Scheduling | Read Model / Subdomain | 週報/Dashboard/開班率散在 PM+CS,無統一讀模型;教室/會議室/助教資源排程與衝突偵測只在巡檢露臉,無擁有者。 | 支援 | 誰要看什麼數字?資源(室/助教)如何避免撞期? |