Skip to content

A customer is told what happened, and never what might - #793

Merged
sridharkalaibala merged 2 commits into
developfrom
feat/a-customer-can-see-their-own-order
Sep 16, 2026
Merged

sridharkalaibala merged 2 commits into
developfrom
feat/a-customer-can-see-their-own-order

Conversation

@sridharkalaibala

Copy link
Copy Markdown
Contributor

Stage 5 of the print roadmap - "the customer knows".

The thank-you page asked the shop one question, once, as it opened: is this
paid yet. Everything that happened to the order afterwards - a person
accepting it, a ticket coming out of a kitchen printer, the shop refusing it
at 2am - happened behind the customer's back, and the only way to find out was
to walk to the counter and ask.

No ladder

The stage carries its own warning: "Do not ship a stage nothing can move off.
If Ready is unreachable because nobody presses anything, a frozen tracker is
worse than none."

Three of the four rungs everyone has seen on a delivery app are unreachable
here:

rung why it cannot light
Ready nothing in the product sets it. Nobody presses anything.
Cooking we know a ticket printed. Nothing says a cook started.
Accepted a shop on automatic never decides anything, so the word describes a decision nobody made.

So there is no ladder. There is a trail: what has already happened, each
with the moment it happened, newest last. A trail cannot freeze, because it
never claims anything about what comes next - a shop whose kitchen printer is
off simply has a shorter trail, not a stuck one.

  • Placed, from created_date
  • Accepted, only where order_state_by names the person who worked the queue
  • In the kitchen, only where a till reported that a printer produced paper
  • Refused / Cancelled as endings, drawn after the history rather than
    in place of it: a customer who cancelled two minutes late needs to know the
    kitchen had already started

The one thing named before it happens is a held order's acceptance, because
order-approval.js allows pending to move nowhere else. It carries the shop's
own recent answering speed - median over a fortnight, cached, bounded by an
_id range so it is an index walk rather than an in-memory sort - worded as a
description of the past. No cooking time: nothing here knows when food is
finished, and an invented ETA is the number a customer waits against and then
comes to the counter about.

Keys and times on the wire, words on the page, because /order carries its own
Tamil dictionary keyed by the English sentence and a sentence built on the
server arrives as English nothing can translate.

Two bugs found on the way

The history page was making the claim this stage exists to stop. It called
every accepted order "With the kitchen", including ones whose ticket never
printed. Both customer screens are now drawn from the same trail, so they
cannot disagree.

The thank-you page could not reach the shop at all. It resolved the shop
through knownBranchId() and the order through rememberedOrders(), both of
which live in indexedDB.js - which that page does not load and never has.
Both calls sat behind typeof ... === "function" guards, so nothing threw and
nothing showed: the bill-when-paid button and the pay-by-UPI offer have
silently done nothing there since the day they were written. Loading
indexedDB.js is not the fix; it starts a timer that refetches the whole menu
every ten seconds. The page now answers from the ?order= it arrives with or
the sale id on its own receipt, and from posnic_store, whose two spellings
are pinned together by a test.

Cost

The page polls with backoff and asks nothing while the phone is in a
pocket, resuming the moment somebody looks. It stops for good at a settled
state or a payment, and after half an hour regardless. The shop's answering
speed is read only while an order is actually being waited on, once per page
of history rather than once per row, and cached for five minutes per branch.

Checks

  • api: 372 suites, 10,797 tests
  • tests/online-ordering-ux.test.js: 136
  • npm run check: 7/7

The new history-page test was run against the old code first and fails there,
naming every accepted order "With the kitchen".

Not in this PR

ready_by from #790 is drawn on the history page but not on the thank-you
page, because its helper lives in indexedDB.js too. Now that the fetch works,
that is a small follow-up - worth doing as a shared file rather than a second
copy.

Stage 5 of the print roadmap - "the customer knows". The thank-you page
asked the shop one question, once, as it opened: is this paid yet.
Everything that happened to the order after that - a person accepting it,
a ticket coming out of a kitchen printer, the shop refusing it at 2am -
happened behind the customer's back, and the only way to find out was to
walk to the counter and ask.

The stage's own warning is what shaped this: "Do not ship a stage nothing
can move off. If Ready is unreachable because nobody presses anything, a
frozen tracker is worse than none." Three of the four rungs everyone has
seen on a delivery app are unreachable here. Nothing marks an order ready.
Nothing says a cook started; we know a ticket PRINTED. And a shop on
automatic never decides anything, so "Accepted" would describe a decision
nobody made.

So there is no ladder. There is a TRAIL: what has already happened, each
with the moment it happened, newest last. A trail cannot freeze, because
it never claims anything about what comes next - a shop whose kitchen
printer is off simply has a shorter trail, not a stuck one.

Placed, from created_date. Accepted, only where order_state_by names the
person who worked the queue. In the kitchen, only where a till reported
that a printer produced paper. Refused and cancelled as endings, drawn
after the history rather than in place of it: a customer who cancelled two
minutes late needs to know the kitchen had already started.

The one thing named before it happens is a held order's acceptance,
because order-approval.js allows pending to move nowhere else. It carries
the shop's own recent answering speed, median over a fortnight, worded as
a description of the past. No cooking time: nothing in the product knows
when food is finished, and an invented ETA is the number a customer waits
against and then comes to the counter about.

Keys and times on the wire, words on the page, because /order carries its
own Tamil dictionary keyed by the English sentence and a sentence built on
the server arrives as English nothing can translate.

The history page is fixed by the same shape: it called every accepted
order "With the kitchen", including ones whose ticket never printed.

The page polls with backoff and asks NOTHING while the phone is in a
pocket, resuming the moment somebody looks.
The thank-you page resolved the shop through knownBranchId() and the order
through rememberedOrders(). Both live in indexedDB.js. This page does not
load indexedDB.js and never has.

Both calls were written behind `typeof ... === "function"` guards, so
nothing threw and nothing showed: the shop id came out empty, the function
returned before its first request, and everything behind it - the bill
when the shop marks the order paid, the offer to pay by UPI - has silently
done nothing on that page since the day it was written. A guard that turns
a missing dependency into a quiet nothing is how a shipped feature runs for
months without ever running once, and the trail would have joined it.

Loading indexedDB.js here is not the fix: it starts a timer that refetches
the shop's whole menu every ten seconds, behind a page whose only job is to
show a token.

So the page answers from what it already holds. The order comes from
?order= on the way in from the history page, or from the sale id on the
receipt this phone was handed at checkout. The shop comes from
posnic_store, which indexedDB.js writes on every menu load. The two
spellings of that key are pinned together, because a rename on one side
would put this page straight back where it was.
@sridharkalaibala
sridharkalaibala force-pushed the feat/a-customer-can-see-their-own-order branch from 8a51275 to c6b2450 Compare September 16, 2026 04:43
@sridharkalaibala
sridharkalaibala merged commit d7f5aa0 into develop Sep 16, 2026
9 checks passed
@github-actions github-actions Bot added the ready for QA Merged to develop and live on develop.posnic.io - anyone can test it label Sep 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Merged to develop. Anyone can test this - you do not need write access.

Try it at https://develop.posnic.io, or run it yourself:

git fetch origin develop && git checkout develop
npm install && npm --prefix api install
npm run dev   # then http://localhost:3000

When you have tested it, say what you did and what happened, and set
QA passed or QA failed. If you cannot set labels, just comment -
a maintainer will.

Reporting that something is broken is as useful as fixing it. It is
better found here than by a shopkeeper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for QA Merged to develop and live on develop.posnic.io - anyone can test it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant