Haeminway haemin/way
한국어
4 min read

Shift Swap: ask from your phone, one tap to approve, the roster fixes itself

A small mobile web app for shift trades: staff request a swap, the manager approves once, and both shifts move together. Plus how I'd hand it to Google Sheets.

Two shift blocks swapping places on a roster board, with a phone below giving one approving pulse

A pending request leaves both shifts unchanged

Before approval Alex is assigned Monday and Jamie Tuesday; a pending swap keeps those assignments, and approval swaps both roster rows together.View full-size diagram
Visual guideIn the fictional local demo, a request changes nothing while pending. Approval moves Alex to Tuesday and Jamie to Monday as one roster decision.
Takeaway

A shift swap is two changes, not one. Move Alex to Tuesday and forget to move Jamie to Monday, and Monday has nobody. Shift Swap treats the request as a proposal, and approval moves both shifts at once. Try the demo (fictional cafe, no login, nothing leaves your browser).

The usual version of this goes through a group chat. Alex asks, Jamie says “sure” in a DM, the manager updates one cell in the schedule, and three people now have three different rosters.

I built a tiny app for exactly that moment. Everything below is from the live demo.

Three Shift Swap screens: my shifts, the manager's review, and the approved swap

The example

Willow Cafe is made up. So are Alex and Jamie.

ShiftBeforeAfter approval
Mon, Oct 19 · 8am–2pm · BaristaAlex MorganJamie Lee
Tue, Oct 20 · 8am–2pm · BaristaJamie LeeAlex Morgan

Alex has an appointment on Monday morning. Jamie agreed to trade.

Staff side: four short steps

My shifts: next shift card, the week list and the Request a swap button

Alex opens My shifts, taps Request a swap, picks the Monday shift, picks Jamie’s Tuesday shift, adds a reason and sends it for review.

Step 3 of 4: the chosen shifts and a short reason

Until the manager decides, the roster doesn’t change. Alex is still on Monday. That’s the whole point: a request is a question, not an edit.

Manager side: one decision

Review swap sheet with both shifts, the reason, Decline and Approve swap

The manager opens Requests, sees both shifts side by side with the reason, and taps Approve swap or Decline. Declining leaves both shifts exactly where they were.

History tab: request approved, roster updated

After approval the request moves to History as Approved, and the roster shows Jamie on Monday and Alex on Tuesday.

The part I cared about: no half swaps

Before approving, the app checks a few boring things:

  • both shifts still belong to the people in the request (nobody changed them in the meantime)
  • the roles match (a barista shift for a barista shift)
  • the two people are different, and there isn’t already a pending request for the same two shifts
  • the trade doesn’t make anyone work two overlapping shifts

If any of those fail, the old request can’t overwrite the newer roster. Each shift carries a version number for this. In the exported CSV, the two swapped shifts show Version 2, the untouched ones 1.

Date,Start,End,Role,Staff,Version
2026-10-19,08:00,14:00,Barista,Jamie Lee,2
2026-10-20,08:00,14:00,Barista,Alex Morgan,2
2026-10-21,14:00,20:00,Shift lead,Sam Rivera,1

That’s straight from the demo’s roster export after approving the request.

What it does not handle: overtime limits, breaks, qualifications, overnight shifts or local labour rules. A real team would need to tell me their rules first. A green Approve button shouldn’t quietly invent a policy.

Desktop is the same app

The roster on desktop, shown inside a phone frame

On a laptop it shows the same phone layout in a frame. It’s a phone tool, so I didn’t build a second dashboard.

Where Google Sheets comes in

Right now the public demo keeps its state in your browser only. That’s on purpose: you can play manager without me collecting anyone’s name.

For a real team, the roster would live in a Google Sheet, with a small Apps Script in front of it. The way I set that adapter up:

  1. The script maps the signed-in Google account to a staff row, and only the configured owner can approve.
  2. On approve, it takes a script lock and re-reads both rows first.
  3. It sends both shift changes plus the request status as one Sheets API batchUpdate, so an error can’t leave half a swap in the sheet.

I’ve tested that adapter against mocked Google services: permissions, lock, stale request, decline and the single update.

It is not connected to a live Sheet in the public demo, and I’m not going to pretend it is. Hooking it to a real roster is a separate step with the owner’s own Google account.

Google’s docs, if you’re building your own:

Try it

Open Shift Swap, request the Monday trade as Alex, then approve it as the manager and download the roster CSV. Use fake reasons, not real staff details.

Your team runs swaps through a group chat and a sheet nobody trusts? Tell me how it works today and I’ll tell you if something this small would fit.