feat(reservations): native booking-confirmation import via KDE KItinerary (#1102)

* feat(reservations): native booking-confirmation import via KDE KItinerary

Adds a two-step preview → confirm flow for importing booking emails,
PDFs, PKPass and HTML confirmations. The server invokes the KDE
kitinerary-extractor binary, maps JSON-LD schema.org output to TREK
reservation shapes, and persists via the existing createReservation
pipeline (accommodations, budget, places, WebSocket broadcasts).

- NestJS BookingImportModule: preview + confirm endpoints under
  /api/trips/:tripId/reservations/import/booking{,/confirm}
- KitineraryExtractorService: spawns the binary, filters stderr noise,
  handles QDateTime (@value) timezone-aware datetimes
- kitinerary-mapper: FlightReservation, TrainReservation, BusReservation,
  BoatReservation, LodgingReservation, FoodEstablishmentReservation,
  RentalCarReservation, EventReservation → typed preview items
- BookingImportService: auto-creates place rows; geocodes venues without
  coordinates via Nominatim (name+address → address → name fallback);
  resolves day IDs for accommodation linking
- BookingImportModal: drag-and-drop multi-file upload, preview cards
  with type icons, per-item exclude toggle, confirm step
- Shared Zod contracts: BookingImportPreviewItem, PreviewResponse,
  ConfirmRequest, ConfirmResponse — consumed by controller, service,
  API client and modal
- Dockerfile: node:24-trixie-slim runtime; amd64 downloads KDE static
  binary + locales; arm64 installs libkitinerary-bin + symlinks to
  fixed path; ENV KITINERARY_EXTRACTOR_PATH set for both arches
- /api/health/features exposes { bookingImport: boolean } so the UI
  hides the Import button when the binary is absent
- i18n keys (English), wiki docs, API.md, README one-liner

* i18n: add booking import translations for all 19 non-English locales

Adds 17 reservations.import.* keys and undo.importBooking to ar, br, cs,
de, es, fr, gr, hu, id, it, ja, ko, nl, pl, ru, tr, uk, zh, zh-TW.

* chore: enforce i18n parity

* docs(wiki): add KItinerary local setup instructions to dev environment guide
This commit is contained in:
jubnl
2026-06-04 20:40:57 +02:00
committed by GitHub
parent abe1c549bd
commit 6ef3c7ae6b
64 changed files with 1851 additions and 31 deletions
+17
View File
@@ -117,5 +117,22 @@ const reservations: TranslationStrings = {
'reservations.validation.endBeforeStart':
'종료 날짜/시간은 시작 날짜/시간 이후여야 합니다',
'reservations.addBooking': '예약 추가',
'reservations.import.title': '예약 확인서 가져오기',
'reservations.import.cta': '파일에서 가져오기',
'reservations.import.dropHere': '예약 확인 파일을 여기에 끌어다 놓거나 클릭하여 선택',
'reservations.import.dropActive': '가져올 파일을 여기에 놓으세요',
'reservations.import.acceptedFormats': '허용 형식: EML, PDF, PKPass, HTML, TXT (파일당 최대 10 MB, 최대 5개)',
'reservations.import.parsing': '파일 분석 중…',
'reservations.import.previewHeading': '{count}개 예약 발견',
'reservations.import.previewEmpty': '업로드된 파일에서 예약을 추출할 수 없었습니다.',
'reservations.import.removeItem': '제거',
'reservations.import.confirm': '{count}개 예약 가져오기',
'reservations.import.back': '뒤로',
'reservations.import.success': '{count}개 예약을 가져왔습니다',
'reservations.import.partialFailure': '{created}개 가져옴, {failed}개 실패',
'reservations.import.error': '분석 실패. 파일이 유효한 예약 확인서인지 확인하세요.',
'reservations.import.unavailable': '이 서버에서는 예약 가져오기를 사용할 수 없습니다.',
'reservations.import.unsupportedFormat': '지원하지 않는 파일 형식입니다. EML, PDF, PKPass, HTML 또는 TXT를 사용하세요.',
'reservations.import.fileTooLarge': '파일 "{name}"이(가) 10 MB 제한을 초과합니다.',
};
export default reservations;
+1
View File
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
'undo.importNaverList': '네이버 지도 가져오기',
'undo.addPlace': '장소가 추가되었습니다',
'undo.done': '실행 취소됨: {action}',
'undo.importBooking': '예약 확인서 가져오기',
};
export default undo;