Skip to main content

Shift Management System

Overview​

The shift management system is a comprehensive time-tracking solution implemented across the AttuneLogic platform. It supports both mobile and web applications, providing functionality for:

  • Clock in/out management
  • Break tracking
  • Overtime calculation
  • Payroll integration
  • Location tracking
  • Multi-tenant support

Database Schema​

Shift Model​

The shift model (models/Shift.js) includes:

{
employee: ObjectId, // Reference to Employee model
startTime: Date, // Required, when shift starts
endTime: Date, // When shift ends
totalTime: Number, // Total shift duration in milliseconds
totalBreakTime: Number, // Total break time in milliseconds
totalWorkTime: Number, // Actual working time (totalTime - totalBreakTime)
status: String, // ["scheduled", "in-progress", "completed", "cancelled"]
location: { // GeoJSON Point
type: String,
coordinates: [Number]
},
breaks: [{ // Array of break periods
startTime: Date,
endTime: Date,
type: String, // ["lunch", "rest", "other"]
active: Boolean
}],
// Payout related fields
payoutRate: Number,
payoutHourlyTotal: Number,
payoutTotal: Number,
payoutSupplemental: Number,
payoutType: String, // ["Flat", "Hourly"]
payoutId: String,
overtime: Number,
overtimeRate: Number,
department: String,
parentCompany: String
}

API Endpoints​

Shifts​

MethodEndpointDescriptionAccess
GET/api/v1/shiftsGet all shifts with paginationPrivate
GET/api/v1/shifts/:idGet shift by IDPrivate
POST/api/v1/shiftsCreate new shiftPrivate
PUT/api/v1/shifts/:idUpdate shiftPrivate
DELETE/api/v1/shiftsDelete shift(s)Private/Admin
PUT/api/v1/shifts/:shiftId/breakAdd/update breakPrivate

Mobile Implementation​

The mobile app uses a React Context-based implementation through the useShift hook:

Features​

  • Real-time time tracking
  • Break management
  • Persistent state using local storage
  • Integration with job/task management
  • Offline support

Usage Example​

const {
active, // Is shift active
startShift, // Start new shift
endShift, // End current shift
shift, // Current shift data
elapsedTime, // Formatted elapsed time
startBreak, // Start break
endBreak, // End break
breakActive, // Is break active
breakElapsedTime, // Formatted break time
} = useShift();

Time Calculations​

The system uses millisecond-based calculations for precise time tracking:

  1. Total Time: End time - Start time
  2. Break Time: Sum of all break durations
  3. Working Time: Total time - Break time
  4. Overtime: Working time beyond 8 hours

Overtime Calculation​

const EIGHT_HOURS_MS = 8 * 60 * 60 * 1000;
const overtimeMs =
workingTime > EIGHT_HOURS_MS ? workingTime - EIGHT_HOURS_MS : 0;

Payroll Integration​

Shifts integrate with the payroll system through the Payout model:

  • Automatic rate calculations
  • Support for regular and overtime hours
  • Custom rate overrides
  • Break time deductions
  • Integration with job/task completion

Job Integration​

The shift system integrates with the job management system:

  • Tracks time spent on specific tasks
  • Prevents shift completion with pending tasks
  • Supports task pausing and resuming
  • Maintains accurate billable hours

Security​

All shift endpoints are protected with:

  • Token verification
  • User authentication
  • Parent company verification
  • Role-based access control

Best Practices​

  1. Time Tracking

    • Always use millisecond precision
    • Store times in UTC
    • Use server time for critical operations
  2. Break Management

    • Validate break transitions
    • Prevent overlapping breaks
    • Track break types separately
  3. Data Integrity

    • Validate shift state transitions
    • Prevent backdated modifications
    • Maintain audit trails
  4. Performance

    • Use pagination for shift lists
    • Index frequently queried fields
    • Optimize time calculations

Error Handling​

Common error scenarios and handling:

  1. Incomplete Tasks

    if (inProgressItems.length > 0) {
    return {
    status: "error",
    message: "Complete pending tasks before ending shift",
    data: { pendingItems: inProgressItems },
    };
    }
  2. Invalid Break Operations

    if (!currentBreak) {
    return {
    status: "error",
    message: "No active break found to end",
    };
    }

Future Enhancements​

  1. Planned Features

    • Geofencing support
    • Advanced break rules
    • Shift templates
    • Schedule integration
  2. Optimization Opportunities

    • Caching improvements
    • Real-time updates
    • Offline sync
    • Batch operations

Known Issues and Solutions​

Break Type Validation​

Issue: Break types are inconsistently enforced across the system.

Solution:

  1. Add middleware validation:
const validateBreakType = (req, res, next) => {
const validTypes = ["lunch", "rest", "other"];
if (req.body.breakType && !validTypes.includes(req.body.breakType)) {
return res.status(400).json({
status: "error",
message: "Invalid break type. Must be one of: lunch, rest, other",
});
}
next();
};
  1. Add schema-level validation:
breaks: [
{
type: {
type: String,
enum: {
values: ["lunch", "rest", "other"],
message: "Invalid break type",
},
required: true,
},
},
];

Clock In/Out Issues​

Issue: Users experience clock in/out problems due to various edge cases.

Solutions:

  1. Concurrent Shift Prevention:
const preventConcurrentShifts = async (employeeId) => {
const activeShift = await Shift.findOne({
employee: employeeId,
endTime: null,
status: "in-progress",
});
if (activeShift) {
throw new Error("Employee already has an active shift");
}
};
  1. Timezone Handling:
// Store all times in UTC
const startTime = new Date().toISOString();

// Convert to local time for display
const localStartTime = new Date(shift.startTime).toLocaleString();
  1. Network Resilience:
// Mobile app
const handleClockIn = async () => {
try {
// Save locally first
await Storage.setItem("pendingClockIn", {
time: new Date().toISOString(),
type: "clockIn",
});

// Attempt server sync
await startShift();

// Clear local storage on success
await Storage.removeItem("pendingClockIn");
} catch (error) {
// Handle offline mode
setOfflineMode(true);
}
};
  1. Time Validation:
const validateShiftTimes = (startTime, endTime) => {
// Prevent future start times
if (startTime > new Date()) {
throw new Error("Cannot start shift in the future");
}

// Prevent end time before start time
if (endTime && endTime < startTime) {
throw new Error("Shift cannot end before it starts");
}

// Prevent extremely long shifts
const MAX_SHIFT_HOURS = 24;
if (endTime && endTime - startTime > MAX_SHIFT_HOURS * 60 * 60 * 1000) {
throw new Error(`Shift cannot be longer than ${MAX_SHIFT_HOURS} hours`);
}
};
  1. Device/Server Time Sync:
const syncTimeWithServer = async () => {
const serverTime = await fetchServerTime();
const localTime = new Date();
const timeDiff = serverTime - localTime;

if (Math.abs(timeDiff) > 5 * 60 * 1000) {
// 5 minutes
throw new Error("Device time significantly different from server time");
}
return timeDiff;
};

Best Practices for Implementation​

  1. Break Management:

    • Always specify break type
    • Validate break duration limits
    • Prevent overlapping breaks
    • Track mandatory break compliance
  2. Clock Operations:

    • Use server time as source of truth
    • Implement offline queue for operations
    • Add retry logic for failed operations
    • Validate against schedule if applicable
  3. Data Integrity:

    • Add database constraints
    • Implement transaction handling
    • Add audit logging for time changes
    • Regular data validation checks
  4. User Experience:

    • Clear error messages
    • Offline mode indicators
    • Sync status visibility
    • Confirmation for critical actions

Monitoring and Alerts​

  1. System Health:

    • Track failed clock operations
    • Monitor time discrepancies
    • Alert on validation failures
    • Track offline sync success rate
  2. User Patterns:

    • Monitor unusual shift patterns
    • Track break compliance
    • Identify common error scenarios
    • Analyze usage patterns