共用領域物件 (Domain Model) OOA
來源:fp 性質:跨 feature 共用 OOA(Published Language 的結構面);欄位級 single source of truth 落於此。 消費方 OOA:rough-cut-scheduler OOA 下游:domain-model.pseudo.md(尚未建立) 狀態:已簽核(2026-06-09,含 eligibility cascade)
1. 領域詞彙(Ubiquitous Language)
主體類 / 具識別(Entities)
- §DM-OA-1
- §DM-OA-2
- 詞彙:製程樹
- 英文:
VSM - 說明:per-工單 instance:工單釋放時實例化的製程路徑(樹狀、多上游匯流)
- §DM-OA-3
- 詞彙:工序節點
- 英文:
VSMNode - 說明:VSM 內的節點,由
OperationCoordinate識別;帶製程時間(DataBox)與物料需求
- §DM-OA-4
- 詞彙:資源
- 英文:
Resource - 說明:產能承載主體(鍵=資源×日);持
WorkCapability、identityResourceId(如 LA01/LA02)。WorkCenter退為純WorkCenterIdVO(活在能力 pair 與OperationCoordinate),不另建實體;資源歸屬工作站本期不建模(YAGNI)
共用值物件(Value Objects)
- §DM-OA-5
- §DM-OA-6
- §DM-OA-7
- 詞彙:物料需求
- 英文:
MaterialRequirement - 說明:領料清單項;可標
pickAt(中途領料節點,預設第一站)
- §DM-OA-8
- 詞彙:工作能力
- 英文:
WorkCapability - 說明:資源能做的製程-工作站集合,存為
Map<ProcessId, Set<WorkCenterId>>;canPerform(processId, workCenterId)本期=exact 比對,未來「鄰近工作站」relax 點集中於此(本期不實作)
時間/資源類(Temporal / Capacity)
- §DM-OA-9
- 詞彙:資源主檔
- 英文:
ResourcePool - 說明:「有哪些資源、各能做什麼」的主檔;
eligible(processId, workCenterId)回傳該製程-工作站的 eligible 資源集合。與AvailableCapacity(何時有空)分離(SRP)
- §DM-OA-10
- §DM-OA-11
- 詞彙:產能格
- 英文:
CapacitySlot - 說明:單一(資源×日)的可用量與其佔用清單
- §DM-OA-12
- 詞彙:佔用
- 英文:
Occupation - 說明:對某 slot 的一筆佔用,帶 occupier(工序座標)+ source
- §DM-OA-13
查詢/輸出投影(Query / Output Projection)
- §DM-OA-14
- §DM-OA-15
- 詞彙:粗排節點結果
- 英文:
ScheduledNode - 說明:每節點掛
leanPlayDate/lsd/sequence;快照複製輸入節點參數,可回溯
2. 關係草圖(全景)
三個子系統,靠兩個「接縫」串起來:
OperationCoordinate接「製程樹 ↔ 產能」、VSMNode接「製程樹 ↔ 結果」。下方 §3 各子系統一張小圖。
【子系統 A:製程樹】
ProductionOrder ──has 1──> VSM ──composed of *──> VSMNode
VSM ──designates 0..1──> VSMNode(takt)
VSMNode ──tree link──> VSMNode
VSMNode ──has──> DataBox / MaterialRequirement
VSMNode ──identified by──> OperationCoordinate ──┐(接縫 1)
│
【子系統 B:資源主檔 + 產能佔用】 │
ResourcePool ──*──> Resource ──has──> WorkCapability(製程→工作站集合)
Resource ──eligible(製程-工作站)──> VSMNode(接縫 1,經 OperationCoordinate)
AvailableCapacity ──*──> CapacitySlot(資源×日) │
CapacitySlot ──keyed by──> ResourceId │
CapacitySlot ──*──> Occupation │
Occupation ──occupier──> OperationCoordinate ◀────┘
Occupation ──source──> {FREEZE | IN_RUN}
【子系統 C:粗排結果】
RoughScheduleResult ──*──> ScheduledNode
ScheduledNode ──snapshot of──> VSMNode ◀──(接縫 2,可回溯)
3. 類別圖(拆成三張子圖)
子圖 A — 製程樹(Order & Routing)
classDiagram direction TB class ProductionOrder { -poNo: PoNo -product: PartNo -qty: int -dueDate: LocalDate -prioritySeq: int +vsm() VSM } class VSM { -nodes: List~VSMNode~ +takt() VSMNode +lastNode() VSMNode +allNodes() List~VSMNode~ +childrenNodes() List~VSMNode~ +parentNode() VSMNode +upstreamOf(node) List~VSMNode~ +downstreamOf(node) List~VSMNode~ } class VSMNode { -coordinate: OperationCoordinate -dataBox: DataBox -materials: List~MaterialRequirement~ +upstream() List~VSMNode~ +downstream() List~VSMNode~ } class OperationCoordinate { <<value object>> -poNo: PoNo -workOrderNo: String -partNo: PartNo -opSeq: int -processId: ProcessId -workCenterId: WorkCenterId -qty: int } class DataBox { <<value object>> -cycleTime: Duration -changeOverTime: Duration -waitingTime: Duration -transferTime: Duration } class MaterialRequirement { <<value object>> -partNo: PartNo -qty: int -pickAt: OperationCoordinate } note for VSM "導航共用契約:upstreamOf/downstreamOf 回傳『遞移』節點集且依拓樸序;allNodes 供正/反向拓樸走訪;lastNode=樹的唯一匯流末站(sink)" ProductionOrder "1" *-- "1" VSM VSM "1" *-- "*" VSMNode VSM "1" --> "0..1" VSMNode : takt VSMNode "*" --> "*" VSMNode : downstream VSMNode "1" *-- "1" DataBox VSMNode "1" *-- "*" MaterialRequirement VSMNode "1" --> "1" OperationCoordinate : identified by
子圖 B — 資源主檔 + 產能佔用(Capacity,鍵=資源×日)
classDiagram direction TB class ResourcePool { -resources: List~Resource~ +eligible(processId, workCenterId) List~Resource~ } class Resource { -id: ResourceId -capability: WorkCapability +canPerform(processId, workCenterId) boolean } class WorkCapability { <<value object>> -byProcess: Map < ProcessId, Set < WorkCenterId > > +canPerform(processId, workCenterId) boolean } class AvailableCapacity { -slots: List~CapacitySlot~ +isAvailable(resourceId, day) boolean +slotOf(resourceId, day) CapacitySlot } class CapacitySlot { -resourceId: ResourceId -day: LocalDate -capacity: Duration -occupations: List~Occupation~ +remaining() Duration +occupy(occ) void } class Occupation { <<value object>> -occupier: OperationCoordinate -source: CapacityOccupationSource -amount: Duration } class CapacityOccupationSource { <<enumeration>> FREEZE IN_RUN } class OperationCoordinate { <<value object>> } note for WorkCapability "canPerform 本期=exact 製程-工作站;未來『鄰近工作站』relax 點集中於此(本期不實作)" note for OperationCoordinate "共用 VO;完整欄位見子圖 A。不含 resourceId——粗排不指派實際資源" note for CapacitySlot "鍵=資源×日;occupations 只存 FREEZE(外部、唯讀)" note for CapacityOccupationSource "IN_RUN 由引擎 per-run overlay 持有,不落地於本 model" ResourcePool "1" o-- "*" Resource Resource "1" *-- "1" WorkCapability AvailableCapacity "1" o-- "*" CapacitySlot CapacitySlot "*" --> "1" Resource : keyed by(資源×日) CapacitySlot "1" o-- "*" Occupation Occupation "1" --> "1" OperationCoordinate : occupier Occupation "1" --> "1" CapacityOccupationSource
子圖 C — 粗排結果(Result,快照可回溯)
classDiagram direction TB class RoughScheduleResult { -nodes: List~ScheduledNode~ +bySequence() List~ScheduledNode~ } class ScheduledNode { -coordinate: OperationCoordinate -dataBox: DataBox -leanPlayDate: LocalDate -lsd: LocalDate -sequence: int } class VSMNode { } note for VSMNode "完整定義見子圖 A" RoughScheduleResult "1" *-- "*" ScheduledNode ScheduledNode ..> VSMNode : 可回溯(快照自)
設計決策(步驟 1–2 已拍板 / 待確認)
已拍板(2026-06-05)
-
VSM = per-工單 instance:
ProductionOrder *──組合──> VSM,VSMNode綁工單。與 Stage 2 identity「工單-料號-…」一致,不 cascade 回 Stage 2。 -
RoughScheduleResult= 快照複製:ScheduledNode攜帶當時節點參數的不可變副本,符合「不反查、減少資訊誤差」;result 為獨立可追溯 record。 -
抽出共用 VO
OperationCoordinate:VSMNode與Occupation.occupier共用(§3 兩個接縫之一);識別欄位順序 opSeq → processId → workCenterId。 -
產能鍵=工作站×日(非節點×日):不同工單的節點搶同一實體工作站(§RCS-FS-2 排擠本質)。屬 OOA 精修,Stage 2「節點×日」用語不動。
-
Freeze 不做獨立類別:實現為
source=FREEZE的Occupation(進來只標記哪些產能被佔)。 -
IN_RUN 不落地於本 model:共用
CapacitySlot只存 FREEZE;本次 run 的暫時佔用由引擎 overlay 持有 →「不寫回」為結構保證。
已拍板(2026-06-08)
- VSM 導航為 Published Language 共用契約:
upstreamOf/downstreamOf回傳遞移節點集且依拓樸序、allNodes可正/反向拓樸走訪、lastNode為樹的唯一匯流末站。粗排為首個消費方(§2/§4、§RCS-FS-1 fallback),未來 feature 一律依此契約,不各自定義。
已拍板(2026-06-09,eligibility cascade,承 FS #17)
- 產能鍵再下沉:工作站×日 → 資源×日:一個工作站(製程-工作站)底下對應多台資源(如 L 底下 LA01/LA02),
CapacitySlot改鍵(resourceId, day)。上方 2026-06-05「產能鍵=工作站×日」決策併此細化,同方向更細一層,非推翻。 - 新增
Resource/WorkCapability/ResourcePool:Resource為產能承載主體、持WorkCapability;ResourcePool管資源主檔 +eligible(processId, workCenterId)查詢,與AvailableCapacity(何時有空)分離(SRP:能力為相對靜態主檔、產能為隨時間變動的讀模型;引擎在 overlay 層合用)。 - eligibility = exact 製程-工作站 pair(FS-faithful):
WorkCapability存Map<ProcessId, Set<WorkCenterId>>、canPerform本期 exact;「鄰近工作站」彈性點預留於canPerform內、本期不實作(YAGNI)。LASR-L/LASR-L2差在工作站(L/L2)、製程同為 LASR。 WorkCenter實體移除、Resource→WorkCenter歸屬不建模:WorkCenterId降為純 VO(活在能力 pair 與OperationCoordinate);eligibility 完全由能力的製程-工作站 pair 驅動,不靠歸屬。OperationCoordinate不加 resourceId:粗排不指派實際資源、輸出不含資源;資源是引擎 overlay 的暫時分配(見../rough-cut-scheduler/rough-cut-scheduler.ooa.md的ResourceAllocationStrategy)。
備註(非阻擋)
Leadtime(ceil((CT×qty+CO)/480)、受 x-y 三策略影響)不放本 model,屬引擎 Strategy(../rough-cut-scheduler/rough-cut-scheduler.ooa.md)。- 佔用顆粒度目前為「天」(節點佔 L 連續日)。
- Repository(取外部物件)本輪不引入,留實作/消費方 OOA。
4. SOLID 審查 + 設計模式
Part A — SOLID
✅ 穩固
- SRP:VO 各司其職(
OperationCoordinate識別、DataBox製程時間、MaterialRequirement物料);VSM管樹導航、VSMNode管節點資料+鄰接、CapacitySlot管單格產能。ResourcePool管「資源主檔 + eligibility 查詢」、AvailableCapacity管「資源×日 可用性」,兩關注點分離;eligibility 邏輯收斂於WorkCapability.canPerform。 - DIP:純 domain、零 infra 依賴。
- 避免 Primitive Obsession:id 一律 VO(
PoNo/WorkCenterId/ProcessId)。 - LSP:零繼承(全 VO + flat entity),無替換風險。
⚠️ 風險與處置
- SRP × 不寫回(已處置):
CapacitySlot若同時裝 FREEZE+IN_RUN,共用物件會在排程中被 mutate、「不寫回」僅靠紀律。決議:共用CapacitySlot只存FREEZE;IN_RUN由引擎 per-run overlay 持有(見../rough-cut-scheduler/rough-cut-scheduler.ooa.md)。「不寫回」成為結構保證。 - OCP(觀察點):
CapacityOccupationSource目前為純 tag(無行為),OK;若未來各來源要不同處理,改多型、勿用 switch。
Part B — 設計模式
| # | 模式 | 用於 | 決議 |
|---|---|---|---|
| 1 | Value Object | OperationCoordinate/DataBox/ids | ✅ 採用 |
| 2 | Snapshot | ScheduledNode 快照 VSMNode | ✅ 採用 |
| 3 | Repository | 取外部物件 | ⏸ 先不引入(取得方式留實作/消費方 OOA) |
| 4 | Composite | VSM 樹 | ❌ 不採(VSMNode 鄰接 list 已足,避免 pattern-itis) |
| 5 | Strategy(x-y leadtime) | 三策略切換 | ➡️ 屬引擎,留 ../rough-cut-scheduler/rough-cut-scheduler.ooa.md |
| 6 | Specification(eligibility 匹配) | node 製程-工作站 ↔ 資源 WorkCapability | ❌ 不採(本期純集合比對;避免 pattern-itis,彈性點留 WorkCapability.canPerform,要長條件再抽 Specification) |
| 7 | Strategy(資源分配) | 多 eligible 資源選哪台 | ➡️ 屬引擎 ResourceAllocationStrategy,留 ../rough-cut-scheduler/rough-cut-scheduler.ooa.md |
5. functional spec 對照
| Stage 2 domain-model 物件 | 對應 OOA 類別 |
|---|---|
| VSM | VSM + VSMNode + DataBox + MaterialRequirement + OperationCoordinate(+ WorkCenter) |
| 投產單 | ProductionOrder |
| 可用產能(資源×日) | AvailableCapacity + CapacitySlot(鍵 ResourceId)+ Occupation |
| 資源 + eligibility(#17 / §RCS-FS-16–B19) | Resource + WorkCapability + ResourcePool.eligible() |
| Freeze | CapacityOccupationSource.FREEZE(佔用來源) |
| RoughScheduleResult | RoughScheduleResult + ScheduledNode |
簽核
- 編輯者:Alan / 日期:2026/06/09
- Reviewer:Alan / 日期:2026/06/09