Skip to content
keforo-app

Case study

Keforo App

The order desk for MENA e-commerce teams: orders, stock, customers and a Google Sheet that stays in sync.

Role
Founder, full-stack engineer
Year
2024
Stack
Next.js · Hono · Bun · MongoDB · Redis

The challenge

Shops here run on a Google Sheet before they run on anything else. The order desk had to read that sheet, move stock and status together, and let nobody do more than they may.

In numbers

  1. 386Routes, each declared as data: method, path, scopes and schema.
  2. 68Scopes across 18 modules, edited per person.
  3. 585Backend tests, against MongoDB and Redis.
  4. 7Order transitions, one endpoint each.

What it runs

One board for every order.

One board for every order, with a strict lifecycle, line items that can be cancelled or marked out of stock one by one, partial returns that restock, and an activity log with 18 kinds of entry.

Stock lives in two buckets, on hand and committed. Every change writes a stock movement that points back at the order, import or return that caused it.

In Arabic, French and English, with a real right-to-left layout.

The lifecycle

An order is a state machine

Every status change goes through one service. It checks the move against a table, applies what the move does to stock, writes the new status and appends to the activity log, all inside one MongoDB transaction. If any part fails, none of it happened.

draftbeing built, no stock heldpendingplaced · units committedconfirmedstatus onlypackedstatus onlyshippedheld until delivereddeliveredsold · on hand −refundedon hand +cancelledcommitted releasedPOST /placePOST /confirmPOST /packPOST /shipPOST /deliverPOST /refundPOST /cancel

Live

Try the transitions

Pick a token, then press an endpoint. The route refuses a missing scope before the handler runs, the service refuses a move that is not in the table, and a legal move changes the status, moves stock and writes the log.

Live

Google Sheets

One sheet, one run

  1. Step 1 of 6

    Queue

    One job per sheet, from the cron or the Sync now button. The worker runs one job at a time, on purpose.

  2. Step 2 of 6

    Version

    One Drive call compares the sheet’s version with the last run. An unchanged sheet is skipped right there.

  3. Step 3 of 6

    Mapping

    Every mapped header must still be there. If one is gone, the sheet is paused and its owner gets one email; nothing is guessed at run time.

  4. Step 4 of 6

    Read

    Rows are read 5,000 to a page, under a per-organisation limit of sixty calls a minute.

  5. Step 5 of 6

    Import

    Every row goes through the same processor a CSV upload uses. An order that is packed or later is never touched by a sheet.

  6. Step 6 of 6

    Report

    The run writes its counts and an error sample, and the organisation’s room hears it over WebSocket. A run always ends; none is left running.

Replay

A sync run, replayed

The connector treats the sheet as the source and the app as the mirror: each run reads the sheet, and nothing is written back to it.

Replay

Connecting

Three ways to connect

Google reviews every app that asks for Drive access, and the review takes time. So the connector has three doors, and two of them need no review at all.

Your sheetGoogle SheetsGoogle sign-infile picker · drive.file scopePublic CSV linkno Google API at allService accountshare the sheet with an emailLinked sheetmapping · conflict policy · cadenceSync runone job, one worker at a timetoken, encryptedcontent hashkey, encryptedcron · Sync now

The assistant

The assistant only does what you may

The chat in the sidebar is an orchestrator that owns no domain knowledge and one tool: delegate. It hands a sub-task to one of five specialists, in parallel when a question spans domains.

The first line of every tool is a scope check. The scopes come from the caller’s token; a model saying “the user is an admin” changes nothing.

Writes wait for a person. Cancelling an order or changing a price creates a pending action that the person confirms in the chat, and the scope is checked again at confirmation.

Permissions

Every tool checks the caller

Eleven tools, each declaring the scope it needs. A specialist whose tools need scopes the caller lacks is left out of the orchestrator’s prompt, so the model cannot even try.

Youchat in the sidebarPOST /ai/chatSSE streamOrchestratorsees one tooldelegateone specialist per domainSpecialistorder · product · customer · analytics · helperTool11, each declares a scoperequireScopeyour JWT, never the model’s wordMongoDBscoped to your organisationmessageturnsub-taskin parallelcallfirst linethen the servicetokens

Built with

  • Bun
  • Hono
  • MongoDB
  • Redis
  • BullMQ
  • WebSocket
  • Next.js
  • TanStack
  • OpenRouter
  • Google Sheets
  • Google Drive

Where it stands

Live at app.keforo.com

Orders, stock, team scopes, the assistant and bank-transfer billing run today, with Google Sheets as the first connector. Still to come: store connectors, writing back to the sheet, per-row change detection and card payment.

Read how it works
Models, each carrying its organisation.
50
Background workers: sheet sync, sheet cron, imports and billing.
4
Next caseJad Elevateur