# Offline Attendance Sync API - Setup Guide

## Overview
This API endpoint allows a mobile app to sync offline attendance records to the server database.

## Files Created

### 1. Migration File
**Location:** `app/Database/Migrations/2026-01-16-100000_AddLocalUuidToAttendanceTable.php`

This migration adds two new columns to the `attendance` table:
- `local_uuid` (VARCHAR 100, unique) - Unique identifier from mobile device for offline sync
- `device_time` (DATETIME) - Timestamp from mobile device when record was created

### 2. API Controller
**Location:** `app/Controllers/Api/AttendanceController.php`

The controller handles the sync endpoint with the following logic:
- Validates required fields (local_uuid, employee_id, attendance_date)
- Checks for duplicates using local_uuid
- Converts lunch_start_time → lunch_out_time
- Converts lunch_end_time → lunch_in_time
- Calculates lunch_duration_minutes automatically
- Inserts the attendance record

### 3. Route Definition
**Location:** `app/Config/Routes.php` (lines 183-186)

Route: `POST /api/attendance/sync`

### 4. Model Update
**Location:** `app/Models/AttendanceModel.php`

Added `local_uuid` and `device_time` to the `allowedFields` array.

---

## Installation Steps

### Option 1: Run Migration (Requires PHP 8.0+)
```bash
cd c:\wamp64\www\real-time-signin
php spark migrate
```

### Option 2: Manual SQL (For PHP 7.4)
Execute this SQL in your database:

```sql
ALTER TABLE `attendance`
ADD COLUMN `local_uuid` VARCHAR(100) NULL UNIQUE COMMENT 'Unique identifier from mobile device for offline sync',
ADD COLUMN `device_time` DATETIME NULL COMMENT 'Timestamp from mobile device when record was created';

CREATE INDEX `idx_local_uuid` ON `attendance` (`local_uuid`);
```

---

## API Endpoint Documentation

### Endpoint
**POST** `/api/attendance/sync`

### Request Headers
```
Content-Type: application/json
```

### Request Body
```json
{
  "local_uuid": "device-123-record-456",
  "employee_id": 1,
  "attendance_date": "2026-01-16",
  "sign_in_time": "08:30:00",
  "lunch_start_time": "12:00:00",
  "lunch_end_time": "13:00:00",
  "sign_out_time": "17:30:00",
  "sign_in_method": "QR Code",
  "lunch_out_method": "QR Code",
  "lunch_in_method": "QR Code",
  "sign_out_method": "QR Code",
  "status": "present",
  "notes": "Regular work day",
  "device_time": "2026-01-16 08:30:00"
}
```

### Required Fields
- `local_uuid` (string) - Unique per device record
- `employee_id` (integer) - Employee ID
- `attendance_date` (string) - Date in YYYY-MM-DD format

### Optional Fields
All other fields are optional and will be set to NULL if not provided.

---

## Response Examples

### Success Response (HTTP 200)
```json
{
  "status": "success",
  "message": "Attendance synced successfully"
}
```

### Duplicate Record (HTTP 200)
```json
{
  "status": "success",
  "message": "Already synced"
}
```

### Validation Error (HTTP 400)
```json
{
  "status": "error",
  "message": "local_uuid is required"
}
```

### Employee Not Found (HTTP 400)
```json
{
  "status": "error",
  "message": "Employee not found"
}
```

### Server Error (HTTP 500)
```json
{
  "status": "error",
  "message": "Server error occurred while syncing attendance"
}
```

---

## Key Logic Explanation

### 1. Duplicate Prevention
The API checks if a record with the same `local_uuid` already exists:
```php
$existingRecord = $this->attendanceModel
    ->where('local_uuid', $json['local_uuid'])
    ->first();

if ($existingRecord) {
    return response "Already synced";
}
```

### 2. Lunch Time Conversion
The mobile app sends `lunch_start_time` and `lunch_end_time`, which are converted to match the database schema:
- `lunch_start_time` → `lunch_out_time`
- `lunch_end_time` → `lunch_in_time`

### 3. Lunch Duration Calculation
If both lunch times are provided, the duration is automatically calculated in minutes:
```php
$lunchOutTime = new DateTime($attendance_date . ' ' . $lunch_out_time);
$lunchInTime = new DateTime($attendance_date . ' ' . $lunch_in_time);
$interval = $lunchOutTime->diff($lunchInTime);
$lunchDurationMinutes = ($interval->h * 60) + $interval->i;
```

### 4. Default Location
If `location_id` is not provided in the request, the system fetches the employee's default location from the employees table.

---

## Testing the API

### Using cURL
```bash
curl -X POST http://your-domain.com/api/attendance/sync \
  -H "Content-Type: application/json" \
  -d '{
    "local_uuid": "test-device-001",
    "employee_id": 1,
    "attendance_date": "2026-01-16",
    "sign_in_time": "08:30:00",
    "lunch_start_time": "12:00:00",
    "lunch_end_time": "13:00:00",
    "sign_out_time": "17:30:00",
    "sign_in_method": "QR Code",
    "status": "present"
  }'
```

### Using Postman
1. Method: POST
2. URL: `http://your-domain.com/api/attendance/sync`
3. Headers: `Content-Type: application/json`
4. Body (raw JSON): Use the example JSON above

---

## Security Notes

**IMPORTANT:** This endpoint currently has NO authentication. Consider adding:
1. API key authentication
2. IP whitelisting
3. Rate limiting
4. HTTPS requirement

For production use, you should implement proper API security measures.
