Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@ jobs:
- name: Install dependencies
run: npm install

- name: Type check
run: npx tsc --noEmit

- name: Build
run: npm run build

- name: Deploy to GitHub Pages
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
149 changes: 149 additions & 0 deletions METHODOLOGY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Methodology & Assumptions

This document makes the model defensible. Every figure in the app derives from the
inputs and formulas below. Numbers are **illustrative** — calibrated to OEM scale so
the narrative is coherent, not pulled from Hyundai's actuals.

## 1. Scope & unit of analysis

- **Market:** single market (U.S.), national aggregate. Not modeled per-region or per-dealer.
- **Cadence:** monthly demand, expressed as steady-state run-rate.
- **Pipeline:** units in the national pipeline (in-transit + on-lot), valued at OEM wholesale cost.
- **Currency:** USD, OEM wholesale (not retail/MSRP), to keep capital-at-risk on a cost basis.

## 2. Inputs (per model)

| Field | Meaning |
|---|---|
| `stock` | Units in the national pipeline |
| `avgMonthlySales` | Steady-state monthly demand (units) |
| `unitCost` | OEM wholesale cost per unit (USD) |
| `category` | Luxury / EV / SUV / Volume — drives the target DSI |

## 3. Core formulas

```
dailySales = avgMonthlySales × (1 + demandShift) / 30
DSI = stock / dailySales # days of inventory on hand
targetStock = targetDSI[category] × dailySales
excessUnits = max(0, stock − targetStock)
excessCapital = excessUnits × unitCost
carryingOnExcess= excessCapital × carryingRate # annual $ bled on the excess
liquidationLoss = excessCapital × liquidationDiscount # one-time clearance haircut
recaptured = excessCapital × (1 − liquidationDiscount)
netFirstYear = carryingOnExcess − liquidationLoss
portfolioDSI = Σ stock / Σ dailySales # volume-weighted, not a simple average
```

**Status rule (segment-specific, not one universal cutoff):**

- `At Risk` — `DSI > targetDSI` (over-stocked relative to the segment's velocity)
- `Stockout Risk` — `DSI < 0.5 × targetDSI` (too lean; turning away serviceable demand)
- `Healthy` — otherwise

## 4. Segment DSI targets (rationale)

High-margin, low-velocity segments tolerate more days on hand; fast-turning volume
segments do not. A uniform threshold would contradict the thesis.

| Segment | Target DSI | Rationale |
|---|---|---|
| Luxury | 75 | Low velocity, high margin; longer hold is economic |
| EV | 70 | Elevated by residual-value risk during the BEV transition |
| SUV | 60 | Mainstream mid-velocity |
| Volume | 45 | High turnover; lean target protects ROIC |

## 5. Decision rule

For each above-target pool, act **only when `netFirstYear > 0`** — i.e. the annual
carrying cost avoided exceeds the one-time clearance loss. Recaptured capital is then
redeployed against `Stockout Risk` pools first (relieving lost-sale demand), with the
remainder funding strategic EV / growth priorities. This resolves the
redirect-vs-liquidate distinction: transfer where a constrained pool can absorb units,
clear only where none can.

## 6. Scenario parameters (defaults & ranges)

| Parameter | Default | Range | Source logic |
|---|---|---|---|
| `carryingRate` | 18%/yr | 8–28% | Floorplan interest (~8%) + depreciation (~7%) + storage/insurance (~3%) |
| `liquidationDiscount` | 6% | 2–15% | Wholesale/auction haircut to clear excess units |
| `demandShift` | 0% | −20% to +20% | Demand stress test |

## 7. Baseline results (default assumptions)

| Metric | Value |
|---|---|
| Capital deployed | $2.87B |
| Capital above target | $412M (14% of deployed) |
| Annualized carrying cost on excess | $74M/yr |
| Capital recaptured (net of discount) | $387M |
| One-time clearance loss | $25M |
| First-year net benefit | $49M |
| Stockout-risk funding gap | $216M (fully covered by recaptured capital) |
| Portfolio DSI (volume-weighted) | 50 days |

## 8. Sensitivity (illustrative)

- **Carrying rate is the swing factor.** At 8% the annual bleed falls to ~$33M and several
pools no longer clear the net-benefit hurdle; at 28% it rises past ~$115M and clearance is
obviously worth it. This is why the rate assumption must be owned by Finance, not assumed.
- **Clearance discount** mostly affects *how much* is recaptured, not *whether* to act,
until it approaches the carrying rate.
- **Demand shift** moves pools across thresholds — a −10% shock pushes additional volume/SUV
pools above target; +10% relieves them. The status logic recomputes live.

## 9. Known limitations (and the honest next steps)

- **No regional granularity.** A real reallocation engine needs per-region inventory and demand
to choose transfer-vs-clear; this models the portfolio level. *Next step: a region × model matrix.*
- **Contribution margin not modeled**, so redeployment upside is stated as the funded demand gap,
not an incremental-profit figure. *Next step: per-segment margin to value recaptured capital.*
- **Steady-state demand** — no seasonality, model-year transitions, or incentive elasticity.
- **Single-period view** — `netFirstYear` mixes a recurring annual saving with a one-time loss;
a full NPV would discount multi-year carrying savings. *Next step: multi-period NPV.*
- Figures are illustrative and not Hyundai actuals.

## 10. Retail & DMS layer

The retail view drills the portfolio thesis down to the dealer P&L, where above-target
capital becomes **aged inventory carrying floorplan interest**.

**Data lineage.** The Dealer Management System (CDK, Reynolds & Reynolds, Tekion, etc.) is
the system of record. VIN-level in-stock dates, F&I and sales transactions, and RDR (retail
delivery reporting) to the OEM are the source for days-on-lot, floorplan balance, and turn.
DMS vendors are named for context only — no affiliation or endorsement.

**Inputs (per dealer):** `avgUnitCost`, `monthlySales`, and an aging vector
(`0–30 / 31–60 / 61–90 / 90+` day buckets, in units).

```
onLot = Σ aging buckets
agedUnits = units 61–90 + units 90+ # > 60 days
criticalUnits = units 90+ # floorplan-curtailment territory
agedShare = agedUnits / onLot
daysSupply = onLot / (monthlySales / 30)
turn (annual) = monthlySales × 12 / onLot
floorplanMonth = onLot × avgUnitCost × (floorplanAPR / 12)
agedFloorplanMo = agedUnits × avgUnitCost × (floorplanAPR / 12) # recoverable waste
```

**Floorplan APR:** 9.5% (constant). At 90+ days most floorplan lenders require principal
curtailment, so 90+ is treated as the critical bucket.

**Retail lever rule (heuristic):**

- `agedShare > 25%` → **Targeted incentive** if turn > 9x (the store can retail its way out),
else **Dealer trade + incentive** (move units to a higher-velocity rooftop).
- `agedShare 15–25%` → **Promote pre-90d** (act before curtailment).
- otherwise → **Hold**.

**Baseline network result (illustrative, 5 rooftops):** 540 units on lot, 31% aged > 60 days,
$17.8M floorplan balance costing ~$141K/mo, of which ~$48K/mo is burned on aged units. The
EV-heavy and luxury rooftops carry ~43% aged inventory — the same IONIQ 5 / Genesis pressure
from the OEM layer, now visible as floorplan cost.

**Retail-layer limitations / next steps:** front + back-end gross erosion by age bucket is not
yet modeled (would quantify the *margin* cost of aging, not just floorplan); dealer-trade
logistics cost is assumed negligible; and a live DMS integration (vs. illustrative aging
vectors) is the obvious productionization step.
126 changes: 67 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,87 +1,95 @@
# OEM Inventory Health Dashboard
# OEM Inventory Health

A strategic **Days Sales of Inventory (DSI)** optimization platform for automotive OEM supply chain management. This interactive dashboard enables executives to monitor global fleet health, identify capital-locked inventory, and execute real-time reallocation strategies across regional channels.
**A decision-support model for automotive inventory strategy — from OEM portfolio down to the dealer lot. Answer-first brief, a live net-benefit engine, a governed rollout plan, and a DMS-sourced retail view.**

## Features
🔗 **Live:** https://privatejoel.github.io/OEM-Inventory-Health/
📄 **Methodology & assumptions:** [METHODOLOGY.md](./METHODOLOGY.md)

- 📊 **Real-Time DSI Monitoring** – Calculates Days Sales of Inventory metrics across vehicle segments
- 🎯 **Capital Leakage Detection** – Identifies at-risk inventory (DSI > 60 days) prone to depreciation
- 🔄 **Inventory Redirection Simulation** – Model 30% capital reallocation with 6% liquidation loss vs. 15% holding-cost savings
- 📈 **Multi-Segment Analytics** – Track Luxury, Volume, EV, and SUV categories simultaneously
- 💰 **Liquidity Tracking** – Real-time recaptured capital display for reinvestment decisions
- 📋 **Executive Case Study** – Comprehensive narrative on OEM inventory challenges and solutions
---

## Built With
## The problem

- **React** 18.2 – UI framework
- **TypeScript** – Type-safe development
- **Tailwind CSS** 3.3 – Utility-first styling
- **Vite** 5.0 – Lightning-fast build tool
- **Lucide React** – Premium icon library
A multi-billion-dollar national vehicle portfolio is, at any moment, simultaneously
*over-stocked in slow-turning segments* and *under-stocked in fast ones*. Judging every
segment against one inventory benchmark hides this — luxury and high-volume models have
fundamentally different velocity economics. The result is capital bleeding carrying cost in
one place while demand goes unserved in another.

## Quick Start
## The approach

```bash
# Install dependencies
npm install

# Start development server
npm run dev

# Build for production
npm run build
```
Measure each model's **Days Sales of Inventory (DSI)** against a **segment-specific target**,
then apply a **net-benefit decision rule**: clear above-target inventory *only when the annual
carrying cost avoided exceeds the one-time clearance loss*, and redeploy the recaptured capital
to relieve stockout-risk segments first.

The app will open at `http://localhost:5173` with:
- **Case Study** tab – Educational narrative on inventory optimization frameworks
- **Live Dashboard** tab – Interactive inventory health simulator with Hyundai/Genesis product lineup
## Key results (illustrative baseline)

## Deployment
| Metric | Value |
|---|---|
| Capital deployed | **$2.87B** |
| Capital above segment target | **$412M** (14%) |
| Annualized carrying cost bled | **$74M/yr** |
| Capital recaptured | **$387M** |
| First-year net benefit | **$49M** |
| Demand-constrained gap funded | **$216M**, fully covered |

### GitHub Pages (Automatic)
The recaptured capital more than covers the volume shortfall — the EV-glut and slow-luxury pools
fund the lean volume line, with ~$171M left for strategic priorities. Full derivation in
[METHODOLOGY.md](./METHODOLOGY.md).

This project is configured for automatic deployment to GitHub Pages. Every push to `main` branch triggers the deployment workflow.
## How it's structured

**To set up:**
The app is organized as four role-targeted views:

1. Ensure the repository is public or has GitHub Pages enabled
2. Go to **Settings** → **Pages** → set source to "Deploy from a branch" (gh-pages)
3. The site will be live at: `https://privatejoel.github.io/OEM-Inventory-Health/`
1. **Strategy Brief** — answer-first recommendation with quantified impact, then a
Situation / Complication / Resolution case. *(Consulting framing.)*
2. **Decision Dashboard** — segment-targeted DSI table, corrected and accurately-labeled KPIs,
a ranked net-benefit recommendation engine, and **live scenario sliders** (carrying rate,
clearance discount, demand shift) so every figure can be stress-tested. *(Planning / analytics.)*
3. **Execution Plan** — phased rollout, RACI decision rights, governance KPIs, and a
risk/mitigation register. *(Program management.)*
4. **Retail & DMS** — drills the OEM thesis down to the dealer P&L: DMS-sourced aging buckets,
floorplan cost, inventory turn, and dealer-level retail levers (incentive / dealer trade /
wholesale). Shows the OEM → dealer → DMS data flow. *(Retail execution.)*

### Manual Deployment
## Why the metrics are defensible

```bash
# Deploy to GitHub Pages
npm run deploy
```
This was deliberately built to survive a probing interview:

This runs the build and deploys the `dist` folder to the `gh-pages` branch.
- **Scale matches the narrative** — national-aggregate units and OEM wholesale costs put the
portfolio in the billions, not the low millions.
- **Metrics are labeled for what they are** — "Annualized Carrying Cost," "Capital Above Target,"
and a volume-weighted "Portfolio DSI," not a count ratio mislabeled as a financial return.
- **The headline tradeoff is actually computed** — carrying cost avoided vs. clearance loss, per
pool, with an explicit act/hold rule — not asserted in prose.
- **Targets are segment-specific**, consistent with the core thesis.
- **Assumptions are owned and sourced**, with sensitivity and limitations documented openly.

## Use Case
## Built with

**Scenario:** A global OEM (Hyundai Motor Group) manages a multi-billion-dollar vehicle pipeline across luxury (Genesis G80), volume (Venue, Elantra), and EV segments (IONIQ 5). High-DSI luxury models accumulate holding costs while volume segments suffer from stockouts. This dashboard provides the decision-support layer to:
React 18 · TypeScript (strict) · Tailwind CSS 3 · Vite 5 · lucide-react

1. **Detect** – Identify which regional channels have stagnant capital
2. **Model** – Simulate inventory redirection and capital recapture scenarios
3. **Execute** – Approve strategic liquidation with transparent ROI calculations
## Run locally

## Data Model
```bash
npm install
npm run dev # http://localhost:5173
npm run build # production build to /dist
npm run deploy # publish /dist to GitHub Pages
```

The dashboard tracks 6 vehicle models with realistic metrics:
## Limitations

| Model | Segment | Stock | Monthly Sales | Unit Cost | Category |
|-------|---------|-------|---|---|---|
| Genesis G80 | Luxury Sedan | 14 | 3.2 | $56,000 | Luxury |
| Hyundai Venue | Compact SUV | 58 | 62 | $19,800 | Volume |
| Hyundai IONIQ 5 | EV SUV | 32 | 38 | $45,000 | EV |
| Hyundai Santa Fe | Mid-size SUV | 24 | 28 | $36,000 | SUV |
| Hyundai Elantra | Sedan | 42 | 55 | $21,500 | Volume |
| Hyundai Palisade | Full-size SUV | 18 | 5.5 | $48,000 | Luxury |
Portfolio-level (no per-region matrix), steady-state demand, single-period net benefit, and
contribution margin not yet modeled. Each is called out with its next step in
[METHODOLOGY.md](./METHODOLOGY.md) §9.

## Disclaimer

This project is **for educational purposes only**. It is not affiliated with, endorsed by, or representative of Hyundai Motor Group or its subsidiaries. All data, scenarios, and optimization models are simulated to demonstrate product planning and analytical frameworks.
For portfolio and educational purposes only. Not affiliated with, endorsed by, or representative
of Hyundai Motor Group or its subsidiaries. All data and scenarios are simulated to demonstrate
the analytical framework.

## Author

Joel Johnson – OEM Product Strategy Portfolio
**Joel Johnson** — Automotive Strategy & Planning Portfolio
Loading
Loading