38980-vm/app-9w9pd00g5j41/ITINERARY_FIX_SUMMARY.md
2026-03-04 18:25:09 +00:00

208 lines
5.2 KiB
Markdown

# 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:
```typescript
// 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:
```typescript
// 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:
```typescript
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**:
```typescript
// Blocked if type was used ANYWHERE in the day
if (place.type && usedTypesInDay.has(place.type)) {
return false;
}
```
**New Logic**:
```typescript
// 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`:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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
1. **src/db/api.ts** - `generateAutoSeedItinerary()` function
- Fixed targetPlaces calculation
- Fixed order_index logic
- Added duration parsing
- Improved logging and error handling
2. **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 `lastPlaceType` instead of `usedTypesInDay`
---
## 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.