<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Building an End-to-End Store Order Forecasting System on Databricks: From Zero to Automated Pipeline in Community Articles</title>
    <link>https://community.databricks.com/t5/community-articles/building-an-end-to-end-store-order-forecasting-system-on/m-p/166651#M1471</link>
    <description>&lt;H2&gt;Why I Built This&lt;/H2&gt;&lt;P&gt;After nearly 15 years working in enterprise supply chain and data engineering — most recently as a Staff Engineer at a large national grocery retailer — I have seen firsthand how retail organizations struggle with one persistent problem: &lt;STRONG&gt;store-level demand forecasting at scale.&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;The consequences of getting it wrong are real. Overstock leads to waste, especially in perishable categories like meat, dairy, and produce. Understock leads to empty shelves, missed sales, and frustrated customers. Most enterprise retailers have forecasting systems, but they are often built on legacy infrastructure that is slow to adapt, difficult to extend, and opaque to the business users who rely on them.&lt;/P&gt;&lt;P&gt;I wanted to explore whether modern cloud-native tooling — specifically Databricks — could make it meaningfully easier to build a forecasting system that was not just technically sound, but operationally useful: one that translates ML forecasts directly into order recommendations, flags waste and stockout risks, and gives buyers a natural language interface to ask questions without writing SQL.&lt;/P&gt;&lt;P&gt;So I built one from scratch. This article documents what I built, how I built it, what broke along the way, and what I learned.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;The Goal&lt;/H2&gt;&lt;P&gt;Build a fully automated prototype retail order forecasting pipeline on Databricks that:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Ingests and cleans synthetic retail data (sales, inventory, deliveries, promotions)&lt;/LI&gt;&lt;LI&gt;Engineers features for ML training using Medallion Architecture&lt;/LI&gt;&lt;LI&gt;Trains per-category demand forecasting models with experiment tracking&lt;/LI&gt;&lt;LI&gt;Translates forecasts into actionable order recommendations with risk labels&lt;/LI&gt;&lt;LI&gt;Surfaces insights through an operational dashboard and natural language analytics&lt;/LI&gt;&lt;LI&gt;Runs automatically on a daily schedule&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;STRONG&gt;Scope:&lt;/STRONG&gt; 10 stores, 20 products, 52 weeks of synthetic data — small enough to build fast, structured enough to reflect real enterprise patterns.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Architecture Overview: Medallion + ML + Decision Engine&lt;/H2&gt;&lt;P&gt;The system follows the &lt;STRONG&gt;Medallion Architecture&lt;/STRONG&gt; — an industry-standard data engineering pattern that organizes data into progressively refined layers — extended with an ML layer, a decision engine, and operational outputs.&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;Raw CSV Files
     ↓
Bronze Layer  →  Raw Delta tables (never modified)
     ↓
Silver Layer  →  Cleaned, validated, quality-flagged data
     ↓
Gold Layer    →  Feature-engineered ML-ready + business-ready tables
     ↓
ML Models     →  LightGBM per category, tracked with MLflow
     ↓
Decision Engine → Order recommendations, risk labels, financial estimates
     ↓
Dashboard + Genie Space + Workflow Automation&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;Each layer has a distinct contract: Bronze preserves raw data exactly as received. Silver fixes quality issues visibly without silently dropping records. Gold produces model-ready and business-consumable tables. This separation makes the pipeline auditable, debuggable, and extensible.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 1: Synthetic Data Generation&lt;/H2&gt;&lt;P&gt;Since this was a prototype built on a trial Databricks environment, I generated all input data synthetically using Python and Pandas — no proprietary or real-world data was used.&lt;/P&gt;&lt;P&gt;Seven CSV datasets were generated and stored in a Databricks Volume:&lt;/P&gt;&lt;DIV&gt;File Purpose &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;sales.csv&lt;/TD&gt;&lt;TD&gt;10,400 rows — 10 stores × 20 SKUs × 52 weeks&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;inventory.csv&lt;/TD&gt;&lt;TD&gt;Perpetual stock on hand plus in-transit quantities&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;persistent_stock.csv&lt;/TD&gt;&lt;TD&gt;Physical counts every 4 weeks&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;deliveries.csv&lt;/TD&gt;&lt;TD&gt;Supplier delivery records with dates and quantities&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;stores.csv&lt;/TD&gt;&lt;TD&gt;Store reference data&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;products.csv&lt;/TD&gt;&lt;TD&gt;Product catalogue with shelf life and supplier lead times&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;promotions.csv&lt;/TD&gt;&lt;TD&gt;Promotional calendar&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&gt;One important consistency challenge: the stock_on_hand value in inventory.csv and the perpetual_stock value in persistent_stock.csv needed to align across datasets. I solved this by using a shared lookup dictionary during generation — a small but critical detail that would cause downstream join failures if ignored.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;First lesson learned:&lt;/STRONG&gt; Data consistency between input files is not automatic. Even in synthetic data generation, you need to explicitly enforce referential integrity across datasets.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 2: Bronze Layer — Raw Ingestion with Delta&lt;/H2&gt;&lt;P&gt;The Bronze layer reads each CSV using Apache Spark with schema inference and saves each file as a Delta table in the bronze schema.&lt;/P&gt;&lt;P&gt;Two design decisions here that matter in production contexts:&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;1. Added an ingestion timestamp at write time:&lt;/STRONG&gt;&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;python&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;&lt;SPAN&gt;df.withColumn("_ingested_at", current_timestamp())&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;This creates a simple audit trail — you always know when data arrived, which is essential for debugging pipeline failures.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;2. Used schema-safe overwrite:&lt;/STRONG&gt;&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;python&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;&lt;SPAN&gt;.mode("overwrite").option("overwriteSchema", "true")&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;During iterative development, schema changes between runs are common. Without overwriteSchema, Databricks will throw a DELTA_METADATA_MISMATCH error every time the schema evolves. This single option makes the notebook safely re-runnable.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; Delta tables are not just storage — they support versioning, ACID transactions, and time travel. Bronze equals raw data: ingest it, timestamp it, never modify it.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 3: Silver Layer — Clean Visibly, Never Silently&lt;/H2&gt;&lt;P&gt;The Silver layer is where data quality work happens. The critical design principle here: &lt;STRONG&gt;never silently drop bad records. Always flag them.&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;For each source table, I applied targeted cleaning:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Sales:&lt;/STRONG&gt; Deduplicated on store + SKU + week; fixed negative sales values; added a stockout_flag; joined store and product reference data; added calendar features (week of year, month, quarter)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Inventory:&lt;/STRONG&gt; Fixed negative stock values; joined perpetual stock with physical counts; calculated days_of_cover and shrinkage_pct&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Deliveries:&lt;/STRONG&gt; Calculated days_late, fill_rate_pct, and is_on_time per delivery record&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Products:&lt;/STRONG&gt; Added perishability_tier based on shelf life (critical for downstream waste risk scoring)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Promotions:&lt;/STRONG&gt; Added promo_duration_days and validated date ranges for consistency&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Rather than dropping rows with quality issues, each table gets a _quality_flag column marking records as clean, warning, or error. This means downstream teams can always trace data quality issues back to the source — an essential capability in any production data pipeline.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; The Silver rule is auditability. If something goes wrong in ML training or order recommendations, you need to be able to trace it back to the raw data. Silent drops make that impossible.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 4: Gold Layer — Feature Engineering for ML and Business&lt;/H2&gt;&lt;P&gt;The Gold layer is where raw cleaned data becomes model-ready features. This is the most complex and highest-value layer in the pipeline.&lt;/P&gt;&lt;P&gt;The primary ML training table — gold.weekly_sales_features — contains 35+ features per store, SKU, and week, including:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Temporal features:&lt;/STRONG&gt; Rolling 4-week and 13-week averages, year-over-year growth, seasonality index&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Demand volatility:&lt;/STRONG&gt; Rolling standard deviation of weekly sales&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Trend features:&lt;/STRONG&gt; 4-week vs. 13-week trend comparison (short-term vs. long-term momentum)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Promotion features:&lt;/STRONG&gt; Whether a promotion was active, promotion duration&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Inventory features:&lt;/STRONG&gt; Days of cover, stockout flag from Silver layer&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Holiday flags:&lt;/STRONG&gt; Week-level holiday indicators&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;In addition to the ML training table, the Gold layer produces two business-consumption tables:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;gold.inventory_health — latest stock position, waste risk score, and stockout risk label per store/SKU&lt;/LI&gt;&lt;LI&gt;gold.supplier_performance — OTIF %, fill rate %, lead-time mean and p90, reliability score per supplier/SKU&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; Window functions are essential here. Rolling averages, volatility calculations, and trend features all require looking back at prior rows — window functions let you do this entirely in SQL without leaving the table. Gold = model-ready and business-readable data in one layer.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 5: ML Forecasting — LightGBM with MLflow Tracking&lt;/H2&gt;&lt;P&gt;With 35+ features per store/SKU/week available in the Gold layer, I trained one LightGBM model per product category.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Why LightGBM?&lt;/STRONG&gt; It handles tabular data well, trains fast, and works naturally with the feature set I had — including categorical columns (store, SKU, region) encoded with LabelEncoder.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;The most important decision: time-based train/test split.&lt;/STRONG&gt;&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;python&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;&lt;SPAN&gt;# First 80% of weeks for training, last 20% for evaluation
cutoff_week = sorted_weeks[int(len(sorted_weeks) * 0.8)]
train = df[df['week'] &amp;lt;= cutoff_week]
test = df[df['week'] &amp;gt; cutoff_week]&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;In forecasting, a random train/test split causes &lt;STRONG&gt;data leakage&lt;/STRONG&gt; — the model sees future data during training. Always split by time.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Model results across 8 category models:&lt;/STRONG&gt;&lt;/P&gt;&lt;DIV&gt;Category MAPE &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;Meat&lt;/TD&gt;&lt;TD&gt;10.5%&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Snacks&lt;/TD&gt;&lt;TD&gt;10.8%&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Produce&lt;/TD&gt;&lt;TD&gt;11.6%&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Dairy&lt;/TD&gt;&lt;TD&gt;14.8%&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;&lt;STRONG&gt;Average&lt;/STRONG&gt;&lt;/TD&gt;&lt;TD&gt;&lt;STRONG&gt;12.3%&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&gt;A 12.3% average MAPE on synthetic data is a reasonable baseline. In production retail forecasting, MAPE targets typically range from 15–25% for perishable categories, so this prototype is in a credible range.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Quantile forecasting for uncertainty:&lt;/STRONG&gt; Rather than a single point forecast, I generated p10/p50/p90 forecasts using rolling standard deviation as the uncertainty measure. This is important for order recommendations — you want to know not just the expected demand, but the range of outcomes.&lt;/P&gt;&lt;P&gt;All models were registered in &lt;STRONG&gt;Unity Catalog Model Registry&lt;/STRONG&gt; with MLflow signatures. MLflow tracks every experiment run so you can compare models, roll back to prior versions, and audit exactly which model version produced which recommendations.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; Never use random splits in time-series forecasting. And always track experiments with MLflow — without it, you cannot reproduce or audit your results.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 6: Decision Engine — From Forecast to Action&lt;/H2&gt;&lt;P&gt;A forecast has no business value until it drives a decision. The Decision Engine translates ML forecasts into actionable order recommendations using a standard inventory replenishment formula:&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;Order Qty = Demand over lead time 
          + Safety Stock 
          - Stock on Hand 
          - In Transit&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;Key design decisions:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Service level by perishability:&lt;/STRONG&gt; High-tier perishable items use a 90% service level (tighter — less buffer to avoid waste); other items use 95% service level (more buffer to avoid stockouts)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Supplier reliability adjustment:&lt;/STRONG&gt; Order quantity is adjusted upward based on the supplier's historical fill rate from gold.supplier_performance&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Risk-based order status labels:&lt;/STRONG&gt;&lt;UL&gt;&lt;LI&gt;URGENT — immediate action required&lt;/LI&gt;&lt;LI&gt;PENDING_APPROVAL — needs review before placing&lt;/LI&gt;&lt;LI&gt;REVIEW_BEFORE_ORDERING — marginal case&lt;/LI&gt;&lt;LI&gt;NO_ORDER_NEEDED — sufficient stock&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;The output table gold.order_recommendations contains order quantity, waste risk score, stockout risk score, and financial estimates (unit cost × order quantity) for each store/SKU combination.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; The decision engine is where supply chain domain knowledge meets ML output. The formula, service levels, and risk labels all encode business rules — and these rules matter as much as model accuracy.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 7: Dashboard — Making the Forecast Visible&lt;/H2&gt;&lt;P&gt;I built a 9-tile operational dashboard using Databricks AI/BI Dashboards:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;4 KPI counters: total orders to place, total order value, urgent orders, waste risk count&lt;/LI&gt;&lt;LI&gt;Order status breakdown (bar chart)&lt;/LI&gt;&lt;LI&gt;Order units by category (bar chart)&lt;/LI&gt;&lt;LI&gt;Waste risk distribution by category (pie chart)&lt;/LI&gt;&lt;LI&gt;Inventory cover by category (bar chart)&lt;/LI&gt;&lt;LI&gt;Urgent orders detail table (full width)&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;The dashboard is connected directly to the Gold layer tables — it refreshes automatically when the daily workflow runs.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 8: Genie Space — Natural Language Analytics&lt;/H2&gt;&lt;P&gt;One of the most practically useful additions was the &lt;STRONG&gt;Databricks Genie Space&lt;/STRONG&gt; — an AI-powered natural language interface over the Gold tables.&lt;/P&gt;&lt;P&gt;I connected 5 Gold tables and added detailed context instructions explaining business terminology, table descriptions, and example questions. This enables buyers and operations managers to ask questions like:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;EM&gt;"Which stores have urgent orders today?"&lt;/EM&gt;&lt;/LI&gt;&lt;LI&gt;&lt;EM&gt;"Show me high waste risk Dairy SKUs"&lt;/EM&gt;&lt;/LI&gt;&lt;LI&gt;&lt;EM&gt;"Which supplier has the lowest fill rate this month?"&lt;/EM&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Without Genie, answering these questions requires either a SQL analyst or pre-built dashboard tiles for every possible question. Genie makes the data accessible to non-technical users directly.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; Curated Gold tables with good context instructions are the foundation of useful AI analytics. Garbage in, garbage out — Genie is only as good as the data and context you give it.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 9: Workflow Automation — Making It Repeatable&lt;/H2&gt;&lt;P&gt;The final stage ties everything together into an automated daily pipeline using Databricks Workflows:&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;01_bronze → 02_silver → 03_gold → 04_ml_model → 05_decision&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;5 tasks chained in dependency order, scheduled at 06:00 AM daily, with email notifications on success and failure. A manual test run confirmed all 5 tasks passed end to end.&lt;/P&gt;&lt;P&gt;This is the difference between a notebook experiment and an operational system. Automation creates a repeatable pipeline that runs without human intervention — and fails loudly when something goes wrong.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Errors I Hit and How I Fixed Them&lt;/H2&gt;&lt;P&gt;These are real errors from building the prototype — worth documenting because they will likely affect anyone following a similar path:&lt;/P&gt;&lt;DIV&gt;Error Root Cause Fix &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;DELTA_METADATA_MISMATCH&lt;/TD&gt;&lt;TD&gt;Schema changed between runs&lt;/TD&gt;&lt;TD&gt;Add option("overwriteSchema", "true")&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;ModuleNotFoundError: lightgbm&lt;/TD&gt;&lt;TD&gt;Not pre-installed on serverless compute&lt;/TD&gt;&lt;TD&gt;Add %pip install lightgbm at top of notebook&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;ValueError: pandas dtypes&lt;/TD&gt;&lt;TD&gt;Non-numeric columns in LightGBM features&lt;/TD&gt;&lt;TD&gt;Use pd.to_numeric(...).astype(float)&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;MlflowException: signature required&lt;/TD&gt;&lt;TD&gt;Unity Catalog requires model schema&lt;/TD&gt;&lt;TD&gt;Call infer_signature() before log_model()&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;RestException: directory not found&lt;/TD&gt;&lt;TD&gt;MLflow experiment parent path missing&lt;/TD&gt;&lt;TD&gt;Use WorkspaceClient().workspace.mkdirs()&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Window function in WHERE clause&lt;/TD&gt;&lt;TD&gt;SQL restriction&lt;/TD&gt;&lt;TD&gt;Move window function into a CTE first&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;timedelta numpy int error&lt;/TD&gt;&lt;TD&gt;NumPy vs Python int type mismatch&lt;/TD&gt;&lt;TD&gt;Wrap with int()&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;HR /&gt;&lt;H2&gt;What It Would Take to Go to Production&lt;/H2&gt;&lt;P&gt;This prototype was built on synthetic data in a trial environment. Taking it to production at enterprise scale would require:&lt;/P&gt;&lt;DIV&gt;Step Detail &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;Real data&lt;/TD&gt;&lt;TD&gt;Connect cloud data warehouse (e.g., GCP BigQuery) using Databricks connector&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Scale&lt;/TD&gt;&lt;TD&gt;Support 2,000+ stores — the pipeline architecture scales without code changes&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Governance&lt;/TD&gt;&lt;TD&gt;Configure Unity Catalog row- and column-level security&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Model monitoring&lt;/TD&gt;&lt;TD&gt;Add Lakehouse Monitoring for forecast drift detection&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;ERP integration&lt;/TD&gt;&lt;TD&gt;Push order_recommendations to procurement systems via REST API&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;CI/CD&lt;/TD&gt;&lt;TD&gt;Set up Databricks Asset Bundles for dev/staging/production promotion&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&gt;The Medallion Architecture and modular notebook design mean that each of these steps can be added incrementally without restructuring the pipeline.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Key Takeaways&lt;/H2&gt;&lt;OL&gt;&lt;LI&gt;&lt;STRONG&gt;Medallion Architecture works.&lt;/STRONG&gt; The Bronze → Silver → Gold separation is not just theoretical — it makes the pipeline debuggable, auditable, and extensible in practice.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Always split by time in forecasting.&lt;/STRONG&gt; Random splits cause data leakage and will produce misleadingly good training metrics that fall apart in production.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;The decision engine is as important as the model.&lt;/STRONG&gt; A 12% MAPE model produces no business value without a clear translation from forecast to order recommendation to risk label.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Flag quality issues visibly.&lt;/STRONG&gt; Never silently drop bad records. A _quality_flag column in Silver saves enormous debugging time downstream.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;MLflow tracking is non-negotiable.&lt;/STRONG&gt; Without experiment tracking, you cannot reproduce, compare, or audit your model results — especially important when models are making operational recommendations.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Genie Space lowers the barrier to insight.&lt;/STRONG&gt; With well-curated Gold tables and good context instructions, non-technical users can get answers without SQL — which changes how operations teams interact with forecasting data.&lt;/LI&gt;&lt;/OL&gt;&lt;HR /&gt;&lt;H2&gt;Final Thoughts&lt;/H2&gt;&lt;P&gt;Building this prototype in a single focused session on Databricks confirmed something I had suspected from years of enterprise supply chain work: &lt;STRONG&gt;the hardest problems in retail forecasting are not the ML algorithms — they are the data engineering foundations that make those algorithms trustworthy and operationally useful.&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;The Medallion Architecture, MLflow tracking, and the Decision Engine layer are what separate a notebook experiment from a system that a business can actually rely on. Getting those right matters more than squeezing another percentage point of MAPE.&lt;/P&gt;&lt;P&gt;If you are building something similar — whether for retail, logistics, or any demand-driven supply chain — I hope the architecture, the errors, and the lessons documented here save you some of the discovery time I spent.&lt;/P&gt;</description>
    <pubDate>Thu, 27 Aug 2026 20:24:51 GMT</pubDate>
    <dc:creator>Aafaq_Mohammed</dc:creator>
    <dc:date>2026-08-27T20:24:51Z</dc:date>
    <item>
      <title>Building an End-to-End Store Order Forecasting System on Databricks: From Zero to Automated Pipeline</title>
      <link>https://community.databricks.com/t5/community-articles/building-an-end-to-end-store-order-forecasting-system-on/m-p/166651#M1471</link>
      <description>&lt;H2&gt;Why I Built This&lt;/H2&gt;&lt;P&gt;After nearly 15 years working in enterprise supply chain and data engineering — most recently as a Staff Engineer at a large national grocery retailer — I have seen firsthand how retail organizations struggle with one persistent problem: &lt;STRONG&gt;store-level demand forecasting at scale.&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;The consequences of getting it wrong are real. Overstock leads to waste, especially in perishable categories like meat, dairy, and produce. Understock leads to empty shelves, missed sales, and frustrated customers. Most enterprise retailers have forecasting systems, but they are often built on legacy infrastructure that is slow to adapt, difficult to extend, and opaque to the business users who rely on them.&lt;/P&gt;&lt;P&gt;I wanted to explore whether modern cloud-native tooling — specifically Databricks — could make it meaningfully easier to build a forecasting system that was not just technically sound, but operationally useful: one that translates ML forecasts directly into order recommendations, flags waste and stockout risks, and gives buyers a natural language interface to ask questions without writing SQL.&lt;/P&gt;&lt;P&gt;So I built one from scratch. This article documents what I built, how I built it, what broke along the way, and what I learned.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;The Goal&lt;/H2&gt;&lt;P&gt;Build a fully automated prototype retail order forecasting pipeline on Databricks that:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Ingests and cleans synthetic retail data (sales, inventory, deliveries, promotions)&lt;/LI&gt;&lt;LI&gt;Engineers features for ML training using Medallion Architecture&lt;/LI&gt;&lt;LI&gt;Trains per-category demand forecasting models with experiment tracking&lt;/LI&gt;&lt;LI&gt;Translates forecasts into actionable order recommendations with risk labels&lt;/LI&gt;&lt;LI&gt;Surfaces insights through an operational dashboard and natural language analytics&lt;/LI&gt;&lt;LI&gt;Runs automatically on a daily schedule&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;STRONG&gt;Scope:&lt;/STRONG&gt; 10 stores, 20 products, 52 weeks of synthetic data — small enough to build fast, structured enough to reflect real enterprise patterns.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Architecture Overview: Medallion + ML + Decision Engine&lt;/H2&gt;&lt;P&gt;The system follows the &lt;STRONG&gt;Medallion Architecture&lt;/STRONG&gt; — an industry-standard data engineering pattern that organizes data into progressively refined layers — extended with an ML layer, a decision engine, and operational outputs.&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;Raw CSV Files
     ↓
Bronze Layer  →  Raw Delta tables (never modified)
     ↓
Silver Layer  →  Cleaned, validated, quality-flagged data
     ↓
Gold Layer    →  Feature-engineered ML-ready + business-ready tables
     ↓
ML Models     →  LightGBM per category, tracked with MLflow
     ↓
Decision Engine → Order recommendations, risk labels, financial estimates
     ↓
Dashboard + Genie Space + Workflow Automation&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;Each layer has a distinct contract: Bronze preserves raw data exactly as received. Silver fixes quality issues visibly without silently dropping records. Gold produces model-ready and business-consumable tables. This separation makes the pipeline auditable, debuggable, and extensible.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 1: Synthetic Data Generation&lt;/H2&gt;&lt;P&gt;Since this was a prototype built on a trial Databricks environment, I generated all input data synthetically using Python and Pandas — no proprietary or real-world data was used.&lt;/P&gt;&lt;P&gt;Seven CSV datasets were generated and stored in a Databricks Volume:&lt;/P&gt;&lt;DIV&gt;File Purpose &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;sales.csv&lt;/TD&gt;&lt;TD&gt;10,400 rows — 10 stores × 20 SKUs × 52 weeks&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;inventory.csv&lt;/TD&gt;&lt;TD&gt;Perpetual stock on hand plus in-transit quantities&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;persistent_stock.csv&lt;/TD&gt;&lt;TD&gt;Physical counts every 4 weeks&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;deliveries.csv&lt;/TD&gt;&lt;TD&gt;Supplier delivery records with dates and quantities&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;stores.csv&lt;/TD&gt;&lt;TD&gt;Store reference data&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;products.csv&lt;/TD&gt;&lt;TD&gt;Product catalogue with shelf life and supplier lead times&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;promotions.csv&lt;/TD&gt;&lt;TD&gt;Promotional calendar&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&gt;One important consistency challenge: the stock_on_hand value in inventory.csv and the perpetual_stock value in persistent_stock.csv needed to align across datasets. I solved this by using a shared lookup dictionary during generation — a small but critical detail that would cause downstream join failures if ignored.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;First lesson learned:&lt;/STRONG&gt; Data consistency between input files is not automatic. Even in synthetic data generation, you need to explicitly enforce referential integrity across datasets.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 2: Bronze Layer — Raw Ingestion with Delta&lt;/H2&gt;&lt;P&gt;The Bronze layer reads each CSV using Apache Spark with schema inference and saves each file as a Delta table in the bronze schema.&lt;/P&gt;&lt;P&gt;Two design decisions here that matter in production contexts:&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;1. Added an ingestion timestamp at write time:&lt;/STRONG&gt;&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;python&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;&lt;SPAN&gt;df.withColumn("_ingested_at", current_timestamp())&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;This creates a simple audit trail — you always know when data arrived, which is essential for debugging pipeline failures.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;2. Used schema-safe overwrite:&lt;/STRONG&gt;&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;python&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;&lt;SPAN&gt;.mode("overwrite").option("overwriteSchema", "true")&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;During iterative development, schema changes between runs are common. Without overwriteSchema, Databricks will throw a DELTA_METADATA_MISMATCH error every time the schema evolves. This single option makes the notebook safely re-runnable.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; Delta tables are not just storage — they support versioning, ACID transactions, and time travel. Bronze equals raw data: ingest it, timestamp it, never modify it.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 3: Silver Layer — Clean Visibly, Never Silently&lt;/H2&gt;&lt;P&gt;The Silver layer is where data quality work happens. The critical design principle here: &lt;STRONG&gt;never silently drop bad records. Always flag them.&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;For each source table, I applied targeted cleaning:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Sales:&lt;/STRONG&gt; Deduplicated on store + SKU + week; fixed negative sales values; added a stockout_flag; joined store and product reference data; added calendar features (week of year, month, quarter)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Inventory:&lt;/STRONG&gt; Fixed negative stock values; joined perpetual stock with physical counts; calculated days_of_cover and shrinkage_pct&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Deliveries:&lt;/STRONG&gt; Calculated days_late, fill_rate_pct, and is_on_time per delivery record&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Products:&lt;/STRONG&gt; Added perishability_tier based on shelf life (critical for downstream waste risk scoring)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Promotions:&lt;/STRONG&gt; Added promo_duration_days and validated date ranges for consistency&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Rather than dropping rows with quality issues, each table gets a _quality_flag column marking records as clean, warning, or error. This means downstream teams can always trace data quality issues back to the source — an essential capability in any production data pipeline.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; The Silver rule is auditability. If something goes wrong in ML training or order recommendations, you need to be able to trace it back to the raw data. Silent drops make that impossible.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 4: Gold Layer — Feature Engineering for ML and Business&lt;/H2&gt;&lt;P&gt;The Gold layer is where raw cleaned data becomes model-ready features. This is the most complex and highest-value layer in the pipeline.&lt;/P&gt;&lt;P&gt;The primary ML training table — gold.weekly_sales_features — contains 35+ features per store, SKU, and week, including:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Temporal features:&lt;/STRONG&gt; Rolling 4-week and 13-week averages, year-over-year growth, seasonality index&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Demand volatility:&lt;/STRONG&gt; Rolling standard deviation of weekly sales&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Trend features:&lt;/STRONG&gt; 4-week vs. 13-week trend comparison (short-term vs. long-term momentum)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Promotion features:&lt;/STRONG&gt; Whether a promotion was active, promotion duration&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Inventory features:&lt;/STRONG&gt; Days of cover, stockout flag from Silver layer&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Holiday flags:&lt;/STRONG&gt; Week-level holiday indicators&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;In addition to the ML training table, the Gold layer produces two business-consumption tables:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;gold.inventory_health — latest stock position, waste risk score, and stockout risk label per store/SKU&lt;/LI&gt;&lt;LI&gt;gold.supplier_performance — OTIF %, fill rate %, lead-time mean and p90, reliability score per supplier/SKU&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; Window functions are essential here. Rolling averages, volatility calculations, and trend features all require looking back at prior rows — window functions let you do this entirely in SQL without leaving the table. Gold = model-ready and business-readable data in one layer.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 5: ML Forecasting — LightGBM with MLflow Tracking&lt;/H2&gt;&lt;P&gt;With 35+ features per store/SKU/week available in the Gold layer, I trained one LightGBM model per product category.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Why LightGBM?&lt;/STRONG&gt; It handles tabular data well, trains fast, and works naturally with the feature set I had — including categorical columns (store, SKU, region) encoded with LabelEncoder.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;The most important decision: time-based train/test split.&lt;/STRONG&gt;&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;python&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;&lt;SPAN&gt;# First 80% of weeks for training, last 20% for evaluation
cutoff_week = sorted_weeks[int(len(sorted_weeks) * 0.8)]
train = df[df['week'] &amp;lt;= cutoff_week]
test = df[df['week'] &amp;gt; cutoff_week]&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;In forecasting, a random train/test split causes &lt;STRONG&gt;data leakage&lt;/STRONG&gt; — the model sees future data during training. Always split by time.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Model results across 8 category models:&lt;/STRONG&gt;&lt;/P&gt;&lt;DIV&gt;Category MAPE &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;Meat&lt;/TD&gt;&lt;TD&gt;10.5%&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Snacks&lt;/TD&gt;&lt;TD&gt;10.8%&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Produce&lt;/TD&gt;&lt;TD&gt;11.6%&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Dairy&lt;/TD&gt;&lt;TD&gt;14.8%&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;&lt;STRONG&gt;Average&lt;/STRONG&gt;&lt;/TD&gt;&lt;TD&gt;&lt;STRONG&gt;12.3%&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&gt;A 12.3% average MAPE on synthetic data is a reasonable baseline. In production retail forecasting, MAPE targets typically range from 15–25% for perishable categories, so this prototype is in a credible range.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Quantile forecasting for uncertainty:&lt;/STRONG&gt; Rather than a single point forecast, I generated p10/p50/p90 forecasts using rolling standard deviation as the uncertainty measure. This is important for order recommendations — you want to know not just the expected demand, but the range of outcomes.&lt;/P&gt;&lt;P&gt;All models were registered in &lt;STRONG&gt;Unity Catalog Model Registry&lt;/STRONG&gt; with MLflow signatures. MLflow tracks every experiment run so you can compare models, roll back to prior versions, and audit exactly which model version produced which recommendations.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; Never use random splits in time-series forecasting. And always track experiments with MLflow — without it, you cannot reproduce or audit your results.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 6: Decision Engine — From Forecast to Action&lt;/H2&gt;&lt;P&gt;A forecast has no business value until it drives a decision. The Decision Engine translates ML forecasts into actionable order recommendations using a standard inventory replenishment formula:&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;Order Qty = Demand over lead time 
          + Safety Stock 
          - Stock on Hand 
          - In Transit&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;Key design decisions:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Service level by perishability:&lt;/STRONG&gt; High-tier perishable items use a 90% service level (tighter — less buffer to avoid waste); other items use 95% service level (more buffer to avoid stockouts)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Supplier reliability adjustment:&lt;/STRONG&gt; Order quantity is adjusted upward based on the supplier's historical fill rate from gold.supplier_performance&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Risk-based order status labels:&lt;/STRONG&gt;&lt;UL&gt;&lt;LI&gt;URGENT — immediate action required&lt;/LI&gt;&lt;LI&gt;PENDING_APPROVAL — needs review before placing&lt;/LI&gt;&lt;LI&gt;REVIEW_BEFORE_ORDERING — marginal case&lt;/LI&gt;&lt;LI&gt;NO_ORDER_NEEDED — sufficient stock&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;The output table gold.order_recommendations contains order quantity, waste risk score, stockout risk score, and financial estimates (unit cost × order quantity) for each store/SKU combination.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; The decision engine is where supply chain domain knowledge meets ML output. The formula, service levels, and risk labels all encode business rules — and these rules matter as much as model accuracy.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 7: Dashboard — Making the Forecast Visible&lt;/H2&gt;&lt;P&gt;I built a 9-tile operational dashboard using Databricks AI/BI Dashboards:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;4 KPI counters: total orders to place, total order value, urgent orders, waste risk count&lt;/LI&gt;&lt;LI&gt;Order status breakdown (bar chart)&lt;/LI&gt;&lt;LI&gt;Order units by category (bar chart)&lt;/LI&gt;&lt;LI&gt;Waste risk distribution by category (pie chart)&lt;/LI&gt;&lt;LI&gt;Inventory cover by category (bar chart)&lt;/LI&gt;&lt;LI&gt;Urgent orders detail table (full width)&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;The dashboard is connected directly to the Gold layer tables — it refreshes automatically when the daily workflow runs.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 8: Genie Space — Natural Language Analytics&lt;/H2&gt;&lt;P&gt;One of the most practically useful additions was the &lt;STRONG&gt;Databricks Genie Space&lt;/STRONG&gt; — an AI-powered natural language interface over the Gold tables.&lt;/P&gt;&lt;P&gt;I connected 5 Gold tables and added detailed context instructions explaining business terminology, table descriptions, and example questions. This enables buyers and operations managers to ask questions like:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;EM&gt;"Which stores have urgent orders today?"&lt;/EM&gt;&lt;/LI&gt;&lt;LI&gt;&lt;EM&gt;"Show me high waste risk Dairy SKUs"&lt;/EM&gt;&lt;/LI&gt;&lt;LI&gt;&lt;EM&gt;"Which supplier has the lowest fill rate this month?"&lt;/EM&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Without Genie, answering these questions requires either a SQL analyst or pre-built dashboard tiles for every possible question. Genie makes the data accessible to non-technical users directly.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key concept:&lt;/STRONG&gt; Curated Gold tables with good context instructions are the foundation of useful AI analytics. Garbage in, garbage out — Genie is only as good as the data and context you give it.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Stage 9: Workflow Automation — Making It Repeatable&lt;/H2&gt;&lt;P&gt;The final stage ties everything together into an automated daily pipeline using Databricks Workflows:&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;PRE&gt;01_bronze → 02_silver → 03_gold → 04_ml_model → 05_decision&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;5 tasks chained in dependency order, scheduled at 06:00 AM daily, with email notifications on success and failure. A manual test run confirmed all 5 tasks passed end to end.&lt;/P&gt;&lt;P&gt;This is the difference between a notebook experiment and an operational system. Automation creates a repeatable pipeline that runs without human intervention — and fails loudly when something goes wrong.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Errors I Hit and How I Fixed Them&lt;/H2&gt;&lt;P&gt;These are real errors from building the prototype — worth documenting because they will likely affect anyone following a similar path:&lt;/P&gt;&lt;DIV&gt;Error Root Cause Fix &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;DELTA_METADATA_MISMATCH&lt;/TD&gt;&lt;TD&gt;Schema changed between runs&lt;/TD&gt;&lt;TD&gt;Add option("overwriteSchema", "true")&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;ModuleNotFoundError: lightgbm&lt;/TD&gt;&lt;TD&gt;Not pre-installed on serverless compute&lt;/TD&gt;&lt;TD&gt;Add %pip install lightgbm at top of notebook&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;ValueError: pandas dtypes&lt;/TD&gt;&lt;TD&gt;Non-numeric columns in LightGBM features&lt;/TD&gt;&lt;TD&gt;Use pd.to_numeric(...).astype(float)&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;MlflowException: signature required&lt;/TD&gt;&lt;TD&gt;Unity Catalog requires model schema&lt;/TD&gt;&lt;TD&gt;Call infer_signature() before log_model()&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;RestException: directory not found&lt;/TD&gt;&lt;TD&gt;MLflow experiment parent path missing&lt;/TD&gt;&lt;TD&gt;Use WorkspaceClient().workspace.mkdirs()&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Window function in WHERE clause&lt;/TD&gt;&lt;TD&gt;SQL restriction&lt;/TD&gt;&lt;TD&gt;Move window function into a CTE first&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;timedelta numpy int error&lt;/TD&gt;&lt;TD&gt;NumPy vs Python int type mismatch&lt;/TD&gt;&lt;TD&gt;Wrap with int()&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;HR /&gt;&lt;H2&gt;What It Would Take to Go to Production&lt;/H2&gt;&lt;P&gt;This prototype was built on synthetic data in a trial environment. Taking it to production at enterprise scale would require:&lt;/P&gt;&lt;DIV&gt;Step Detail &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;Real data&lt;/TD&gt;&lt;TD&gt;Connect cloud data warehouse (e.g., GCP BigQuery) using Databricks connector&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Scale&lt;/TD&gt;&lt;TD&gt;Support 2,000+ stores — the pipeline architecture scales without code changes&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Governance&lt;/TD&gt;&lt;TD&gt;Configure Unity Catalog row- and column-level security&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Model monitoring&lt;/TD&gt;&lt;TD&gt;Add Lakehouse Monitoring for forecast drift detection&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;ERP integration&lt;/TD&gt;&lt;TD&gt;Push order_recommendations to procurement systems via REST API&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;CI/CD&lt;/TD&gt;&lt;TD&gt;Set up Databricks Asset Bundles for dev/staging/production promotion&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&gt;The Medallion Architecture and modular notebook design mean that each of these steps can be added incrementally without restructuring the pipeline.&lt;/P&gt;&lt;HR /&gt;&lt;H2&gt;Key Takeaways&lt;/H2&gt;&lt;OL&gt;&lt;LI&gt;&lt;STRONG&gt;Medallion Architecture works.&lt;/STRONG&gt; The Bronze → Silver → Gold separation is not just theoretical — it makes the pipeline debuggable, auditable, and extensible in practice.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Always split by time in forecasting.&lt;/STRONG&gt; Random splits cause data leakage and will produce misleadingly good training metrics that fall apart in production.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;The decision engine is as important as the model.&lt;/STRONG&gt; A 12% MAPE model produces no business value without a clear translation from forecast to order recommendation to risk label.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Flag quality issues visibly.&lt;/STRONG&gt; Never silently drop bad records. A _quality_flag column in Silver saves enormous debugging time downstream.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;MLflow tracking is non-negotiable.&lt;/STRONG&gt; Without experiment tracking, you cannot reproduce, compare, or audit your model results — especially important when models are making operational recommendations.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Genie Space lowers the barrier to insight.&lt;/STRONG&gt; With well-curated Gold tables and good context instructions, non-technical users can get answers without SQL — which changes how operations teams interact with forecasting data.&lt;/LI&gt;&lt;/OL&gt;&lt;HR /&gt;&lt;H2&gt;Final Thoughts&lt;/H2&gt;&lt;P&gt;Building this prototype in a single focused session on Databricks confirmed something I had suspected from years of enterprise supply chain work: &lt;STRONG&gt;the hardest problems in retail forecasting are not the ML algorithms — they are the data engineering foundations that make those algorithms trustworthy and operationally useful.&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;The Medallion Architecture, MLflow tracking, and the Decision Engine layer are what separate a notebook experiment from a system that a business can actually rely on. Getting those right matters more than squeezing another percentage point of MAPE.&lt;/P&gt;&lt;P&gt;If you are building something similar — whether for retail, logistics, or any demand-driven supply chain — I hope the architecture, the errors, and the lessons documented here save you some of the discovery time I spent.&lt;/P&gt;</description>
      <pubDate>Thu, 27 Aug 2026 20:24:51 GMT</pubDate>
      <guid>https://community.databricks.com/t5/community-articles/building-an-end-to-end-store-order-forecasting-system-on/m-p/166651#M1471</guid>
      <dc:creator>Aafaq_Mohammed</dc:creator>
      <dc:date>2026-08-27T20:24:51Z</dc:date>
    </item>
    <item>
      <title>Re: Building an End-to-End Store Order Forecasting System on Databricks: From Zero to Automated Pipe</title>
      <link>https://community.databricks.com/t5/community-articles/building-an-end-to-end-store-order-forecasting-system-on/m-p/166674#M1472</link>
      <description>&lt;P&gt;Really solid project—especially the focus on turning ML forecasts into practical order recommendations. The data quality and decision-engine approach makes it genuinely useful.&lt;/P&gt;</description>
      <pubDate>Fri, 28 Aug 2026 09:50:30 GMT</pubDate>
      <guid>https://community.databricks.com/t5/community-articles/building-an-end-to-end-store-order-forecasting-system-on/m-p/166674#M1472</guid>
      <dc:creator>davidwarner344</dc:creator>
      <dc:date>2026-08-28T09:50:30Z</dc:date>
    </item>
  </channel>
</rss>

