- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
12 KiB
Map Functionality Critical Analysis & Improvement Recommendations
Executive Summary
The map implementation has several critical bugs, performance issues, and architectural problems that need immediate attention. The most severe issue is that organizations don't have location data in the backend schema, but the map code attempts to access org.location.lng/lat, which will cause runtime errors.
🔴 CRITICAL ISSUES
1. Missing Location Data (BREAKING BUG)
Problem:
- Backend
Organizationschema has nolocationor coordinate fields - Map code accesses
org.location.lngandorg.location.lat(seeuseMapInteraction.ts:18,AiConnectionLines.tsx:14,19,20) - Locations are stored in
Siteentities, notOrganizationentities MapMarkercomponent doesn't receive coordinates prop
Impact:
- Runtime errors when selecting organizations
- Map markers cannot be positioned
- Connection lines cannot be drawn
Evidence:
// ❌ BROKEN: Backend schema has no location
export const backendOrganizationSchema = z.object({
ID: z.string(),
Name: z.string(),
// ... no Latitude/Longitude fields
});
// ❌ BROKEN: Code tries to access non-existent location
setMapCenter([org.location.lng, org.location.lat]); // useMapInteraction.ts:18
if (!match.org?.location || !selectedOrg.location) return null; // AiConnectionLines.tsx:14
Fix Required:
- Fetch Sites for each organization and use Site coordinates
- Create a mapping:
Organization ID → Site coordinates - Update all location access to use Site data
- Add fallback handling for organizations without sites
2. MapMarker Missing Coordinates
Problem:
MapMarkercomponent doesn't use theMarkercomponent from@vnedyalk0v/react19-simple-maps- No
coordinatesprop passed to position markers - Markers are rendered as raw SVG
<g>elements without positioning
Evidence:
// ❌ MapMarker.tsx - no coordinates, no Marker wrapper
return (
<g onClick={handleSelect}>
{/* SVG elements but no positioning */}
</g>
);
Fix Required:
// ✅ Should be:
<Marker coordinates={[org.site.longitude, org.site.latitude]}>
<MapMarkerContent ... />
</Marker>
⚠️ PERFORMANCE ISSUES
3. No Viewport Culling
Problem:
- All markers render regardless of viewport bounds
- With 100+ organizations, this causes significant performance degradation
- No spatial filtering before rendering
Impact:
- Slow rendering with many organizations
- Unnecessary DOM/SVG elements
- High memory usage
Recommendation:
// Implement viewport culling
const visibleOrgs = useMemo(() => {
return organizations.filter((org) => {
const [lng, lat] = [org.site.longitude, org.site.latitude];
return isInViewport(lng, lat, mapCenter, zoom);
});
}, [organizations, mapCenter, zoom]);
4. No Marker Clustering
Problem:
- Dense marker areas cause visual clutter
- No clustering algorithm for nearby markers
- All markers render individually even when overlapping
Recommendation:
- Implement marker clustering (e.g.,
superclusterlibrary) - Cluster markers at low zoom levels
- Show cluster count badges
- Expand clusters on zoom in
5. Inefficient Sector Lookup
Problem:
SECTORS.find()called in render loop for every organization- O(n*m) complexity where n=orgs, m=sectors
- Should be O(1) lookup with Map
Evidence:
// ❌ In render loop - called for every org
organizations.map((org) => {
const sector = SECTORS.find((s) => s.nameKey === org.Sector); // O(m) lookup
// ...
});
Fix:
// ✅ Pre-compute sector map
const sectorMap = useMemo(() => {
return new Map(SECTORS.map((s) => [s.nameKey, s]));
}, []);
// Then O(1) lookup
const sector = sectorMap.get(org.Sector);
6. No Memoization in InteractiveMap
Problem:
InteractiveMapcomponent re-renders on every state change- No
React.memooruseMemofor expensive operations - Marker list recreated on every render
Fix:
const InteractiveMap = React.memo(() => {
const visibleMarkers = useMemo(() => {
// Filter and memoize markers
}, [organizations, mapCenter, zoom, selectedOrg, hoveredOrgId]);
// ...
});
7. Client-Side Filtering of All Data
Problem:
- All organizations fetched and filtered client-side
- No backend pagination or spatial filtering
- Filtering happens on every keystroke (even with debounce)
Recommendation:
- Backend should support:
- Viewport bounds filtering (
?bounds=minLng,minLat,maxLng,maxLat) - Search with pagination
- Sector filtering server-side
- Viewport bounds filtering (
🏗️ ARCHITECTURE ISSUES
8. Over-Complex Context Structure
Problem:
- 5 separate contexts (
MapViewState,MapInteractionState,MapFilterState,MapUIState,MapActions) - Context splitting doesn't provide performance benefits (all consumers re-render anyway)
- Difficult to trace state flow
Recommendation:
- Consolidate to 1-2 contexts
- Use React Query for server state
- Keep only UI state in context
9. Missing Spatial Indexing
Problem:
- No spatial data structure (R-tree, quadtree, etc.)
- Linear search for nearby organizations
- No efficient distance calculations
Recommendation:
- Use spatial indexing library (e.g.,
rbush) - Pre-index organizations by coordinates
- Fast nearest-neighbor queries
10. Static Historical Data
Problem:
- Historical landmarks loaded from static JSON file
- No backend API for historical data
- No ability to update without code changes
Recommendation:
- Move to backend API
- Support dynamic updates
- Add spatial queries for landmarks
🔧 RELIABILITY ISSUES
11. No Error Boundaries for Map Rendering
Problem:
- Map errors can crash entire page
- No fallback UI for map failures
- No error recovery
Fix:
<ErrorBoundary fallback={<MapErrorFallback />}>
<InteractiveMap />
</ErrorBoundary>
12. No Coordinate Validation
Problem:
- No validation that coordinates are within valid ranges
- No handling of missing/invalid coordinates
- Can cause map projection errors
Fix:
const isValidCoordinate = (lat: number, lng: number) => {
return lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180;
};
13. Missing Fallback for Organizations Without Sites
Problem:
- Organizations may not have associated Sites
- No handling for missing location data
- Map will break silently
Fix:
- Filter out organizations without sites
- Show warning/indicator
- Provide UI to add site for organization
⚡ EFFICIENCY ISSUES
14. No Debouncing of Map Movements
Problem:
onMoveEndfires on every pan/zoom- Can cause excessive state updates
- No throttling for smooth interactions
Recommendation:
- Debounce
onMoveEnd(100-200ms) - Use
requestAnimationFramefor smooth updates - Batch state updates
15. Inefficient Connection Line Rendering
Problem:
- All connection lines render even when off-screen
- No culling for lines outside viewport
- Lines re-render on every hover state change
Fix:
const visibleLines = useMemo(() => {
return matches.filter((match) => {
// Check if line intersects viewport
return lineIntersectsViewport(match, viewport);
});
}, [matches, viewport]);
16. No Lazy Loading
Problem:
- All organizations loaded upfront
- No pagination or infinite scroll
- Large datasets cause initial load delays
Recommendation:
- Implement virtual scrolling for sidebar
- Lazy load markers as viewport changes
- Progressive data loading
📦 LIBRARY-SPECIFIC ISSUES
17. Unused Library Dependency
Problem:
react-zoom-pan-pinchinstalled but not used@vnedyalk0v/react19-simple-mapshas built-in zoom/pan- Dead code increases bundle size
Fix:
- Remove unused dependency
- Clean up package.json
18. Missing Marker Component Usage
Problem:
- Not using
Markercomponent from library - Manual SVG positioning instead of library's coordinate system
- Missing proper projection handling
Fix:
- Use
<Marker coordinates={[lng, lat]}>wrapper - Let library handle coordinate transformation
🎯 RECOMMENDED IMPROVEMENTS (Priority Order)
Phase 1: Critical Fixes (Immediate)
- ✅ Fix location data access (use Sites instead of Organization.location)
- ✅ Add coordinates to MapMarker component
- ✅ Add error boundaries
- ✅ Add coordinate validation
Phase 2: Performance (High Priority)
- ✅ Implement viewport culling
- ✅ Add sector lookup Map
- ✅ Memoize InteractiveMap and marker lists
- ✅ Add marker clustering
Phase 3: Architecture (Medium Priority)
- ✅ Consolidate contexts
- ✅ Add backend spatial filtering
- ✅ Implement spatial indexing
- ✅ Move historical data to backend
Phase 4: Polish (Low Priority)
- ✅ Debounce map movements
- ✅ Optimize connection line rendering
- ✅ Add lazy loading
- ✅ Remove unused dependencies
📊 Performance Metrics to Track
- Initial Load Time: Target < 2s
- Time to Interactive: Target < 3s
- FPS During Pan/Zoom: Target > 30fps
- Memory Usage: Monitor for leaks
- Bundle Size: Track library sizes
🔍 Code Quality Issues
Missing Type Safety
match.org?.location- location type not definedgeo: anyin MapPicker- Missing coordinate types
Inconsistent Patterns
- Some components use
React.memo, others don't - Mixed use of
useCallbackvs inline functions - Inconsistent error handling
Documentation
- Missing JSDoc for complex functions
- No performance notes
- No architecture diagrams
🚀 Quick Wins
- Add sector lookup Map (5 min, high impact)
- Memoize marker list (10 min, medium impact)
- Add React.memo to InteractiveMap (2 min, low impact)
- Remove unused dependency (1 min, low impact)
- Add coordinate validation (15 min, high reliability)
📝 Testing Recommendations
-
Unit Tests:
- Viewport culling logic
- Coordinate validation
- Sector lookup performance
-
Integration Tests:
- Map rendering with 100+ markers
- Pan/zoom performance
- Marker selection/hover
-
E2E Tests:
- Full map interaction flow
- Error recovery
- Performance benchmarks
🎓 Best Practices to Adopt
-
Spatial Data Handling:
- Always validate coordinates
- Use spatial indexing for queries
- Implement viewport culling
-
React Performance:
- Memoize expensive computations
- Use React.memo for pure components
- Avoid inline object/array creation in render
-
Map Libraries:
- Use library components (Marker, etc.)
- Follow library best practices
- Monitor library updates
-
State Management:
- Keep contexts minimal
- Use React Query for server state
- Local state for UI-only concerns
Conclusion
The map functionality has critical bugs that must be fixed immediately, particularly the location data access issue. Performance optimizations should follow, with viewport culling and clustering providing the biggest impact. The architecture is over-engineered with too many contexts, but this is less urgent than the critical bugs.
Estimated Effort:
- Critical fixes: 4-6 hours
- Performance improvements: 8-12 hours
- Architecture refactoring: 6-8 hours
- Testing & polish: 4-6 hours
- Total: 22-32 hours