Anyone can build a clock-in button. Punch in, punch out, write two timestamps to a table — that’s an afternoon of work, and it’s the least interesting part of a time clock. For an enterprise client running hourly staff, the value wasn’t in the punches. It was in everything that happens between them.
Because here’s the failure mode a naive time clock has: someone misses a required meal break on a Tuesday, nobody notices, and you find out two weeks later when payroll gets reconstructed and the numbers don’t add up. Now you’re back-calculating penalties, apologising to an employee, and doing archaeology on timestamps. Expensive, slow, and completely avoidable.
Table of contents
Open Table of contents
The interesting part is the watching
So the design premise was simple: don’t wait for payroll to find problems. Watch active shifts in near-real-time and flag issues as they happen.
That flips a reporting problem into a monitoring problem. Instead of a big reconciliation job at the end of a pay period, there’s a small background process that keeps an eye on every shift that’s currently open. A meal break that’s overdue gets flagged while the shift is still running — while someone can still act on it — not two weeks after the fact when all you can do is pay the penalty.
The mechanism is unglamorous, which is the point. A background flow sweeps active shifts every 15 minutes. It pulls every open shift, checks each one against the rules, and raises a flag on anything that’s drifted out of bounds. No magic, no ML, just a clock that actually looks at what it’s tracking.
Rules don’t belong in flow logic
Here’s the decision I’d defend hardest. The compliance thresholds — when a break becomes due, when a shift has run too long — do not live inside the flow.
They live in environment variables.
This matters more than it sounds. Labor rules vary by jurisdiction, and they change. If “a meal break is due after 5 hours” is buried in a condition step three branches deep in a Power Automate flow, then every time a rule shifts — or you onboard staff under a different jurisdiction — someone has to open the flow, find the right node, edit it, test it, and re-publish. That’s a developer task, and it’s a fragile one.
Pull those thresholds into environment variables and the rules become configuration. You tune them per state or per jurisdiction without touching a single flow step. The logic that enforces the rule and the value of the rule are two different things, and conflating them is how you end up with brittle automation nobody wants to touch. Keep them apart and the flow stops being something you edit and starts being something that just runs.
The two guards that keep it honest
Real-world time clocks get abused by accident, not malice. Two safety mechanisms handle the messy edges.
First, a duplicate-punch guard. People double-tap. A button feels unresponsive, they hit it again, and now you’ve got two clock-ins a second apart — which, unguarded, opens two overlapping shifts for the same person. The guard checks for an already-open shift before creating a new one, so a double tap is a no-op instead of a data-integrity problem you clean up later.
Second, an auto-close safety net. Sometimes people forget to punch out. Without a backstop, that shift runs forever, quietly poisoning every report it touches. So any shift still open past 14 hours gets closed automatically. It’s not a guess at what the person actually worked — it’s a floor that stops one forgotten punch from corrupting the data downstream.
Neither of these is clever. Both are the difference between a demo and a system.
One data model, many front doors
Underneath all of it is a deliberately boring data model: a shift record, with child break records hanging off it. That’s the whole shape. A shift knows when it started, when it ended, and which breaks belong to it.
The discipline is that the same tables back the clock no matter where the punch comes from. Whether someone clocks in from the React app or from another surface entirely, they’re writing to the same shift and break records. There’s no “web time” and “kiosk time” living in separate structures that someone has to reconcile. One model, one source of truth.
And that bought the thing I care about most: only the payroll export ever has to change. Today the export is manual — someone pulls the data and hands it to the payroll system. Tomorrow it might be an API integration. When that day comes, I swap the export and nothing else moves. The data model stays put, the compliance sweep stays put, the guards stay put. The volatile part is isolated at the edge, where volatility belongs.
The takeaway
Enforce compliance live, not in hindsight. That’s the whole thesis. The engineering that matters in a time clock isn’t the button — it’s the 15-minute sweep, the thresholds you can tune without a deployment, and the guards that keep bad data from ever landing. Catching a missed break the moment it happens is dramatically cheaper than reconstructing it from timestamps after payroll has already run.
Slides: the condensed version is in a short deck — download the PDF.
If your time tracking only tells you about problems after the pay period closes, how much are you paying to find out late?