Locations¶
Overview¶
The Locations app provides an intelligent, crowd-sourced geographic data management system for Jend-Z. It enables location-based content discovery while dramatically reducing geocoding API costs through smart boundary detection and community-driven location naming. The system combines traditional hierarchical location data with dynamic neighborhood boundaries and consensus-based location names.
Smart Location System¶
Key Features¶
- Hybrid Geocoding: Reduces API calls by reusing existing location data for nearby users
- Dynamic Boundaries: Automatically calculates neighborhood boundaries based on user distribution
- Crowd-Sourced Naming: Community-driven location naming with weighted consensus
- Quality Scoring: Confidence metrics based on user count and name agreement
- Intelligent Fallbacks: Progressive location discovery with multiple hierarchy levels
How It Works¶
- First User in Area: Frontend geocoding creates initial location with default 500m radius
- Subsequent Users: System detects existing boundaries, suggests location without geocoding
- Name Consensus: Users suggest/correct names, system builds weighted consensus
- Boundary Evolution: Boundaries automatically adjust as more users join the area
- Quality Improvement: Confidence scores increase with user participation
Enhanced Data Model¶
Location Model¶
The Location model now includes both traditional geographic data and smart location features.
Traditional Geographic Fields¶
id(UUID): Unique identifiername(CharField): Auto-generated display name (editable=False)created_at(DateTimeField): Creation timestamplongitude/latitude(FloatField): Original coordinate pair- Standard hierarchy:
country,state,city,neighbourhood, etc. (17 levels)
Smart Location Extensions¶
Dynamic Boundaries:
center_latitude(FloatField): Calculated center of user clustercenter_longitude(FloatField): Calculated center of user clusterestimated_radius(IntegerField): Dynamic radius in meters (200m-2km bounds)last_boundary_update(DateTimeField): Timestamp of last recalculation
Consensus System:
name_suggestions(JSONField): Weighted vote tracking{"name": vote_weight}total_users(IntegerField): Number of users in this locationconfidence_score(FloatField): Overall location quality (0.0-1.0)
Quality Management:
needs_verification(BooleanField): Flagged for moderator reviewis_auto_generated(BooleanField): Created without geocoding datamoderator_approved(BooleanField): Staff-approved location
Supporting Models¶
LocationNameSuggestion¶
Tracks individual name suggestions from users with detailed analytics.
{
"id": "uuid",
"location": "location-uuid",
"user": "user-uuid",
"suggested_name": "Downtown Lagos",
"vote_weight": 1.2,
"is_approved": false,
"is_flagged": false,
"created_at": "2024-01-15T10:30:00Z"
}
LocationModerationLog¶
Audit trail for all location modifications and administrative actions.
API Endpoints¶
Smart Location Management¶
1. Smart Location Update¶
Endpoint: POST /api/locations/locations/smart_update/
Description: Intelligent location update that reuses existing boundaries when possible.
Request Body:
{
"latitude": 6.4302,
"longitude": 3.4236,
"suggested_name": "VI Business District", // Optional
"geocoded_data": {
// Optional - from frontend geocoding
"address": {
"country": "Nigeria",
"state": "Lagos State",
"city": "Lagos",
"neighbourhood": "Victoria Island"
}
}
}
Response - Existing Location Found:
{
"location": {
"id": "location-uuid",
"name": "Victoria Island",
"confidence_score": 0.85,
"estimated_radius": 750,
"center_latitude": 6.4298,
"center_longitude": 3.4238,
"total_users": 23,
"country": "Nigeria",
"state": "Lagos State",
"city": "Lagos",
"neighbourhood": "Victoria Island"
},
"source": "existing",
"message": "Found existing location: Victoria Island",
"alternative_names": ["VI", "Victoria Island", "Lagos Island"],
"name_suggestion": {
"message": "Name suggestion recorded",
"vote_weight": 1.2,
"top_suggestions": ["Victoria Island", "VI Business District", "Lagos VI"]
}
}
Response - New Location Created:
{
"location": {
"id": "new-location-uuid",
"name": "VI Business District",
"confidence_score": 0.3,
"estimated_radius": 500,
"center_latitude": 6.4302,
"center_longitude": 3.4236,
"total_users": 1,
"is_auto_generated": false
},
"source": "new",
"message": "Created new location",
"needs_more_data": false
}
2. Suggest Location Name¶
Endpoint: POST /api/locations/locations/{location_id}/suggest_name/
Description: Community-driven location naming with consensus building.
Request Body:
Response - Name Accepted:
{
"message": "Name suggestion accepted and location name updated",
"old_name": "Victoria Island",
"new_name": "Lagos Business District",
"confidence": 0.87,
"vote_weight": 1.2
}
Response - Suggestion Recorded:
{
"message": "Name suggestion recorded",
"current_name": "Victoria Island",
"suggested_name": "Lagos Business District",
"vote_weight": 1.2,
"top_suggestions": [
"Victoria Island",
"Lagos Business District",
"VI Downtown"
]
}
3. Get Location Name Suggestions¶
Endpoint: GET /api/locations/locations/{location_id}/name_suggestions/
Description: View community suggestions for a location with smart grouping to eliminate duplicates.
Query Parameters:
show_individual(optional): Set totruefor paginated individual suggestions instead of grouped view
Default Response (Grouped View):
{
"location_name": "Victoria Island",
"confidence_score": 0.75,
"total_suggestions": 15,
"view_type": "grouped",
"grouped_suggestions": [
{
"representative_name": "Victoria Island",
"total_weight": 18.5,
"suggestion_count": 8,
"is_current_name": true,
"suggestions": [
{
"id": "suggestion-uuid",
"suggested_name": "Victoria Island",
"user": {
"username": "lagos_user",
"display_name": "Lagos User"
},
"vote_weight": 2.1,
"created_at": "2024-01-15T10:30:00Z"
},
{
"id": "suggestion-uuid-2",
"suggested_name": "victoria island", // Similar names grouped together
"user": {
"username": "local_resident",
"display_name": "Local Resident"
},
"vote_weight": 1.8,
"created_at": "2024-01-14T15:20:00Z"
}
]
},
{
"representative_name": "VI Business District",
"total_weight": 12.3,
"suggestion_count": 4,
"is_current_name": false,
"suggestions": [...]
}
],
"consensus_data": {
"Victoria Island": 18.5,
"VI Business District": 12.3,
"Lagos VI": 8.7
},
"top_voted_names": [
["Victoria Island", 18.5],
["VI Business District", 12.3],
["Lagos VI", 8.7]
]
}
Individual Suggestions (Paginated):
Endpoint: GET /api/locations/locations/{location_id}/name_suggestions/?show_individual=true
{
"count": 47,
"next": "http://api.example.com/api/locations/locations/{id}/name_suggestions/?show_individual=true&page=2",
"previous": null,
"results": {
"location_name": "Victoria Island",
"confidence_score": 0.75,
"total_suggestions": 47,
"view_type": "individual",
"suggestions": [
{
"id": "suggestion-uuid",
"suggested_name": "VI Business District",
"user": {
"username": "lagos_user",
"display_name": "Lagos User"
},
"vote_weight": 1.5,
"created_at": "2024-01-15T10:30:00Z",
"is_current_name": false,
"similarity_to_current": 65
}
]
}
}
Smart Grouping Features:
- Fuzzy Matching: Similar names like "Downtown" and "Down Town" are grouped together
- Representative Names: Shows the highest-weighted suggestion as the group representative
- Vote Aggregation: Combines vote weights for similar suggestions
- Duplicate Elimination: Users see clean, organized suggestions without confusion
- Fallback Support: Works even without fuzzy matching library (exact matches only)
#### 4. Find Nearby Locations
**Endpoint:** `GET /api/locations/locations/nearby/`
**Description:** Discover existing locations near coordinates.
**Query Parameters:**
- `latitude` (required): Latitude coordinate
- `longitude` (required): Longitude coordinate
- `max_distance` (optional): Maximum distance in km (default: 5.0)
**Response:**
```json
{
"count": 3,
"locations": [
{
"id": "location-1",
"name": "Victoria Island",
"confidence_score": 0.85,
"estimated_radius": 750,
"distance_km": 0.8,
"total_users": 23
},
{
"id": "location-2",
"name": "Ikoyi",
"confidence_score": 0.72,
"estimated_radius": 900,
"distance_km": 2.1,
"total_users": 18
}
]
}
5. Search Locations¶
Endpoint: GET /api/locations/locations/search/
Description: Search locations with fuzzy name matching.
Query Parameters:
q(required): Search querylatitude(optional): For distance-based sortinglongitude(optional): For distance-based sorting
Response:
{
"query": "victoria island",
"count": 5,
"locations": [
{
"id": "location-uuid",
"name": "Victoria Island",
"confidence_score": 0.85,
"total_users": 23,
"city": "Lagos",
"state": "Lagos State"
}
]
}
Traditional Location APIs¶
6. List All Locations¶
Endpoint: GET /api/locations/locations/
Enhanced Query Parameters:
- Traditional filters:
country,state,city,neighbourhood - Smart filters:
min_confidence,needs_verification,order_by_confidence - Activity filters:
order_by_posts,order_by_stores
Response includes confidence metrics:
{
"count": 150,
"results": [
{
"id": "location-uuid",
"name": "Victoria Island",
"confidence_score": 0.85,
"is_high_confidence": true,
"total_users": 23,
"estimated_radius": 750,
"top_suggestions": [
{ "name": "Victoria Island", "votes": 15.2 },
{ "name": "VI", "votes": 8.7 }
],
"country": "Nigeria",
"state": "Lagos State",
"city": "Lagos",
"neighbourhood": "Victoria Island",
"post_count": 245,
"store_count": 18
}
]
}
Location Name Consensus System¶
How Name Consensus Works¶
Voting Weight Calculation¶
User votes are weighted based on several factors:
Base Factors:
- Account Age: Newer users (1 day) get 0.1x weight, established users (2+ years) get up to 2.0x
- Activity Level: Users with more posts get slight boost (max 1.5x)
- Verification Status: Verified users get 1.2x multiplier
- Very New Accounts: Accounts less than 7 days get reduced weight (0.5x)
Example Vote Weights:
- New user (2 days old): 0.5
- Regular user (6 months, some posts): 1.2
- Active user (1 year, many posts, verified): 2.0
- Very new user (few hours old): 0.1
Consensus Algorithm¶
Name Grouping:
- Uses fuzzy string matching (85% similarity threshold)
- Groups similar names: "Downtown Lagos" + "Down Town Lagos" = same group
- Combines vote weights for similar names
Name Selection:
- Location name updates when new consensus has >60% confidence
- Requires significant improvement over current name (+10% confidence)
- Most voted name in winning group becomes the location name
Quality Safeguards:
- Profanity filtering and inappropriate content detection
- Length limits (2-100 characters)
- Character validation (letters, numbers, basic punctuation)
- Staff moderation for disputed names
User Experience Flow¶
Suggesting Location Names¶
// Frontend integration for name suggestions
const suggestLocationName = async (locationId, suggestedName) => {
try {
const response = await api.post(
`/api/locations/locations/${locationId}/suggest_name/`,
{ name: suggestedName }
);
if (response.data.message.includes("updated")) {
showNotification("Location name updated! 🎉", "success");
} else {
showNotification("Thanks for the suggestion!", "info");
showAlternatives(response.data.top_suggestions);
}
} catch (error) {
handleNameSuggestionError(error);
}
};
Displaying Name Suggestions¶
// Show alternative names to users
const showLocationWithAlternatives = (location) => {
const alternatives = location.alternative_names || [];
return (
<div className="location-card">
<h3>{location.name}</h3>
<p className="confidence">
Confidence: {(location.confidence_score * 100).toFixed(1)}%
</p>
{alternatives.length > 0 && (
<div className="alternatives">
<p>Also known as:</p>
<ul>
{alternatives.map((alt) => (
<li key={alt}>{alt}</li>
))}
</ul>
</div>
)}
<button onClick={() => suggestName(location.id)}>
Suggest Better Name
</button>
</div>
);
};
Dynamic Boundary System¶
Boundary Calculation¶
Algorithm:
- User Clustering: Collect coordinates of all users in location
- Center Calculation: Compute centroid of user coordinates
- Radius Determination: Use 90th percentile distance from center
- Bounds Enforcement: Minimum 200m, maximum 2km radius
- Quality Update: Adjust confidence based on user count and consensus
Automatic Updates:
- Triggered when new users join location
- Recalculated when user count reaches thresholds (5, 10, 25, 50+)
- Manual recalculation available for administrators
Integration with Content Discovery¶
Smart Post Filtering:
// Posts are automatically filtered by dynamic boundaries
const getLocalPosts = async (userLocation) => {
// Backend automatically finds posts within the user's location boundary
const response = await api.get(
`/api/posts/posts/by-location/?location_id=${userLocation.id}`
);
return response.data.posts;
};
Boundary Visualization:
// Display location boundary on map
const showLocationBoundary = (location) => {
const circle = new google.maps.Circle({
center: {
lat: location.center_latitude,
lng: location.center_longitude,
},
radius: location.estimated_radius,
fillColor: location.confidence_score > 0.7 ? "#00FF00" : "#FFA500",
fillOpacity: 0.2,
strokeColor: "#0066CC",
strokeWeight: 2,
});
circle.setMap(map);
};
Administrative & Moderation Features¶
Location Quality Management¶
7. Flag Location for Review¶
Endpoint: POST /api/locations/locations/{location_id}/flag_for_review/
Request Body:
8. Location Analytics (Staff Only)¶
Endpoint: GET /api/locations/locations/analytics/
Response:
{
"summary": {
"total_locations": 1250,
"low_confidence_count": 45,
"needs_verification_count": 12,
"auto_generated_count": 234,
"recent_suggestions_count": 67
},
"top_locations": [
{
"id": "location-uuid",
"name": "Victoria Island",
"total_users": 156,
"confidence_score": 0.92
}
]
}
Name Suggestion Management¶
9. Name Suggestion Analytics¶
Endpoint: GET /api/locations/suggestions/
Query Parameters:
location_id: Filter by locationmy_suggestions=true: User's own suggestions only
Response:
{
"count": 25,
"results": [
{
"id": "suggestion-uuid",
"suggested_name": "Lagos Business Hub",
"location_name": "Victoria Island",
"user": {
"username": "local_expert",
"display_name": "Local Expert"
},
"vote_weight": 2.1,
"is_current_name": false,
"similarity_to_current": 72,
"created_at": "2024-01-15T10:30:00Z"
}
]
}
Frontend Integration Patterns¶
Smart Location Detection¶
// Enhanced location detection with smart suggestions
const getLocationSmart = async () => {
try {
const position = await getCurrentPosition();
const { latitude, longitude } = position.coords;
// Try frontend geocoding first (optional, for better UX)
let geocodedData = null;
try {
geocodedData = await frontendGeocode(latitude, longitude);
} catch (geocodeError) {
console.log("Frontend geocoding failed, backend will handle");
}
// Smart backend location update
const response = await api.post("/api/locations/locations/smart_update/", {
latitude,
longitude,
geocoded_data: geocodedData,
});
const locationData = response.data;
// Handle different scenarios
if (locationData.source === "existing") {
showLocationConfirmation({
location: locationData.location,
alternatives: locationData.alternative_names,
canSuggestName: true,
});
} else {
showNewLocationCreated({
location: locationData.location,
needsMoreData: locationData.needs_more_data,
});
}
return locationData.location;
} catch (error) {
handleLocationError(error);
}
};
Location Name Suggestions UI¶
// UI for location name suggestions
const LocationNameEditor = ({ location, onUpdate }) => {
const [suggestions, setSuggestions] = useState([]);
const [newSuggestion, setNewSuggestion] = useState("");
useEffect(() => {
loadNameSuggestions();
}, [location.id]);
const loadNameSuggestions = async () => {
const response = await api.get(
`/api/locations/locations/${location.id}/name_suggestions/`
);
setSuggestions(response.data.suggestions);
};
const submitSuggestion = async () => {
if (!newSuggestion.trim()) return;
try {
const response = await api.post(
`/api/locations/locations/${location.id}/suggest_name/`,
{ name: newSuggestion }
);
showNotification(response.data.message);
loadNameSuggestions();
setNewSuggestion("");
if (response.data.new_name) {
onUpdate({ ...location, name: response.data.new_name });
}
} catch (error) {
showError(error.response.data.error);
}
};
return (
<div className="location-name-editor">
<h3>Location: {location.name}</h3>
<p>Confidence: {(location.confidence_score * 100).toFixed(1)}%</p>
<div className="suggestion-input">
<input
type="text"
placeholder="Suggest a better name..."
value={newSuggestion}
onChange={(e) => setNewSuggestion(e.target.value)}
/>
<button onClick={submitSuggestion}>Suggest</button>
</div>
{suggestions.length > 0 && (
<div className="existing-suggestions">
<h4>Community Suggestions:</h4>
{suggestions.slice(0, 5).map((suggestion) => (
<div key={suggestion.id} className="suggestion-item">
<span className="name">{suggestion.suggested_name}</span>
<span className="votes">
({suggestion.vote_weight.toFixed(1)} votes)
</span>
<span className="user">by {suggestion.user.display_name}</span>
</div>
))}
</div>
)}
</div>
);
};
Location Discovery¶
// Enhanced location search with smart suggestions
const LocationSearch = ({ onLocationSelect }) => {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const [nearbyLocations, setNearbyLocations] = useState([]);
const searchLocations = async (searchQuery) => {
if (searchQuery.length < 2) return;
const response = await api.get("/api/locations/locations/search/", {
params: { q: searchQuery },
});
setResults(response.data.locations);
};
const findNearbyLocations = async () => {
const position = await getCurrentPosition();
const response = await api.get("/api/locations/locations/nearby/", {
params: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
max_distance: 10,
},
});
setNearbyLocations(response.data.locations);
};
useEffect(() => {
findNearbyLocations();
}, []);
return (
<div className="location-search">
<input
type="text"
placeholder="Search locations..."
value={query}
onChange={(e) => {
setQuery(e.target.value);
searchLocations(e.target.value);
}}
/>
{results.length > 0 && (
<div className="search-results">
{results.map((location) => (
<LocationCard
key={location.id}
location={location}
onSelect={onLocationSelect}
showConfidence={true}
/>
))}
</div>
)}
{nearbyLocations.length > 0 && (
<div className="nearby-locations">
<h4>Nearby Locations:</h4>
{nearbyLocations.map((location) => (
<LocationCard
key={location.id}
location={location}
onSelect={onLocationSelect}
showDistance={true}
/>
))}
</div>
)}
</div>
);
};
Error Handling¶
Smart Location API Errors¶
Location Update Errors:
Name Suggestion Errors:
Rate Limiting (if implemented):
Frontend Error Handling¶
const handleLocationError = (error) => {
if (error.response) {
switch (error.response.status) {
case 400:
showError("Invalid location data. Please try again.");
break;
case 429:
showError("Too many requests. Please wait a moment.");
break;
default:
showError("Location update failed. Please try again.");
}
} else {
showError("Network error. Please check your connection.");
}
};
Performance Considerations¶
Caching Strategy¶
Location Data:
- Cache frequently accessed locations (high user count)
- Cache search results for common queries
- Cache user's current location for session
Name Suggestions:
- Cache top suggestions for popular locations
- Invalidate cache when consensus changes
Database Optimization¶
Indexes:
- Geographic coordinates for spatial queries
- Confidence scores for quality filtering
- User counts for popularity sorting
Query Optimization:
- Use subqueries for count aggregations
- Limit concurrent boundary recalculations
- Batch process suggestion weight updates
Best Practices¶
Location Management¶
- Gradual Rollout: Deploy smart location features gradually
- Fallback Strategies: Always provide fallbacks for location detection failures
- User Education: Explain the community-driven naming system
- Quality Monitoring: Regular review of low-confidence locations
Name Suggestions¶
- Encourage Participation: Make name suggestion UI discoverable
- Show Progress: Display confidence scores and vote counts
- Handle Conflicts: Provide clear feedback when suggestions are similar
- Moderate Actively: Review flagged content promptly
Frontend Integration¶
- Progressive Enhancement: Smart features should enhance, not break, basic functionality
- Loading States: Show appropriate loading indicators during API calls
- Offline Handling: Cache location data for offline scenarios
- Accessibility: Ensure location UI is accessible to all users
The smart location system transforms static geographic data into a living, community-driven resource that becomes more accurate and valuable as your user base grows, while significantly reducing operational costs.