5.2 KiB
Itinerary Auto-Generation Fix Summary
Problems Fixed
1. Daily Place Count Issue ✅
Problem: Timeline showed only 1-2 places per day instead of 3-5.
Root Cause: Faulty targetPlaces calculation:
// OLD (WRONG)
const targetPlaces = Math.min(
MAX_PLACES_PER_DAY - dayPlaces.length,
Math.max(MIN_PLACES_PER_DAY - dayPlaces.length, 0)
);
When balloon existed (dayPlaces.length = 1):
- Result: Math.min(4, 1) = 1
- Only 1 additional place added → Total 2 places ❌
Fix: Simplified to fill all remaining slots:
// NEW (CORRECT)
const remainingSlots = MAX_PLACES_PER_DAY - dayPlaces.length;
// Add places until remainingSlots is filled or candidates run out
Now adds up to 5 places total per day ✅
2. Order Index Collision ✅
Problem: order_index conflicts when balloon place exists.
Root Cause: Loop index i didn't account for balloon at position 0.
Fix: Explicit order_index calculation:
let orderIndex: number;
if (isBalloon) {
orderIndex = 0; // Balloon always first
} else {
const hasBalloon = dayPlaces.some(p => p.type === BALLOON_PLACE_TYPE);
orderIndex = hasBalloon ? i : i; // Sequential after balloon
}
Result:
- With balloon: 0 (balloon), 1, 2, 3, 4
- Without balloon: 0, 1, 2, 3, 4
3. Validation Logic Too Aggressive ✅
Problem: isValidForDay blocked ALL same types in same day.
Old Logic:
// Blocked if type was used ANYWHERE in the day
if (place.type && usedTypesInDay.has(place.type)) {
return false;
}
New Logic:
// Only block if CONSECUTIVE (last place was same type)
if (place.type && lastPlaceType === place.type) {
return false;
}
Now allows: Museum → Viewpoint → Museum ✅
Still blocks: Museum → Museum ❌
4. Minimum Places Requirement ✅
Problem: MIN_PLACES_PER_DAY was 2, but requirement is 3-5.
Fix: Updated cappadocia-rules.ts:
export const DAY_RULES: DayRules = {
max_places: 5,
min_places: 3, // Changed from 2 to 3
// ...
};
5. Duration Handling ✅
Problem: Duration stored as string ("2 hours") but database expects integer minutes.
Fix: Safe parsing with defaults:
let durationMinutes = 120; // Default 2 hours
if (place.duration) {
if (typeof place.duration === 'number') {
durationMinutes = place.duration;
} else if (typeof place.duration === 'string') {
const match = place.duration.match(/(\d+)/);
if (match) {
durationMinutes = parseInt(match[1]) * 60; // Convert hours to minutes
}
}
} else {
// Use typical duration from rules
const typicalDuration = getTypicalDuration(place.type || 'default');
const match = typicalDuration.match(/(\d+)/);
if (match) {
durationMinutes = parseInt(match[1]) * 60;
}
}
Key Improvements
Better Logging
Added comprehensive console logs for debugging:
console.log(`\n=== Processing Day ${day.day_number} ===`);
console.log(`Remaining slots: ${remainingSlots}`);
console.log(`✓ Added: ${place.name} (type: ${place.type})`);
console.log(`⊘ Skipping ${place.name} (consecutive type)`);
Error Handling
Continue processing even if individual inserts fail:
if (placeError) {
console.error(`✗ Insert error for ${place.name}:`, placeError.message);
// Continue even if error (might be duplicate)
} else {
console.log(`✓ Inserted: ${place.name}`);
}
Validation Warnings
Alert when minimum requirements not met:
if (dayPlaces.length < MIN_PLACES_PER_DAY) {
console.warn(`⚠ Day ${day.day_number} has only ${dayPlaces.length} places (min: ${MIN_PLACES_PER_DAY})`);
}
Expected Behavior After Fix
Before Fix ❌
- Day 1: 2 places (balloon + 1 other)
- Day 2: 1 place
- Day 3: 2 places
- Total: Sparse timeline, poor user experience
After Fix ✅
- Day 1: 5 places (balloon + 4 others)
- Day 2: 5 places
- Day 3: 5 places
- Total: Full daily itineraries, rich experience
Files Modified
-
src/db/api.ts -
generateAutoSeedItinerary()function- Fixed targetPlaces calculation
- Fixed order_index logic
- Added duration parsing
- Improved logging and error handling
-
src/config/cappadocia-rules.ts
- Changed MIN_PLACES_PER_DAY from 2 to 3
- Relaxed
isValidForDay()to allow non-consecutive same types - Changed signature to use
lastPlaceTypeinstead ofusedTypesInDay
Testing Checklist
- Create new trip with balloon interest
- Verify each day has 3-5 places
- Verify balloon has order_index = 0
- Verify other places have sequential order_index (1, 2, 3, 4)
- Verify no duplicate place_id across days
- Verify same type can appear in same day if not consecutive
- Verify duration is stored as integer minutes
- Check console logs for detailed execution flow
Architecture Reminder
places (global catalog)
↓ read-only
trip_places (itinerary timeline)
↓ per trip, per day
Timeline UI (displays joined data)
Critical: Timeline UI reads ONLY from trip_places joined with places.
The fix ensures trip_places is correctly populated with 3-5 places per day.