← ./work / NIGHTSHIFT.flow
NIGHTSHIFT.flow
An event-driven back office for a publisher selling in six places
A small publisher sells books and prints in six places, and every sale used to mean copying details by hand into four systems. NIGHTSHIFT is a study of the back office I'd build for them: event-driven, queue-backed, and boring in the best way.
- Type
- Automation · architecture
- Year
- 2026
- Role
- Architecture, workflows, AI extraction
- Status
- Concept study
Concept A study of how I’d approach this kind of problem, not a client project.
$ cat ./targets — design targets, not measured results
- ~1,800
- orders a week
- < 60 s
- order to shipping label
- 97%
- handled without a person
- 0
- orders dropped, by design
Ingress
Every channel calls one webhook gateway. It checks the signature, gives each order an idempotency key so a retried webhook can't create a duplicate, and answers in under 200 ms. Emailed and PDF orders go through document AI first: OCR, then a language model pulls out the fields and scores how sure it is about each one.
Queue and workers
Nothing heavy happens inside the request. The gateway puts a job on a Redis-backed queue with a priority, and a pool of stateless workers picks it up. The pool scales from 2 to 12 containers on queue depth, so a sales spike only makes the queue longer for a while.
When things go wrong
Every step retries with exponential backoff. After five failures the job moves to a dead-letter queue with its full payload, where it can be replayed with one click. Anything the extractor is unsure about (confidence under 0.9) waits in the team chat with approve and edit buttons.
Observability
Each run writes to an execution log in Postgres, which doubles as the audit trail for the accountant. Queue depth, error rate and time from order to label go to one dashboard, and alerts arrive as a single sentence in chat.
What changes
Mornings start with three exceptions instead of a pile of orders. Every Monday a short summary, written by a language model from the week's numbers, says what sold, what's running low and what needs a decision.
$ trace — how it works
- 016 sales channels
- 02Webhook gateway
- 03Document AI
- 04Job queue
- 05Worker pool
- 06Accounting · carriers · stock · CRM
- 07Monday report
$ open ./result — what it would look like