14 enterprise data problems facing ShaDey Inc., ordered by dependency chain. Each problem includes root causes, solutions, ShaDey-specific implementation guidance, data modeling resolution, and framework alignment to DAMA DMBOK, EDM Council DCAM, and modeling best practices.
Solve first. Everything downstream depends on these. You cannot fix what you cannot define.
If “Revenue” means three different things to three departments, every downstream fix inherits the ambiguity. Shared vocabulary, ownership, and quality rules are prerequisite to all other work.
Conceptual Data Model (CDM) ├─ Customer ← glossary term #001 ├─ Product ← glossary term #002 ├─ Store ← glossary term #003 ├─ Supplier ← glossary term #004 ├─ Promotion ← glossary term #005 ├─ Sales ← glossary term #006 ├─ Inventory ← glossary term #007 └─ Return ← glossary term #008 Rule: No entity enters LDM without a glossary entry signed by the Council.
The CDM is the single source of truth for business semantics. Every entity in the CDM maps 1:1 to a glossary term. Every attribute in the LDM inherits its definition from the glossary. Every column in the PDM carries a glossary_term_id metadata tag. This means:
Naming Convention dim_customer, not tbl_cust or customer_master_v2. The name itself encodes the entity type and business domain.
Certification Gate CDM→LDM transition requires business sign-off. LDM→PDM transition requires steward approval. No physical table is born without a semantic anchor.
Quality by Design Valid values defined in the glossary become CHECK constraints in the PDM. If the glossary says customer_type IN ('B2B','B2C','B2B2C'), the PDM enforces it.
KA 3: Data Governance: Operating model, decision rights, accountability. KA 12: Metadata Management: Business glossary, technical metadata, operational metadata. KA 13: Data Quality: Quality dimensions (completeness, accuracy, consistency, timeliness, validity, uniqueness).
Component 6: Data Governance: Policy framework, stewardship, issue management. Component 7: Data Control Environment: Lineage, quality measurement, monitoring. Targets: Level 4 (Managed) for governance, Level 3 (Defined) for quality.
CDM entities must have glossary-backed definitions before LDM design begins. Every attribute in the LDM must map to a glossary term. Naming conventions enforced by governance council: dim_customer, not tbl_cust.
Governance gives you definitions; modeling gives you structure. Missing entities block entire use cases. Wrong grain produces misleading aggregations. Skipping CDM/LDM and jumping to PDM embeds business rules in SQL where no one can find them.
dim_promotion at design time, you cannot answer “which promotions drove sales growth?” Without fact_return, reverse logistics analytics must be reverse-engineered from daily snapshots.fact_sales is at billing document header grain instead of line-item grain, product-level margin analysis is impossible without rebuilding the table.customer in three schemas, each with different definitions, grain, and attributes.dim_), fact prefix (fact_), or attribute naming (snake_case).dim_customer, dim_product, dim_supplier.dim_ for dimensions, fact_ for facts, ref_ for reference, stg_ for staging, dp_ for data products. All attributes in snake_case.dim_promotion exist? Does fact_return exist? Does dim_date cover fiscal calendar attributes needed for ShaDey’s financial reporting?fact_sales must be at VBRP line-item grain (one row per billing document item), not VBRK header grain. fact_inventory_snapshot must be at product-location-date grain from MARD, not plant-level aggregate.dim_customer: track customer_type, credit_limit, sales_org changes. dim_product: track material_group, category, status changes. dim_supplier: track vendor_class, payment_terms changes. Add effective_from_ts, effective_to_ts, is_current_flag to each.dim_, fact_, ref_, stg_, dp_, or ml_. Reject any attribute not in snake_case. Document standard in the platform’s Modeling Tutorial page.CDM (Business-approved)
Customer, Product, Sales, Inventory...
LDM (3NF, domain-reviewed)
Customer { id, name, type, region }
Product { id, name, category, uom }
Sales { customer, product, date, qty, amt }
PDM (Star Schema, implemented)
dim_customer ← SCD Type 2
dim_product ← SCD Type 2
dim_date ← role-playing (order/ship/bill)
fact_sales ← grain: 1 row per line item
└ FK → dim_customer, dim_product, dim_date,
dim_store, dim_promotion
Grain Declaration Every fact table documents its grain in the LDM metadata. fact_sales: “One row per billing line item (VBRP) per fiscal period.” Grain changes require a formal model change request; no silent redefinition.
SCD Type 2 Dimensions that need historical tracking carry effective_from_ts, effective_to_ts, is_current_flag. This is declared at CDM stage (“do we need to track changes to customer type?”), not discovered during ETL.
Conformed Dimensions dim_customer is shared across fact_sales, fact_order, fact_return, and dp_customer_360. One definition, one surrogate key, one SCD policy. Eliminates naming collisions by design.
Entity Completeness Before PDM implementation, validate: “Can we answer every business question in the use-case backlog with these entities?” Missing dim_promotion is caught at CDM review, not after 6 months of production.
KA 5: Data Modeling & Design: Conceptual, logical, physical model progression. Normalization to 3NF in LDM, denormalization with documented justification in PDM. KA 4: Data Architecture: Enterprise data model, subject area models.
Component 3: Data Architecture: Logical and physical architecture alignment. Models must be traceable to business requirements. Target: Level 3 (Defined) with progression to Level 4 (Managed).
Kimball star schema for analytical models. Inmon 3NF for enterprise data warehouse. Grain declaration mandatory. Conformed dimensions shared across fact tables. Surrogate keys on all dimensions. Natural keys preserved for lineage.
Material master sprawled across 12+ SAP tables (MARA, MARC, MVKE, MARM, MEAN, MBEW, T023). Customer and vendor maintained as separate objects (KNA1 vs LFA1). Every transaction and analytic is only as good as the master data behind it.
dim_product consolidates MARA + MAKT + MARC + MVKE + MARM + MBEW. dim_customer consolidates KNA1 + KNB1 + KNVV + KNVP.dim_customer and dim_supplier to support both ECC and S/4 source patterns.stg_product staging table that joins all 7 sources on MATNR. Apply deduplication rules: flag materials with zero transactions in 24 months (check against MSEG/MATDOC) for steward review.ref_* tables in the PDM. Add foreign key constraints: dim_product.material_group_code → ref_material_group.code.dim_customer and dim_supplier with a source_system discriminator column. During ECC→S/4 coexistence, the staging layer maps KNA1 and BUT000 into the same target schema. The PDM does not change; only the source adapter changes.dim_product (SCD Type 2) ├─ product_sk INT [surrogate key] ├─ product_id VARCHAR(18) [MARA.MATNR] ├─ product_name VARCHAR [MAKT.MAKTX] ├─ material_type VARCHAR [MARA.MTART] ├─ material_group VARCHAR [MARA.MATKL → T023] ├─ category_code VARCHAR [KLAH/KSML] ├─ base_uom VARCHAR [MARA.MEINS] ├─ sales_uom VARCHAR [MVKE.VRKME] ├─ standard_cost DECIMAL [MBEW.STPRS] ├─ plant_code VARCHAR [MARC.WERKS] ├─ effective_from_ts TIMESTAMP ├─ effective_to_ts TIMESTAMP └─ is_current_flag BOOLEAN Sources: 7 SAP tables → 1 dimension
dim_customer (SCD Type 2) ├─ customer_sk INT [surrogate key] ├─ customer_id VARCHAR(10) [KNA1.KUNNR / BUT000.PARTNER] ├─ customer_name VARCHAR [KNA1.NAME1 / BUT000.NAME_ORG1] ├─ customer_type VARCHAR [B2B / B2C / B2B2C] ├─ city VARCHAR [KNA1.ORT01] ├─ region VARCHAR [KNA1.REGIO] ├─ sales_org VARCHAR [KNVV.VKORG] ├─ credit_limit DECIMAL [KNKK.KLIMK] ├─ source_system VARCHAR [ECC / S4HANA] ├─ effective_from_ts TIMESTAMP ├─ effective_to_ts TIMESTAMP └─ is_current_flag BOOLEAN Sources: KNA1+KNB1+KNVV+KNVP+KNKK (ECC) or BUT000+roles (S/4HANA)
The conformed dimension is the modeling solution to master data fragmentation. Instead of 7 scattered SAP tables, a single dim_product with surrogate keys becomes the shared reference across all fact tables. SCD Type 2 preserves history. The source_system discriminator enables dual-source support during migration.
KA 10: Reference & Master Data: Golden record management, match-merge, survivorship. KA 13: Data Quality: Profiling, cleansing, standardization, monitoring.
Component 5: Data Quality Management: Quality rules on master data, profiling, remediation. Component 3: Data Architecture: Master data integration patterns (hub, registry, coexistence).
Conformed dimensions are the modeling solution to master data fragmentation. Dimension tables consolidate multiple source tables into one SCD Type 2 entity with surrogate keys. Natural keys preserved for lineage.
Before migrating or building new pipelines, you must know what feeds what. Without lineage, migration is blind surgery. Without regulatory traceability, audits fail.
source_system (ECC/S4), source_table (e.g., KNA1), source_column (e.g., NAME1), transformation_rule (e.g., “TRIM + UPPER”). Use the ECC-to-PDM and S/4HANA-to-PDM mapping pages as the source-to-target specification.(:SourceTable)-[:EXTRACTS]→(:Column)-[:TRANSFORMS_INTO]→(:PDMColumn)-[:FEEDS]→(:Report). Use the graph-database.html data lineage use case as the design pattern.dim_customer.customer_name = CONFIDENTIAL/PII, dim_customer.customer_id = INTERNAL, fact_sales.net_amount = INTERNAL. Build a GDPR deletion view: “Given customer_id X, show all tables and columns where this customer’s data exists.”stg_financial_posting → fact_sales (net_amount, tax_amount) → dp_netsales → P&L dashboard. Auditors can traverse this path in the catalog without contacting IT.Graph Schema
(:SourceTable {name, module, system})
-[:HAS_COLUMN]→
(:SourceColumn {name, datatype, pii_flag})
-[:TRANSFORMS_INTO {rule, owner}]→
(:PDMColumn {name, entity, glossary_term_id})
-[:BELONGS_TO]→
(:PDMEntity {name, grain, scd_type})
-[:FEEDS]→
(:Report {name, owner, certification})
Cypher: Forward impact
MATCH (s:SourceColumn {name:"MATNR"})
-[:TRANSFORMS_INTO*]→(r:Report)
RETURN r.name, r.owner
Every PDM column carries: ├─ source_system [ECC / S4HANA / CRM] ├─ source_table [e.g., KNA1] ├─ source_column [e.g., NAME1] ├─ transformation_rule [e.g., TRIM+UPPER] ├─ pii_classification [PUBLIC/INTERNAL/ │ CONFIDENTIAL/RESTRICTED] ├─ glossary_term_id [links to CDM] └─ data_contract_id [links to SLA/schema] This metadata IS the lineage backbone. No visualization tool can replace it.
Data modeling resolves lineage by embedding traceability into the model itself. Every PDM column carries metadata attributes that link it back to its source. The Neo4j graph makes this traversable. Together, they make “where does this number come from?” a 5-second query, not a 3-day investigation.
KA 12: Metadata Management: Active metadata, lineage, data catalogs. KA 7: Data Security: PII classification, access control, encryption. KA 8: Data Integration: Documented transformation logic, data contracts.
Component 7: Data Control Environment: Lineage documentation, quality measurement, regulatory reporting. Component 4: Technology Architecture: Catalog and lineage tooling.
Every PDM column should carry metadata attributes: source_system, source_table, source_column, transformation_rule, pii_flag. This is the column-level lineage backbone.
Structural changes that enable operational fixes. Requires the foundation layer to be in place.
Nine major structural changes hitting simultaneously: BUT000 consolidation, MATDOC denormalization, EWM replacement, Material Ledger mandatory, MRP Live, ACDOCA Universal Journal, PRCD_ELEMENTS, UKM credit engine, LIS elimination. Each breaks existing queries, reports, and interfaces.
dim_customer accepts data from KNA1 (ECC) or BUT000 (S/4) via an adapter pattern. The PDM schema does not change; the source mapping changes.dim_customer, dim_supplier; (2) MATDOC → affects fact_inventory_snapshot, all goods movement analytics; (3) ACDOCA → affects fact_sales, all financial analytics; (4) Embedded EWM → affects dim_warehouse_location; (5) PRCD_ELEMENTS → affects dim_promotion pricing logic; (6) UKM → affects dim_customer credit attributes; (7) MRP Live → affects demand planning feeds; (8) Material Ledger → affects dim_product valuation; (9) LIS removal → affects all pre-aggregated operational reports.stg_customer_ecc (from KNA1+KNB1+KNVV) and stg_customer_s4 (from BUT000+BP roles). Both feed the same dim_customer target through a unified transformation. Configuration flag active_source = 'ECC'|'S4' per entity. Same pattern for stg_material_movement_ecc (MKPF+MSEG) and stg_material_movement_s4 (MATDOC).fact_sales financial attributes from ACDOCA.RACCT, ACDOCA.RCNTR, ACDOCA.HSL.Staging Layer (source-specific)
stg_customer_ecc ← KNA1+KNB1+KNVV
stg_customer_s4 ← BUT000+BP roles
│ │
└────── UNION ──────┐
│
PDM Layer (source-agnostic)
dim_customer (unchanged schema)
├─ customer_sk
├─ customer_id
├─ customer_name
├─ source_system [ECC / S4HANA]
└─ ...all other attributes
Key insight: PDM schema is STABLE.
Source changes are absorbed by staging.
Star schema consumers see no change.
Adapter Pattern The staging layer absorbs all 9 structural changes. stg_*_ecc and stg_*_s4 tables are the only place where source-specific logic exists. The PDM star schema remains stable across the entire migration.
Schema Stability fact_sales consumers query dim_customer.customer_name regardless of whether it came from KNA1.NAME1 or BUT000.NAME_ORG1. The join key is customer_sk (surrogate), not the source natural key.
Dual-Source Coexistence During migration, both adapters run in parallel. source_system column in every dimension enables filtering and reconciliation. Variance detection built into the pipeline.
This is the primary value of the CDM→LDM→PDM progression: physical tables represent business entities, not source system structures. Source systems can be swapped without reshaping the analytical layer.
KA 4: Data Architecture: Technology migration planning, integration architecture. KA 8: Data Integration & Interoperability: ETL redesign, API adapter patterns, coexistence strategies.
Component 4: Technology Architecture: Platform migration planning, dual-stack support. Component 3: Data Architecture: Logical model must be stable across technology changes.
The PDM should be source-agnostic. Adapter/staging layer absorbs source changes; the star schema remains stable. This is the primary value of the CDM→LDM→PDM progression.
CO-PA tells one story, FI tells another, LIS S-tables tell a third. Each department builds its own aggregations. S/4HANA merges everything into ACDOCA, but existing BI extracts all break.
dp_netsales, dp_salesdaily, dp_promoeff. Each has a published schema, owner, SLA, and quality contract.net_sales = fact_sales.gross_amount - fact_sales.discount_amount - fact_sales.return_amount, gross_margin = (net_sales - fact_sales.cogs_amount) / net_sales, OTIF = COUNT(on_time AND in_full) / COUNT(total_deliveries). Each metric owned by a business domain lead from the Governance Council (P1).dp_netsales (daily net sales at product-store grain, SLA: available by 6AM), dp_salesdaily (daily sales summary at store grain with YoY comparison), dp_promoeff (promotion effectiveness at product-store-promo-week grain). Each has a published schema, version, owner, and data contract.Star Schema (Foundation)
fact_sales × dim_customer × dim_product
× dim_store × dim_date × dim_promotion
Data Product Layer (Governed Aggregates)
dp_netsales
├─ date_key [FK → dim_date]
├─ product_sk [FK → dim_product]
├─ store_sk [FK → dim_store]
├─ gross_amount [SUM(fact_sales)]
├─ discount_amount [SUM conditions]
├─ return_amount [SUM(fact_return)]
└─ net_sales [calculated]
Grain: product × store × day
SLA: refreshed daily by 6:00 AM
Owner: Finance domain lead
Single Source of Metrics Data products are first-class PDM entities, not ad-hoc views. dp_netsales is modeled with its own grain, attributes, source lineage, and refresh cadence. Every dashboard that shows “Net Sales” queries this entity.
Aggregate Fact Tables Data products are modeled as aggregate facts derived from the star schema. They pre-compute common metrics so dashboards don’t need complex joins. But unlike LIS S-tables, they are governed, versioned, and have published contracts.
ACDOCA Integration The fact_sales entity is redesigned to source from ACDOCA (single table) instead of BSEG + CE1xxxx separately. This eliminates the 3–5% reconciliation gap at the model level: one source table, one extraction, one truth.
KA 11: DW & Business Intelligence: Dimensional modeling for analytics, semantic layers, metrics catalogs. KA 3: Data Governance: Report certification, metric ownership.
Component 5: Data Quality Management: Cross-source reconciliation rules. Component 1: Data Management Strategy: Single semantic layer as strategic goal.
Data products are modeled as aggregate fact tables derived from the star schema. They are first-class PDM entities with documented grain, source lineage, and refresh cadence.
Business process optimization. Needs a clean, governed, migrated platform underneath.
Demand forecasts consistently miss by 20–30%. Classic MRP (MD01/MD02) uses manual tuning. IBP and DDMRP offer ML-driven alternatives, but only if historical demand data is trustworthy and planning parameters in MARC are correct.
fact_demand_signal at product-location-day grain, combining POS, e-commerce, and wholesale channels.dp_demand_forecast as a governed data product: historical demand + seasonality indices + promotion calendar + weather features.ml_feature_store) sourced from the PDM. Features: rolling 7/30/90-day sales velocity, promotion lift coefficients, stockout frequency, price elasticity.fact_demand_signal (Sprint 1). Source from three channels: (1) VBRP billing items for wholesale (grain: material + plant + billing date), (2) POS transaction feed for retail stores (grain: material + store + transaction date), (3) e-commerce order API for online (grain: material + ship-to + order date). Unify into product-location-day grain using dim_product.product_sk and dim_store.store_sk as conformed keys.dp_demand_forecast (Sprint 2). Join fact_demand_signal (12 months history) with: dim_date seasonality flags, dim_promotion active promo calendar, external weather API data. Publish as a data product with daily refresh SLA. Grain: product × location × day × forecast_horizon (7d, 30d, 90d).rolling_7d_velocity (AVG qty from fact_demand_signal last 7 days), promo_lift_coefficient (ratio of promo vs. baseline sales from dp_promoeff), stockout_frequency_30d (COUNT days where fact_inventory_snapshot.qty_available = 0), price_elasticity (regression on price changes vs. demand changes). Store in ml_feature_store entity with feature versioning.dp_demand_forecast 90-day horizon to recalculate: safety stock = Z-score × σ(demand) × √(lead_time). Write recalculated values back to MARC.EISBE (safety stock) and MARC.MINBE (reorder point) via RFC or S/4 API. MRP Live on HANA re-plans automatically. Target: reduce forecast MAPE from 25% to <15%.fact_demand_signal (transactional fact) Grain: product × location × day ├─ demand_signal_sk [surrogate key] ├─ product_sk [FK → dim_product] ├─ store_sk [FK → dim_store] ├─ date_key [FK → dim_date] ├─ channel [POS/ECOM/WHOLESALE] ├─ demand_qty [units demanded] └─ demand_amount [value demanded] ml_feature_store (derived entity) ├─ product_sk ├─ store_sk ├─ feature_date ├─ rolling_7d_velocity ├─ rolling_30d_velocity ├─ promo_lift_coeff ├─ stockout_freq_30d └─ feature_version [v1, v2, ...]
Atomic Grain fact_demand_signal at product-location-day grain captures demand from all channels in one place. This is the single input for both statistical forecasting and ML models; no more fragmented signals.
Conformed Keys Demand signals from POS, e-commerce, and wholesale all join to the same dim_product and dim_store via surrogate keys. Channel-specific attributes are measures in the fact, not separate tables.
Feature Store as PDM Entity ML features are derived attributes modeled in their own entity with versioning. They are computed from the star schema (not raw source data), making them governed, reproducible, and auditable. Feature engineering is a modeling activity, not a notebook hack.
Closed-Loop Design The PDM enables a feedback loop: fact_demand_signal → ml_feature_store → dp_demand_forecast → MARC parameters → better inventory → better demand fulfillment. The model architecture makes this loop possible.
KA 11: DW & BI: Fact table design at the correct grain. KA 14: Big Data & Data Science: Feature engineering, ML model management, feature stores as governed assets.
Component 3: Data Architecture: Demand signal integration across channels. Component 5: Data Quality: Historical data completeness for training ML models.
Demand fact at atomic grain (product-location-day). ML features modeled as derived attributes in the data product layer. Feature store is a separate PDM entity with its own refresh cadence.
Manufacturing variance between planned and actual is hard to trace. BOM accuracy issues across MAST/STKO/STPO. Batch recall requires manual traversal of MCH1 → MCHA → QALS → LIPS.
fact_production_order at production order + operation grain. Join AUFK → AFKO → AFVC → COBK/COEP. Calculate variance per operation.dim_bom with effective_from_ts / effective_to_ts.dp_quality_metrics.fact_production_order (Sprint 1). Extract AUFK (order header: order number, order type, material, plant), AFKO (order operations header: planned start/finish, actual start/finish), AFVC (operations: work center, setup time, run time), COBK/COEP (actual costs: cost element, amount). Join on AUFNR. Grain: one row per production order × operation. Calculate variance: planned_cost - actual_cost, planned_hours - actual_hours.dim_bom with SCD Type 2 (Sprint 2). Extract MAST (BOM header link), STKO (BOM header: usage, status, valid-from), STPO (BOM items: component material, quantity, UoM). Track BOM versions with effective_from_ts / effective_to_ts. Production orders reference the BOM version active at order creation via dim_bom.bom_sk.(:Batch), MCHA (plant assignment) as relationship, QALS (inspection lot) as (:InspectionLot), LIPS (delivery items) as (:DeliveryItem), KNA1/BUT000 as (:Customer). Graph: (:Batch)-[:USED_IN]→(:ProductionOrder)-[:PRODUCED]→(:Product)-[:DELIVERED_VIA]→(:Delivery)-[:SHIPPED_TO]→(:Customer). Batch recall: single Cypher query returns all affected customers in seconds.dp_quality_metrics (Sprint 3). Extract QALS (inspection lot header), QASR (inspection results), QAVE (usage decisions). Compute: inspection pass rate by product, defect category Pareto (top 5 defect types), supplier quality score (correlation between LFA1/BUT000 supplier and defect rates). Publish weekly to quality and procurement teams.fact_production_order (process fact) Grain: production order × operation ├─ prod_order_sk [surrogate key] ├─ order_number [AUFK.AUFNR] ├─ product_sk [FK → dim_product] ├─ bom_sk [FK → dim_bom (versioned)] ├─ work_center_sk [FK → dim_work_center] ├─ planned_start_date [AFKO] ├─ actual_start_date [AFKO] ├─ planned_cost [AFVC planned] ├─ actual_cost [COBK/COEP actual] └─ variance_amount [calculated] dim_bom (SCD Type 2) ├─ bom_sk, bom_id, material_sk ├─ component_list (JSON or child table) ├─ effective_from_ts, effective_to_ts └─ is_current_flag
Operation-Level Grain fact_production_order at operation grain (not order-header grain) enables variance analysis per manufacturing step. “Which operation caused the cost overrun?” becomes a simple WHERE clause.
Versioned BOM dim_bom with SCD Type 2 links each production order to the BOM version active at creation time. When a BOM changes mid-quarter, old orders reference old BOM, new orders reference new BOM. Costing accuracy preserved.
Graph for Multi-Hop Traversal Batch recall is inherently a multi-hop problem: batch → production order → product → delivery → customer. Neo4j traverses this in milliseconds. The star schema handles aggregation (“total defect cost this quarter”); the graph handles traversal (“who received batch X?”).
KA 8: Data Integration: Cross-module integration (PP + QM + MM). KA 5: Data Modeling: Process-centric fact tables with operation-level grain.
Component 3: Data Architecture: Operational data integration into analytical platform. Cross-domain entity relationships.
Production fact at operation grain. BOM as a versioned dimension (SCD2). Batch lineage modeled as a graph for multi-hop traversal. Quality metrics as a data product.
Simultaneous overstock in one location, stockouts in another. Physical inventory discrepancies (IKPF/ISEG vs. MARD). Classic WM (LQUA/LAGP) fully removed in S/4HANA, replaced by Embedded EWM.
fact_inventory_snapshot not refreshed frequently enough. Daily snapshots miss intraday stock movements.fact_inventory_snapshot at product-location-batch grain with multiple daily snapshots or near-real-time via MATDOC CDC.dp_inventory_position data product: owned + consignment + in-transit + reserved stock.fact_physical_inventory capturing IKPF/ISEG with variance analysis.dim_warehouse_location mapping both LAGP and /SCWM/LAGP.fact_inventory_snapshot (Sprint 1). Current grain is product-plant-day from MARD. New grain: product-storage_location-batch-date. Source: MARD (unrestricted stock), MCHB (batch stock), MKOL (consignment), MSKA (sales order stock). Capture multiple snapshots per day: 6AM (opening), 12PM (midday), 6PM (closing). In S/4HANA, switch to CDC on MATDOC for near-real-time updates.dp_inventory_position (Sprint 2). Aggregate across all stock types: owned_qty (MARD), consignment_qty (MKOL), in_transit_qty (LIPS items not yet received), reserved_qty (MSKA). Single metric: available_to_promise = owned_qty - reserved_qty + in_transit_qty. Published as a data product with hourly refresh SLA during business hours.fact_physical_inventory (Sprint 2). Extract IKPF (PI document header) + ISEG (PI document items). Calculate: book_qty (from MARD at count date), counted_qty (from ISEG), variance_qty, variance_pct, adjustment_reason_code. Enable root-cause analysis: “which storage locations have the highest variance?”, “which product categories are most undercounted?”dim_warehouse_location (Sprint 3). During ECC-to-S/4 coexistence, map both schemas: LAGP (classic WM: warehouse, storage type, storage bin) and /SCWM/LAGP (EWM: warehouse, storage type, bin, activity area). Unified hierarchy: warehouse → zone → aisle → bin. source_system discriminator supports dual-source.fact_inventory_snapshot (periodic snapshot) Grain: product × location × batch × date ├─ snapshot_sk [surrogate key] ├─ product_sk [FK → dim_product] ├─ store_sk [FK → dim_store] ├─ warehouse_sk [FK → dim_warehouse_location] ├─ batch_id [MCH1 batch number] ├─ date_key [FK → dim_date] ├─ snapshot_time [06:00/12:00/18:00] ├─ owned_qty [MARD unrestricted] ├─ consignment_qty [MKOL] ├─ in_transit_qty [LIPS pending] ├─ reserved_qty [MSKA] └─ available_to_promise [calculated]
Periodic Snapshot Kimball’s periodic snapshot pattern captures stock levels at regular intervals. Multiple stock types (owned, consignment, transit, reserved) modeled as measures in one fact, not separate tables. This unifies ShaDey’s fragmented stock views.
Batch-Level Grain Adding batch_id to the grain enables batch-level traceability. “Where is batch X right now?” becomes a fact table query, not a multi-table SAP investigation.
dim_warehouse_location A single warehouse dimension abstracts over both WM (LAGP) and EWM (/SCWM/LAGP). The same star schema works before, during, and after the EWM migration. Bin structure changes are absorbed in the dimension, not in every query.
Near-Real-Time In S/4HANA, MATDOC CDC enables the accumulating snapshot variant: instead of periodic captures, update the snapshot on every goods movement. The model supports both patterns without schema change.
KA 6: Data Storage & Operations: Snapshot pattern design, CDC for near-real-time. KA 5: Data Modeling: Periodic snapshot vs. accumulating snapshot fact patterns.
Component 3: Data Architecture: Multi-source inventory integration. Component 4: Technology Architecture: CDC infrastructure for MATDOC streaming.
Inventory is a periodic snapshot fact. Grain = product × location × date. Multiple stock types as measures. Near-real-time requires accumulating snapshot pattern.
Can’t answer “if this supplier fails, who gets hurt?” without joining 4–5 tables. Single-source supplier risk invisible until disruption hits. Multi-tier visibility stops at tier-1.
dp_supplier_risk: single-source flag, quality audit history, delivery reliability, geographic concentration.fact_shipment at delivery-item grain for OTIF measurement.(:Supplier) from LFA1/BUT000, (:Product) from MARA, (:Plant) from T001W, (:Store) from T001W (retail). Relationships: (:Supplier)-[:SUPPLIES {source_list: EORD}]→(:Product), (:Product)-[:STOCKED_AT]→(:Store), (:Customer)-[:ORDERED]→(:Product). Index: single-source flag = products where COUNT(DISTINCT supplier) = 1.dp_supplier_risk (Sprint 2). Compute per supplier: single_source_product_count (from EORD), avg_quality_score (from dp_quality_metrics P8), delivery_OTIF_rate (from fact_shipment), geographic_concentration (% of suppliers in same country/region), financial_risk_score (from external data). Composite risk score: weighted average. Flag suppliers scoring > 7/10 for Governance Council review.fact_shipment (Sprint 2). Join LIKP (delivery header: delivery date, ship-to party) + LIPS (delivery items: material, quantity, batch) + VTTK (shipment header: carrier, planned arrival) + VTTP (shipment items). Grain: one row per delivery item. Metrics: planned_delivery_date, actual_delivery_date, on_time_flag, in_full_flag, OTIF_flag. Target: network-wide OTIF visibility.(:Tier2Supplier)-[:SUPPLIES]→(:Tier1Supplier). Disruption impact query: MATCH (t2:Tier2Supplier {country:"CN"})-[:SUPPLIES*1..3]→(p:Product) RETURN p.name, COUNT(t2). Enables “what if China shuts down?” scenario analysis.Star Schema (for aggregation)
fact_shipment
Grain: delivery item
├─ supplier_sk [FK → dim_supplier]
├─ product_sk [FK → dim_product]
├─ store_sk [FK → dim_store]
├─ date_key [FK → dim_date]
├─ planned_date, actual_date
└─ otif_flag
Graph (for traversal)
(:Tier2Supplier)-[:SUPPLIES]→
(:Tier1Supplier)-[:SUPPLIES]→
(:Product)-[:STOCKED_AT]→
(:Store)-[:SERVES]→
(:Customer)
Graph nodes carry PDM surrogate keys
for cross-paradigm joins.
Dual Paradigm Supply chain analytics requires two modeling paradigms: star schema for aggregation (“what is our average OTIF this quarter?”) and graph for traversal (“if supplier X fails, which customers are affected?”). The key is that graph nodes carry PDM surrogate keys (supplier_sk, product_sk), enabling cross-paradigm joins.
Multi-Hop Traversal “Supplier X fails → which products affected → which stores stocked out → which customers impacted?” is a 3-hop traversal in Neo4j. In a star schema, this requires 3 self-joins with exponentially degrading performance. The graph model makes this constant-time.
Risk as a Data Product dp_supplier_risk aggregates signals from multiple PDM entities (quality, delivery, sourcing) into a single risk score. This is a derived data product, a first-class modeled entity, not an ad-hoc calculation.
KA 8: Data Integration: Cross-module and external data integration. KA 14: Big Data: Graph analytics for network analysis.
Component 3: Data Architecture: Graph as complementary architecture. External data onboarding governance.
Supply chain modeled in two paradigms: star schema for aggregation, graph for traversal. Neo4j nodes map to PDM surrogate keys for cross-paradigm joins.
Last-mile optimization. Needs the operational layer working before these deliver value.
Condition records scattered across KONH/KONP/A-tables/WPM with no unified view. Can’t answer “did this promotion actually drive incremental sales or just pull forward demand?”
dim_promotion as a conformed dimension: promotion ID, type, start/end dates, mechanic (BOGO, % off, fixed), target products, target stores.dp_promoeff: baseline sales, promoted sales, incremental lift, cost of promotion, ROI.dp_margin_waterfall: gross → discounts → rebates → markdowns → COGS → net margin.dim_promotion (Sprint 1). Source from KONH (condition header: promo key, valid dates) + KONP (condition items: amount, rate, scale) + A-tables (condition access: material, customer, sales org combinations) + WPM* (Retail promotion management, if applicable). Attributes: promotion_id, promo_name, promo_type (% off, BOGO, fixed price, markdown), start_date, end_date, mechanic_description, target_product_list, target_store_list, planned_spend. This dimension does not exist in the current 24-entity PDM; it must be added.dp_promoeff (Sprint 2). Grain: product × store × promotion × week. Calculate: baseline_sales (avg of same weeks in non-promo periods), promoted_sales (actual during promo), incremental_lift (promoted - baseline), promo_cost (from dim_promotion.planned_spend), ROI ((incremental_revenue - promo_cost) / promo_cost). Join fact_sales with dim_promotion via promotion_sk. Publish weekly to Marketing and Merchandising.dp_margin_waterfall (Sprint 3). Decompose each sale from gross to net using KONV/PRCD_ELEMENTS condition types: list_price (PR00) → trade_discount (K004/K005) → volume_rebate (BO01-BO05) → markdown (final selling price) → COGS (from MBEW.STPRS/ML actual cost) → net_margin. Grain: product × store × month. Enables: “where is margin leaking?” at any level of the product/store hierarchy.dp_margin_waterfall source mapping: KONV.KSCHL → PRCD_ELEMENTS.KSCHL. Use the dual-source adapter pattern from P5.dim_promotion (conformed dimension) ├─ promotion_sk [surrogate key] ├─ promotion_id [business key] ├─ promo_type [%OFF/BOGO/FIXED/MKDN] ├─ mechanic_desc [human-readable] ├─ start_date [KONH.DATAB] ├─ end_date [KONH.DATBI] └─ planned_spend [budget allocated] dp_margin_waterfall (derived wide table) Grain: product × store × month ├─ list_price [PR00] ├─ trade_discount [K004/K005] ├─ volume_rebate [BO01-BO05] ├─ markdown [final price delta] ├─ cogs [MBEW.STPRS] └─ net_margin [calculated]
Conformed Dimension dim_promotion is shared by fact_sales and dp_promoeff. Every sale that occurred during a promotion period is linked to the promotion via promotion_sk. This enables “was this sale promoted?” at the line-item level.
Margin Waterfall The waterfall is a derived wide table that decomposes price into named components. Each component maps to specific KONV/PRCD_ELEMENTS condition types. This makes margin leakage visible: if trade discounts grew 15% while volume only grew 3%, the model surfaces it.
Promotion Effectiveness Without dim_promotion, there is no analytical anchor for promo ROI. The dimension provides the structural capability to ask: “what was the incremental lift of this specific promotion on this specific product at this specific store?” This question is unanswerable without the modeled entity.
KA 11: DW & BI: Conformed dimensions shared across promotional and sales facts. KA 10: Reference & Master Data: Condition record management as reference data.
Component 5: Data Quality: Condition record validity monitoring. Component 1: Strategy: Margin visibility as strategic analytics capability.
dim_promotion is a conformed dimension shared by fact_sales and dp_promoeff. Margin waterfall is a derived wide table with named price components.
“Which location should fulfill this order?” requires real-time stock visibility that doesn’t exist. Classic ATP gives binary yes/no. Credit blocks (KNKK) stall orders silently.
fact_order joining VBAK + VBAP + VBEP + VBKD. Track order lifecycle states.dp_order_fulfillment: order-to-delivery lead time, perfect order rate, fill rate by location, backorder aging.dim_customer with real-time utilization.fact_order (Sprint 1). Extract VBAK (order header: order number, customer, order date, order type) + VBAP (order items: material, quantity, net value) + VBEP (schedule lines: confirmed qty, delivery date) + VBKD (business data: payment terms, incoterms). Grain: one row per order item per schedule line. Track lifecycle: order_created_date, order_confirmed_date (from VBEP), delivery_date (join to LIKP), billing_date (join to VBRK), completion_flag.dp_order_fulfillment (Sprint 2). Derived metrics: order_to_delivery_days (delivery_date - order_created_date), perfect_order_flag (on_time AND in_full AND no_damage AND correct_invoice), fill_rate (confirmed_qty / requested_qty), backorder_age_days (today - order_created_date WHERE not yet delivered). Grain: customer × product × order_date. SLA: refreshed hourly during business hours. Published to Sales, Logistics, and Customer Service teams.(:Order)-[:PLACED_BY]→(:Customer {location}), (:Store)-[:HAS_STOCK {qty, available_to_promise}]→(:Product), (:Store)-[:SHIPS_VIA {cost, lead_days}]→(:Carrier). Routing query: given an order for product X to customer Y, find the store with stock that minimizes (shipping_cost + lead_days × urgency_weight) using Dijkstra shortest path. This replaces static delivery plant determination rules with data-driven optimization.dim_customer. In S/4HANA: migrate to UKM_* tables for real-time credit utilization. Add credit_utilization_pct to dim_customer and dp_order_fulfillment. Auto-flag orders where customer credit utilization > 90% for proactive review before order entry.fact_order (transactional fact) Grain: order item × schedule line ├─ order_sk [surrogate key] ├─ order_number [VBAK.VBELN] ├─ customer_sk [FK → dim_customer] ├─ product_sk [FK → dim_product] ├─ store_sk [FK → dim_store] ├─ order_date_key [FK → dim_date (role)] ├─ delivery_date_key [FK → dim_date (role)] ├─ requested_qty [VBAP.KWMENG] ├─ confirmed_qty [VBEP.BMENG] ├─ net_value [VBAP.NETWR] ├─ lifecycle_state [CREATED/CONFIRMED/ │ DELIVERED/BILLED/COMPLETE] └─ perfect_order_flag [calculated]
Transactional Fact fact_order at order-line grain joins data from 4 SAP document categories (VBAK/VBAP/VBEP/VBKD) into one fact. The lifecycle_state column tracks each order through its states. This replaces the manual VBAK→LIKP→VTTK chain investigation.
Role-Playing Dimensions dim_date is used twice: once as order_date_key and once as delivery_date_key. This Kimball pattern enables “orders placed in January but delivered in March” analysis without self-joins.
Graph for Network Optimization The fulfillment graph overlays inventory data (dp_inventory_position) onto the network topology. This is fundamentally a shortest-path problem; the graph model enables real-time routing that the star schema cannot.
KA 8: Data Integration: Order-to-cash process integration across SD, LE, FI. KA 11: DW & BI: Operational BI for near-real-time fulfillment.
Component 4: Technology Architecture: Near-real-time data infrastructure. Component 5: Data Quality: Order data completeness for SLA measurement.
fact_order is a transactional fact at order-line grain. Role-playing dim_date for order vs. delivery date. Graph overlay for network optimization.
No unified customer view. KNA1/KNB1/KNVV/KNVP/KNKK each hold a slice. Churn is invisible until the customer is gone. Segmentation is static and rule-based.
dim_customer, the transactional behavior layer is missing: no pre-computed aggregates for lifetime value, purchase frequency, recency, or category preferences.fact_sales are O(n²) and impractical at scale.dp_customer_360: total lifetime value, order frequency, recency, average basket, preferred categories, channel mix, credit utilization, loyalty tier.dp_customer_segmentation using ML clustering on 360 features. Replace static rules with data-driven segments.dp_customer_360. Store predictions in ml_training_snapshot.dp_customer_360 (Sprint 1). Source from the PDM star schema: dim_customer (master attributes) + fact_sales (aggregated: total_lifetime_value, total_orders, avg_basket_value, days_since_last_order, top_3_categories) + fact_order (order_frequency, avg_lead_time) + fact_return (return_rate, return_reasons) + credit utilization from dim_customer. Grain: one row per customer. Refreshed daily. This is ShaDey’s single customer intelligence hub.dp_customer_360: recency, frequency, monetary value (RFM), category_diversity, channel_mix, return_rate. Apply k-means or DBSCAN clustering. Output: segment labels (e.g., “High-Value Loyal”, “At-Risk Declining”, “New Growth”, “Price-Sensitive Seasonal”). Write segment_id back to dim_customer as a slowly-changing attribute. Retrain monthly.(:Customer)-[:PURCHASED {qty, date}]→(:Product) from fact_sales. Apply GDS algorithms: Jaccard similarity between customers based on purchase overlap, community detection (Louvain) for customer clusters, PageRank on products for “most connected” items. Output: look-alike audience lists for Marketing, product recommendation pairs for e-commerce.dp_customer_360: days_since_last_order (recency), order_frequency_trend (last 90d vs. prior 90d), return_rate_trend, category_concentration (Herfindahl index). Label: churned = no order in 120 days. Model: gradient boosting classifier. Store predictions in ml_training_snapshot with model_version, prediction_date, churn_probability. Alert Sales when high-value customers cross 70% churn probability threshold.dp_customer_360 (wide aggregate table) Grain: one row per customer ├─ customer_sk [FK → dim_customer] ├─ total_lifetime_value [SUM(fact_sales)] ├─ total_orders [COUNT(fact_order)] ├─ avg_basket_value [AVG order value] ├─ days_since_last_order[recency] ├─ top_categories [JSON array] ├─ return_rate [returns/orders] ├─ channel_mix [POS/ECOM/WHOLESALE %] ├─ credit_utilization [from dim_customer] ├─ segment_id [ML-assigned] └─ churn_probability [ML prediction] ml_training_snapshot ├─ model_id, model_version ├─ customer_sk, prediction_date ├─ churn_probability, segment_id └─ feature_vector_hash
Wide Aggregate Table dp_customer_360 pre-computes all customer metrics into a single row. This is a modeled data product, not an ad-hoc query. It aggregates from fact_sales, fact_order, fact_return, and dim_customer through documented transformations. Every customer question starts here.
ML as a Modeling Layer Segment labels and churn probabilities are derived attributes that flow back into the model. dim_customer.segment_id becomes a filter dimension: “show me sales trends for At-Risk customers.” ML outputs are first-class modeled entities with versioning, not ephemeral notebook outputs.
Graph for Affinity Customer-product affinity is a bipartite graph problem. Neo4j’s GDS library computes Jaccard similarity and community detection natively. The graph complements the star schema: the star schema answers “what did this customer buy?”; the graph answers “which customers are similar?”
KA 14: Big Data & Data Science: ML model lifecycle, feature engineering, model governance. KA 10: Reference & Master Data: Customer golden record as foundation for 360 views.
Component 1: Strategy: Customer analytics as strategic differentiator. Component 5: Data Quality: Customer data completeness drives ML model accuracy.
dp_customer_360 is a wide aggregate table. ML features stored in a feature store entity with versioning. Graph overlay for collaborative filtering.
Return data fragmented across 4 document types: sales return (VBAK type RE), return delivery (LIKP type LR), credit memo (VBRK type G2), and goods movements (MSEG 651/653). No unified return entity.
fact_return as a multi-source fact table. Union all 4 document types. Deduplicate on return chain.ref_return_reason reference table mapping all SAP reason codes to a unified hierarchy.dp_return_analytics: return rate by product/category/supplier, cost per unit, time to credit.fact_return (Sprint 1). Extract and union 4 sources: (1) VBAK/VBAP where AUART = 'RE' (return orders: customer, material, quantity, reason AUGRU), (2) LIKP/LIPS where LFART = 'LR' (return deliveries: actual returned qty, return date), (3) VBRK/VBRP where FKART = 'G2' (credit memos: credit amount, billing date), (4) MSEG where BWART IN ('651','653') (goods receipts for returns: batch, storage location). Deduplicate on return chain: link return order → return delivery → credit memo via VBFA (document flow table). Final grain: one row per returned line item.ref_return_reason (Sprint 1). Map all SAP reason codes to a unified 4-level hierarchy: Level 1 (Defective, Wrong Item, Customer Changed Mind, Damaged in Transit, Other), Level 2 (subcategories within each), Level 3 (specific defect codes from QM), Level 4 (free text for edge cases). Add return_reason_sk as a foreign key in fact_return. The Governance Council (P1) approves the taxonomy; the Customer Data Steward maintains it.dp_return_analytics (Sprint 2). Derive from fact_return + fact_sales + dim_product + dim_supplier: return_rate_by_product (returns / sales per product), return_rate_by_supplier (returns of products from supplier X / total sales of those products), avg_days_to_credit (credit_memo_date - return_order_date), return_cost_per_unit (estimated from CO cost center allocations). Serial returner detection: flag customers where return_rate > 3x category average.(:Return)-[:OF_PRODUCT]→(:Product)-[:FROM_BATCH]→(:Batch)-[:PRODUCED_BY]→(:Supplier). Query: “Are returns for product X concentrated in batches from supplier Y?” If 80% of returns for SKU-1234 come from batches produced at Plant A by Supplier Z, the root cause is supplier quality, not product design. Link to dp_quality_metrics (P8) for closed-loop quality improvement.fact_return (multi-source transactional fact) Grain: one row per returned line item ├─ return_sk [surrogate key] ├─ return_order_number [VBAK.VBELN type RE] ├─ customer_sk [FK → dim_customer] ├─ product_sk [FK → dim_product] ├─ store_sk [FK → dim_store] ├─ return_reason_sk [FK → ref_return_reason] ├─ return_date_key [FK → dim_date] ├─ returned_qty [LIPS.LFIMG] ├─ credit_amount [VBRP.NETWR type G2] ├─ batch_id [MSEG.CHARG] ├─ source_doc_type [RE/LR/G2/651] └─ original_order_sk [FK → fact_order] ref_return_reason (junk dimension) ├─ return_reason_sk ├─ reason_level_1 [Defective/Wrong/...] ├─ reason_level_2 [subcategory] └─ reason_level_3 [specific code]
Multi-Source Fact fact_return unions 4 disparate SAP document types into a single fact with a source_doc_type discriminator. The grain (one row per returned line item) is consistent regardless of source. This is the modeling solution to the “returns are not a first-class entity” problem.
Junk Dimension for Reasons ref_return_reason uses the Kimball junk dimension pattern to standardize free-text and locally-maintained reason codes into a governed hierarchy. Every return in fact_return has a foreign key to this reference dimension, enabling return-reason analytics across all channels and document types.
Cross-Fact Linkage fact_return.original_order_sk links back to fact_order, enabling: return rate = COUNT(fact_return) / COUNT(fact_order) per customer, per product, per period. This cross-fact relationship is only possible because both facts share conformed dimensions.
Graph for Root Cause The Neo4j return-to-root-cause graph traverses: return → product → batch → supplier. Pattern detection: “80% of returns for this SKU come from this supplier’s batches” is a 3-hop query. The star schema quantifies the problem; the graph finds the cause.
KA 5: Data Modeling: Multi-source fact design: union disparate document types into a single fact. KA 10: Reference Data: Standardized reason code taxonomies.
Component 3: Data Architecture: Reverse logistics as a first-class data domain. Component 5: Data Quality: Return reason completeness and consistency.
fact_return is a multi-source transactional fact with a source_doc_type discriminator. Grain = returned line item. Return reasons as a junk dimension.
P1Governance └─▸P2Data Modeling └─▸P3Master Data └─▸P4Lineage └─▸P5S/4HANA Migration ├─▸P6Analytics ──▸P11Pricing ──▸P12Fulfillment ──▸P13Customer Intel │ │ └─▸P7Demand ──▸P8Production ──▸P9Inventory ──▸P10Supply Chain │ └───────────────────▸P14Returns