# Biometric Attendance Synchronization Assessment & Manual Pairing Plan This plan documents the current integration state between the biometric devices, the Windows Sync Agent, and the core HRMS attendance records, and proposes a design for enhanced manual pairing when multiple daily pings occur. --- ## 🔍 Codebase Assessment Findings ### 1. The Sync Pipeline Architecture The system uses a pull-then-push architecture split into three main parts: 1. **Branch Sync Agent (`branch-agent/sync.js`)**: - A packaged Node.js script (`sync-agent.exe`) running locally on a branch PC. - It queries the local ZKTeco biometric device via TCP (port 4370) using the `zklib-js` library. - It filters pings to the last 15 days and sends an HTTP POST request with an API key to the cloud API endpoint: `/api/zkteco/sync`. 2. **Receiving API (`AttendanceSyncController@sync`)**: - Authenticates the agent using the `ZKTECO_SYNC_KEY` (configured in `.env`). - Receives the JSON payload and registers punches in the `biometric_attendances` table with a state of `pending`. It avoids duplicates by checking `biometric_emp_id` and `punch_time`. 3. **Attendance Mapping & Conversion (`BiometricAttendanceController`)**: - **Is it synced automatically?** **No.** It is currently designed to be manually triggered by an HR administrator from the `/hr/biometric-attendance` dashboard. - **How it works:** - **Bulk Trigger (`Pull Data & Sync` button)**: Loops through all `pending` biometric records, groups them by employee + date, takes the **first entry** as `clock_in`, the **last entry** as `clock_out` (requires at least 2 pings), creates an `AttendanceRecord`, and processes payroll hours. - **Row Trigger (`Sync` action)**: Syncs a single employee-day grouping using the first/last punch logic. --- ## 🛠️ Proposed Improvements: Manual Triggering & Multiple Punch Pairing Currently, if an employee has multiple entries (e.g., Clock In, break pings, Clock Out), the system automatically picks the first and last. If the user wants to **manually pair** custom punch times (e.g. ignoring a false scan or choosing a specific middle scan): ### Phase 1: Database Schema Support No schema changes are required as `BiometricAttendance` records already store the individual raw punch timestamps and can be marked as `synced` individually. ### Phase 2: Backend Controller Updates (`BiometricAttendanceController`) - **[New Endpoint] Custom Sync Pairing (`/hr/biometric-attendance/sync-custom`)**: - Accept a custom POST request containing `employee_code`, `date`, `clock_in_biometric_id`, and `clock_out_biometric_id`. - Fetch the specific biometric records by ID to extract the custom clock-in and clock-out times. - Insert/update the `AttendanceRecord` with these custom values. - Mark all biometric entries for that employee/date as `synced`. ### Phase 3: Frontend UI Enhancements (`resources/js/pages/hr/biometric-attendance/index.tsx`) - Enhance the **Details Modal** (`View` component) to display checkbox selectors or action buttons next to the list of pings for a specific day. - Allow HR to check one ping as the desired **"Clock In"** and another ping as the **"Clock Out"**. - Provide a **"Confirm Custom Sync"** button in the modal that triggers the new custom pairing endpoint. --- ## 📋 Verification Plan ### Automated Verification - Run `npm run build` to verify React components bundle correctly with Shadcn UI additions. - Execute unit/integration tests for the new `sync-custom` endpoint. ### Manual Walkthrough 1. **Agent Simulation**: Push mock data containing 4 punches for an employee on a single day to `/api/zkteco/sync`. 2. **Dashboard Review**: View the record on the `/hr/biometric-attendance` page (it will show 4 total entries). 3. **Details Pairing**: Click "Details" (Eye icon), select Punch #1 as Clock In and Punch #4 as Clock Out, and click "Confirm Custom Sync". 4. **Attendance Parity**: Verify that the generated `AttendanceRecord` matches the chosen times, and all 4 logs are marked as `synced`.