Geolocation Accuracy Enhancement Plan
Executive Summary
Problem Statement
The current geolocation system has a critical flaw in how it determines if tracker devices are within storage or delivery locations. The system uses exact point coordinates from location reports/history records, ignoring the confidence and horizontal_accuracy data that indicates the actual precision of GPS readings.
Current Issues:
- Point-in-polygon detection using exact coordinates
- Ignores
horizontal_accuracyfield (GPS precision in meters) - Ignores
confidencefield (signal quality indicator) - Frontend displays only point markers, suggesting exact positioning
- Users cannot assess location uncertainty
Solution Overview
Implement circle-to-circle intersection detection where:
- Tracker position becomes a circle with radius =
horizontal_accuracy - Geofence detection checks if accuracy circle intersects with location geofence
- Frontend displays both point markers and accuracy circles with purple styling
- Users can visually assess location precision
- Confidence values (1, 2, 3 from FindMy) may be used for future enhancements or ignored initially
Current System Analysis
Database Schema
Location Reports Table:
-- location_reports table already contains:
horizontal_accuracy FLOAT NULL -- GPS accuracy in meters
confidence INTEGER -- Signal confidence level
location GEOGRAPHY(POINT) -- Exact coordinates
Location History Table:
-- location_history table already contains:
horizontal_accuracy FLOAT NULL -- GPS accuracy in meters
confidence INTEGER -- Signal confidence level
location GEOGRAPHY(POINT) -- Exact coordinates
Geofence Tables:
-- delivery_locations & storage_locations contain:
geofence_size_meters INTEGER NOT NULL DEFAULT 100 -- Geofence radius
location GEOGRAPHY(POINT) -- Center point
Current Geofencing Logic
File: app/crud/location.py
# Current implementation - PROBLEMATIC
def get_nearby(self, db: Session, *, latitude: float, longitude: float, distance_meters: int = 1000):
point = func.ST_SetSRID(func.ST_MakePoint(longitude, latitude), 4326)
return db.query(DeliveryLocation).filter(
func.ST_DWithin(
DeliveryLocation.location,
point,
DeliveryLocation.geofence_size_meters,
)
).all()
Current Frontend Implementation
Files:
tracker-frontend/src/features/dashboard/components/TrackerMap.tsxtracker-admin/src/components/common/LocationMap.tsx
Current Colors:
- Blue: IN_TRANSIT trackers
- Green: DELIVERED trackers
- Orange: IN_STORAGE trackers
- Grey: CREATED trackers
- Green circles: Delivery location geofences
- Orange circles: Storage location geofences
Technical Implementation Plan
Phase 1: Backend Geospatial Logic Enhancement
1.1 Create Geospatial Service
File: app/services/geospatial_service.py
from typing import Optional, Tuple
from sqlalchemy import func
from sqlalchemy.orm import Session
class GeospatialService:
@staticmethod
def get_effective_accuracy(horizontal_accuracy: Optional[float], confidence: Optional[int]) -> float:
"""
Calculate effective accuracy radius considering confidence levels.
Args:
horizontal_accuracy: GPS reported accuracy in meters
confidence: FindMy confidence level (1, 2, or 3) - significance TBD
Returns:
Effective accuracy radius in meters
"""
# Default accuracy if none provided
base_accuracy = horizontal_accuracy or 10.0
# Note: Confidence values are 1, 2, or 3 from FindMy
# For now, we'll ignore confidence or apply minimal adjustment
# TODO: Investigate significance of FindMy confidence values (1=worst, 3=best?)
if confidence is not None:
if confidence == 1:
# Lowest confidence - slight increase in uncertainty
base_accuracy *= 1.2
elif confidence == 2:
# Medium confidence - minimal adjustment
base_accuracy *= 1.1
# confidence == 3: Highest confidence - use base accuracy
# Cap maximum accuracy at reasonable limit
return min(base_accuracy, 500.0)
@staticmethod
def check_tracker_in_geofence(
tracker_lat: float,
tracker_lng: float,
horizontal_accuracy: Optional[float],
confidence: Optional[int],
geofence_lat: float,
geofence_lng: float,
geofence_radius: float
) -> bool:
"""
Check if tracker accuracy circle intersects with geofence circle.
Returns True if circles intersect (tracker could be in geofence).
"""
effective_accuracy = GeospatialService.get_effective_accuracy(
horizontal_accuracy, confidence
)
# Use PostGIS to calculate if circles intersect
# Distance between centers <= sum of radii means intersection
return True # Implementation will use PostGIS ST_DWithin
@staticmethod
def get_nearby_locations_with_accuracy(
db: Session,
location_model, # DeliveryLocation or StorageLocation
tracker_lat: float,
tracker_lng: float,
horizontal_accuracy: Optional[float],
confidence: Optional[int]
):
"""
Get locations where tracker accuracy circle intersects geofence.
"""
effective_accuracy = GeospatialService.get_effective_accuracy(
horizontal_accuracy, confidence
)
tracker_point = func.ST_SetSRID(
func.ST_MakePoint(tracker_lng, tracker_lat), 4326
)
return db.query(location_model).filter(
func.ST_DWithin(
location_model.location,
tracker_point,
location_model.geofence_size_meters + effective_accuracy
)
).all()
1.2 Update CRUD Location Methods
File: app/crud/location.py
# Add import
from app.services.geospatial_service import GeospatialService
class CRUDDeliveryLocation(CRUDBase[DeliveryLocation, DeliveryLocationCreate, DeliveryLocationUpdate]):
def get_nearby_with_accuracy(
self,
db: Session,
*,
latitude: float,
longitude: float,
horizontal_accuracy: Optional[float] = None,
confidence: Optional[int] = None
) -> List[DeliveryLocation]:
"""Get delivery locations considering tracker accuracy."""
return GeospatialService.get_nearby_locations_with_accuracy(
db, DeliveryLocation, latitude, longitude, horizontal_accuracy, confidence
)
# Keep existing get_nearby for backward compatibility
def get_nearby(self, db: Session, *, latitude: float, longitude: float, distance_meters: int = 1000):
"""Legacy method - use get_nearby_with_accuracy for new code."""
return self.get_nearby_with_accuracy(db, latitude=latitude, longitude=longitude)
# Similar updates for CRUDStorageLocation
1.3 Update API Endpoints
Files: app/api/routes/delivery_locations.py, app/api/routes/storage_locations.py
Add new endpoints that accept accuracy parameters:
@router.get("/nearby-with-accuracy/")
def get_nearby_delivery_locations_with_accuracy(
latitude: float,
longitude: float,
horizontal_accuracy: Optional[float] = None,
confidence: Optional[int] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""Get delivery locations considering GPS accuracy."""
locations = delivery_location.get_nearby_with_accuracy(
db,
latitude=latitude,
longitude=longitude,
horizontal_accuracy=horizontal_accuracy,
confidence=confidence
)
return [
DeliveryLocationResponse(
id=loc.id,
name=loc.name,
coordinates=Coordinates(
latitude=loc.get_coordinates(db)["latitude"],
longitude=loc.get_coordinates(db)["longitude"]
),
geofence_size_meters=loc.geofence_size_meters,
production_run_id=loc.production_run_id
)
for loc in locations
]
Phase 2: Frontend Accuracy Visualization
2.1 Enhanced Tracker Markers
Color Scheme for Accuracy Circles:
- Purple (
#8B5CF6) - Distinct from existing colors, user preference - Semi-transparent (opacity: 0.15)
- Dashed border for differentiation from geofence circles
2.2 Update TrackerMap Component
File: tracker-frontend/src/features/dashboard/components/TrackerMap.tsx
// Add Circle import
import { Circle } from 'react-leaflet';
// Add accuracy circle rendering function
const renderAccuracyCircles = (trackers: any[]) => {
return trackers
.filter(tracker => tracker.horizontal_accuracy && tracker.lat && tracker.lng)
.map(tracker => (
<Circle
key={`accuracy-${tracker.id}`}
center={[tracker.lat, tracker.lng]}
radius={tracker.horizontal_accuracy}
pathOptions={{
color: '#8B5CF6',
fillColor: '#8B5CF6',
fillOpacity: 0.15,
weight: 2,
opacity: 0.6,
dashArray: '5, 5'
}}
/>
));
};
// Update MarkerClusterGroup component to include accuracy circles
function MarkerClusterGroup({ trackers, isDarkMode }) {
// ... existing marker logic ...
return (
<>
{/* Existing marker cluster logic */}
{/* Add accuracy circles */}
{renderAccuracyCircles(trackers)}
</>
);
}
2.3 Update Legend
Add accuracy circle explanation to map legend:
{/* Add to existing legend */}
<div className="flex items-center">
<div
className="w-3 h-3 border-2 border-purple-500 rounded-full mr-2"
style={{
backgroundColor: "rgba(139, 92, 246, 0.15)",
borderStyle: "dashed"
}}
></div>
<span className="text-xs text-gray-700 dark:text-gray-300">
GPS Accuracy
</span>
</div>
2.4 Update Admin Panel Maps
File: tracker-admin/src/components/common/LocationMap.tsx
Similar updates to include accuracy circles for nearby trackers.
2.5 Update Tracker History Modal
File: tracker-frontend/src/features/dashboard/components/TrackerHistoryModal.tsx
Add accuracy circles to historical location display.
Phase 3: API Response Updates
3.1 Include Accuracy Data in Responses
Files: app/schemas/tracker.py, app/api/routes/trackers/location_history.py
# Update LocationHistoryResponse schema
class LocationHistoryResponse(BaseModel):
id: int
timestamp: datetime
coordinates: Coordinates
nearest_city: Optional[str] = None
horizontal_accuracy: Optional[float] = None # Add this
confidence: Optional[int] = None # Add this
class Config:
from_attributes = True
3.2 Update Tracker Detail Endpoints
Ensure all location-related endpoints return accuracy data:
# In tracker detail responses
{
"latest_location": {
"coordinates": {"latitude": 51.5074, "longitude": -0.1278},
"horizontal_accuracy": 15.5,
"confidence": 3, # FindMy confidence level (1, 2, or 3)
"timestamp": "2025-01-07T12:00:00Z"
}
}
Phase 4: Database Optimizations
4.1 Handle Null Accuracy Values
Migration Script: alembic/versions/xxx_set_default_accuracy.py
def upgrade():
# Set reasonable defaults for null horizontal_accuracy
op.execute("""
UPDATE location_reports
SET horizontal_accuracy = 10.0
WHERE horizontal_accuracy IS NULL
""")
op.execute("""
UPDATE location_history
SET horizontal_accuracy = 10.0
WHERE horizontal_accuracy IS NULL
""")
def downgrade():
# Revert changes if needed
pass
4.2 Add Computed Indexes (Optional)
-- Index for geospatial queries with accuracy
CREATE INDEX idx_location_reports_accuracy_geom
ON location_reports USING GIST (location, horizontal_accuracy);
CREATE INDEX idx_location_history_accuracy_geom
ON location_history USING GIST (location, horizontal_accuracy);
Phase 5: Testing Strategy
5.1 Unit Tests
File: tests/services/test_geospatial_service.py
import pytest
from app.services.geospatial_service import GeospatialService
class TestGeospatialService:
def test_get_effective_accuracy_default(self):
"""Test default accuracy when none provided."""
accuracy = GeospatialService.get_effective_accuracy(None, None)
assert accuracy == 10.0
def test_get_effective_accuracy_low_confidence(self):
"""Test accuracy adjustment for low confidence (FindMy confidence = 1)."""
accuracy = GeospatialService.get_effective_accuracy(10.0, 1)
assert accuracy == 12.0 # 1.2x multiplier for lowest confidence
def test_get_effective_accuracy_medium_confidence(self):
"""Test accuracy adjustment for medium confidence (FindMy confidence = 2)."""
accuracy = GeospatialService.get_effective_accuracy(10.0, 2)
assert accuracy == 11.0 # 1.1x multiplier for medium confidence
def test_get_effective_accuracy_high_confidence(self):
"""Test accuracy with high confidence (FindMy confidence = 3)."""
accuracy = GeospatialService.get_effective_accuracy(10.0, 3)
assert accuracy == 10.0 # No adjustment for highest confidence
def test_accuracy_cap(self):
"""Test maximum accuracy cap."""
accuracy = GeospatialService.get_effective_accuracy(1000.0, 1)
assert accuracy == 500.0 # Capped at maximum even with low confidence
5.2 Integration Tests
File: tests/api/routes/test_delivery_locations_accuracy.py
def test_get_nearby_with_accuracy(client, db_session, sample_delivery_location):
"""Test accuracy-aware geofence detection."""
# Test case where point is outside geofence but accuracy circle intersects
response = client.get(
"/api/v1/delivery-locations/nearby-with-accuracy/",
params={
"latitude": 51.5074, # Just outside geofence
"longitude": -0.1278,
"horizontal_accuracy": 50.0, # Large enough to intersect
"confidence": 2 # FindMy confidence level (1, 2, or 3)
}
)
assert response.status_code == 200
assert len(response.json()) > 0 # Should find location due to accuracy
5.3 Frontend Tests
File: tracker-frontend/src/features/dashboard/components/__tests__/TrackerMap.test.tsx
describe('TrackerMap Accuracy Circles', () => {
it('renders accuracy circles for trackers with horizontal_accuracy', () => {
const trackersWithAccuracy = [
{
id: 1,
lat: 51.5074,
lng: -0.1278,
horizontal_accuracy: 25.5,
status: 'IN_TRANSIT'
}
];
render(<TrackerMap trackers={trackersWithAccuracy} />);
// Check for accuracy circle
expect(screen.getByTestId('accuracy-circle-1')).toBeInTheDocument();
});
});
Deployment Considerations
Migration Strategy
- Phase 1: Deploy backend changes with feature flag
- Phase 2: Deploy frontend changes (backward compatible)
- Phase 3: Enable accuracy-aware geofencing gradually
- Phase 4: Monitor performance and adjust
Rollback Plan
- Keep existing
get_nearby()methods for backward compatibility - Feature flag to switch between old/new geofencing logic
- Database changes are additive (no data loss)
Performance Monitoring
- Monitor geospatial query performance
- Track accuracy circle rendering performance
- Monitor API response times
Configuration
Environment Variables:
# Feature flags
ENABLE_ACCURACY_GEOFENCING=true
DEFAULT_GPS_ACCURACY=10.0
MAX_GPS_ACCURACY=500.0
# Performance tuning
GEOFENCE_QUERY_TIMEOUT=5000
ACCURACY_CIRCLE_MAX_ZOOM=15
Success Metrics
Technical Metrics
- Geofencing accuracy improvement (measured against known test cases)
- API response time impact (should be < 20% increase)
- Frontend rendering performance (accuracy circles)
User Experience Metrics
- Reduced false positive/negative geofence detections
- User understanding of location uncertainty
- Support ticket reduction related to "incorrect" location detection
Future Enhancements
Phase 6: Advanced Features (Future)
- Confidence-based styling: Different circle styles based on confidence levels
- Historical accuracy trends: Show accuracy improvement over time
- Accuracy-based alerts: Warn when accuracy is too low for reliable geofencing
- Machine learning: Predict accuracy based on environmental factors
Phase 7: Analytics (Future)
- Accuracy statistics: Dashboard showing GPS accuracy trends
- Geofence effectiveness: Metrics on geofence detection reliability
- Location quality scoring: Overall location data quality metrics
Implementation Timeline
Week 1-2: Phase 1 (Backend geospatial service) Week 3: Phase 2 (Frontend accuracy circles) Week 4: Phase 3 (API updates and testing) Week 5: Phase 4 (Database optimizations) Week 6: Phase 5 (Comprehensive testing and deployment)
Conclusion
This enhancement addresses a fundamental flaw in the current geolocation system by properly accounting for GPS accuracy limitations. The solution provides:
- More accurate geofencing through circle-to-circle intersection
- Better user understanding through accuracy visualization
- Backward compatibility with existing systems
- Scalable architecture for future enhancements
The implementation is designed to be deployed incrementally with minimal risk and maximum benefit to location-based functionality.