Automated Accountability: Managing Attendance and Reprobation in Laravel
Dealing with user engagement in subscription-based services, especially when it involves recurring sessions, can be a complex challenge. How do you ensure accountability for attendance without overwhelming administrators with manual tasks? And how do you implement fair, automated consequences for no-shows while providing a path for re-engagement?
This post explores a multi-phase approach to building a robust attendance and absence management system, focusing on automation, clear business rules, and empowering mentors, all within a Laravel application.
The Mentorship Attendance Lifecycle
Our system manages a comprehensive attendance lifecycle for mentorship sessions, moving mentees through various states based on their engagement:
- Session Join: Mentees automatically marked present when they join a session within a predefined window.
- Absence Detection: A scheduled task periodically identifies past bookings where attendance was not registered.
- Rule Enforcement: Business rules are applied based on consecutive absences.
- Communication: Automated warning and reprobation emails are sent to both mentees and mentors.
- Reprobation: After consecutive absences, mentees can be "reprobated," leading to cancellation of future bookings while their subscription remains active.
- Reactivation: Mentors are empowered with a dashboard to track absences and reactivate reprobated mentees, clearing their status and regenerating bookings.
Architecting the Workflow
The system's design relies on several key components working in concert:
MentorAbsenceHandler: This class encapsulates the core business logic. It's responsible for counting consecutive absences, triggering warnings, handling reprobation, and managing mentee reactivation.ProcessMentorshipAbsencesCommand: A scheduled Laravel command (e.g., hourly) acts as the system's heartbeat. It identifies past, unattended bookings, marks them as absent, and then delegates to theMentorAbsenceHandlerto apply business rules.MentorBookingController::joinSession: This controller method handles the "join session" action. It includes logic to automatically mark a mentee asattended = trueandattendance_marked_by = systemif they join within a specific pre-session time window.MentorSubscribersController: Powers the mentor's dashboard, providing visibility into mentee attendance records and offering the "Reactivate" action with appropriate ownership checks.AttendanceMarkedByEnum: A simple enum (system|mentor) distinguishes how attendance was recorded, providing valuable context for audit trails.
Implementing Absence Rules
The business rules for absence management are precise:
- First Absence: If a mentee misses a session, a warning email is automatically sent to both the mentee and their mentor. This serves as an initial alert without immediate severe consequences.
- Second Consecutive Absence: If a mentee misses a second consecutive session, they are reprobated. All their remaining bookings within the current mentorship cycle are cancelled. Critically, their Stripe subscription remains active, ensuring continuity of payment per the signed contract.
- Non-Consecutive Absences: If a mentee misses a session, attends the next, and then misses another, the consecutive absence count resets, preventing immediate reprobation.
Empowering Mentors with Reactivation
To provide flexibility and a path for mentees to re-engage, mentors have a dedicated dashboard (/dashboard/mentorship/subscribers). Here, they can view each subscriber's absence count. If a mentee is reprobated, the mentor can perform a "Reactivate" action. This clears the reprobation status, sends a reactivation email, and regenerates bookings for the mentee until their cycle_ends_at date.
Illustrative Code Snippet
Here's a simplified example demonstrating how the MentorAbsenceHandler might process an unattended booking and how a mentee could be reactivated:
// Example: Simplified MentorAbsenceHandler
class MentorAbsenceHandler
{
public function handleUnattendedBooking(MentorshipBooking $booking): void
{
// Ensure booking is marked as not attended
if ($booking->attended === null) {
$booking->update(['attended' => false]);
}
$subscription = $booking->menteeSubscription;
$consecutiveAbsences = $this->getConsecutiveAbsenceCount($subscription);
if ($consecutiveAbsences === 1) {
// First absence: Send warning emails
$this->sendWarningEmails($subscription, $booking);
$booking->update(['absence_warning_sent_at' => now()]);
} elseif ($consecutiveAbsences >= 2) {
// Second consecutive absence: Reprobate mentee
$this->reprobateMentee($subscription);
$this->sendReprobationEmail($subscription);
}
}
public function reactivateMentee(MenteeSubscription $subscription): void
{
if ($subscription->is_reprobated) {
$subscription->update(['is_reprobated' => false]);
// Regenerate future bookings for the subscription cycle
// ... (e.g., call a booking generation service)
$this->sendReactivationEmail($subscription);
}
}
// Private methods for counting absences, sending emails, cancelling bookings etc.
private function getConsecutiveAbsenceCount(MenteeSubscription $subscription): int { /* ... */ }
private function sendWarningEmails(MenteeSubscription $subscription, MentorshipBooking $booking): void { /* ... */ }
private function reprobateMentee(MenteeSubscription $subscription): void { /* ... */ }
private function sendReprobationEmail(MenteeSubscription $subscription): void { /* ... */ }
private function sendReactivationEmail(MenteeSubscription $subscription): void { /* ... */ }
}
This handler centralizes the complex business logic, making the system maintainable and testable.
Conclusion
Implementing an automated attendance and absence management system provides clarity and fairness in managing user engagement. By combining scheduled commands, dedicated handlers for business logic, and empowering users with appropriate actions (like mentor reactivation), we build a robust system that ensures accountability, communicates clearly, and offers pathways for users to re-engage. This multi-phase approach allows for gradual feature rollout and creates a resilient workflow within your application.