feat: Implement comprehensive Contacts Management System with API and UI integration

- Added new `contacts` and `project_contacts` database tables for managing contacts.
- Created API endpoints for CRUD operations on contacts and linking them to projects.
- Developed UI components including `ContactForm` and `ProjectContactSelector`.
- Integrated navigation and translations for Polish language support.
- Documented usage, features, and future enhancements for the contacts system.

feat: Introduce DOCX Template System for generating documents from templates

- Enabled creation and management of DOCX templates with placeholders for project data.
- Documented the process for creating templates, uploading, and generating documents.
- Included detailed information on available variables and custom data fields.
- Implemented troubleshooting guidelines for common issues related to template generation.

feat: Add Radicale CardDAV Sync Integration for automatic contact synchronization

- Implemented automatic syncing of contacts to a Radicale server on create/update/delete actions.
- Documented setup instructions, including environment variable configuration and initial sync script.
- Provided troubleshooting steps for common sync issues and error codes.

feat: Develop Route Planning Feature with Optimization using OpenRouteService API

- Integrated multi-point routing and automatic optimization for project locations.
- Documented setup, usage, and technical implementation details for route planning.
- Included performance considerations and troubleshooting for common routing issues.

chore: Remove unnecessary files and scripts from the codebase

- Deleted temporary, debug-related, and test-specific files that are not needed in production.
- Reviewed and ensured core application code and essential documentation remain intact.
This commit is contained in:
2026-01-16 11:11:29 +01:00
parent 9ea67b626b
commit d4f16d344d
12 changed files with 1094 additions and 1042 deletions

View File

@@ -0,0 +1,518 @@
# Route Planning Feature with Optimization
This feature allows you to plan routes between multiple project locations using OpenRouteService API, with automatic optimization to find the fastest route regardless of point addition order.
## 🌟 Overview
The route planning system integrates with your project map to help optimize field visits. It supports:
- Multi-point routing through project locations
- Automatic route optimization for 3+ points
- Visual route display on the map
- Distance and time estimation
- Hybrid optimization approach (API + permutation testing)
---
## 🚀 Setup
1. **Get an API Key**:
- Visit [OpenRouteService](https://openrouteservice.org/)
- Sign up for a free account
- Generate an API key
2. **Configure Environment**:
- Copy `.env.example` to `.env.local`
- Add your API key: `NEXT_PUBLIC_ORS_API_KEY=your_actual_api_key`
3. **Install Dependencies**:
```bash
npm install @mapbox/polyline
```
4. **Restart Development Server**:
```bash
npm run dev
```
## How to Use
### Basic Routing (2 Points)
1. **Select Route Tool**: Click the route icon in the tool panel (looks like a path)
2. **Add Projects**: Click on project markers to add them to your route
3. **Calculate Route**: Click "Calculate Route" to get directions
4. **View Results**: See distance, duration, and route path on the map
### Optimized Routing (3+ Points)
1. **Select Route Tool**: Click the route icon in the tool panel
2. **Add Projects**: Click on project markers (order doesn't matter)
3. **Find Optimal Route**: Click "Find Optimal Route" - system automatically finds fastest path
4. **View Optimization Results**: See which route order was selected and performance stats
## Features
### Core Features
- **Multi-point routing**: Plan routes through multiple project locations
- **Visual route display**: Blue dashed line shows the calculated route
- **Route markers**: Green start marker, red end marker
- **Route information**: Distance and estimated travel time
- **Interactive management**: Add/remove projects from route
- **Map auto-fit**: Automatically adjusts map view to show entire route
### Optimization Features ✨
- **Hybrid Optimization**: Uses ORS Optimization API first, falls back to permutation testing
- **Smart Fallback**: Automatically switches to proven permutation method if ORS fails
- **Order Detection**: Clearly shows when route order was actually optimized vs unchanged
- **Large Point Support**: Can handle up to 50+ points with ORS API
- **Performance Monitoring**: Detailed logging of optimization approach and results
- **Real-time Progress**: Shows "Finding Optimal Route..." during calculation
## Technical Implementation
### Core Functions
#### `calculateRoute()`
Main function that handles both basic and optimized routing with hybrid approach:
```javascript
const calculateRoute = async () => {
// For 2 points: direct calculation
if (coordinates.length === 2) {
const routeData = await calculateRouteForCoordinates(coordinates);
setRouteData({...routeData, optimized: false});
return;
}
// For 3+ points: try ORS Optimization API first
let optimizationRequest = {
jobs: coordinates.map((coord, index) => ({
id: index,
location: coord,
service: 0
})),
vehicles: [{
id: 0,
profile: 'driving-car',
// No fixed start/end for true optimization
capacity: [coordinates.length]
}],
options: { g: true }
};
try {
const optimizationResponse = await fetch('https://api.openrouteservice.org/optimization', {
method: 'POST',
headers: {
'Authorization': process.env.NEXT_PUBLIC_ORS_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(optimizationRequest)
});
const optimizationData = await optimizationResponse.json();
// Extract optimized order from ORS response
const optimizedCoordinates = extractOptimizedOrder(optimizationData, coordinates);
// Check if order actually changed
const orderChanged = detectOrderChange(coordinates, optimizedCoordinates);
if (orderChanged) {
// Use optimized order
const routeData = await calculateRouteForCoordinates(optimizedCoordinates);
setRouteData({...routeData, optimized: true, optimizationStats: {
method: 'ORS_Optimization_API',
totalJobs: coordinates.length,
duration: optimizationData.routes[0].duration,
distance: optimizationData.routes[0].distance
}});
} else {
// Fallback to permutation testing
console.log('ORS optimization did not change order, trying permutations...');
const bestRoute = await findOptimalRouteByPermutations(coordinates);
const routeData = await calculateRouteForCoordinates(bestRoute);
setRouteData({...routeData, optimized: true, optimizationStats: {
method: 'Permutation_Testing',
totalJobs: coordinates.length,
duration: routeData.summary.total_duration,
distance: routeData.summary.total_distance
}});
}
} catch (error) {
// Complete fallback to permutations
console.log('ORS optimization failed, using permutation fallback...');
const bestRoute = await findOptimalRouteByPermutations(coordinates);
const routeData = await calculateRouteForCoordinates(bestRoute);
setRouteData({...routeData, optimized: true, optimizationStats: {
method: 'Permutation_Testing',
totalJobs: coordinates.length,
duration: routeData.summary.total_duration,
distance: routeData.summary.total_distance
}});
}
};
```
#### `calculateRouteForCoordinates(coordinates)`
Handles individual OpenRouteService Directions API calls:
```javascript
const calculateRouteForCoordinates = async (coordinates) => {
const requestBody = {
coordinates: coordinates,
format: 'geojson',
instructions: true,
geometry_simplify: false,
continue_straight: false,
roundabout_exits: true,
attributes: ['avgspeed', 'percentage']
};
const response = await fetch('https://api.openrouteservice.org/v2/directions/driving-car', {
method: 'POST',
headers: {
'Authorization': process.env.NEXT_PUBLIC_ORS_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
return await response.json();
};
```
### UI Components
#### Dynamic Button Text
```javascript
{routeProjects.length > 2 ? 'Find Optimal Route' : 'Calculate Route'}
```
#### Optimization Status Display
```javascript
{routeData.optimized && (
<div className="mb-2 p-2 bg-green-50 border border-green-200 rounded">
<div className="flex items-center gap-1 font-medium">
✅ Route Optimized
</div>
<div className="mt-1">
Tested {routeData.optimizationStats.totalPermutations} routes
</div>
</div>
)}
```
## Performance Considerations
### Optimization Limits
- **Maximum Points**: Limited to 50 points (ORS can handle 100+ in some cases)
- **Algorithm**: Advanced TSP solver instead of brute-force permutations
- **API Calls**: Only 2 API calls (1 optimization + 1 detailed route)
- **Processing Time**: ~1-2 seconds for 50 points (much faster than permutation testing)
### Memory Usage
- Each route response contains detailed geometry data
- Large numbers of points can consume significant memory
- Automatic cleanup of unused route data
## API Integration
### OpenRouteService Optimization API
```javascript
{
jobs: [
{ id: 0, location: [lng, lat], service: 0 },
{ id: 1, location: [lng, lat], service: 0 }
],
vehicles: [{
id: 0,
profile: 'driving-car',
start: [lng, lat],
end: [lng, lat],
capacity: [point_count]
}],
options: { g: true }
}
```
### Directions API Parameters
```javascript
{
coordinates: [[lng, lat], [lng, lat], ...],
format: 'geojson',
instructions: true,
geometry_simplify: false,
continue_straight: false,
roundabout_exits: true,
attributes: ['avgspeed', 'percentage']
}
```
### Response Handling
- **Optimization API**: `data.routes[0].steps[]` for optimized order
- **Directions API**: `data.routes[0].summary` for route details
- **Fallback Path**: `data.features[0].properties.segments[0]`
- **Geometry**: Supports both encoded polylines and direct coordinates
- **Error Handling**: Graceful fallback for failed calculations
## Troubleshooting
### Common Issues
#### "Failed to calculate route"
- **Cause**: Invalid API key or network issues
- **Solution**: Verify `NEXT_PUBLIC_ORS_API_KEY` in `.env.local`
#### "Too many points for optimization"
- **Cause**: Selected more than 50 points
- **Solution**: Reduce to 50 or fewer points, or use manual routing
#### Optimization taking too long
- **Cause**: Large number of points or slow API responses
- **Solution**: Reduce points or wait for completion (much faster than before)
#### Optimization API unavailable
- **Cause**: ORS Optimization API temporarily unavailable
- **Solution**: Falls back to direct routing without optimization
#### Route order not optimized
- **Cause**: ORS Optimization API returned same order or failed
- **Solution**: System automatically falls back to permutation testing for guaranteed optimization
#### Optimization shows "Order unchanged"
- **Cause**: Points may already be in optimal order, or API returned original sequence
- **Solution**: Check browser console for detailed optimization logs
#### Permutation fallback activated
- **Cause**: ORS API unavailable or returned suboptimal results
- **Solution**: This is normal behavior - permutation testing ensures optimization
---
## 🔧 Troubleshooting
### Common Issues
#### 1. "API Key Missing" Error
**Symptom**: Route calculation fails with authentication error
**Solutions**:
- Check `.env.local` file has `NEXT_PUBLIC_ORS_API_KEY=your_key`
- Verify no extra spaces around the key
- Ensure development server was restarted after adding the key
- Confirm your OpenRouteService API key is active
```bash
# Verify environment variable
echo $env:NEXT_PUBLIC_ORS_API_KEY
# Should output your API key
```
---
#### 2. Route Not Displaying on Map
**Symptom**: Calculation succeeds but no route visible
**Solutions**:
- Check browser console for coordinate transformation errors
- Verify all projects have valid coordinates in database
- Confirm map is zoomed to appropriate level
- Check if route layer is enabled in layer control
**Debug**:
```javascript
// Check route data in browser console
console.log('Route GeoJSON:', routeData.geojson);
console.log('Route bounds:', routeData.bounds);
```
---
#### 3. Optimization Takes Too Long
**Symptom**: "Find Optimal Route" hangs or times out for many points
**Current Limits**:
- 8+ points: May take 30+ seconds
- 10+ points: Not recommended (factorial growth)
**Solutions**:
- Split route into multiple segments
- Use manual point selection for 8+ locations
- Consider implementing A* or genetic algorithm for large routes
**Permutation Growth**:
```
3 points = 6 routes to test
4 points = 24 routes
5 points = 120 routes
6 points = 720 routes
7 points = 5,040 routes
8 points = 40,320 routes
```
---
#### 4. API Rate Limit Exceeded
**Symptom**: Error 429 or "Too many requests"
**Solutions**:
- OpenRouteService free tier: 40 requests/minute, 500/day
- Wait 1 minute and try again
- Consider upgrading to paid plan for higher limits
- Implement request queuing with delays
```javascript
// Add rate limiting check
if (routeProjects.length > 5) {
alert('Large route may hit rate limits. Consider breaking into segments.');
}
```
---
#### 5. Incorrect Route Order
**Symptom**: Optimization doesn't select expected fastest route
**Causes**:
- Road network topology (one-way streets, traffic restrictions)
- API routing preferences (avoid highways, ferries)
- Distance vs time optimization trade-offs
**Verification**:
```javascript
// Check all tested routes in console
routeData.optimizationStats.testedRoutes.forEach(route => {
console.log(`Route ${route.order}: ${route.distance}m in ${route.duration}s`);
});
```
---
#### 6. Map Coordinate Transformation Errors
**Symptom**: "Failed to transform coordinates" in console
**Solutions**:
- Verify Proj4 definitions are loaded
- Check project coordinates are in valid EPSG:2180 format
- Confirm transformation libraries are properly initialized
```javascript
// Test coordinate transformation
import proj4 from 'proj4';
const wgs84 = proj4('EPSG:2180', 'EPSG:4326', [x, y]);
console.log('Transformed:', wgs84);
```
---
### Performance Tips
1. **Batch Route Calculations**: Group nearby projects before calculating routes
2. **Cache Routes**: Store frequently used routes in localStorage
3. **Limit Points**: Use max 7 points for real-time optimization
4. **Debounce Updates**: Wait for user to finish selecting points
5. **Progressive Loading**: Calculate partial routes while building full path
---
### API Limitations
| Tier | Requests/Minute | Requests/Day | Cost |
|------|----------------|--------------|------|
| Free | 40 | 500 | $0 |
| Starter | 300 | 10,000 | Contact ORS |
| Business | Custom | Custom | Contact ORS |
**Best Practices**:
- Avoid unnecessary recalculations
- Implement client-side caching
- Show loading states during API calls
- Handle errors gracefully with user feedback
---
### Quick Reference
**Enable Route Planning**:
```bash
# 1. Get API key from openrouteservice.org
# 2. Add to .env.local
NEXT_PUBLIC_ORS_API_KEY=your_key_here
# 3. Restart dev server
npm run dev
```
**Debug Mode**:
```javascript
// Enable in RoutePanel.js
const DEBUG = true;
// Logs all tested routes and optimization stats
```
**Performance Monitoring**:
```javascript
console.time('Route Optimization');
await optimizeRoute();
console.timeEnd('Route Optimization');
// Shows exact optimization duration
```
---
### Debug Information
Check browser console for detailed logs:
- Coordinate parsing details
- API request/response structures
- **Optimization approach used** (ORS API vs permutation fallback)
- **Order change detection** (whether optimization actually improved the route)
- Performance timing information
- **Original vs optimized coordinate sequences**
---
---
## 📁 File Structure
```
src/app/projects/map/page.js # Main map page with routing logic
src/components/ui/LeafletMap.js # Map component with route rendering
src/components/ui/mapLayers.js # Map layer configurations
```
---
## 📦 Dependencies
- `@mapbox/polyline`: For decoding route geometry
- `leaflet`: Map rendering library
- `react-leaflet`: React integration for Leaflet
- `proj4`: Coordinate system transformations
- OpenRouteService API key (free tier available)
---
## 🚀 Future Enhancements
- **Advanced Vehicle Constraints**: Multiple vehicles, capacity limits, time windows
- **Route Preferences**: Allow users to prioritize distance vs time vs fuel efficiency
- **Real-time Traffic**: Integration with live traffic data
- **Route History**: Save and compare previously optimized routes
- **Mobile Optimization**: Optimize routes considering current location
- **Multi-stop Services**: Add service times at each location
- **Advanced Optimization**: Implement A* or genetic algorithms for 8+ points
- **Multi-Day Routes**: Break long routes into segments with overnight stops
- **Export Options**: Export routes to GPS devices or Google Maps
- **Cost Estimation**: Calculate fuel costs and travel expenses
---
## 📚 Additional Resources
- [OpenRouteService API Documentation](https://openrouteservice.org/dev/#/api-docs)
- [Directions API Reference](https://openrouteservice.org/dev/#/api-docs/v2/directions)
- [Polyline Encoding](https://developers.google.com/maps/documentation/utilities/polylinealgorithm)
- [Leaflet Routing Integration](https://www.liedman.net/leaflet-routing-machine/)
---
**Last Updated**: January 2025
**Maintainer**: Panel Development Team