HandbookLearning45

Office hours & appointments.

Some conversations need a few uninterrupted minutes: a student who missed the thread of a proof, a question a teacher would rather answer live than in a chat. Office hours turn the teacher's open door into a schedule. A teacher publishes bookable slots; a student claims one — atomically, so two students never grab the last seat; a reminder fires; and if it's a YESS Live slot, one tap opens a private online room both sides join. This handbook walks that loop end to end, and is honest about where it stops.

  • 2core tables
  • 3booking RPCs
  • 4slot statuses
  • ≈9 minto read

Prologue

Three doors that share a name#

Before we open a single screen, a word about names — because YESS has three features that all use the phrase "office hours," and only one of them is this module. Read this once and you will never open the wrong screen.

This module — teacher office hours. A teacher publishes bookable one-on-one (or small-group) slots; a student books one. It lives at /dashboard/office-hours for the teacher and /portal/office-hours for the student, and is built on two tables — office_hours_slots and office_hours_bookings.

Parent-teacher conferences are a separate module with their own tables and their own booking engine — that is report-card night, documented in its own handbook. Student-government office hours at /portal/student-government/office-hours are a weekly drop-in availability grid for student officers — no booking, no slots, just "when and where you can find your reps." Neither shares a table with this module.

One teacher, one slot, one student, one atomic booking — the smallest honest unit of a teacher's time.

Chapter one

The loop, end to end#

Follow one slot through its whole life and the rest of the book is detail.

Tuesday, 16:00. A maths teacher at Greenwood opens /dashboard/office-hours, fills the composer — Thursday 15:00–15:20, capacity 1, topic "Quadratics catch-up," host on YESS Live — and clicks Publish. A slot row is written in status open. The moment it lands, every student the teacher teaches gets a notification: "New office-hours slot — tap to book," deep-linked to their portal.

16:04. A student opens /portal/office-hours, sees the slot under "Open this week," types her own question in the topic box, and books. The booking is written through a database function that locks the slot first — so even if a classmate taps at the same second, only one of them gets the seat. Capacity was 1, so the slot flips to full. The teacher gets a notification: "New booking — Quadratics catch-up."

Thursday, 14:30. If the school has enabled the reminder job, both teacher and student get a thirty-minute nudge.

Thursday, 14:58. The teacher clicks Start live session. Because this is a YESS Live slot and it is inside the time window, YESS creates a private live-session room, stamps it onto the booking, and sends the student an urgent "Office hours starting — tap to join." The student joins at /portal/live-classes; the teacher lands in the same room via /dashboard/virtual-classes. Twenty minutes later the quadratics make sense.

Chapter two

Publishing a slot#

The teacher's surface is /dashboard/office-hours (the same page is re-exported at /teacher/office-hours so it renders inside teacher chrome). It resolves the teacher's own staff record, lists their upcoming and recent slots, and carries a KPI strip — upcoming, open, bookings, full. The composer is the heart of it.

Designed product mock — the teacher publishes a slot: start and end, capacity, topic, and a YESS Live switch, above a list of upcoming slots with their booking counts.

What a slot actually carries

  1. 1

    Start and end

    Two timestamps. The database enforces that the end is after the start, so a slot can never be zero-length or reversed. A past-dated slot can be created but cannot be booked — the booking function rejects any slot whose start is already behind now.

  2. 2

    Capacity

    Defaults to 1 — a true one-on-one — but any positive number up to 50 is allowed, so a teacher can run a small revision huddle. When bookings reach capacity the slot auto-flips to full; a cancellation drops it back to open.

  3. 3

    Topic and description

    Both optional. The topic is the teacher's headline for the slot; the description adds detail. The student later attaches their own topic to the booking, so the teacher sees exactly what each attendee wants before the session.

  4. 4

    Host on YESS Live

    A switch. On (the default) means the slot is backed by a private LiveKit room the teacher opens at session time; off means it's an in-person slot and the live controls never appear. This one flag decides whether chapter four applies.

  5. 5

    Status

    One of open, full, cancelled, or completed. Open and full are set automatically as bookings come and go; cancelled is a deliberate teacher action; completed is set by the auto-complete job after the slot's end time (when that job is enabled).

Chapter three

Booking a slot, without a collision#

The student's surface is /portal/office-hours. It shows three bands: "Open this week" (open, future slots the student hasn't already booked), "My upcoming bookings," and a short history. Booking takes one tap plus an optional topic — but underneath, it is the most carefully engineered action in the module.

A booking is never a plain insert. It runs through a database function that locks the slot row first, then checks — in that locked window — that the slot still exists, is still open, isn't in the past, and has a free seat. Only then does it write the booking and, if the slot has just filled, flip it to full. Two students tapping the last seat in the same instant cannot both win: one gets the booking, the other gets a clean "slot full" message.

Each student can hold at most one booking per slot — a unique constraint on the pair guarantees it, and re-booking a slot the student previously cancelled simply reuses the same row. The student may cancel at any time; cancelling reopens the slot (full → open) so the seat is immediately available to someone else. A teacher can also cancel a whole slot, which auto-cancels every booking on it and notifies each affected student.

Chapter four

Opening the private room#

A YESS Live slot has one more move. Near session time, the teacher's slot row grows a Start live session button — but only when two things are true: the slot was published with "Host on YESS Live" on, and the clock is inside the window (from ten minutes before the start to fifteen minutes after the end). Outside that window the button reports "too early" or "the slot window has passed" rather than opening an empty room.

Clicking it runs a database function that creates a private live-session room, marks it not-recorded (office hours are private by design), and stamps the new session id onto every booking on the slot. It is idempotent — click it twice and you re-enter the same room, you don't create a second. The same call sends every booked student an urgent "Office hours starting — tap to join" notification deep-linked to /portal/live-classes, while the teacher is redirected into the room at /dashboard/virtual-classes.

From there, the session is an ordinary YESS Live room — the same LiveKit surface documented in the Live & virtual classes handbook, with the same join tokens. The office-hours booking itself does not record attendance; it hands off to the live-classes room and that is where the two people actually meet. In-person slots skip this chapter entirely.

Chapter five

Who gets told, and when#

Office hours only work if the right person is nudged at the right moment. The module fires notification fan-outs automatically, plus an optional reminder.

On publish — every student the teacher teaches is told a new slot is open, deep-linked to their portal. On booking — the teacher is told who booked and what topic they attached. On slot cancellation — every currently-booked student is told the slot is off, and their bookings are auto-cancelled in the same step. And on session start, as chapter four described, booked students get the urgent "tap to join" ping.

A further signal — the thirty-minute reminder to both sides, plus the auto-complete that closes a slot after its end time — runs on a scheduled job that is opt-in and off by default. On a stock install no reminders fire and slots are not auto-completed; a school turns the job on when it wants those behaviours. The reminder is idempotent — it stamps a "reminder sent" marker so a slot is never nudged twice.

Chapter six

Who can see a booking#

A booking is a small, private thing, and the row-level rules treat it that way. Slots are readable by anyone in the school — a slot is public availability. Bookings are not: a booking is visible only to the student who made it, the teacher who owns the slot, a linked active parent of that student, and an administrator with the right oversight permission. A classmate browsing open slots never sees who else has booked.

All of these surfaces sit under the LMS permission set — the same permission that opens courses and assignments gates the office-hours screens, and every write is stamped into the audit trail under the LMS module. There is no separate "office hours" role to grant.

Chapter seven

What makes office hours elite#

Five things done right

  1. 1

    Booking that cannot double-sell a seat

    The booking function locks the slot row before it counts seats, so two simultaneous bookings on the last place resolve cleanly to one winner and one 'slot full' — no overbooking, no race, no lost booking. This is the single hardest thing about a booking system, and it's handled at the database, not hopefully in the client.

  2. 2

    Bookings are private by row

    Slots are public availability; a booking is visible only to the booking student, the slot's teacher, a linked parent, and an oversight admin. Privacy isn't a UI choice a crafted request can bypass — it's enforced in the row-level policy itself.

  3. 3

    One switch from calendar to classroom

    A single 'Host on YESS Live' flag turns a slot into a private, non-recorded LiveKit room that both sides join from their own portal with one tap, deep-linked from the notification. No separate meeting link to paste, no third-party invite.

  4. 4

    Nobody picks a recipient list

    Publishing a slot notifies exactly the students that teacher teaches — the audience is derived from the teacher's section assignments. Booking notifies the teacher. Cancelling notifies the affected students. Every fan-out is automatic and correctly scoped.

  5. 5

    Idempotent by design

    Start the live session twice and you re-enter the same room. Re-book a cancelled slot and you reuse the same booking row. Run the reminder job twice and no one is nudged twice. Repeat actions are safe everywhere it matters.

Planned features

What comes next#

The module is small and sharp — it does the hard part (atomic booking) well, and leaves some softer edges for later. These are the honest gaps, listed so you can plan around them.

Four edges still open

  1. 1

    Attendance & no-show tracking

    The booking record already has room for 'completed' and 'no-show' states, but nothing sets them yet — accurate no-show detection needs a live-attendance signal from the room, which is the next piece to wire. Until then, a booking only ever reads as booked or cancelled.

  2. 2

    Reminders on by default

    The thirty-minute reminder and the after-the-fact auto-complete are real, but gated behind an opt-in scheduled job that ships off. The plan is to make sensible reminder defaults part of a school's setup rather than a hidden toggle.

  3. 3

    A parent-initiated booking flow

    A linked parent can already see their child's bookings, but the booking screen resolves a student profile — booking is student-initiated. A dedicated parent booking surface (for the younger years where the parent drives) is planned.

  4. 4

    Teacher self-overlap guard

    Slot creation is a direct write with no check that a new slot overlaps one the teacher already published. Adding an overlap warning at publish time will keep a teacher from double-booking their own afternoon.

Adjacent modules

Where office hours connect#

Tutorial

Do it step by step#

Open your door for an afternoon and run a booked, live one-on-one — five steps, teacher then student.

  1. 1

    Publish the slot

    Open /dashboard/office-hours, set a start and end, a capacity (leave it at 1 for a true one-on-one), a topic, and leave Host on YESS Live on if you want an online room. Click Publish — the slot goes live as open and your students are notified automatically.

    Capacity can be up to 50 — use a higher number to run a small revision huddle instead of a one-on-one.

  2. 2

    Let the student book

    Your student opens /portal/office-hours, finds the slot under "Open this week," types the question they want to bring, and books. The slot flips to full at capacity and you get a "new booking" notification with their topic.

    Two students racing for the last seat can't both win — the booking is locked at the database, so one gets it and the other sees a clean 'slot full'.

  3. 3

    Let the reminder do the chasing

    If your school has enabled the reminder job, both of you get a thirty-minute nudge before the slot. Nothing to do here — it's automatic and never fires twice.
  4. 4

    Open the room

    A few minutes before the start, the slot grows a Start live session button. Click it — YESS opens a private room, tells your student to join at /portal/live-classes, and drops you into the same room at /dashboard/virtual-classes.

    The button only appears inside the time window (ten minutes before to fifteen after). Click it twice and you re-enter the same room, never a second one.

  5. 5

    Wrap up

    Leave the room when you're done. In-person slots skip the room entirely — you just meet. Either way the student can cancel a booking they can't make, which reopens the seat for someone else.

A door that was 'come find me sometime' is now a slot on a schedule — booked, reminded, and one tap from a private room.