Architecture
The unglamorous math behind a good booking calendar
A calendar that shows available slots is deceptively hard: working hours per weekday, timezones, lead time, buffers, and pre-existing bookings all have to compose. Get one wrong and users book slots you cannot honour.
{"ar": "<p>محرّك الحجز في كلّ منتجٍ استشاريّ، وكلّ منتجٍ لعلاجٍ نفسيّ، وكلّ منتج جلسات، يفعل الشيء ذاته أربع مرّات: يعدّد نافذة العمل ليومٍ ما، ويطرح الحجوزات والحصص المشغولة، ويحترم مهلة التقدّم والفواصل، ويقدّم النتيجة في منطقة زمن المستدعي.</p>\n<p>المحرّك صغير. أوجه الفشل كثيرة.</p><h2>ساعات العمل لكلّ يوم</h2><p>احفظ ساعات العمل هيكلاً لكلّ يومٍ من الأسبوع، لا رايةً مسطّحةً لـ"ساعات العمل". الأحد إلى الخميس في المملكة ليس الاثنين إلى الجمعة في مكانٍ آخر؛ أداةٌ عالميّةٌ تفرض الاثنين إلى الجمعة تُنتج نتائج خاطئةً بصمت.</p><h2>المناطق الزمنيّة، بصدق</h2><p>احفظ كلّ حجزٍ بـUTC. احسب التوفّر في منطقة زمن الخدمة الأصليّة (حيث تُعرَّف ساعات العمل). قدّم النتيجة في منطقة زمن المستدعي. لا تحفظ وقتاً محلّيّاً كسلسلةٍ عارية أبداً. كلّ خطأ مرتبطٍ بالتوقيت الصيفيّ بدأ باختصارٍ على القاعدة الأخيرة.</p><h2>مهلة التقدّم والفواصل إعداداتٌ من الدرجة الأولى</h2><p>خدمةٌ تقول "احجز قبل ساعتَين على الأقلّ، واترك خمس عشرة دقيقةً بين الجلسات" تُعبّر عن قيدَين يجب على المحرّك تطبيقهما آليّاً. مهلة التقدّم قيمةٌ، والفاصل قيمةٌ أخرى؛ خلطُهما في "زمنِ إعدادٍ" واحد سيُحاصرك في كلّ قرارٍ منتجٍ ثالث.</p><h2>الحصص المُستثناة</h2><p>تحتاج طريقةً لوسم يومٍ، أو تكرارٍ أسبوعيّ، أو مدىً محدَّد، على أنّه غير متاح — خارج نموذج ساعات العمل. عطلةٌ وطنيّة، أو أسبوع إجازةٍ شخصيّ، أو نافذة صيانة. مثّل هذه في جدولِ استثناءاتٍ منفصل بدلاً من تعديل نموذج ساعات العمل؛ سلوك الفرق أسهل في التفكير.</p>", "en": "<p>The booking engine in every consulting product, every therapist product, every consultation product, does the same four things: enumerate the working window for a date, subtract existing bookings and blocks, honour lead time and buffers, and present the result in the caller's timezone.</p>\n<p>The engine is small. The failure modes are many.</p><h2>Working hours per weekday</h2><p>Store working hours as a per-weekday structure, not a flat business-hours flag. Sunday–Thursday in the Kingdom is not Monday–Friday elsewhere; a global tool that hard-codes Monday–Friday as business days silently produces the wrong output.</p><h2>Timezones, honestly</h2><p>Store every booking in UTC. Compute availability in the service's home timezone (that is where working hours are defined). Present in the caller's timezone. Never store a local time as a naked string. Every subtle DST-adjacent bug starts with someone taking a shortcut on that last rule.</p><h2>Lead time and buffers as first-class settings</h2><p>A service that says <em>book at least two hours ahead, and leave fifteen minutes between sessions</em> is expressing constraints that the engine must apply mechanically. A lead-time value and a buffer value are two separate settings; conflating them into a single "setup time" will corner you on every third product decision.</p><h2>Blocks</h2><p>You need a way to mark a date, a weekly recurrence, or a specific range as unavailable — outside the working-hours model. A national holiday, a personal week off, a maintenance window. Model these as a separate table of exclusions rather than modifying the working-hours model; the diff behaviour is easier to reason about.</p>"}
About the author
H
Hani Yousif
CTO & Co-founder · Solutions Architect
Related
Architecture
The case for modular ERP in Saudi enterprise
Architecture
Building Arabic-first, not English-translated
Architecture