State machine
Lesson states
| State | Value | Description |
|---|---|---|
ACTIVE | 1 | Lesson is confirmed and scheduled |
RESCHEDULE | 2 | Reschedule has been proposed, awaiting response |
CANCELLED | 0 | Lesson is cancelled |
Booking states
Creating a lesson
When a booking is created, aLesson record is created with:
tutor_id— the tutorsubject_id,level_id,exam_board_id— what’s being taughtstart,finish— lesson timesteach_id— which teach record this relates tostate = ACTIVE (1)
boot() method auto-calculates duration in minutes from start/finish.
Students are linked via the lesson_user pivot table. Children via lesson_child.
Rescheduling
Endpoint:PUT /api/lessons/{id}/edit (uses web.api middleware)
Method: Lesson::reschedule($data)
Rules
Flow
Propose new time
The requester submits
suggested_start and suggested_finish. The lesson state changes to RESCHEDULE (2).Notify other party
LessonReschedule email is sent with two action buttons:- Accept — signed URL that approves the reschedule
- Decline — signed URL that cancels
Accept or decline
Accept:
Lesson::approveRescheduledLesson() — updates start/finish to the suggested times, clears suggested fields, sets state back to ACTIVE (1).Decline: Lesson moves to CANCELLED (0).Cancellation
Endpoint:PUT /api/bookings/{id}/cancel (uses web.api middleware)
Who can cancel
Defined inBookingPolicy::cancel():
- Internal users (admin)
- The user who made the booking
- The student associated with the lesson
- The parent of a child in the lesson
What happens
- Lesson state →
CANCELLED (0) StripeService::refund()processes the refund- Booking state →
REFUNDED (0)orPARTIAL_REFUNDED (4) LessonCancelledemail sent to the other party (BCC internal team)- Includes cancellation note if provided
Post-lesson flows
Lesson reminders
TheSendLessonReminderPushNotification job runs every 15 minutes and sends push notifications:
- 24 hours before lesson start
- 2 hours before lesson start
Summary notes
After a lesson completes:SendSummaryNoteNotificationjob (daily at 10:00) reminds tutors to add notes for yesterday’s lessons- Tutor adds notes via
NoteService::store()atPOST /api/v1/notes - Notes support file attachments (polymorphic via
fileablestable) - Student receives
LessonSummaryNoteemail with the note content - Student also gets a push notification
Review request
TheSendReviewTutorNotification job runs daily at 10:00 UTC:
- Finds lessons completed yesterday
- Determines the reviewer (student or parent)
- Avoids duplicate requests (one email per tutor-reviewer pair per day)
- Sends
ReviewTutoremail with a review submission link
Review submission
Reviews use a multi-criteria rating system: File:app/Models/TutorReview.php + app/Models/TutorRatingCriteria.php
- Each review has ratings across multiple criteria
- A comment is optional (max 300 chars)
TutorReviewService::getReviewSummary()returns aggregated ratings (cached until end of day)
Experience rating
Students can also rate their overall experience (1-5) directly on the lesson:Meeting management
For online lessons, a meeting is created or updated: File:app/Models/v1/Meeting.php
Meeting::createOrUpdateMeeting() — upsert logic that stores:
meeting_id— external meeting ID (Zoom or Daily.co)password— meeting passwordjoin_url— host join URLparticipant_join_url— student join URLlesson_id— linked lesson
LessonBooked mail class) with direct join links.
Calendar integration
When a lesson is booked, aCalendarEvent record is created:
CalendarService syncs events with the tutor’s Google Calendar if they have it connected. Calendar events are checked during availability calculations to prevent double-booking.