Build an online booking system for a small business
Customers pick a free time slot, book it and get an email confirmation; the owner sees and cancels bookings in a simple admin page.
1 Friday evening: rules before code
Booking apps fail on the rules, not the code. Write them down for one real business (a barber, a tutor, a repair shop):
- Opening hours per weekday (e.g. Mon–Fri 09:00–17:00, Sat 10:00–14:00).
- Slot length (30 min) and buffer between bookings (0–10 min).
- How far ahead customers may book (e.g. 30 days) and the minimum notice (e.g. 2 hours).
- What the customer must give: name, email, phone, a note.
Done when: a friend can read your rules and tell you whether "Saturday 13:45" can be booked.
2 Saturday morning: data model and slots
python -m venv .venv && source .venv/bin/activate
pip install flask flask-sqlalchemy python-dotenv
# models.py
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Booking(db.Model):
id = db.Column(db.Integer, primary_key=True)
starts_at = db.Column(db.DateTime, nullable=False, unique=True) # one booking per slot
name = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(120), nullable=False)
note = db.Column(db.String(500))
cancelled = db.Column(db.Boolean, default=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
Generate the free slots for a day from the rules, then remove the booked ones:
# slots.py
from datetime import datetime, timedelta, time
HOURS = {0: (9, 17), 1: (9, 17), 2: (9, 17), 3: (9, 17), 4: (9, 17), 5: (10, 14)} # Mon=0
SLOT = timedelta(minutes=30)
def free_slots(day, booked, now):
if day.weekday() not in HOURS:
return []
open_h, close_h = HOURS[day.weekday()]
t, end = datetime.combine(day, time(open_h)), datetime.combine(day, time(close_h))
out = []
while t + SLOT <= end:
if t not in booked and t >= now + timedelta(hours=2):
out.append(t)
t += SLOT
return out
Done when: free_slots returns the right list for a weekday, a Saturday, a Sunday and "today after 15:00" in a quick test.
3 Saturday afternoon: the booking page
GET /book?day=2026-11-03shows the free slots as buttons.POST /bookre-checks the slot is still free inside the request (two people can click the same slot), then inserts. Theunique=Trueonstarts_atis the final guard: catchIntegrityErrorand show "Sorry, that slot was just taken".- Validate the email, cap the note length, add CSRF protection (Flask-WTF) and a rate limit (Flask-Limiter, e.g. 10 bookings/hour per IP).
Done when: two browser windows trying to book the same slot end with exactly one booking.
4 Sunday morning: confirmations and cancelling
Send a confirmation email with Resend and a cancel link that carries a signed token, not the booking id:
from itsdangerous import URLSafeTimedSerializer
s = URLSafeTimedSerializer(app.config["SECRET_KEY"], salt="cancel")
token = s.dumps(booking.id) # in the email: /cancel/<token>
booking_id = s.loads(token, max_age=60 * 60 * 24 * 30) # in the route
Add an owner page (/admin, behind a password from an environment variable) listing upcoming bookings with a Cancel button (POST form).
Done when: the customer gets the email, the cancel link frees the slot, and a tampered token is rejected.
5 Sunday afternoon: deploy
- Move to PostgreSQL on Render (
DATABASE_URL), keep secrets in environment variables. - Store times in UTC and show them in the business's time zone (
zoneinfo.ZoneInfo("Europe/London")). - Add the booking link to the business's Google profile and website.
Done when: a real customer books from their phone and both of you get the email.
Approfondir avec ces parcours
Plus de guides
- schedule_sendAutomate a daily report with Python, cron and emailA script that pulls data every morning, builds a short summary with a chart, and emails it to you, running unattended on a small Linux server.
- account_balance_walletBuild an offline budget tracker app (PWA)An installable app that records income and expenses, works offline, shows a monthly chart and exports to CSV, with no server and no account.
- monitor_heartBuild an uptime monitor that alerts youA small service that checks your websites every minute, records response times, and emails you when a site goes down and when it comes back.