Online app.bizleen.com
Bizleen Orbit
The team’s workspace, inside Bizleen.
In short
Bizleen Orbit (formerly StaffClock) is a product of Bizleen: the team’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 in 14 languages.
Born for one restaurant, it now serves eleven verticals with nine shipped modules, a covers-based booking engine, and an appointment engine undergoing unification. One Cloudflare Worker: Hono 4, React 19, Drizzle, D1, R2, three Durable Objects. Online at app.bizleen.com, linked to Bizleen through bidirectional production SSO; the historical domain staffclock.app is still served.
Highlights
-
Bidirectional SSO active in production
Since 16 September 2026, Bizleen SSO has been live in production both ways: an active session on bizleen.com opens app.bizleen.com with no password, and from app.bizleen.com a manager reaches Bizleen Studio or Insights through a one-time token valid for 60 seconds, with cascade revocation traced in the audit log.
-
Venue mode (internal / standalone)
definirNiveauEspace contract: an internal-mode venue disables standalone public bookings without losing any of its records or staff rights.
-
Custom 5-slot navigation bar
Mobile navigation bar capped at 5 clear tabs with permanently legible labels; managers pick their pinned tabs under their thumb (ongletsEpingles).
-
Rigorous address conventions
Informal address for employees on their private space and calendar; formal address strictly applied for management and independent contractors.
-
Icon styles & extended dark mode
Choice of icon style per device (outline or solid/colour) in settings; dark theme extended to contractors and the shared counter tablet.
-
Autonomous web push re-subscription
The app re-subscribes autonomously when push subscriptions drop, shows the real device state and offers explicit opt-out.
-
One-tap clock-in
Shared front-of-house tablet, server and manager PINs, daily entries, work locations. Big buttons born from the first restaurant rush.
-
Tips in 3 modes
Three distribution modes remembered day by day, a separate axis for cash, idempotent weekly settlements: a replayed settlement never pays twice.
-
Estimated pay
Calculation, exports, scheduled payroll sends, monthly closures: each employee sees their estimate, the venue closes its month.
-
Leave & scheduling
Leave requests with designated approvers, shift planning, swaps between employees and rest patterns.
-
Employee portal in 14 languages
Personal employee portal translated into 14 team languages, guarded by cryptographic signatures against desynchronisation.
-
Hardened booking engine
One-click service closure, strict time floor, absence awareness and Google review requests scoped to completed services < 3 days old.
By the numbers
- 9 Modules shipped
- 11 Verticals served
- 13,990 Test cases
- 87 Database tables
- 113 SQL migrations
- 573 API endpoints
The story
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. On 16 September 2026, unified SSO with Bizleen went live in production both ways, complemented by seven RPC channels. Everything runs in a single Cloudflare Worker, with 300,310 lines of test for 301,870 lines of production code.
Structural technical decisions
A shared tablet on the floor, and roles that model it
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 tables are partitioned by venue, and a superadmin entering a venue is traced in the audit log.
Eleven verticals served by behaviour axes, not by the name of the trade
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.
Verifiable layers and a domain with no side effects
The server is split so the separation can be checked, not just declared: 46 route files (573 verbs) carrying only validation and authorisation, 92 service files, 89 pure domain files with no side effects, 58 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 dozens of test files replay the SQL migrations until triggers show up in sqlite_master.
Three Durable Objects, each for a single reason
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.
A React client with no state manager and no component library
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
The appointment engine: hardening and convergence
It is the largest block in the codebase, featuring dozens of dedicated tables, named CHECK constraints and strict SQL triggers. It stacks three engines (rules, allocation with a bounded deterministic solver, and orchestration under Durable Objects).
The week of 13-20 September resolved historic issues: past slots are strictly forbidden by a temporal floor, employees on approved leave are removed from online booking automatically, service completion happens in a single tap, and Google review invites only target completed services under 3 days old.
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 maintain a test suite close to one-to-one with production code (300,310 against 301,870 lines).
Tech specs
Where it runs Cloudflare Workers (single Worker) · Cloudflare D1 (SQLite) · R2 · 3 Durable Objects · Hono 4
| Runtime | Cloudflare Workers (single Worker) · Static Assets · 3 Durable Objects |
|---|---|
| Backend | Hono 4 · TypeScript strict · Zod · 573 endpoints (46 routes) |
| Data | Cloudflare D1 (SQLite) · Drizzle ORM · 87 tables · 113 migrations · R2 |
| Frontend | React 19 · 48 lazy-loaded screens · Tailwind CSS 4 · Vite 8 |
| Environments | Production · Isolated demo (its own database, bucket, subdomain and secrets) |
| Tests | 300,310 test lines · 13,990 cases · 301,870 production lines (ratio 0.99) |