# Branch Geofence Guide ## Purpose Branch geofencing restricts mobile attendance to an employee's assigned work location. Each branch under a brand can have its own polygon boundary. When an employee taps **Time In** or **Time Out**, the application captures one fresh GPS reading and checks it against the assigned branch boundary. The application does not continuously track employees. ## Data model Each employee is connected to a branch through `employees.branch_id`. The branch belongs to a company and brand and stores its own location and boundary. ```text Company `-- Brand |-- Branch A -> geofence A |-- Branch B -> geofence B `-- Branch C -> geofence C Employee -> assigned branch -> branch geofence used for attendance ``` Required branch columns: ```sql ALTER TABLE branches ADD COLUMN IF NOT EXISTS geofence_location VARCHAR(255) NULL, ADD COLUMN IF NOT EXISTS geofence_polygon JSON NULL, ADD COLUMN IF NOT EXISTS latitude DECIMAL(10,8) NULL, ADD COLUMN IF NOT EXISTS longitude DECIMAL(11,8) NULL; ``` Field definitions: | Field | Purpose | | --- | --- | | `geofence_location` | Human-readable address selected from map search | | `geofence_polygon` | JSON list of `[latitude, longitude]` boundary coordinates | | `latitude` | Selected map location latitude and marker position | | `longitude` | Selected map location longitude and marker position | Example polygon: ```json [ [8.48319612, 124.66406196], [8.48302102, 124.66510132], [8.48400841, 124.66534018], [8.48420975, 124.66420374] ] ``` ## Administrator workflow 1. Open **Admin Account Settings**. 2. Open **Brand & Branch Management**. 3. Expand the applicable brand. 4. Add a branch or edit an existing branch. 5. Enter a place, landmark, or address in **Geofence Location**. 6. Open **Draw Polygon** or **Edit Polygon**. 7. Search for the exact location and select a result. 8. Draw the permitted attendance boundary on the map. 9. Complete the polygon using the Leaflet drawing controls. 10. Save the branch. Reopening the branch map displays the saved marker and polygon. ## Attendance workflow When an employee taps **Time In** or **Time Out**: 1. The application asks for location permission. 2. The browser captures one fresh, high-accuracy GPS reading. 3. The frontend sends latitude, longitude, and reported accuracy to the attendance API. 4. The backend loads the employee's `branch_id`. 5. The backend loads that branch's polygon and coordinates. 6. The backend checks whether the GPS point is inside the polygon. 7. If accepted, attendance processing continues. 8. If rejected, the API returns HTTP `403` and attendance is not recorded. The backend performs the authoritative check. Client-side values cannot override the assigned branch boundary. ## Branch and brand fallback rules Geofence selection follows this priority: 1. Assigned branch polygon 2. Assigned branch coordinate radius 3. Brand polygon 4. Brand coordinate radius 5. No configured boundary: allow attendance without a geofence restriction Once a branch polygon or complete branch coordinates are configured, the employee is checked against the branch rather than another branch under the same brand. ## GPS accuracy tolerance Phone GPS readings may drift near walls, roofs, or polygon edges. The backend therefore: - accepts points directly inside the polygon; - accepts points close to an edge using the browser's reported GPS accuracy; - limits the boundary tolerance to a minimum of 15 meters and a maximum of 75 meters; - rejects points clearly outside the boundary. The tolerance is calculated once for each attendance button click. It is not real-time tracking. ## Important backend files | File | Responsibility | | --- | --- | | `backend/brand_api/create_branch.php` | Validates and stores new branch geofence data | | `backend/brand_api/update_branch.php` | Updates branch location, coordinates, and polygon | | `backend/brand_api/read_brands.php` | Returns saved geofence data to the administrator UI | | `backend/brand_api/search_locations.php` | Authenticated address and place search endpoint | | `backend/brand_api/geocoding.php` | OpenStreetMap Nominatim integration | | `backend/mobile/time_in/geofence_helper.php` | Polygon, distance, and GPS-tolerance calculations | | `backend/mobile/time_in/create_attendance.php` | Enforces geofencing on the first attendance record | | `backend/mobile/time_in/update_attendance.php` | Enforces geofencing on later punches | ## Important frontend files | File | Responsibility | | --- | --- | | `frontend/src/features/brandManagement/components/GeofenceMap.jsx` | Map search, marker, polygon drawing, editing, and restoration | | `frontend/src/features/brandManagement/components/BranchFormModal.jsx` | Branch creation geofence form | | `frontend/src/features/brandManagement/components/EditBranchModal.jsx` | Branch geofence editing form | | `frontend/src/features/brandManagement/api/brandApi.js` | Branch and location-search API calls | | `frontend/src/mobile/utils/requestEmployeeLocation.js` | Captures one fresh browser GPS reading | | `frontend/src/mobile/employee/Time_IN_OUT/Emp_TIO_Component/Emp_TIO_page.jsx` | Starts location verification when Time In/Out is clicked | ## CORS configuration When the frontend and backend use different origins, the backend must explicitly allow the frontend origin. Example development configuration in `backend/.env`: ```env CORS_ALLOWED_ORIGINS=https://your-production-frontend.example,http://localhost:5173 CORS_ALLOW_LOCALHOST=true ``` Do not use `*` because authenticated requests use credentials and authorization headers. ## Deployment checklist - Apply the required database columns. - Deploy all changed frontend and backend files. - Configure the production backend's allowed CORS origins. - Confirm PHP cURL can access `nominatim.openstreetmap.org`. - Build and deploy the frontend. - Clear old PWA/browser caches after deployment. - Confirm every geofenced employee has the correct `branch_id`. - Confirm the assigned branch is active and has a valid polygon. ## Verification queries Check an employee's branch assignment: ```sql SELECT e.employee_id, e.company_id, e.brand_id, e.branch_id, b.branch_name, b.geofence_location, b.geofence_polygon, b.latitude, b.longitude FROM employees e LEFT JOIN branches b ON b.branch_id = e.branch_id AND b.company_id = e.company_id AND b.brand_id = e.brand_id WHERE e.employee_id = '123456'; ``` Find branches missing a polygon: ```sql SELECT branch_id, brand_id, branch_name, geofence_location FROM branches WHERE is_active = 1 AND geofence_polygon IS NULL; ``` ## Acceptance tests For each branch, test using an employee assigned to that branch: 1. **Inside polygon:** Time In succeeds. 2. **Near polygon edge:** Time In succeeds when within the capped GPS accuracy tolerance. 3. **Clearly outside polygon:** Time In returns `403` and creates no attendance record. 4. **Location denied:** The frontend does not submit attendance. 5. **Wrong branch:** An employee near another branch but outside the assigned branch is rejected. 6. **Reopen branch:** The saved marker and polygon appear in Edit Branch. 7. **Time Out:** The same branch check is enforced when updating attendance. ## Troubleshooting ### Saved polygon does not appear - Confirm `geofence_polygon` contains valid JSON with at least three coordinate pairs. - Deploy the latest `GeofenceMap.jsx` lifecycle fix. - Rebuild the frontend and hard-refresh to replace cached PWA assets. ### Employee is rejected while inside - Confirm the employee has the expected `branch_id`. - Confirm the branch polygon encloses the physical work area. - Enable precise location permission on the phone. - Disable device battery-saving location restrictions. - Test outdoors or near a window to improve the first GPS fix. - Confirm the latest accuracy-tolerance backend files are deployed. ### Employee outside the branch can clock in - Deploy both attendance endpoints and `geofence_helper.php` together. - Confirm the branch polygon is not `NULL`. - Confirm the employee is assigned to the intended branch. - Ensure no older endpoint or cached frontend build is being used. ### Location search has no response - Confirm the frontend origin is allowed by backend CORS configuration. - Confirm the search endpoint is deployed on the backend host used by the frontend. - Confirm PHP cURL and outbound HTTPS access are available. ## Privacy and security - Location is requested only after the employee initiates Time In/Out. - The application does not continuously monitor employee movement. - The backend, not the frontend, decides whether attendance is accepted. - Authentication and company/brand/branch relationships must remain enforced. - Attendance coordinates should be retained only as required by company policy and applicable privacy rules.