Skip to content

Commit ee2a7c3

Browse files
committed
Add documentation for booking policy, configuration modules, quick start guide, and TypeScript integration
- Created `booking-policy.md` to outline the enforcement checks for booking requests. - Added `config-modules.md` detailing the six built-in configuration modules and their fields. - Introduced `quick-start.md` for a streamlined guide to setting up the platform and creating a booking. - Developed `typescript-integration.md` with code samples for integrating ServiceForge in Node.js or browser applications.
1 parent 59bd59f commit ee2a7c3

10 files changed

Lines changed: 2268 additions & 108 deletions

File tree

docs/web/content/guide/api-reference.md

Lines changed: 505 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
title: Booking Policy
3+
description: How the booking-service enforces tenant configuration on every POST /v1/bookings
4+
order: 5
5+
---
6+
7+
# Booking Policy Enforcement
8+
9+
Every `POST /v1/bookings` passes through a sequential policy pipeline before the booking is stored. The pipeline reads the tenant's `booking` and `business-hours` module configs from the config-service (cached for 60 seconds) and applies seven checks in order.
10+
11+
**If any check fails, the pipeline stops immediately and returns the error.** Subsequent checks are not evaluated.
12+
13+
---
14+
15+
## The Pipeline
16+
17+
### 1. Advance Booking Limit
18+
19+
**Config key:** `booking.advanceBookingDays` (default: 365)
20+
21+
`slotStart` must not be further into the future than `now + advanceBookingDays`.
22+
23+
```
24+
slotStart > now + 14 days → 422 "slot is too far in the future: bookings may only be created up to 14 day(s) ahead"
25+
```
26+
27+
**Use case:** Prevent customers from reserving slots years in advance. Set to `14` for a two-week booking window.
28+
29+
---
30+
31+
### 2. Past-Slot Check
32+
33+
No config — always enforced.
34+
35+
`slotStart` must be in the future relative to the server's current UTC time.
36+
37+
```
38+
slotStart ≤ now → 422 "slot start must be in the future"
39+
```
40+
41+
---
42+
43+
### 3. Minimum Duration
44+
45+
**Config key:** `booking.slotDurationMinutes` (default: 30)
46+
47+
The slot length (`slotEnd − slotStart` in minutes) must be ≥ `slotDurationMinutes`.
48+
49+
```
50+
(slotEnd - slotStart) < 30 min → 422 "slot duration (20 min) is shorter than the minimum slot duration configured for this tenant (30 min)"
51+
```
52+
53+
**Use case:** Prevent zero-length or unrealistically short bookings.
54+
55+
---
56+
57+
### 4. Business Hours
58+
59+
**Config keys:** `business-hours` module (all fields)
60+
61+
This check only runs when:
62+
- The tenant has **explicitly saved** a `business-hours` config (`isDefault: false`), **and**
63+
- `allowBookingsOutsideHours: false`
64+
65+
If either condition is not met, business-hours enforcement is skipped entirely.
66+
67+
When active, the check validates:
68+
69+
1. The start day's `open` flag — if `false`: `"business is closed on <day>"`
70+
2. `slotStart ≥ openTime` on the start day — if violated: `"slot starts before opening time (HH:MM)"`
71+
3. `slotEnd ≤ closeTime` on the **end day** — if violated: `"slot ends after closing time (HH:MM)"`
72+
4. For same-day bookings, the slot must not overlap the configured break window
73+
74+
For multi-day bookings, the closing time check uses the *end day's* schedule (not the start day's), so a booking that genuinely spans overnight is evaluated correctly.
75+
76+
```
77+
slotStart on Saturday, open: false → 422 "business is closed on saturday"
78+
slotStart before 09:00 → 422 "slot starts before opening time (09:00)"
79+
slotEnd after 17:00 → 422 "slot ends after closing time (17:00)"
80+
overlaps 12:00–13:00 break → 422 "slot overlaps with the business break (12:00 – 60 min)"
81+
```
82+
83+
---
84+
85+
### 5. Daily Capacity
86+
87+
**Config key:** `booking.maxBookingsPerDay` (default: 100)
88+
89+
The count of non-cancelled, non-no-show bookings on the same UTC calendar day as `slotStart` must be less than `maxBookingsPerDay`.
90+
91+
```
92+
count ≥ 50 → 409 "daily booking limit reached (50/50) — no further bookings accepted on this date"
93+
```
94+
95+
**Use case:** Hard-cap how many bookings a tenant's operation can handle per day.
96+
97+
---
98+
99+
### 6. Buffer Gap
100+
101+
**Config key:** `booking.bufferMinutes` (default: 0, enforcement skipped when 0)
102+
103+
No existing booking for the same `serviceRef` may fall within ±`bufferMinutes` of the new slot.
104+
105+
The SQL check:
106+
107+
```sql
108+
slot_end > NEW.slotStart - (bufferMinutes * interval '1 minute')
109+
AND
110+
slot_start < NEW.slotEnd + (bufferMinutes * interval '1 minute')
111+
```
112+
113+
```
114+
existing booking bk_xyz overlaps the 15-min buffer → 409 "a 15-minute buffer is required between consecutive bookings for this service"
115+
```
116+
117+
**Use case:** Ensure cleanup or travel time between appointments for the same service.
118+
119+
---
120+
121+
### 7. Auto-Confirm
122+
123+
**Config key:** `booking.autoConfirm` (default: false)
124+
125+
Not a gate — this step sets the initial status.
126+
127+
- `autoConfirm: true` → booking is stored as `status: confirmed`
128+
- `autoConfirm: false` → booking is stored as `status: pending` (operator must confirm manually)
129+
130+
---
131+
132+
## Graceful Degradation
133+
134+
If the config-service is **unreachable** when a booking is created, the booking-service falls back to its in-process defaults:
135+
136+
| Setting | Fallback value |
137+
|---|---|
138+
| `slotDurationMinutes` | 30 |
139+
| `maxBookingsPerDay` | 1000 |
140+
| `advanceBookingDays` | 365 |
141+
| `autoConfirm` | false |
142+
| `bufferMinutes` | 0 |
143+
| Business hours | Not enforced |
144+
145+
A config-service outage will never prevent bookings from being created. The cache also means that even if the config-service goes down, the last known config remains in effect for up to 60 seconds.
146+
147+
---
148+
149+
## Config Propagation Timing
150+
151+
The booking-service caches each tenant's module config for **60 seconds** (configurable via `CONFIG_CACHE_TTL` environment variable). After you `PUT /v1/config/booking`, the new rules take effect within one cache TTL cycle.
152+
153+
To change the TTL:
154+
155+
```yaml
156+
# deploy/docker/docker-compose.dev.yml
157+
booking-service:
158+
environment:
159+
CONFIG_CACHE_TTL: "10" # seconds
160+
```
161+
162+
---
163+
164+
## Disabling Enforcement for Testing
165+
166+
The fastest way to disable all policy checks during development is to set permissive values:
167+
168+
```bash
169+
# Turn off all restrictions
170+
curl -X PUT http://localhost:8085/v1/config/booking \
171+
-H "Content-Type: application/json" \
172+
-H "X-Tenant-ID: 01HZ..." \
173+
-d '{
174+
"slotDurationMinutes": 1,
175+
"maxBookingsPerDay": 99999,
176+
"advanceBookingDays": 3650,
177+
"autoConfirm": true,
178+
"bufferMinutes": 0
179+
}'
180+
181+
# Disable business hours
182+
curl -X PUT http://localhost:8085/v1/config/business-hours \
183+
-H "Content-Type: application/json" \
184+
-H "X-Tenant-ID: 01HZ..." \
185+
-d '{"allowBookingsOutsideHours": true}'
186+
```

0 commit comments

Comments
 (0)