turash/bugulma/frontend/MAP_ANALYSIS.md
Damir Mukimov 6347f42e20
Consolidate repositories: Remove nested frontend .git and merge into main repository
- 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.
2025-11-25 06:02:57 +01:00

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 Organization schema has no location or coordinate fields
  • Map code accesses org.location.lng and org.location.lat (see useMapInteraction.ts:18, AiConnectionLines.tsx:14,19,20)
  • Locations are stored in Site entities, not Organization entities
  • MapMarker component 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:

  1. Fetch Sites for each organization and use Site coordinates
  2. Create a mapping: Organization ID → Site coordinates
  3. Update all location access to use Site data
  4. Add fallback handling for organizations without sites

2. MapMarker Missing Coordinates

Problem:

  • MapMarker component doesn't use the Marker component from @vnedyalk0v/react19-simple-maps
  • No coordinates prop 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., supercluster library)
  • 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:

  • InteractiveMap component re-renders on every state change
  • No React.memo or useMemo for 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

🏗️ 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:

  • onMoveEnd fires on every pan/zoom
  • Can cause excessive state updates
  • No throttling for smooth interactions

Recommendation:

  • Debounce onMoveEnd (100-200ms)
  • Use requestAnimationFrame for 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-pinch installed but not used
  • @vnedyalk0v/react19-simple-maps has 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 Marker component 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

Phase 1: Critical Fixes (Immediate)

  1. Fix location data access (use Sites instead of Organization.location)
  2. Add coordinates to MapMarker component
  3. Add error boundaries
  4. Add coordinate validation

Phase 2: Performance (High Priority)

  1. Implement viewport culling
  2. Add sector lookup Map
  3. Memoize InteractiveMap and marker lists
  4. Add marker clustering

Phase 3: Architecture (Medium Priority)

  1. Consolidate contexts
  2. Add backend spatial filtering
  3. Implement spatial indexing
  4. Move historical data to backend

Phase 4: Polish (Low Priority)

  1. Debounce map movements
  2. Optimize connection line rendering
  3. Add lazy loading
  4. Remove unused dependencies

📊 Performance Metrics to Track

  1. Initial Load Time: Target < 2s
  2. Time to Interactive: Target < 3s
  3. FPS During Pan/Zoom: Target > 30fps
  4. Memory Usage: Monitor for leaks
  5. Bundle Size: Track library sizes

🔍 Code Quality Issues

Missing Type Safety

  • match.org?.location - location type not defined
  • geo: any in MapPicker
  • Missing coordinate types

Inconsistent Patterns

  • Some components use React.memo, others don't
  • Mixed use of useCallback vs inline functions
  • Inconsistent error handling

Documentation

  • Missing JSDoc for complex functions
  • No performance notes
  • No architecture diagrams

🚀 Quick Wins

  1. Add sector lookup Map (5 min, high impact)
  2. Memoize marker list (10 min, medium impact)
  3. Add React.memo to InteractiveMap (2 min, low impact)
  4. Remove unused dependency (1 min, low impact)
  5. Add coordinate validation (15 min, high reliability)

📝 Testing Recommendations

  1. Unit Tests:

    • Viewport culling logic
    • Coordinate validation
    • Sector lookup performance
  2. Integration Tests:

    • Map rendering with 100+ markers
    • Pan/zoom performance
    • Marker selection/hover
  3. E2E Tests:

    • Full map interaction flow
    • Error recovery
    • Performance benchmarks

🎓 Best Practices to Adopt

  1. Spatial Data Handling:

    • Always validate coordinates
    • Use spatial indexing for queries
    • Implement viewport culling
  2. React Performance:

    • Memoize expensive computations
    • Use React.memo for pure components
    • Avoid inline object/array creation in render
  3. Map Libraries:

    • Use library components (Marker, etc.)
    • Follow library best practices
    • Monitor library updates
  4. 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