> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dmly.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Staff and availability

> Add staff, set their working hours and services, and understand exactly how DMLY works out which slots a client can book.

A staff member is a bookable person: the stylist, the therapist, the dentist. Clients book
*their* time, so the slots on your booking page are worked out per staff member — from their
own working hours, in their own timezone, minus everything already in their way.

Most availability problems come from one of two places: hours that were never set, or a rule
set somewhere else that quietly overrides the one you are looking at. Both are covered below.

## Add a staff member

Go to **Business → Appointments → Staff** — *Manage staff members, their hours and the
services they offer.* An empty workspace shows **No staff yet. Add one to get started.**

<Steps>
  <Step title="Create the staff member">
    Select **New staff member** and give them a name. **Email** and **Phone** are both required
    — the form only marks **Phone** with a `*`, but saving without an email is rejected too.
    **Timezone** is required as well and comes pre-filled; check it before you save, because it
    decides what their working hours actually mean. A **Job title** is optional.
  </Step>

  <Step title="Link a team account (optional)">
    **Link team member** connects this staff member to a DMLY login — *Link this staff member
    to a team account so they can manage their own bookings.* Leave it empty for someone who
    does not log in to DMLY at all.
  </Step>

  <Step title="Let them take bookings">
    Turn on **Accepts bookings** *and* **Active (available for booking)**. These are two separate
    switches, and DMLY only offers a staff member a slot when **both** are on.
  </Step>

  <Step title="Set their working hours">
    Fill in **Working hours** — the days and times they normally work. This is the foundation
    everything else subtracts from.
  </Step>

  <Step title="Save">
    Select **Save staff member**.
  </Step>
</Steps>

<Note>
  A staff member does **not** need a DMLY login. Leaving **Link team member** empty is normal
  for a contractor or a room-based resource. Linking only matters when that person will sign
  in and work their own bookings themselves.
</Note>

**Edit staff member** and **Delete staff member** are on each row. Deleting asks
`Delete <name>? This can't be undone.`, but that warning overstates it: if the staff member has
any bookings, DMLY does **not** delete them. It turns **Active (available for booking)** off
instead and tells you *A staff member with bookings was deactivated instead of deleted.* Their
history is protected automatically. Only a staff member with zero bookings is really removed —
their availability, their service assignments and the row itself all go.

<Warning>
  That auto-deactivation is a common source of missing slots. A staff member you tried to delete
  is now inactive while **Accepts bookings** is still on, so the row looks fine but they are
  never offered a slot. Turn **Active (available for booking)** back on to restore them.
</Warning>

## Working hours are in the staff member's timezone

Each staff member carries their own timezone, and their **Working hours** are wall-clock times
*in that timezone*. Nine in the morning for a staff member in Lagos is nine in the morning in
Lagos, whatever timezone you or the client are in. DMLY converts the resulting slots for
whoever is looking.

This is the single most common surprise on a multi-location team: the hours are right, the
timezone on the person is wrong, and every slot lands hours off.

<Warning>
  A staff member with **no** working hours of their own is not treated as unavailable. DMLY
  falls back to the service's own **Weekly availability** and its timezone instead. So a new
  staff member you never gave hours to can start appearing for bookings across the service's
  whole window. Set hours on every staff member you add.
</Warning>

What clients see on the public booking page is a separate setting: **Fixed timezone** pins the
page to one timezone for everyone, and without it the page renders in the contact's own
timezone. See [Booking page](/appointments/booking-page).

## Which services a staff member offers

Each service lists its **Assigned staff**; a service with none shows **No staff assigned yet**.
Assignment is what connects the two — a staff member is only ever offered for a service they
are assigned to.

On the booking page, a service with several assigned staff lets the client choose from a **With**
dropdown. Alongside the named staff it offers **Anyone available**, which doesn't pin the booking
to one person: its slots are the union of every eligible staff member's slots, so a time shows up
if *at least one* of them is free.

That union is why **Anyone available** almost always shows more availability than any individual,
and why turning **Accepts bookings** off for one person often changes nothing visible.

To remove the choice entirely, turn on **Hide staff selection** — *Clients won't choose a staff
member; one is assigned automatically.* This one lives on your workspace settings under
**Business → Appointments → Settings**, not on the individual service, so it applies to every
service at once.

{/* TODO(verify): staff weekly hours have a nullable service_id, i.e. hours that apply to one service only. No UI label confirmed for setting per-service hours. Omitted. */}

## How availability is actually computed

This is the part worth reading. For a given staff member and service, DMLY starts with their
weekly **Working hours** expanded into candidate start times, then removes:

<Steps>
  <Step title="Times that break the notice and horizon rules">
    Anything too soon to book, or too far out. See the next section — these rules come from two
    places at once.
  </Step>

  <Step title="Whatever the connected calendar says they are busy with">
    If a calendar is connected, its busy time is subtracted directly. External events DMLY does
    not own also become blocks automatically. See [Calendar sync](/appointments/calendar-sync).
  </Step>

  <Step title="Their existing bookings, plus the service's buffers">
    Any booking that is still live — confirmed, pending, or holding a slot while it waits for
    payment — takes the time out, and so does the buffer before and after it. Cancelled,
    completed, no-show, failed and expired bookings free the slot back up.
  </Step>

  <Step title="Blocks and time off">
    Both the staff member's own, and any workspace-wide block that applies to everybody.
  </Step>

  <Step title="Classes they are hosting">
    Every scheduled class session with that staff member as its host comes out too. Class seats
    are booked against the session rather than the host, so this is the only step that catches
    them. See [Classes](/appointments/classes).
  </Step>
</Steps>

Whatever survives is a bookable slot. For **Anyone available**, DMLY runs this per staff member
and merges the results.

<Note>
  A slot held for a pay-before booking is genuinely taken while the hold lasts — it is not
  bookable by anyone else until the hold clears or expires. That is deliberate. See
  [Payments](/appointments/payments).
</Note>

## Minimum notice and booking horizon come from two places

Notice and horizon are set in two places, under two different names — and, for notice, in two
different **units**. DMLY combines them rather than letting one win.

On your workspace settings, under **Business → Appointments → Settings**:

* **Minimum notice (hours)** — *Least amount of notice required before a booking can start.*
* **Booking horizon (days)** — *How far in advance clients can book. Leave blank for no limit.*

On the individual service, under **Offerings → Services**:

* **Min notice (min)** — the same rule in **minutes**, not hours.
* **Days ahead** — the same horizon. It cannot be left blank; the minimum is 1.

<Warning>
  The service field is **Min notice (min)** — minutes. Typing `2` there buys you two minutes of
  notice, not two hours. Two hours is `120`. Only the workspace field is in hours.
</Warning>

| Rule            | How the two combine                                             | Result                                                                |
| --------------- | --------------------------------------------------------------- | --------------------------------------------------------------------- |
| Minimum notice  | The **longer** of the two applies                               | A workspace floor can only ever make a service stricter, never looser |
| Booking horizon | The **shorter** of the two applies, when the workspace sets one | A workspace ceiling caps every service                                |

So if a service allows booking two hours ahead but your workspace requires 24, clients get 24.
Set no workspace values and each service simply uses its own.

<Tip>
  If one service ignores the notice you set on it, check the workspace setting before you touch
  the service again. The stricter number always wins, and it is easy to forget it is there.
</Tip>

## Block time and time off

Blocks are one-off holes in availability, made from the calendar view
(**Business → Appointments → Calendar** — *View and manage all bookings, classes and blocked
time in one place*).

Select **Block time** to create one. **All day** covers a whole day; the **Blocks** view lists
what exists, and removing one confirms with **Block removed**. A block can belong to one staff
member, or apply across the workspace — the workspace-wide kind is how you handle a public
holiday or a closure without editing everybody's hours.

Blocks subtract from availability on the public booking page immediately. They do not touch
bookings that already exist — blocking a morning someone is already booked into does not cancel
that booking.

## Manual bookings ignore availability on purpose

Booking someone in yourself from the **Calendar** does **not** check your published
availability. That is intentional — an agent may squeeze a client in outside normal hours,
outside the notice window, or on a blocked day.

The one thing a manual booking still refuses is a genuine clash: it will not overlap the same
staff member's existing live booking.

So "the booking page won't offer this, but I can" is expected behaviour, not a bug. It also
means your calendar can contain appointments no client could ever have made themselves.

## Two people booking the same slot

They cannot. DMLY locks the staff member's row while a booking is written, re-checks the slot
inside that lock, and backs it with a database constraint as a last line of defence. The loser
of a race is told rather than double-booked:

* On the public booking page: **Sorry, that time was just taken — please choose another.**
* Inside DMLY: **That time slot is no longer available**

Both mean the same thing — pick another time. Nothing was booked.

<Accordion title="A slot I expect isn't showing on the booking page">
  Work down the list in order — the first one that fails is nearly always the cause.

  1. **Accepts bookings** is off for that staff member.
  2. **Active (available for booking)** is off — a separate switch, and easy to miss. Both it and
     **Accepts bookings** must be on. Remember a failed delete turns this one off for you.
  3. They are not in the service's **Assigned staff**, or the service shows **No staff assigned yet**.
  4. Their **Working hours** don't actually cover that time — check their timezone before the hours.
  5. Minimum notice rules it out — from the service's **Min notice (min)** *or* the workspace's
     **Minimum notice (hours)**, whichever is stricter. Check the units before you conclude the
     number is wrong.
  6. The booking horizon rules it out — the service's **Days ahead** or the workspace's
     **Booking horizon (days)**, whichever is shorter.
  7. A block, time off, or a workspace-wide closure covers it.
  8. They are hosting a class then. See [Classes](/appointments/classes).
  9. A connected calendar says they are busy — including an event you created outside DMLY.
  10. An existing booking, or its buffer, overlaps it.
</Accordion>

<Accordion title="A staff member is showing slots I never gave them">
  They almost certainly have no **Working hours** of their own, so they inherited the service's
  **Weekly availability**. Set their hours and the fallback stops applying.
</Accordion>

## Next

<Columns cols={2}>
  <Card title="Services" icon="tags" href="/appointments/services">
    Duration, buffers, notice, horizon and price live on the service — in **Offerings**.
  </Card>

  <Card title="Booking page" icon="globe" href="/appointments/booking-page">
    What clients see, the timezone they see it in, and the fields they fill in.
  </Card>

  <Card title="Calendar sync" icon="calendar-check" href="/appointments/calendar-sync">
    Connect a calendar so outside commitments block your DMLY slots.
  </Card>

  <Card title="Classes" icon="users" href="/appointments/classes">
    Group sessions with seats and a waitlist, rather than one-to-one slots.
  </Card>
</Columns>
