Functionality Reference
This section provides an exhaustive catalogue of every feature and capability in Mirabelle, organised by functional domain. Each entry corresponds to a real endpoint, pipeline step, UI interaction, or Rust engine behaviour present in the codebase.
Table of Contents
Demand & ETL
| Capability |
Details |
| Historical demand loading |
Reads demand_actuals from PostgreSQL; weekly bucketed, keyed by item_id × site_id × date |
| Pipeline-scoped corrections |
Outlier-adjusted values stored in demand_corrected per pipeline_id; two pipelines can have different corrections for the same demand point |
| Demand overrides (scenario) |
Scenario-level demand multipliers and absolute overrides stored in forecast_scenarios.demand_overrides |
| Sales returns integration |
sales_return table tracks expected/actual returns; returns contribute to netting and supply demand |
| Firm order netting |
Firm orders from ERP deducted from statistical forecast before supply planning |
| Data quality routing-cycle check |
Detects self-loops, bidirectional routes, and multi-node cycles in the route graph before supply runs |
| Demand breakdown by source |
API returns statistical, causal, maintenance, and firm demand separately per week |
| Consume profile |
Supply runner builds a per-SKU weekly consumption array from netted forecast + sales returns |
Outlier Detection
Outlier detection runs automatically as the first step inside every forecast run (run_pipeline.py --only forecast). It is not a standalone pipeline step in the UI.
| Capability |
Details |
| IQR method |
Fence = [Q1 − k·IQR, Q3 + k·IQR]; configurable multiplier k (default 1.5) |
| Z-score method |
Rolling mean ± n·σ; configurable threshold (default 3.0) |
| STL decomposition method |
Anomalies identified in the residual component after seasonal-trend decomposition |
| Correction strategies |
Three options per detected outlier: clip (replace with bound), remove (set to null), interpolate (linear fill) |
| Minimum observations guard |
Outlier detection skipped when series has fewer than min_observations points |
| Pipeline isolation |
Each pipeline run overwrites its own partition in demand_corrected; re-running does not affect other pipelines |
| Outlier analysis panel (UI) |
Draggable table in Time Series Viewer: date, original value, corrected value, Δ cut (abs + %), lower/upper bounds, z-score |
| Outlier markers on chart |
Red markers for original outlier values with z-score in hover tooltip; amber shaded bounds polygon |
Characterisation
| Capability |
Details |
| Seasonality detection |
STL decomposition + autocorrelation; outputs has_seasonality, seasonal_strength, seasonal_periods |
| Trend analysis |
Linear regression on STL trend component; outputs has_trend, trend_direction, trend_strength |
| Intermittency (ADI) |
Average Demand Interval; series with ADI > threshold classified as intermittent |
| Intermittency (CoV) |
Coefficient of Variation; high CoV + high ADI → lumpy demand |
| Zero ratio |
Fraction of weeks with zero demand |
| Stationarity (ADF) |
Augmented Dickey-Fuller test; outputs is_stationary, adf_pvalue |
| Complexity scoring |
Composite score across trend, seasonality, intermittency, and data volume; levels: low / medium / high |
| ML / DL eligibility |
Minimum observation thresholds checked before routing a series to neural or foundation models |
| Method recommendation |
_recommend_methods() maps characterisation profile to a ranked list of allowed forecasting methods |
| Per-pipeline results |
All characterisation outputs tagged with pipeline_id + scenario_id; stored in series_characteristics |
Forecasting
Statistical Models (CPU, fast)
| Method |
Library |
Notes |
| AutoARIMA |
StatsForecast (Nixtla) |
Automatic order selection (p,d,q)(P,D,Q) |
| AutoETS |
StatsForecast |
Automatic error/trend/seasonality selection |
| AutoTheta |
StatsForecast |
Theta family with automatic variant selection |
| MSTL |
StatsForecast |
Multiple Seasonal Trend decomposition; ideal for dual-seasonality |
| CrostonOptimised |
StatsForecast |
Croston variant for intermittent demand |
| SeasonalNaive |
StatsForecast |
Baseline: repeat last seasonal cycle |
| HistoricAverage |
StatsForecast |
Baseline: rolling mean |
Neural Models (GPU-optional)
| Method |
Library |
Notes |
| NHITS |
NeuralForecast (Nixtla) |
Hierarchical interpolation; strong on long horizons |
| NBEATS |
NeuralForecast |
Interpretable neural basis expansion |
| PatchTST |
NeuralForecast |
Transformer with patch-based attention |
| TFT |
NeuralForecast |
Temporal Fusion Transformer; handles covariates |
| DeepAR |
NeuralForecast |
Autoregressive RNN; probabilistic |
Foundation Model
| Method |
Details |
| TimesFM (Google) |
Zero-shot inference; no per-series training; runs on any series length |
Forecast Engine Features
| Capability |
Details |
| 24-week horizon |
All methods produce a 24-step weekly point forecast stored as JSONB |
| Quantile forecasts |
Multiple confidence levels (50%, 80%, 90%, 95%) stored per method |
| Dask parallelisation |
Forecast runs distributed across workers; configurable worker count and batch size |
| Hyperparameter overrides |
Per-series method-level overrides stored in series_hyperparameters_overrides |
| Forecast origin slider (UI) |
Replay any historical backtest origin; chart updates to show what the model predicted at that point |
| Forecast evolution viewer |
Overlays multiple origin forecasts to visualise how a model's view changed over time |
| Forecast convergence analysis |
Shows how quickly a method converges to actuals as the horizon shrinks |
| Forecast adjustments |
Manual overrides applied on top of model output; stored in forecast_adjustments per pipeline_id |
| NPI copy-forecast |
Copy a donor series' forecast to a new item/site with a configurable scale factor |
| Per-method colour coding |
METHOD_COLORS constant ensures consistent colours across all charts |
| Best method highlighted |
Best method always shown in green (#059669) in all views |
Backtesting & Evaluation
| Capability |
Details |
| Rolling-window backtesting |
Models retrained on progressively larger windows; performance measured on held-out horizon |
| Metrics computed |
MAE, RMSE, MAPE, sMAPE, MASE, BIAS, CRPS, Winkler score, interval coverage at 50/80/90/95% |
| Per-origin storage |
forecasts_by_origin stores point forecast paired with actual for every backtest origin date |
| Backtest fingerprinting |
backtest_fingerprints hashes data + parameters to skip unchanged series on re-run |
| Metric comparison table (UI) |
Sortable table of all methods × all metrics; best value per column highlighted |
| Racing bar chart (UI) |
Animated ranking of methods by chosen metric |
| Segment-level aggregation |
Metrics aggregated by segment for portfolio-level reporting |
Best Method Selection
| Capability |
Details |
| Composite weighted scoring |
Configurable weights per metric (MAPE, RMSE, BIAS, CRPS…); lowest composite score wins |
| Per-series lock |
Planners can lock a method (locked_method, locked_by, locked_at) to prevent future overwrites |
| Lock / unlock from UI |
One-click lock/unlock in Time Series Viewer; shows who locked and when |
| Runner-up tracking |
runner_up_method and full all_rankings JSON stored for transparency |
| Method override |
Best method can be manually overridden without locking |
| Fallback behaviour |
When no backtest data exists, uses characterisation recommendation |
Causal Forecasting (MRO / Asset-Based)
Causal forecasting models demand as a function of asset deployment, usage rates, and failure rates — used primarily for MRO and aerospace parts.
| Capability |
Details |
| Asset type master |
causal_asset_type: code, name, AOG cost per day |
| Individual asset registry |
causal_asset: serial number, type, status |
| Asset deployment |
causal_asset_deployment: which asset is at which site/customer, from which date, in what quantity |
| Asset coverage |
causal_asset_coverage: coverage percentage per asset × site × customer |
| Asset usage rates |
causal_asset_usage: usage factor per asset × customer × usage type |
| Bill of Materials |
causal_bom: item lines per asset type — qty per asset, LRU flag, repair yield, sub-asset name, position, effectivity dates |
| Failure rate waterfall |
4-level specificity (global → position → site+position → asset+position); most specific wins |
| Fleet plan |
causal_fleet_plan: asset quantity by customer and period |
| Causal scenarios |
Override fleet quantities, usage rates, coverage percentages per scenario |
| Causal forecast output |
Derived demand per item × site; stored in forecast_results with causal scenario tag |
| BOM explosion |
Full recursive BOM roll-up for demand computation |
| Deployment comparison (UI) |
Side-by-side comparison of deployment quantities across scenarios |
| Usage comparison (UI) |
Chart of usage rates across customers per asset |
| Coverage heatmap (UI) |
Asset × site coverage matrix |
Maintenance Scenarios
| Capability |
Details |
| Maintenance event types |
maintenance_event: name, description |
| Event BOM |
maintenance_bom: items required per event with quantity and likelihood of removal |
| Scenario-event assignment |
Which events are included in each maintenance scenario |
| Event scheduling |
maintenance_scenario_event_date: scheduled date, site, quantity per occurrence |
| Weekly event calendar (UI) |
Grid view of upcoming events by week |
| Demand by item (UI) |
Shows which items are consumed by which events in a given week |
| Event-level BOM assignment (UI) |
Drag-and-drop item lines onto events |
| Maintenance demand integration |
Maintenance-driven demand contributed to netting alongside statistical and causal |
Demand Netting
| Capability |
Details |
| Multi-source netting |
Statistical + causal + maintenance + firm orders netted into a single weekly demand signal |
| Blend percentages |
Each pipeline defines series_pct, causal_pct, maintenance_pct (must sum to 100%) |
| Firm order deduction |
Open firm orders deducted week by week before supply planning |
| Sales returns |
Expected returns added back to net supply requirement |
| Netting table |
forecast_netting: stat_forecast_qty, total_netted_qty, firm_demand_qty per (item_id, site_id) × week |
| Netting overlay (UI) |
Chart overlay showing each demand source as a stacked area; toggled from Time Series Viewer |
| Netting refresh |
Dedicated endpoint to recompute netting for a pipeline without re-running full forecast |
MEIO / Inventory Optimisation
| Capability |
Details |
| Safety stock optimisation |
Per-SKU safety stock computed from fitted demand distributions and service-level targets |
| Reorder point (ROP) |
ROP = expected demand during lead time + safety stock |
| EOQ per item |
Economic Order Quantity minimising total ordering + holding cost |
| Service-level targeting |
Configure target fill rate or stockout probability per segment |
| Budget-constrained mode |
Optimise safety stock allocation within a total inventory budget |
| Multi-echelon support |
item_chain links define echelon relationships; MEIO respects upstream/downstream dependencies |
| MEIO scenarios |
Multiple scenarios with different service-level targets or budget caps |
| Segment-level parameter overrides |
Each segment within a scenario can have distinct MEIO parameters |
| Repair loops |
meio_repair_flows: return rate, repair yield, repair TAT mean, WIP quantity |
| Manual overrides (IO) |
io_overrides: per-SKU override of service level, EOQ, or fill rate |
| MEIO results |
committed_buffer, fill_rate, marginal_value, wait_time, leg_lead_time per item × site |
| Group-level results |
Achieved fill rate and budget utilisation per group |
| Parallel Rust engine |
meio_optimizer Rust crate (PyO3); Rayon parallelism; statrs distributions; Monte-Carlo uncertainty |
| MEIO run (async) |
Triggered via Process Runner; status polled via job queue; results written to meio_results |
| Diagnostic report (UI) |
Projected vs. optimised stock level comparison per segment |
EOQ & K-Curve
| Capability |
Details |
| EOQ formula |
Classical Wilson formula: EOQ = √(2DS/H) where D = demand, S = order cost, H = holding cost |
| K-curve (exchange curve) |
Plots total inventory investment vs. number of orders per year across all SKUs simultaneously |
| Efficient frontier |
K-curve shows the Pareto-optimal boundary; planners pick operating point on the curve |
| Per-item EOQ |
Individual EOQ computed and stored per item_id × site_id |
| EOQ write-back |
Computed EOQ values written back to item.eoq for use in supply planning |
| Item cost tracking |
item.price, item.cost, item.unit_cost; item_site overrides per location |
| Holding rate override |
item_site.holding_rate overrides default carrying cost rate |
| Order cost override |
item_site.order_cost overrides default ordering cost |
| K-curve visualisation (UI) |
Interactive Plotly chart; click a point to see which SKUs define the frontier |
| Pipeline-scoped EOQ runs |
EOQ results tagged by pipeline; comparing pipelines shows sensitivity to cost assumptions |
Supply Planning
Supply planning is powered by the supply_engine Rust crate — an MRP-style scheduler that processes thousands of SKUs across 52-week horizons in parallel using Rayon.
Order Types
| Type |
Meaning |
| BUY |
Purchase from external supplier |
| BUILD |
Manufacture / assemble in-house |
| TRANSFER |
Move stock between locations |
| REPAIR |
Send unserviceable stock for repair |
| RETURN |
Return from customer or field |
Core Planning Capabilities
| Capability |
Details |
| Supply run execution |
Runs as a subprocess (run_pipeline.py --only supply) with a DescendantTracker watchdog that reaps surviving workers after completion; results written to ClickHouse PIPE_* tables |
| Order generation |
Orders created for every demand gap exceeding safety stock within the 52-week horizon |
| Lead time application |
Route lead times applied to compute release_week from arrival_week |
| Minimum quantity |
route.min_qty enforced per order type (BUY, TRANSFER, REPAIR etc. each use their own route's min/mult qty, not the primary route's values) |
| Multiple quantity (lot sizing) |
route.mult_qty enforced; quantity rounded up to nearest multiple |
| Safety stock respect |
No order generated if projected inventory stays above safety stock |
| Inventory projection |
PIPE_supply_inventory_projection: weekly projected_inventory, demand, supply_received, shortage, safety_stock in ClickHouse |
| Pegging |
Demand-supply link stored in PIPE_supply_pegging |
| Pegging tree (UI) |
Interactive tree view showing upstream supply chain for any demand week |
| Exception generation |
Rust engine generates typed exceptions: Shortage, UnmetDemand, CapacityExceeded, NoRoute; stored in PIPE_supply_exceptions |
| Humanised exception messages |
Exception messages post-processed to replace integer IDs with item/location names; stored as exception_type_label |
| Capacity constraints |
PIPE_supply_capacity: resource capacity per week; engine respects hard and soft constraints |
| Expiry tracking |
Expiry dates and expired quantities tracked per order |
| Bad stock |
Unserviceable inventory tracked separately; for repair-only warehouses, OH Bad is derived from REPAIR order throughput |
| Supply scenario management |
Multiple supply scenarios with parameter overrides per segment |
| Supply calendar |
Bitfield-encoded working calendars per supplier/route |
| Netted demand input |
Supply engine reads PIPE_forecast_netting WHERE is_past = 0; includes stat + return + maintenance demand streams |
Supply UI
| UI Feature |
Details |
| Orders tab |
Filterable table (type, site, week, cost range); order status badges; approve/cancel/unapprove actions |
| Inventory tab |
52-week projection chart per SKU; demand, supply, safety stock, shortage overlaid |
| Pegging tab |
Demand → supply chain tree |
| Exceptions tab |
Typed exception list with severity; inline exception panel auto-expands on Critical |
| Constraints tab |
Three sub-views: Why (constrained orders + exception cards), Timeline (per-resource capacity bars), Flow Map (Plotly network of routes with capacity status) |
| Capacity tab |
Resource utilisation heatmap; constrained-items list |
| Order approval workflow |
Approve/unapprove with approved quantity; approval stored in order_approvals |
| Supply dashboard KPIs |
Order count, total cost, shortage count, coverage weeks |
| Route network view |
Plotly scatter network: source → destination lanes coloured by capacity status (green/amber/red) |
| SKU flow analysis |
Per-SKU view of all routes, their resource constraints, and constrained orders |
ABC Classification
| Capability |
Details |
| Classification metrics |
Demand volume, demand value (volume × price), order hit frequency |
| Lookback period |
Configurable months of history used for the calculation |
| Granularity |
Item-only or item × site |
| Classification method |
Cumulative percentage cutoffs or rank percentage cutoffs |
| Class labels |
Configurable (default A/B/C; custom labels supported) |
| Thresholds |
JSON array of class boundary values |
| Segment scoping |
Classification run within a specific segment |
| Pareto curve (UI) |
Interactive cumulative distribution chart; class boundaries shown as vertical lines |
| Results per series |
abc_results: class label, metric value, rank, cumulative percentage |
| Multiple configurations |
Several ABC configs can coexist (e.g., one by value, one by volume) |
| Active / inactive toggle |
Inactive configurations excluded from pipeline runs |
| Run all active |
Pipeline step runs all active ABC configurations in sequence |
| Dashboard integration |
ABC class shown as colour-coded badge in the series table |
Segmentation
Segments are the primary mechanism for applying different parameters to different groups of SKUs.
| Capability |
Details |
| Filter builder |
Recursive AND/OR filter tree; each node is a field + operator + value |
| Filter fields |
Item columns (name, code, type, JSONB attributes), site columns, series characteristics (complexity, trend, seasonality, intermittency, zero_ratio, mean, n_observations), ABC class |
| Filter operators |
contains, starts_with, ends_with, equals, not_equals, is_null, is_not_null, gt, gte, lt, lte |
| JSONB attribute filtering |
Arbitrary key-value filters on item.attributes and location.attributes |
| Natural language query |
NL input parsed to structured filters via alerts_rs Rust engine |
| Preview |
Before saving, shows member count and sample series |
| Segment membership |
segment_membership stores which (item_id, site_id) belongs to which segment with optional participation weight |
| Parameter assignment |
Each segment maps to a forecast parameter set, outlier parameter set, and characterisation parameter set |
| Safety stock budget |
Per-segment safety_stock_budget used by MEIO budget-constrained mode |
| Characterisation horizon |
Per-segment characterisation_horizon overrides the default lookback |
| Series parameter assignment |
series_parameter_assignment resolves the final parameter set per series via 3-level hierarchy (per-SKU → segment → default) |
| Segment deletion |
Cascade deletes membership and parameter assignments |
| Pipeline-segment link |
scenario_pipeline_segment controls which segments are active in each pipeline |
Scenarios & Pipelines
Scenario Types
| Type |
Table |
Controls |
| Series (forecast) |
forecast_scenarios |
Statistical forecast parameters, demand overrides |
| Causal |
causal_scenarios |
Fleet overrides, usage overrides, coverage overrides |
| Maintenance |
Maintenance scenario tables |
Event schedules and item coverage |
| MEIO |
meio_scenarios |
Service-level targets, budget caps |
| Supply |
supply_scenario |
Supply planning parameters per segment |
| Inventory / EOQ |
inventory_scenario |
EOQ and holding-cost parameters |
Pipeline Features
| Capability |
Details |
| Pipeline registry |
scenario_pipeline: named container linking one scenario of each type |
| Blend percentages |
series_pct, causal_pct, maintenance_pct define demand mix |
| Pipeline selector (UI) |
Left-toolbar dropdown; all UI screens respect the selected pipeline |
| Workflow isolation |
Workflow-triggered processes use the pipeline defined in the workflow, not the toolbar |
| Scenario cloning |
Copy an existing scenario as a starting point for what-if analysis |
| Parameter overrides |
Each scenario stores a param_overrides JSONB to override specific parameters |
| Scenario status tracking |
draft → running → complete / failed |
| Baseline forecast |
Pipeline exposes a consolidated baseline view across all scenario types |
| Pipeline × segment |
scenario_pipeline_segment restricts which segments are active per pipeline |
| Multi-pipeline support |
Any number of pipelines can coexist; results are always isolated by pipeline_id |
NPI (New Part Introduction)
| Capability |
Details |
| Donor selection |
Autocomplete search for a source item × site whose forecast will be used as a template |
| Target selection |
Autocomplete for the new item × site receiving the forecast |
| Scale factor |
Multiplier (0.0–2.0×) applied to the donor forecast before copy |
| Forecast preview |
Chart shows historical (donor), donor forecast, and scaled forecast before committing |
| Data sufficiency check |
Warns when donor series has too few observations for reliable forecasting |
| Apply |
Stores scaled forecast as a forecast_adjustments override for the target series |
| History log |
Table of all NPI copies: who, when, donor, target, scale factor |
| Audit trail |
NPI actions appear in audit_log |
Alerts & Exceptions
Alert Engine
| Capability |
Details |
| Ontology |
34 static alert rules covering forecast accuracy, service level, stock depth, lead time, distribution fit, demand characteristics, and supply order activity (repair/return orders) |
| Semantic NL query |
Natural-language query parsed by alerts_rs Rust engine via vector similarity against ontology synonyms |
| LLM evaluation |
Optional LLM-based alert triage for complex conditions |
| Alert severities |
Critical, High, Medium, Low |
| Alert lifecycle |
Generated → reviewed → approved / rejected |
| Batch run |
Evaluate all ontology rules across all series in one pass |
| Alert feedback |
alert_feedback: user action (approve/reject) + comment stored per alert |
| Synonym learning |
New NL terms can be added to alert_synonyms table |
Exception Types (Series-Level)
| Exception |
Trigger |
| Forecast accuracy |
MAPE, RMSE, or BIAS exceeds threshold |
| High bias |
Systematic over- or under-forecast |
| Service level |
Projected fill rate below target |
| Stock depth |
Weeks-of-stock below minimum |
| Long lead time |
Route lead time above P90 threshold |
| Low fill rate (MEIO) |
MEIO result below segment target |
| Distribution fit |
KS p-value below threshold (poor fit) |
| Data sparsity |
Too few non-zero observations |
Exception Types (Supply-Level)
| Exception |
Generated by |
| Shortage |
Projected inventory goes negative |
| Unmet demand |
No route or insufficient capacity to cover demand |
| Capacity exceeded |
Resource utilisation > 100% |
| No route |
No valid supply route exists for a SKU |
Exception UI
| Feature |
Details |
| Inline exception panel |
Embedded in each detail tab (Forecast, Netting, IO, Supply); auto-expands on Critical |
| Cross-series exception list |
Full 95%-width view; up to 50 per page with pagination |
| Exception row layout |
Forecast + IO side-by-side (2-col); Supply always full-width below to accommodate the orders table |
| Supply Cell orders table |
All orders shown with editable Qty and Date; per-row OK (approve) / ✕ (cancel) / Undo buttons |
| IO Cell placeholders |
SL field placeholder = MEIO target SL; EOQ placeholder = computed EOQ; FR placeholder = MEIO achieved fill rate |
| Exception navigation overlay |
Jump directly to a series from any exception entry |
| Exception snooze |
Suppress an exception rule per (item_id, site_id) until a specified date |
| Exception log |
interact_exception_log: pipeline-level exceptions with status workflow (open → reviewed → snoozed → actioned). Auto-populated by exceptions_runner.generate_exception_log() at the end of each Exceptions pipeline step |
User Management & Authentication
| Capability |
Details |
| Local auth |
Email + bcrypt-hashed password; JWT issued on login |
| Google OAuth |
OAuth2 PKCE flow; JWT issued after token exchange |
| Microsoft OAuth |
Same OAuth2 flow for Azure AD accounts |
| JWT revocation |
revoked_tokens table; middleware checks on every request |
| Role hierarchy |
superadmin → admin → user |
| Segment permissions |
allowed_segments: which segments a user can view |
| Edit permissions |
allowed_segments_edit: which segments a user can edit |
| Process run permission |
can_run_process flag per user |
| Override permission |
can_create_override flag per user |
| User CRUD (admin) |
Create, update, deactivate users within the tenant |
| Protected routes |
React routes gated by role; unauthenticated requests redirected to /login |
| Token storage |
JWT stored in localStorage as forecastai_token; Axios interceptor attaches on every request |
| Auto-redirect |
401 responses auto-redirect to /login via Axios response interceptor |
Audit & Observability
| Capability |
Details |
| Process log |
process_log: every pipeline step logged with start/end time, rows processed, status, error message, log tail |
| Live log streaming |
Server-Sent Events endpoint streams log lines to Process Runner UI during a run |
| Job queue |
Async jobs tracked with UUID; status polled from UI; cancellation supported |
| Audit log |
audit_log: entity-level change history (old value → new value, who changed, when) |
| Audit log UI |
Filterable table; full JSON diff viewer per entry |
| OpenTelemetry (OTel) |
files/api/otel_setup.py: traces and metrics exported to Jaeger / OTLP collector |
| Rust → Python log bridge |
pyo3-log forwards Rust log::debug! / log::info! into Python logging and on to OTel |
| Health check endpoint |
/health: returns DB connectivity status |
| Application reload |
/admin/reload: refreshes in-memory account cache without process restart |
| Dynamic log level |
Log verbosity adjustable at runtime |
Administration (Multi-Tenancy)
| Capability |
Details |
| Tenant provisioning |
SuperAdmin creates a new account in forecastai_master.master.accounts; assigns a dedicated PostgreSQL DB |
| Account cache |
_account_cache in-memory dict maps account_id UUID to DB connection params; built at startup |
| Request isolation |
JWTAuthMiddleware decodes JWT account_id and sets a ContextVar; every DB call resolves to the correct tenant DB |
| Schema isolation |
Each tenant has its own PostgreSQL database with a scenario schema |
| SuperAdmin cross-tenant login |
SuperAdmin JWT includes special claim; can impersonate any tenant |
| User-to-account assignment |
SuperAdmin assigns existing users to specific tenant accounts |
| Received-date population |
Admin tool populates received_date on supply historical actuals for accurate lead-time computation |
| Account status |
Active / inactive; inactive accounts cannot authenticate |
| Master DB |
forecastai_master holds master.accounts, master.superadmins, master.parameters (JWT secret, token expiry) |
Settings & Configuration
| Capability |
Details |
| All parameters in DB |
scenario.parameters JSONB; loaded at runtime via ParameterResolver (3-level: per-SKU → segment → default) |
| Forecast parameter sets |
Per-pipeline sets (method list, horizon, outlier sub-config); managed via ForecastParameterSets.jsx |
| Parameter reorder |
Drag-and-drop priority ordering for parameter sets |
| Segment-parameter link |
parameter_segment maps which segments use which parameter set |
| Outlier sub-config |
Embedded in forecast parameter set: method (iqr/zscore/stl), correction, thresholds |
| Characterisation config |
Trend/seasonality/intermittency thresholds, stationarity p-value cutoff, complexity weights |
| Backtesting weights |
Per-metric weights for composite best-method scoring |
| Parallel backend |
Dask; configurable worker count and batch size |
| Calendar management |
calendar + calendar_entry: working-day calendars with date ranges and labels; used by supply planning |
| Item master edits |
Create/update items, prices, costs, lead times, EOQ |
| Location master edits |
Create/update sites, coordinates, type |
| Route management |
Define supply routes (buy, make, transfer, repair) with lead time, min qty, mult qty, unit cost |
| Route resource assignment |
Attach capacity resources (labour, machine) to routes with qty_per_unit |
| On-hand inventory |
Create/update inventory snapshots per item × site × type |
| Dark mode |
Tailwind class-based dark mode toggle; persisted in ThemeContext |
| Locale settings |
Number and date formatting via LocaleContext |
Frontend Architecture Features
| Feature |
Details |
| Code splitting |
Every route lazy-loaded via React.lazy + Suspense; initial bundle minimised |
| Shared axios instance |
utils/api.js: auth interceptor, base URL, 401 redirect — all API calls use this instance |
useSupplyParams() hook |
Centralised hook for pipeline_id + scenario_id; mandatory for all /supply/* calls |
| Draggable panels |
DraggablePanel + usePanelLayout: all detail panels in Supply and Time Series Viewer are draggable and foldable |
| Resizable modals |
ResizableModal: drag-to-resize; defaults to 80% of screen width |
| Sortable tables |
SortableTable: column click to sort; column visibility toggle; drag-to-reorder columns |
| Item popover |
ItemPopover: hover a series to see item metadata without navigating away |
| BOM explorer |
BomExplorer + BomTreeGraph: interactive multi-level BOM tree with Plotly |
| Pegging tree |
PeggingTree: supply chain tree from any demand week |
| Overview map |
OverviewMap: geographic or hierarchical network map of assets and locations |
| Exception nav overlay |
ExceptionNavOverlay: floating panel listing exceptions; click to jump to series |
| Netted forecast overlay |
NettedForecastOverlay: demand source breakdown overlay in Time Series Viewer |
| Inline sparklines |
SVG sparklines in series table (not Plotly) for 10× render performance |
| Pipeline selector |
Left-toolbar dropdown; pipeline change re-fetches all context-dependent data |
| Dark / light themes |
All components styled for both modes via Tailwind dark: variants |
| Configuration panel |
DetailConfigPanel: foldable panel at bottom of each detail tab (Forecast, IO, Supply, Netting, EOQ) showing active scenario + parameter set for the current pipeline; clicking any item navigates to the screen where it can be edited |
| Process runner persistence |
Log lines buffered in memory and saved to localStorage (proc_jobs_cache_v1) every 1 s; logs survive navigation away from the Processes page and are restored on return |