# Recurring shift patterns

A shift pattern is standing cover at one site — a start and end time, the days it runs, and how many people it needs. Patterns are built one site at a time in the pattern builder; the catalogue under Scheduling is read-only. A pattern does not create shifts by itself. It draws empty seats on the roster that somebody still has to fill.

## Where are patterns created?

Inside a site, always.

The header has **Scheduling → Patterns**, and it is tempting to start there, but `/patterns` is a **Pattern catalog** — a read-only list of every pattern across your sites, with **Preview** and **Copy to site…** as its only row actions. There is no "new pattern" button on it.

Creating and editing happens in the **Shift Pattern Builder**, at `/sites/{id}/shift-patterns`. Four things lead there:

- **Sites → Configure → Shift Patterns** in the header of the site's screen;
- the **Add** button on the **Shift Patterns** card on the site's Overview tab;
- **Add Shift Pattern** in that card's empty state;
- the coverage step of the create-site wizard, which writes patterns for you.

## What do you need first?

The permission `shifts.edit.pattern_days`, which **Admin** and **Manager** hold and **Control** does not. Control can see patterns but not change them.

You also need an active subscription, and headroom in your plan's pattern quota — both are checked when patterns are saved, and neither is checked when the site itself is created.

Before you start, know what the numbers mean. **Staff** is how many people the pattern needs *per day it runs*, and each of those is a seat on the roster. A pattern of 2 staff running 7 days draws 14 seats a week. **Active Days** is Monday through Sunday; the presets are **All**, **M-F**, **S-S** and **Clear**.

## How do you add one?

1. Open the site's pattern builder. The heading reads **Shift Pattern Builder** with the site name beneath it.
2. In the **New Pattern** panel, fill **Pattern Name**.
3. Set **Start** and **End**. An end earlier than the start is an overnight shift and is allowed — you get the amber note *Overnight shift — ends next day*, which does not block saving.
4. Choose **Role / Grade**. The list is your organisation's grades if you have set any up under **Settings → Workforce**, and a built-in list of common security roles if you have not.
5. Set **Staff**, which must be at least 1.
6. Pick the days under **Active Days**.
7. Optionally open **Advanced options** for **Priority**, **Required Skills**, **Notes**, **Automatic book off** and **Bounded coverage window**.
8. Press **Add Pattern**.

The pattern saves immediately — the builder writes on every add and every update, so **Save All** in the header is a re-save that then returns you to the site's configuration screen rather than the moment your work is committed.

![The Shift Pattern Builder for a site, headed with its name and a strip reading 2 patterns · 3 staff required · 100% 24h coverage. On the left, an empty New Pattern form: Pattern Name, Start and End (all three showing their own required warnings), Role / Grade on Select role / grade, Staff at 1, Active Days with Mon–Fri lit and All / M-F / S-S / Clear presets, a collapsed Advanced options row, an Add Pattern button and an empty Preview (next 28 days) panel. Below it, Quick Templates for 84, 108 and 168 hours a week. On the right, a 24-hour coverage strip laying Gatehouse Day (2) across 07 to 19 and Gatehouse Night (1) from 19, with its wrapped remainder drawn as (cont.) from midnight; then Current Patterns, holding Gatehouse Day 07:00 – 19:00, 2x Security Guard and Gatehouse Night 19:00 – 07:00, 1x Security Guard, both badged high, both running all seven days, each with its own 28-day projection.](/docs/img/shift-pattern-builder.png)

**Preview (next 28 days)** beside the form projects what you have typed: shifts, hours and people over four weeks. It is arithmetic on the numbers in the form, not a promise that rows exist.

## What do the advanced fields do?

| Field | Effect |
|---|---|
| Priority | **Low**, **Normal** or **High**. Colours the badge on the pattern card and the bar on the 24-hour coverage strip. Nothing in scheduling reads it. |
| Required Skills | Recorded against the pattern and shown in the catalogue. Advisory — no assignment is refused for missing a skill. |
| Notes | Free text. Deliberately excluded from version forking, so a notes-only edit updates the pattern in place rather than creating a new version. |
| Automatic book off | *Auto book off a booked-on officer at the scheduled end time once the shift end passes, and mark the shift completed.* Off by default. |
| Bounded coverage window | Adds **Start date** and **End date**. The pattern draws no seats outside them. This is the only way to stop a pattern without deleting it. |

There is no **Active** toggle for a shift pattern, and nothing in the application writes one — a pattern you finish with is either retired by removing it from its site's builder, or deleted outright. **Include inactive** on the catalogue widens the list to include any paused pattern rather than replacing it, so ticking it always shows at least what was already there. A row that only appears when it is ticked is badged **Paused**.

## How does a pattern become a shift?

It does not, on its own. Nothing generates rows.

A pattern is expanded on read, every time a roster is loaded: for each date in the range being viewed, if the weekday is in **Active Days** and the date is inside the coverage window, the pattern offers **Staff** seats. Seats already covered by a real shift row are subtracted, so a filled seat stops being offered.

Rows are written only when a person acts on a cell:

| Action | What it writes |
|---|---|
| Picking a name in the roster cell's popover | A shift assigned to that person |
| **Create Open Shift** in the same popover | An unassigned shift, marked available for application |
| **Save Changes** on the month grid | Assigned shifts for every cell you filled |

That is why the roster shows next month even though nothing has been generated — and why copying a week forward, rather than waiting for a generator, is how you get ahead.

Because there is no lookahead, a pattern edited today changes what every future roster view offers, including weeks you have already looked at. Shifts already written are untouched.

## What about overnight patterns?

They work, and the shipped 24/7 template uses one. A 19:00–07:00 block is treated as 12 hours, the coverage strip splits it into two segments with the second labelled `(cont.)`, and the resulting shift is stored against its **start** date with no end-date column — the next day is implied by the end time being earlier than the start.

One caution: the builder's overlap badge compares times as plain numbers with no wrap at midnight, so it will not flag a genuine clash between an overnight pattern and a day pattern. Do not rely on it for night cover.

## How do you remove one?

Two controls, two different outcomes.

**The bin icon on a pattern card** opens **Delete pattern "{name}"?**, which counts the shifts already written from it, splits them into *future scheduled*, *in progress*, *completed* and *cancelled*, and asks what to do with the non-completed ones:

- **Leave them orphaned** — they stay on the roster with no pattern. This is the default.
- **Reassign to another pattern** — pick a replacement on the same site.
- **Delete them too** — removes those shifts and their assignments.

Completed and cancelled shifts are preserved whichever you choose, so pay history and audit trails survive. The pattern row itself is deleted.

**Removing a pattern and pressing Save All** does something else: the server retires it by stamping an end date on it rather than deleting it, so existing shifts keep their link and the history stays intact.

## If it goes wrong

**Add Pattern does nothing at all — no error, no toast.** You left **Role / Grade** empty. It carries a required asterisk but is not covered by the validation that enables the button, and the save then bails out silently. Pick a role.

**"Access denied. You do not have permission to manage shift patterns."** Your role is Control, or a permission override has removed `shifts.edit.pattern_days`.

**The copy did not appear on the target site.** Check you picked the right site — the copy is added to whatever the dialog names, alongside that site's existing patterns rather than replacing them. It arrives as a new pattern with its own dates cleared, so it will not carry the original's date range.

**A coverage end date is refused.** The server rejects a **Bounded coverage window** whose end is before its start, and one whose end is earlier than today.

**Reassigning a day refuses with a locked-arbitration message.** Saving a single day from the site schedule replaces every shift on that date for that site, and it will not do so if any of them have arbitration locked because they have already been exported to payroll or an invoice. Unlock via arbitration force-edit first.

**You want to pause a pattern for a fortnight.** There is no way to. Set a **Bounded coverage window** end date, or delete the pattern and rebuild it — those are the only two options.

## Related

- [Patterns, seats and ad-hoc shifts](/docs/concepts/patterns-seats-and-ad-hoc-shifts)
- [Create your first site](/docs/organisation/create-your-first-site)
- [Broadcast open shifts](/docs/organisation/broadcast-open-shifts)
- [Four ways to fill an open shift](/docs/concepts/four-ways-to-fill-an-open-shift)
- [Roles and permissions](/docs/reference/permissions-reference)
