Komvos Connect
Lead Developer
A self-hosted booking platform: drop a single script tag on any business website and you have availability, calendar sync, and confirmations. Replacing Calendly-class SaaS for clinics, hairdressers, and service providers.
Results
- script tag to put booking on any website
- 1
- files of automated checks before every change
- 385
- calendars kept in sync, Google and Outlook
- 2

The situation
Small businesses that run on appointments, clinics, hairdressers and service bureaus, usually pay per user per month for a calendar on somebody else’s machine. I wanted to see whether the same job could be done by a system that runs on a server I control and drops onto any website, without rebuilding that website. Komvos Connect is that: I designed and built it on my own, and it is in production.
Booking on the site they already have
The business does not change its website and does not send its customer somewhere else. It puts one line on its page and the calendar of free times appears, in its own colours.
The visitor picks a service, a day and a time and gets an email confirmation, without an account and without leaving the page.

How it works
- Widget: a vanilla JavaScript bundle installed with a single
<script>tag, because tenants put it on third-party sites where React or Vue cannot be assumed. - Configured from the markup: it attaches to an empty
divand reads its tenant, public key and accent colour from that element’s data attributes, so no secret reaches the browser. - API: Fastify 5 on Node 22, with Zod validation on every input and Turnstile in the widget behind a consent check.
- Queues: a separate worker with BullMQ on Redis for confirmation emails and hold expiry, so an HTTP request never waits on a mail server.
One calendar, not two
Staff do not keep a second calendar for bookings. They connect their Google or Outlook once, and the hours already taken there stop showing up as free.
Every provider has their own hours, exceptions and services, so two colleagues in the same room need not work the same shift.

How it works
- OAuth per provider: Google and Outlook, with credentials stored per provider and per tenant.
- A single loader for busy hours: every reader and every writer goes through the same function, so a new source of busy time has exactly one insertion point.
- Admin SPA: React 19 with TanStack Router, Query and Table, and Better Auth for sign-in.
- Per-tenant settings: SMTP, language, timezone and branding live on the tenant’s own row, not in environment variables. The admin, the emails and the manage-booking pages each carry a dictionary per language.
The time the customer sees is the right one

Booking works the same way on a phone and on a desktop: service, day, time, confirmation. The visitor may be in a different country from the clinic, and a daylight-saving change can fall between the moment of booking and the day of the appointment.
How it works
- Stored in UTC, but availability is always calculated in the provider’s timezone with date-fns/tz, never the guest’s, and converted back for display.
- Tested against real clock-change dates for
Europe/AthensandEurope/London, so the bug is caught in CI rather than in October. - Holds: the slot is reserved while the visitor fills in their details and released by the worker if they do not finish.
- How the 385 test files split: 219 unit files for the logic and the admin components, 159 integration files that bring up a real PostgreSQL in a container with Testcontainers instead of mocks, and 7 Playwright specs.
Each business’s data stays its own
Many businesses live in the same system, and none of them should be able to see another’s appointments. That is not a matter of care, it is a matter of construction.
How it works
- Row-level isolation:
tenant_idon every data table, and 24 of the 31 schema files carry it. - Access through scoped accessors rather than free-hand queries that could forget the filter.
- Prefixed identifiers: a nanoid with a per-type prefix, so a
booking_7kRt3min the logs reads immediately as a booking. - Database and deployment: PostgreSQL 16 with Drizzle and 34 migrations so far, deployed through Coolify with a multi-stage Docker build.
Links
- Repo:
jimrarras/multi-tenant-calendar(private)
Related work
- TaskFlow: another multi-tenant SaaS with real-time and offline-first, but for task dispatch rather than bookings
- Heartbeat Pharmacy PIM: another production system with Better Auth and Coolify deployment