A case on a shelf
Tracking systems answer where is it now? for something that moves: a driver, a parcel, a route. Ataya asks the same question about something that doesn’t move until somebody picks it up, a phone case on a shelf in Sharqia. The answer is the same kind: it is where the last real event put it.
Behind that is one Bun process and one SQLite file, serving four surfaces: the
counter, a Preact PWA that sells offline; the web store, in Arabic, cash on
delivery, with no account to create; a repair desk; and a kiosk tablet inside
the shop, turned to face the customer. 52 commits between 2026-09-18 and
2026-09-25, 17 migrations, 259 tests, eight decision records. Live at
ataya.kariem.dev.
Every screen below comes from a demo shop: the product’s own sample catalogue on a scratch database, driven through its own API. The names, numbers and prices are made up; the behaviour is the real code.
The customer starts with their phone
A shop like this doesn’t sell “cases”. It sells a case that fits this phone. So the store’s first question isn’t a category, it’s the customer’s phone.


The customer gets a promise
In Egypt most web orders are paid on delivery, and many never happen. The number doesn’t answer, the customer changes their mind on the call, or the parcel is refused at the door. So the first thing Ataya gives a customer is not a shipment. It is a promise, and the screens say so.


The store also refuses promises the shop can’t keep. A first order paid on delivery is capped at 1,500 EGP, checked on the server. Past that, the customer pays part up front, because a shop this size can’t absorb a large refused parcel from someone it has never met.
The link on that page is the customer’s receipt. There’s no account and no password. It carries a token, and it keeps telling the truth as the order moves:


Nothing crosses the shelf but hands
Most stock systems take the item out of stock the moment an order is placed. Here that would fill the ledger with events that never happened. The fourth decision record draws the line instead:
“A placed order creates reservations (24 hours), not moves. The stock move happens at
packed, when someone takes the item off the shelf.” “Every ledger move matches a physical event.”
The seller sees the line from the other side. A confirmed web order is still a promise, so each piece in it shows how many are on the shelf right now, next to what the courier has to collect:

Below the line the order is a fact, a signed row in a table the database won’t let anyone edit:
CREATE TRIGGER trg_stock_moves_no_update
BEFORE UPDATE ON stock_moves
BEGIN
SELECT RAISE(ABORT, 'stock_moves append-only: UPDATE ممنوع. سجّل حركة تصحيح جديدة بدلًا من التعديل.');
END;An edit is refused with its own instruction: record a correcting move instead. A mistake stays visible, next to its correction. On-hand is SUM(qty), so there is no stored number that could drift away from the history.
Cost follows the same rule. Each supplier receipt is a FIFO layer, and a sale consumes the oldest layers first and records which ones it used. A refused parcel goes back into the layer it came from, not into a new one at today’s price. The layers aren’t hidden in the database; every item shows them:

At the counter, the count is blind
The counter is where money and stock move together, so every screen here is about not letting the two drift apart.


Nothing sells until a shift is open, and opening one means counting the float:

At closing the seller counts the cash. If the screen shows the expected amount first, the count tends to match it: a miscount gets “found”, a shortfall gets covered, and the variance stops meaning anything.

So closing is two calls, in order. submitBlindCount() takes the count and the
PIN of someone allowed to close the drawer, closes the shift, and replies with
nothing but the closing time. Only after that does revealExpected()
compute what the drawer should hold:

The counter sells whether the network is up or not. Sales wait in an outbox
and sync one at a time when it comes back, and two unique keys on the server,
(device_id, local_id) and (device_id, local_seq), make a resend harmless. A
flaky connection can’t turn one sale into two.
A phone left at the desk
Half of a phone shop’s trust is the repair desk: someone leaves a phone that holds their whole life and walks out with a paper slip. Ataya gives them a link instead of the slip, and a rule before any work starts.


Inside the shop, the same ticket holds what the technician needs and hides what nobody else should see:

What the owner reads at night
The book, الدفتر, is what the owner opens after closing. It doesn’t show a dashboard of everything. It answers one question first: did today pay for itself?



Every mark has one job
The design system is called «صنعة», craft, and its first law is that nothing on screen is decoration. There are three marks, and each has one job:
- The seal, الختم, is trust. It goes on three things only: an original product, a real photo from the shop, and an item checked before shipping. It is on the order and repair pages above. If the shop isn’t sure, there is no seal.
- The stitch, الغرزة, is the divider. It’s the seam of a leather case, and it joins the order steps on the tracking pages. It is never a frame.
- The ruler, المسطرة, is fit. It appears in one place, under «موبايلك إيه؟», what’s your phone?, because the phone model is the first filter everywhere, before the category.
The colours are named after materials in the shop: coffee-brown ink, kraft paper, sand, brass. Brass is kept for trust and money: the seal, and the button that collects cash. The palette is brown because the street’s colours are taken: Vodafone red, Orange orange, Etisalat green, WE purple, and the chains’ corporate blue.
This site’s card for Ataya is built from the same system: the product card’s 18px radius, a one-pixel ring instead of a shadow, a 2px lift on hover, and the stitch above the role line. The signature, the letter ع inside a phone case, is rendered from the product’s own font file, and the script that renders it is in this site’s repository.
What is not done
- The shop is small, and the numbers say so. On 2026-09-25 the live database held 82 products, 8 counter sales, 1 delivered web order and 5 shifts. That’s a real shop starting on a real system, not a system at scale.
- The photos aren’t real yet. Every product shows a drawn icon labelled «رسم توضيحي», illustration, because the brand forbids implying a photo that doesn’t exist. The shoot spec is written: kraft paper behind the product, daylight from a window, square, a hand holding it for scale.
- Fit data is coarse. Compatibility still says “iPhone · Android”. The ruler needs a brand and model on every case and screen protector to keep its promise.
- No e-receipts. Egypt’s tax e-receipt system isn’t connected. The shop isn’t registered with it yet, and the integration isn’t built.
- The repository is private. It’s ready for open source, with fake test data, a public-safe seed, docs and decision records, but it hasn’t been published.