Bizleen Orbit
Online ยท app.bizleen.comBizleen Orbit (formerly StaffClock) is Bizleen's connected workspace: clock-in, tips, estimated pay, leave, shift planning, events, notifications and documents, served on the venue's shared tablet and on each employee's phone. Born for one restaurant, it now serves eleven verticals with nine shipped modules, a covers-based booking engine, and an appointment engine still in progress. One Cloudflare Worker: Hono 4, React 19, Drizzle, D1, R2, three Durable Objects. Online at app.bizleen.com; the historical domain staffclock.app is still served.
Why I built it
A restaurant was tracking hours on a slow app, with a time picker impossible to handle during a rush; card tips were split by hand and salaries estimated by gut feel. I built the tool on 3 June 2026 for that exact need, under its first name: big-button clock-in, automatic tip distribution to the cent, estimated pay, formal closures. Once the tool was in place for one venue, I opened it to several (superadmin, venues, admins invited by email), then to eleven verticals served by behaviour axes rather than by the name of the trade. On top of clock-in came leave, shift planning, events, notifications, documents and estimated payroll: nine shipped modules. In August 2026, the connection to the public Bizleen site began, because a mini-site can display a grid of priced services but cannot say whether Tuesday at 3 pm is free, and that information lives in the tool that already holds the schedule. The tool became Bizleen Orbit on every surface the customer sees: application, manifest, emails, logos, and the app.bizleen.com domain. The bridge between the public site and the connected workspace is built and tested on both sides; its commercial rollout is under way. Everything runs in a single Cloudflare Worker, with 252,814 lines of test for 211,451 lines of production code.
Structural technical decisions
In a restaurant, the device that clocks people in belongs to nobody: it is a tablet left at the pass, touched by everyone. Orbit's roles start from that reality instead of working around it. The tablet is a shared consultation post; a server or manager PIN raises rights for the length of one action, and that elevation is traced. Each employee's phone is their private space: their hours, their tips, their leave, nothing else. On the data side, 74 of 84 tables are partitioned by venue, and a superadmin entering a venue is traced in the audit log.
Orbit never tests "if restaurant then". Each trade is described by pure axes: private tracker, medical bonuses, tips, solo timesheet, event organiser. A vertical is a combination of those axes, and opening a twelfth trade is configuration work, not a code duplication. That is what made it possible to go from one restaurant to eleven verticals without forking the engine.
The server is split so the separation can be checked, not just declared: 45 route files (21,304 lines) that carry only validation and authorisation, 85 service files (47,303 lines), 79 pure domain files with no side effects, 53 repositories, and no repository imports a service. Under that stack, an integration base: a transactional outbox with leases and a dead letter, a consumption inbox, an idempotency registry able to replay the original response, read projections of the catalogue published by Bizleen. And 52 test files replay the SQL migrations until the triggers show up in sqlite_master.
A booking coordinator per venue, which serialises requests on a date; a debounce for tip notifications, which batches bursts before the push send; and a guard that refuses any command addressed to the wrong instance. Notification fan-out is bounded per venue and per time window, so a burst of entries never becomes a burst of pushes.
48 screens loaded on demand along role boundaries, no state manager, no component library, and a single fetch call in the whole client: every request goes through the same door. The SPA is served as Static Assets next to the API, in the same Worker.
The non-trivial challenge
It is the largest block in the codebase: 45,657 server lines, 14,807 client lines, 20 dedicated tables, 167 named CHECK constraints, 69 SQL triggers. It stacks three engines. A rules engine describes a service as ordered steps, with margins and, for each step, resource requirements (kind, skill, level, quantity). An allocation engine places holds whose lifetime is read from the database clock, and resolves them with a bounded, deterministic solver. A command orchestrator runs under a coordinator Durable Object, one instance per venue, and a guard refuses any command addressed to the wrong instance. The simpler covers engine (capacity per service) is shipped and already serves restaurant bookings. The appointment engine remains a build in progress: it is presented as such, with no date.
Lesson learned
A tool built for a single restaurant can become the connected workspace of eleven trades, on two conditions I learned here. First, the engines must never know the name of the trade: each vertical is a combination of behaviour axes, and one more trade is configuration. Second, a layered architecture is only worth something if it can be verified: routes that only validate and authorise, a domain with no side effects, repositories that never import a service, and tests that replay the migrations all the way to the triggers. That is what makes it possible to write more lines of test than lines of production code (252,814 against 211,451). Last lesson, a simpler one: a build in progress is called a build in progress. The appointment engine is under construction, and this page says so.
Features
Shared front-of-house tablet, server and manager PINs, daily entries, work locations. The big buttons come from the first restaurant: you have to be able to clock in during a rush.
Three distribution modes remembered day by day, a separate axis for cash, idempotent weekly settlements: a replayed settlement never pays twice.
Calculation, exports, scheduled payroll sends, monthly closures: each employee sees their estimate, the venue closes its month.
Requests, per-venue designated approvers, automatic reminders when a request is waiting.
Availability, shift swaps between employees, rest patterns: 7,465 lines for this module alone.
34 endpoints, QR clock-in with a regenerable secret, billing by hourly rate or flat fee.
Web push, a debounce Durable Object, device subscriptions; fan-out bounded per venue and per time window.
Declarative register, business audit trail that can be produced on request, account purge on demand.
33 endpoints, traced impersonation, 74 of 84 tables partitioned by venue.
Capacity per service, serialised per venue and per date: this is what serves Bizleen's partner booking widget.
45,657 server lines, 20 tables, three stacked engines (rules, allocation, orchestration). An open build, presented as such, with no date.