Inspiration
Unstaffed and micro-format grocery stores are booming, but they inherit an old problem with no one on the floor to catch it: stock that looks healthy on a count can still be about to spoil. A shelf with 15 cartons of milk reads as "fine" to any simple reorder rule — until you notice 12 of them expire tomorrow.
The result is the worst of both worlds: waste (product thrown out) and stockouts (empty shelves the next morning), at the same time, on the same item. We wanted an agent that sees what a human stock clerk would see — not just how much is on the shelf, but how much can realistically sell before it expires — and acts on it, while keeping a person in control of what actually gets bought.
What it does
FreshFlow AI watches the store's inventory and recent sales, decides what to reorder using expiry-adjusted logic, and hands those decisions to a human for one-click approval before placing orders with suppliers.
- Reads the shelf honestly. For each product it computes daily sales velocity, then runs a FIFO expiry simulation: by the day each batch expires, only
velocity × daysunits can realistically have sold — the rest is waste. That gives an expiry-adjusted (sellable) stock figure, not a raw count. - Decides with a clear rule. It reorders when sellable days-of-cover drops below the supplier lead time plus a safety buffer, and orders up to a target days-of-stock, rounded to the supplier's case pack.
- Explains itself. Every product gets a plain-language rationale ("15 on shelf but 12 expire in 1 day and only ~3 will sell in time — 9 spoil; ~2 days of sellable cover; ordering 18") and the full computation is printed for inspection.
- Keeps a human in the loop. Decisions are published as a clean JSON contract. UiPath pulls it, shows an approval card per order, and only on approval drives the supplier portal to place the order.
- Closes the loop. Orders placed through the portal flow back into the inventory view as goods received, so the shop's stock updates in real time.
The "aha": milk that a naive threshold marks as healthy (15 units ≈ 5 days of cover) is correctly flagged for reorder once expiry is accounted for (~2 days of sellable cover). Side by side, the agent catches what a count-based rule silently misses — without over-ordering items that merely have a little expiring stock but plenty of runway.
How we built it
We split the system into small, single-responsibility services so each piece is independently runnable and easy to reason about:
- Inventory data layer (Flask, port 5003) — stands in for the POS. Serves a clean inventory + 7-day trends page and exposes
GET /inventoryandGET /trends. Batch expiry dates are computed live relative to today, and received orders are folded back into stock. - Reasoning engine (Python) — the brain. Reads the store data, computes velocity, expiry-adjusted stock, days-of-cover, and reorder quantities, prints the trace, and writes the decision contract
decisions.json. - Decisions API (Flask, port 5002) — exposes
GET /decisionsfor the orchestration layer to pull. - Supplier portal (Flask, port 5001) — a web storefront with login, a product catalog, and order placement, built with stable, descriptive element IDs (
qty-milk-1l,btn-place-order) so a selector-based automation tool can drive it reliably. - UiPath (separate) — the human-in-the-loop orchestrator: pulls the decisions, shows approval cards, and on approval logs into the portal and places the approved orders.
Stack: Python + Flask, plain HTML/JS, minimal dependencies, one-command run. Everything runs locally.
Challenges we ran into
- Modeling expiry honestly. Our first instinct — "subtract anything expiring soon" — was wrong; at a high enough velocity those units do sell in time. We landed on a FIFO sell-through simulation that only counts what genuinely can't move before it expires.
- Rigging data that tells a true story. The demo needed a real "aha" without being cartoonish. We tuned velocities, batch sizes, and expiry windows so milk looks healthy by count yet fails on expiry-adjusted cover — and so the report isn't all-action (some items reorder, some don't, one has expiring stock but is correctly left alone).
- Designing for automation, not just humans. Browser automation breaks on dynamic or hashed IDs. We gave every interactive element a stable, descriptive
id/nameand verified them end-to-end. - Keeping the contract clean. UiPath needed a predictable schema where an approved decision (
product_id+order_qty) maps directly onto a portal submit — so the boundary between "agent reasoning" and "robot doing" stayed crisp. - Closing the loop. Initially the portal and the inventory view were disconnected, so placing an order didn't change stock. We wired received orders back into the inventory layer (as goods received, recomputed per request) so the demo updates live.
Accomplishments that we're proud of
- The expiry-aware decision actually works — and is demonstrably smarter than a naive threshold on the exact case that matters.
- Genuine human-in-the-loop AI: the agent recommends and explains; a person approves; only then does anything get bought.
- A clean, automatable boundary between reasoning (the agent), orchestration + approval (UiPath), and the supplier system (the portal) — each replaceable without touching the others.
- Transparent by design: every decision ships with a plain-language rationale and a full printed computation, so the logic is inspectable, not a black box.
- Runs in one command and closes the full loop, from "here's the shelf" to "order received."
What we learned
- Counts lie; cover tells the truth. The single most valuable signal in perishable retail isn't how much you have — it's how much can sell before it expires.
- A little reasoning beats a big threshold. A simple, explainable rule on the right number outperforms a fancier rule on the wrong one.
- Trust comes from transparency and approval. Surfacing the "why" and keeping a human gate made the automation something you'd actually let near a purchasing budget.
- Build the seam first. Designing the JSON decision contract and stable selectors up front let the AI half and the UiPath half develop in parallel and snap together cleanly.
What's next for FreshFlow AI
- Real POS + supplier integration to replace the stand-in data and the demo portal.
- Smarter demand forecasting — day-of-week, seasonality, and promotions instead of a flat average velocity.
- Cost-aware ordering. Unit cost (in SEK) is already in the data; next is totaling order cost, respecting budgets, and optimizing across multiple suppliers.
- Learning from waste. Feed actual spoilage back in to auto-tune buffers and even shelf pricing (markdowns on near-expiry stock before it's lost).
- Dynamic safety buffers per product and per store, learned from stockout and waste history.
- Proactive alerts — flag at-risk batches for markdown or donation before they expire.
- Scale-out to multi-store fleets with a single approval queue.
Built With
- api
- bmpn
- claude
- maestro
- uipath
Log in or sign up for Devpost to join the conversation.