PHPackages                             nandan108/slot-flow - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. nandan108/slot-flow

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

nandan108/slot-flow
===================

SlotFlow is a domain-neutral, deterministic engine for modeling and executing quantity flows across a multidimensional state space.

v0.2.0(2mo ago)03GPL-2.0-or-laterPHPPHP ^8.1CI passing

Since Mar 25Pushed 2mo agoCompare

[ Source](https://github.com/Nandan108/slot-flow)[ Packagist](https://packagist.org/packages/nandan108/slot-flow)[ RSS](/packages/nandan108-slot-flow/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (2)Dependencies (12)Versions (4)Used By (0)

SlotFlow
========

[](#slotflow)

[![CI](https://github.com/nandan108/slot-flow/actions/workflows/ci.yml/badge.svg)](https://github.com/nandan108/slot-flow/actions/workflows/ci.yml/badge.svg)[![Coverage](https://camo.githubusercontent.com/32a3558347d94e3b0a0b64f6066c3a78be62cd22cb93b5281aad0e257700d173/68747470733a2f2f636f6465636f762e696f2f67682f6e616e64616e3130382f736c6f742d666c6f772f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://camo.githubusercontent.com/32a3558347d94e3b0a0b64f6066c3a78be62cd22cb93b5281aad0e257700d173/68747470733a2f2f636f6465636f762e696f2f67682f6e616e64616e3130382f736c6f742d666c6f772f6272616e63682f6d61696e2f67726170682f62616467652e737667)[![Style](https://camo.githubusercontent.com/77a781eb39a9e5a05b2ca0fb24ed710d9ba4e063d4077b5a622535447c5d4790/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374796c652d7068702d2d63732d2d66697865722d627269676874677265656e)](https://camo.githubusercontent.com/77a781eb39a9e5a05b2ca0fb24ed710d9ba4e063d4077b5a622535447c5d4790/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374796c652d7068702d2d63732d2d66697865722d627269676874677265656e)[![Packagist](https://camo.githubusercontent.com/9a6f25fd10a54ee1a458df96e5f95e59f914bcdb66b143155defcce1e8dac7a6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e616e64616e3130382f736c6f742d666c6f77)](https://camo.githubusercontent.com/9a6f25fd10a54ee1a458df96e5f95e59f914bcdb66b143155defcce1e8dac7a6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e616e64616e3130382f736c6f742d666c6f77)

SlotFlow is a deterministic PHP engine for inventory and commerce operations that model quantity movement across an explicit multidimensional state space.

Mental Model
------------

[](#mental-model)

Think of SlotFlow as a constrained routing engine:

- each **slot** is a node in a graph
- each **edge** is an allowed movement
- a **flow** is an ordered movement definition

When you request a quantity movement, SlotFlow:

1. finds valid edges from the current state
2. orders them according to your policies
3. moves as much as possible
4. carries the remainder to the next options

> SlotFlow makes quantity movements explicit, deterministic, and auditable.

SlotFlow is intentionally not a full ERP, OMS, or WMS. It is the lower-level engine those systems can build on for stock movement, allocation, backorders, and delivery promises.

Core Concepts
-------------

[](#core-concepts)

- A `Slot` is one concrete state such as `wh1.FP.fs`.
    - The special `nil` slot represents outside-of-space flow: both source, sink, and effectively `/dev/null`.
- A `SlotSpace` is the finite universe of valid slots generated from named dimensions.
- An `Edge` is an allowed movement between two slots.
- A `Flow` is an ordered movement definition that defines how movement is attempted.
- A `QuantityState` stores the current quantity distribution for one subject across the slot space.
- `MovementEngine` executes a requested quantity against current state and returns movement events plus any remainder.

At its core, SlotFlow acts as a declarative inventory-movement engine over a constrained state space.

**Notes**

- Flows can be instantiated independently, but are typically registered on a `SlotSpace` and referenced by name during execution.
- Flows can be reversed with `reverseIf()` and parameterized, allowing a single definition to adapt to different execution contexts.
- `Cascade` and `Inventory` remain available as deprecated compatibility aliases for `Flow` and `QuantityState`.

When SlotFlow shines
--------------------

[](#when-slotflow-shines)

SlotFlow is a good fit when:

- quantities exist in multiple states or locations
- movement rules are non-trivial or evolving
- allocation must be deterministic and explainable
- you need to model backorders or delivery promises
- multi-line orders may release in full, partial, threshold-based, or priority-based shipments
- you need auditability (ledger-style tracking)

It is likely overkill for simple stock counters or single-location systems.

Install
-------

[](#install)

SlotFlow currently requires PHP 8.1 or newer.

```
composer require nandan108/slot-flow

## Licensing

SlotFlow is dual-licensed:

- `GPL-2.0-or-later` for open-source use under GPL-compatible terms
- a separate commercial license for proprietary or otherwise non-GPL-compatible use

See [LICENSE](LICENSE), [LICENSE-GPL-2.0-or-later](LICENSE-GPL-2.0-or-later), and [LICENSE-SlotFlow-Commercial](LICENSE-SlotFlow-Commercial).
```

Minimal Example
---------------

[](#minimal-example)

```
use Nandan108\SlotFlow\Flow;
use Nandan108\SlotFlow\MovementEngine;
use Nandan108\SlotFlow\Policies\DimensionPriority;
use Nandan108\SlotFlow\QuantityState;
use Nandan108\SlotFlow\SlotSpace;

$space = SlotSpace::define([
    'loc' => ['sup', 'wh1'],
    'stt' => ['fs', 'res', 'sd'],
])
->flow('reserve', static fn (Flow $flow) => $flow
    ->move(['stt' => 'fs'], ['stt' => 'res'])
    ->orderBy(new DimensionPriority(['loc' => ['wh*', 'sup']]))
);

$inventory = new QuantityState($space, [
    ['wh1.fs', 5],
    ['sup.fs', 10],
]);

$result = (new MovementEngine())->execute(
    inventory: $inventory,
    space: $space,
    cascade: 'reserve',
    quantity: 6,
    subject: 'SKU-123',
);
```

`MovementEngine::execute()` accepts either a `Flow` object or the name of a flow registered on the provided `SlotSpace`. Named execution is often the cleaner option once your flows are part of the modeled space.

For backward compatibility, the named argument on `MovementEngine::execute()` is still called `cascade`.

### How the flow behaves

[](#how-the-flow-behaves)

[![SlotFlow overview](docs/diagrams/slotflow-overview.svg)](docs/diagrams/slotflow-overview.svg)

In this example:

- the engine first consumes `wh1.fs → wh1.res`
- then falls back to `sup.fs → sup.res`

So 5 units move from `wh1.fs` to `wh1.res`, then the remaining 1 unit moves from `sup.fs` to `sup.res`.

Slightly more advanced routing
------------------------------

[](#slightly-more-advanced-routing)

Flows can express real-world fallback strategies, including backorders.

```
$space = SlotSpace::define([
    'loc' => ['sup','wh1', 'wh2'], // sup: supplier, wh*: our warehouses
    'own' => ['S', 'P'],           // S: supplier-owned / P: purchased
    'stt' => ['fs', 'res', 'sd'],  // fs: for-sale, res: reserved, sd: sold
])
->flow('backorder', static fn (Flow $flow) => $flow
    // prioritize stock we already own
    ->move(['stt' => 'fs', 'own' => 'P'], ['stt' => 'res'])

    // prefer warehouse over supplier
    ->orderBy(new DimensionPriority(['loc' => ['wh*', 'sup'],]))

    // fallback: create supplier-owned reservation (backorder)
    // this represents stock that will be ordered from the supplier
    // Note: could also be written ->create('sup.S.res') or ->create(['sup','S','res'])
    ->create(['loc' => 'sup', 'own' => 'S', 'stt' => 'res'])
    // disallow backorders beyond 100
    ->constraint(static fn (MovementEdge $edge, FlowContext $ctx): int|float =>
        max(0, 100 - $ctx->inventory->getSum('sup.S.res|sd')))
);
```

This flow encodes a common allocation policy:

1. use purchased stock first
2. prefer stock already in your warehouses
3. if insufficient, create a supplier reservation (backorder)
4. but never let open supplier backorders (`sup.S.res|sd`) exceed 100 units

This makes backordering an explicit, deterministic part of the flow.

The same policy also supports alternatives such as `'wh1|wh2'`, because priority entries are resolved through the configured slot codec before ranking edges. All values matched by the same entry share the same priority tier.

Registered flow names pair especially well with parameterized templates: you define the flow once on the `SlotSpace`, then execute it by name with different `params` depending on the request.

Delivery Promises And Order Release
-----------------------------------

[](#delivery-promises-and-order-release)

SlotFlow can also plan timed delivery promises.

- `ScheduleRequest` and `EarliestArrivalSolver` build one timed movement schedule for one subject quantity
- `Demand`, `DemandLine`, `DemandScheduleRequest`, and `DemandScheduler` compose many subject schedules into one order-level promise
- release policies such as `PartialShipmentPolicy`, `FullShipmentPolicy`, `ThresholdReleasePolicy`, and `PriorityReleasePolicy` decide how ready lines turn into shipments
- timed slot spaces can also apply dispatch calendars, for example cutoff-time or no-weekend dispatch rules

Execution Output
----------------

[](#execution-output)

SlotFlow computes movement. It does not persist it.

It produces explicit, inspectable results that you can store, audit, or replay.

The main result shapes are:

- `MovementResult::deltas()` for net per-slot current-state deltas
- `MovementResult::ledgerEntries($context)` for append-only movement records
- `MovementSchedule::$steps`, `MovementSchedule::$milestones`, and `MovementSchedule::deltas()` for time-based planning output
- `DemandSchedule::$lines` and `DemandSchedule::$shipments` for multi-line order promise output
- `QuantityStateBatch::deltas()` and `QuantityStateBatch::ledgerEntries($context)` for the same outputs across many subjects

Terminology
-----------

[](#terminology)

Current core terminology:

- `Flow`: generic ordered movement definition
- `QuantityState`: quantity distribution for one subject
- `QuantityStateBatch`: grouped quantity states for batch execution
- `QuantityStateDelta`: one net per-slot quantity delta

Deprecated compatibility aliases:

- `Cascade` -&gt; `Flow`
- `Inventory` -&gt; `QuantityState`
- `InventoryBatch` -&gt; `QuantityStateBatch`
- `InventoryMutation` -&gt; `QuantityStateDelta`

Guide
-----

[](#guide)

- [Guide](docs/guide.md): core SlotFlow concepts, execution, and batch processing
- [Time And Planning Guide](docs/time-planning-guide.md): timeless planning, timed slot spaces, earliest-arrival scheduling, and demand scheduling
- [Commerce Example](docs/commerce-example.md): a fuller e-commerce flow model
- [v0.2.0 notes](docs/release-notes-v0.2.0.md): summary of the timed layer, planners, and demand scheduling additions
- [Changelog](CHANGELOG.md): release-by-release project history
- Generated API docs:

Origin
------

[](#origin)

SlotFlow originates from a real-world inventory system I developed in 2017 for a production e-commerce platform.

That system handled:

- multi-location stock allocation
- inbound stock and delivery promise computation
- reservation and booking flows
- partial shipment tracking
- movement logging (ledger)

Over time, the limitations of a tightly coupled implementation became clear: movement rules, state representation, and execution logic were all intertwined.

SlotFlow is an extraction of its core ideas as a composable engine for inventory movement and promise calculation.

For historical reference, the original implementation is preserved here: 👉 [`docs/history/original-MPB-InventoryEngine.php`](docs/history/original-MPB-InventoryEngine.php)

Quality
-------

[](#quality)

- 99% automated test coverage
- Psalm level 1 clean
- CI runs Psalm, coverage, and phpDocumentor on PHP 8.1
- CI runs PHPUnit on PHP 8.1, 8.2, 8.3, 8.4, and 8.5
- Generated API docs published from source via phpDocumentor

Release Status
--------------

[](#release-status)

`v0.2.0` is the first release that adds a full timed planning layer:

- `TimeAxis`, `TimedSlotSpace`, and timed edges
- `MovementPlanner` for timeless path planning
- `ScheduleRequest` and `EarliestArrivalSolver` for timed planning
- `DemandScheduler` and shipment release policies for order-level promise calculation

The core execution engine remains the most mature part of the library. The timed and demand-scheduling APIs are documented and tested, but they should still be expected to evolve as more real-world use cases are applied to them.

License
-------

[](#license)

SlotFlow is dual-licensed under `GPL-2.0-or-later` or the SlotFlow commercial license. See [LICENSE](LICENSE), [LICENSE-GPL-2.0-or-later](LICENSE-GPL-2.0-or-later), [LICENSE-SlotFlow-Commercial](LICENSE-SlotFlow-Commercial), and [NOTICE](NOTICE).

Organizations using SlotFlow in proprietary or otherwise non-GPL-compatible software must obtain a separate commercial license. Reduced-fee or no-fee commercial licenses may be available on request for qualified nonprofit, humanitarian, and public-interest organizations.

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance87

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity35

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~9 days

Total

3

Last Release

73d ago

PHP version history (2 changes)v0.1.0PHP ^8.3

v0.2.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/024c3beb5cbe22cd3e3f3db6938cf893c09d0b3b90076e2e1566530cd0693372?d=identicon)[Nandan108](/maintainers/Nandan108)

---

Top Contributors

[![Nandan108](https://avatars.githubusercontent.com/u/354944?v=4)](https://github.com/Nandan108 "Nandan108 (17 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/nandan108-slot-flow/health.svg)

```
[![Health](https://phpackages.com/badges/nandan108-slot-flow/health.svg)](https://phpackages.com/packages/nandan108-slot-flow)
```

###  Alternatives

[magepsycho/magento2-discountlimit

Magento 2 Discount Amount Limiter

1012.1k](/packages/magepsycho-magento2-discountlimit)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
