Files
2026-05-06 23:16:47 +02:00

10 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, duration, started, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established duration started completed
09-finalizacja 02 integrations
ical
google-calendar
sync
multi-yacht
prefix-matching
phase provides
04-frontend-kalendarz widget kalendarza per-yacht (już filtruje po _booking_yacht_id)
phase provides
08-gcal-synchronizacja per-yacht ICal_Feed/ICal_Import + OAuth GCal_Service (zachowane jako fallback)
Globalny iCal Export feed (jeden URL z tokenem dla wszystkich jachtów)
Globalny iCal Import URL (jeden wspólny kalendarz Google → wiele jachtów)
Mechanizm dopasowania jachtu po prefiksie SUMMARY (separator " - ")
Pole _yacht_gcal_alias (krótki alias dla skróconej nazwy w GCal)
Anti-loop (eventy zaimportowane z GCal nie są re-eksportowane)
Settings UI
nowa sekcja "Globalna synchronizacja iCal"
przyszłe plany sprzątające pola per-yacht (Google Calendar ID, iCal Import URL w yacht-edit)
ewentualne wycofanie OAuth push (drugi mechanizm, klient go nie używa)
added patterns
mb_strtolower/mb_substr/mb_strpos do parsowania prefiksu (poprawne dla polskich znaków)
Lookup map yachts: lowercase(alias|post_title) => yacht_id
Anti-loop via _booking_source flag (ical_import_global)
Token-based public feed authorization (hash_equals)
created modified
wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php
wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php
wp-content/plugins/yacht-booking-system/includes/class-yacht.php
wp-content/plugins/yacht-booking-system/includes/class-installer.php
wp-content/plugins/yacht-booking-system/admin/class-admin.php
wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php
Separator prefiksu: ' - ' (spacja-myślnik-spacja) — zgodne z istniejącym formatem per-yacht ICal_Feed::output_ics
Lookup case-insensitive po post_title lub _yacht_gcal_alias (priorytet alias)
Eventy bez separatora lub bez dopasowania — IGNOROWANE (nie blokują)
iCal jako mechanizm zamiast OAuth — klient nie chce konfigurować Google Cloud Console
Per-yacht feedy + OAuth zostają jako kompatybilność wsteczna (out of scope ich sprzątania)
Globalny feed: home_url('/yacht-ical-global/{token}.ics') — token w wp_options
Booking source 'ical_import_global' identyfikuje rezerwacje z globalnego importu (vs 'ical_import' per-yacht)
exact match po lowercase prefiksu — ŻADNYCH partial/substring matchings (uniknięcie kolizji 'Maja' vs 'Maja Słoneczna')
~25min 2026-05-06T11:00:00Z 2026-05-06T11:25:00Z

Phase 9 Plan 02: Globalna synchronizacja iCal Summary

Dwukierunkowa synchronizacja całej floty z jednym wspólnym Google Calendar przez iCal feedy, z automatycznym przypisaniem eventów do jachtów po prefiksie nazwy w tytule (separator " - ").

Performance

Metric Value
Duration ~25min
Tasks 3 auto + 1 human-verify (wszystkie zaakceptowane)
Files modified 6

Acceptance Criteria Results

Criterion Status Notes
AC-1: Globalny iCal Export feed Pass output_global_ics() zwraca .ics ze wszystkimi rezerwacjami, każda z prefiksem {yacht_title} - {customer_name}, anti-loop pomija source ical_import_global
AC-2: Globalny Import — dopasowanie po prefiksie Pass run_global_import() + match_yacht_by_prefix() parsuje SUMMARY przed pierwszym -, dopasowuje case-insensitive (mb_*), eventy bez dopasowania logowane i pomijane
AC-3: Globalny Import — czyszczenie usuniętych Pass existing_global_map vs seen_uids — zniknięte UID-y → Availability::clear_booking_availability() + wp_delete_post
AC-4: Alias jachtu Pass Yacht::get_gcal_alias() + update_gcal_alias(), build_yacht_lookup_map() używa aliasu z priorytetem
AC-5: Frontend filtrowanie (regresja) Pass Bez zmian w widget — działa przez _booking_yacht_id jak dotąd; klient zweryfikował na produkcji
AC-6: Settings UI Pass Nowa sekcja "Globalna synchronizacja iCal" (krok 1: export URL + kopiuj + regeneracja tokenu, krok 2: import URL + zapis, krok 3: importuj teraz, instrukcja) + alias w yacht-edit

Accomplishments

  • Klient może subskrybować jeden URL pluginu w Google Calendar i widzieć rezerwacje WSZYSTKICH jachtów w jednym widoku floty
  • Klient może tworzyć ręczne eventy w GCal z tytułem "Nazwa - opis" — plugin automatycznie przypisuje je do właściwego jachtu i blokuje availability tylko dla tego jachtu
  • Frontend kalendarz per-jacht pokazuje tylko swoje rezerwacje (bez zmian w widgecie — działa dzięki poprawnemu przypisaniu _booking_yacht_id przy imporcie)
  • Anti-loop zapobiega duplikacji (eventy zaimportowane z GCal nie są wysyłane z powrotem)
  • Stale cleanup automatycznie usuwa rezerwacje gdy event zostanie skasowany w GCal
  • Per-yacht feedy + OAuth push zostały zachowane (kompatybilność wsteczna)

Files Created/Modified

File Change Purpose
integrations/ical/class-ical-feed.php Modified +rewrite rule ^yacht-ical-global/, +query var yacht_ical_global, +get_global_feed_token(), +regenerate_global_token(), +get_global_feed_url(), +output_global_ics() (anti-loop, prefiks per yacht)
integrations/ical/class-ical-import.php Modified +GLOBAL_IMPORT_SOURCE, +SUMMARY_SEPARATOR, +run_global_import(), +build_yacht_lookup_map() (alias priority), +match_yacht_by_prefix() (mb_*), +get_existing_global_import_map(), +upsert_global_booking(), cron yacht_booking_ical_global_import (hourly), zmiana visibility parse_ics na protected
includes/class-yacht.php Modified +get_gcal_alias(), +update_gcal_alias() (meta _yacht_gcal_alias)
includes/class-installer.php Modified +domyślne opcje: yacht_booking_global_ical_import_url, yacht_booking_global_ical_token, yacht_booking_global_ical_last_import
admin/class-admin.php Modified +obsługa 3 form actions (save/regenerate token/run import), +4 admin notices, +sekcja UI "Globalna synchronizacja iCal" w render_google_calendar_settings(), +zapis aliasu w save_yacht()
admin/views/yacht-edit.php Modified +pole yacht_gcal_alias z opisem

Decisions Made

Decision Rationale Impact
Separator " - " (spacja-myślnik-spacja) Zgodność z istniejącym formatem output_ics (per-yacht feed już używał tego stylu) Klient nie musi uczyć się nowej konwencji; istniejące eksporty działają tak samo
Lookup po lowercase pełnej nazwy/aliasu (exact, nie substring) Uniknięcie kolizji typu "Maja" trafia w "Maja" i "Maja Słoneczna" jednocześnie Klient z długimi nazwami flot musi ustawić aliasy, ale ma pewność rozróżnienia
Eventy bez dopasowania — ignorowane (nie blokują) Klient nie chce niespodzianek (przypadkowa blokada całej floty przez literówkę) Dyscyplina nazewnictwa w GCal, ale przewidywalność
Anti-loop przez _booking_source flag Najprostsze, niezawodne Bez ryzyka eskalacji duplikatów między iteracjami
Per-yacht feedy zostają Kompatybilność wsteczna (potencjalni subskrybenci OTA) Out of scope ich usunięcia — decyzja na osobny plan po stabilizacji
Cron co godzinę dla globalnego importu Spójne z per-yacht cron Klient widzi import w panelu lub może wymusić "Importuj teraz"

Deviations from Plan

Summary

Type Count Impact
Auto-fixed 0
Scope additions 0
Deferred 0

Total impact: Plan wykonany dokładnie zgodnie ze specyfikacją. Brak odchyleń.

Auto-fixed Issues

Brak.

Deferred Items

Brak.

Issues Encountered

Brak — żadnych problemów podczas implementacji ani weryfikacji manualnej.

Otwarte pytania (do następnego planu)

Klient w trakcie planowania prosił "zapytaj po zrobieniu importu i eksportu" — te pytania zostają otwarte:

  1. Pola per-yacht "Google Calendar ID" i "iCal Import URL" w yacht-edit — czy je usunąć/ukryć teraz, gdy klient będzie używał globalnej synchronizacji? Jeśli tak: usunąć z UI ale zachować dane w meta na wypadek migracji.

  2. OAuth push do GCal (sync_to_gcal cron + on_booking_created hook) — drugi mechanizm jest aktywny tylko gdy admin podłączył OAuth. Klient nie planuje tego używać. Czy wyłączyć całkowicie (żeby uniknąć ewentualnych duplikatów gdy ktoś przez pomyłkę połączy OAuth) czy zostawić jako opcję?

Reproduction Path (do testów regresyjnych)

  1. Settings → Google Calendar → sekcja "Globalna synchronizacja iCal" → skopiuj Export URL → wklej w GCal "Z URL-a"
  2. Utwórz w GCal event "NazwaJachtu - Test" (data za tydzień, całodniowy)
  3. Skopiuj iCal URL kalendarza Google → wklej w pole "iCal Import URL" → Zapisz → "Importuj teraz"
  4. WP Admin → Rezerwacje → pojawia się booking "GCal: NazwaJachtu - Test" (source ical_import_global)
  5. Frontend kalendarz tego jachtu → data zablokowana; inny jacht → data wolna
  6. Usuń event w GCal → "Importuj teraz" → booking zniknął, daty zwolnione

Next Phase Readiness

Ready:

  • Globalna synchronizacja iCal w pełni funkcjonalna i zweryfikowana przez klienta
  • Architektura per-yacht zachowana (no breaking changes)
  • 2 z 4 plans w fazie 9 ukończone

Concerns:

  • Ewentualna kolizja gdy admin przypadkowo użyje OAuth obok iCal — drugi mechanizm tworzyłby duplikaty. Mitigacja: GCal_Service::create_event ustawia _gcal_event_id którego nie zerujemy, ale plugin już teraz ma anti-loop tylko na imporcie globalnym, nie na OAuth pull. Klient nie używa OAuth → praktyczny ryzyko zerowe.
  • Klient powinien wykonać deploy FTP + jednorazowy "Save" na stronie Permalinks żeby flush rewrite rules zarejestrowało nową regułę ^yacht-ical-global/ (dokumentowane w instrukcji checkpointu).

Blockers: None


Phase: 09-finalizacja, Plan: 02 Completed: 2026-05-06