How a Preply-like tutoring marketplace might evolve
A two-sided marketplace where students find tutors, book lessons across time zones, meet over video and pay, while tutors get paid out. How search, scheduling, video and money shape the architecture from one Django app to a multi-region platform.
The user problem and the hard parts
A student wants the right tutor, at a time that works, for a price they accept, and a tutor wants a full calendar and reliable pay. The product is a matchmaker plus a scheduler plus a classroom plus a bank. Each of those is a different engineering problem:
- Tutor search and ranking: thousands of tutors per language, filtered by price, availability, specialty and country, then ranked by how likely this student is to book and stay. Ranking is the business: bad ranking means students churn and new tutors never get a first lesson.
- Scheduling across time zones: a tutor in Manila and a student in Toronto see the same slot as different local times. Daylight-saving changes move slots. Two students must never book the same slot.
- Lesson video: a 50-minute real-time call with low , on bad home networks, with a whiteboard and chat.
- Payments and payouts: students prepay in many currencies; tutors are paid out weekly in other currencies, minus commission. Refunds and disputes happen after lessons.
- Trust: fake reviews, off-platform payments, inappropriate behaviour with minors, chargebacks.
How the architecture might evolve
A plausible architecture for a tutoring marketplace at each scale. It is not a description of Preply's actual internal systems.
- 1
Stage 1 · Product-market fit
500 tutors · 200 lessons/dayNext.js frontendDjango monolith (REST API + admin)PostgreSQLPayment provider (cards, tokenised)Third-party video linksOne database gives transactions for bookings and credits for free. Django admin doubles as the ops tool. Video is outsourced: the team must learn what students want, not run media servers.
- 2
Stage 2 · Growth
10k tutors · 10k lessons/dayCDN for assets and tutor intro videosRedis cache for tutor cards and sessionsBackground workers (reminders, emails, payouts)Object storage for videos and documentsRead replica for reportingSearch pages and tutor profiles are read-heavy, so they move to a . Reminders, payout batches and video transcoding are slow and retryable: they leave the request path for workers.
- 3
Stage 3 · Marketplace at scale
50k tutors · 150k lessons/daySearch engine with ranking featuresMessage queue / event bus (BookingCreated, LessonCompleted)Managed real-time video infrastructure (WebRTC SFU)Analytics warehouse + experimentationFraud and trust scoring serviceSQL filters can no longer rank 50k tutors with dozens of signals in tens of milliseconds. Events let ranking, analytics, fraud and notifications consume bookings without coupling to the booking code.
- 4
Stage 4 · Platform
Global · millions of lessons/monthSeparate services: search, scheduling, payments/ledger, classroomEvent streaming (Kafka) with outboxData platform (lake + feature store for ranking ML)Multi-region read paths, single-writer booking per regionPayout ledger with double-entry accountingTeams own and deploy independently. Money moves to a dedicated ledger because auditors and payout partners need an immutable history, not a mutable
balancecolumn.
Search, book, meet, pay
A plausible architecture for Stage 3 might look like this. Click the nodes, then walk through a student's journey.
Click any component to see what it does.
Deep dive: time zones and money
Time zones. Store tutor availability rules in the tutor's own zone ("Mondays 18:00–21:00 Europe/Madrid") and expand them into concrete UTC slots for the next few weeks. Store bookings only as UTC instants. If you store rules in UTC, a daylight-saving change silently shifts every tutor's working hours by one hour.
Money. A student buys 10 lessons. That is not one number in a balance column; it is a sequence of entries: purchase +10, lesson -1, refund +1. A ledger of immutable entries can be audited, replayed and reconciled with the payment provider's reports. Tutor payouts are computed from LessonCompleted minus refunds, batched weekly, and sent with idempotent payout requests.
| Data | Consistency need | Where it lives |
|---|---|---|
| Slot bookings | Strong: no double booking | Primary database, unique constraint |
| Credits and ledger | Strong and auditable | Primary database, append-only entries |
| Search index | Eventual (seconds) | Search engine, fed by events |
| Reviews and ratings | Eventual | Database + cache, recomputed async |
| Analytics | Eventual (minutes to hours) | Warehouse |
Engineering trade-offs
Search directly in PostgreSQL
- One system, always fresh
- Simple to build and debug
- Ranking with many signals becomes slow
- Search load competes with bookings
Dedicated search engine fed by events
- Fast faceted filtering and relevance ranking
- Isolates read load from the booking database
- Index lags the source of truth
- Another system to operate and reindex
Build your own video stack
- Control over quality, cost at very high volume
- Custom classroom features
- Media servers, TURN relays, codecs and global points of presence to run
- Hard to hire for
Managed video vendor
- Weeks to ship instead of quarters
- Global infrastructure included
- Per-minute cost
- Vendor lock-in on SDKs
Practical exercise
The daylight-saving bug
A tutor in Madrid sets availability "Mondays 18:00–21:00". You stored it as "Mondays 17:00–20:00 UTC". On the last Sunday of March, Spain moves clocks forward. What do students and the tutor see, and how should the data model change?