Run your e-commerce store like a tiny army with one person in charge. You.
OrderFlow is a local-first desktop command center for online sellers who live inside Shopify, WhatsApp, courier street logistics and COD cash at the same time. It does one job very well: it walks every order from "someone clicked buy" to "money is safely in your wallet", and it keeps every rupee accountable along the way.
If you have ever sold online with cash on delivery, you already know the pain: an order gets confirmed over WhatsApp, then someone has to remember it, then the courier picks it up, then you have to check whether it was delivered, then you have to chase the cash, and somewhere in between your ad spend, courier fees, and subscription costs quietly eat away at what you actually earned. Spreadsheets break. Notes get lost.
OrderFlow keeps the whole battlefield on one screen. One machine. One SQLite file. No cloud, no subscription, no internet required just to see your numbers. It runs on Windows as a Tauri 2 desktop app, and it is fast enough that the UI feels instant even while it is quietly doing heavy lifting in Rust.
Store Dashboard here is the home base for a store: the balance, 30 day revenue and profit, and the live pipeline.
Overview Dashboard rolls all of your stores into one picture, with a card per store.
Orders Pipeline is where every order lives while it waits for its next step.
Orders Confirmation Queue is where you confirm or deny the day's incoming orders.
Orders Packaging asks the questions that matter: which courier, which tracking number, and how much COD the courier should collect.
Orders Transit watches the physical world: in transit, out for delivery, awaiting collection, returning.
Orders History keeps every settled, denied and returned order in one searchable place.
Wallet Transaction Ledger is the double-entry heart of the app. Every rupee in and out, with a timestamp.
Wallet COD Collection groups deliveries by courier so you can record exactly what came back from each one.
Wallet Subscription tracks recurring charges and deductions.
Ads Screen follows spend per campaign and per platform, and tells you which ad budget actually earned money.
Analytics Screen is the deep dive: filters, KPIs with deltas, funnel, returns, city heat and CSV export.
Store Shopify Connection ties an OrderFlow store to its Shopify store.
Add New Store onboards a brand new store in a couple of clicks.
Each store gets its own landing page with the numbers you actually care about:
- Wallet balance, 30 day revenue, order count, ROAS, and net profit (with the ads, subscriptions and loss breakdowns that explain it)
- Live pipeline strip: awaiting confirmation, pending collection, in transit value, due subscriptions
- Revenue vs spend chart, order funnel bars with dropoff, COD vs prepaid donut
- Quick actions into every other part of the store
Everything refreshes on a timer and reacts instantly when an order changes state.
One page for all your stores: combined balance, combined 30 day profit, and a card per store with its own sparkline, pending confirmations and today's orders. Click a card to dive into that store's dashboard.
- Pipeline view and table view of every order, with search, filters and sorting
- Quick actions on new orders: send to the confirmation queue, or delete (NEW state only)
- Edit an order while it is still NEW or CONFIRMING: customer, items, payment method, notes. Your edits stick until you manually re-sync from Shopify, and the order is marked as locally edited
- Create manual orders by hand for anything that never went through the online store
Orders that came in from Shopify land here and wait for a human decision:
- Per-order contact attempts (WhatsApp and calls) with configurable attempt thresholds per store, per order, or a global default
- Confirm or deny with a reason, both logged in the order timeline
- Queue stats show how many are still waiting, and how many have used up all their attempts
- The sidebar badge never lets you forget a waiting order
Everything confirmed slips into packaging. Per order you set:
- Tracking ID
- Courier (pick from your history or type a brand new one, the input is always there)
- COD amount for cash orders, deducted from your wallet at ship time
The physical world in four columns: In Transit, Out for Delivery, Awaiting Collection, Returning. Per order you can log delivery attempts (delivered, rejected, no response, with auto-retry rules), mark a return, or confirm collection. Tracking history can be fetched automatically (see the speed section below).
Every terminal state in one place: settled, denied, returned. Filter, search, sort, and export the whole store to CSV.
The heart of OrderFlow. A fully double-entry-style ledger per store:
- Balance plus a dated ledger of every single transaction (
order_income,refund_out,delivery_fee_loss,cod_paid_out,ad_spend,subscription_charge,recharge,withdraw,adjustment) - Recharge and withdraw with amount, counterparty and note
- COD Collection tab groups orders by courier; when you confirm a collection you can adjust the exact amount that came back (couriers rarely remit the full total), and the ledger records what really landed
- Subscriptions with automatic or manual deduction and due tracking
Track ad spend per campaign and platform, log daily reach figures, and see the performance signals that matter: CPC, CTR, CPM, CAC, ROAS and effective spend. Because the wallet knows your costs, the platform rollup (Meta, TikTok, Google) shows which platform actually earned its keep.
The deep dive, per store and per time range:
- KPI header with deltas versus the previous period
- Revenue vs spend series, platform spend pie
- Order funnel with stage dropoff
- Return analysis by reason with total losses
- City heat map with return rate, COD vs prepaid mix, monthly wallet waterfall, profit sparkline
- Export orders, ledger and ad spend CSV right from the page
A what-if engine: feed it your product margins, daily ad spend, cost per acquisition, delivery lag and collection lag, and it simulates day by day how your wallet behaves, including spend ramp events. The answer to "can I afford to double my ad spend until Friday?" lives here.
Backup and restore your entire database from a file, inspect app info, and manage everything at the app level.
Money is always stored as integer minor units (cents). No floats, no rounding drift, ever. The wallet balance is never a separate number that can disagree with the ledger: every mutation recomputes the balance from the sum of its own transactions inside one SQLite transaction. If the ledger says something, the balance says the same thing.
The rules reflect cash-on-delivery reality:
- COD orders: the COD amount is deducted from your wallet when you package the order and pay the courier. The money comes back when the collection gets confirmed, at whatever amount you recorded. If the parcel is returned anyway, the packaging deduction stays as a loss, because the courier already got paid.
- Prepaid orders: income is credited the moment you confirm the order, since the money is already with the platform.
- Returns: handled with a refund from the wallet (minus delivery fee), logged as
refund_out.
Order lifecycle states are a strict state machine with a full timeline of events per order. You can walk an order backwards: any event in the timeline can be rolled back, with its wallet adjustments reversed in the same motion. Confirmed and delivered steps are protected, because money moved and the physical parcel is already out there.
OrderFlow uses the same trick you would use for a race car: the engine never stops, you just press the pedal.
Automatic tracking runs on a Lightpanda headless browser served from WSL on port 9222. On app launch, the app checks whether the browser is alive, boots it if needed, and then holds one persistent WebSocket connection to it with a dedicated page open on the courier's tracking site. When you click "Check tracking", the request does not pay the cost of starting a browser session. It tells the already warm page to go, scrapes the status timeline, and hands the data back. A full check takes a couple of seconds instead of the tens of seconds a cold browser would need, and Lightpanda itself is light on RAM, so it can sit there all day.
When the headless engine is unavailable (or fails), OrderFlow falls back to a bundled obscura.exe headless fetcher so tracking still works, and notes which path it took.
- Each OrderFlow store maps to a Shopify store (domain, client ID, client secret)
- A background scheduler polls Shopify for new orders; no webhooks needed
- Tokens are kept in the database (or an OS keyring when compiled with the keyring feature)
- Per-order manual re-sync is available from the order drawer; it applies latest Shopify data and clears the locally-edited flag
- Manual orders you create in the app are marked with a shopify_order_id-like status and are never overwritten by sync
| Layer | Choices |
|---|---|
| Shell | Tauri 2 (Rust backend, Windows desktop) |
| Backend | Rust with tokio, sqlx (SQLite), chrono, uuid v7, reqwest |
| Database | SQLite, single file per install (com.orderflow.app/orderflow.db), versioned migrations from 001 to 013 |
| Frontend | React 18 + TypeScript, Vite, Tailwind CSS, TanStack Query for data, Zustand for UI state, react-router (memory router), framer-motion, recharts, lucide-react icons |
| Headless browser | Lightpanda via CDP (WSL), obscura as fallback |
| Tooling | Rust toolchain, Node 18+, Tauri CLI |
orderflow/
src/ Frontend (React + TS + Tailwind)
App.tsx Routes and app shell
pages/ Overview, Dashboard, Orders, ConfirmationQueue,
PackagingQueue, TransitBoard, OrderHistory, Wallet,
Ads, Analytics, Optimizer, StoreSettings, AppSettings
components/ Drawer, modals, navigation, UI kit (ShimmerButton,
BorderBeamCard, GlassDialog, NumberTicker...)
lib/ tauri.ts (typed IPC bindings), store.ts, sim.ts, utils.ts
src-tauri/ Rust backend (Tauri)
src/
main.rs App boot, command registration, lightpanda boot
commands.rs All IPC commands (>70)
sync.rs Shopify polling, per-order sync, wallet helpers
db.rs SQLite init with migrations
models.rs Data structures
lightpanda.rs Persistent CDP client for tracking
migrations/ 001_initial.sql ... 013_local_edited.sql
tauri.conf.json App window, bundle, CSP
Prerequisites
- Node.js 18+ and npm
- The Rust toolchain (stable)
- Optional, for fast automatic tracking: WSL Ubuntu with the Lightpanda binary at
/root/lightpanda(the app can download and start it itself; on machines without WSL, tracking falls back to obscura)
Run in development
npm install
npm run tauri devType-check and build
npx tsc --noEmit # frontend type check
npm run build # full frontend build (tsc -b then vite)
cargo check # backend check, inside src-tauri
npm run tauri build # production bundleThe first launch of the app warms the tracking browser in the background, so the very first tracking check may take a few seconds while Lightpanda boots. Every check after that is fast.
- The database lives at
%APPDATA%\com.orderflow.app\orderflow.db(Windows) - App Settings offers one-click backup of the whole database to a file, with restore
- All destructive operations (reversing orders, clearing wallet entries, resetting store data, deleting a store) use foreign-key-safe child-first deletes inside transactions and ask for typed confirmation
- Migrations are versioned and applied in order; wallet balance is never trusted from a stored value, it is always recomputed
- One source of truth: every amount the UI shows comes from the ledger or a state-filtered query, never from a stored total that could drift
- Snake case on the wire, camel case in TypeScript: Tauri 2 converts top-level command params automatically; nested struct fields stay as authored, which the typed bindings in
lib/tauri.tskeep honest - Live by events: the backend emits
order:state_changedon every mutation, and the UI invalidates its query cache on it, so the dashboard updates itself the second something happens - Dark by default: a deliberately dark, dense UI built from in-house components (no external component libraries) with motion handled by framer-motion
Private project. Own it, ship it, run your store with it.














