Sendy
Iraqi merchants were running a whole business across a notebook, a chat app and three delivery companies. Sendy puts the entire operation in one system.

The interface above is a presentation mockup of the product, not a screenshot captured from a running system. The interface compositions further down this page are built from the platform’s real module structure — these are private client and commercial platforms.
- Role
- Founder · Full-stack engineer
- Year
- 2026
- Status
- In production · Pilot merchants
- Category
- SaaS
Sendy is a multi-tenant SaaS platform where a merchant runs orders, customers, products, inventory, warehouses, storefronts, delivery, drivers, payments, expenses, subscriptions and analytics from one dashboard. I founded it, shaped the product, and build the frontend platform alongside the backend team.
The problem
A merchant in Baghdad typically tracks orders in a notebook or a spreadsheet, takes them over Instagram or WhatsApp, hands delivery to two or three separate companies, and only discovers what an order actually cost after it is finished. Nothing reconciles. Inventory drifts. Nobody can answer "did this month make money?" without a manual audit.
The outcome
One tenant-isolated system that carries an order from storefront to delivered and reconciles inventory, payment and cost along the way — in Arabic first, English second, tested with real pilot merchants.
Stack
- React 19
- TypeScript
- Tailwind CSS
- shadcn/ui
- Vite
- TanStack Query
- Zustand
- React Hook Form
- Zod
- i18next
- SignalR
- ASP.NET Core
- PostgreSQL
- DigitalOcean
- Railway
Services
The operation before the software
Sendy did not start from a technology idea. It started from watching how much of an Iraqi merchant’s day is spent moving the same information between systems that do not talk to each other. It is live today at sendyiq.com.
Orders arrive through Instagram and WhatsApp. They are copied into a notebook or a spreadsheet. Stock is adjusted from memory. Delivery is handed to whichever of two or three companies is answering that day, each with its own sheet and its own status vocabulary. Payment is settled days later, in cash, against a list that has already drifted from reality.
The cost of that is not inefficiency in the abstract. It is a merchant who genuinely cannot tell you which products make money, how much a delivery zone actually costs to serve, or whether last month was profitable — without sitting down for an evening with a calculator.
Who actually uses it
Sendy is not a single-persona product. Seven distinct roles touch the same order record from different angles, and each needs a different amount of the system exposed to them.
Merchant / store owner
Runs the whole business. Needs the full picture — products, stock, orders, money — without needing to understand the system’s internals.
Call centre & cashier
High-volume, repetitive entry. Optimised for speed and keyboard flow, not for exploration.
Delivery company & fleet
Sees assignments and status transitions across many merchants — but only the fields their contract entitles them to.
Driver
A separate, deliberately small application. One screen, one job, usable on a mid-range phone with poor signal.
End customer
Never sees the dashboard. Meets the merchant through a public storefront that must load fast on mobile data.
Scope discipline
The risk in a platform this wide is obvious: build eleven mediocre modules instead of one system. The rule I set was that a module only ships when it changes the state of an order, a product, or money — and when its state change is visible to every other module that depends on it.
- Orders, customers, products, inventory and warehouses form the operational core — nothing else ships before these reconcile.
- Storefronts, delivery and drivers extend the order lifecycle outward to the customer and the road.
- Payments, expenses, discounts and subscriptions attach money to records that already exist rather than creating a parallel ledger.
- Analytics and CRM read from that single source — they never hold their own numbers.
Interface decisions that mattered
Sendy is Arabic-first. That is a structural decision, not a translation task. The default direction is RTL, the default language is Arabic, and the English interface is the mirrored variant — which is the opposite of how most platforms in the region are built, and it changes how every layout is authored.
- Challenge
70+ data tables were each solving pagination, filtering, empty and error states slightly differently.
DecisionI audited every table and data-driven surface, then collapsed them onto one composable table architecture with shared state contracts.
Trade-offA large, unglamorous refactor that produced no new features — paid back on every screen built afterwards.
- Challenge
Mirroring the interface for English kept breaking numeric, currency and technical fields.
DecisionDirectional layout is mirrored; identifiers, currency, phone numbers, URLs and technical tokens are isolated as LTR islands regardless of locale.
Trade-offEvery new field has to declare its directional behaviour — more discipline up front, no bidirectional bugs later.
- Challenge
Delivery partners and merchants needed the same order screen with materially different visibility.
DecisionPermission checks run at the field level, not just the route level, so one screen renders honestly for seven roles.
Trade-offMore complex render logic, but no duplicated screens drifting apart over time.
System architecture
Clients
Three surfaces, one component language
- Merchant dashboard
- Driver app
- Public storefronts
Client state
Server state and real-time state kept deliberately separate
- TanStack Query
- Zustand
- React Hook Form + Zod
- i18next
Transport
REST for records, sockets for live tracking
- REST API
- SignalR / socket.io
- JWT + RBAC
Services
Tenant-scoped business rules
- ASP.NET Core
- PostgreSQL
- Payment gateways
- Delivery providers
Platform
Separate development and production environments
- DigitalOcean App Platform
- Railway
- Custom domains + DNS
- 01
Placed
Created from the storefront, the call centre, or the merchant directly. Same record either way.
- 02
Reserved
Stock is committed against the warehouse so two orders cannot claim the same unit.
- 03
Assigned
Routed to a delivery company or an in-house driver, with the assignment visible to both sides.
- 04
In transit
Driver status updates flow back live; the merchant sees the same state the driver reports.
- 05
Settled
Delivery outcome, payment and cost land on the order — so analytics never needs a manual reconciliation.
Engineering challenges
Multi-tenancy without leaks
Every query, every socket subscription and every uploaded asset is scoped to a tenant. The failure mode here is not a bug, it is one merchant seeing another merchant’s customers — so tenant scope is enforced at the data layer rather than trusted from the client.
Real-time without chaos
Live delivery tracking and server-cached records are two different kinds of state. Mixing them produces interfaces that flicker and lie. Server state stays in the query cache; live positions and status pushes live in a separate real-time store.
Bidirectional layout at scale
RTL is straightforward on a marketing page and genuinely hard across dense operational tables, charts, date pickers and drawer navigation. Building logical-property layouts from the start was cheaper than mirroring a finished LTR product.
Integrations that fail politely
Payment gateways and delivery providers are external and occasionally unavailable. Payment sessions, webhook handling and transaction status surfaces are built so a provider outage degrades one module instead of stopping the merchant from working.
Where it stands
- Status
In production, tested with pilot merchants
- My role
Founder and full-stack engineer
- Surfaces shipped
Merchant dashboard, driver app, storefronts
- Languages
Arabic (default) and English
The most useful thing Sendy taught me is that operational software is judged on the day something goes wrong, not the day it is demoed. A merchant does not care that the dashboard is elegant if a delivery provider times out and the order is stuck in a state nobody can explain. Most of the engineering effort that matters went into the unglamorous half — permission checks, error states, reconciliation, and making failure legible.
Next case study
Building something in this space?
I am available for a limited number of projects. Tell me what you are working on.