Use Case: Geographical Location Tracking (LAT/LON)
Use Case: Geographical Location Tracking (LAT/LON)
Overview
This use case describes how the Plings system can capture and store geographical coordinates (latitude/longitude) for objects during creation, enabling location-based discovery and “near me” functionality for outdoor, mobile, or uncontained objects.
User Story
As a user, I want to store the geographical location where objects are created or located so that I can discover objects near my current location or search for items in specific geographical areas.
Business Value
- Spatial Discovery: Find objects based on geographical proximity (“tools near me”)
- Location Context: Understand where objects were created or last seen
- Outdoor Object Management: Track items in large outdoor spaces (construction sites, parks, farms)
- Mobile Asset Tracking: Monitor equipment that moves between geographical locations
- Emergency Response: Quickly locate critical equipment during emergencies
Current System Integration
Existing Foundation
The Plings system already has some geographical components:
- ✅ ScanEvent Location:
ScanEventnodes track lat/lon of tag scans - ✅ Spatial System: Comprehensive relative positioning (IN, ON, LEFT_OF, etc.)
- ✅ Object Creation Flow: Established CreateObjectModal workflow
- ✅ Mobile Architecture: Mobile-responsive object creation interface
Integration with Spatial Relationships
Complementary Systems: Geographical coordinates complement rather than replace spatial relationships:
- Relative Positioning: Objects maintain
IN,ON,NEXT_TOrelationships for local spatial context - Absolute Positioning: Objects gain
latitude,longitudefor global geographical context - Hierarchy Integration: Containers can have geographical coordinates that child objects inherit
- Multi-Scale Navigation: Users can navigate from global map view to detailed spatial relationships
Workflow Steps
Step 1: Location Permission Request
- Trigger: User opens CreateObjectModal
- Browser API: Request
navigator.geolocation.getCurrentPosition() - User Experience:
📍 Location Access Plings would like to store the location where this object is created. [Allow] [Deny] [Ask Each Time] - Privacy: Clear explanation of location data usage
Step 2: Location Detection and Display
Success Path:
navigator.geolocation.getCurrentPosition((position) => {
const { latitude, longitude, accuracy } = position.coords;
// Display: "📍 Current Location: 59.3293°N, 18.0686°E (±10m)"
});
User Interface:
📍 Location: Stockholm, Sweden
📍 Coordinates: 59.3293°N, 18.0686°E
🎯 Accuracy: ±10 meters
[📍 Use Current] [🌍 Select on Map] [❌ No Location]
Step 3: Location Options and Overrides
Location Source Options:
- Current GPS: Use device’s current location
- Manual Entry: User enters coordinates or address
- Map Selection: Interactive map picker for precise placement
- Inherited Location: Use parent container’s location for indoor objects
- No Location: Skip geographical tracking for indoor/contained objects
Override Scenarios:
- Creating Historic Records: Object was located elsewhere previously
- Indoor Objects: Skip geo-location for items with clear spatial containers
- Privacy Sensitive: User chooses not to share location for certain objects
Step 4: Location Storage and Validation
Data Validation:
interface GeographicalLocation {
latitude: number; // -90 to +90
longitude: number; // -180 to +180
accuracy?: number; // meters
altitude?: number; // meters above sea level
capturedAt: string; // ISO 8601 timestamp
source: 'gps' | 'manual' | 'map' | 'inherited' | 'estimated';
address?: string; // Reverse-geocoded human-readable address
}
Storage Integration:
- Neo4j ObjectInstance: Add geographical properties to nodes
- Supabase Metadata: Store location metadata for querying and indexing
- Privacy Controls: Respect user location sharing preferences
Step 5: Location-Based Discovery
“Near Me” Functionality:
// Find objects within radius of current location
const nearbyObjects = await findObjectsNear({
latitude: userLocation.lat,
longitude: userLocation.lon,
radiusKm: 5,
objectTypes: ['tools', 'equipment'],
organizationId: currentOrg.id
});
Distance Calculation:
// Haversine formula for distance between coordinates
function calculateDistance(lat1, lon1, lat2, lon2) {
const R = 6371; // Earth's radius in kilometers
const dLat = toRadians(lat2 - lat1);
const dLon = toRadians(lon2 - lon1);
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c; // Distance in kilometers
}
Use Cases and Scenarios
Use Case 1: Construction Site Equipment
Scenario: Construction project with equipment spread across large outdoor area
- Creation: Bulldozer created with GPS coordinates when delivered to site
- Discovery: Foreman searches “heavy equipment near Building A coordinates”
- Tracking: Equipment location updated when moved to different site areas
- Reporting: Generate location-based equipment utilization reports
Use Case 2: Outdoor Event Management
Scenario: Festival organizer tracking assets across event grounds
- Setup Phase: Speakers, lighting, generators placed and GPS-tagged
- Event Phase: Staff can find nearest backup equipment by location
- Breakdown: Recovery teams locate all equipment for removal
- Analysis: Heat maps showing equipment density and usage patterns
Use Case 3: Agricultural Equipment
Scenario: Farm with equipment distributed across multiple fields
- Seasonal Storage: Tractors, implements stored in different field locations
- Work Planning: Find implements near specific field coordinates
- Maintenance: Locate equipment for scheduled service visits
- Weather Response: Quickly secure equipment before storms
Use Case 4: Emergency Response
Scenario: Emergency services managing equipment across jurisdiction
- Resource Deployment: Find nearest medical equipment to incident location
- Mutual Aid: Share equipment locations with neighboring departments
- Inventory Management: Track equipment across multiple stations/locations
- Response Optimization: Analyze equipment placement effectiveness
Use Case 5: Found and Lost Object Management
Scenario: Community members documenting found, lost, or misplaced objects
- Found Items: User finds abandoned bicycle and logs its location for potential owner recovery
- Lost Object Reporting: User reports missing laptop with last known location
- Public Objects: Document location of public resources (benches, water fountains, charging stations)
- Recovery Networks: Enable community-based object recovery efforts
Use Case 6: Environmental and Conservation Tracking
Scenario: Environmental monitoring and waste management
- Litter Documentation: Volunteers log trash locations for cleanup coordination
- Recycling Points: Map recycling centers and waste collection points
- Natural Resource Monitoring: Track environmental objects and their conditions
- Conservation Efforts: Document wildlife equipment, trail markers, research instruments
Use Case 7: Commercial and Public Space Objects
Scenario: Tracking objects in commercial or public environments
- Store Visits: Document interesting products or services encountered while shopping
- Public Infrastructure: Map public amenities, facilities, and services
- Business Resources: Track equipment or tools available at different locations
- Shared Resources: Community tool libraries, equipment sharing programs
Use Case 8: Tool Discovery and Sharing Economy
Scenario: Finding tools and equipment available for purchase, rent, or borrowing based on proximity
- Immediate Need: “I need a drill right now” - discover drills available within walking distance
- Multi-Source Discovery: Single search shows tools from:
- Retail Stores: Tools for purchase at nearby hardware stores
- Rental Services: Professional tool rental shops in the area
- Peer-to-Peer: Neighbors willing to lend tools through sharing platforms
- Community Resources: Tool libraries and maker spaces
- Availability Filtering: Filter by immediate availability, price range, rental terms
- Distance-Based Decisions: Compare options based on proximity vs. cost trade-offs
Example User Journey:
- User searches: “power drill near me”
- System returns sorted by distance:
- “John’s DeWalt Drill - 200m away - Available to borrow”
- “Home Depot - 800m away - $89 purchase”
- “Tool Library - 1.2km away - Free with membership”
- “Rent-A-Tool - 2.5km away - $15/day rental”
- User can filter by:
- Acquisition type (buy/rent/borrow)
- Maximum distance willing to travel
- Price range or free options only
- User ratings and tool condition
- Integration with object status system:
- Shows real-time availability
- Indicates if tool is currently in use
- Estimated return time for borrowed items
Technical Implementation Strategy
Frontend Location Capture
Enhanced CreateObjectModal:
const LocationSection = () => {
const [location, setLocation] = useState<GeographicalLocation | null>(null);
const [locationStatus, setLocationStatus] = useState<'detecting' | 'found' | 'denied' | 'manual'>('detecting');
const requestLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
setLocation({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
accuracy: position.coords.accuracy,
capturedAt: new Date().toISOString(),
source: 'gps'
});
setLocationStatus('found');
},
(error) => {
console.error('Location access denied:', error);
setLocationStatus('denied');
}
);
}
};
return (
<div className="location-section">
{locationStatus === 'detecting' && (
<div className="location-detecting">
<GpsIcon className="animate-pulse" />
<span>Detecting location...</span>
</div>
)}
{locationStatus === 'found' && location && (
<div className="location-found">
<MapPinIcon />
<span>{formatCoordinates(location.latitude, location.longitude)}</span>
<Badge variant="secondary">±{location.accuracy}m</Badge>
<Button variant="outline" onClick={() => setLocationStatus('manual')}>
Change Location
</Button>
</div>
)}
{locationStatus === 'denied' && (
<div className="location-denied">
<MapPinOffIcon />
<span>Location access denied</span>
<Button onClick={() => setLocationStatus('manual')}>
Enter Manually
</Button>
</div>
)}
{locationStatus === 'manual' && (
<ManualLocationEntry
onLocationSet={setLocation}
onCancel={() => setLocationStatus('denied')}
/>
)}
</div>
);
};
Backend Database Extensions
Architecture Alignment: Following Plings database architecture rules where PostgreSQL stores metadata/audit trails and Neo4j stores graph data used for queries.
Neo4j ObjectInstance Enhancement:
// Enhanced ObjectInstance node with geographical properties
CREATE (obj:ObjectInstance {
id: $objectId,
name: $name,
description: $description,
statuses: $statuses,
owner: $owner,
// Geographical properties
latitude: $latitude,
longitude: $longitude,
location_accuracy: $accuracy,
location_captured_at: $capturedAt,
location_source: $locationSource,
location_address: $address
})
PostgreSQL Location Events Table (for audit trail):
-- Create location_events table for location history and audit
CREATE TABLE location_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
object_instance_id UUID REFERENCES object_instances(id) NOT NULL,
event_type TEXT NOT NULL CHECK (event_type IN ('created', 'updated', 'manual_override', 'inherited')),
latitude DECIMAL(10, 8) NOT NULL,
longitude DECIMAL(11, 8) NOT NULL,
accuracy INTEGER, -- meters
altitude INTEGER, -- meters above sea level
source TEXT NOT NULL CHECK (source IN ('gps', 'manual', 'map', 'inherited', 'estimated')),
address TEXT,
captured_by UUID REFERENCES profiles(id) NOT NULL,
captured_at TIMESTAMPTZ DEFAULT now(),
device_info JSONB, -- optional device/browser info
-- Indexes for performance
INDEX idx_location_events_object (object_instance_id),
INDEX idx_location_events_captured_at (captured_at DESC)
);
-- RLS policy for location_events
CREATE POLICY location_events_access ON location_events
FOR ALL USING (
object_instance_id IN (
SELECT id FROM object_instances
-- Inherits RLS from object_instances
)
);
Note: The primary location data lives in Neo4j for graph-based proximity queries, while PostgreSQL maintains the audit trail and location history. This follows the existing pattern used by ScanEvent nodes which store lat/lon in Neo4j.
GraphQL Schema Extensions
New Types and Operations:
# Location Types
type GeographicalLocation {
latitude: Float!
longitude: Float!
accuracy: Int
altitude: Int
capturedAt: String!
source: LocationSource!
address: String
}
enum LocationSource {
GPS
MANUAL
MAP
INHERITED
ESTIMATED
}
# Enhanced Object Creation
input CreateObjectInput {
name: String!
description: String
ownerOrgId: ID!
statuses: [String!]
photos: [Upload!]
location: GeographicalLocationInput # NEW
}
input GeographicalLocationInput {
latitude: Float!
longitude: Float!
accuracy: Int
altitude: Int
source: LocationSource!
address: String
}
# Location-based Queries
type Query {
objectsNear(
latitude: Float!
longitude: Float!
radiusKm: Float!
filters: ObjectFilters
): [ObjectInstance!]!
objectsInBounds(
northEast: LatLngInput!
southWest: LatLngInput!
filters: ObjectFilters
): [ObjectInstance!]!
# Tool Discovery Query - NEW
findToolsNear(
latitude: Float!
longitude: Float!
radiusKm: Float!
toolQuery: String!
acquisitionTypes: [AcquisitionType!]
maxPrice: Float
availableOnly: Boolean = true
): [ToolAvailabilityResult!]!
}
input LatLngInput {
latitude: Float!
longitude: Float!
}
# Tool Discovery Types - NEW
type ToolAvailabilityResult {
object: ObjectInstance!
distance: Float! # Distance in meters
acquisitionOptions: [AcquisitionOption!]!
availability: ToolAvailability!
userRating: Float
estimatedTravelTime: Int # Minutes walking/driving
}
type AcquisitionOption {
type: AcquisitionType!
price: Float
currency: String
terms: String # "per day", "per hour", "one-time", etc.
provider: AcquisitionProvider!
contactInfo: ContactInfo
immediateAvailability: Boolean!
}
type AcquisitionProvider {
id: ID!
name: String!
type: ProviderType!
rating: Float
trustScore: Int
responseTime: String # "Usually responds within 1 hour"
}
type ToolAvailability {
status: AvailabilityStatus!
availableUntil: String # ISO datetime
nextAvailable: String # ISO datetime if currently unavailable
currentUser: String # Who has it now if borrowed
estimatedReturnTime: String # When expected back
}
enum AcquisitionType {
BUY
RENT
BORROW
FREE_USE
}
enum ProviderType {
PRIVATE_OWNER
RETAIL_STORE
RENTAL_SERVICE
COMMUNITY_LIBRARY
MAKER_SPACE
SHARING_PLATFORM
}
enum AvailabilityStatus {
AVAILABLE
IN_USE
RESERVED
MAINTENANCE
UNAVAILABLE
}
type ContactInfo {
method: ContactMethod!
value: String!
preferredHours: String
}
enum ContactMethod {
PHONE
EMAIL
IN_APP_MESSAGE
WALK_IN
WEBSITE
}
# Enhanced Object with Location
type ObjectInstance {
id: ID!
name: String!
description: String
location: GeographicalLocation # NEW
spatialParent: SpatialRef
spatialHierarchy: [SpatialRef!]!
# Tool sharing extensions
acquisitionOptions: [AcquisitionOption!]! # NEW
availability: ToolAvailability # NEW
# ... existing fields
}
Location-Based Search Implementation
Backend Resolver for Proximity Search:
async def resolve_objects_near(self, info, latitude: float, longitude: float, radius_km: float, filters=None):
"""
Find objects within specified radius of given coordinates
Uses Neo4j for spatial queries since location data lives in the graph
"""
# Neo4j Cypher query for proximity search using Haversine formula
query = """
MATCH (obj:ObjectInstance)
WHERE obj.latitude IS NOT NULL AND obj.longitude IS NOT NULL
WITH obj,
point.distance(
point({latitude: $latitude, longitude: $longitude}),
point({latitude: obj.latitude, longitude: obj.longitude})
) AS distance
WHERE distance <= $radius_meters
RETURN obj.id AS id,
obj.name AS name,
obj.latitude AS latitude,
obj.longitude AS longitude,
distance
ORDER BY distance
LIMIT 100
"""
radius_meters = radius_km * 1000
# Execute Neo4j query
async with info.context["neo4j_driver"].session() as session:
result = await session.run(
query,
latitude=latitude,
longitude=longitude,
radius_meters=radius_meters
)
neo4j_objects = [dict(record) async for record in result]
# Enrich with PostgreSQL metadata if needed
object_ids = [obj['id'] for obj in neo4j_objects]
if object_ids:
pg_query = """
SELECT id, name, description, owner_organization_id, main_image_url
FROM object_instances
WHERE id = ANY($1)
"""
pg_objects = await db.fetch(pg_query, object_ids)
# Merge Neo4j location data with PostgreSQL metadata
return merge_location_with_metadata(neo4j_objects, pg_objects)
return []
User Interface Design
Location Display Components
1. Location Capture Interface
┌─────────────────────────────────────┐
│ 📍 Object Location │
│ │
│ ○ Use current location (📡 GPS) │
│ ○ Enter coordinates manually │
│ ○ Select on map │
│ ○ Skip location (indoor object) │
│ │
│ [📍 Detect Location] │
└─────────────────────────────────────┘
2. Location Status Display
┌─────────────────────────────────────┐
│ 📍 Location Detected │
│ │
│ Coordinates: 59.3293°N, 18.0686°E │
│ Address: Stockholm, Sweden │
│ Accuracy: ±10 meters │
│ Source: GPS │
│ │
│ [🗺️ View on Map] [✏️ Edit] [❌ Remove] │
└─────────────────────────────────────┘
3. Tool Discovery Widget
┌─────────────────────────────────────┐
│ 🔧 Find Tools Near You │
│ │
│ 🔍 [Search for tools... ] 📍 │
│ │
│ Recent: drill, ladder, saw │
│ [🎯 200m] [💰 <$20] [⚡ Available] │
└─────────────────────────────────────┘
4. Tool Search Results
┌─────────────────────────────────────┐
│ 🔧 "power drill" near you │
│ │
│ 📍 John's DeWalt Drill • 200m │
│ 🆓 Borrow • ⭐ 4.9 • Available now │
│ [💬 Message John] [📍 Directions] │
│ │
│ 📍 Home Depot • 800m │
│ 💰 $89 Purchase • ⭐ 4.2 • Open │
│ [🌐 Visit Store] [📍 Directions] │
│ │
│ 📍 Tool Library • 1.2km │
│ 🆓 Free w/ membership • ⭐ 4.7 │
│ [ℹ️ Learn More] [📍 Directions] │
│ │
│ [Show 4 more results...] │
└─────────────────────────────────────┘
5. Nearby Objects Widget
┌─────────────────────────────────────┐
│ 🗺️ Objects Near You │
│ │
│ 📍 Drill Set (50m away) │
│ 📍 Safety Equipment (120m away) │
│ 📍 Generator (300m away) │
│ │
│ [View All on Map] │
└─────────────────────────────────────┘
4. Map Integration Component
const ObjectLocationMap = ({ objects, userLocation }) => {
return (
<div className="object-map">
<MapContainer center={[userLocation.lat, userLocation.lng]} zoom={13}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
{/* User location marker */}
<Marker position={[userLocation.lat, userLocation.lng]}>
<Popup>Your current location</Popup>
</Marker>
{/* Object markers */}
{objects.map(object => (
<Marker key={object.id} position={[object.latitude, object.longitude]}>
<Popup>
<div>
<h3>{object.name}</h3>
<p>Distance: {calculateDistance(userLocation, object)}m</p>
<Button onClick={() => viewObject(object.id)}>View Details</Button>
</div>
</Popup>
</Marker>
))}
</MapContainer>
</div>
);
};
Privacy and Security Considerations
Location Privacy Controls
User Preferences:
interface LocationPrivacySettings {
enableLocationTracking: boolean;
requireConfirmationPerObject: boolean;
shareLocationWithOrganization: boolean;
retainLocationHistory: boolean;
precisionLevel: 'precise' | 'approximate' | 'city' | 'region';
}
Organization-Level Controls:
- Admin Settings: Organization admins can require or disable location tracking
- Data Retention: Configurable retention periods for location data
- Access Controls: Who can view object locations within organization
- Export Restrictions: Control over location data in exports and reports
Security Implementation
Data Protection:
- HTTPS Only: All location data transmitted over encrypted connections
- Database Encryption: Location coordinates encrypted at rest
- Access Logging: Audit trail of location data access
- Geographic Restrictions: Optional geofencing for sensitive locations
Privacy by Design:
- Opt-in Only: Location tracking disabled by default
- Clear Consent: Explicit user consent for location collection
- Granular Control: Per-object location sharing decisions
- Data Minimization: Only collect necessary location precision
Performance Optimization
Location Query Performance
Database Optimization:
- Neo4j Spatial Indexes: Point indexes on latitude/longitude properties for fast proximity queries
- Graph Traversal: Combine location queries with spatial relationships (IN, ON, etc.)
- Query Caching: Cache frequent location-based searches at API level
- Batched Updates: Group location updates when modifying multiple objects
- Selective Loading: Only fetch location properties when explicitly requested
Frontend Optimization:
- Location Caching: Cache user location to avoid repeated GPS requests
- Debounced Queries: Prevent excessive API calls during map interaction
- Progressive Loading: Load nearby objects incrementally as user explores
- Offline Support: Cache location data for offline object creation
Mobile Performance
GPS Optimization:
- Timeout Management: Fallback to last known location if GPS slow
- Battery Conservation: Minimize GPS usage through smart caching
- Network Efficiency: Compress location data in API requests
- Background Processing: Location detection while user fills other fields
Analytics and Insights
Location-Based Analytics
Usage Metrics:
- Location Adoption Rate: Percentage of objects with geographical data
- Search Patterns: Most common location-based search queries
- Discovery Effectiveness: Success rate of “near me” searches
- Geographic Distribution: Heat maps of object density
Business Intelligence:
- Asset Utilization: Equipment usage patterns by geographical area
- Efficiency Analysis: Travel time savings from location-based discovery
- Coverage Assessment: Identification of under-served geographical areas
- Demand Forecasting: Predict equipment needs by location and time
Success Metrics
User Experience Metrics
- Location Capture Rate: % of objects created with geographical coordinates
- Search Success Rate: % of location-based searches that find relevant objects
- Time to Discovery: Average time to locate objects using geographical search
- User Satisfaction: Feedback on location-based features
Technical Performance Metrics
- GPS Accuracy: Average accuracy of captured location coordinates
- Query Performance: Response time for proximity-based object searches
- Battery Impact: GPS usage impact on mobile device battery life
- Data Quality: Completeness and accuracy of geographical metadata
Business Impact Metrics
- Operational Efficiency: Reduction in time spent physically searching for objects
- Asset Recovery: Improved success rate in locating misplaced equipment
- Cost Savings: Reduced travel time and fuel costs for asset retrieval
- Decision Making: Better resource allocation based on geographical insights
Future Enhancements
Advanced Location Features
- Movement Tracking: Historical location trail for mobile objects
- Geofencing: Alerts when objects move outside designated areas
- Route Optimization: Optimal paths for collecting multiple objects
- Location-Based Automation: Automatic status changes based on geographical triggers
Integration Expansions
- IoT Integration: Real-time location updates from GPS-enabled devices
- Augmented Reality: AR-guided navigation to object locations
- Weather Integration: Weather conditions at object locations
- Traffic Integration: Real-time travel time estimates to object locations
Related Documentation
Current System References
- Use Case: create-object.md - Base object creation workflow
- Architecture: spatial-relationships.md - Current spatial positioning
- Database: neo4j-core-schema.md - Existing ScanEvent location tracking
Integration Points
- Spatial System: Complements existing relative positioning with absolute coordinates
- Object Creation: Extends CreateObjectModal with location capture
- Search System: Adds geographical dimension to object discovery
- Mobile Experience: Leverages mobile GPS capabilities for location-aware workflows
Use Case Created: Mån 7 Jul 2025 11:04:28 CEST - Geographical Location (LAT/LON) tracking for location-based object discovery and “near me” functionality