Retail Inventory Intelligence
Gather per-branch inventory and competitor pricing data, then build a pricing competitiveness dashboard.
Workshop goals
By the time you finish this Workshop you will have built the following flow by hand inside D.Hub:
- Imported one scenario into portal in a single command, registering collections, datasets, code, pipelines, ontology, and a dashboard at once.
- Brought per-branch inventory and per-channel competitor pricing into the same collection and inspected the schemas of both source datasets.
- Applied the latest competitor prices to the inventory data via the
update_competitor_pricespipeline. - Toured the ontology — four entities (
RI_Product,RI_Branch,RI_Region,RI_Supplier) and three relations. - Analyzed the
inventory_overviewdashboard, which bundles pricing-competitiveness KPIs and per-branch / per-region visualizations. - (Optional) Run one cycle of natural-language queries against the graph using the assistant agent.
It's an integrated exercise that ties the collection, pipeline, ontology, and dashboard concepts from the Analyst and Engineer Paths into one real scenario. Recommended time is 90 minutes, stretching to about 100 with the optional section.
Prerequisites
- An analyst or engineer account with access to D.Hub portal (Editor or higher)
- ~2 MB of download room for one scenario zip
No terminal, Python, or dhub2-examples clone needed. Finishing the entry-level tutorials Import a scenario zip in one shot and Create your first collection first makes step 1 flow smoothly. Both tutorials are linked directly from the prerequisites card at the top of this Workshop.
1. Import the scenario (10 minutes)
Download one zip and feed it to portal's Import dialog — every asset in the scenario gets registered in a single pass.
retail_inventory_intelligence.zip Download(1.5 MB)With the zip in hand, go to Collections in the left sidebar. The more (⋯) menu next to the Explorer header (the page title Collections area) has an Import (가져오기) item. Open it, pick the zip you just downloaded, and watch the dialog show upload progress. When it finishes, one collection appears automatically.
Driven by manifest.json, the import creates the following in order:
- Collection
retail_inventory_intelligence(alias: Retail Inventory Analysis) - Three datasets —
retail_inventory,competitor_prices,update_competitor_price - Two code assets —
update_competitor_price(python),build_retail_ontology(python) - Two pipelines —
update_competitor_prices,ontology_materialization - Ontology — four entities (
RI_Product,RI_Branch,RI_Region,RI_Supplier) and three relations (RI_LOCATED_IN,RI_STOCKED_AT,RI_SUPPLIED_BY) - Dashboard
inventory_overview - Agent
retail-assistantand tool definitions
Right after import, look for retail_inventory_intelligence in the collection tree on the left of portal — that's step 1 done. The collection card header shows the asset count, and the number should match the list above.
2. Explore the data (10 minutes)
Inside the collection, open the Explorer to see how the assets are grouped.
Start with the three dataset cards:
retail_inventory(alias: Product Info) — Per-branch product inventory. 27 columns. Eleven branches, item codes,inventory_qty,outbound_qty,inventory_turnover_rate,selling_price_krw_synth,competitor_price_krw_synth,stockout_risk_flag_synth, and latitude/longitude coordinates all in one row.competitor_prices(alias: Competitor Pricing Data) — Competitor price observations by channel, branch, and product. 10 columns.item_codeis the join key withretail_inventory.update_competitor_price(alias: Competitor Price Update Result) — The pipeline output. Right after import, this may be empty or contain only sample parquet.
Click each dataset and check:
- The Schema tab — column names, types, and comments are mapped correctly
- The Preview tab — the row count is not zero (a few hundred rows for
retail_inventory) - The Versions tab — v1 is recorded right after import
Next, open the two Code assets (update_competitor_price.py, build_retail_ontology.py). You don't need to read the bodies — glance at the input/output signatures. All you need to keep in mind is that which datasets each code node consumes and emits lines up exactly with the pipeline diagram in the next step.
3. Run the pipeline once (15 minutes)
Now you'll send data through once. In the Pipelines section of the collection, click update_competitor_prices to open the Workflow editor.
You'll see three nodes:
- Left inputs:
retail_inventory,competitor_pricesdataset nodes - Center: the
update_competitor_pricecode node (python,cdcread mode) - Right output: the
update_competitor_pricedataset node (overwritewrite mode)
Click the code node and expand Script preview in the right panel — you'll see a one-liner: left-join retail_inventory and competitor_prices on item_code, then overwrite the competitor_price_krw_synth column with the latest value. The output always needs to reflect current market state, so it's in overwrite mode.
Hit Run at the top to execute once. Progress and step logs flow at the bottom of the run panel, and when it finishes the right-side output node's status flips to fresh. Go back to the collection tree and confirm that the row count and the freshness timestamp on the update_competitor_price dataset have updated.
4. Inspect the ontology (15 minutes)
Now the graph view. Open the Ontology area in the left sidebar and expand the entity list in the retail_inventory_intelligence collection context.
Four entities and three relations should be present.
| Type | Name | Meaning |
|---|---|---|
| Entity | RI_Product | Product master. id = item_code, name, price, PROD_GRP |
| Entity | RI_Branch | Branch master. id = branch_code, name, location, latitude/longitude |
| Entity | RI_Region | Region master. id = region_name (e.g. Seoul Gangnam) |
| Entity | RI_Supplier | Supplier master. id = supplier_name |
| Relation | RI_LOCATED_IN | RI_Branch → RI_Region |
| Relation | RI_STOCKED_AT | RI_Product → RI_Branch. Carries inventory, turnover, price, and stockout-risk attributes |
| Relation | RI_SUPPLIED_BY | RI_Product → RI_Supplier |
Click the RI_Product card and check the following in the Builder tab:
- The backing dataset is set to
update_competitor_price(this scenario loads the processed dataset into the graph) - The identifier key is
idand the display column isname - The attribute mapping connects
PROD_GRPandprice1:1 to dataset columns
Then open the Graph Explorer. If it's empty, you need to run the ontology_materialization pipeline once more. That pipeline takes update_competitor_price as input and upserts the seven RI_* tables (four entities + three relations). Once it finishes, the Explorer can see the first instances with a one-line Cypher query:
MATCH (p:RI_Product)-[r:RI_STOCKED_AT]->(b:RI_Branch)
RETURN p, r, b
LIMIT 25
When 25 product–branch edges appear in the graph panel, step 4 is complete. Double-clicking a node expands its neighbors — RI_LOCATED_IN reaches the region, RI_SUPPLIED_BY reaches the supplier, all in one step.
The query looks like this:
MATCH (b:RI_Branch)-[:RI_STOCKED_AT]-(p:RI_Product)-[:RI_SUPPLIED_BY]-(s:RI_Supplier)
WHERE b.name = 'Gangnam Finance Store'
RETURN p, s
LIMIT 50
5. Inspect the dashboard (15 minutes)
The final stop is the dashboard. In the Dashboards section of the collection, open inventory_overview (alias: Inventory Intelligence Dashboard). Thirteen widgets are laid out across four rows. Start with the five in the top row.
- Total inventory (statistic) —
SUM(inventory_qty)ofupdate_competitor_price, shown with theEAunit - Total outbound (statistic) —
SUM(outbound_qty) - Average turnover (statistic) —
AVG(inventory_turnover_rate)shown as % - Stockout risk (statistic) — Count of rows with
stockout_risk_flag_synth = 1 - Average discount rate (statistic) —
AVG(discount_rate_synth) * 100
All five are built in SQL Query mode. Click the ⋯ menu on the widget card and choose Edit and you can see the query body as-is. Compare with the Simple mode vs. Query mode toggle from the Analyst Path to see how each applies in practice.
The next row down has visualization widgets:
- Inventory / outbound by branch — Stacked bar chart.
UNION ALLof inventory vs. outbound onbranch_namerendered in one chart. - Daily outbound trend — Line chart.
delivery_dateon the X-axis, multi-series by branch. - Outbound heatmap by time of day — Intensity map of
delivery_time×branch_name. - Inventory share by branch — Donut chart, with percentage labels.
- Inventory detail table — Data table. Page size 10, sorting and search on.
The last row has three pricing-competitiveness widgets. Items priced above competitors (statistic), Average price gap by branch (bar), and Price adjustment candidates (table) all share the selling_price_krw_synth > competitor_price_krw_synth condition. Without running the step-3 pipeline first, the values on these three widgets become meaningless.
6. (Optional) Assistant agent (10 minutes)
If you have time left, call the retail-assistant agent that came with the scenario. In the collection's Agents area, open the Retail Assistant card and start a new session. Run one cycle with these two prompts:
- "Show the products sold at the Gangnam Finance Store and their suppliers."
- "List the five branches with the weakest pricing competitiveness versus competitors."
The agent runs Cypher through the ontology_graph_query tool and answers in tables, bar charts, and maps. When the response contains node markers like [[Gangnam Finance Store]], that signals two-way wiring with the Graph Explorer.
This step isn't on the Workshop's critical path, but touching the same graph from human, tool, and LLM points of view at once makes it a strong launch pad for the automation learning round.
7. What comes next (5 minutes)
If you made it here, you've crossed the spot on the Learn site's map where the analysis and visualization of the Analyst Path and the data modeling and pipelines of the Engineer Path meet in a single scenario. Pick the direction that pulls you most and take one more step.
- Reopen the Analyst Path's chart and DRS lessons and break the Query-mode behavior of this Workshop's widgets down to code.
- Move to the Engineer Path and go deeper into code nodes and pipeline options. The meaning of
cdcread mode andoverwritewrite mode is the subject of the next round. - Write your own domain scenario into
dhub2-examples. The Authoring page covers the manifest structure and PR checklist you should follow when authoring a new scenario.
Verification checklist
Self-check whether this Workshop is complete with the five items below.
retail_inventory_intelligenceappears in the collection tree with seven assets (three datasets, two code, two pipelines — excluding ontology, dashboard, and agent).- After running
update_competitor_prices, the freshness ofupdate_competitor_priceshows the latest timestamp. - The dashboard KPI Stockout risk is greater than 0 (the scenario data deliberately includes some stockout flags).
- Starting from one product in the Graph Explorer, you can expand branch nodes by following the
RI_STOCKED_ATrelation. - The dashboard freshness matches the update timestamp of the
update_competitor_pricedataset.