The Engineering Behind ShiftSync: Turning Workforce Rostering Into a Constraint-Optimisation Problem

The Engineering Behind ShiftSync: Turning Workforce Rostering Into a Constraint-Optimisation Problem

1 5
calendar_today agoschedule8 min read

How 20+ scheduling algorithms, a privacy-first local architecture, and zero mandatory registration combine to make free AI-powered shift scheduling actually work.

Workforce scheduling looks like a UI problem until you try to automate it correctly.

Then the real engineering begins.
A calendar is trivial to draw. An accurate, fair, legally compliant roster for a 60-person hospital ward covering a 28-day planning period — that is a non-trivial constraint-satisfaction problem that has been forcing managers to stay late with spreadsheets for decades.
ShiftSync is my attempt to solve this properly. It is a browser-based, offline-capable, privacy-first workforce scheduling application with 20+ mathematical algorithms, full leave management, fatigue enforcement, and PDF/Excel export — free, no registration required.
Source code: github.com/validivar/ShiftSync Live application: www.shiftsync.world
This article is about the engineering decisions that made it work — and the ones I had to revisit when my first approach turned out to be wrong.

Start With Constraints, Not the Interface
The most seductive mistake in scheduling software is starting with the UI.
You build the staff table. You build the weekly grid. You add colour-coded shift indicators. It looks impressive. Then someone asks: how does it automatically generate a valid schedule?
That is when you discover you have been building the wrong thing first.
Before any interface code, a scheduling system requires a precise constraint model. ShiftSync's constraint model distinguishes between two fundamentally different types of rules:
Hard Constraints — Inviolable

  1. An employee on approved leave cannot be assigned to any shift
    during their leave period.

  2. No employee may exceed their defined maximum consecutive shift count.

  3. A minimum rest interval (default: 11 hours, EU Working Time
    Directive aligned) must separate the end of one shift
    and the start of the next.

  4. Any shift designated as requiring a specific skill (ICU, ACLS,
    Forklift, etc.) must receive an employee who holds that
    certification.
    Soft Constraints — Optimised, Not Mandated

  5. Employees' stated shift preferences should be honoured when
    coverage allows.

  6. Total working hours across the planning period should be
    distributed equitably across the team.

  7. Night shift assignments should rotate across the full team
    rather than concentrating on a subset.

  8. Individual weekly hours should approach (not necessarily
    reach) the configured minimum.

The distinction is load-bearing. An algorithm that treats all constraints identically either refuses to generate a roster (too many collisions between hard rules) or generates one that is technically valid but practically awful (maximises compliance metrics while ignoring everything a human manager actually cares about).
The correct model is validity plus optimisation — not just assignment.

Why 20 Algorithms Instead of One
My first instinct was to build a single generalised scheduling algorithm that could handle any pattern.
This was wrong.
Different industries use shift patterns with fundamentally incompatible structures. The Panama Plan's 2-2-3 cycle is not a generalisation of the Dupont rotation's 28-day sequence. A 24-hour call duty schedule has completely different rest constraint arithmetic than a standard 4x4 eight-hour pattern.
Trying to represent all of these inside a single algorithm produces either a combinatorial explosion of special cases or a lowest-common-denominator system that handles none of them well.
The correct approach is a dispatch table — separate, cleanly implemented algorithms for each pattern, each with full knowledge of its own cycle structure and timing requirements.
const algorithms = {

'4x4':   generate4x4Schedule,    // 8hr 3-shift rotation
'panama': generatePanamaSchedule, // 12hr 2-2-3 cycle
'pitman': generatePitmanSchedule, // 12hr 4-on-4-off
'dupont': generateDupontSchedule, // 12hr 28-day complex rotation
'ddnnoo': generateDDNNOOSchedule, // 12hr D-D-N-N-O-O cycle
'4-10':  generate4_10Schedule,   // 10hr 4-day week
'8hour': generate8HourSchedule,  // 8hr standard 5/2
'12hour':generate12HourSchedule, // 12hr 3-on-3-off
'24hour':generate24HourSchedule, // 24hr call duty
'48hour':generate48HourSchedule, // 48hr weekend call
'mixed': generateMixedSchedule   // hybrid 8hr+12hr extended nights

};

const fn = algorithms[config.shiftType] || generateFairSchedule;
return fn(startDate, period, staffMembers.length, config);
Each function receives: start date (Luxon DateTime), planning period in days, staff count, and the full config object. Each independently implements its cycle logic before calling checkStaffLeave on every staff-date combination to enforce leave constraints.

Deep Dive: The Dupont Algorithm
The Dupont is the most complex pattern to implement correctly because its cycle is 28 days long and mixes night shifts, day shifts, and rest in a non-obvious sequence.
The canonical Dupont sequence is:
N N N N O O O D D D O N N N O O O D D D D O O O O O O O
Where N = Night, D = Day, O = Off.
The critical implementation challenge is assigning teams to positions in this cycle such that:
1.All shifts are covered on all days
2.No team is assigned the same position in consecutive cycles
3.Employee preferences shift the assignment within the cycle without breaking coverage
function generateDupontSchedule(startDate, days, staffCount, config) {

const schedule = [];
const dp = [
    'N','N','N','N','O','O','O',  // 4 nights, 3 off
    'M','M','M','O',               // 3 days, 1 off
    'N','N','N','O','O','O',       // 3 nights, 3 off
    'M','M','M','M',               // 4 days
    'O','O','O','O','O','O','O'   // 7 off
];

for (let day = 0; day < days; day++) {
    const currentDate = startDate.plus({ days: day });
    const dayEntry = { 
        date: currentDate.toFormat('yyyy-MM-dd'),
        dayOfWeek: currentDate.toFormat('EEE'),
        formattedDate: currentDate.toFormat('MMM dd'),
        shifts: {}
    };
    
    staffMembers.forEach((staff, i) => {
        // Offset each staff member's position in the cycle
        // to ensure continuous coverage
        const cyclePos = (day + Math.floor(i * dp.length / staffCount)) 
                         % dp.length;
        let shift = dp[cyclePos];
        
        // Hard constraint: leave always wins
        const leave = checkStaffLeave(staff, currentDate);
        if (leave) shift = 'L-' + leave;
        
        dayEntry.shifts[staff.id] = { 
            type: shift, 
            staffName: staff.fullName, 
            staffRank: staff.rank, 
            hours: shift === 'O' ? 0 : 12 
        };
    });
    
    schedule.push(dayEntry);
}
return schedule;

}
The Math.floor(i * dp.length / staffCount) offset distributes team members across the cycle such that all 28 cycle positions have coverage on every day of the planning period.

The Objective Function
Two schedules can both satisfy every hard constraint. Which one is better?
ShiftSync's compliance scoring function evaluates quality across four dimensions:
function calculateRosterStats(schedule) {

const stats = {
    totalHours: 0,
    shiftCount: { M:0, A:0, N:0, O:0, C:0 },
    staffHours: {},
    minHours: Infinity,
    maxHours: 0,
    avgHours: 0,
    compliant: true
};

// Accumulate per-staff hours
schedule.forEach(day => {
    staffMembers.forEach(staff => {
        const s = day.shifts[staff.id];
        if (s) {
            const t = s.type.charAt(0);
            if (stats.shiftCount[t] !== undefined) stats.shiftCount[t]++;
            stats.totalHours += s.hours || 0;
            stats.staffHours[staff.id] += s.hours || 0;
        }
    });
});

// Evaluate compliance bounds
const arr = Object.values(stats.staffHours);
stats.minHours = Math.min(...arr);
stats.maxHours = Math.max(...arr);
stats.avgHours = arr.reduce((a,b) => a+b, 0) / arr.length;

const wks = schedule.length / 7;
const maxW = parseInt(document.getElementById('maxHoursWeek').value) || 48;
const minW = parseInt(document.getElementById('minHoursWeek').value) || 36;

stats.compliant = stats.maxHours <= maxW * wks 
               && stats.minHours >= minW * wks * 0.5;

return stats;

}
The compliance flag (PASS / REVIEW) surfaces in the roster display panel. It is not a gate — the manager receives the roster regardless — but the flag ensures that borderline cases are visible rather than buried.

Local-First Architecture: A Deliberate Privacy Stance
Workforce scheduling data is operationally sensitive. It reveals staffing levels, employee identities, capability distributions, and leave patterns — information that many organisations in healthcare, security, and government are legitimately concerned about transmitting to third-party cloud infrastructure.
ShiftSync's response to this is architectural, not policy-based. The application has no server-side component. There is no API endpoint receiving scheduling data. There is no cloud database. There is no authentication layer that could become a breach surface.

Traditional SaaS: Browser → API → Database → Application → Browser
ShiftSync: Browser ← localStorage → Browser
All data is stored in localStorage. All scheduling computation happens in the browser. All export (PDF, Excel) is generated client-side by jsPDF and SheetJS respectively. The application works entirely offline after the initial HTML page load.
This architecture has real limitations for large enterprise deployments that require multi-user collaboration, centralised audit logs, and cross-device synchronisation. Those are genuine trade-offs, not ignored problems.
But for the target audience — small to medium organisations, NGOs, community hospitals, SMEs — this architecture is not a limitation. It is an advantage. It eliminates an entire category of data management risk.

The Fatigue Management System
EU Working Time Directive requires a minimum 11-hour rest period between shifts. Many clinical governance frameworks require maximum consecutive shift limits. ShiftSync enforces both.
The consecutive shift counter runs during algorithm execution. After generation, the conflict detection system evaluates whether the staff count is sufficient to satisfy the configured limits:
function checkConflicts() {

const maxC = parseInt(document.getElementById('maxConsecutive').value) || 5;
const alertEl = document.getElementById('conflictAlert');

if (staffMembers.length > 0 && staffMembers.length < maxC) {
    alertEl.classList.add('show');
    document.getElementById('conflictMsg').textContent = 
        `Warning: Only ${staffMembers.length} staff for patterns 
         requiring ${maxC}+ members. Some may exceed consecutive 
         shift limits.`;
} else {
    alertEl.classList.remove('show');
}

}
The warning surfaces before generation, giving the manager the option to add staff or adjust the consecutive limit before committing to a roster that will need manual correction.

Stack Decisions and Why

The absence of a framework is a deliberate choice. A scheduling tool used by a ward manager in Lagos, a factory supervisor in Manila, and an NGO coordinator in Nairobi needs to load fast on 3G and work when the connection drops. A React bundle adds seconds to the load time and introduces a dependency on JavaScript delivery infrastructure.
Single-file HTML with CDN dependencies loads in under two seconds on a mobile connection. It works offline. It deploys by dragging a file into a hosting panel.

What the Open Source Invitation Is Really For
ShiftSync is on GitHub not primarily as a portfolio item, but because scheduling logic is domain-specific in ways that a solo developer building from first principles will get wrong.
The DDNNOO algorithm is straightforward. But is the implementation correct for the specific variant used in ICU environments where one of the two "day" slots has different skill requirements from the other? I do not know. A developer who has worked scheduling in that environment might.
The Panama Plan cycle is mathematically clear. Does it interact correctly with a 14-day planning period where the cycle straddles the boundary? The tests should tell us. They might not cover all cases.
Open source is the mechanism for closing those gaps. If you work in scheduling, healthcare technology, workforce management, or HR software — the codebase is readable, the algorithms are individually separated, and issues are open.

Build It. Try It. Improve It.
ShiftSync is live at www.shiftsync.world.
No signup. No email. No credit card. Open the page. Add staff. Select a pattern. Generate. Export.
If you find a constraint the algorithm mishandles, open an issue: github.com/validivar/ShiftSync
If you use it in a production scheduling environment and find something wrong, tell me. That feedback is the most valuable contribution the project can receive.
And if you know an organisation — a clinic, an NGO, a small manufacturer, a security firm — still building rosters in Excel at midnight, send them the link. The better schedule is the product. Help us build it.
The immediate goal to sustaining ShiftSync is maintaining its website. You could help towards website renewal subscription using the donation buttons on the live site.


🌐 Live app: www.shiftsync.world | ⭐ GitHub: github.com/validivar/ShiftSync |
Mikhail Ikpoma — Founder, ShiftSync

🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

Beyond the Crisis: Why Engineering Your Personal Health Baseline Matters

Huifer - Jan 24

The Zero-Net-Loss Fleet & The Mercenary Squad: A Live AI Economy

DEVPlank - Aug 4

Decoding Subclinical Signals: Turning "Lifestyle Noise" into Predictive Health Insights

Huifer - Jan 31

Why Are There Only 13 DNS Root Servers For The Whole World? Is that a problem

richarddjarbeng - May 7

The Sovereign Vault — A Comprehensive Guide to Protocol-Driven AI

Ken W. Algerverified - Jun 4
chevron_left
184 Points6 Badges
3Posts
0Comments
2Connections
# About Me

Hi, I'm Mikhail Ikpoma, healthcare quality leader, AI researcher, technical writer, and ... Show more

Related Jobs

View all jobs →

Commenters (This Week)

1 comment
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!